@ue-too/board-vue-adapter 0.12.1 → 0.12.3

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/index.js.map CHANGED
@@ -1,50 +1 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../node_modules/.bun/@vue+shared@3.5.25/node_modules/@vue/shared/dist/shared.esm-bundler.js", "../../../node_modules/.bun/@vue+reactivity@3.5.25/node_modules/@vue/reactivity/dist/reactivity.esm-bundler.js", "../../../node_modules/.bun/@vue+runtime-core@3.5.25/node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js", "../../../node_modules/.bun/vue@3.5.25+e91562cb5bcb0454/node_modules/vue/dist/vue.runtime.esm-bundler.js", "../../math/src/index.ts", "../../board/src/utils/observable.ts", "../../board/src/camera/update-publisher.ts", "../../board/src/camera/utils/matrix.ts", "../../board/src/utils/coordinate-conversions/canvas-viewport.ts", "../../board/src/utils/coordinate-conversions/viewport-world.ts", "../../board/src/camera/utils/coordinate-conversion.ts", "../../board/src/camera/utils/position.ts", "../../board/src/camera/utils/zoom.ts", "../../board/src/camera/utils/rotation.ts", "../../board/src/camera/base.ts", "../../board/src/camera/default-camera.ts", "../../board/src/input-interpretation/raw-input-parser/vanilla-kmt-event-parser.ts", "../../board/src/input-interpretation/raw-input-parser/vanilla-touch-event-parser.ts", "../../board/src/utils/coordinate-conversions/window-canvas.ts", "../../board/src/utils/coorindate-conversion.ts", "../../board/src/utils/handler-pipeline.ts", "../../board/src/utils/canvas-position-dimension.ts", "../../board/src/utils/drawing.ts", "../../board/src/utils/zoomlevel-adjustment.ts", "../../board/src/input-interpretation/raw-input-publisher/raw-input-publisher.ts", "../../being/src/interface.ts", "../../board/src/camera/camera-mux/animation-and-lock/pan-control-state-machine.ts", "../../board/src/camera/camera-mux/animation-and-lock/zoom-control-state-machine.ts", "../../board/src/camera/camera-mux/animation-and-lock/rotation-control-state-machine.ts", "../../board/src/camera/camera-mux/animation-and-lock/animation-and-lock.ts", "../../board/src/camera/camera-rig/zoom-handler.ts", "../../board/src/camera/camera-rig/pan-handler.ts", "../../board/src/camera/camera-rig/rotation-handler.ts", "../../board/src/camera/camera-rig/camera-rig.ts", "../../board/src/input-interpretation/input-state-machine/kmt-input-context.ts", "../../board/src/input-interpretation/input-state-machine/touch-input-context.ts", "../../board/src/input-interpretation/input-state-machine/touch-input-state-machine.ts", "../../board/src/input-interpretation/input-state-machine/kmt-input-state-machine.ts", "../../board/src/input-interpretation/input-orchestrator.ts", "../../board/src/boardify/index.ts", "../src/useBoard.ts"],
4
- "sourcesContent": [
5
- "/**\n* @vue/shared v3.5.25\n* (c) 2018-present Yuxi (Evan) You and Vue contributors\n* @license MIT\n**/\n// @__NO_SIDE_EFFECTS__\nfunction makeMap(str) {\n const map = /* @__PURE__ */ Object.create(null);\n for (const key of str.split(\",\")) map[key] = 1;\n return (val) => val in map;\n}\n\nconst EMPTY_OBJ = !!(process.env.NODE_ENV !== \"production\") ? Object.freeze({}) : {};\nconst EMPTY_ARR = !!(process.env.NODE_ENV !== \"production\") ? Object.freeze([]) : [];\nconst NOOP = () => {\n};\nconst NO = () => false;\nconst isOn = (key) => key.charCodeAt(0) === 111 && key.charCodeAt(1) === 110 && // uppercase letter\n(key.charCodeAt(2) > 122 || key.charCodeAt(2) < 97);\nconst isModelListener = (key) => key.startsWith(\"onUpdate:\");\nconst extend = Object.assign;\nconst remove = (arr, el) => {\n const i = arr.indexOf(el);\n if (i > -1) {\n arr.splice(i, 1);\n }\n};\nconst hasOwnProperty = Object.prototype.hasOwnProperty;\nconst hasOwn = (val, key) => hasOwnProperty.call(val, key);\nconst isArray = Array.isArray;\nconst isMap = (val) => toTypeString(val) === \"[object Map]\";\nconst isSet = (val) => toTypeString(val) === \"[object Set]\";\nconst isDate = (val) => toTypeString(val) === \"[object Date]\";\nconst isRegExp = (val) => toTypeString(val) === \"[object RegExp]\";\nconst isFunction = (val) => typeof val === \"function\";\nconst isString = (val) => typeof val === \"string\";\nconst isSymbol = (val) => typeof val === \"symbol\";\nconst isObject = (val) => val !== null && typeof val === \"object\";\nconst isPromise = (val) => {\n return (isObject(val) || isFunction(val)) && isFunction(val.then) && isFunction(val.catch);\n};\nconst objectToString = Object.prototype.toString;\nconst toTypeString = (value) => objectToString.call(value);\nconst toRawType = (value) => {\n return toTypeString(value).slice(8, -1);\n};\nconst isPlainObject = (val) => toTypeString(val) === \"[object Object]\";\nconst isIntegerKey = (key) => isString(key) && key !== \"NaN\" && key[0] !== \"-\" && \"\" + parseInt(key, 10) === key;\nconst isReservedProp = /* @__PURE__ */ makeMap(\n // the leading comma is intentional so empty string \"\" is also included\n \",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted\"\n);\nconst isBuiltInDirective = /* @__PURE__ */ makeMap(\n \"bind,cloak,else-if,else,for,html,if,model,on,once,pre,show,slot,text,memo\"\n);\nconst cacheStringFunction = (fn) => {\n const cache = /* @__PURE__ */ Object.create(null);\n return ((str) => {\n const hit = cache[str];\n return hit || (cache[str] = fn(str));\n });\n};\nconst camelizeRE = /-\\w/g;\nconst camelize = cacheStringFunction(\n (str) => {\n return str.replace(camelizeRE, (c) => c.slice(1).toUpperCase());\n }\n);\nconst hyphenateRE = /\\B([A-Z])/g;\nconst hyphenate = cacheStringFunction(\n (str) => str.replace(hyphenateRE, \"-$1\").toLowerCase()\n);\nconst capitalize = cacheStringFunction((str) => {\n return str.charAt(0).toUpperCase() + str.slice(1);\n});\nconst toHandlerKey = cacheStringFunction(\n (str) => {\n const s = str ? `on${capitalize(str)}` : ``;\n return s;\n }\n);\nconst hasChanged = (value, oldValue) => !Object.is(value, oldValue);\nconst invokeArrayFns = (fns, ...arg) => {\n for (let i = 0; i < fns.length; i++) {\n fns[i](...arg);\n }\n};\nconst def = (obj, key, value, writable = false) => {\n Object.defineProperty(obj, key, {\n configurable: true,\n enumerable: false,\n writable,\n value\n });\n};\nconst looseToNumber = (val) => {\n const n = parseFloat(val);\n return isNaN(n) ? val : n;\n};\nconst toNumber = (val) => {\n const n = isString(val) ? Number(val) : NaN;\n return isNaN(n) ? val : n;\n};\nlet _globalThis;\nconst getGlobalThis = () => {\n return _globalThis || (_globalThis = typeof globalThis !== \"undefined\" ? globalThis : typeof self !== \"undefined\" ? self : typeof window !== \"undefined\" ? window : typeof global !== \"undefined\" ? global : {});\n};\nconst identRE = /^[_$a-zA-Z\\xA0-\\uFFFF][_$a-zA-Z0-9\\xA0-\\uFFFF]*$/;\nfunction genPropsAccessExp(name) {\n return identRE.test(name) ? `__props.${name}` : `__props[${JSON.stringify(name)}]`;\n}\nfunction genCacheKey(source, options) {\n return source + JSON.stringify(\n options,\n (_, val) => typeof val === \"function\" ? val.toString() : val\n );\n}\n\nconst PatchFlags = {\n \"TEXT\": 1,\n \"1\": \"TEXT\",\n \"CLASS\": 2,\n \"2\": \"CLASS\",\n \"STYLE\": 4,\n \"4\": \"STYLE\",\n \"PROPS\": 8,\n \"8\": \"PROPS\",\n \"FULL_PROPS\": 16,\n \"16\": \"FULL_PROPS\",\n \"NEED_HYDRATION\": 32,\n \"32\": \"NEED_HYDRATION\",\n \"STABLE_FRAGMENT\": 64,\n \"64\": \"STABLE_FRAGMENT\",\n \"KEYED_FRAGMENT\": 128,\n \"128\": \"KEYED_FRAGMENT\",\n \"UNKEYED_FRAGMENT\": 256,\n \"256\": \"UNKEYED_FRAGMENT\",\n \"NEED_PATCH\": 512,\n \"512\": \"NEED_PATCH\",\n \"DYNAMIC_SLOTS\": 1024,\n \"1024\": \"DYNAMIC_SLOTS\",\n \"DEV_ROOT_FRAGMENT\": 2048,\n \"2048\": \"DEV_ROOT_FRAGMENT\",\n \"CACHED\": -1,\n \"-1\": \"CACHED\",\n \"BAIL\": -2,\n \"-2\": \"BAIL\"\n};\nconst PatchFlagNames = {\n [1]: `TEXT`,\n [2]: `CLASS`,\n [4]: `STYLE`,\n [8]: `PROPS`,\n [16]: `FULL_PROPS`,\n [32]: `NEED_HYDRATION`,\n [64]: `STABLE_FRAGMENT`,\n [128]: `KEYED_FRAGMENT`,\n [256]: `UNKEYED_FRAGMENT`,\n [512]: `NEED_PATCH`,\n [1024]: `DYNAMIC_SLOTS`,\n [2048]: `DEV_ROOT_FRAGMENT`,\n [-1]: `CACHED`,\n [-2]: `BAIL`\n};\n\nconst ShapeFlags = {\n \"ELEMENT\": 1,\n \"1\": \"ELEMENT\",\n \"FUNCTIONAL_COMPONENT\": 2,\n \"2\": \"FUNCTIONAL_COMPONENT\",\n \"STATEFUL_COMPONENT\": 4,\n \"4\": \"STATEFUL_COMPONENT\",\n \"TEXT_CHILDREN\": 8,\n \"8\": \"TEXT_CHILDREN\",\n \"ARRAY_CHILDREN\": 16,\n \"16\": \"ARRAY_CHILDREN\",\n \"SLOTS_CHILDREN\": 32,\n \"32\": \"SLOTS_CHILDREN\",\n \"TELEPORT\": 64,\n \"64\": \"TELEPORT\",\n \"SUSPENSE\": 128,\n \"128\": \"SUSPENSE\",\n \"COMPONENT_SHOULD_KEEP_ALIVE\": 256,\n \"256\": \"COMPONENT_SHOULD_KEEP_ALIVE\",\n \"COMPONENT_KEPT_ALIVE\": 512,\n \"512\": \"COMPONENT_KEPT_ALIVE\",\n \"COMPONENT\": 6,\n \"6\": \"COMPONENT\"\n};\n\nconst SlotFlags = {\n \"STABLE\": 1,\n \"1\": \"STABLE\",\n \"DYNAMIC\": 2,\n \"2\": \"DYNAMIC\",\n \"FORWARDED\": 3,\n \"3\": \"FORWARDED\"\n};\nconst slotFlagsText = {\n [1]: \"STABLE\",\n [2]: \"DYNAMIC\",\n [3]: \"FORWARDED\"\n};\n\nconst GLOBALS_ALLOWED = \"Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,console,Error,Symbol\";\nconst isGloballyAllowed = /* @__PURE__ */ makeMap(GLOBALS_ALLOWED);\nconst isGloballyWhitelisted = isGloballyAllowed;\n\nconst range = 2;\nfunction generateCodeFrame(source, start = 0, end = source.length) {\n start = Math.max(0, Math.min(start, source.length));\n end = Math.max(0, Math.min(end, source.length));\n if (start > end) return \"\";\n let lines = source.split(/(\\r?\\n)/);\n const newlineSequences = lines.filter((_, idx) => idx % 2 === 1);\n lines = lines.filter((_, idx) => idx % 2 === 0);\n let count = 0;\n const res = [];\n for (let i = 0; i < lines.length; i++) {\n count += lines[i].length + (newlineSequences[i] && newlineSequences[i].length || 0);\n if (count >= start) {\n for (let j = i - range; j <= i + range || end > count; j++) {\n if (j < 0 || j >= lines.length) continue;\n const line = j + 1;\n res.push(\n `${line}${\" \".repeat(Math.max(3 - String(line).length, 0))}| ${lines[j]}`\n );\n const lineLength = lines[j].length;\n const newLineSeqLength = newlineSequences[j] && newlineSequences[j].length || 0;\n if (j === i) {\n const pad = start - (count - (lineLength + newLineSeqLength));\n const length = Math.max(\n 1,\n end > count ? lineLength - pad : end - start\n );\n res.push(` | ` + \" \".repeat(pad) + \"^\".repeat(length));\n } else if (j > i) {\n if (end > count) {\n const length = Math.max(Math.min(end - count, lineLength), 1);\n res.push(` | ` + \"^\".repeat(length));\n }\n count += lineLength + newLineSeqLength;\n }\n }\n break;\n }\n }\n return res.join(\"\\n\");\n}\n\nfunction normalizeStyle(value) {\n if (isArray(value)) {\n const res = {};\n for (let i = 0; i < value.length; i++) {\n const item = value[i];\n const normalized = isString(item) ? parseStringStyle(item) : normalizeStyle(item);\n if (normalized) {\n for (const key in normalized) {\n res[key] = normalized[key];\n }\n }\n }\n return res;\n } else if (isString(value) || isObject(value)) {\n return value;\n }\n}\nconst listDelimiterRE = /;(?![^(]*\\))/g;\nconst propertyDelimiterRE = /:([^]+)/;\nconst styleCommentRE = /\\/\\*[^]*?\\*\\//g;\nfunction parseStringStyle(cssText) {\n const ret = {};\n cssText.replace(styleCommentRE, \"\").split(listDelimiterRE).forEach((item) => {\n if (item) {\n const tmp = item.split(propertyDelimiterRE);\n tmp.length > 1 && (ret[tmp[0].trim()] = tmp[1].trim());\n }\n });\n return ret;\n}\nfunction stringifyStyle(styles) {\n if (!styles) return \"\";\n if (isString(styles)) return styles;\n let ret = \"\";\n for (const key in styles) {\n const value = styles[key];\n if (isString(value) || typeof value === \"number\") {\n const normalizedKey = key.startsWith(`--`) ? key : hyphenate(key);\n ret += `${normalizedKey}:${value};`;\n }\n }\n return ret;\n}\nfunction normalizeClass(value) {\n let res = \"\";\n if (isString(value)) {\n res = value;\n } else if (isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n const normalized = normalizeClass(value[i]);\n if (normalized) {\n res += normalized + \" \";\n }\n }\n } else if (isObject(value)) {\n for (const name in value) {\n if (value[name]) {\n res += name + \" \";\n }\n }\n }\n return res.trim();\n}\nfunction normalizeProps(props) {\n if (!props) return null;\n let { class: klass, style } = props;\n if (klass && !isString(klass)) {\n props.class = normalizeClass(klass);\n }\n if (style) {\n props.style = normalizeStyle(style);\n }\n return props;\n}\n\nconst HTML_TAGS = \"html,body,base,head,link,meta,style,title,address,article,aside,footer,header,hgroup,h1,h2,h3,h4,h5,h6,nav,section,div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,ruby,s,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,output,progress,select,textarea,details,dialog,menu,summary,template,blockquote,iframe,tfoot\";\nconst SVG_TAGS = \"svg,animate,animateMotion,animateTransform,circle,clipPath,color-profile,defs,desc,discard,ellipse,feBlend,feColorMatrix,feComponentTransfer,feComposite,feConvolveMatrix,feDiffuseLighting,feDisplacementMap,feDistantLight,feDropShadow,feFlood,feFuncA,feFuncB,feFuncG,feFuncR,feGaussianBlur,feImage,feMerge,feMergeNode,feMorphology,feOffset,fePointLight,feSpecularLighting,feSpotLight,feTile,feTurbulence,filter,foreignObject,g,hatch,hatchpath,image,line,linearGradient,marker,mask,mesh,meshgradient,meshpatch,meshrow,metadata,mpath,path,pattern,polygon,polyline,radialGradient,rect,set,solidcolor,stop,switch,symbol,text,textPath,title,tspan,unknown,use,view\";\nconst MATH_TAGS = \"annotation,annotation-xml,maction,maligngroup,malignmark,math,menclose,merror,mfenced,mfrac,mfraction,mglyph,mi,mlabeledtr,mlongdiv,mmultiscripts,mn,mo,mover,mpadded,mphantom,mprescripts,mroot,mrow,ms,mscarries,mscarry,msgroup,msline,mspace,msqrt,msrow,mstack,mstyle,msub,msubsup,msup,mtable,mtd,mtext,mtr,munder,munderover,none,semantics\";\nconst VOID_TAGS = \"area,base,br,col,embed,hr,img,input,link,meta,param,source,track,wbr\";\nconst isHTMLTag = /* @__PURE__ */ makeMap(HTML_TAGS);\nconst isSVGTag = /* @__PURE__ */ makeMap(SVG_TAGS);\nconst isMathMLTag = /* @__PURE__ */ makeMap(MATH_TAGS);\nconst isVoidTag = /* @__PURE__ */ makeMap(VOID_TAGS);\n\nconst specialBooleanAttrs = `itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly`;\nconst isSpecialBooleanAttr = /* @__PURE__ */ makeMap(specialBooleanAttrs);\nconst isBooleanAttr = /* @__PURE__ */ makeMap(\n specialBooleanAttrs + `,async,autofocus,autoplay,controls,default,defer,disabled,hidden,inert,loop,open,required,reversed,scoped,seamless,checked,muted,multiple,selected`\n);\nfunction includeBooleanAttr(value) {\n return !!value || value === \"\";\n}\nconst unsafeAttrCharRE = /[>/=\"'\\u0009\\u000a\\u000c\\u0020]/;\nconst attrValidationCache = {};\nfunction isSSRSafeAttrName(name) {\n if (attrValidationCache.hasOwnProperty(name)) {\n return attrValidationCache[name];\n }\n const isUnsafe = unsafeAttrCharRE.test(name);\n if (isUnsafe) {\n console.error(`unsafe attribute name: ${name}`);\n }\n return attrValidationCache[name] = !isUnsafe;\n}\nconst propsToAttrMap = {\n acceptCharset: \"accept-charset\",\n className: \"class\",\n htmlFor: \"for\",\n httpEquiv: \"http-equiv\"\n};\nconst isKnownHtmlAttr = /* @__PURE__ */ makeMap(\n `accept,accept-charset,accesskey,action,align,allow,alt,async,autocapitalize,autocomplete,autofocus,autoplay,background,bgcolor,border,buffered,capture,challenge,charset,checked,cite,class,code,codebase,color,cols,colspan,content,contenteditable,contextmenu,controls,coords,crossorigin,csp,data,datetime,decoding,default,defer,dir,dirname,disabled,download,draggable,dropzone,enctype,enterkeyhint,for,form,formaction,formenctype,formmethod,formnovalidate,formtarget,headers,height,hidden,high,href,hreflang,http-equiv,icon,id,importance,inert,integrity,ismap,itemprop,keytype,kind,label,lang,language,loading,list,loop,low,manifest,max,maxlength,minlength,media,min,multiple,muted,name,novalidate,open,optimum,pattern,ping,placeholder,poster,preload,radiogroup,readonly,referrerpolicy,rel,required,reversed,rows,rowspan,sandbox,scope,scoped,selected,shape,size,sizes,slot,span,spellcheck,src,srcdoc,srclang,srcset,start,step,style,summary,tabindex,target,title,translate,type,usemap,value,width,wrap`\n);\nconst isKnownSvgAttr = /* @__PURE__ */ makeMap(\n `xmlns,accent-height,accumulate,additive,alignment-baseline,alphabetic,amplitude,arabic-form,ascent,attributeName,attributeType,azimuth,baseFrequency,baseline-shift,baseProfile,bbox,begin,bias,by,calcMode,cap-height,class,clip,clipPathUnits,clip-path,clip-rule,color,color-interpolation,color-interpolation-filters,color-profile,color-rendering,contentScriptType,contentStyleType,crossorigin,cursor,cx,cy,d,decelerate,descent,diffuseConstant,direction,display,divisor,dominant-baseline,dur,dx,dy,edgeMode,elevation,enable-background,end,exponent,fill,fill-opacity,fill-rule,filter,filterRes,filterUnits,flood-color,flood-opacity,font-family,font-size,font-size-adjust,font-stretch,font-style,font-variant,font-weight,format,from,fr,fx,fy,g1,g2,glyph-name,glyph-orientation-horizontal,glyph-orientation-vertical,glyphRef,gradientTransform,gradientUnits,hanging,height,href,hreflang,horiz-adv-x,horiz-origin-x,id,ideographic,image-rendering,in,in2,intercept,k,k1,k2,k3,k4,kernelMatrix,kernelUnitLength,kerning,keyPoints,keySplines,keyTimes,lang,lengthAdjust,letter-spacing,lighting-color,limitingConeAngle,local,marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mask,maskContentUnits,maskUnits,mathematical,max,media,method,min,mode,name,numOctaves,offset,opacity,operator,order,orient,orientation,origin,overflow,overline-position,overline-thickness,panose-1,paint-order,path,pathLength,patternContentUnits,patternTransform,patternUnits,ping,pointer-events,points,pointsAtX,pointsAtY,pointsAtZ,preserveAlpha,preserveAspectRatio,primitiveUnits,r,radius,referrerPolicy,refX,refY,rel,rendering-intent,repeatCount,repeatDur,requiredExtensions,requiredFeatures,restart,result,rotate,rx,ry,scale,seed,shape-rendering,slope,spacing,specularConstant,specularExponent,speed,spreadMethod,startOffset,stdDeviation,stemh,stemv,stitchTiles,stop-color,stop-opacity,strikethrough-position,strikethrough-thickness,string,stroke,stroke-dasharray,stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,stroke-width,style,surfaceScale,systemLanguage,tabindex,tableValues,target,targetX,targetY,text-anchor,text-decoration,text-rendering,textLength,to,transform,transform-origin,type,u1,u2,underline-position,underline-thickness,unicode,unicode-bidi,unicode-range,units-per-em,v-alphabetic,v-hanging,v-ideographic,v-mathematical,values,vector-effect,version,vert-adv-y,vert-origin-x,vert-origin-y,viewBox,viewTarget,visibility,width,widths,word-spacing,writing-mode,x,x-height,x1,x2,xChannelSelector,xlink:actuate,xlink:arcrole,xlink:href,xlink:role,xlink:show,xlink:title,xlink:type,xmlns:xlink,xml:base,xml:lang,xml:space,y,y1,y2,yChannelSelector,z,zoomAndPan`\n);\nconst isKnownMathMLAttr = /* @__PURE__ */ makeMap(\n `accent,accentunder,actiontype,align,alignmentscope,altimg,altimg-height,altimg-valign,altimg-width,alttext,bevelled,close,columnsalign,columnlines,columnspan,denomalign,depth,dir,display,displaystyle,encoding,equalcolumns,equalrows,fence,fontstyle,fontweight,form,frame,framespacing,groupalign,height,href,id,indentalign,indentalignfirst,indentalignlast,indentshift,indentshiftfirst,indentshiftlast,indextype,justify,largetop,largeop,lquote,lspace,mathbackground,mathcolor,mathsize,mathvariant,maxsize,minlabelspacing,mode,other,overflow,position,rowalign,rowlines,rowspan,rquote,rspace,scriptlevel,scriptminsize,scriptsizemultiplier,selection,separator,separators,shift,side,src,stackalign,stretchy,subscriptshift,superscriptshift,symmetric,voffset,width,widths,xlink:href,xlink:show,xlink:type,xmlns`\n);\nfunction isRenderableAttrValue(value) {\n if (value == null) {\n return false;\n }\n const type = typeof value;\n return type === \"string\" || type === \"number\" || type === \"boolean\";\n}\n\nconst escapeRE = /[\"'&<>]/;\nfunction escapeHtml(string) {\n const str = \"\" + string;\n const match = escapeRE.exec(str);\n if (!match) {\n return str;\n }\n let html = \"\";\n let escaped;\n let index;\n let lastIndex = 0;\n for (index = match.index; index < str.length; index++) {\n switch (str.charCodeAt(index)) {\n case 34:\n escaped = \"&quot;\";\n break;\n case 38:\n escaped = \"&amp;\";\n break;\n case 39:\n escaped = \"&#39;\";\n break;\n case 60:\n escaped = \"&lt;\";\n break;\n case 62:\n escaped = \"&gt;\";\n break;\n default:\n continue;\n }\n if (lastIndex !== index) {\n html += str.slice(lastIndex, index);\n }\n lastIndex = index + 1;\n html += escaped;\n }\n return lastIndex !== index ? html + str.slice(lastIndex, index) : html;\n}\nconst commentStripRE = /^-?>|<!--|-->|--!>|<!-$/g;\nfunction escapeHtmlComment(src) {\n return src.replace(commentStripRE, \"\");\n}\nconst cssVarNameEscapeSymbolsRE = /[ !\"#$%&'()*+,./:;<=>?@[\\\\\\]^`{|}~]/g;\nfunction getEscapedCssVarName(key, doubleEscape) {\n return key.replace(\n cssVarNameEscapeSymbolsRE,\n (s) => doubleEscape ? s === '\"' ? '\\\\\\\\\\\\\"' : `\\\\\\\\${s}` : `\\\\${s}`\n );\n}\n\nfunction looseCompareArrays(a, b) {\n if (a.length !== b.length) return false;\n let equal = true;\n for (let i = 0; equal && i < a.length; i++) {\n equal = looseEqual(a[i], b[i]);\n }\n return equal;\n}\nfunction looseEqual(a, b) {\n if (a === b) return true;\n let aValidType = isDate(a);\n let bValidType = isDate(b);\n if (aValidType || bValidType) {\n return aValidType && bValidType ? a.getTime() === b.getTime() : false;\n }\n aValidType = isSymbol(a);\n bValidType = isSymbol(b);\n if (aValidType || bValidType) {\n return a === b;\n }\n aValidType = isArray(a);\n bValidType = isArray(b);\n if (aValidType || bValidType) {\n return aValidType && bValidType ? looseCompareArrays(a, b) : false;\n }\n aValidType = isObject(a);\n bValidType = isObject(b);\n if (aValidType || bValidType) {\n if (!aValidType || !bValidType) {\n return false;\n }\n const aKeysCount = Object.keys(a).length;\n const bKeysCount = Object.keys(b).length;\n if (aKeysCount !== bKeysCount) {\n return false;\n }\n for (const key in a) {\n const aHasKey = a.hasOwnProperty(key);\n const bHasKey = b.hasOwnProperty(key);\n if (aHasKey && !bHasKey || !aHasKey && bHasKey || !looseEqual(a[key], b[key])) {\n return false;\n }\n }\n }\n return String(a) === String(b);\n}\nfunction looseIndexOf(arr, val) {\n return arr.findIndex((item) => looseEqual(item, val));\n}\n\nconst isRef = (val) => {\n return !!(val && val[\"__v_isRef\"] === true);\n};\nconst toDisplayString = (val) => {\n return isString(val) ? val : val == null ? \"\" : isArray(val) || isObject(val) && (val.toString === objectToString || !isFunction(val.toString)) ? isRef(val) ? toDisplayString(val.value) : JSON.stringify(val, replacer, 2) : String(val);\n};\nconst replacer = (_key, val) => {\n if (isRef(val)) {\n return replacer(_key, val.value);\n } else if (isMap(val)) {\n return {\n [`Map(${val.size})`]: [...val.entries()].reduce(\n (entries, [key, val2], i) => {\n entries[stringifySymbol(key, i) + \" =>\"] = val2;\n return entries;\n },\n {}\n )\n };\n } else if (isSet(val)) {\n return {\n [`Set(${val.size})`]: [...val.values()].map((v) => stringifySymbol(v))\n };\n } else if (isSymbol(val)) {\n return stringifySymbol(val);\n } else if (isObject(val) && !isArray(val) && !isPlainObject(val)) {\n return String(val);\n }\n return val;\n};\nconst stringifySymbol = (v, i = \"\") => {\n var _a;\n return (\n // Symbol.description in es2019+ so we need to cast here to pass\n // the lib: es2016 check\n isSymbol(v) ? `Symbol(${(_a = v.description) != null ? _a : i})` : v\n );\n};\n\nfunction normalizeCssVarValue(value) {\n if (value == null) {\n return \"initial\";\n }\n if (typeof value === \"string\") {\n return value === \"\" ? \" \" : value;\n }\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n console.warn(\n \"[Vue warn] Invalid value used for CSS binding. Expected a string or a finite number but received:\",\n value\n );\n }\n }\n return String(value);\n}\n\nexport { EMPTY_ARR, EMPTY_OBJ, NO, NOOP, PatchFlagNames, PatchFlags, ShapeFlags, SlotFlags, camelize, capitalize, cssVarNameEscapeSymbolsRE, def, escapeHtml, escapeHtmlComment, extend, genCacheKey, genPropsAccessExp, generateCodeFrame, getEscapedCssVarName, getGlobalThis, hasChanged, hasOwn, hyphenate, includeBooleanAttr, invokeArrayFns, isArray, isBooleanAttr, isBuiltInDirective, isDate, isFunction, isGloballyAllowed, isGloballyWhitelisted, isHTMLTag, isIntegerKey, isKnownHtmlAttr, isKnownMathMLAttr, isKnownSvgAttr, isMap, isMathMLTag, isModelListener, isObject, isOn, isPlainObject, isPromise, isRegExp, isRenderableAttrValue, isReservedProp, isSSRSafeAttrName, isSVGTag, isSet, isSpecialBooleanAttr, isString, isSymbol, isVoidTag, looseEqual, looseIndexOf, looseToNumber, makeMap, normalizeClass, normalizeCssVarValue, normalizeProps, normalizeStyle, objectToString, parseStringStyle, propsToAttrMap, remove, slotFlagsText, stringifyStyle, toDisplayString, toHandlerKey, toNumber, toRawType, toTypeString };\n",
6
- "/**\n* @vue/reactivity v3.5.25\n* (c) 2018-present Yuxi (Evan) You and Vue contributors\n* @license MIT\n**/\nimport { extend, hasChanged, isArray, isIntegerKey, isSymbol, isMap, hasOwn, makeMap, isObject, capitalize, toRawType, def, isFunction, EMPTY_OBJ, isSet, isPlainObject, remove, NOOP } from '@vue/shared';\n\nfunction warn(msg, ...args) {\n console.warn(`[Vue warn] ${msg}`, ...args);\n}\n\nlet activeEffectScope;\nclass EffectScope {\n constructor(detached = false) {\n this.detached = detached;\n /**\n * @internal\n */\n this._active = true;\n /**\n * @internal track `on` calls, allow `on` call multiple times\n */\n this._on = 0;\n /**\n * @internal\n */\n this.effects = [];\n /**\n * @internal\n */\n this.cleanups = [];\n this._isPaused = false;\n this.parent = activeEffectScope;\n if (!detached && activeEffectScope) {\n this.index = (activeEffectScope.scopes || (activeEffectScope.scopes = [])).push(\n this\n ) - 1;\n }\n }\n get active() {\n return this._active;\n }\n pause() {\n if (this._active) {\n this._isPaused = true;\n let i, l;\n if (this.scopes) {\n for (i = 0, l = this.scopes.length; i < l; i++) {\n this.scopes[i].pause();\n }\n }\n for (i = 0, l = this.effects.length; i < l; i++) {\n this.effects[i].pause();\n }\n }\n }\n /**\n * Resumes the effect scope, including all child scopes and effects.\n */\n resume() {\n if (this._active) {\n if (this._isPaused) {\n this._isPaused = false;\n let i, l;\n if (this.scopes) {\n for (i = 0, l = this.scopes.length; i < l; i++) {\n this.scopes[i].resume();\n }\n }\n for (i = 0, l = this.effects.length; i < l; i++) {\n this.effects[i].resume();\n }\n }\n }\n }\n run(fn) {\n if (this._active) {\n const currentEffectScope = activeEffectScope;\n try {\n activeEffectScope = this;\n return fn();\n } finally {\n activeEffectScope = currentEffectScope;\n }\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn(`cannot run an inactive effect scope.`);\n }\n }\n /**\n * This should only be called on non-detached scopes\n * @internal\n */\n on() {\n if (++this._on === 1) {\n this.prevScope = activeEffectScope;\n activeEffectScope = this;\n }\n }\n /**\n * This should only be called on non-detached scopes\n * @internal\n */\n off() {\n if (this._on > 0 && --this._on === 0) {\n activeEffectScope = this.prevScope;\n this.prevScope = void 0;\n }\n }\n stop(fromParent) {\n if (this._active) {\n this._active = false;\n let i, l;\n for (i = 0, l = this.effects.length; i < l; i++) {\n this.effects[i].stop();\n }\n this.effects.length = 0;\n for (i = 0, l = this.cleanups.length; i < l; i++) {\n this.cleanups[i]();\n }\n this.cleanups.length = 0;\n if (this.scopes) {\n for (i = 0, l = this.scopes.length; i < l; i++) {\n this.scopes[i].stop(true);\n }\n this.scopes.length = 0;\n }\n if (!this.detached && this.parent && !fromParent) {\n const last = this.parent.scopes.pop();\n if (last && last !== this) {\n this.parent.scopes[this.index] = last;\n last.index = this.index;\n }\n }\n this.parent = void 0;\n }\n }\n}\nfunction effectScope(detached) {\n return new EffectScope(detached);\n}\nfunction getCurrentScope() {\n return activeEffectScope;\n}\nfunction onScopeDispose(fn, failSilently = false) {\n if (activeEffectScope) {\n activeEffectScope.cleanups.push(fn);\n } else if (!!(process.env.NODE_ENV !== \"production\") && !failSilently) {\n warn(\n `onScopeDispose() is called when there is no active effect scope to be associated with.`\n );\n }\n}\n\nlet activeSub;\nconst EffectFlags = {\n \"ACTIVE\": 1,\n \"1\": \"ACTIVE\",\n \"RUNNING\": 2,\n \"2\": \"RUNNING\",\n \"TRACKING\": 4,\n \"4\": \"TRACKING\",\n \"NOTIFIED\": 8,\n \"8\": \"NOTIFIED\",\n \"DIRTY\": 16,\n \"16\": \"DIRTY\",\n \"ALLOW_RECURSE\": 32,\n \"32\": \"ALLOW_RECURSE\",\n \"PAUSED\": 64,\n \"64\": \"PAUSED\",\n \"EVALUATED\": 128,\n \"128\": \"EVALUATED\"\n};\nconst pausedQueueEffects = /* @__PURE__ */ new WeakSet();\nclass ReactiveEffect {\n constructor(fn) {\n this.fn = fn;\n /**\n * @internal\n */\n this.deps = void 0;\n /**\n * @internal\n */\n this.depsTail = void 0;\n /**\n * @internal\n */\n this.flags = 1 | 4;\n /**\n * @internal\n */\n this.next = void 0;\n /**\n * @internal\n */\n this.cleanup = void 0;\n this.scheduler = void 0;\n if (activeEffectScope && activeEffectScope.active) {\n activeEffectScope.effects.push(this);\n }\n }\n pause() {\n this.flags |= 64;\n }\n resume() {\n if (this.flags & 64) {\n this.flags &= -65;\n if (pausedQueueEffects.has(this)) {\n pausedQueueEffects.delete(this);\n this.trigger();\n }\n }\n }\n /**\n * @internal\n */\n notify() {\n if (this.flags & 2 && !(this.flags & 32)) {\n return;\n }\n if (!(this.flags & 8)) {\n batch(this);\n }\n }\n run() {\n if (!(this.flags & 1)) {\n return this.fn();\n }\n this.flags |= 2;\n cleanupEffect(this);\n prepareDeps(this);\n const prevEffect = activeSub;\n const prevShouldTrack = shouldTrack;\n activeSub = this;\n shouldTrack = true;\n try {\n return this.fn();\n } finally {\n if (!!(process.env.NODE_ENV !== \"production\") && activeSub !== this) {\n warn(\n \"Active effect was not restored correctly - this is likely a Vue internal bug.\"\n );\n }\n cleanupDeps(this);\n activeSub = prevEffect;\n shouldTrack = prevShouldTrack;\n this.flags &= -3;\n }\n }\n stop() {\n if (this.flags & 1) {\n for (let link = this.deps; link; link = link.nextDep) {\n removeSub(link);\n }\n this.deps = this.depsTail = void 0;\n cleanupEffect(this);\n this.onStop && this.onStop();\n this.flags &= -2;\n }\n }\n trigger() {\n if (this.flags & 64) {\n pausedQueueEffects.add(this);\n } else if (this.scheduler) {\n this.scheduler();\n } else {\n this.runIfDirty();\n }\n }\n /**\n * @internal\n */\n runIfDirty() {\n if (isDirty(this)) {\n this.run();\n }\n }\n get dirty() {\n return isDirty(this);\n }\n}\nlet batchDepth = 0;\nlet batchedSub;\nlet batchedComputed;\nfunction batch(sub, isComputed = false) {\n sub.flags |= 8;\n if (isComputed) {\n sub.next = batchedComputed;\n batchedComputed = sub;\n return;\n }\n sub.next = batchedSub;\n batchedSub = sub;\n}\nfunction startBatch() {\n batchDepth++;\n}\nfunction endBatch() {\n if (--batchDepth > 0) {\n return;\n }\n if (batchedComputed) {\n let e = batchedComputed;\n batchedComputed = void 0;\n while (e) {\n const next = e.next;\n e.next = void 0;\n e.flags &= -9;\n e = next;\n }\n }\n let error;\n while (batchedSub) {\n let e = batchedSub;\n batchedSub = void 0;\n while (e) {\n const next = e.next;\n e.next = void 0;\n e.flags &= -9;\n if (e.flags & 1) {\n try {\n ;\n e.trigger();\n } catch (err) {\n if (!error) error = err;\n }\n }\n e = next;\n }\n }\n if (error) throw error;\n}\nfunction prepareDeps(sub) {\n for (let link = sub.deps; link; link = link.nextDep) {\n link.version = -1;\n link.prevActiveLink = link.dep.activeLink;\n link.dep.activeLink = link;\n }\n}\nfunction cleanupDeps(sub) {\n let head;\n let tail = sub.depsTail;\n let link = tail;\n while (link) {\n const prev = link.prevDep;\n if (link.version === -1) {\n if (link === tail) tail = prev;\n removeSub(link);\n removeDep(link);\n } else {\n head = link;\n }\n link.dep.activeLink = link.prevActiveLink;\n link.prevActiveLink = void 0;\n link = prev;\n }\n sub.deps = head;\n sub.depsTail = tail;\n}\nfunction isDirty(sub) {\n for (let link = sub.deps; link; link = link.nextDep) {\n if (link.dep.version !== link.version || link.dep.computed && (refreshComputed(link.dep.computed) || link.dep.version !== link.version)) {\n return true;\n }\n }\n if (sub._dirty) {\n return true;\n }\n return false;\n}\nfunction refreshComputed(computed) {\n if (computed.flags & 4 && !(computed.flags & 16)) {\n return;\n }\n computed.flags &= -17;\n if (computed.globalVersion === globalVersion) {\n return;\n }\n computed.globalVersion = globalVersion;\n if (!computed.isSSR && computed.flags & 128 && (!computed.deps && !computed._dirty || !isDirty(computed))) {\n return;\n }\n computed.flags |= 2;\n const dep = computed.dep;\n const prevSub = activeSub;\n const prevShouldTrack = shouldTrack;\n activeSub = computed;\n shouldTrack = true;\n try {\n prepareDeps(computed);\n const value = computed.fn(computed._value);\n if (dep.version === 0 || hasChanged(value, computed._value)) {\n computed.flags |= 128;\n computed._value = value;\n dep.version++;\n }\n } catch (err) {\n dep.version++;\n throw err;\n } finally {\n activeSub = prevSub;\n shouldTrack = prevShouldTrack;\n cleanupDeps(computed);\n computed.flags &= -3;\n }\n}\nfunction removeSub(link, soft = false) {\n const { dep, prevSub, nextSub } = link;\n if (prevSub) {\n prevSub.nextSub = nextSub;\n link.prevSub = void 0;\n }\n if (nextSub) {\n nextSub.prevSub = prevSub;\n link.nextSub = void 0;\n }\n if (!!(process.env.NODE_ENV !== \"production\") && dep.subsHead === link) {\n dep.subsHead = nextSub;\n }\n if (dep.subs === link) {\n dep.subs = prevSub;\n if (!prevSub && dep.computed) {\n dep.computed.flags &= -5;\n for (let l = dep.computed.deps; l; l = l.nextDep) {\n removeSub(l, true);\n }\n }\n }\n if (!soft && !--dep.sc && dep.map) {\n dep.map.delete(dep.key);\n }\n}\nfunction removeDep(link) {\n const { prevDep, nextDep } = link;\n if (prevDep) {\n prevDep.nextDep = nextDep;\n link.prevDep = void 0;\n }\n if (nextDep) {\n nextDep.prevDep = prevDep;\n link.nextDep = void 0;\n }\n}\nfunction effect(fn, options) {\n if (fn.effect instanceof ReactiveEffect) {\n fn = fn.effect.fn;\n }\n const e = new ReactiveEffect(fn);\n if (options) {\n extend(e, options);\n }\n try {\n e.run();\n } catch (err) {\n e.stop();\n throw err;\n }\n const runner = e.run.bind(e);\n runner.effect = e;\n return runner;\n}\nfunction stop(runner) {\n runner.effect.stop();\n}\nlet shouldTrack = true;\nconst trackStack = [];\nfunction pauseTracking() {\n trackStack.push(shouldTrack);\n shouldTrack = false;\n}\nfunction enableTracking() {\n trackStack.push(shouldTrack);\n shouldTrack = true;\n}\nfunction resetTracking() {\n const last = trackStack.pop();\n shouldTrack = last === void 0 ? true : last;\n}\nfunction onEffectCleanup(fn, failSilently = false) {\n if (activeSub instanceof ReactiveEffect) {\n activeSub.cleanup = fn;\n } else if (!!(process.env.NODE_ENV !== \"production\") && !failSilently) {\n warn(\n `onEffectCleanup() was called when there was no active effect to associate with.`\n );\n }\n}\nfunction cleanupEffect(e) {\n const { cleanup } = e;\n e.cleanup = void 0;\n if (cleanup) {\n const prevSub = activeSub;\n activeSub = void 0;\n try {\n cleanup();\n } finally {\n activeSub = prevSub;\n }\n }\n}\n\nlet globalVersion = 0;\nclass Link {\n constructor(sub, dep) {\n this.sub = sub;\n this.dep = dep;\n this.version = dep.version;\n this.nextDep = this.prevDep = this.nextSub = this.prevSub = this.prevActiveLink = void 0;\n }\n}\nclass Dep {\n // TODO isolatedDeclarations \"__v_skip\"\n constructor(computed) {\n this.computed = computed;\n this.version = 0;\n /**\n * Link between this dep and the current active effect\n */\n this.activeLink = void 0;\n /**\n * Doubly linked list representing the subscribing effects (tail)\n */\n this.subs = void 0;\n /**\n * For object property deps cleanup\n */\n this.map = void 0;\n this.key = void 0;\n /**\n * Subscriber counter\n */\n this.sc = 0;\n /**\n * @internal\n */\n this.__v_skip = true;\n if (!!(process.env.NODE_ENV !== \"production\")) {\n this.subsHead = void 0;\n }\n }\n track(debugInfo) {\n if (!activeSub || !shouldTrack || activeSub === this.computed) {\n return;\n }\n let link = this.activeLink;\n if (link === void 0 || link.sub !== activeSub) {\n link = this.activeLink = new Link(activeSub, this);\n if (!activeSub.deps) {\n activeSub.deps = activeSub.depsTail = link;\n } else {\n link.prevDep = activeSub.depsTail;\n activeSub.depsTail.nextDep = link;\n activeSub.depsTail = link;\n }\n addSub(link);\n } else if (link.version === -1) {\n link.version = this.version;\n if (link.nextDep) {\n const next = link.nextDep;\n next.prevDep = link.prevDep;\n if (link.prevDep) {\n link.prevDep.nextDep = next;\n }\n link.prevDep = activeSub.depsTail;\n link.nextDep = void 0;\n activeSub.depsTail.nextDep = link;\n activeSub.depsTail = link;\n if (activeSub.deps === link) {\n activeSub.deps = next;\n }\n }\n }\n if (!!(process.env.NODE_ENV !== \"production\") && activeSub.onTrack) {\n activeSub.onTrack(\n extend(\n {\n effect: activeSub\n },\n debugInfo\n )\n );\n }\n return link;\n }\n trigger(debugInfo) {\n this.version++;\n globalVersion++;\n this.notify(debugInfo);\n }\n notify(debugInfo) {\n startBatch();\n try {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n for (let head = this.subsHead; head; head = head.nextSub) {\n if (head.sub.onTrigger && !(head.sub.flags & 8)) {\n head.sub.onTrigger(\n extend(\n {\n effect: head.sub\n },\n debugInfo\n )\n );\n }\n }\n }\n for (let link = this.subs; link; link = link.prevSub) {\n if (link.sub.notify()) {\n ;\n link.sub.dep.notify();\n }\n }\n } finally {\n endBatch();\n }\n }\n}\nfunction addSub(link) {\n link.dep.sc++;\n if (link.sub.flags & 4) {\n const computed = link.dep.computed;\n if (computed && !link.dep.subs) {\n computed.flags |= 4 | 16;\n for (let l = computed.deps; l; l = l.nextDep) {\n addSub(l);\n }\n }\n const currentTail = link.dep.subs;\n if (currentTail !== link) {\n link.prevSub = currentTail;\n if (currentTail) currentTail.nextSub = link;\n }\n if (!!(process.env.NODE_ENV !== \"production\") && link.dep.subsHead === void 0) {\n link.dep.subsHead = link;\n }\n link.dep.subs = link;\n }\n}\nconst targetMap = /* @__PURE__ */ new WeakMap();\nconst ITERATE_KEY = Symbol(\n !!(process.env.NODE_ENV !== \"production\") ? \"Object iterate\" : \"\"\n);\nconst MAP_KEY_ITERATE_KEY = Symbol(\n !!(process.env.NODE_ENV !== \"production\") ? \"Map keys iterate\" : \"\"\n);\nconst ARRAY_ITERATE_KEY = Symbol(\n !!(process.env.NODE_ENV !== \"production\") ? \"Array iterate\" : \"\"\n);\nfunction track(target, type, key) {\n if (shouldTrack && activeSub) {\n let depsMap = targetMap.get(target);\n if (!depsMap) {\n targetMap.set(target, depsMap = /* @__PURE__ */ new Map());\n }\n let dep = depsMap.get(key);\n if (!dep) {\n depsMap.set(key, dep = new Dep());\n dep.map = depsMap;\n dep.key = key;\n }\n if (!!(process.env.NODE_ENV !== \"production\")) {\n dep.track({\n target,\n type,\n key\n });\n } else {\n dep.track();\n }\n }\n}\nfunction trigger(target, type, key, newValue, oldValue, oldTarget) {\n const depsMap = targetMap.get(target);\n if (!depsMap) {\n globalVersion++;\n return;\n }\n const run = (dep) => {\n if (dep) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n dep.trigger({\n target,\n type,\n key,\n newValue,\n oldValue,\n oldTarget\n });\n } else {\n dep.trigger();\n }\n }\n };\n startBatch();\n if (type === \"clear\") {\n depsMap.forEach(run);\n } else {\n const targetIsArray = isArray(target);\n const isArrayIndex = targetIsArray && isIntegerKey(key);\n if (targetIsArray && key === \"length\") {\n const newLength = Number(newValue);\n depsMap.forEach((dep, key2) => {\n if (key2 === \"length\" || key2 === ARRAY_ITERATE_KEY || !isSymbol(key2) && key2 >= newLength) {\n run(dep);\n }\n });\n } else {\n if (key !== void 0 || depsMap.has(void 0)) {\n run(depsMap.get(key));\n }\n if (isArrayIndex) {\n run(depsMap.get(ARRAY_ITERATE_KEY));\n }\n switch (type) {\n case \"add\":\n if (!targetIsArray) {\n run(depsMap.get(ITERATE_KEY));\n if (isMap(target)) {\n run(depsMap.get(MAP_KEY_ITERATE_KEY));\n }\n } else if (isArrayIndex) {\n run(depsMap.get(\"length\"));\n }\n break;\n case \"delete\":\n if (!targetIsArray) {\n run(depsMap.get(ITERATE_KEY));\n if (isMap(target)) {\n run(depsMap.get(MAP_KEY_ITERATE_KEY));\n }\n }\n break;\n case \"set\":\n if (isMap(target)) {\n run(depsMap.get(ITERATE_KEY));\n }\n break;\n }\n }\n }\n endBatch();\n}\nfunction getDepFromReactive(object, key) {\n const depMap = targetMap.get(object);\n return depMap && depMap.get(key);\n}\n\nfunction reactiveReadArray(array) {\n const raw = toRaw(array);\n if (raw === array) return raw;\n track(raw, \"iterate\", ARRAY_ITERATE_KEY);\n return isShallow(array) ? raw : raw.map(toReactive);\n}\nfunction shallowReadArray(arr) {\n track(arr = toRaw(arr), \"iterate\", ARRAY_ITERATE_KEY);\n return arr;\n}\nfunction toWrapped(target, item) {\n if (isReadonly(target)) {\n return isReactive(target) ? toReadonly(toReactive(item)) : toReadonly(item);\n }\n return toReactive(item);\n}\nconst arrayInstrumentations = {\n __proto__: null,\n [Symbol.iterator]() {\n return iterator(this, Symbol.iterator, (item) => toWrapped(this, item));\n },\n concat(...args) {\n return reactiveReadArray(this).concat(\n ...args.map((x) => isArray(x) ? reactiveReadArray(x) : x)\n );\n },\n entries() {\n return iterator(this, \"entries\", (value) => {\n value[1] = toWrapped(this, value[1]);\n return value;\n });\n },\n every(fn, thisArg) {\n return apply(this, \"every\", fn, thisArg, void 0, arguments);\n },\n filter(fn, thisArg) {\n return apply(\n this,\n \"filter\",\n fn,\n thisArg,\n (v) => v.map((item) => toWrapped(this, item)),\n arguments\n );\n },\n find(fn, thisArg) {\n return apply(\n this,\n \"find\",\n fn,\n thisArg,\n (item) => toWrapped(this, item),\n arguments\n );\n },\n findIndex(fn, thisArg) {\n return apply(this, \"findIndex\", fn, thisArg, void 0, arguments);\n },\n findLast(fn, thisArg) {\n return apply(\n this,\n \"findLast\",\n fn,\n thisArg,\n (item) => toWrapped(this, item),\n arguments\n );\n },\n findLastIndex(fn, thisArg) {\n return apply(this, \"findLastIndex\", fn, thisArg, void 0, arguments);\n },\n // flat, flatMap could benefit from ARRAY_ITERATE but are not straight-forward to implement\n forEach(fn, thisArg) {\n return apply(this, \"forEach\", fn, thisArg, void 0, arguments);\n },\n includes(...args) {\n return searchProxy(this, \"includes\", args);\n },\n indexOf(...args) {\n return searchProxy(this, \"indexOf\", args);\n },\n join(separator) {\n return reactiveReadArray(this).join(separator);\n },\n // keys() iterator only reads `length`, no optimization required\n lastIndexOf(...args) {\n return searchProxy(this, \"lastIndexOf\", args);\n },\n map(fn, thisArg) {\n return apply(this, \"map\", fn, thisArg, void 0, arguments);\n },\n pop() {\n return noTracking(this, \"pop\");\n },\n push(...args) {\n return noTracking(this, \"push\", args);\n },\n reduce(fn, ...args) {\n return reduce(this, \"reduce\", fn, args);\n },\n reduceRight(fn, ...args) {\n return reduce(this, \"reduceRight\", fn, args);\n },\n shift() {\n return noTracking(this, \"shift\");\n },\n // slice could use ARRAY_ITERATE but also seems to beg for range tracking\n some(fn, thisArg) {\n return apply(this, \"some\", fn, thisArg, void 0, arguments);\n },\n splice(...args) {\n return noTracking(this, \"splice\", args);\n },\n toReversed() {\n return reactiveReadArray(this).toReversed();\n },\n toSorted(comparer) {\n return reactiveReadArray(this).toSorted(comparer);\n },\n toSpliced(...args) {\n return reactiveReadArray(this).toSpliced(...args);\n },\n unshift(...args) {\n return noTracking(this, \"unshift\", args);\n },\n values() {\n return iterator(this, \"values\", (item) => toWrapped(this, item));\n }\n};\nfunction iterator(self, method, wrapValue) {\n const arr = shallowReadArray(self);\n const iter = arr[method]();\n if (arr !== self && !isShallow(self)) {\n iter._next = iter.next;\n iter.next = () => {\n const result = iter._next();\n if (!result.done) {\n result.value = wrapValue(result.value);\n }\n return result;\n };\n }\n return iter;\n}\nconst arrayProto = Array.prototype;\nfunction apply(self, method, fn, thisArg, wrappedRetFn, args) {\n const arr = shallowReadArray(self);\n const needsWrap = arr !== self && !isShallow(self);\n const methodFn = arr[method];\n if (methodFn !== arrayProto[method]) {\n const result2 = methodFn.apply(self, args);\n return needsWrap ? toReactive(result2) : result2;\n }\n let wrappedFn = fn;\n if (arr !== self) {\n if (needsWrap) {\n wrappedFn = function(item, index) {\n return fn.call(this, toWrapped(self, item), index, self);\n };\n } else if (fn.length > 2) {\n wrappedFn = function(item, index) {\n return fn.call(this, item, index, self);\n };\n }\n }\n const result = methodFn.call(arr, wrappedFn, thisArg);\n return needsWrap && wrappedRetFn ? wrappedRetFn(result) : result;\n}\nfunction reduce(self, method, fn, args) {\n const arr = shallowReadArray(self);\n let wrappedFn = fn;\n if (arr !== self) {\n if (!isShallow(self)) {\n wrappedFn = function(acc, item, index) {\n return fn.call(this, acc, toWrapped(self, item), index, self);\n };\n } else if (fn.length > 3) {\n wrappedFn = function(acc, item, index) {\n return fn.call(this, acc, item, index, self);\n };\n }\n }\n return arr[method](wrappedFn, ...args);\n}\nfunction searchProxy(self, method, args) {\n const arr = toRaw(self);\n track(arr, \"iterate\", ARRAY_ITERATE_KEY);\n const res = arr[method](...args);\n if ((res === -1 || res === false) && isProxy(args[0])) {\n args[0] = toRaw(args[0]);\n return arr[method](...args);\n }\n return res;\n}\nfunction noTracking(self, method, args = []) {\n pauseTracking();\n startBatch();\n const res = toRaw(self)[method].apply(self, args);\n endBatch();\n resetTracking();\n return res;\n}\n\nconst isNonTrackableKeys = /* @__PURE__ */ makeMap(`__proto__,__v_isRef,__isVue`);\nconst builtInSymbols = new Set(\n /* @__PURE__ */ Object.getOwnPropertyNames(Symbol).filter((key) => key !== \"arguments\" && key !== \"caller\").map((key) => Symbol[key]).filter(isSymbol)\n);\nfunction hasOwnProperty(key) {\n if (!isSymbol(key)) key = String(key);\n const obj = toRaw(this);\n track(obj, \"has\", key);\n return obj.hasOwnProperty(key);\n}\nclass BaseReactiveHandler {\n constructor(_isReadonly = false, _isShallow = false) {\n this._isReadonly = _isReadonly;\n this._isShallow = _isShallow;\n }\n get(target, key, receiver) {\n if (key === \"__v_skip\") return target[\"__v_skip\"];\n const isReadonly2 = this._isReadonly, isShallow2 = this._isShallow;\n if (key === \"__v_isReactive\") {\n return !isReadonly2;\n } else if (key === \"__v_isReadonly\") {\n return isReadonly2;\n } else if (key === \"__v_isShallow\") {\n return isShallow2;\n } else if (key === \"__v_raw\") {\n if (receiver === (isReadonly2 ? isShallow2 ? shallowReadonlyMap : readonlyMap : isShallow2 ? shallowReactiveMap : reactiveMap).get(target) || // receiver is not the reactive proxy, but has the same prototype\n // this means the receiver is a user proxy of the reactive proxy\n Object.getPrototypeOf(target) === Object.getPrototypeOf(receiver)) {\n return target;\n }\n return;\n }\n const targetIsArray = isArray(target);\n if (!isReadonly2) {\n let fn;\n if (targetIsArray && (fn = arrayInstrumentations[key])) {\n return fn;\n }\n if (key === \"hasOwnProperty\") {\n return hasOwnProperty;\n }\n }\n const res = Reflect.get(\n target,\n key,\n // if this is a proxy wrapping a ref, return methods using the raw ref\n // as receiver so that we don't have to call `toRaw` on the ref in all\n // its class methods\n isRef(target) ? target : receiver\n );\n if (isSymbol(key) ? builtInSymbols.has(key) : isNonTrackableKeys(key)) {\n return res;\n }\n if (!isReadonly2) {\n track(target, \"get\", key);\n }\n if (isShallow2) {\n return res;\n }\n if (isRef(res)) {\n const value = targetIsArray && isIntegerKey(key) ? res : res.value;\n return isReadonly2 && isObject(value) ? readonly(value) : value;\n }\n if (isObject(res)) {\n return isReadonly2 ? readonly(res) : reactive(res);\n }\n return res;\n }\n}\nclass MutableReactiveHandler extends BaseReactiveHandler {\n constructor(isShallow2 = false) {\n super(false, isShallow2);\n }\n set(target, key, value, receiver) {\n let oldValue = target[key];\n const isArrayWithIntegerKey = isArray(target) && isIntegerKey(key);\n if (!this._isShallow) {\n const isOldValueReadonly = isReadonly(oldValue);\n if (!isShallow(value) && !isReadonly(value)) {\n oldValue = toRaw(oldValue);\n value = toRaw(value);\n }\n if (!isArrayWithIntegerKey && isRef(oldValue) && !isRef(value)) {\n if (isOldValueReadonly) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warn(\n `Set operation on key \"${String(key)}\" failed: target is readonly.`,\n target[key]\n );\n }\n return true;\n } else {\n oldValue.value = value;\n return true;\n }\n }\n }\n const hadKey = isArrayWithIntegerKey ? Number(key) < target.length : hasOwn(target, key);\n const result = Reflect.set(\n target,\n key,\n value,\n isRef(target) ? target : receiver\n );\n if (target === toRaw(receiver)) {\n if (!hadKey) {\n trigger(target, \"add\", key, value);\n } else if (hasChanged(value, oldValue)) {\n trigger(target, \"set\", key, value, oldValue);\n }\n }\n return result;\n }\n deleteProperty(target, key) {\n const hadKey = hasOwn(target, key);\n const oldValue = target[key];\n const result = Reflect.deleteProperty(target, key);\n if (result && hadKey) {\n trigger(target, \"delete\", key, void 0, oldValue);\n }\n return result;\n }\n has(target, key) {\n const result = Reflect.has(target, key);\n if (!isSymbol(key) || !builtInSymbols.has(key)) {\n track(target, \"has\", key);\n }\n return result;\n }\n ownKeys(target) {\n track(\n target,\n \"iterate\",\n isArray(target) ? \"length\" : ITERATE_KEY\n );\n return Reflect.ownKeys(target);\n }\n}\nclass ReadonlyReactiveHandler extends BaseReactiveHandler {\n constructor(isShallow2 = false) {\n super(true, isShallow2);\n }\n set(target, key) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warn(\n `Set operation on key \"${String(key)}\" failed: target is readonly.`,\n target\n );\n }\n return true;\n }\n deleteProperty(target, key) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warn(\n `Delete operation on key \"${String(key)}\" failed: target is readonly.`,\n target\n );\n }\n return true;\n }\n}\nconst mutableHandlers = /* @__PURE__ */ new MutableReactiveHandler();\nconst readonlyHandlers = /* @__PURE__ */ new ReadonlyReactiveHandler();\nconst shallowReactiveHandlers = /* @__PURE__ */ new MutableReactiveHandler(true);\nconst shallowReadonlyHandlers = /* @__PURE__ */ new ReadonlyReactiveHandler(true);\n\nconst toShallow = (value) => value;\nconst getProto = (v) => Reflect.getPrototypeOf(v);\nfunction createIterableMethod(method, isReadonly2, isShallow2) {\n return function(...args) {\n const target = this[\"__v_raw\"];\n const rawTarget = toRaw(target);\n const targetIsMap = isMap(rawTarget);\n const isPair = method === \"entries\" || method === Symbol.iterator && targetIsMap;\n const isKeyOnly = method === \"keys\" && targetIsMap;\n const innerIterator = target[method](...args);\n const wrap = isShallow2 ? toShallow : isReadonly2 ? toReadonly : toReactive;\n !isReadonly2 && track(\n rawTarget,\n \"iterate\",\n isKeyOnly ? MAP_KEY_ITERATE_KEY : ITERATE_KEY\n );\n return {\n // iterator protocol\n next() {\n const { value, done } = innerIterator.next();\n return done ? { value, done } : {\n value: isPair ? [wrap(value[0]), wrap(value[1])] : wrap(value),\n done\n };\n },\n // iterable protocol\n [Symbol.iterator]() {\n return this;\n }\n };\n };\n}\nfunction createReadonlyMethod(type) {\n return function(...args) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n const key = args[0] ? `on key \"${args[0]}\" ` : ``;\n warn(\n `${capitalize(type)} operation ${key}failed: target is readonly.`,\n toRaw(this)\n );\n }\n return type === \"delete\" ? false : type === \"clear\" ? void 0 : this;\n };\n}\nfunction createInstrumentations(readonly, shallow) {\n const instrumentations = {\n get(key) {\n const target = this[\"__v_raw\"];\n const rawTarget = toRaw(target);\n const rawKey = toRaw(key);\n if (!readonly) {\n if (hasChanged(key, rawKey)) {\n track(rawTarget, \"get\", key);\n }\n track(rawTarget, \"get\", rawKey);\n }\n const { has } = getProto(rawTarget);\n const wrap = shallow ? toShallow : readonly ? toReadonly : toReactive;\n if (has.call(rawTarget, key)) {\n return wrap(target.get(key));\n } else if (has.call(rawTarget, rawKey)) {\n return wrap(target.get(rawKey));\n } else if (target !== rawTarget) {\n target.get(key);\n }\n },\n get size() {\n const target = this[\"__v_raw\"];\n !readonly && track(toRaw(target), \"iterate\", ITERATE_KEY);\n return target.size;\n },\n has(key) {\n const target = this[\"__v_raw\"];\n const rawTarget = toRaw(target);\n const rawKey = toRaw(key);\n if (!readonly) {\n if (hasChanged(key, rawKey)) {\n track(rawTarget, \"has\", key);\n }\n track(rawTarget, \"has\", rawKey);\n }\n return key === rawKey ? target.has(key) : target.has(key) || target.has(rawKey);\n },\n forEach(callback, thisArg) {\n const observed = this;\n const target = observed[\"__v_raw\"];\n const rawTarget = toRaw(target);\n const wrap = shallow ? toShallow : readonly ? toReadonly : toReactive;\n !readonly && track(rawTarget, \"iterate\", ITERATE_KEY);\n return target.forEach((value, key) => {\n return callback.call(thisArg, wrap(value), wrap(key), observed);\n });\n }\n };\n extend(\n instrumentations,\n readonly ? {\n add: createReadonlyMethod(\"add\"),\n set: createReadonlyMethod(\"set\"),\n delete: createReadonlyMethod(\"delete\"),\n clear: createReadonlyMethod(\"clear\")\n } : {\n add(value) {\n if (!shallow && !isShallow(value) && !isReadonly(value)) {\n value = toRaw(value);\n }\n const target = toRaw(this);\n const proto = getProto(target);\n const hadKey = proto.has.call(target, value);\n if (!hadKey) {\n target.add(value);\n trigger(target, \"add\", value, value);\n }\n return this;\n },\n set(key, value) {\n if (!shallow && !isShallow(value) && !isReadonly(value)) {\n value = toRaw(value);\n }\n const target = toRaw(this);\n const { has, get } = getProto(target);\n let hadKey = has.call(target, key);\n if (!hadKey) {\n key = toRaw(key);\n hadKey = has.call(target, key);\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n checkIdentityKeys(target, has, key);\n }\n const oldValue = get.call(target, key);\n target.set(key, value);\n if (!hadKey) {\n trigger(target, \"add\", key, value);\n } else if (hasChanged(value, oldValue)) {\n trigger(target, \"set\", key, value, oldValue);\n }\n return this;\n },\n delete(key) {\n const target = toRaw(this);\n const { has, get } = getProto(target);\n let hadKey = has.call(target, key);\n if (!hadKey) {\n key = toRaw(key);\n hadKey = has.call(target, key);\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n checkIdentityKeys(target, has, key);\n }\n const oldValue = get ? get.call(target, key) : void 0;\n const result = target.delete(key);\n if (hadKey) {\n trigger(target, \"delete\", key, void 0, oldValue);\n }\n return result;\n },\n clear() {\n const target = toRaw(this);\n const hadItems = target.size !== 0;\n const oldTarget = !!(process.env.NODE_ENV !== \"production\") ? isMap(target) ? new Map(target) : new Set(target) : void 0;\n const result = target.clear();\n if (hadItems) {\n trigger(\n target,\n \"clear\",\n void 0,\n void 0,\n oldTarget\n );\n }\n return result;\n }\n }\n );\n const iteratorMethods = [\n \"keys\",\n \"values\",\n \"entries\",\n Symbol.iterator\n ];\n iteratorMethods.forEach((method) => {\n instrumentations[method] = createIterableMethod(method, readonly, shallow);\n });\n return instrumentations;\n}\nfunction createInstrumentationGetter(isReadonly2, shallow) {\n const instrumentations = createInstrumentations(isReadonly2, shallow);\n return (target, key, receiver) => {\n if (key === \"__v_isReactive\") {\n return !isReadonly2;\n } else if (key === \"__v_isReadonly\") {\n return isReadonly2;\n } else if (key === \"__v_raw\") {\n return target;\n }\n return Reflect.get(\n hasOwn(instrumentations, key) && key in target ? instrumentations : target,\n key,\n receiver\n );\n };\n}\nconst mutableCollectionHandlers = {\n get: /* @__PURE__ */ createInstrumentationGetter(false, false)\n};\nconst shallowCollectionHandlers = {\n get: /* @__PURE__ */ createInstrumentationGetter(false, true)\n};\nconst readonlyCollectionHandlers = {\n get: /* @__PURE__ */ createInstrumentationGetter(true, false)\n};\nconst shallowReadonlyCollectionHandlers = {\n get: /* @__PURE__ */ createInstrumentationGetter(true, true)\n};\nfunction checkIdentityKeys(target, has, key) {\n const rawKey = toRaw(key);\n if (rawKey !== key && has.call(target, rawKey)) {\n const type = toRawType(target);\n warn(\n `Reactive ${type} contains both the raw and reactive versions of the same object${type === `Map` ? ` as keys` : ``}, which can lead to inconsistencies. Avoid differentiating between the raw and reactive versions of an object and only use the reactive version if possible.`\n );\n }\n}\n\nconst reactiveMap = /* @__PURE__ */ new WeakMap();\nconst shallowReactiveMap = /* @__PURE__ */ new WeakMap();\nconst readonlyMap = /* @__PURE__ */ new WeakMap();\nconst shallowReadonlyMap = /* @__PURE__ */ new WeakMap();\nfunction targetTypeMap(rawType) {\n switch (rawType) {\n case \"Object\":\n case \"Array\":\n return 1 /* COMMON */;\n case \"Map\":\n case \"Set\":\n case \"WeakMap\":\n case \"WeakSet\":\n return 2 /* COLLECTION */;\n default:\n return 0 /* INVALID */;\n }\n}\nfunction getTargetType(value) {\n return value[\"__v_skip\"] || !Object.isExtensible(value) ? 0 /* INVALID */ : targetTypeMap(toRawType(value));\n}\nfunction reactive(target) {\n if (isReadonly(target)) {\n return target;\n }\n return createReactiveObject(\n target,\n false,\n mutableHandlers,\n mutableCollectionHandlers,\n reactiveMap\n );\n}\nfunction shallowReactive(target) {\n return createReactiveObject(\n target,\n false,\n shallowReactiveHandlers,\n shallowCollectionHandlers,\n shallowReactiveMap\n );\n}\nfunction readonly(target) {\n return createReactiveObject(\n target,\n true,\n readonlyHandlers,\n readonlyCollectionHandlers,\n readonlyMap\n );\n}\nfunction shallowReadonly(target) {\n return createReactiveObject(\n target,\n true,\n shallowReadonlyHandlers,\n shallowReadonlyCollectionHandlers,\n shallowReadonlyMap\n );\n}\nfunction createReactiveObject(target, isReadonly2, baseHandlers, collectionHandlers, proxyMap) {\n if (!isObject(target)) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warn(\n `value cannot be made ${isReadonly2 ? \"readonly\" : \"reactive\"}: ${String(\n target\n )}`\n );\n }\n return target;\n }\n if (target[\"__v_raw\"] && !(isReadonly2 && target[\"__v_isReactive\"])) {\n return target;\n }\n const targetType = getTargetType(target);\n if (targetType === 0 /* INVALID */) {\n return target;\n }\n const existingProxy = proxyMap.get(target);\n if (existingProxy) {\n return existingProxy;\n }\n const proxy = new Proxy(\n target,\n targetType === 2 /* COLLECTION */ ? collectionHandlers : baseHandlers\n );\n proxyMap.set(target, proxy);\n return proxy;\n}\nfunction isReactive(value) {\n if (isReadonly(value)) {\n return isReactive(value[\"__v_raw\"]);\n }\n return !!(value && value[\"__v_isReactive\"]);\n}\nfunction isReadonly(value) {\n return !!(value && value[\"__v_isReadonly\"]);\n}\nfunction isShallow(value) {\n return !!(value && value[\"__v_isShallow\"]);\n}\nfunction isProxy(value) {\n return value ? !!value[\"__v_raw\"] : false;\n}\nfunction toRaw(observed) {\n const raw = observed && observed[\"__v_raw\"];\n return raw ? toRaw(raw) : observed;\n}\nfunction markRaw(value) {\n if (!hasOwn(value, \"__v_skip\") && Object.isExtensible(value)) {\n def(value, \"__v_skip\", true);\n }\n return value;\n}\nconst toReactive = (value) => isObject(value) ? reactive(value) : value;\nconst toReadonly = (value) => isObject(value) ? readonly(value) : value;\n\nfunction isRef(r) {\n return r ? r[\"__v_isRef\"] === true : false;\n}\nfunction ref(value) {\n return createRef(value, false);\n}\nfunction shallowRef(value) {\n return createRef(value, true);\n}\nfunction createRef(rawValue, shallow) {\n if (isRef(rawValue)) {\n return rawValue;\n }\n return new RefImpl(rawValue, shallow);\n}\nclass RefImpl {\n constructor(value, isShallow2) {\n this.dep = new Dep();\n this[\"__v_isRef\"] = true;\n this[\"__v_isShallow\"] = false;\n this._rawValue = isShallow2 ? value : toRaw(value);\n this._value = isShallow2 ? value : toReactive(value);\n this[\"__v_isShallow\"] = isShallow2;\n }\n get value() {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n this.dep.track({\n target: this,\n type: \"get\",\n key: \"value\"\n });\n } else {\n this.dep.track();\n }\n return this._value;\n }\n set value(newValue) {\n const oldValue = this._rawValue;\n const useDirectValue = this[\"__v_isShallow\"] || isShallow(newValue) || isReadonly(newValue);\n newValue = useDirectValue ? newValue : toRaw(newValue);\n if (hasChanged(newValue, oldValue)) {\n this._rawValue = newValue;\n this._value = useDirectValue ? newValue : toReactive(newValue);\n if (!!(process.env.NODE_ENV !== \"production\")) {\n this.dep.trigger({\n target: this,\n type: \"set\",\n key: \"value\",\n newValue,\n oldValue\n });\n } else {\n this.dep.trigger();\n }\n }\n }\n}\nfunction triggerRef(ref2) {\n if (ref2.dep) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n ref2.dep.trigger({\n target: ref2,\n type: \"set\",\n key: \"value\",\n newValue: ref2._value\n });\n } else {\n ref2.dep.trigger();\n }\n }\n}\nfunction unref(ref2) {\n return isRef(ref2) ? ref2.value : ref2;\n}\nfunction toValue(source) {\n return isFunction(source) ? source() : unref(source);\n}\nconst shallowUnwrapHandlers = {\n get: (target, key, receiver) => key === \"__v_raw\" ? target : unref(Reflect.get(target, key, receiver)),\n set: (target, key, value, receiver) => {\n const oldValue = target[key];\n if (isRef(oldValue) && !isRef(value)) {\n oldValue.value = value;\n return true;\n } else {\n return Reflect.set(target, key, value, receiver);\n }\n }\n};\nfunction proxyRefs(objectWithRefs) {\n return isReactive(objectWithRefs) ? objectWithRefs : new Proxy(objectWithRefs, shallowUnwrapHandlers);\n}\nclass CustomRefImpl {\n constructor(factory) {\n this[\"__v_isRef\"] = true;\n this._value = void 0;\n const dep = this.dep = new Dep();\n const { get, set } = factory(dep.track.bind(dep), dep.trigger.bind(dep));\n this._get = get;\n this._set = set;\n }\n get value() {\n return this._value = this._get();\n }\n set value(newVal) {\n this._set(newVal);\n }\n}\nfunction customRef(factory) {\n return new CustomRefImpl(factory);\n}\nfunction toRefs(object) {\n if (!!(process.env.NODE_ENV !== \"production\") && !isProxy(object)) {\n warn(`toRefs() expects a reactive object but received a plain one.`);\n }\n const ret = isArray(object) ? new Array(object.length) : {};\n for (const key in object) {\n ret[key] = propertyToRef(object, key);\n }\n return ret;\n}\nclass ObjectRefImpl {\n constructor(_object, _key, _defaultValue) {\n this._object = _object;\n this._key = _key;\n this._defaultValue = _defaultValue;\n this[\"__v_isRef\"] = true;\n this._value = void 0;\n this._raw = toRaw(_object);\n let shallow = true;\n let obj = _object;\n if (!isArray(_object) || !isIntegerKey(String(_key))) {\n do {\n shallow = !isProxy(obj) || isShallow(obj);\n } while (shallow && (obj = obj[\"__v_raw\"]));\n }\n this._shallow = shallow;\n }\n get value() {\n let val = this._object[this._key];\n if (this._shallow) {\n val = unref(val);\n }\n return this._value = val === void 0 ? this._defaultValue : val;\n }\n set value(newVal) {\n if (this._shallow && isRef(this._raw[this._key])) {\n const nestedRef = this._object[this._key];\n if (isRef(nestedRef)) {\n nestedRef.value = newVal;\n return;\n }\n }\n this._object[this._key] = newVal;\n }\n get dep() {\n return getDepFromReactive(this._raw, this._key);\n }\n}\nclass GetterRefImpl {\n constructor(_getter) {\n this._getter = _getter;\n this[\"__v_isRef\"] = true;\n this[\"__v_isReadonly\"] = true;\n this._value = void 0;\n }\n get value() {\n return this._value = this._getter();\n }\n}\nfunction toRef(source, key, defaultValue) {\n if (isRef(source)) {\n return source;\n } else if (isFunction(source)) {\n return new GetterRefImpl(source);\n } else if (isObject(source) && arguments.length > 1) {\n return propertyToRef(source, key, defaultValue);\n } else {\n return ref(source);\n }\n}\nfunction propertyToRef(source, key, defaultValue) {\n return new ObjectRefImpl(source, key, defaultValue);\n}\n\nclass ComputedRefImpl {\n constructor(fn, setter, isSSR) {\n this.fn = fn;\n this.setter = setter;\n /**\n * @internal\n */\n this._value = void 0;\n /**\n * @internal\n */\n this.dep = new Dep(this);\n /**\n * @internal\n */\n this.__v_isRef = true;\n // TODO isolatedDeclarations \"__v_isReadonly\"\n // A computed is also a subscriber that tracks other deps\n /**\n * @internal\n */\n this.deps = void 0;\n /**\n * @internal\n */\n this.depsTail = void 0;\n /**\n * @internal\n */\n this.flags = 16;\n /**\n * @internal\n */\n this.globalVersion = globalVersion - 1;\n /**\n * @internal\n */\n this.next = void 0;\n // for backwards compat\n this.effect = this;\n this[\"__v_isReadonly\"] = !setter;\n this.isSSR = isSSR;\n }\n /**\n * @internal\n */\n notify() {\n this.flags |= 16;\n if (!(this.flags & 8) && // avoid infinite self recursion\n activeSub !== this) {\n batch(this, true);\n return true;\n } else if (!!(process.env.NODE_ENV !== \"production\")) ;\n }\n get value() {\n const link = !!(process.env.NODE_ENV !== \"production\") ? this.dep.track({\n target: this,\n type: \"get\",\n key: \"value\"\n }) : this.dep.track();\n refreshComputed(this);\n if (link) {\n link.version = this.dep.version;\n }\n return this._value;\n }\n set value(newValue) {\n if (this.setter) {\n this.setter(newValue);\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn(\"Write operation failed: computed value is readonly\");\n }\n }\n}\nfunction computed(getterOrOptions, debugOptions, isSSR = false) {\n let getter;\n let setter;\n if (isFunction(getterOrOptions)) {\n getter = getterOrOptions;\n } else {\n getter = getterOrOptions.get;\n setter = getterOrOptions.set;\n }\n const cRef = new ComputedRefImpl(getter, setter, isSSR);\n if (!!(process.env.NODE_ENV !== \"production\") && debugOptions && !isSSR) {\n cRef.onTrack = debugOptions.onTrack;\n cRef.onTrigger = debugOptions.onTrigger;\n }\n return cRef;\n}\n\nconst TrackOpTypes = {\n \"GET\": \"get\",\n \"HAS\": \"has\",\n \"ITERATE\": \"iterate\"\n};\nconst TriggerOpTypes = {\n \"SET\": \"set\",\n \"ADD\": \"add\",\n \"DELETE\": \"delete\",\n \"CLEAR\": \"clear\"\n};\nconst ReactiveFlags = {\n \"SKIP\": \"__v_skip\",\n \"IS_REACTIVE\": \"__v_isReactive\",\n \"IS_READONLY\": \"__v_isReadonly\",\n \"IS_SHALLOW\": \"__v_isShallow\",\n \"RAW\": \"__v_raw\",\n \"IS_REF\": \"__v_isRef\"\n};\n\nconst WatchErrorCodes = {\n \"WATCH_GETTER\": 2,\n \"2\": \"WATCH_GETTER\",\n \"WATCH_CALLBACK\": 3,\n \"3\": \"WATCH_CALLBACK\",\n \"WATCH_CLEANUP\": 4,\n \"4\": \"WATCH_CLEANUP\"\n};\nconst INITIAL_WATCHER_VALUE = {};\nconst cleanupMap = /* @__PURE__ */ new WeakMap();\nlet activeWatcher = void 0;\nfunction getCurrentWatcher() {\n return activeWatcher;\n}\nfunction onWatcherCleanup(cleanupFn, failSilently = false, owner = activeWatcher) {\n if (owner) {\n let cleanups = cleanupMap.get(owner);\n if (!cleanups) cleanupMap.set(owner, cleanups = []);\n cleanups.push(cleanupFn);\n } else if (!!(process.env.NODE_ENV !== \"production\") && !failSilently) {\n warn(\n `onWatcherCleanup() was called when there was no active watcher to associate with.`\n );\n }\n}\nfunction watch(source, cb, options = EMPTY_OBJ) {\n const { immediate, deep, once, scheduler, augmentJob, call } = options;\n const warnInvalidSource = (s) => {\n (options.onWarn || warn)(\n `Invalid watch source: `,\n s,\n `A watch source can only be a getter/effect function, a ref, a reactive object, or an array of these types.`\n );\n };\n const reactiveGetter = (source2) => {\n if (deep) return source2;\n if (isShallow(source2) || deep === false || deep === 0)\n return traverse(source2, 1);\n return traverse(source2);\n };\n let effect;\n let getter;\n let cleanup;\n let boundCleanup;\n let forceTrigger = false;\n let isMultiSource = false;\n if (isRef(source)) {\n getter = () => source.value;\n forceTrigger = isShallow(source);\n } else if (isReactive(source)) {\n getter = () => reactiveGetter(source);\n forceTrigger = true;\n } else if (isArray(source)) {\n isMultiSource = true;\n forceTrigger = source.some((s) => isReactive(s) || isShallow(s));\n getter = () => source.map((s) => {\n if (isRef(s)) {\n return s.value;\n } else if (isReactive(s)) {\n return reactiveGetter(s);\n } else if (isFunction(s)) {\n return call ? call(s, 2) : s();\n } else {\n !!(process.env.NODE_ENV !== \"production\") && warnInvalidSource(s);\n }\n });\n } else if (isFunction(source)) {\n if (cb) {\n getter = call ? () => call(source, 2) : source;\n } else {\n getter = () => {\n if (cleanup) {\n pauseTracking();\n try {\n cleanup();\n } finally {\n resetTracking();\n }\n }\n const currentEffect = activeWatcher;\n activeWatcher = effect;\n try {\n return call ? call(source, 3, [boundCleanup]) : source(boundCleanup);\n } finally {\n activeWatcher = currentEffect;\n }\n };\n }\n } else {\n getter = NOOP;\n !!(process.env.NODE_ENV !== \"production\") && warnInvalidSource(source);\n }\n if (cb && deep) {\n const baseGetter = getter;\n const depth = deep === true ? Infinity : deep;\n getter = () => traverse(baseGetter(), depth);\n }\n const scope = getCurrentScope();\n const watchHandle = () => {\n effect.stop();\n if (scope && scope.active) {\n remove(scope.effects, effect);\n }\n };\n if (once && cb) {\n const _cb = cb;\n cb = (...args) => {\n _cb(...args);\n watchHandle();\n };\n }\n let oldValue = isMultiSource ? new Array(source.length).fill(INITIAL_WATCHER_VALUE) : INITIAL_WATCHER_VALUE;\n const job = (immediateFirstRun) => {\n if (!(effect.flags & 1) || !effect.dirty && !immediateFirstRun) {\n return;\n }\n if (cb) {\n const newValue = effect.run();\n if (deep || forceTrigger || (isMultiSource ? newValue.some((v, i) => hasChanged(v, oldValue[i])) : hasChanged(newValue, oldValue))) {\n if (cleanup) {\n cleanup();\n }\n const currentWatcher = activeWatcher;\n activeWatcher = effect;\n try {\n const args = [\n newValue,\n // pass undefined as the old value when it's changed for the first time\n oldValue === INITIAL_WATCHER_VALUE ? void 0 : isMultiSource && oldValue[0] === INITIAL_WATCHER_VALUE ? [] : oldValue,\n boundCleanup\n ];\n oldValue = newValue;\n call ? call(cb, 3, args) : (\n // @ts-expect-error\n cb(...args)\n );\n } finally {\n activeWatcher = currentWatcher;\n }\n }\n } else {\n effect.run();\n }\n };\n if (augmentJob) {\n augmentJob(job);\n }\n effect = new ReactiveEffect(getter);\n effect.scheduler = scheduler ? () => scheduler(job, false) : job;\n boundCleanup = (fn) => onWatcherCleanup(fn, false, effect);\n cleanup = effect.onStop = () => {\n const cleanups = cleanupMap.get(effect);\n if (cleanups) {\n if (call) {\n call(cleanups, 4);\n } else {\n for (const cleanup2 of cleanups) cleanup2();\n }\n cleanupMap.delete(effect);\n }\n };\n if (!!(process.env.NODE_ENV !== \"production\")) {\n effect.onTrack = options.onTrack;\n effect.onTrigger = options.onTrigger;\n }\n if (cb) {\n if (immediate) {\n job(true);\n } else {\n oldValue = effect.run();\n }\n } else if (scheduler) {\n scheduler(job.bind(null, true), true);\n } else {\n effect.run();\n }\n watchHandle.pause = effect.pause.bind(effect);\n watchHandle.resume = effect.resume.bind(effect);\n watchHandle.stop = watchHandle;\n return watchHandle;\n}\nfunction traverse(value, depth = Infinity, seen) {\n if (depth <= 0 || !isObject(value) || value[\"__v_skip\"]) {\n return value;\n }\n seen = seen || /* @__PURE__ */ new Map();\n if ((seen.get(value) || 0) >= depth) {\n return value;\n }\n seen.set(value, depth);\n depth--;\n if (isRef(value)) {\n traverse(value.value, depth, seen);\n } else if (isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n traverse(value[i], depth, seen);\n }\n } else if (isSet(value) || isMap(value)) {\n value.forEach((v) => {\n traverse(v, depth, seen);\n });\n } else if (isPlainObject(value)) {\n for (const key in value) {\n traverse(value[key], depth, seen);\n }\n for (const key of Object.getOwnPropertySymbols(value)) {\n if (Object.prototype.propertyIsEnumerable.call(value, key)) {\n traverse(value[key], depth, seen);\n }\n }\n }\n return value;\n}\n\nexport { ARRAY_ITERATE_KEY, EffectFlags, EffectScope, ITERATE_KEY, MAP_KEY_ITERATE_KEY, ReactiveEffect, ReactiveFlags, TrackOpTypes, TriggerOpTypes, WatchErrorCodes, computed, customRef, effect, effectScope, enableTracking, getCurrentScope, getCurrentWatcher, isProxy, isReactive, isReadonly, isRef, isShallow, markRaw, onEffectCleanup, onScopeDispose, onWatcherCleanup, pauseTracking, proxyRefs, reactive, reactiveReadArray, readonly, ref, resetTracking, shallowReactive, shallowReadArray, shallowReadonly, shallowRef, stop, toRaw, toReactive, toReadonly, toRef, toRefs, toValue, track, traverse, trigger, triggerRef, unref, watch };\n",
7
- "/**\n* @vue/runtime-core v3.5.25\n* (c) 2018-present Yuxi (Evan) You and Vue contributors\n* @license MIT\n**/\nimport { pauseTracking, resetTracking, isRef, toRaw, traverse, shallowRef, readonly, isReactive, ref, isShallow, isReadonly, shallowReadArray, toReadonly, toReactive, shallowReadonly, track, reactive, watch as watch$1, customRef, shallowReactive, trigger, ReactiveEffect, isProxy, proxyRefs, markRaw, EffectScope, computed as computed$1 } from '@vue/reactivity';\nexport { EffectScope, ReactiveEffect, TrackOpTypes, TriggerOpTypes, customRef, effect, effectScope, getCurrentScope, getCurrentWatcher, isProxy, isReactive, isReadonly, isRef, isShallow, markRaw, onScopeDispose, onWatcherCleanup, proxyRefs, reactive, readonly, ref, shallowReactive, shallowReadonly, shallowRef, stop, toRaw, toRef, toRefs, toValue, triggerRef, unref } from '@vue/reactivity';\nimport { isString, isFunction, EMPTY_OBJ, isPromise, isArray, NOOP, getGlobalThis, extend, isBuiltInDirective, NO, hasOwn, remove, def, isOn, isReservedProp, normalizeClass, stringifyStyle, normalizeStyle, isKnownSvgAttr, isBooleanAttr, isKnownHtmlAttr, includeBooleanAttr, isRenderableAttrValue, normalizeCssVarValue, getEscapedCssVarName, isObject, isRegExp, invokeArrayFns, toHandlerKey, camelize, capitalize, isSymbol, isGloballyAllowed, hyphenate, hasChanged, looseToNumber, isModelListener, EMPTY_ARR, makeMap, toRawType, toNumber } from '@vue/shared';\nexport { camelize, capitalize, normalizeClass, normalizeProps, normalizeStyle, toDisplayString, toHandlerKey } from '@vue/shared';\n\nconst stack = [];\nfunction pushWarningContext(vnode) {\n stack.push(vnode);\n}\nfunction popWarningContext() {\n stack.pop();\n}\nlet isWarning = false;\nfunction warn$1(msg, ...args) {\n if (isWarning) return;\n isWarning = true;\n pauseTracking();\n const instance = stack.length ? stack[stack.length - 1].component : null;\n const appWarnHandler = instance && instance.appContext.config.warnHandler;\n const trace = getComponentTrace();\n if (appWarnHandler) {\n callWithErrorHandling(\n appWarnHandler,\n instance,\n 11,\n [\n // eslint-disable-next-line no-restricted-syntax\n msg + args.map((a) => {\n var _a, _b;\n return (_b = (_a = a.toString) == null ? void 0 : _a.call(a)) != null ? _b : JSON.stringify(a);\n }).join(\"\"),\n instance && instance.proxy,\n trace.map(\n ({ vnode }) => `at <${formatComponentName(instance, vnode.type)}>`\n ).join(\"\\n\"),\n trace\n ]\n );\n } else {\n const warnArgs = [`[Vue warn]: ${msg}`, ...args];\n if (trace.length && // avoid spamming console during tests\n true) {\n warnArgs.push(`\n`, ...formatTrace(trace));\n }\n console.warn(...warnArgs);\n }\n resetTracking();\n isWarning = false;\n}\nfunction getComponentTrace() {\n let currentVNode = stack[stack.length - 1];\n if (!currentVNode) {\n return [];\n }\n const normalizedStack = [];\n while (currentVNode) {\n const last = normalizedStack[0];\n if (last && last.vnode === currentVNode) {\n last.recurseCount++;\n } else {\n normalizedStack.push({\n vnode: currentVNode,\n recurseCount: 0\n });\n }\n const parentInstance = currentVNode.component && currentVNode.component.parent;\n currentVNode = parentInstance && parentInstance.vnode;\n }\n return normalizedStack;\n}\nfunction formatTrace(trace) {\n const logs = [];\n trace.forEach((entry, i) => {\n logs.push(...i === 0 ? [] : [`\n`], ...formatTraceEntry(entry));\n });\n return logs;\n}\nfunction formatTraceEntry({ vnode, recurseCount }) {\n const postfix = recurseCount > 0 ? `... (${recurseCount} recursive calls)` : ``;\n const isRoot = vnode.component ? vnode.component.parent == null : false;\n const open = ` at <${formatComponentName(\n vnode.component,\n vnode.type,\n isRoot\n )}`;\n const close = `>` + postfix;\n return vnode.props ? [open, ...formatProps(vnode.props), close] : [open + close];\n}\nfunction formatProps(props) {\n const res = [];\n const keys = Object.keys(props);\n keys.slice(0, 3).forEach((key) => {\n res.push(...formatProp(key, props[key]));\n });\n if (keys.length > 3) {\n res.push(` ...`);\n }\n return res;\n}\nfunction formatProp(key, value, raw) {\n if (isString(value)) {\n value = JSON.stringify(value);\n return raw ? value : [`${key}=${value}`];\n } else if (typeof value === \"number\" || typeof value === \"boolean\" || value == null) {\n return raw ? value : [`${key}=${value}`];\n } else if (isRef(value)) {\n value = formatProp(key, toRaw(value.value), true);\n return raw ? value : [`${key}=Ref<`, value, `>`];\n } else if (isFunction(value)) {\n return [`${key}=fn${value.name ? `<${value.name}>` : ``}`];\n } else {\n value = toRaw(value);\n return raw ? value : [`${key}=`, value];\n }\n}\nfunction assertNumber(val, type) {\n if (!!!(process.env.NODE_ENV !== \"production\")) return;\n if (val === void 0) {\n return;\n } else if (typeof val !== \"number\") {\n warn$1(`${type} is not a valid number - got ${JSON.stringify(val)}.`);\n } else if (isNaN(val)) {\n warn$1(`${type} is NaN - the duration expression might be incorrect.`);\n }\n}\n\nconst ErrorCodes = {\n \"SETUP_FUNCTION\": 0,\n \"0\": \"SETUP_FUNCTION\",\n \"RENDER_FUNCTION\": 1,\n \"1\": \"RENDER_FUNCTION\",\n \"NATIVE_EVENT_HANDLER\": 5,\n \"5\": \"NATIVE_EVENT_HANDLER\",\n \"COMPONENT_EVENT_HANDLER\": 6,\n \"6\": \"COMPONENT_EVENT_HANDLER\",\n \"VNODE_HOOK\": 7,\n \"7\": \"VNODE_HOOK\",\n \"DIRECTIVE_HOOK\": 8,\n \"8\": \"DIRECTIVE_HOOK\",\n \"TRANSITION_HOOK\": 9,\n \"9\": \"TRANSITION_HOOK\",\n \"APP_ERROR_HANDLER\": 10,\n \"10\": \"APP_ERROR_HANDLER\",\n \"APP_WARN_HANDLER\": 11,\n \"11\": \"APP_WARN_HANDLER\",\n \"FUNCTION_REF\": 12,\n \"12\": \"FUNCTION_REF\",\n \"ASYNC_COMPONENT_LOADER\": 13,\n \"13\": \"ASYNC_COMPONENT_LOADER\",\n \"SCHEDULER\": 14,\n \"14\": \"SCHEDULER\",\n \"COMPONENT_UPDATE\": 15,\n \"15\": \"COMPONENT_UPDATE\",\n \"APP_UNMOUNT_CLEANUP\": 16,\n \"16\": \"APP_UNMOUNT_CLEANUP\"\n};\nconst ErrorTypeStrings$1 = {\n [\"sp\"]: \"serverPrefetch hook\",\n [\"bc\"]: \"beforeCreate hook\",\n [\"c\"]: \"created hook\",\n [\"bm\"]: \"beforeMount hook\",\n [\"m\"]: \"mounted hook\",\n [\"bu\"]: \"beforeUpdate hook\",\n [\"u\"]: \"updated\",\n [\"bum\"]: \"beforeUnmount hook\",\n [\"um\"]: \"unmounted hook\",\n [\"a\"]: \"activated hook\",\n [\"da\"]: \"deactivated hook\",\n [\"ec\"]: \"errorCaptured hook\",\n [\"rtc\"]: \"renderTracked hook\",\n [\"rtg\"]: \"renderTriggered hook\",\n [0]: \"setup function\",\n [1]: \"render function\",\n [2]: \"watcher getter\",\n [3]: \"watcher callback\",\n [4]: \"watcher cleanup function\",\n [5]: \"native event handler\",\n [6]: \"component event handler\",\n [7]: \"vnode hook\",\n [8]: \"directive hook\",\n [9]: \"transition hook\",\n [10]: \"app errorHandler\",\n [11]: \"app warnHandler\",\n [12]: \"ref function\",\n [13]: \"async component loader\",\n [14]: \"scheduler flush\",\n [15]: \"component update\",\n [16]: \"app unmount cleanup function\"\n};\nfunction callWithErrorHandling(fn, instance, type, args) {\n try {\n return args ? fn(...args) : fn();\n } catch (err) {\n handleError(err, instance, type);\n }\n}\nfunction callWithAsyncErrorHandling(fn, instance, type, args) {\n if (isFunction(fn)) {\n const res = callWithErrorHandling(fn, instance, type, args);\n if (res && isPromise(res)) {\n res.catch((err) => {\n handleError(err, instance, type);\n });\n }\n return res;\n }\n if (isArray(fn)) {\n const values = [];\n for (let i = 0; i < fn.length; i++) {\n values.push(callWithAsyncErrorHandling(fn[i], instance, type, args));\n }\n return values;\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(\n `Invalid value type passed to callWithAsyncErrorHandling(): ${typeof fn}`\n );\n }\n}\nfunction handleError(err, instance, type, throwInDev = true) {\n const contextVNode = instance ? instance.vnode : null;\n const { errorHandler, throwUnhandledErrorInProduction } = instance && instance.appContext.config || EMPTY_OBJ;\n if (instance) {\n let cur = instance.parent;\n const exposedInstance = instance.proxy;\n const errorInfo = !!(process.env.NODE_ENV !== \"production\") ? ErrorTypeStrings$1[type] : `https://vuejs.org/error-reference/#runtime-${type}`;\n while (cur) {\n const errorCapturedHooks = cur.ec;\n if (errorCapturedHooks) {\n for (let i = 0; i < errorCapturedHooks.length; i++) {\n if (errorCapturedHooks[i](err, exposedInstance, errorInfo) === false) {\n return;\n }\n }\n }\n cur = cur.parent;\n }\n if (errorHandler) {\n pauseTracking();\n callWithErrorHandling(errorHandler, null, 10, [\n err,\n exposedInstance,\n errorInfo\n ]);\n resetTracking();\n return;\n }\n }\n logError(err, type, contextVNode, throwInDev, throwUnhandledErrorInProduction);\n}\nfunction logError(err, type, contextVNode, throwInDev = true, throwInProd = false) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n const info = ErrorTypeStrings$1[type];\n if (contextVNode) {\n pushWarningContext(contextVNode);\n }\n warn$1(`Unhandled error${info ? ` during execution of ${info}` : ``}`);\n if (contextVNode) {\n popWarningContext();\n }\n if (throwInDev) {\n throw err;\n } else {\n console.error(err);\n }\n } else if (throwInProd) {\n throw err;\n } else {\n console.error(err);\n }\n}\n\nconst queue = [];\nlet flushIndex = -1;\nconst pendingPostFlushCbs = [];\nlet activePostFlushCbs = null;\nlet postFlushIndex = 0;\nconst resolvedPromise = /* @__PURE__ */ Promise.resolve();\nlet currentFlushPromise = null;\nconst RECURSION_LIMIT = 100;\nfunction nextTick(fn) {\n const p = currentFlushPromise || resolvedPromise;\n return fn ? p.then(this ? fn.bind(this) : fn) : p;\n}\nfunction findInsertionIndex(id) {\n let start = flushIndex + 1;\n let end = queue.length;\n while (start < end) {\n const middle = start + end >>> 1;\n const middleJob = queue[middle];\n const middleJobId = getId(middleJob);\n if (middleJobId < id || middleJobId === id && middleJob.flags & 2) {\n start = middle + 1;\n } else {\n end = middle;\n }\n }\n return start;\n}\nfunction queueJob(job) {\n if (!(job.flags & 1)) {\n const jobId = getId(job);\n const lastJob = queue[queue.length - 1];\n if (!lastJob || // fast path when the job id is larger than the tail\n !(job.flags & 2) && jobId >= getId(lastJob)) {\n queue.push(job);\n } else {\n queue.splice(findInsertionIndex(jobId), 0, job);\n }\n job.flags |= 1;\n queueFlush();\n }\n}\nfunction queueFlush() {\n if (!currentFlushPromise) {\n currentFlushPromise = resolvedPromise.then(flushJobs);\n }\n}\nfunction queuePostFlushCb(cb) {\n if (!isArray(cb)) {\n if (activePostFlushCbs && cb.id === -1) {\n activePostFlushCbs.splice(postFlushIndex + 1, 0, cb);\n } else if (!(cb.flags & 1)) {\n pendingPostFlushCbs.push(cb);\n cb.flags |= 1;\n }\n } else {\n pendingPostFlushCbs.push(...cb);\n }\n queueFlush();\n}\nfunction flushPreFlushCbs(instance, seen, i = flushIndex + 1) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n seen = seen || /* @__PURE__ */ new Map();\n }\n for (; i < queue.length; i++) {\n const cb = queue[i];\n if (cb && cb.flags & 2) {\n if (instance && cb.id !== instance.uid) {\n continue;\n }\n if (!!(process.env.NODE_ENV !== \"production\") && checkRecursiveUpdates(seen, cb)) {\n continue;\n }\n queue.splice(i, 1);\n i--;\n if (cb.flags & 4) {\n cb.flags &= -2;\n }\n cb();\n if (!(cb.flags & 4)) {\n cb.flags &= -2;\n }\n }\n }\n}\nfunction flushPostFlushCbs(seen) {\n if (pendingPostFlushCbs.length) {\n const deduped = [...new Set(pendingPostFlushCbs)].sort(\n (a, b) => getId(a) - getId(b)\n );\n pendingPostFlushCbs.length = 0;\n if (activePostFlushCbs) {\n activePostFlushCbs.push(...deduped);\n return;\n }\n activePostFlushCbs = deduped;\n if (!!(process.env.NODE_ENV !== \"production\")) {\n seen = seen || /* @__PURE__ */ new Map();\n }\n for (postFlushIndex = 0; postFlushIndex < activePostFlushCbs.length; postFlushIndex++) {\n const cb = activePostFlushCbs[postFlushIndex];\n if (!!(process.env.NODE_ENV !== \"production\") && checkRecursiveUpdates(seen, cb)) {\n continue;\n }\n if (cb.flags & 4) {\n cb.flags &= -2;\n }\n if (!(cb.flags & 8)) cb();\n cb.flags &= -2;\n }\n activePostFlushCbs = null;\n postFlushIndex = 0;\n }\n}\nconst getId = (job) => job.id == null ? job.flags & 2 ? -1 : Infinity : job.id;\nfunction flushJobs(seen) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n seen = seen || /* @__PURE__ */ new Map();\n }\n const check = !!(process.env.NODE_ENV !== \"production\") ? (job) => checkRecursiveUpdates(seen, job) : NOOP;\n try {\n for (flushIndex = 0; flushIndex < queue.length; flushIndex++) {\n const job = queue[flushIndex];\n if (job && !(job.flags & 8)) {\n if (!!(process.env.NODE_ENV !== \"production\") && check(job)) {\n continue;\n }\n if (job.flags & 4) {\n job.flags &= ~1;\n }\n callWithErrorHandling(\n job,\n job.i,\n job.i ? 15 : 14\n );\n if (!(job.flags & 4)) {\n job.flags &= ~1;\n }\n }\n }\n } finally {\n for (; flushIndex < queue.length; flushIndex++) {\n const job = queue[flushIndex];\n if (job) {\n job.flags &= -2;\n }\n }\n flushIndex = -1;\n queue.length = 0;\n flushPostFlushCbs(seen);\n currentFlushPromise = null;\n if (queue.length || pendingPostFlushCbs.length) {\n flushJobs(seen);\n }\n }\n}\nfunction checkRecursiveUpdates(seen, fn) {\n const count = seen.get(fn) || 0;\n if (count > RECURSION_LIMIT) {\n const instance = fn.i;\n const componentName = instance && getComponentName(instance.type);\n handleError(\n `Maximum recursive updates exceeded${componentName ? ` in component <${componentName}>` : ``}. This means you have a reactive effect that is mutating its own dependencies and thus recursively triggering itself. Possible sources include component template, render function, updated hook or watcher source function.`,\n null,\n 10\n );\n return true;\n }\n seen.set(fn, count + 1);\n return false;\n}\n\nlet isHmrUpdating = false;\nconst hmrDirtyComponents = /* @__PURE__ */ new Map();\nif (!!(process.env.NODE_ENV !== \"production\")) {\n getGlobalThis().__VUE_HMR_RUNTIME__ = {\n createRecord: tryWrap(createRecord),\n rerender: tryWrap(rerender),\n reload: tryWrap(reload)\n };\n}\nconst map = /* @__PURE__ */ new Map();\nfunction registerHMR(instance) {\n const id = instance.type.__hmrId;\n let record = map.get(id);\n if (!record) {\n createRecord(id, instance.type);\n record = map.get(id);\n }\n record.instances.add(instance);\n}\nfunction unregisterHMR(instance) {\n map.get(instance.type.__hmrId).instances.delete(instance);\n}\nfunction createRecord(id, initialDef) {\n if (map.has(id)) {\n return false;\n }\n map.set(id, {\n initialDef: normalizeClassComponent(initialDef),\n instances: /* @__PURE__ */ new Set()\n });\n return true;\n}\nfunction normalizeClassComponent(component) {\n return isClassComponent(component) ? component.__vccOpts : component;\n}\nfunction rerender(id, newRender) {\n const record = map.get(id);\n if (!record) {\n return;\n }\n record.initialDef.render = newRender;\n [...record.instances].forEach((instance) => {\n if (newRender) {\n instance.render = newRender;\n normalizeClassComponent(instance.type).render = newRender;\n }\n instance.renderCache = [];\n isHmrUpdating = true;\n if (!(instance.job.flags & 8)) {\n instance.update();\n }\n isHmrUpdating = false;\n });\n}\nfunction reload(id, newComp) {\n const record = map.get(id);\n if (!record) return;\n newComp = normalizeClassComponent(newComp);\n updateComponentDef(record.initialDef, newComp);\n const instances = [...record.instances];\n for (let i = 0; i < instances.length; i++) {\n const instance = instances[i];\n const oldComp = normalizeClassComponent(instance.type);\n let dirtyInstances = hmrDirtyComponents.get(oldComp);\n if (!dirtyInstances) {\n if (oldComp !== record.initialDef) {\n updateComponentDef(oldComp, newComp);\n }\n hmrDirtyComponents.set(oldComp, dirtyInstances = /* @__PURE__ */ new Set());\n }\n dirtyInstances.add(instance);\n instance.appContext.propsCache.delete(instance.type);\n instance.appContext.emitsCache.delete(instance.type);\n instance.appContext.optionsCache.delete(instance.type);\n if (instance.ceReload) {\n dirtyInstances.add(instance);\n instance.ceReload(newComp.styles);\n dirtyInstances.delete(instance);\n } else if (instance.parent) {\n queueJob(() => {\n if (!(instance.job.flags & 8)) {\n isHmrUpdating = true;\n instance.parent.update();\n isHmrUpdating = false;\n dirtyInstances.delete(instance);\n }\n });\n } else if (instance.appContext.reload) {\n instance.appContext.reload();\n } else if (typeof window !== \"undefined\") {\n window.location.reload();\n } else {\n console.warn(\n \"[HMR] Root or manually mounted instance modified. Full reload required.\"\n );\n }\n if (instance.root.ce && instance !== instance.root) {\n instance.root.ce._removeChildStyle(oldComp);\n }\n }\n queuePostFlushCb(() => {\n hmrDirtyComponents.clear();\n });\n}\nfunction updateComponentDef(oldComp, newComp) {\n extend(oldComp, newComp);\n for (const key in oldComp) {\n if (key !== \"__file\" && !(key in newComp)) {\n delete oldComp[key];\n }\n }\n}\nfunction tryWrap(fn) {\n return (id, arg) => {\n try {\n return fn(id, arg);\n } catch (e) {\n console.error(e);\n console.warn(\n `[HMR] Something went wrong during Vue component hot-reload. Full reload required.`\n );\n }\n };\n}\n\nlet devtools$1;\nlet buffer = [];\nlet devtoolsNotInstalled = false;\nfunction emit$1(event, ...args) {\n if (devtools$1) {\n devtools$1.emit(event, ...args);\n } else if (!devtoolsNotInstalled) {\n buffer.push({ event, args });\n }\n}\nfunction setDevtoolsHook$1(hook, target) {\n var _a, _b;\n devtools$1 = hook;\n if (devtools$1) {\n devtools$1.enabled = true;\n buffer.forEach(({ event, args }) => devtools$1.emit(event, ...args));\n buffer = [];\n } else if (\n // handle late devtools injection - only do this if we are in an actual\n // browser environment to avoid the timer handle stalling test runner exit\n // (#4815)\n typeof window !== \"undefined\" && // some envs mock window but not fully\n window.HTMLElement && // also exclude jsdom\n // eslint-disable-next-line no-restricted-syntax\n !((_b = (_a = window.navigator) == null ? void 0 : _a.userAgent) == null ? void 0 : _b.includes(\"jsdom\"))\n ) {\n const replay = target.__VUE_DEVTOOLS_HOOK_REPLAY__ = target.__VUE_DEVTOOLS_HOOK_REPLAY__ || [];\n replay.push((newHook) => {\n setDevtoolsHook$1(newHook, target);\n });\n setTimeout(() => {\n if (!devtools$1) {\n target.__VUE_DEVTOOLS_HOOK_REPLAY__ = null;\n devtoolsNotInstalled = true;\n buffer = [];\n }\n }, 3e3);\n } else {\n devtoolsNotInstalled = true;\n buffer = [];\n }\n}\nfunction devtoolsInitApp(app, version) {\n emit$1(\"app:init\" /* APP_INIT */, app, version, {\n Fragment,\n Text,\n Comment,\n Static\n });\n}\nfunction devtoolsUnmountApp(app) {\n emit$1(\"app:unmount\" /* APP_UNMOUNT */, app);\n}\nconst devtoolsComponentAdded = /* @__PURE__ */ createDevtoolsComponentHook(\"component:added\" /* COMPONENT_ADDED */);\nconst devtoolsComponentUpdated = /* @__PURE__ */ createDevtoolsComponentHook(\"component:updated\" /* COMPONENT_UPDATED */);\nconst _devtoolsComponentRemoved = /* @__PURE__ */ createDevtoolsComponentHook(\n \"component:removed\" /* COMPONENT_REMOVED */\n);\nconst devtoolsComponentRemoved = (component) => {\n if (devtools$1 && typeof devtools$1.cleanupBuffer === \"function\" && // remove the component if it wasn't buffered\n !devtools$1.cleanupBuffer(component)) {\n _devtoolsComponentRemoved(component);\n }\n};\n// @__NO_SIDE_EFFECTS__\nfunction createDevtoolsComponentHook(hook) {\n return (component) => {\n emit$1(\n hook,\n component.appContext.app,\n component.uid,\n component.parent ? component.parent.uid : void 0,\n component\n );\n };\n}\nconst devtoolsPerfStart = /* @__PURE__ */ createDevtoolsPerformanceHook(\"perf:start\" /* PERFORMANCE_START */);\nconst devtoolsPerfEnd = /* @__PURE__ */ createDevtoolsPerformanceHook(\"perf:end\" /* PERFORMANCE_END */);\nfunction createDevtoolsPerformanceHook(hook) {\n return (component, type, time) => {\n emit$1(hook, component.appContext.app, component.uid, component, type, time);\n };\n}\nfunction devtoolsComponentEmit(component, event, params) {\n emit$1(\n \"component:emit\" /* COMPONENT_EMIT */,\n component.appContext.app,\n component,\n event,\n params\n );\n}\n\nlet currentRenderingInstance = null;\nlet currentScopeId = null;\nfunction setCurrentRenderingInstance(instance) {\n const prev = currentRenderingInstance;\n currentRenderingInstance = instance;\n currentScopeId = instance && instance.type.__scopeId || null;\n return prev;\n}\nfunction pushScopeId(id) {\n currentScopeId = id;\n}\nfunction popScopeId() {\n currentScopeId = null;\n}\nconst withScopeId = (_id) => withCtx;\nfunction withCtx(fn, ctx = currentRenderingInstance, isNonScopedSlot) {\n if (!ctx) return fn;\n if (fn._n) {\n return fn;\n }\n const renderFnWithContext = (...args) => {\n if (renderFnWithContext._d) {\n setBlockTracking(-1);\n }\n const prevInstance = setCurrentRenderingInstance(ctx);\n let res;\n try {\n res = fn(...args);\n } finally {\n setCurrentRenderingInstance(prevInstance);\n if (renderFnWithContext._d) {\n setBlockTracking(1);\n }\n }\n if (!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_DEVTOOLS__) {\n devtoolsComponentUpdated(ctx);\n }\n return res;\n };\n renderFnWithContext._n = true;\n renderFnWithContext._c = true;\n renderFnWithContext._d = true;\n return renderFnWithContext;\n}\n\nfunction validateDirectiveName(name) {\n if (isBuiltInDirective(name)) {\n warn$1(\"Do not use built-in directive ids as custom directive id: \" + name);\n }\n}\nfunction withDirectives(vnode, directives) {\n if (currentRenderingInstance === null) {\n !!(process.env.NODE_ENV !== \"production\") && warn$1(`withDirectives can only be used inside render functions.`);\n return vnode;\n }\n const instance = getComponentPublicInstance(currentRenderingInstance);\n const bindings = vnode.dirs || (vnode.dirs = []);\n for (let i = 0; i < directives.length; i++) {\n let [dir, value, arg, modifiers = EMPTY_OBJ] = directives[i];\n if (dir) {\n if (isFunction(dir)) {\n dir = {\n mounted: dir,\n updated: dir\n };\n }\n if (dir.deep) {\n traverse(value);\n }\n bindings.push({\n dir,\n instance,\n value,\n oldValue: void 0,\n arg,\n modifiers\n });\n }\n }\n return vnode;\n}\nfunction invokeDirectiveHook(vnode, prevVNode, instance, name) {\n const bindings = vnode.dirs;\n const oldBindings = prevVNode && prevVNode.dirs;\n for (let i = 0; i < bindings.length; i++) {\n const binding = bindings[i];\n if (oldBindings) {\n binding.oldValue = oldBindings[i].value;\n }\n let hook = binding.dir[name];\n if (hook) {\n pauseTracking();\n callWithAsyncErrorHandling(hook, instance, 8, [\n vnode.el,\n binding,\n vnode,\n prevVNode\n ]);\n resetTracking();\n }\n }\n}\n\nconst TeleportEndKey = Symbol(\"_vte\");\nconst isTeleport = (type) => type.__isTeleport;\nconst isTeleportDisabled = (props) => props && (props.disabled || props.disabled === \"\");\nconst isTeleportDeferred = (props) => props && (props.defer || props.defer === \"\");\nconst isTargetSVG = (target) => typeof SVGElement !== \"undefined\" && target instanceof SVGElement;\nconst isTargetMathML = (target) => typeof MathMLElement === \"function\" && target instanceof MathMLElement;\nconst resolveTarget = (props, select) => {\n const targetSelector = props && props.to;\n if (isString(targetSelector)) {\n if (!select) {\n !!(process.env.NODE_ENV !== \"production\") && warn$1(\n `Current renderer does not support string target for Teleports. (missing querySelector renderer option)`\n );\n return null;\n } else {\n const target = select(targetSelector);\n if (!!(process.env.NODE_ENV !== \"production\") && !target && !isTeleportDisabled(props)) {\n warn$1(\n `Failed to locate Teleport target with selector \"${targetSelector}\". Note the target element must exist before the component is mounted - i.e. the target cannot be rendered by the component itself, and ideally should be outside of the entire Vue component tree.`\n );\n }\n return target;\n }\n } else {\n if (!!(process.env.NODE_ENV !== \"production\") && !targetSelector && !isTeleportDisabled(props)) {\n warn$1(`Invalid Teleport target: ${targetSelector}`);\n }\n return targetSelector;\n }\n};\nconst TeleportImpl = {\n name: \"Teleport\",\n __isTeleport: true,\n process(n1, n2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized, internals) {\n const {\n mc: mountChildren,\n pc: patchChildren,\n pbc: patchBlockChildren,\n o: { insert, querySelector, createText, createComment }\n } = internals;\n const disabled = isTeleportDisabled(n2.props);\n let { shapeFlag, children, dynamicChildren } = n2;\n if (!!(process.env.NODE_ENV !== \"production\") && isHmrUpdating) {\n optimized = false;\n dynamicChildren = null;\n }\n if (n1 == null) {\n const placeholder = n2.el = !!(process.env.NODE_ENV !== \"production\") ? createComment(\"teleport start\") : createText(\"\");\n const mainAnchor = n2.anchor = !!(process.env.NODE_ENV !== \"production\") ? createComment(\"teleport end\") : createText(\"\");\n insert(placeholder, container, anchor);\n insert(mainAnchor, container, anchor);\n const mount = (container2, anchor2) => {\n if (shapeFlag & 16) {\n mountChildren(\n children,\n container2,\n anchor2,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds,\n optimized\n );\n }\n };\n const mountToTarget = () => {\n const target = n2.target = resolveTarget(n2.props, querySelector);\n const targetAnchor = prepareAnchor(target, n2, createText, insert);\n if (target) {\n if (namespace !== \"svg\" && isTargetSVG(target)) {\n namespace = \"svg\";\n } else if (namespace !== \"mathml\" && isTargetMathML(target)) {\n namespace = \"mathml\";\n }\n if (parentComponent && parentComponent.isCE) {\n (parentComponent.ce._teleportTargets || (parentComponent.ce._teleportTargets = /* @__PURE__ */ new Set())).add(target);\n }\n if (!disabled) {\n mount(target, targetAnchor);\n updateCssVars(n2, false);\n }\n } else if (!!(process.env.NODE_ENV !== \"production\") && !disabled) {\n warn$1(\n \"Invalid Teleport target on mount:\",\n target,\n `(${typeof target})`\n );\n }\n };\n if (disabled) {\n mount(container, mainAnchor);\n updateCssVars(n2, true);\n }\n if (isTeleportDeferred(n2.props)) {\n n2.el.__isMounted = false;\n queuePostRenderEffect(() => {\n mountToTarget();\n delete n2.el.__isMounted;\n }, parentSuspense);\n } else {\n mountToTarget();\n }\n } else {\n if (isTeleportDeferred(n2.props) && n1.el.__isMounted === false) {\n queuePostRenderEffect(() => {\n TeleportImpl.process(\n n1,\n n2,\n container,\n anchor,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds,\n optimized,\n internals\n );\n }, parentSuspense);\n return;\n }\n n2.el = n1.el;\n n2.targetStart = n1.targetStart;\n const mainAnchor = n2.anchor = n1.anchor;\n const target = n2.target = n1.target;\n const targetAnchor = n2.targetAnchor = n1.targetAnchor;\n const wasDisabled = isTeleportDisabled(n1.props);\n const currentContainer = wasDisabled ? container : target;\n const currentAnchor = wasDisabled ? mainAnchor : targetAnchor;\n if (namespace === \"svg\" || isTargetSVG(target)) {\n namespace = \"svg\";\n } else if (namespace === \"mathml\" || isTargetMathML(target)) {\n namespace = \"mathml\";\n }\n if (dynamicChildren) {\n patchBlockChildren(\n n1.dynamicChildren,\n dynamicChildren,\n currentContainer,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds\n );\n traverseStaticChildren(n1, n2, !!!(process.env.NODE_ENV !== \"production\"));\n } else if (!optimized) {\n patchChildren(\n n1,\n n2,\n currentContainer,\n currentAnchor,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds,\n false\n );\n }\n if (disabled) {\n if (!wasDisabled) {\n moveTeleport(\n n2,\n container,\n mainAnchor,\n internals,\n 1\n );\n } else {\n if (n2.props && n1.props && n2.props.to !== n1.props.to) {\n n2.props.to = n1.props.to;\n }\n }\n } else {\n if ((n2.props && n2.props.to) !== (n1.props && n1.props.to)) {\n const nextTarget = n2.target = resolveTarget(\n n2.props,\n querySelector\n );\n if (nextTarget) {\n moveTeleport(\n n2,\n nextTarget,\n null,\n internals,\n 0\n );\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(\n \"Invalid Teleport target on update:\",\n target,\n `(${typeof target})`\n );\n }\n } else if (wasDisabled) {\n moveTeleport(\n n2,\n target,\n targetAnchor,\n internals,\n 1\n );\n }\n }\n updateCssVars(n2, disabled);\n }\n },\n remove(vnode, parentComponent, parentSuspense, { um: unmount, o: { remove: hostRemove } }, doRemove) {\n const {\n shapeFlag,\n children,\n anchor,\n targetStart,\n targetAnchor,\n target,\n props\n } = vnode;\n if (target) {\n hostRemove(targetStart);\n hostRemove(targetAnchor);\n }\n doRemove && hostRemove(anchor);\n if (shapeFlag & 16) {\n const shouldRemove = doRemove || !isTeleportDisabled(props);\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n unmount(\n child,\n parentComponent,\n parentSuspense,\n shouldRemove,\n !!child.dynamicChildren\n );\n }\n }\n },\n move: moveTeleport,\n hydrate: hydrateTeleport\n};\nfunction moveTeleport(vnode, container, parentAnchor, { o: { insert }, m: move }, moveType = 2) {\n if (moveType === 0) {\n insert(vnode.targetAnchor, container, parentAnchor);\n }\n const { el, anchor, shapeFlag, children, props } = vnode;\n const isReorder = moveType === 2;\n if (isReorder) {\n insert(el, container, parentAnchor);\n }\n if (!isReorder || isTeleportDisabled(props)) {\n if (shapeFlag & 16) {\n for (let i = 0; i < children.length; i++) {\n move(\n children[i],\n container,\n parentAnchor,\n 2\n );\n }\n }\n }\n if (isReorder) {\n insert(anchor, container, parentAnchor);\n }\n}\nfunction hydrateTeleport(node, vnode, parentComponent, parentSuspense, slotScopeIds, optimized, {\n o: { nextSibling, parentNode, querySelector, insert, createText }\n}, hydrateChildren) {\n function hydrateDisabledTeleport(node2, vnode2, targetStart, targetAnchor) {\n vnode2.anchor = hydrateChildren(\n nextSibling(node2),\n vnode2,\n parentNode(node2),\n parentComponent,\n parentSuspense,\n slotScopeIds,\n optimized\n );\n vnode2.targetStart = targetStart;\n vnode2.targetAnchor = targetAnchor;\n }\n const target = vnode.target = resolveTarget(\n vnode.props,\n querySelector\n );\n const disabled = isTeleportDisabled(vnode.props);\n if (target) {\n const targetNode = target._lpa || target.firstChild;\n if (vnode.shapeFlag & 16) {\n if (disabled) {\n hydrateDisabledTeleport(\n node,\n vnode,\n targetNode,\n targetNode && nextSibling(targetNode)\n );\n } else {\n vnode.anchor = nextSibling(node);\n let targetAnchor = targetNode;\n while (targetAnchor) {\n if (targetAnchor && targetAnchor.nodeType === 8) {\n if (targetAnchor.data === \"teleport start anchor\") {\n vnode.targetStart = targetAnchor;\n } else if (targetAnchor.data === \"teleport anchor\") {\n vnode.targetAnchor = targetAnchor;\n target._lpa = vnode.targetAnchor && nextSibling(vnode.targetAnchor);\n break;\n }\n }\n targetAnchor = nextSibling(targetAnchor);\n }\n if (!vnode.targetAnchor) {\n prepareAnchor(target, vnode, createText, insert);\n }\n hydrateChildren(\n targetNode && nextSibling(targetNode),\n vnode,\n target,\n parentComponent,\n parentSuspense,\n slotScopeIds,\n optimized\n );\n }\n }\n updateCssVars(vnode, disabled);\n } else if (disabled) {\n if (vnode.shapeFlag & 16) {\n hydrateDisabledTeleport(node, vnode, node, nextSibling(node));\n }\n }\n return vnode.anchor && nextSibling(vnode.anchor);\n}\nconst Teleport = TeleportImpl;\nfunction updateCssVars(vnode, isDisabled) {\n const ctx = vnode.ctx;\n if (ctx && ctx.ut) {\n let node, anchor;\n if (isDisabled) {\n node = vnode.el;\n anchor = vnode.anchor;\n } else {\n node = vnode.targetStart;\n anchor = vnode.targetAnchor;\n }\n while (node && node !== anchor) {\n if (node.nodeType === 1) node.setAttribute(\"data-v-owner\", ctx.uid);\n node = node.nextSibling;\n }\n ctx.ut();\n }\n}\nfunction prepareAnchor(target, vnode, createText, insert) {\n const targetStart = vnode.targetStart = createText(\"\");\n const targetAnchor = vnode.targetAnchor = createText(\"\");\n targetStart[TeleportEndKey] = targetAnchor;\n if (target) {\n insert(targetStart, target);\n insert(targetAnchor, target);\n }\n return targetAnchor;\n}\n\nconst leaveCbKey = Symbol(\"_leaveCb\");\nconst enterCbKey = Symbol(\"_enterCb\");\nfunction useTransitionState() {\n const state = {\n isMounted: false,\n isLeaving: false,\n isUnmounting: false,\n leavingVNodes: /* @__PURE__ */ new Map()\n };\n onMounted(() => {\n state.isMounted = true;\n });\n onBeforeUnmount(() => {\n state.isUnmounting = true;\n });\n return state;\n}\nconst TransitionHookValidator = [Function, Array];\nconst BaseTransitionPropsValidators = {\n mode: String,\n appear: Boolean,\n persisted: Boolean,\n // enter\n onBeforeEnter: TransitionHookValidator,\n onEnter: TransitionHookValidator,\n onAfterEnter: TransitionHookValidator,\n onEnterCancelled: TransitionHookValidator,\n // leave\n onBeforeLeave: TransitionHookValidator,\n onLeave: TransitionHookValidator,\n onAfterLeave: TransitionHookValidator,\n onLeaveCancelled: TransitionHookValidator,\n // appear\n onBeforeAppear: TransitionHookValidator,\n onAppear: TransitionHookValidator,\n onAfterAppear: TransitionHookValidator,\n onAppearCancelled: TransitionHookValidator\n};\nconst recursiveGetSubtree = (instance) => {\n const subTree = instance.subTree;\n return subTree.component ? recursiveGetSubtree(subTree.component) : subTree;\n};\nconst BaseTransitionImpl = {\n name: `BaseTransition`,\n props: BaseTransitionPropsValidators,\n setup(props, { slots }) {\n const instance = getCurrentInstance();\n const state = useTransitionState();\n return () => {\n const children = slots.default && getTransitionRawChildren(slots.default(), true);\n if (!children || !children.length) {\n return;\n }\n const child = findNonCommentChild(children);\n const rawProps = toRaw(props);\n const { mode } = rawProps;\n if (!!(process.env.NODE_ENV !== \"production\") && mode && mode !== \"in-out\" && mode !== \"out-in\" && mode !== \"default\") {\n warn$1(`invalid <transition> mode: ${mode}`);\n }\n if (state.isLeaving) {\n return emptyPlaceholder(child);\n }\n const innerChild = getInnerChild$1(child);\n if (!innerChild) {\n return emptyPlaceholder(child);\n }\n let enterHooks = resolveTransitionHooks(\n innerChild,\n rawProps,\n state,\n instance,\n // #11061, ensure enterHooks is fresh after clone\n (hooks) => enterHooks = hooks\n );\n if (innerChild.type !== Comment) {\n setTransitionHooks(innerChild, enterHooks);\n }\n let oldInnerChild = instance.subTree && getInnerChild$1(instance.subTree);\n if (oldInnerChild && oldInnerChild.type !== Comment && !isSameVNodeType(oldInnerChild, innerChild) && recursiveGetSubtree(instance).type !== Comment) {\n let leavingHooks = resolveTransitionHooks(\n oldInnerChild,\n rawProps,\n state,\n instance\n );\n setTransitionHooks(oldInnerChild, leavingHooks);\n if (mode === \"out-in\" && innerChild.type !== Comment) {\n state.isLeaving = true;\n leavingHooks.afterLeave = () => {\n state.isLeaving = false;\n if (!(instance.job.flags & 8)) {\n instance.update();\n }\n delete leavingHooks.afterLeave;\n oldInnerChild = void 0;\n };\n return emptyPlaceholder(child);\n } else if (mode === \"in-out\" && innerChild.type !== Comment) {\n leavingHooks.delayLeave = (el, earlyRemove, delayedLeave) => {\n const leavingVNodesCache = getLeavingNodesForType(\n state,\n oldInnerChild\n );\n leavingVNodesCache[String(oldInnerChild.key)] = oldInnerChild;\n el[leaveCbKey] = () => {\n earlyRemove();\n el[leaveCbKey] = void 0;\n delete enterHooks.delayedLeave;\n oldInnerChild = void 0;\n };\n enterHooks.delayedLeave = () => {\n delayedLeave();\n delete enterHooks.delayedLeave;\n oldInnerChild = void 0;\n };\n };\n } else {\n oldInnerChild = void 0;\n }\n } else if (oldInnerChild) {\n oldInnerChild = void 0;\n }\n return child;\n };\n }\n};\nfunction findNonCommentChild(children) {\n let child = children[0];\n if (children.length > 1) {\n let hasFound = false;\n for (const c of children) {\n if (c.type !== Comment) {\n if (!!(process.env.NODE_ENV !== \"production\") && hasFound) {\n warn$1(\n \"<transition> can only be used on a single element or component. Use <transition-group> for lists.\"\n );\n break;\n }\n child = c;\n hasFound = true;\n if (!!!(process.env.NODE_ENV !== \"production\")) break;\n }\n }\n }\n return child;\n}\nconst BaseTransition = BaseTransitionImpl;\nfunction getLeavingNodesForType(state, vnode) {\n const { leavingVNodes } = state;\n let leavingVNodesCache = leavingVNodes.get(vnode.type);\n if (!leavingVNodesCache) {\n leavingVNodesCache = /* @__PURE__ */ Object.create(null);\n leavingVNodes.set(vnode.type, leavingVNodesCache);\n }\n return leavingVNodesCache;\n}\nfunction resolveTransitionHooks(vnode, props, state, instance, postClone) {\n const {\n appear,\n mode,\n persisted = false,\n onBeforeEnter,\n onEnter,\n onAfterEnter,\n onEnterCancelled,\n onBeforeLeave,\n onLeave,\n onAfterLeave,\n onLeaveCancelled,\n onBeforeAppear,\n onAppear,\n onAfterAppear,\n onAppearCancelled\n } = props;\n const key = String(vnode.key);\n const leavingVNodesCache = getLeavingNodesForType(state, vnode);\n const callHook = (hook, args) => {\n hook && callWithAsyncErrorHandling(\n hook,\n instance,\n 9,\n args\n );\n };\n const callAsyncHook = (hook, args) => {\n const done = args[1];\n callHook(hook, args);\n if (isArray(hook)) {\n if (hook.every((hook2) => hook2.length <= 1)) done();\n } else if (hook.length <= 1) {\n done();\n }\n };\n const hooks = {\n mode,\n persisted,\n beforeEnter(el) {\n let hook = onBeforeEnter;\n if (!state.isMounted) {\n if (appear) {\n hook = onBeforeAppear || onBeforeEnter;\n } else {\n return;\n }\n }\n if (el[leaveCbKey]) {\n el[leaveCbKey](\n true\n /* cancelled */\n );\n }\n const leavingVNode = leavingVNodesCache[key];\n if (leavingVNode && isSameVNodeType(vnode, leavingVNode) && leavingVNode.el[leaveCbKey]) {\n leavingVNode.el[leaveCbKey]();\n }\n callHook(hook, [el]);\n },\n enter(el) {\n let hook = onEnter;\n let afterHook = onAfterEnter;\n let cancelHook = onEnterCancelled;\n if (!state.isMounted) {\n if (appear) {\n hook = onAppear || onEnter;\n afterHook = onAfterAppear || onAfterEnter;\n cancelHook = onAppearCancelled || onEnterCancelled;\n } else {\n return;\n }\n }\n let called = false;\n const done = el[enterCbKey] = (cancelled) => {\n if (called) return;\n called = true;\n if (cancelled) {\n callHook(cancelHook, [el]);\n } else {\n callHook(afterHook, [el]);\n }\n if (hooks.delayedLeave) {\n hooks.delayedLeave();\n }\n el[enterCbKey] = void 0;\n };\n if (hook) {\n callAsyncHook(hook, [el, done]);\n } else {\n done();\n }\n },\n leave(el, remove) {\n const key2 = String(vnode.key);\n if (el[enterCbKey]) {\n el[enterCbKey](\n true\n /* cancelled */\n );\n }\n if (state.isUnmounting) {\n return remove();\n }\n callHook(onBeforeLeave, [el]);\n let called = false;\n const done = el[leaveCbKey] = (cancelled) => {\n if (called) return;\n called = true;\n remove();\n if (cancelled) {\n callHook(onLeaveCancelled, [el]);\n } else {\n callHook(onAfterLeave, [el]);\n }\n el[leaveCbKey] = void 0;\n if (leavingVNodesCache[key2] === vnode) {\n delete leavingVNodesCache[key2];\n }\n };\n leavingVNodesCache[key2] = vnode;\n if (onLeave) {\n callAsyncHook(onLeave, [el, done]);\n } else {\n done();\n }\n },\n clone(vnode2) {\n const hooks2 = resolveTransitionHooks(\n vnode2,\n props,\n state,\n instance,\n postClone\n );\n if (postClone) postClone(hooks2);\n return hooks2;\n }\n };\n return hooks;\n}\nfunction emptyPlaceholder(vnode) {\n if (isKeepAlive(vnode)) {\n vnode = cloneVNode(vnode);\n vnode.children = null;\n return vnode;\n }\n}\nfunction getInnerChild$1(vnode) {\n if (!isKeepAlive(vnode)) {\n if (isTeleport(vnode.type) && vnode.children) {\n return findNonCommentChild(vnode.children);\n }\n return vnode;\n }\n if (vnode.component) {\n return vnode.component.subTree;\n }\n const { shapeFlag, children } = vnode;\n if (children) {\n if (shapeFlag & 16) {\n return children[0];\n }\n if (shapeFlag & 32 && isFunction(children.default)) {\n return children.default();\n }\n }\n}\nfunction setTransitionHooks(vnode, hooks) {\n if (vnode.shapeFlag & 6 && vnode.component) {\n vnode.transition = hooks;\n setTransitionHooks(vnode.component.subTree, hooks);\n } else if (vnode.shapeFlag & 128) {\n vnode.ssContent.transition = hooks.clone(vnode.ssContent);\n vnode.ssFallback.transition = hooks.clone(vnode.ssFallback);\n } else {\n vnode.transition = hooks;\n }\n}\nfunction getTransitionRawChildren(children, keepComment = false, parentKey) {\n let ret = [];\n let keyedFragmentCount = 0;\n for (let i = 0; i < children.length; i++) {\n let child = children[i];\n const key = parentKey == null ? child.key : String(parentKey) + String(child.key != null ? child.key : i);\n if (child.type === Fragment) {\n if (child.patchFlag & 128) keyedFragmentCount++;\n ret = ret.concat(\n getTransitionRawChildren(child.children, keepComment, key)\n );\n } else if (keepComment || child.type !== Comment) {\n ret.push(key != null ? cloneVNode(child, { key }) : child);\n }\n }\n if (keyedFragmentCount > 1) {\n for (let i = 0; i < ret.length; i++) {\n ret[i].patchFlag = -2;\n }\n }\n return ret;\n}\n\n// @__NO_SIDE_EFFECTS__\nfunction defineComponent(options, extraOptions) {\n return isFunction(options) ? (\n // #8236: extend call and options.name access are considered side-effects\n // by Rollup, so we have to wrap it in a pure-annotated IIFE.\n /* @__PURE__ */ (() => extend({ name: options.name }, extraOptions, { setup: options }))()\n ) : options;\n}\n\nfunction useId() {\n const i = getCurrentInstance();\n if (i) {\n return (i.appContext.config.idPrefix || \"v\") + \"-\" + i.ids[0] + i.ids[1]++;\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(\n `useId() is called when there is no active component instance to be associated with.`\n );\n }\n return \"\";\n}\nfunction markAsyncBoundary(instance) {\n instance.ids = [instance.ids[0] + instance.ids[2]++ + \"-\", 0, 0];\n}\n\nconst knownTemplateRefs = /* @__PURE__ */ new WeakSet();\nfunction useTemplateRef(key) {\n const i = getCurrentInstance();\n const r = shallowRef(null);\n if (i) {\n const refs = i.refs === EMPTY_OBJ ? i.refs = {} : i.refs;\n let desc;\n if (!!(process.env.NODE_ENV !== \"production\") && (desc = Object.getOwnPropertyDescriptor(refs, key)) && !desc.configurable) {\n warn$1(`useTemplateRef('${key}') already exists.`);\n } else {\n Object.defineProperty(refs, key, {\n enumerable: true,\n get: () => r.value,\n set: (val) => r.value = val\n });\n }\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(\n `useTemplateRef() is called when there is no active component instance to be associated with.`\n );\n }\n const ret = !!(process.env.NODE_ENV !== \"production\") ? readonly(r) : r;\n if (!!(process.env.NODE_ENV !== \"production\")) {\n knownTemplateRefs.add(ret);\n }\n return ret;\n}\n\nconst pendingSetRefMap = /* @__PURE__ */ new WeakMap();\nfunction setRef(rawRef, oldRawRef, parentSuspense, vnode, isUnmount = false) {\n if (isArray(rawRef)) {\n rawRef.forEach(\n (r, i) => setRef(\n r,\n oldRawRef && (isArray(oldRawRef) ? oldRawRef[i] : oldRawRef),\n parentSuspense,\n vnode,\n isUnmount\n )\n );\n return;\n }\n if (isAsyncWrapper(vnode) && !isUnmount) {\n if (vnode.shapeFlag & 512 && vnode.type.__asyncResolved && vnode.component.subTree.component) {\n setRef(rawRef, oldRawRef, parentSuspense, vnode.component.subTree);\n }\n return;\n }\n const refValue = vnode.shapeFlag & 4 ? getComponentPublicInstance(vnode.component) : vnode.el;\n const value = isUnmount ? null : refValue;\n const { i: owner, r: ref } = rawRef;\n if (!!(process.env.NODE_ENV !== \"production\") && !owner) {\n warn$1(\n `Missing ref owner context. ref cannot be used on hoisted vnodes. A vnode with ref must be created inside the render function.`\n );\n return;\n }\n const oldRef = oldRawRef && oldRawRef.r;\n const refs = owner.refs === EMPTY_OBJ ? owner.refs = {} : owner.refs;\n const setupState = owner.setupState;\n const rawSetupState = toRaw(setupState);\n const canSetSetupRef = setupState === EMPTY_OBJ ? NO : (key) => {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n if (hasOwn(rawSetupState, key) && !isRef(rawSetupState[key])) {\n warn$1(\n `Template ref \"${key}\" used on a non-ref value. It will not work in the production build.`\n );\n }\n if (knownTemplateRefs.has(rawSetupState[key])) {\n return false;\n }\n }\n return hasOwn(rawSetupState, key);\n };\n const canSetRef = (ref2) => {\n return !!!(process.env.NODE_ENV !== \"production\") || !knownTemplateRefs.has(ref2);\n };\n if (oldRef != null && oldRef !== ref) {\n invalidatePendingSetRef(oldRawRef);\n if (isString(oldRef)) {\n refs[oldRef] = null;\n if (canSetSetupRef(oldRef)) {\n setupState[oldRef] = null;\n }\n } else if (isRef(oldRef)) {\n if (canSetRef(oldRef)) {\n oldRef.value = null;\n }\n const oldRawRefAtom = oldRawRef;\n if (oldRawRefAtom.k) refs[oldRawRefAtom.k] = null;\n }\n }\n if (isFunction(ref)) {\n callWithErrorHandling(ref, owner, 12, [value, refs]);\n } else {\n const _isString = isString(ref);\n const _isRef = isRef(ref);\n if (_isString || _isRef) {\n const doSet = () => {\n if (rawRef.f) {\n const existing = _isString ? canSetSetupRef(ref) ? setupState[ref] : refs[ref] : canSetRef(ref) || !rawRef.k ? ref.value : refs[rawRef.k];\n if (isUnmount) {\n isArray(existing) && remove(existing, refValue);\n } else {\n if (!isArray(existing)) {\n if (_isString) {\n refs[ref] = [refValue];\n if (canSetSetupRef(ref)) {\n setupState[ref] = refs[ref];\n }\n } else {\n const newVal = [refValue];\n if (canSetRef(ref)) {\n ref.value = newVal;\n }\n if (rawRef.k) refs[rawRef.k] = newVal;\n }\n } else if (!existing.includes(refValue)) {\n existing.push(refValue);\n }\n }\n } else if (_isString) {\n refs[ref] = value;\n if (canSetSetupRef(ref)) {\n setupState[ref] = value;\n }\n } else if (_isRef) {\n if (canSetRef(ref)) {\n ref.value = value;\n }\n if (rawRef.k) refs[rawRef.k] = value;\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(\"Invalid template ref type:\", ref, `(${typeof ref})`);\n }\n };\n if (value) {\n const job = () => {\n doSet();\n pendingSetRefMap.delete(rawRef);\n };\n job.id = -1;\n pendingSetRefMap.set(rawRef, job);\n queuePostRenderEffect(job, parentSuspense);\n } else {\n invalidatePendingSetRef(rawRef);\n doSet();\n }\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(\"Invalid template ref type:\", ref, `(${typeof ref})`);\n }\n }\n}\nfunction invalidatePendingSetRef(rawRef) {\n const pendingSetRef = pendingSetRefMap.get(rawRef);\n if (pendingSetRef) {\n pendingSetRef.flags |= 8;\n pendingSetRefMap.delete(rawRef);\n }\n}\n\nlet hasLoggedMismatchError = false;\nconst logMismatchError = () => {\n if (hasLoggedMismatchError) {\n return;\n }\n console.error(\"Hydration completed but contains mismatches.\");\n hasLoggedMismatchError = true;\n};\nconst isSVGContainer = (container) => container.namespaceURI.includes(\"svg\") && container.tagName !== \"foreignObject\";\nconst isMathMLContainer = (container) => container.namespaceURI.includes(\"MathML\");\nconst getContainerType = (container) => {\n if (container.nodeType !== 1) return void 0;\n if (isSVGContainer(container)) return \"svg\";\n if (isMathMLContainer(container)) return \"mathml\";\n return void 0;\n};\nconst isComment = (node) => node.nodeType === 8;\nfunction createHydrationFunctions(rendererInternals) {\n const {\n mt: mountComponent,\n p: patch,\n o: {\n patchProp,\n createText,\n nextSibling,\n parentNode,\n remove,\n insert,\n createComment\n }\n } = rendererInternals;\n const hydrate = (vnode, container) => {\n if (!container.hasChildNodes()) {\n (!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_HYDRATION_MISMATCH_DETAILS__) && warn$1(\n `Attempting to hydrate existing markup but container is empty. Performing full mount instead.`\n );\n patch(null, vnode, container);\n flushPostFlushCbs();\n container._vnode = vnode;\n return;\n }\n hydrateNode(container.firstChild, vnode, null, null, null);\n flushPostFlushCbs();\n container._vnode = vnode;\n };\n const hydrateNode = (node, vnode, parentComponent, parentSuspense, slotScopeIds, optimized = false) => {\n optimized = optimized || !!vnode.dynamicChildren;\n const isFragmentStart = isComment(node) && node.data === \"[\";\n const onMismatch = () => handleMismatch(\n node,\n vnode,\n parentComponent,\n parentSuspense,\n slotScopeIds,\n isFragmentStart\n );\n const { type, ref, shapeFlag, patchFlag } = vnode;\n let domType = node.nodeType;\n vnode.el = node;\n if (!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_DEVTOOLS__) {\n def(node, \"__vnode\", vnode, true);\n def(node, \"__vueParentComponent\", parentComponent, true);\n }\n if (patchFlag === -2) {\n optimized = false;\n vnode.dynamicChildren = null;\n }\n let nextNode = null;\n switch (type) {\n case Text:\n if (domType !== 3) {\n if (vnode.children === \"\") {\n insert(vnode.el = createText(\"\"), parentNode(node), node);\n nextNode = node;\n } else {\n nextNode = onMismatch();\n }\n } else {\n if (node.data !== vnode.children) {\n (!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_HYDRATION_MISMATCH_DETAILS__) && warn$1(\n `Hydration text mismatch in`,\n node.parentNode,\n `\n - rendered on server: ${JSON.stringify(\n node.data\n )}\n - expected on client: ${JSON.stringify(vnode.children)}`\n );\n logMismatchError();\n node.data = vnode.children;\n }\n nextNode = nextSibling(node);\n }\n break;\n case Comment:\n if (isTemplateNode(node)) {\n nextNode = nextSibling(node);\n replaceNode(\n vnode.el = node.content.firstChild,\n node,\n parentComponent\n );\n } else if (domType !== 8 || isFragmentStart) {\n nextNode = onMismatch();\n } else {\n nextNode = nextSibling(node);\n }\n break;\n case Static:\n if (isFragmentStart) {\n node = nextSibling(node);\n domType = node.nodeType;\n }\n if (domType === 1 || domType === 3) {\n nextNode = node;\n const needToAdoptContent = !vnode.children.length;\n for (let i = 0; i < vnode.staticCount; i++) {\n if (needToAdoptContent)\n vnode.children += nextNode.nodeType === 1 ? nextNode.outerHTML : nextNode.data;\n if (i === vnode.staticCount - 1) {\n vnode.anchor = nextNode;\n }\n nextNode = nextSibling(nextNode);\n }\n return isFragmentStart ? nextSibling(nextNode) : nextNode;\n } else {\n onMismatch();\n }\n break;\n case Fragment:\n if (!isFragmentStart) {\n nextNode = onMismatch();\n } else {\n nextNode = hydrateFragment(\n node,\n vnode,\n parentComponent,\n parentSuspense,\n slotScopeIds,\n optimized\n );\n }\n break;\n default:\n if (shapeFlag & 1) {\n if ((domType !== 1 || vnode.type.toLowerCase() !== node.tagName.toLowerCase()) && !isTemplateNode(node)) {\n nextNode = onMismatch();\n } else {\n nextNode = hydrateElement(\n node,\n vnode,\n parentComponent,\n parentSuspense,\n slotScopeIds,\n optimized\n );\n }\n } else if (shapeFlag & 6) {\n vnode.slotScopeIds = slotScopeIds;\n const container = parentNode(node);\n if (isFragmentStart) {\n nextNode = locateClosingAnchor(node);\n } else if (isComment(node) && node.data === \"teleport start\") {\n nextNode = locateClosingAnchor(node, node.data, \"teleport end\");\n } else {\n nextNode = nextSibling(node);\n }\n mountComponent(\n vnode,\n container,\n null,\n parentComponent,\n parentSuspense,\n getContainerType(container),\n optimized\n );\n if (isAsyncWrapper(vnode) && !vnode.type.__asyncResolved) {\n let subTree;\n if (isFragmentStart) {\n subTree = createVNode(Fragment);\n subTree.anchor = nextNode ? nextNode.previousSibling : container.lastChild;\n } else {\n subTree = node.nodeType === 3 ? createTextVNode(\"\") : createVNode(\"div\");\n }\n subTree.el = node;\n vnode.component.subTree = subTree;\n }\n } else if (shapeFlag & 64) {\n if (domType !== 8) {\n nextNode = onMismatch();\n } else {\n nextNode = vnode.type.hydrate(\n node,\n vnode,\n parentComponent,\n parentSuspense,\n slotScopeIds,\n optimized,\n rendererInternals,\n hydrateChildren\n );\n }\n } else if (shapeFlag & 128) {\n nextNode = vnode.type.hydrate(\n node,\n vnode,\n parentComponent,\n parentSuspense,\n getContainerType(parentNode(node)),\n slotScopeIds,\n optimized,\n rendererInternals,\n hydrateNode\n );\n } else if (!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_HYDRATION_MISMATCH_DETAILS__) {\n warn$1(\"Invalid HostVNode type:\", type, `(${typeof type})`);\n }\n }\n if (ref != null) {\n setRef(ref, null, parentSuspense, vnode);\n }\n return nextNode;\n };\n const hydrateElement = (el, vnode, parentComponent, parentSuspense, slotScopeIds, optimized) => {\n optimized = optimized || !!vnode.dynamicChildren;\n const { type, props, patchFlag, shapeFlag, dirs, transition } = vnode;\n const forcePatch = type === \"input\" || type === \"option\";\n if (!!(process.env.NODE_ENV !== \"production\") || forcePatch || patchFlag !== -1) {\n if (dirs) {\n invokeDirectiveHook(vnode, null, parentComponent, \"created\");\n }\n let needCallTransitionHooks = false;\n if (isTemplateNode(el)) {\n needCallTransitionHooks = needTransition(\n null,\n // no need check parentSuspense in hydration\n transition\n ) && parentComponent && parentComponent.vnode.props && parentComponent.vnode.props.appear;\n const content = el.content.firstChild;\n if (needCallTransitionHooks) {\n const cls = content.getAttribute(\"class\");\n if (cls) content.$cls = cls;\n transition.beforeEnter(content);\n }\n replaceNode(content, el, parentComponent);\n vnode.el = el = content;\n }\n if (shapeFlag & 16 && // skip if element has innerHTML / textContent\n !(props && (props.innerHTML || props.textContent))) {\n let next = hydrateChildren(\n el.firstChild,\n vnode,\n el,\n parentComponent,\n parentSuspense,\n slotScopeIds,\n optimized\n );\n let hasWarned = false;\n while (next) {\n if (!isMismatchAllowed(el, 1 /* CHILDREN */)) {\n if ((!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_HYDRATION_MISMATCH_DETAILS__) && !hasWarned) {\n warn$1(\n `Hydration children mismatch on`,\n el,\n `\nServer rendered element contains more child nodes than client vdom.`\n );\n hasWarned = true;\n }\n logMismatchError();\n }\n const cur = next;\n next = next.nextSibling;\n remove(cur);\n }\n } else if (shapeFlag & 8) {\n let clientText = vnode.children;\n if (clientText[0] === \"\\n\" && (el.tagName === \"PRE\" || el.tagName === \"TEXTAREA\")) {\n clientText = clientText.slice(1);\n }\n const { textContent } = el;\n if (textContent !== clientText && // innerHTML normalize \\r\\n or \\r into a single \\n in the DOM\n textContent !== clientText.replace(/\\r\\n|\\r/g, \"\\n\")) {\n if (!isMismatchAllowed(el, 0 /* TEXT */)) {\n (!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_HYDRATION_MISMATCH_DETAILS__) && warn$1(\n `Hydration text content mismatch on`,\n el,\n `\n - rendered on server: ${textContent}\n - expected on client: ${clientText}`\n );\n logMismatchError();\n }\n el.textContent = vnode.children;\n }\n }\n if (props) {\n if (!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_HYDRATION_MISMATCH_DETAILS__ || forcePatch || !optimized || patchFlag & (16 | 32)) {\n const isCustomElement = el.tagName.includes(\"-\");\n for (const key in props) {\n if ((!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_HYDRATION_MISMATCH_DETAILS__) && // #11189 skip if this node has directives that have created hooks\n // as it could have mutated the DOM in any possible way\n !(dirs && dirs.some((d) => d.dir.created)) && propHasMismatch(el, key, props[key], vnode, parentComponent)) {\n logMismatchError();\n }\n if (forcePatch && (key.endsWith(\"value\") || key === \"indeterminate\") || isOn(key) && !isReservedProp(key) || // force hydrate v-bind with .prop modifiers\n key[0] === \".\" || isCustomElement) {\n patchProp(el, key, null, props[key], void 0, parentComponent);\n }\n }\n } else if (props.onClick) {\n patchProp(\n el,\n \"onClick\",\n null,\n props.onClick,\n void 0,\n parentComponent\n );\n } else if (patchFlag & 4 && isReactive(props.style)) {\n for (const key in props.style) props.style[key];\n }\n }\n let vnodeHooks;\n if (vnodeHooks = props && props.onVnodeBeforeMount) {\n invokeVNodeHook(vnodeHooks, parentComponent, vnode);\n }\n if (dirs) {\n invokeDirectiveHook(vnode, null, parentComponent, \"beforeMount\");\n }\n if ((vnodeHooks = props && props.onVnodeMounted) || dirs || needCallTransitionHooks) {\n queueEffectWithSuspense(() => {\n vnodeHooks && invokeVNodeHook(vnodeHooks, parentComponent, vnode);\n needCallTransitionHooks && transition.enter(el);\n dirs && invokeDirectiveHook(vnode, null, parentComponent, \"mounted\");\n }, parentSuspense);\n }\n }\n return el.nextSibling;\n };\n const hydrateChildren = (node, parentVNode, container, parentComponent, parentSuspense, slotScopeIds, optimized) => {\n optimized = optimized || !!parentVNode.dynamicChildren;\n const children = parentVNode.children;\n const l = children.length;\n let hasWarned = false;\n for (let i = 0; i < l; i++) {\n const vnode = optimized ? children[i] : children[i] = normalizeVNode(children[i]);\n const isText = vnode.type === Text;\n if (node) {\n if (isText && !optimized) {\n if (i + 1 < l && normalizeVNode(children[i + 1]).type === Text) {\n insert(\n createText(\n node.data.slice(vnode.children.length)\n ),\n container,\n nextSibling(node)\n );\n node.data = vnode.children;\n }\n }\n node = hydrateNode(\n node,\n vnode,\n parentComponent,\n parentSuspense,\n slotScopeIds,\n optimized\n );\n } else if (isText && !vnode.children) {\n insert(vnode.el = createText(\"\"), container);\n } else {\n if (!isMismatchAllowed(container, 1 /* CHILDREN */)) {\n if ((!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_HYDRATION_MISMATCH_DETAILS__) && !hasWarned) {\n warn$1(\n `Hydration children mismatch on`,\n container,\n `\nServer rendered element contains fewer child nodes than client vdom.`\n );\n hasWarned = true;\n }\n logMismatchError();\n }\n patch(\n null,\n vnode,\n container,\n null,\n parentComponent,\n parentSuspense,\n getContainerType(container),\n slotScopeIds\n );\n }\n }\n return node;\n };\n const hydrateFragment = (node, vnode, parentComponent, parentSuspense, slotScopeIds, optimized) => {\n const { slotScopeIds: fragmentSlotScopeIds } = vnode;\n if (fragmentSlotScopeIds) {\n slotScopeIds = slotScopeIds ? slotScopeIds.concat(fragmentSlotScopeIds) : fragmentSlotScopeIds;\n }\n const container = parentNode(node);\n const next = hydrateChildren(\n nextSibling(node),\n vnode,\n container,\n parentComponent,\n parentSuspense,\n slotScopeIds,\n optimized\n );\n if (next && isComment(next) && next.data === \"]\") {\n return nextSibling(vnode.anchor = next);\n } else {\n logMismatchError();\n insert(vnode.anchor = createComment(`]`), container, next);\n return next;\n }\n };\n const handleMismatch = (node, vnode, parentComponent, parentSuspense, slotScopeIds, isFragment) => {\n if (!isMismatchAllowed(node.parentElement, 1 /* CHILDREN */)) {\n (!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_HYDRATION_MISMATCH_DETAILS__) && warn$1(\n `Hydration node mismatch:\n- rendered on server:`,\n node,\n node.nodeType === 3 ? `(text)` : isComment(node) && node.data === \"[\" ? `(start of fragment)` : ``,\n `\n- expected on client:`,\n vnode.type\n );\n logMismatchError();\n }\n vnode.el = null;\n if (isFragment) {\n const end = locateClosingAnchor(node);\n while (true) {\n const next2 = nextSibling(node);\n if (next2 && next2 !== end) {\n remove(next2);\n } else {\n break;\n }\n }\n }\n const next = nextSibling(node);\n const container = parentNode(node);\n remove(node);\n patch(\n null,\n vnode,\n container,\n next,\n parentComponent,\n parentSuspense,\n getContainerType(container),\n slotScopeIds\n );\n if (parentComponent) {\n parentComponent.vnode.el = vnode.el;\n updateHOCHostEl(parentComponent, vnode.el);\n }\n return next;\n };\n const locateClosingAnchor = (node, open = \"[\", close = \"]\") => {\n let match = 0;\n while (node) {\n node = nextSibling(node);\n if (node && isComment(node)) {\n if (node.data === open) match++;\n if (node.data === close) {\n if (match === 0) {\n return nextSibling(node);\n } else {\n match--;\n }\n }\n }\n }\n return node;\n };\n const replaceNode = (newNode, oldNode, parentComponent) => {\n const parentNode2 = oldNode.parentNode;\n if (parentNode2) {\n parentNode2.replaceChild(newNode, oldNode);\n }\n let parent = parentComponent;\n while (parent) {\n if (parent.vnode.el === oldNode) {\n parent.vnode.el = parent.subTree.el = newNode;\n }\n parent = parent.parent;\n }\n };\n const isTemplateNode = (node) => {\n return node.nodeType === 1 && node.tagName === \"TEMPLATE\";\n };\n return [hydrate, hydrateNode];\n}\nfunction propHasMismatch(el, key, clientValue, vnode, instance) {\n let mismatchType;\n let mismatchKey;\n let actual;\n let expected;\n if (key === \"class\") {\n if (el.$cls) {\n actual = el.$cls;\n delete el.$cls;\n } else {\n actual = el.getAttribute(\"class\");\n }\n expected = normalizeClass(clientValue);\n if (!isSetEqual(toClassSet(actual || \"\"), toClassSet(expected))) {\n mismatchType = 2 /* CLASS */;\n mismatchKey = `class`;\n }\n } else if (key === \"style\") {\n actual = el.getAttribute(\"style\") || \"\";\n expected = isString(clientValue) ? clientValue : stringifyStyle(normalizeStyle(clientValue));\n const actualMap = toStyleMap(actual);\n const expectedMap = toStyleMap(expected);\n if (vnode.dirs) {\n for (const { dir, value } of vnode.dirs) {\n if (dir.name === \"show\" && !value) {\n expectedMap.set(\"display\", \"none\");\n }\n }\n }\n if (instance) {\n resolveCssVars(instance, vnode, expectedMap);\n }\n if (!isMapEqual(actualMap, expectedMap)) {\n mismatchType = 3 /* STYLE */;\n mismatchKey = \"style\";\n }\n } else if (el instanceof SVGElement && isKnownSvgAttr(key) || el instanceof HTMLElement && (isBooleanAttr(key) || isKnownHtmlAttr(key))) {\n if (isBooleanAttr(key)) {\n actual = el.hasAttribute(key);\n expected = includeBooleanAttr(clientValue);\n } else if (clientValue == null) {\n actual = el.hasAttribute(key);\n expected = false;\n } else {\n if (el.hasAttribute(key)) {\n actual = el.getAttribute(key);\n } else if (key === \"value\" && el.tagName === \"TEXTAREA\") {\n actual = el.value;\n } else {\n actual = false;\n }\n expected = isRenderableAttrValue(clientValue) ? String(clientValue) : false;\n }\n if (actual !== expected) {\n mismatchType = 4 /* ATTRIBUTE */;\n mismatchKey = key;\n }\n }\n if (mismatchType != null && !isMismatchAllowed(el, mismatchType)) {\n const format = (v) => v === false ? `(not rendered)` : `${mismatchKey}=\"${v}\"`;\n const preSegment = `Hydration ${MismatchTypeString[mismatchType]} mismatch on`;\n const postSegment = `\n - rendered on server: ${format(actual)}\n - expected on client: ${format(expected)}\n Note: this mismatch is check-only. The DOM will not be rectified in production due to performance overhead.\n You should fix the source of the mismatch.`;\n {\n warn$1(preSegment, el, postSegment);\n }\n return true;\n }\n return false;\n}\nfunction toClassSet(str) {\n return new Set(str.trim().split(/\\s+/));\n}\nfunction isSetEqual(a, b) {\n if (a.size !== b.size) {\n return false;\n }\n for (const s of a) {\n if (!b.has(s)) {\n return false;\n }\n }\n return true;\n}\nfunction toStyleMap(str) {\n const styleMap = /* @__PURE__ */ new Map();\n for (const item of str.split(\";\")) {\n let [key, value] = item.split(\":\");\n key = key.trim();\n value = value && value.trim();\n if (key && value) {\n styleMap.set(key, value);\n }\n }\n return styleMap;\n}\nfunction isMapEqual(a, b) {\n if (a.size !== b.size) {\n return false;\n }\n for (const [key, value] of a) {\n if (value !== b.get(key)) {\n return false;\n }\n }\n return true;\n}\nfunction resolveCssVars(instance, vnode, expectedMap) {\n const root = instance.subTree;\n if (instance.getCssVars && (vnode === root || root && root.type === Fragment && root.children.includes(vnode))) {\n const cssVars = instance.getCssVars();\n for (const key in cssVars) {\n const value = normalizeCssVarValue(cssVars[key]);\n expectedMap.set(`--${getEscapedCssVarName(key, false)}`, value);\n }\n }\n if (vnode === root && instance.parent) {\n resolveCssVars(instance.parent, instance.vnode, expectedMap);\n }\n}\nconst allowMismatchAttr = \"data-allow-mismatch\";\nconst MismatchTypeString = {\n [0 /* TEXT */]: \"text\",\n [1 /* CHILDREN */]: \"children\",\n [2 /* CLASS */]: \"class\",\n [3 /* STYLE */]: \"style\",\n [4 /* ATTRIBUTE */]: \"attribute\"\n};\nfunction isMismatchAllowed(el, allowedType) {\n if (allowedType === 0 /* TEXT */ || allowedType === 1 /* CHILDREN */) {\n while (el && !el.hasAttribute(allowMismatchAttr)) {\n el = el.parentElement;\n }\n }\n const allowedAttr = el && el.getAttribute(allowMismatchAttr);\n if (allowedAttr == null) {\n return false;\n } else if (allowedAttr === \"\") {\n return true;\n } else {\n const list = allowedAttr.split(\",\");\n if (allowedType === 0 /* TEXT */ && list.includes(\"children\")) {\n return true;\n }\n return list.includes(MismatchTypeString[allowedType]);\n }\n}\n\nconst requestIdleCallback = getGlobalThis().requestIdleCallback || ((cb) => setTimeout(cb, 1));\nconst cancelIdleCallback = getGlobalThis().cancelIdleCallback || ((id) => clearTimeout(id));\nconst hydrateOnIdle = (timeout = 1e4) => (hydrate) => {\n const id = requestIdleCallback(hydrate, { timeout });\n return () => cancelIdleCallback(id);\n};\nfunction elementIsVisibleInViewport(el) {\n const { top, left, bottom, right } = el.getBoundingClientRect();\n const { innerHeight, innerWidth } = window;\n return (top > 0 && top < innerHeight || bottom > 0 && bottom < innerHeight) && (left > 0 && left < innerWidth || right > 0 && right < innerWidth);\n}\nconst hydrateOnVisible = (opts) => (hydrate, forEach) => {\n const ob = new IntersectionObserver((entries) => {\n for (const e of entries) {\n if (!e.isIntersecting) continue;\n ob.disconnect();\n hydrate();\n break;\n }\n }, opts);\n forEach((el) => {\n if (!(el instanceof Element)) return;\n if (elementIsVisibleInViewport(el)) {\n hydrate();\n ob.disconnect();\n return false;\n }\n ob.observe(el);\n });\n return () => ob.disconnect();\n};\nconst hydrateOnMediaQuery = (query) => (hydrate) => {\n if (query) {\n const mql = matchMedia(query);\n if (mql.matches) {\n hydrate();\n } else {\n mql.addEventListener(\"change\", hydrate, { once: true });\n return () => mql.removeEventListener(\"change\", hydrate);\n }\n }\n};\nconst hydrateOnInteraction = (interactions = []) => (hydrate, forEach) => {\n if (isString(interactions)) interactions = [interactions];\n let hasHydrated = false;\n const doHydrate = (e) => {\n if (!hasHydrated) {\n hasHydrated = true;\n teardown();\n hydrate();\n e.target.dispatchEvent(new e.constructor(e.type, e));\n }\n };\n const teardown = () => {\n forEach((el) => {\n for (const i of interactions) {\n el.removeEventListener(i, doHydrate);\n }\n });\n };\n forEach((el) => {\n for (const i of interactions) {\n el.addEventListener(i, doHydrate, { once: true });\n }\n });\n return teardown;\n};\nfunction forEachElement(node, cb) {\n if (isComment(node) && node.data === \"[\") {\n let depth = 1;\n let next = node.nextSibling;\n while (next) {\n if (next.nodeType === 1) {\n const result = cb(next);\n if (result === false) {\n break;\n }\n } else if (isComment(next)) {\n if (next.data === \"]\") {\n if (--depth === 0) break;\n } else if (next.data === \"[\") {\n depth++;\n }\n }\n next = next.nextSibling;\n }\n } else {\n cb(node);\n }\n}\n\nconst isAsyncWrapper = (i) => !!i.type.__asyncLoader;\n// @__NO_SIDE_EFFECTS__\nfunction defineAsyncComponent(source) {\n if (isFunction(source)) {\n source = { loader: source };\n }\n const {\n loader,\n loadingComponent,\n errorComponent,\n delay = 200,\n hydrate: hydrateStrategy,\n timeout,\n // undefined = never times out\n suspensible = true,\n onError: userOnError\n } = source;\n let pendingRequest = null;\n let resolvedComp;\n let retries = 0;\n const retry = () => {\n retries++;\n pendingRequest = null;\n return load();\n };\n const load = () => {\n let thisRequest;\n return pendingRequest || (thisRequest = pendingRequest = loader().catch((err) => {\n err = err instanceof Error ? err : new Error(String(err));\n if (userOnError) {\n return new Promise((resolve, reject) => {\n const userRetry = () => resolve(retry());\n const userFail = () => reject(err);\n userOnError(err, userRetry, userFail, retries + 1);\n });\n } else {\n throw err;\n }\n }).then((comp) => {\n if (thisRequest !== pendingRequest && pendingRequest) {\n return pendingRequest;\n }\n if (!!(process.env.NODE_ENV !== \"production\") && !comp) {\n warn$1(\n `Async component loader resolved to undefined. If you are using retry(), make sure to return its return value.`\n );\n }\n if (comp && (comp.__esModule || comp[Symbol.toStringTag] === \"Module\")) {\n comp = comp.default;\n }\n if (!!(process.env.NODE_ENV !== \"production\") && comp && !isObject(comp) && !isFunction(comp)) {\n throw new Error(`Invalid async component load result: ${comp}`);\n }\n resolvedComp = comp;\n return comp;\n }));\n };\n return defineComponent({\n name: \"AsyncComponentWrapper\",\n __asyncLoader: load,\n __asyncHydrate(el, instance, hydrate) {\n let patched = false;\n (instance.bu || (instance.bu = [])).push(() => patched = true);\n const performHydrate = () => {\n if (patched) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(\n `Skipping lazy hydration for component '${getComponentName(resolvedComp) || resolvedComp.__file}': it was updated before lazy hydration performed.`\n );\n }\n return;\n }\n hydrate();\n };\n const doHydrate = hydrateStrategy ? () => {\n const teardown = hydrateStrategy(\n performHydrate,\n (cb) => forEachElement(el, cb)\n );\n if (teardown) {\n (instance.bum || (instance.bum = [])).push(teardown);\n }\n } : performHydrate;\n if (resolvedComp) {\n doHydrate();\n } else {\n load().then(() => !instance.isUnmounted && doHydrate());\n }\n },\n get __asyncResolved() {\n return resolvedComp;\n },\n setup() {\n const instance = currentInstance;\n markAsyncBoundary(instance);\n if (resolvedComp) {\n return () => createInnerComp(resolvedComp, instance);\n }\n const onError = (err) => {\n pendingRequest = null;\n handleError(\n err,\n instance,\n 13,\n !errorComponent\n );\n };\n if (suspensible && instance.suspense || isInSSRComponentSetup) {\n return load().then((comp) => {\n return () => createInnerComp(comp, instance);\n }).catch((err) => {\n onError(err);\n return () => errorComponent ? createVNode(errorComponent, {\n error: err\n }) : null;\n });\n }\n const loaded = ref(false);\n const error = ref();\n const delayed = ref(!!delay);\n if (delay) {\n setTimeout(() => {\n delayed.value = false;\n }, delay);\n }\n if (timeout != null) {\n setTimeout(() => {\n if (!loaded.value && !error.value) {\n const err = new Error(\n `Async component timed out after ${timeout}ms.`\n );\n onError(err);\n error.value = err;\n }\n }, timeout);\n }\n load().then(() => {\n loaded.value = true;\n if (instance.parent && isKeepAlive(instance.parent.vnode)) {\n instance.parent.update();\n }\n }).catch((err) => {\n onError(err);\n error.value = err;\n });\n return () => {\n if (loaded.value && resolvedComp) {\n return createInnerComp(resolvedComp, instance);\n } else if (error.value && errorComponent) {\n return createVNode(errorComponent, {\n error: error.value\n });\n } else if (loadingComponent && !delayed.value) {\n return createInnerComp(\n loadingComponent,\n instance\n );\n }\n };\n }\n });\n}\nfunction createInnerComp(comp, parent) {\n const { ref: ref2, props, children, ce } = parent.vnode;\n const vnode = createVNode(comp, props, children);\n vnode.ref = ref2;\n vnode.ce = ce;\n delete parent.vnode.ce;\n return vnode;\n}\n\nconst isKeepAlive = (vnode) => vnode.type.__isKeepAlive;\nconst KeepAliveImpl = {\n name: `KeepAlive`,\n // Marker for special handling inside the renderer. We are not using a ===\n // check directly on KeepAlive in the renderer, because importing it directly\n // would prevent it from being tree-shaken.\n __isKeepAlive: true,\n props: {\n include: [String, RegExp, Array],\n exclude: [String, RegExp, Array],\n max: [String, Number]\n },\n setup(props, { slots }) {\n const instance = getCurrentInstance();\n const sharedContext = instance.ctx;\n if (!sharedContext.renderer) {\n return () => {\n const children = slots.default && slots.default();\n return children && children.length === 1 ? children[0] : children;\n };\n }\n const cache = /* @__PURE__ */ new Map();\n const keys = /* @__PURE__ */ new Set();\n let current = null;\n if (!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_DEVTOOLS__) {\n instance.__v_cache = cache;\n }\n const parentSuspense = instance.suspense;\n const {\n renderer: {\n p: patch,\n m: move,\n um: _unmount,\n o: { createElement }\n }\n } = sharedContext;\n const storageContainer = createElement(\"div\");\n sharedContext.activate = (vnode, container, anchor, namespace, optimized) => {\n const instance2 = vnode.component;\n move(vnode, container, anchor, 0, parentSuspense);\n patch(\n instance2.vnode,\n vnode,\n container,\n anchor,\n instance2,\n parentSuspense,\n namespace,\n vnode.slotScopeIds,\n optimized\n );\n queuePostRenderEffect(() => {\n instance2.isDeactivated = false;\n if (instance2.a) {\n invokeArrayFns(instance2.a);\n }\n const vnodeHook = vnode.props && vnode.props.onVnodeMounted;\n if (vnodeHook) {\n invokeVNodeHook(vnodeHook, instance2.parent, vnode);\n }\n }, parentSuspense);\n if (!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_DEVTOOLS__) {\n devtoolsComponentAdded(instance2);\n }\n };\n sharedContext.deactivate = (vnode) => {\n const instance2 = vnode.component;\n invalidateMount(instance2.m);\n invalidateMount(instance2.a);\n move(vnode, storageContainer, null, 1, parentSuspense);\n queuePostRenderEffect(() => {\n if (instance2.da) {\n invokeArrayFns(instance2.da);\n }\n const vnodeHook = vnode.props && vnode.props.onVnodeUnmounted;\n if (vnodeHook) {\n invokeVNodeHook(vnodeHook, instance2.parent, vnode);\n }\n instance2.isDeactivated = true;\n }, parentSuspense);\n if (!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_DEVTOOLS__) {\n devtoolsComponentAdded(instance2);\n }\n if (!!(process.env.NODE_ENV !== \"production\") && true) {\n instance2.__keepAliveStorageContainer = storageContainer;\n }\n };\n function unmount(vnode) {\n resetShapeFlag(vnode);\n _unmount(vnode, instance, parentSuspense, true);\n }\n function pruneCache(filter) {\n cache.forEach((vnode, key) => {\n const name = getComponentName(vnode.type);\n if (name && !filter(name)) {\n pruneCacheEntry(key);\n }\n });\n }\n function pruneCacheEntry(key) {\n const cached = cache.get(key);\n if (cached && (!current || !isSameVNodeType(cached, current))) {\n unmount(cached);\n } else if (current) {\n resetShapeFlag(current);\n }\n cache.delete(key);\n keys.delete(key);\n }\n watch(\n () => [props.include, props.exclude],\n ([include, exclude]) => {\n include && pruneCache((name) => matches(include, name));\n exclude && pruneCache((name) => !matches(exclude, name));\n },\n // prune post-render after `current` has been updated\n { flush: \"post\", deep: true }\n );\n let pendingCacheKey = null;\n const cacheSubtree = () => {\n if (pendingCacheKey != null) {\n if (isSuspense(instance.subTree.type)) {\n queuePostRenderEffect(() => {\n cache.set(pendingCacheKey, getInnerChild(instance.subTree));\n }, instance.subTree.suspense);\n } else {\n cache.set(pendingCacheKey, getInnerChild(instance.subTree));\n }\n }\n };\n onMounted(cacheSubtree);\n onUpdated(cacheSubtree);\n onBeforeUnmount(() => {\n cache.forEach((cached) => {\n const { subTree, suspense } = instance;\n const vnode = getInnerChild(subTree);\n if (cached.type === vnode.type && cached.key === vnode.key) {\n resetShapeFlag(vnode);\n const da = vnode.component.da;\n da && queuePostRenderEffect(da, suspense);\n return;\n }\n unmount(cached);\n });\n });\n return () => {\n pendingCacheKey = null;\n if (!slots.default) {\n return current = null;\n }\n const children = slots.default();\n const rawVNode = children[0];\n if (children.length > 1) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(`KeepAlive should contain exactly one component child.`);\n }\n current = null;\n return children;\n } else if (!isVNode(rawVNode) || !(rawVNode.shapeFlag & 4) && !(rawVNode.shapeFlag & 128)) {\n current = null;\n return rawVNode;\n }\n let vnode = getInnerChild(rawVNode);\n if (vnode.type === Comment) {\n current = null;\n return vnode;\n }\n const comp = vnode.type;\n const name = getComponentName(\n isAsyncWrapper(vnode) ? vnode.type.__asyncResolved || {} : comp\n );\n const { include, exclude, max } = props;\n if (include && (!name || !matches(include, name)) || exclude && name && matches(exclude, name)) {\n vnode.shapeFlag &= -257;\n current = vnode;\n return rawVNode;\n }\n const key = vnode.key == null ? comp : vnode.key;\n const cachedVNode = cache.get(key);\n if (vnode.el) {\n vnode = cloneVNode(vnode);\n if (rawVNode.shapeFlag & 128) {\n rawVNode.ssContent = vnode;\n }\n }\n pendingCacheKey = key;\n if (cachedVNode) {\n vnode.el = cachedVNode.el;\n vnode.component = cachedVNode.component;\n if (vnode.transition) {\n setTransitionHooks(vnode, vnode.transition);\n }\n vnode.shapeFlag |= 512;\n keys.delete(key);\n keys.add(key);\n } else {\n keys.add(key);\n if (max && keys.size > parseInt(max, 10)) {\n pruneCacheEntry(keys.values().next().value);\n }\n }\n vnode.shapeFlag |= 256;\n current = vnode;\n return isSuspense(rawVNode.type) ? rawVNode : vnode;\n };\n }\n};\nconst KeepAlive = KeepAliveImpl;\nfunction matches(pattern, name) {\n if (isArray(pattern)) {\n return pattern.some((p) => matches(p, name));\n } else if (isString(pattern)) {\n return pattern.split(\",\").includes(name);\n } else if (isRegExp(pattern)) {\n pattern.lastIndex = 0;\n return pattern.test(name);\n }\n return false;\n}\nfunction onActivated(hook, target) {\n registerKeepAliveHook(hook, \"a\", target);\n}\nfunction onDeactivated(hook, target) {\n registerKeepAliveHook(hook, \"da\", target);\n}\nfunction registerKeepAliveHook(hook, type, target = currentInstance) {\n const wrappedHook = hook.__wdc || (hook.__wdc = () => {\n let current = target;\n while (current) {\n if (current.isDeactivated) {\n return;\n }\n current = current.parent;\n }\n return hook();\n });\n injectHook(type, wrappedHook, target);\n if (target) {\n let current = target.parent;\n while (current && current.parent) {\n if (isKeepAlive(current.parent.vnode)) {\n injectToKeepAliveRoot(wrappedHook, type, target, current);\n }\n current = current.parent;\n }\n }\n}\nfunction injectToKeepAliveRoot(hook, type, target, keepAliveRoot) {\n const injected = injectHook(\n type,\n hook,\n keepAliveRoot,\n true\n /* prepend */\n );\n onUnmounted(() => {\n remove(keepAliveRoot[type], injected);\n }, target);\n}\nfunction resetShapeFlag(vnode) {\n vnode.shapeFlag &= -257;\n vnode.shapeFlag &= -513;\n}\nfunction getInnerChild(vnode) {\n return vnode.shapeFlag & 128 ? vnode.ssContent : vnode;\n}\n\nfunction injectHook(type, hook, target = currentInstance, prepend = false) {\n if (target) {\n const hooks = target[type] || (target[type] = []);\n const wrappedHook = hook.__weh || (hook.__weh = (...args) => {\n pauseTracking();\n const reset = setCurrentInstance(target);\n const res = callWithAsyncErrorHandling(hook, target, type, args);\n reset();\n resetTracking();\n return res;\n });\n if (prepend) {\n hooks.unshift(wrappedHook);\n } else {\n hooks.push(wrappedHook);\n }\n return wrappedHook;\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n const apiName = toHandlerKey(ErrorTypeStrings$1[type].replace(/ hook$/, \"\"));\n warn$1(\n `${apiName} is called when there is no active component instance to be associated with. Lifecycle injection APIs can only be used during execution of setup().` + (` If you are using async setup(), make sure to register lifecycle hooks before the first await statement.` )\n );\n }\n}\nconst createHook = (lifecycle) => (hook, target = currentInstance) => {\n if (!isInSSRComponentSetup || lifecycle === \"sp\") {\n injectHook(lifecycle, (...args) => hook(...args), target);\n }\n};\nconst onBeforeMount = createHook(\"bm\");\nconst onMounted = createHook(\"m\");\nconst onBeforeUpdate = createHook(\n \"bu\"\n);\nconst onUpdated = createHook(\"u\");\nconst onBeforeUnmount = createHook(\n \"bum\"\n);\nconst onUnmounted = createHook(\"um\");\nconst onServerPrefetch = createHook(\n \"sp\"\n);\nconst onRenderTriggered = createHook(\"rtg\");\nconst onRenderTracked = createHook(\"rtc\");\nfunction onErrorCaptured(hook, target = currentInstance) {\n injectHook(\"ec\", hook, target);\n}\n\nconst COMPONENTS = \"components\";\nconst DIRECTIVES = \"directives\";\nfunction resolveComponent(name, maybeSelfReference) {\n return resolveAsset(COMPONENTS, name, true, maybeSelfReference) || name;\n}\nconst NULL_DYNAMIC_COMPONENT = Symbol.for(\"v-ndc\");\nfunction resolveDynamicComponent(component) {\n if (isString(component)) {\n return resolveAsset(COMPONENTS, component, false) || component;\n } else {\n return component || NULL_DYNAMIC_COMPONENT;\n }\n}\nfunction resolveDirective(name) {\n return resolveAsset(DIRECTIVES, name);\n}\nfunction resolveAsset(type, name, warnMissing = true, maybeSelfReference = false) {\n const instance = currentRenderingInstance || currentInstance;\n if (instance) {\n const Component = instance.type;\n if (type === COMPONENTS) {\n const selfName = getComponentName(\n Component,\n false\n );\n if (selfName && (selfName === name || selfName === camelize(name) || selfName === capitalize(camelize(name)))) {\n return Component;\n }\n }\n const res = (\n // local registration\n // check instance[type] first which is resolved for options API\n resolve(instance[type] || Component[type], name) || // global registration\n resolve(instance.appContext[type], name)\n );\n if (!res && maybeSelfReference) {\n return Component;\n }\n if (!!(process.env.NODE_ENV !== \"production\") && warnMissing && !res) {\n const extra = type === COMPONENTS ? `\nIf this is a native custom element, make sure to exclude it from component resolution via compilerOptions.isCustomElement.` : ``;\n warn$1(`Failed to resolve ${type.slice(0, -1)}: ${name}${extra}`);\n }\n return res;\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(\n `resolve${capitalize(type.slice(0, -1))} can only be used in render() or setup().`\n );\n }\n}\nfunction resolve(registry, name) {\n return registry && (registry[name] || registry[camelize(name)] || registry[capitalize(camelize(name))]);\n}\n\nfunction renderList(source, renderItem, cache, index) {\n let ret;\n const cached = cache && cache[index];\n const sourceIsArray = isArray(source);\n if (sourceIsArray || isString(source)) {\n const sourceIsReactiveArray = sourceIsArray && isReactive(source);\n let needsWrap = false;\n let isReadonlySource = false;\n if (sourceIsReactiveArray) {\n needsWrap = !isShallow(source);\n isReadonlySource = isReadonly(source);\n source = shallowReadArray(source);\n }\n ret = new Array(source.length);\n for (let i = 0, l = source.length; i < l; i++) {\n ret[i] = renderItem(\n needsWrap ? isReadonlySource ? toReadonly(toReactive(source[i])) : toReactive(source[i]) : source[i],\n i,\n void 0,\n cached && cached[i]\n );\n }\n } else if (typeof source === \"number\") {\n if (!!(process.env.NODE_ENV !== \"production\") && !Number.isInteger(source)) {\n warn$1(`The v-for range expect an integer value but got ${source}.`);\n }\n ret = new Array(source);\n for (let i = 0; i < source; i++) {\n ret[i] = renderItem(i + 1, i, void 0, cached && cached[i]);\n }\n } else if (isObject(source)) {\n if (source[Symbol.iterator]) {\n ret = Array.from(\n source,\n (item, i) => renderItem(item, i, void 0, cached && cached[i])\n );\n } else {\n const keys = Object.keys(source);\n ret = new Array(keys.length);\n for (let i = 0, l = keys.length; i < l; i++) {\n const key = keys[i];\n ret[i] = renderItem(source[key], key, i, cached && cached[i]);\n }\n }\n } else {\n ret = [];\n }\n if (cache) {\n cache[index] = ret;\n }\n return ret;\n}\n\nfunction createSlots(slots, dynamicSlots) {\n for (let i = 0; i < dynamicSlots.length; i++) {\n const slot = dynamicSlots[i];\n if (isArray(slot)) {\n for (let j = 0; j < slot.length; j++) {\n slots[slot[j].name] = slot[j].fn;\n }\n } else if (slot) {\n slots[slot.name] = slot.key ? (...args) => {\n const res = slot.fn(...args);\n if (res) res.key = slot.key;\n return res;\n } : slot.fn;\n }\n }\n return slots;\n}\n\nfunction renderSlot(slots, name, props = {}, fallback, noSlotted) {\n if (currentRenderingInstance.ce || currentRenderingInstance.parent && isAsyncWrapper(currentRenderingInstance.parent) && currentRenderingInstance.parent.ce) {\n const hasProps = Object.keys(props).length > 0;\n if (name !== \"default\") props.name = name;\n return openBlock(), createBlock(\n Fragment,\n null,\n [createVNode(\"slot\", props, fallback && fallback())],\n hasProps ? -2 : 64\n );\n }\n let slot = slots[name];\n if (!!(process.env.NODE_ENV !== \"production\") && slot && slot.length > 1) {\n warn$1(\n `SSR-optimized slot function detected in a non-SSR-optimized render function. You need to mark this component with $dynamic-slots in the parent template.`\n );\n slot = () => [];\n }\n if (slot && slot._c) {\n slot._d = false;\n }\n openBlock();\n const validSlotContent = slot && ensureValidVNode(slot(props));\n const slotKey = props.key || // slot content array of a dynamic conditional slot may have a branch\n // key attached in the `createSlots` helper, respect that\n validSlotContent && validSlotContent.key;\n const rendered = createBlock(\n Fragment,\n {\n key: (slotKey && !isSymbol(slotKey) ? slotKey : `_${name}`) + // #7256 force differentiate fallback content from actual content\n (!validSlotContent && fallback ? \"_fb\" : \"\")\n },\n validSlotContent || (fallback ? fallback() : []),\n validSlotContent && slots._ === 1 ? 64 : -2\n );\n if (!noSlotted && rendered.scopeId) {\n rendered.slotScopeIds = [rendered.scopeId + \"-s\"];\n }\n if (slot && slot._c) {\n slot._d = true;\n }\n return rendered;\n}\nfunction ensureValidVNode(vnodes) {\n return vnodes.some((child) => {\n if (!isVNode(child)) return true;\n if (child.type === Comment) return false;\n if (child.type === Fragment && !ensureValidVNode(child.children))\n return false;\n return true;\n }) ? vnodes : null;\n}\n\nfunction toHandlers(obj, preserveCaseIfNecessary) {\n const ret = {};\n if (!!(process.env.NODE_ENV !== \"production\") && !isObject(obj)) {\n warn$1(`v-on with no argument expects an object value.`);\n return ret;\n }\n for (const key in obj) {\n ret[preserveCaseIfNecessary && /[A-Z]/.test(key) ? `on:${key}` : toHandlerKey(key)] = obj[key];\n }\n return ret;\n}\n\nconst getPublicInstance = (i) => {\n if (!i) return null;\n if (isStatefulComponent(i)) return getComponentPublicInstance(i);\n return getPublicInstance(i.parent);\n};\nconst publicPropertiesMap = (\n // Move PURE marker to new line to workaround compiler discarding it\n // due to type annotation\n /* @__PURE__ */ extend(/* @__PURE__ */ Object.create(null), {\n $: (i) => i,\n $el: (i) => i.vnode.el,\n $data: (i) => i.data,\n $props: (i) => !!(process.env.NODE_ENV !== \"production\") ? shallowReadonly(i.props) : i.props,\n $attrs: (i) => !!(process.env.NODE_ENV !== \"production\") ? shallowReadonly(i.attrs) : i.attrs,\n $slots: (i) => !!(process.env.NODE_ENV !== \"production\") ? shallowReadonly(i.slots) : i.slots,\n $refs: (i) => !!(process.env.NODE_ENV !== \"production\") ? shallowReadonly(i.refs) : i.refs,\n $parent: (i) => getPublicInstance(i.parent),\n $root: (i) => getPublicInstance(i.root),\n $host: (i) => i.ce,\n $emit: (i) => i.emit,\n $options: (i) => __VUE_OPTIONS_API__ ? resolveMergedOptions(i) : i.type,\n $forceUpdate: (i) => i.f || (i.f = () => {\n queueJob(i.update);\n }),\n $nextTick: (i) => i.n || (i.n = nextTick.bind(i.proxy)),\n $watch: (i) => __VUE_OPTIONS_API__ ? instanceWatch.bind(i) : NOOP\n })\n);\nconst isReservedPrefix = (key) => key === \"_\" || key === \"$\";\nconst hasSetupBinding = (state, key) => state !== EMPTY_OBJ && !state.__isScriptSetup && hasOwn(state, key);\nconst PublicInstanceProxyHandlers = {\n get({ _: instance }, key) {\n if (key === \"__v_skip\") {\n return true;\n }\n const { ctx, setupState, data, props, accessCache, type, appContext } = instance;\n if (!!(process.env.NODE_ENV !== \"production\") && key === \"__isVue\") {\n return true;\n }\n if (key[0] !== \"$\") {\n const n = accessCache[key];\n if (n !== void 0) {\n switch (n) {\n case 1 /* SETUP */:\n return setupState[key];\n case 2 /* DATA */:\n return data[key];\n case 4 /* CONTEXT */:\n return ctx[key];\n case 3 /* PROPS */:\n return props[key];\n }\n } else if (hasSetupBinding(setupState, key)) {\n accessCache[key] = 1 /* SETUP */;\n return setupState[key];\n } else if (__VUE_OPTIONS_API__ && data !== EMPTY_OBJ && hasOwn(data, key)) {\n accessCache[key] = 2 /* DATA */;\n return data[key];\n } else if (hasOwn(props, key)) {\n accessCache[key] = 3 /* PROPS */;\n return props[key];\n } else if (ctx !== EMPTY_OBJ && hasOwn(ctx, key)) {\n accessCache[key] = 4 /* CONTEXT */;\n return ctx[key];\n } else if (!__VUE_OPTIONS_API__ || shouldCacheAccess) {\n accessCache[key] = 0 /* OTHER */;\n }\n }\n const publicGetter = publicPropertiesMap[key];\n let cssModule, globalProperties;\n if (publicGetter) {\n if (key === \"$attrs\") {\n track(instance.attrs, \"get\", \"\");\n !!(process.env.NODE_ENV !== \"production\") && markAttrsAccessed();\n } else if (!!(process.env.NODE_ENV !== \"production\") && key === \"$slots\") {\n track(instance, \"get\", key);\n }\n return publicGetter(instance);\n } else if (\n // css module (injected by vue-loader)\n (cssModule = type.__cssModules) && (cssModule = cssModule[key])\n ) {\n return cssModule;\n } else if (ctx !== EMPTY_OBJ && hasOwn(ctx, key)) {\n accessCache[key] = 4 /* CONTEXT */;\n return ctx[key];\n } else if (\n // global properties\n globalProperties = appContext.config.globalProperties, hasOwn(globalProperties, key)\n ) {\n {\n return globalProperties[key];\n }\n } else if (!!(process.env.NODE_ENV !== \"production\") && currentRenderingInstance && (!isString(key) || // #1091 avoid internal isRef/isVNode checks on component instance leading\n // to infinite warning loop\n key.indexOf(\"__v\") !== 0)) {\n if (data !== EMPTY_OBJ && isReservedPrefix(key[0]) && hasOwn(data, key)) {\n warn$1(\n `Property ${JSON.stringify(\n key\n )} must be accessed via $data because it starts with a reserved character (\"$\" or \"_\") and is not proxied on the render context.`\n );\n } else if (instance === currentRenderingInstance) {\n warn$1(\n `Property ${JSON.stringify(key)} was accessed during render but is not defined on instance.`\n );\n }\n }\n },\n set({ _: instance }, key, value) {\n const { data, setupState, ctx } = instance;\n if (hasSetupBinding(setupState, key)) {\n setupState[key] = value;\n return true;\n } else if (!!(process.env.NODE_ENV !== \"production\") && setupState.__isScriptSetup && hasOwn(setupState, key)) {\n warn$1(`Cannot mutate <script setup> binding \"${key}\" from Options API.`);\n return false;\n } else if (__VUE_OPTIONS_API__ && data !== EMPTY_OBJ && hasOwn(data, key)) {\n data[key] = value;\n return true;\n } else if (hasOwn(instance.props, key)) {\n !!(process.env.NODE_ENV !== \"production\") && warn$1(`Attempting to mutate prop \"${key}\". Props are readonly.`);\n return false;\n }\n if (key[0] === \"$\" && key.slice(1) in instance) {\n !!(process.env.NODE_ENV !== \"production\") && warn$1(\n `Attempting to mutate public property \"${key}\". Properties starting with $ are reserved and readonly.`\n );\n return false;\n } else {\n if (!!(process.env.NODE_ENV !== \"production\") && key in instance.appContext.config.globalProperties) {\n Object.defineProperty(ctx, key, {\n enumerable: true,\n configurable: true,\n value\n });\n } else {\n ctx[key] = value;\n }\n }\n return true;\n },\n has({\n _: { data, setupState, accessCache, ctx, appContext, props, type }\n }, key) {\n let cssModules;\n return !!(accessCache[key] || __VUE_OPTIONS_API__ && data !== EMPTY_OBJ && key[0] !== \"$\" && hasOwn(data, key) || hasSetupBinding(setupState, key) || hasOwn(props, key) || hasOwn(ctx, key) || hasOwn(publicPropertiesMap, key) || hasOwn(appContext.config.globalProperties, key) || (cssModules = type.__cssModules) && cssModules[key]);\n },\n defineProperty(target, key, descriptor) {\n if (descriptor.get != null) {\n target._.accessCache[key] = 0;\n } else if (hasOwn(descriptor, \"value\")) {\n this.set(target, key, descriptor.value, null);\n }\n return Reflect.defineProperty(target, key, descriptor);\n }\n};\nif (!!(process.env.NODE_ENV !== \"production\") && true) {\n PublicInstanceProxyHandlers.ownKeys = (target) => {\n warn$1(\n `Avoid app logic that relies on enumerating keys on a component instance. The keys will be empty in production mode to avoid performance overhead.`\n );\n return Reflect.ownKeys(target);\n };\n}\nconst RuntimeCompiledPublicInstanceProxyHandlers = /* @__PURE__ */ extend({}, PublicInstanceProxyHandlers, {\n get(target, key) {\n if (key === Symbol.unscopables) {\n return;\n }\n return PublicInstanceProxyHandlers.get(target, key, target);\n },\n has(_, key) {\n const has = key[0] !== \"_\" && !isGloballyAllowed(key);\n if (!!(process.env.NODE_ENV !== \"production\") && !has && PublicInstanceProxyHandlers.has(_, key)) {\n warn$1(\n `Property ${JSON.stringify(\n key\n )} should not start with _ which is a reserved prefix for Vue internals.`\n );\n }\n return has;\n }\n});\nfunction createDevRenderContext(instance) {\n const target = {};\n Object.defineProperty(target, `_`, {\n configurable: true,\n enumerable: false,\n get: () => instance\n });\n Object.keys(publicPropertiesMap).forEach((key) => {\n Object.defineProperty(target, key, {\n configurable: true,\n enumerable: false,\n get: () => publicPropertiesMap[key](instance),\n // intercepted by the proxy so no need for implementation,\n // but needed to prevent set errors\n set: NOOP\n });\n });\n return target;\n}\nfunction exposePropsOnRenderContext(instance) {\n const {\n ctx,\n propsOptions: [propsOptions]\n } = instance;\n if (propsOptions) {\n Object.keys(propsOptions).forEach((key) => {\n Object.defineProperty(ctx, key, {\n enumerable: true,\n configurable: true,\n get: () => instance.props[key],\n set: NOOP\n });\n });\n }\n}\nfunction exposeSetupStateOnRenderContext(instance) {\n const { ctx, setupState } = instance;\n Object.keys(toRaw(setupState)).forEach((key) => {\n if (!setupState.__isScriptSetup) {\n if (isReservedPrefix(key[0])) {\n warn$1(\n `setup() return property ${JSON.stringify(\n key\n )} should not start with \"$\" or \"_\" which are reserved prefixes for Vue internals.`\n );\n return;\n }\n Object.defineProperty(ctx, key, {\n enumerable: true,\n configurable: true,\n get: () => setupState[key],\n set: NOOP\n });\n }\n });\n}\n\nconst warnRuntimeUsage = (method) => warn$1(\n `${method}() is a compiler-hint helper that is only usable inside <script setup> of a single file component. Its arguments should be compiled away and passing it at runtime has no effect.`\n);\nfunction defineProps() {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warnRuntimeUsage(`defineProps`);\n }\n return null;\n}\nfunction defineEmits() {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warnRuntimeUsage(`defineEmits`);\n }\n return null;\n}\nfunction defineExpose(exposed) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warnRuntimeUsage(`defineExpose`);\n }\n}\nfunction defineOptions(options) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warnRuntimeUsage(`defineOptions`);\n }\n}\nfunction defineSlots() {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warnRuntimeUsage(`defineSlots`);\n }\n return null;\n}\nfunction defineModel() {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warnRuntimeUsage(\"defineModel\");\n }\n}\nfunction withDefaults(props, defaults) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warnRuntimeUsage(`withDefaults`);\n }\n return null;\n}\nfunction useSlots() {\n return getContext(\"useSlots\").slots;\n}\nfunction useAttrs() {\n return getContext(\"useAttrs\").attrs;\n}\nfunction getContext(calledFunctionName) {\n const i = getCurrentInstance();\n if (!!(process.env.NODE_ENV !== \"production\") && !i) {\n warn$1(`${calledFunctionName}() called without active instance.`);\n }\n return i.setupContext || (i.setupContext = createSetupContext(i));\n}\nfunction normalizePropsOrEmits(props) {\n return isArray(props) ? props.reduce(\n (normalized, p) => (normalized[p] = null, normalized),\n {}\n ) : props;\n}\nfunction mergeDefaults(raw, defaults) {\n const props = normalizePropsOrEmits(raw);\n for (const key in defaults) {\n if (key.startsWith(\"__skip\")) continue;\n let opt = props[key];\n if (opt) {\n if (isArray(opt) || isFunction(opt)) {\n opt = props[key] = { type: opt, default: defaults[key] };\n } else {\n opt.default = defaults[key];\n }\n } else if (opt === null) {\n opt = props[key] = { default: defaults[key] };\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(`props default key \"${key}\" has no corresponding declaration.`);\n }\n if (opt && defaults[`__skip_${key}`]) {\n opt.skipFactory = true;\n }\n }\n return props;\n}\nfunction mergeModels(a, b) {\n if (!a || !b) return a || b;\n if (isArray(a) && isArray(b)) return a.concat(b);\n return extend({}, normalizePropsOrEmits(a), normalizePropsOrEmits(b));\n}\nfunction createPropsRestProxy(props, excludedKeys) {\n const ret = {};\n for (const key in props) {\n if (!excludedKeys.includes(key)) {\n Object.defineProperty(ret, key, {\n enumerable: true,\n get: () => props[key]\n });\n }\n }\n return ret;\n}\nfunction withAsyncContext(getAwaitable) {\n const ctx = getCurrentInstance();\n if (!!(process.env.NODE_ENV !== \"production\") && !ctx) {\n warn$1(\n `withAsyncContext called without active current instance. This is likely a bug.`\n );\n }\n let awaitable = getAwaitable();\n unsetCurrentInstance();\n if (isPromise(awaitable)) {\n awaitable = awaitable.catch((e) => {\n setCurrentInstance(ctx);\n throw e;\n });\n }\n return [awaitable, () => setCurrentInstance(ctx)];\n}\n\nfunction createDuplicateChecker() {\n const cache = /* @__PURE__ */ Object.create(null);\n return (type, key) => {\n if (cache[key]) {\n warn$1(`${type} property \"${key}\" is already defined in ${cache[key]}.`);\n } else {\n cache[key] = type;\n }\n };\n}\nlet shouldCacheAccess = true;\nfunction applyOptions(instance) {\n const options = resolveMergedOptions(instance);\n const publicThis = instance.proxy;\n const ctx = instance.ctx;\n shouldCacheAccess = false;\n if (options.beforeCreate) {\n callHook(options.beforeCreate, instance, \"bc\");\n }\n const {\n // state\n data: dataOptions,\n computed: computedOptions,\n methods,\n watch: watchOptions,\n provide: provideOptions,\n inject: injectOptions,\n // lifecycle\n created,\n beforeMount,\n mounted,\n beforeUpdate,\n updated,\n activated,\n deactivated,\n beforeDestroy,\n beforeUnmount,\n destroyed,\n unmounted,\n render,\n renderTracked,\n renderTriggered,\n errorCaptured,\n serverPrefetch,\n // public API\n expose,\n inheritAttrs,\n // assets\n components,\n directives,\n filters\n } = options;\n const checkDuplicateProperties = !!(process.env.NODE_ENV !== \"production\") ? createDuplicateChecker() : null;\n if (!!(process.env.NODE_ENV !== \"production\")) {\n const [propsOptions] = instance.propsOptions;\n if (propsOptions) {\n for (const key in propsOptions) {\n checkDuplicateProperties(\"Props\" /* PROPS */, key);\n }\n }\n }\n if (injectOptions) {\n resolveInjections(injectOptions, ctx, checkDuplicateProperties);\n }\n if (methods) {\n for (const key in methods) {\n const methodHandler = methods[key];\n if (isFunction(methodHandler)) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n Object.defineProperty(ctx, key, {\n value: methodHandler.bind(publicThis),\n configurable: true,\n enumerable: true,\n writable: true\n });\n } else {\n ctx[key] = methodHandler.bind(publicThis);\n }\n if (!!(process.env.NODE_ENV !== \"production\")) {\n checkDuplicateProperties(\"Methods\" /* METHODS */, key);\n }\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(\n `Method \"${key}\" has type \"${typeof methodHandler}\" in the component definition. Did you reference the function correctly?`\n );\n }\n }\n }\n if (dataOptions) {\n if (!!(process.env.NODE_ENV !== \"production\") && !isFunction(dataOptions)) {\n warn$1(\n `The data option must be a function. Plain object usage is no longer supported.`\n );\n }\n const data = dataOptions.call(publicThis, publicThis);\n if (!!(process.env.NODE_ENV !== \"production\") && isPromise(data)) {\n warn$1(\n `data() returned a Promise - note data() cannot be async; If you intend to perform data fetching before component renders, use async setup() + <Suspense>.`\n );\n }\n if (!isObject(data)) {\n !!(process.env.NODE_ENV !== \"production\") && warn$1(`data() should return an object.`);\n } else {\n instance.data = reactive(data);\n if (!!(process.env.NODE_ENV !== \"production\")) {\n for (const key in data) {\n checkDuplicateProperties(\"Data\" /* DATA */, key);\n if (!isReservedPrefix(key[0])) {\n Object.defineProperty(ctx, key, {\n configurable: true,\n enumerable: true,\n get: () => data[key],\n set: NOOP\n });\n }\n }\n }\n }\n }\n shouldCacheAccess = true;\n if (computedOptions) {\n for (const key in computedOptions) {\n const opt = computedOptions[key];\n const get = isFunction(opt) ? opt.bind(publicThis, publicThis) : isFunction(opt.get) ? opt.get.bind(publicThis, publicThis) : NOOP;\n if (!!(process.env.NODE_ENV !== \"production\") && get === NOOP) {\n warn$1(`Computed property \"${key}\" has no getter.`);\n }\n const set = !isFunction(opt) && isFunction(opt.set) ? opt.set.bind(publicThis) : !!(process.env.NODE_ENV !== \"production\") ? () => {\n warn$1(\n `Write operation failed: computed property \"${key}\" is readonly.`\n );\n } : NOOP;\n const c = computed({\n get,\n set\n });\n Object.defineProperty(ctx, key, {\n enumerable: true,\n configurable: true,\n get: () => c.value,\n set: (v) => c.value = v\n });\n if (!!(process.env.NODE_ENV !== \"production\")) {\n checkDuplicateProperties(\"Computed\" /* COMPUTED */, key);\n }\n }\n }\n if (watchOptions) {\n for (const key in watchOptions) {\n createWatcher(watchOptions[key], ctx, publicThis, key);\n }\n }\n if (provideOptions) {\n const provides = isFunction(provideOptions) ? provideOptions.call(publicThis) : provideOptions;\n Reflect.ownKeys(provides).forEach((key) => {\n provide(key, provides[key]);\n });\n }\n if (created) {\n callHook(created, instance, \"c\");\n }\n function registerLifecycleHook(register, hook) {\n if (isArray(hook)) {\n hook.forEach((_hook) => register(_hook.bind(publicThis)));\n } else if (hook) {\n register(hook.bind(publicThis));\n }\n }\n registerLifecycleHook(onBeforeMount, beforeMount);\n registerLifecycleHook(onMounted, mounted);\n registerLifecycleHook(onBeforeUpdate, beforeUpdate);\n registerLifecycleHook(onUpdated, updated);\n registerLifecycleHook(onActivated, activated);\n registerLifecycleHook(onDeactivated, deactivated);\n registerLifecycleHook(onErrorCaptured, errorCaptured);\n registerLifecycleHook(onRenderTracked, renderTracked);\n registerLifecycleHook(onRenderTriggered, renderTriggered);\n registerLifecycleHook(onBeforeUnmount, beforeUnmount);\n registerLifecycleHook(onUnmounted, unmounted);\n registerLifecycleHook(onServerPrefetch, serverPrefetch);\n if (isArray(expose)) {\n if (expose.length) {\n const exposed = instance.exposed || (instance.exposed = {});\n expose.forEach((key) => {\n Object.defineProperty(exposed, key, {\n get: () => publicThis[key],\n set: (val) => publicThis[key] = val,\n enumerable: true\n });\n });\n } else if (!instance.exposed) {\n instance.exposed = {};\n }\n }\n if (render && instance.render === NOOP) {\n instance.render = render;\n }\n if (inheritAttrs != null) {\n instance.inheritAttrs = inheritAttrs;\n }\n if (components) instance.components = components;\n if (directives) instance.directives = directives;\n if (serverPrefetch) {\n markAsyncBoundary(instance);\n }\n}\nfunction resolveInjections(injectOptions, ctx, checkDuplicateProperties = NOOP) {\n if (isArray(injectOptions)) {\n injectOptions = normalizeInject(injectOptions);\n }\n for (const key in injectOptions) {\n const opt = injectOptions[key];\n let injected;\n if (isObject(opt)) {\n if (\"default\" in opt) {\n injected = inject(\n opt.from || key,\n opt.default,\n true\n );\n } else {\n injected = inject(opt.from || key);\n }\n } else {\n injected = inject(opt);\n }\n if (isRef(injected)) {\n Object.defineProperty(ctx, key, {\n enumerable: true,\n configurable: true,\n get: () => injected.value,\n set: (v) => injected.value = v\n });\n } else {\n ctx[key] = injected;\n }\n if (!!(process.env.NODE_ENV !== \"production\")) {\n checkDuplicateProperties(\"Inject\" /* INJECT */, key);\n }\n }\n}\nfunction callHook(hook, instance, type) {\n callWithAsyncErrorHandling(\n isArray(hook) ? hook.map((h) => h.bind(instance.proxy)) : hook.bind(instance.proxy),\n instance,\n type\n );\n}\nfunction createWatcher(raw, ctx, publicThis, key) {\n let getter = key.includes(\".\") ? createPathGetter(publicThis, key) : () => publicThis[key];\n if (isString(raw)) {\n const handler = ctx[raw];\n if (isFunction(handler)) {\n {\n watch(getter, handler);\n }\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(`Invalid watch handler specified by key \"${raw}\"`, handler);\n }\n } else if (isFunction(raw)) {\n {\n watch(getter, raw.bind(publicThis));\n }\n } else if (isObject(raw)) {\n if (isArray(raw)) {\n raw.forEach((r) => createWatcher(r, ctx, publicThis, key));\n } else {\n const handler = isFunction(raw.handler) ? raw.handler.bind(publicThis) : ctx[raw.handler];\n if (isFunction(handler)) {\n watch(getter, handler, raw);\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(`Invalid watch handler specified by key \"${raw.handler}\"`, handler);\n }\n }\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(`Invalid watch option: \"${key}\"`, raw);\n }\n}\nfunction resolveMergedOptions(instance) {\n const base = instance.type;\n const { mixins, extends: extendsOptions } = base;\n const {\n mixins: globalMixins,\n optionsCache: cache,\n config: { optionMergeStrategies }\n } = instance.appContext;\n const cached = cache.get(base);\n let resolved;\n if (cached) {\n resolved = cached;\n } else if (!globalMixins.length && !mixins && !extendsOptions) {\n {\n resolved = base;\n }\n } else {\n resolved = {};\n if (globalMixins.length) {\n globalMixins.forEach(\n (m) => mergeOptions(resolved, m, optionMergeStrategies, true)\n );\n }\n mergeOptions(resolved, base, optionMergeStrategies);\n }\n if (isObject(base)) {\n cache.set(base, resolved);\n }\n return resolved;\n}\nfunction mergeOptions(to, from, strats, asMixin = false) {\n const { mixins, extends: extendsOptions } = from;\n if (extendsOptions) {\n mergeOptions(to, extendsOptions, strats, true);\n }\n if (mixins) {\n mixins.forEach(\n (m) => mergeOptions(to, m, strats, true)\n );\n }\n for (const key in from) {\n if (asMixin && key === \"expose\") {\n !!(process.env.NODE_ENV !== \"production\") && warn$1(\n `\"expose\" option is ignored when declared in mixins or extends. It should only be declared in the base component itself.`\n );\n } else {\n const strat = internalOptionMergeStrats[key] || strats && strats[key];\n to[key] = strat ? strat(to[key], from[key]) : from[key];\n }\n }\n return to;\n}\nconst internalOptionMergeStrats = {\n data: mergeDataFn,\n props: mergeEmitsOrPropsOptions,\n emits: mergeEmitsOrPropsOptions,\n // objects\n methods: mergeObjectOptions,\n computed: mergeObjectOptions,\n // lifecycle\n beforeCreate: mergeAsArray,\n created: mergeAsArray,\n beforeMount: mergeAsArray,\n mounted: mergeAsArray,\n beforeUpdate: mergeAsArray,\n updated: mergeAsArray,\n beforeDestroy: mergeAsArray,\n beforeUnmount: mergeAsArray,\n destroyed: mergeAsArray,\n unmounted: mergeAsArray,\n activated: mergeAsArray,\n deactivated: mergeAsArray,\n errorCaptured: mergeAsArray,\n serverPrefetch: mergeAsArray,\n // assets\n components: mergeObjectOptions,\n directives: mergeObjectOptions,\n // watch\n watch: mergeWatchOptions,\n // provide / inject\n provide: mergeDataFn,\n inject: mergeInject\n};\nfunction mergeDataFn(to, from) {\n if (!from) {\n return to;\n }\n if (!to) {\n return from;\n }\n return function mergedDataFn() {\n return (extend)(\n isFunction(to) ? to.call(this, this) : to,\n isFunction(from) ? from.call(this, this) : from\n );\n };\n}\nfunction mergeInject(to, from) {\n return mergeObjectOptions(normalizeInject(to), normalizeInject(from));\n}\nfunction normalizeInject(raw) {\n if (isArray(raw)) {\n const res = {};\n for (let i = 0; i < raw.length; i++) {\n res[raw[i]] = raw[i];\n }\n return res;\n }\n return raw;\n}\nfunction mergeAsArray(to, from) {\n return to ? [...new Set([].concat(to, from))] : from;\n}\nfunction mergeObjectOptions(to, from) {\n return to ? extend(/* @__PURE__ */ Object.create(null), to, from) : from;\n}\nfunction mergeEmitsOrPropsOptions(to, from) {\n if (to) {\n if (isArray(to) && isArray(from)) {\n return [.../* @__PURE__ */ new Set([...to, ...from])];\n }\n return extend(\n /* @__PURE__ */ Object.create(null),\n normalizePropsOrEmits(to),\n normalizePropsOrEmits(from != null ? from : {})\n );\n } else {\n return from;\n }\n}\nfunction mergeWatchOptions(to, from) {\n if (!to) return from;\n if (!from) return to;\n const merged = extend(/* @__PURE__ */ Object.create(null), to);\n for (const key in from) {\n merged[key] = mergeAsArray(to[key], from[key]);\n }\n return merged;\n}\n\nfunction createAppContext() {\n return {\n app: null,\n config: {\n isNativeTag: NO,\n performance: false,\n globalProperties: {},\n optionMergeStrategies: {},\n errorHandler: void 0,\n warnHandler: void 0,\n compilerOptions: {}\n },\n mixins: [],\n components: {},\n directives: {},\n provides: /* @__PURE__ */ Object.create(null),\n optionsCache: /* @__PURE__ */ new WeakMap(),\n propsCache: /* @__PURE__ */ new WeakMap(),\n emitsCache: /* @__PURE__ */ new WeakMap()\n };\n}\nlet uid$1 = 0;\nfunction createAppAPI(render, hydrate) {\n return function createApp(rootComponent, rootProps = null) {\n if (!isFunction(rootComponent)) {\n rootComponent = extend({}, rootComponent);\n }\n if (rootProps != null && !isObject(rootProps)) {\n !!(process.env.NODE_ENV !== \"production\") && warn$1(`root props passed to app.mount() must be an object.`);\n rootProps = null;\n }\n const context = createAppContext();\n const installedPlugins = /* @__PURE__ */ new WeakSet();\n const pluginCleanupFns = [];\n let isMounted = false;\n const app = context.app = {\n _uid: uid$1++,\n _component: rootComponent,\n _props: rootProps,\n _container: null,\n _context: context,\n _instance: null,\n version,\n get config() {\n return context.config;\n },\n set config(v) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(\n `app.config cannot be replaced. Modify individual options instead.`\n );\n }\n },\n use(plugin, ...options) {\n if (installedPlugins.has(plugin)) {\n !!(process.env.NODE_ENV !== \"production\") && warn$1(`Plugin has already been applied to target app.`);\n } else if (plugin && isFunction(plugin.install)) {\n installedPlugins.add(plugin);\n plugin.install(app, ...options);\n } else if (isFunction(plugin)) {\n installedPlugins.add(plugin);\n plugin(app, ...options);\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(\n `A plugin must either be a function or an object with an \"install\" function.`\n );\n }\n return app;\n },\n mixin(mixin) {\n if (__VUE_OPTIONS_API__) {\n if (!context.mixins.includes(mixin)) {\n context.mixins.push(mixin);\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(\n \"Mixin has already been applied to target app\" + (mixin.name ? `: ${mixin.name}` : \"\")\n );\n }\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(\"Mixins are only available in builds supporting Options API\");\n }\n return app;\n },\n component(name, component) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n validateComponentName(name, context.config);\n }\n if (!component) {\n return context.components[name];\n }\n if (!!(process.env.NODE_ENV !== \"production\") && context.components[name]) {\n warn$1(`Component \"${name}\" has already been registered in target app.`);\n }\n context.components[name] = component;\n return app;\n },\n directive(name, directive) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n validateDirectiveName(name);\n }\n if (!directive) {\n return context.directives[name];\n }\n if (!!(process.env.NODE_ENV !== \"production\") && context.directives[name]) {\n warn$1(`Directive \"${name}\" has already been registered in target app.`);\n }\n context.directives[name] = directive;\n return app;\n },\n mount(rootContainer, isHydrate, namespace) {\n if (!isMounted) {\n if (!!(process.env.NODE_ENV !== \"production\") && rootContainer.__vue_app__) {\n warn$1(\n `There is already an app instance mounted on the host container.\n If you want to mount another app on the same host container, you need to unmount the previous app by calling \\`app.unmount()\\` first.`\n );\n }\n const vnode = app._ceVNode || createVNode(rootComponent, rootProps);\n vnode.appContext = context;\n if (namespace === true) {\n namespace = \"svg\";\n } else if (namespace === false) {\n namespace = void 0;\n }\n if (!!(process.env.NODE_ENV !== \"production\")) {\n context.reload = () => {\n const cloned = cloneVNode(vnode);\n cloned.el = null;\n render(cloned, rootContainer, namespace);\n };\n }\n if (isHydrate && hydrate) {\n hydrate(vnode, rootContainer);\n } else {\n render(vnode, rootContainer, namespace);\n }\n isMounted = true;\n app._container = rootContainer;\n rootContainer.__vue_app__ = app;\n if (!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_DEVTOOLS__) {\n app._instance = vnode.component;\n devtoolsInitApp(app, version);\n }\n return getComponentPublicInstance(vnode.component);\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(\n `App has already been mounted.\nIf you want to remount the same app, move your app creation logic into a factory function and create fresh app instances for each mount - e.g. \\`const createMyApp = () => createApp(App)\\``\n );\n }\n },\n onUnmount(cleanupFn) {\n if (!!(process.env.NODE_ENV !== \"production\") && typeof cleanupFn !== \"function\") {\n warn$1(\n `Expected function as first argument to app.onUnmount(), but got ${typeof cleanupFn}`\n );\n }\n pluginCleanupFns.push(cleanupFn);\n },\n unmount() {\n if (isMounted) {\n callWithAsyncErrorHandling(\n pluginCleanupFns,\n app._instance,\n 16\n );\n render(null, app._container);\n if (!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_DEVTOOLS__) {\n app._instance = null;\n devtoolsUnmountApp(app);\n }\n delete app._container.__vue_app__;\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(`Cannot unmount an app that is not mounted.`);\n }\n },\n provide(key, value) {\n if (!!(process.env.NODE_ENV !== \"production\") && key in context.provides) {\n if (hasOwn(context.provides, key)) {\n warn$1(\n `App already provides property with key \"${String(key)}\". It will be overwritten with the new value.`\n );\n } else {\n warn$1(\n `App already provides property with key \"${String(key)}\" inherited from its parent element. It will be overwritten with the new value.`\n );\n }\n }\n context.provides[key] = value;\n return app;\n },\n runWithContext(fn) {\n const lastApp = currentApp;\n currentApp = app;\n try {\n return fn();\n } finally {\n currentApp = lastApp;\n }\n }\n };\n return app;\n };\n}\nlet currentApp = null;\n\nfunction provide(key, value) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n if (!currentInstance || currentInstance.isMounted) {\n warn$1(`provide() can only be used inside setup().`);\n }\n }\n if (currentInstance) {\n let provides = currentInstance.provides;\n const parentProvides = currentInstance.parent && currentInstance.parent.provides;\n if (parentProvides === provides) {\n provides = currentInstance.provides = Object.create(parentProvides);\n }\n provides[key] = value;\n }\n}\nfunction inject(key, defaultValue, treatDefaultAsFactory = false) {\n const instance = getCurrentInstance();\n if (instance || currentApp) {\n let provides = currentApp ? currentApp._context.provides : instance ? instance.parent == null || instance.ce ? instance.vnode.appContext && instance.vnode.appContext.provides : instance.parent.provides : void 0;\n if (provides && key in provides) {\n return provides[key];\n } else if (arguments.length > 1) {\n return treatDefaultAsFactory && isFunction(defaultValue) ? defaultValue.call(instance && instance.proxy) : defaultValue;\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(`injection \"${String(key)}\" not found.`);\n }\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(`inject() can only be used inside setup() or functional components.`);\n }\n}\nfunction hasInjectionContext() {\n return !!(getCurrentInstance() || currentApp);\n}\n\nconst ssrContextKey = Symbol.for(\"v-scx\");\nconst useSSRContext = () => {\n {\n const ctx = inject(ssrContextKey);\n if (!ctx) {\n !!(process.env.NODE_ENV !== \"production\") && warn$1(\n `Server rendering context not provided. Make sure to only call useSSRContext() conditionally in the server build.`\n );\n }\n return ctx;\n }\n};\n\nfunction watchEffect(effect, options) {\n return doWatch(effect, null, options);\n}\nfunction watchPostEffect(effect, options) {\n return doWatch(\n effect,\n null,\n !!(process.env.NODE_ENV !== \"production\") ? extend({}, options, { flush: \"post\" }) : { flush: \"post\" }\n );\n}\nfunction watchSyncEffect(effect, options) {\n return doWatch(\n effect,\n null,\n !!(process.env.NODE_ENV !== \"production\") ? extend({}, options, { flush: \"sync\" }) : { flush: \"sync\" }\n );\n}\nfunction watch(source, cb, options) {\n if (!!(process.env.NODE_ENV !== \"production\") && !isFunction(cb)) {\n warn$1(\n `\\`watch(fn, options?)\\` signature has been moved to a separate API. Use \\`watchEffect(fn, options?)\\` instead. \\`watch\\` now only supports \\`watch(source, cb, options?) signature.`\n );\n }\n return doWatch(source, cb, options);\n}\nfunction doWatch(source, cb, options = EMPTY_OBJ) {\n const { immediate, deep, flush, once } = options;\n if (!!(process.env.NODE_ENV !== \"production\") && !cb) {\n if (immediate !== void 0) {\n warn$1(\n `watch() \"immediate\" option is only respected when using the watch(source, callback, options?) signature.`\n );\n }\n if (deep !== void 0) {\n warn$1(\n `watch() \"deep\" option is only respected when using the watch(source, callback, options?) signature.`\n );\n }\n if (once !== void 0) {\n warn$1(\n `watch() \"once\" option is only respected when using the watch(source, callback, options?) signature.`\n );\n }\n }\n const baseWatchOptions = extend({}, options);\n if (!!(process.env.NODE_ENV !== \"production\")) baseWatchOptions.onWarn = warn$1;\n const runsImmediately = cb && immediate || !cb && flush !== \"post\";\n let ssrCleanup;\n if (isInSSRComponentSetup) {\n if (flush === \"sync\") {\n const ctx = useSSRContext();\n ssrCleanup = ctx.__watcherHandles || (ctx.__watcherHandles = []);\n } else if (!runsImmediately) {\n const watchStopHandle = () => {\n };\n watchStopHandle.stop = NOOP;\n watchStopHandle.resume = NOOP;\n watchStopHandle.pause = NOOP;\n return watchStopHandle;\n }\n }\n const instance = currentInstance;\n baseWatchOptions.call = (fn, type, args) => callWithAsyncErrorHandling(fn, instance, type, args);\n let isPre = false;\n if (flush === \"post\") {\n baseWatchOptions.scheduler = (job) => {\n queuePostRenderEffect(job, instance && instance.suspense);\n };\n } else if (flush !== \"sync\") {\n isPre = true;\n baseWatchOptions.scheduler = (job, isFirstRun) => {\n if (isFirstRun) {\n job();\n } else {\n queueJob(job);\n }\n };\n }\n baseWatchOptions.augmentJob = (job) => {\n if (cb) {\n job.flags |= 4;\n }\n if (isPre) {\n job.flags |= 2;\n if (instance) {\n job.id = instance.uid;\n job.i = instance;\n }\n }\n };\n const watchHandle = watch$1(source, cb, baseWatchOptions);\n if (isInSSRComponentSetup) {\n if (ssrCleanup) {\n ssrCleanup.push(watchHandle);\n } else if (runsImmediately) {\n watchHandle();\n }\n }\n return watchHandle;\n}\nfunction instanceWatch(source, value, options) {\n const publicThis = this.proxy;\n const getter = isString(source) ? source.includes(\".\") ? createPathGetter(publicThis, source) : () => publicThis[source] : source.bind(publicThis, publicThis);\n let cb;\n if (isFunction(value)) {\n cb = value;\n } else {\n cb = value.handler;\n options = value;\n }\n const reset = setCurrentInstance(this);\n const res = doWatch(getter, cb.bind(publicThis), options);\n reset();\n return res;\n}\nfunction createPathGetter(ctx, path) {\n const segments = path.split(\".\");\n return () => {\n let cur = ctx;\n for (let i = 0; i < segments.length && cur; i++) {\n cur = cur[segments[i]];\n }\n return cur;\n };\n}\n\nfunction useModel(props, name, options = EMPTY_OBJ) {\n const i = getCurrentInstance();\n if (!!(process.env.NODE_ENV !== \"production\") && !i) {\n warn$1(`useModel() called without active instance.`);\n return ref();\n }\n const camelizedName = camelize(name);\n if (!!(process.env.NODE_ENV !== \"production\") && !i.propsOptions[0][camelizedName]) {\n warn$1(`useModel() called with prop \"${name}\" which is not declared.`);\n return ref();\n }\n const hyphenatedName = hyphenate(name);\n const modifiers = getModelModifiers(props, camelizedName);\n const res = customRef((track, trigger) => {\n let localValue;\n let prevSetValue = EMPTY_OBJ;\n let prevEmittedValue;\n watchSyncEffect(() => {\n const propValue = props[camelizedName];\n if (hasChanged(localValue, propValue)) {\n localValue = propValue;\n trigger();\n }\n });\n return {\n get() {\n track();\n return options.get ? options.get(localValue) : localValue;\n },\n set(value) {\n const emittedValue = options.set ? options.set(value) : value;\n if (!hasChanged(emittedValue, localValue) && !(prevSetValue !== EMPTY_OBJ && hasChanged(value, prevSetValue))) {\n return;\n }\n const rawProps = i.vnode.props;\n if (!(rawProps && // check if parent has passed v-model\n (name in rawProps || camelizedName in rawProps || hyphenatedName in rawProps) && (`onUpdate:${name}` in rawProps || `onUpdate:${camelizedName}` in rawProps || `onUpdate:${hyphenatedName}` in rawProps))) {\n localValue = value;\n trigger();\n }\n i.emit(`update:${name}`, emittedValue);\n if (hasChanged(value, emittedValue) && hasChanged(value, prevSetValue) && !hasChanged(emittedValue, prevEmittedValue)) {\n trigger();\n }\n prevSetValue = value;\n prevEmittedValue = emittedValue;\n }\n };\n });\n res[Symbol.iterator] = () => {\n let i2 = 0;\n return {\n next() {\n if (i2 < 2) {\n return { value: i2++ ? modifiers || EMPTY_OBJ : res, done: false };\n } else {\n return { done: true };\n }\n }\n };\n };\n return res;\n}\nconst getModelModifiers = (props, modelName) => {\n return modelName === \"modelValue\" || modelName === \"model-value\" ? props.modelModifiers : props[`${modelName}Modifiers`] || props[`${camelize(modelName)}Modifiers`] || props[`${hyphenate(modelName)}Modifiers`];\n};\n\nfunction emit(instance, event, ...rawArgs) {\n if (instance.isUnmounted) return;\n const props = instance.vnode.props || EMPTY_OBJ;\n if (!!(process.env.NODE_ENV !== \"production\")) {\n const {\n emitsOptions,\n propsOptions: [propsOptions]\n } = instance;\n if (emitsOptions) {\n if (!(event in emitsOptions) && true) {\n if (!propsOptions || !(toHandlerKey(camelize(event)) in propsOptions)) {\n warn$1(\n `Component emitted event \"${event}\" but it is neither declared in the emits option nor as an \"${toHandlerKey(camelize(event))}\" prop.`\n );\n }\n } else {\n const validator = emitsOptions[event];\n if (isFunction(validator)) {\n const isValid = validator(...rawArgs);\n if (!isValid) {\n warn$1(\n `Invalid event arguments: event validation failed for event \"${event}\".`\n );\n }\n }\n }\n }\n }\n let args = rawArgs;\n const isModelListener = event.startsWith(\"update:\");\n const modifiers = isModelListener && getModelModifiers(props, event.slice(7));\n if (modifiers) {\n if (modifiers.trim) {\n args = rawArgs.map((a) => isString(a) ? a.trim() : a);\n }\n if (modifiers.number) {\n args = rawArgs.map(looseToNumber);\n }\n }\n if (!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_DEVTOOLS__) {\n devtoolsComponentEmit(instance, event, args);\n }\n if (!!(process.env.NODE_ENV !== \"production\")) {\n const lowerCaseEvent = event.toLowerCase();\n if (lowerCaseEvent !== event && props[toHandlerKey(lowerCaseEvent)]) {\n warn$1(\n `Event \"${lowerCaseEvent}\" is emitted in component ${formatComponentName(\n instance,\n instance.type\n )} but the handler is registered for \"${event}\". Note that HTML attributes are case-insensitive and you cannot use v-on to listen to camelCase events when using in-DOM templates. You should probably use \"${hyphenate(\n event\n )}\" instead of \"${event}\".`\n );\n }\n }\n let handlerName;\n let handler = props[handlerName = toHandlerKey(event)] || // also try camelCase event handler (#2249)\n props[handlerName = toHandlerKey(camelize(event))];\n if (!handler && isModelListener) {\n handler = props[handlerName = toHandlerKey(hyphenate(event))];\n }\n if (handler) {\n callWithAsyncErrorHandling(\n handler,\n instance,\n 6,\n args\n );\n }\n const onceHandler = props[handlerName + `Once`];\n if (onceHandler) {\n if (!instance.emitted) {\n instance.emitted = {};\n } else if (instance.emitted[handlerName]) {\n return;\n }\n instance.emitted[handlerName] = true;\n callWithAsyncErrorHandling(\n onceHandler,\n instance,\n 6,\n args\n );\n }\n}\nconst mixinEmitsCache = /* @__PURE__ */ new WeakMap();\nfunction normalizeEmitsOptions(comp, appContext, asMixin = false) {\n const cache = __VUE_OPTIONS_API__ && asMixin ? mixinEmitsCache : appContext.emitsCache;\n const cached = cache.get(comp);\n if (cached !== void 0) {\n return cached;\n }\n const raw = comp.emits;\n let normalized = {};\n let hasExtends = false;\n if (__VUE_OPTIONS_API__ && !isFunction(comp)) {\n const extendEmits = (raw2) => {\n const normalizedFromExtend = normalizeEmitsOptions(raw2, appContext, true);\n if (normalizedFromExtend) {\n hasExtends = true;\n extend(normalized, normalizedFromExtend);\n }\n };\n if (!asMixin && appContext.mixins.length) {\n appContext.mixins.forEach(extendEmits);\n }\n if (comp.extends) {\n extendEmits(comp.extends);\n }\n if (comp.mixins) {\n comp.mixins.forEach(extendEmits);\n }\n }\n if (!raw && !hasExtends) {\n if (isObject(comp)) {\n cache.set(comp, null);\n }\n return null;\n }\n if (isArray(raw)) {\n raw.forEach((key) => normalized[key] = null);\n } else {\n extend(normalized, raw);\n }\n if (isObject(comp)) {\n cache.set(comp, normalized);\n }\n return normalized;\n}\nfunction isEmitListener(options, key) {\n if (!options || !isOn(key)) {\n return false;\n }\n key = key.slice(2).replace(/Once$/, \"\");\n return hasOwn(options, key[0].toLowerCase() + key.slice(1)) || hasOwn(options, hyphenate(key)) || hasOwn(options, key);\n}\n\nlet accessedAttrs = false;\nfunction markAttrsAccessed() {\n accessedAttrs = true;\n}\nfunction renderComponentRoot(instance) {\n const {\n type: Component,\n vnode,\n proxy,\n withProxy,\n propsOptions: [propsOptions],\n slots,\n attrs,\n emit,\n render,\n renderCache,\n props,\n data,\n setupState,\n ctx,\n inheritAttrs\n } = instance;\n const prev = setCurrentRenderingInstance(instance);\n let result;\n let fallthroughAttrs;\n if (!!(process.env.NODE_ENV !== \"production\")) {\n accessedAttrs = false;\n }\n try {\n if (vnode.shapeFlag & 4) {\n const proxyToUse = withProxy || proxy;\n const thisProxy = !!(process.env.NODE_ENV !== \"production\") && setupState.__isScriptSetup ? new Proxy(proxyToUse, {\n get(target, key, receiver) {\n warn$1(\n `Property '${String(\n key\n )}' was accessed via 'this'. Avoid using 'this' in templates.`\n );\n return Reflect.get(target, key, receiver);\n }\n }) : proxyToUse;\n result = normalizeVNode(\n render.call(\n thisProxy,\n proxyToUse,\n renderCache,\n !!(process.env.NODE_ENV !== \"production\") ? shallowReadonly(props) : props,\n setupState,\n data,\n ctx\n )\n );\n fallthroughAttrs = attrs;\n } else {\n const render2 = Component;\n if (!!(process.env.NODE_ENV !== \"production\") && attrs === props) {\n markAttrsAccessed();\n }\n result = normalizeVNode(\n render2.length > 1 ? render2(\n !!(process.env.NODE_ENV !== \"production\") ? shallowReadonly(props) : props,\n !!(process.env.NODE_ENV !== \"production\") ? {\n get attrs() {\n markAttrsAccessed();\n return shallowReadonly(attrs);\n },\n slots,\n emit\n } : { attrs, slots, emit }\n ) : render2(\n !!(process.env.NODE_ENV !== \"production\") ? shallowReadonly(props) : props,\n null\n )\n );\n fallthroughAttrs = Component.props ? attrs : getFunctionalFallthrough(attrs);\n }\n } catch (err) {\n blockStack.length = 0;\n handleError(err, instance, 1);\n result = createVNode(Comment);\n }\n let root = result;\n let setRoot = void 0;\n if (!!(process.env.NODE_ENV !== \"production\") && result.patchFlag > 0 && result.patchFlag & 2048) {\n [root, setRoot] = getChildRoot(result);\n }\n if (fallthroughAttrs && inheritAttrs !== false) {\n const keys = Object.keys(fallthroughAttrs);\n const { shapeFlag } = root;\n if (keys.length) {\n if (shapeFlag & (1 | 6)) {\n if (propsOptions && keys.some(isModelListener)) {\n fallthroughAttrs = filterModelListeners(\n fallthroughAttrs,\n propsOptions\n );\n }\n root = cloneVNode(root, fallthroughAttrs, false, true);\n } else if (!!(process.env.NODE_ENV !== \"production\") && !accessedAttrs && root.type !== Comment) {\n const allAttrs = Object.keys(attrs);\n const eventAttrs = [];\n const extraAttrs = [];\n for (let i = 0, l = allAttrs.length; i < l; i++) {\n const key = allAttrs[i];\n if (isOn(key)) {\n if (!isModelListener(key)) {\n eventAttrs.push(key[2].toLowerCase() + key.slice(3));\n }\n } else {\n extraAttrs.push(key);\n }\n }\n if (extraAttrs.length) {\n warn$1(\n `Extraneous non-props attributes (${extraAttrs.join(\", \")}) were passed to component but could not be automatically inherited because component renders fragment or text or teleport root nodes.`\n );\n }\n if (eventAttrs.length) {\n warn$1(\n `Extraneous non-emits event listeners (${eventAttrs.join(\", \")}) were passed to component but could not be automatically inherited because component renders fragment or text root nodes. If the listener is intended to be a component custom event listener only, declare it using the \"emits\" option.`\n );\n }\n }\n }\n }\n if (vnode.dirs) {\n if (!!(process.env.NODE_ENV !== \"production\") && !isElementRoot(root)) {\n warn$1(\n `Runtime directive used on component with non-element root node. The directives will not function as intended.`\n );\n }\n root = cloneVNode(root, null, false, true);\n root.dirs = root.dirs ? root.dirs.concat(vnode.dirs) : vnode.dirs;\n }\n if (vnode.transition) {\n if (!!(process.env.NODE_ENV !== \"production\") && !isElementRoot(root)) {\n warn$1(\n `Component inside <Transition> renders non-element root node that cannot be animated.`\n );\n }\n setTransitionHooks(root, vnode.transition);\n }\n if (!!(process.env.NODE_ENV !== \"production\") && setRoot) {\n setRoot(root);\n } else {\n result = root;\n }\n setCurrentRenderingInstance(prev);\n return result;\n}\nconst getChildRoot = (vnode) => {\n const rawChildren = vnode.children;\n const dynamicChildren = vnode.dynamicChildren;\n const childRoot = filterSingleRoot(rawChildren, false);\n if (!childRoot) {\n return [vnode, void 0];\n } else if (!!(process.env.NODE_ENV !== \"production\") && childRoot.patchFlag > 0 && childRoot.patchFlag & 2048) {\n return getChildRoot(childRoot);\n }\n const index = rawChildren.indexOf(childRoot);\n const dynamicIndex = dynamicChildren ? dynamicChildren.indexOf(childRoot) : -1;\n const setRoot = (updatedRoot) => {\n rawChildren[index] = updatedRoot;\n if (dynamicChildren) {\n if (dynamicIndex > -1) {\n dynamicChildren[dynamicIndex] = updatedRoot;\n } else if (updatedRoot.patchFlag > 0) {\n vnode.dynamicChildren = [...dynamicChildren, updatedRoot];\n }\n }\n };\n return [normalizeVNode(childRoot), setRoot];\n};\nfunction filterSingleRoot(children, recurse = true) {\n let singleRoot;\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (isVNode(child)) {\n if (child.type !== Comment || child.children === \"v-if\") {\n if (singleRoot) {\n return;\n } else {\n singleRoot = child;\n if (!!(process.env.NODE_ENV !== \"production\") && recurse && singleRoot.patchFlag > 0 && singleRoot.patchFlag & 2048) {\n return filterSingleRoot(singleRoot.children);\n }\n }\n }\n } else {\n return;\n }\n }\n return singleRoot;\n}\nconst getFunctionalFallthrough = (attrs) => {\n let res;\n for (const key in attrs) {\n if (key === \"class\" || key === \"style\" || isOn(key)) {\n (res || (res = {}))[key] = attrs[key];\n }\n }\n return res;\n};\nconst filterModelListeners = (attrs, props) => {\n const res = {};\n for (const key in attrs) {\n if (!isModelListener(key) || !(key.slice(9) in props)) {\n res[key] = attrs[key];\n }\n }\n return res;\n};\nconst isElementRoot = (vnode) => {\n return vnode.shapeFlag & (6 | 1) || vnode.type === Comment;\n};\nfunction shouldUpdateComponent(prevVNode, nextVNode, optimized) {\n const { props: prevProps, children: prevChildren, component } = prevVNode;\n const { props: nextProps, children: nextChildren, patchFlag } = nextVNode;\n const emits = component.emitsOptions;\n if (!!(process.env.NODE_ENV !== \"production\") && (prevChildren || nextChildren) && isHmrUpdating) {\n return true;\n }\n if (nextVNode.dirs || nextVNode.transition) {\n return true;\n }\n if (optimized && patchFlag >= 0) {\n if (patchFlag & 1024) {\n return true;\n }\n if (patchFlag & 16) {\n if (!prevProps) {\n return !!nextProps;\n }\n return hasPropsChanged(prevProps, nextProps, emits);\n } else if (patchFlag & 8) {\n const dynamicProps = nextVNode.dynamicProps;\n for (let i = 0; i < dynamicProps.length; i++) {\n const key = dynamicProps[i];\n if (nextProps[key] !== prevProps[key] && !isEmitListener(emits, key)) {\n return true;\n }\n }\n }\n } else {\n if (prevChildren || nextChildren) {\n if (!nextChildren || !nextChildren.$stable) {\n return true;\n }\n }\n if (prevProps === nextProps) {\n return false;\n }\n if (!prevProps) {\n return !!nextProps;\n }\n if (!nextProps) {\n return true;\n }\n return hasPropsChanged(prevProps, nextProps, emits);\n }\n return false;\n}\nfunction hasPropsChanged(prevProps, nextProps, emitsOptions) {\n const nextKeys = Object.keys(nextProps);\n if (nextKeys.length !== Object.keys(prevProps).length) {\n return true;\n }\n for (let i = 0; i < nextKeys.length; i++) {\n const key = nextKeys[i];\n if (nextProps[key] !== prevProps[key] && !isEmitListener(emitsOptions, key)) {\n return true;\n }\n }\n return false;\n}\nfunction updateHOCHostEl({ vnode, parent }, el) {\n while (parent) {\n const root = parent.subTree;\n if (root.suspense && root.suspense.activeBranch === vnode) {\n root.el = vnode.el;\n }\n if (root === vnode) {\n (vnode = parent.vnode).el = el;\n parent = parent.parent;\n } else {\n break;\n }\n }\n}\n\nconst internalObjectProto = {};\nconst createInternalObject = () => Object.create(internalObjectProto);\nconst isInternalObject = (obj) => Object.getPrototypeOf(obj) === internalObjectProto;\n\nfunction initProps(instance, rawProps, isStateful, isSSR = false) {\n const props = {};\n const attrs = createInternalObject();\n instance.propsDefaults = /* @__PURE__ */ Object.create(null);\n setFullProps(instance, rawProps, props, attrs);\n for (const key in instance.propsOptions[0]) {\n if (!(key in props)) {\n props[key] = void 0;\n }\n }\n if (!!(process.env.NODE_ENV !== \"production\")) {\n validateProps(rawProps || {}, props, instance);\n }\n if (isStateful) {\n instance.props = isSSR ? props : shallowReactive(props);\n } else {\n if (!instance.type.props) {\n instance.props = attrs;\n } else {\n instance.props = props;\n }\n }\n instance.attrs = attrs;\n}\nfunction isInHmrContext(instance) {\n while (instance) {\n if (instance.type.__hmrId) return true;\n instance = instance.parent;\n }\n}\nfunction updateProps(instance, rawProps, rawPrevProps, optimized) {\n const {\n props,\n attrs,\n vnode: { patchFlag }\n } = instance;\n const rawCurrentProps = toRaw(props);\n const [options] = instance.propsOptions;\n let hasAttrsChanged = false;\n if (\n // always force full diff in dev\n // - #1942 if hmr is enabled with sfc component\n // - vite#872 non-sfc component used by sfc component\n !(!!(process.env.NODE_ENV !== \"production\") && isInHmrContext(instance)) && (optimized || patchFlag > 0) && !(patchFlag & 16)\n ) {\n if (patchFlag & 8) {\n const propsToUpdate = instance.vnode.dynamicProps;\n for (let i = 0; i < propsToUpdate.length; i++) {\n let key = propsToUpdate[i];\n if (isEmitListener(instance.emitsOptions, key)) {\n continue;\n }\n const value = rawProps[key];\n if (options) {\n if (hasOwn(attrs, key)) {\n if (value !== attrs[key]) {\n attrs[key] = value;\n hasAttrsChanged = true;\n }\n } else {\n const camelizedKey = camelize(key);\n props[camelizedKey] = resolvePropValue(\n options,\n rawCurrentProps,\n camelizedKey,\n value,\n instance,\n false\n );\n }\n } else {\n if (value !== attrs[key]) {\n attrs[key] = value;\n hasAttrsChanged = true;\n }\n }\n }\n }\n } else {\n if (setFullProps(instance, rawProps, props, attrs)) {\n hasAttrsChanged = true;\n }\n let kebabKey;\n for (const key in rawCurrentProps) {\n if (!rawProps || // for camelCase\n !hasOwn(rawProps, key) && // it's possible the original props was passed in as kebab-case\n // and converted to camelCase (#955)\n ((kebabKey = hyphenate(key)) === key || !hasOwn(rawProps, kebabKey))) {\n if (options) {\n if (rawPrevProps && // for camelCase\n (rawPrevProps[key] !== void 0 || // for kebab-case\n rawPrevProps[kebabKey] !== void 0)) {\n props[key] = resolvePropValue(\n options,\n rawCurrentProps,\n key,\n void 0,\n instance,\n true\n );\n }\n } else {\n delete props[key];\n }\n }\n }\n if (attrs !== rawCurrentProps) {\n for (const key in attrs) {\n if (!rawProps || !hasOwn(rawProps, key) && true) {\n delete attrs[key];\n hasAttrsChanged = true;\n }\n }\n }\n }\n if (hasAttrsChanged) {\n trigger(instance.attrs, \"set\", \"\");\n }\n if (!!(process.env.NODE_ENV !== \"production\")) {\n validateProps(rawProps || {}, props, instance);\n }\n}\nfunction setFullProps(instance, rawProps, props, attrs) {\n const [options, needCastKeys] = instance.propsOptions;\n let hasAttrsChanged = false;\n let rawCastValues;\n if (rawProps) {\n for (let key in rawProps) {\n if (isReservedProp(key)) {\n continue;\n }\n const value = rawProps[key];\n let camelKey;\n if (options && hasOwn(options, camelKey = camelize(key))) {\n if (!needCastKeys || !needCastKeys.includes(camelKey)) {\n props[camelKey] = value;\n } else {\n (rawCastValues || (rawCastValues = {}))[camelKey] = value;\n }\n } else if (!isEmitListener(instance.emitsOptions, key)) {\n if (!(key in attrs) || value !== attrs[key]) {\n attrs[key] = value;\n hasAttrsChanged = true;\n }\n }\n }\n }\n if (needCastKeys) {\n const rawCurrentProps = toRaw(props);\n const castValues = rawCastValues || EMPTY_OBJ;\n for (let i = 0; i < needCastKeys.length; i++) {\n const key = needCastKeys[i];\n props[key] = resolvePropValue(\n options,\n rawCurrentProps,\n key,\n castValues[key],\n instance,\n !hasOwn(castValues, key)\n );\n }\n }\n return hasAttrsChanged;\n}\nfunction resolvePropValue(options, props, key, value, instance, isAbsent) {\n const opt = options[key];\n if (opt != null) {\n const hasDefault = hasOwn(opt, \"default\");\n if (hasDefault && value === void 0) {\n const defaultValue = opt.default;\n if (opt.type !== Function && !opt.skipFactory && isFunction(defaultValue)) {\n const { propsDefaults } = instance;\n if (key in propsDefaults) {\n value = propsDefaults[key];\n } else {\n const reset = setCurrentInstance(instance);\n value = propsDefaults[key] = defaultValue.call(\n null,\n props\n );\n reset();\n }\n } else {\n value = defaultValue;\n }\n if (instance.ce) {\n instance.ce._setProp(key, value);\n }\n }\n if (opt[0 /* shouldCast */]) {\n if (isAbsent && !hasDefault) {\n value = false;\n } else if (opt[1 /* shouldCastTrue */] && (value === \"\" || value === hyphenate(key))) {\n value = true;\n }\n }\n }\n return value;\n}\nconst mixinPropsCache = /* @__PURE__ */ new WeakMap();\nfunction normalizePropsOptions(comp, appContext, asMixin = false) {\n const cache = __VUE_OPTIONS_API__ && asMixin ? mixinPropsCache : appContext.propsCache;\n const cached = cache.get(comp);\n if (cached) {\n return cached;\n }\n const raw = comp.props;\n const normalized = {};\n const needCastKeys = [];\n let hasExtends = false;\n if (__VUE_OPTIONS_API__ && !isFunction(comp)) {\n const extendProps = (raw2) => {\n hasExtends = true;\n const [props, keys] = normalizePropsOptions(raw2, appContext, true);\n extend(normalized, props);\n if (keys) needCastKeys.push(...keys);\n };\n if (!asMixin && appContext.mixins.length) {\n appContext.mixins.forEach(extendProps);\n }\n if (comp.extends) {\n extendProps(comp.extends);\n }\n if (comp.mixins) {\n comp.mixins.forEach(extendProps);\n }\n }\n if (!raw && !hasExtends) {\n if (isObject(comp)) {\n cache.set(comp, EMPTY_ARR);\n }\n return EMPTY_ARR;\n }\n if (isArray(raw)) {\n for (let i = 0; i < raw.length; i++) {\n if (!!(process.env.NODE_ENV !== \"production\") && !isString(raw[i])) {\n warn$1(`props must be strings when using array syntax.`, raw[i]);\n }\n const normalizedKey = camelize(raw[i]);\n if (validatePropName(normalizedKey)) {\n normalized[normalizedKey] = EMPTY_OBJ;\n }\n }\n } else if (raw) {\n if (!!(process.env.NODE_ENV !== \"production\") && !isObject(raw)) {\n warn$1(`invalid props options`, raw);\n }\n for (const key in raw) {\n const normalizedKey = camelize(key);\n if (validatePropName(normalizedKey)) {\n const opt = raw[key];\n const prop = normalized[normalizedKey] = isArray(opt) || isFunction(opt) ? { type: opt } : extend({}, opt);\n const propType = prop.type;\n let shouldCast = false;\n let shouldCastTrue = true;\n if (isArray(propType)) {\n for (let index = 0; index < propType.length; ++index) {\n const type = propType[index];\n const typeName = isFunction(type) && type.name;\n if (typeName === \"Boolean\") {\n shouldCast = true;\n break;\n } else if (typeName === \"String\") {\n shouldCastTrue = false;\n }\n }\n } else {\n shouldCast = isFunction(propType) && propType.name === \"Boolean\";\n }\n prop[0 /* shouldCast */] = shouldCast;\n prop[1 /* shouldCastTrue */] = shouldCastTrue;\n if (shouldCast || hasOwn(prop, \"default\")) {\n needCastKeys.push(normalizedKey);\n }\n }\n }\n }\n const res = [normalized, needCastKeys];\n if (isObject(comp)) {\n cache.set(comp, res);\n }\n return res;\n}\nfunction validatePropName(key) {\n if (key[0] !== \"$\" && !isReservedProp(key)) {\n return true;\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(`Invalid prop name: \"${key}\" is a reserved property.`);\n }\n return false;\n}\nfunction getType(ctor) {\n if (ctor === null) {\n return \"null\";\n }\n if (typeof ctor === \"function\") {\n return ctor.name || \"\";\n } else if (typeof ctor === \"object\") {\n const name = ctor.constructor && ctor.constructor.name;\n return name || \"\";\n }\n return \"\";\n}\nfunction validateProps(rawProps, props, instance) {\n const resolvedValues = toRaw(props);\n const options = instance.propsOptions[0];\n const camelizePropsKey = Object.keys(rawProps).map((key) => camelize(key));\n for (const key in options) {\n let opt = options[key];\n if (opt == null) continue;\n validateProp(\n key,\n resolvedValues[key],\n opt,\n !!(process.env.NODE_ENV !== \"production\") ? shallowReadonly(resolvedValues) : resolvedValues,\n !camelizePropsKey.includes(key)\n );\n }\n}\nfunction validateProp(name, value, prop, props, isAbsent) {\n const { type, required, validator, skipCheck } = prop;\n if (required && isAbsent) {\n warn$1('Missing required prop: \"' + name + '\"');\n return;\n }\n if (value == null && !required) {\n return;\n }\n if (type != null && type !== true && !skipCheck) {\n let isValid = false;\n const types = isArray(type) ? type : [type];\n const expectedTypes = [];\n for (let i = 0; i < types.length && !isValid; i++) {\n const { valid, expectedType } = assertType(value, types[i]);\n expectedTypes.push(expectedType || \"\");\n isValid = valid;\n }\n if (!isValid) {\n warn$1(getInvalidTypeMessage(name, value, expectedTypes));\n return;\n }\n }\n if (validator && !validator(value, props)) {\n warn$1('Invalid prop: custom validator check failed for prop \"' + name + '\".');\n }\n}\nconst isSimpleType = /* @__PURE__ */ makeMap(\n \"String,Number,Boolean,Function,Symbol,BigInt\"\n);\nfunction assertType(value, type) {\n let valid;\n const expectedType = getType(type);\n if (expectedType === \"null\") {\n valid = value === null;\n } else if (isSimpleType(expectedType)) {\n const t = typeof value;\n valid = t === expectedType.toLowerCase();\n if (!valid && t === \"object\") {\n valid = value instanceof type;\n }\n } else if (expectedType === \"Object\") {\n valid = isObject(value);\n } else if (expectedType === \"Array\") {\n valid = isArray(value);\n } else {\n valid = value instanceof type;\n }\n return {\n valid,\n expectedType\n };\n}\nfunction getInvalidTypeMessage(name, value, expectedTypes) {\n if (expectedTypes.length === 0) {\n return `Prop type [] for prop \"${name}\" won't match anything. Did you mean to use type Array instead?`;\n }\n let message = `Invalid prop: type check failed for prop \"${name}\". Expected ${expectedTypes.map(capitalize).join(\" | \")}`;\n const expectedType = expectedTypes[0];\n const receivedType = toRawType(value);\n const expectedValue = styleValue(value, expectedType);\n const receivedValue = styleValue(value, receivedType);\n if (expectedTypes.length === 1 && isExplicable(expectedType) && !isBoolean(expectedType, receivedType)) {\n message += ` with value ${expectedValue}`;\n }\n message += `, got ${receivedType} `;\n if (isExplicable(receivedType)) {\n message += `with value ${receivedValue}.`;\n }\n return message;\n}\nfunction styleValue(value, type) {\n if (type === \"String\") {\n return `\"${value}\"`;\n } else if (type === \"Number\") {\n return `${Number(value)}`;\n } else {\n return `${value}`;\n }\n}\nfunction isExplicable(type) {\n const explicitTypes = [\"string\", \"number\", \"boolean\"];\n return explicitTypes.some((elem) => type.toLowerCase() === elem);\n}\nfunction isBoolean(...args) {\n return args.some((elem) => elem.toLowerCase() === \"boolean\");\n}\n\nconst isInternalKey = (key) => key === \"_\" || key === \"_ctx\" || key === \"$stable\";\nconst normalizeSlotValue = (value) => isArray(value) ? value.map(normalizeVNode) : [normalizeVNode(value)];\nconst normalizeSlot = (key, rawSlot, ctx) => {\n if (rawSlot._n) {\n return rawSlot;\n }\n const normalized = withCtx((...args) => {\n if (!!(process.env.NODE_ENV !== \"production\") && currentInstance && !(ctx === null && currentRenderingInstance) && !(ctx && ctx.root !== currentInstance.root)) {\n warn$1(\n `Slot \"${key}\" invoked outside of the render function: this will not track dependencies used in the slot. Invoke the slot function inside the render function instead.`\n );\n }\n return normalizeSlotValue(rawSlot(...args));\n }, ctx);\n normalized._c = false;\n return normalized;\n};\nconst normalizeObjectSlots = (rawSlots, slots, instance) => {\n const ctx = rawSlots._ctx;\n for (const key in rawSlots) {\n if (isInternalKey(key)) continue;\n const value = rawSlots[key];\n if (isFunction(value)) {\n slots[key] = normalizeSlot(key, value, ctx);\n } else if (value != null) {\n if (!!(process.env.NODE_ENV !== \"production\") && true) {\n warn$1(\n `Non-function value encountered for slot \"${key}\". Prefer function slots for better performance.`\n );\n }\n const normalized = normalizeSlotValue(value);\n slots[key] = () => normalized;\n }\n }\n};\nconst normalizeVNodeSlots = (instance, children) => {\n if (!!(process.env.NODE_ENV !== \"production\") && !isKeepAlive(instance.vnode) && true) {\n warn$1(\n `Non-function value encountered for default slot. Prefer function slots for better performance.`\n );\n }\n const normalized = normalizeSlotValue(children);\n instance.slots.default = () => normalized;\n};\nconst assignSlots = (slots, children, optimized) => {\n for (const key in children) {\n if (optimized || !isInternalKey(key)) {\n slots[key] = children[key];\n }\n }\n};\nconst initSlots = (instance, children, optimized) => {\n const slots = instance.slots = createInternalObject();\n if (instance.vnode.shapeFlag & 32) {\n const type = children._;\n if (type) {\n assignSlots(slots, children, optimized);\n if (optimized) {\n def(slots, \"_\", type, true);\n }\n } else {\n normalizeObjectSlots(children, slots);\n }\n } else if (children) {\n normalizeVNodeSlots(instance, children);\n }\n};\nconst updateSlots = (instance, children, optimized) => {\n const { vnode, slots } = instance;\n let needDeletionCheck = true;\n let deletionComparisonTarget = EMPTY_OBJ;\n if (vnode.shapeFlag & 32) {\n const type = children._;\n if (type) {\n if (!!(process.env.NODE_ENV !== \"production\") && isHmrUpdating) {\n assignSlots(slots, children, optimized);\n trigger(instance, \"set\", \"$slots\");\n } else if (optimized && type === 1) {\n needDeletionCheck = false;\n } else {\n assignSlots(slots, children, optimized);\n }\n } else {\n needDeletionCheck = !children.$stable;\n normalizeObjectSlots(children, slots);\n }\n deletionComparisonTarget = children;\n } else if (children) {\n normalizeVNodeSlots(instance, children);\n deletionComparisonTarget = { default: 1 };\n }\n if (needDeletionCheck) {\n for (const key in slots) {\n if (!isInternalKey(key) && deletionComparisonTarget[key] == null) {\n delete slots[key];\n }\n }\n }\n};\n\nlet supported;\nlet perf;\nfunction startMeasure(instance, type) {\n if (instance.appContext.config.performance && isSupported()) {\n perf.mark(`vue-${type}-${instance.uid}`);\n }\n if (!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_DEVTOOLS__) {\n devtoolsPerfStart(instance, type, isSupported() ? perf.now() : Date.now());\n }\n}\nfunction endMeasure(instance, type) {\n if (instance.appContext.config.performance && isSupported()) {\n const startTag = `vue-${type}-${instance.uid}`;\n const endTag = startTag + `:end`;\n const measureName = `<${formatComponentName(instance, instance.type)}> ${type}`;\n perf.mark(endTag);\n perf.measure(measureName, startTag, endTag);\n perf.clearMeasures(measureName);\n perf.clearMarks(startTag);\n perf.clearMarks(endTag);\n }\n if (!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_DEVTOOLS__) {\n devtoolsPerfEnd(instance, type, isSupported() ? perf.now() : Date.now());\n }\n}\nfunction isSupported() {\n if (supported !== void 0) {\n return supported;\n }\n if (typeof window !== \"undefined\" && window.performance) {\n supported = true;\n perf = window.performance;\n } else {\n supported = false;\n }\n return supported;\n}\n\nfunction initFeatureFlags() {\n const needWarn = [];\n if (typeof __VUE_OPTIONS_API__ !== \"boolean\") {\n !!(process.env.NODE_ENV !== \"production\") && needWarn.push(`__VUE_OPTIONS_API__`);\n getGlobalThis().__VUE_OPTIONS_API__ = true;\n }\n if (typeof __VUE_PROD_DEVTOOLS__ !== \"boolean\") {\n !!(process.env.NODE_ENV !== \"production\") && needWarn.push(`__VUE_PROD_DEVTOOLS__`);\n getGlobalThis().__VUE_PROD_DEVTOOLS__ = false;\n }\n if (typeof __VUE_PROD_HYDRATION_MISMATCH_DETAILS__ !== \"boolean\") {\n !!(process.env.NODE_ENV !== \"production\") && needWarn.push(`__VUE_PROD_HYDRATION_MISMATCH_DETAILS__`);\n getGlobalThis().__VUE_PROD_HYDRATION_MISMATCH_DETAILS__ = false;\n }\n if (!!(process.env.NODE_ENV !== \"production\") && needWarn.length) {\n const multi = needWarn.length > 1;\n console.warn(\n `Feature flag${multi ? `s` : ``} ${needWarn.join(\", \")} ${multi ? `are` : `is`} not explicitly defined. You are running the esm-bundler build of Vue, which expects these compile-time feature flags to be globally injected via the bundler config in order to get better tree-shaking in the production bundle.\n\nFor more details, see https://link.vuejs.org/feature-flags.`\n );\n }\n}\n\nconst queuePostRenderEffect = queueEffectWithSuspense ;\nfunction createRenderer(options) {\n return baseCreateRenderer(options);\n}\nfunction createHydrationRenderer(options) {\n return baseCreateRenderer(options, createHydrationFunctions);\n}\nfunction baseCreateRenderer(options, createHydrationFns) {\n {\n initFeatureFlags();\n }\n const target = getGlobalThis();\n target.__VUE__ = true;\n if (!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_DEVTOOLS__) {\n setDevtoolsHook$1(target.__VUE_DEVTOOLS_GLOBAL_HOOK__, target);\n }\n const {\n insert: hostInsert,\n remove: hostRemove,\n patchProp: hostPatchProp,\n createElement: hostCreateElement,\n createText: hostCreateText,\n createComment: hostCreateComment,\n setText: hostSetText,\n setElementText: hostSetElementText,\n parentNode: hostParentNode,\n nextSibling: hostNextSibling,\n setScopeId: hostSetScopeId = NOOP,\n insertStaticContent: hostInsertStaticContent\n } = options;\n const patch = (n1, n2, container, anchor = null, parentComponent = null, parentSuspense = null, namespace = void 0, slotScopeIds = null, optimized = !!(process.env.NODE_ENV !== \"production\") && isHmrUpdating ? false : !!n2.dynamicChildren) => {\n if (n1 === n2) {\n return;\n }\n if (n1 && !isSameVNodeType(n1, n2)) {\n anchor = getNextHostNode(n1);\n unmount(n1, parentComponent, parentSuspense, true);\n n1 = null;\n }\n if (n2.patchFlag === -2) {\n optimized = false;\n n2.dynamicChildren = null;\n }\n const { type, ref, shapeFlag } = n2;\n switch (type) {\n case Text:\n processText(n1, n2, container, anchor);\n break;\n case Comment:\n processCommentNode(n1, n2, container, anchor);\n break;\n case Static:\n if (n1 == null) {\n mountStaticNode(n2, container, anchor, namespace);\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n patchStaticNode(n1, n2, container, namespace);\n }\n break;\n case Fragment:\n processFragment(\n n1,\n n2,\n container,\n anchor,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds,\n optimized\n );\n break;\n default:\n if (shapeFlag & 1) {\n processElement(\n n1,\n n2,\n container,\n anchor,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds,\n optimized\n );\n } else if (shapeFlag & 6) {\n processComponent(\n n1,\n n2,\n container,\n anchor,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds,\n optimized\n );\n } else if (shapeFlag & 64) {\n type.process(\n n1,\n n2,\n container,\n anchor,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds,\n optimized,\n internals\n );\n } else if (shapeFlag & 128) {\n type.process(\n n1,\n n2,\n container,\n anchor,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds,\n optimized,\n internals\n );\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(\"Invalid VNode type:\", type, `(${typeof type})`);\n }\n }\n if (ref != null && parentComponent) {\n setRef(ref, n1 && n1.ref, parentSuspense, n2 || n1, !n2);\n } else if (ref == null && n1 && n1.ref != null) {\n setRef(n1.ref, null, parentSuspense, n1, true);\n }\n };\n const processText = (n1, n2, container, anchor) => {\n if (n1 == null) {\n hostInsert(\n n2.el = hostCreateText(n2.children),\n container,\n anchor\n );\n } else {\n const el = n2.el = n1.el;\n if (n2.children !== n1.children) {\n hostSetText(el, n2.children);\n }\n }\n };\n const processCommentNode = (n1, n2, container, anchor) => {\n if (n1 == null) {\n hostInsert(\n n2.el = hostCreateComment(n2.children || \"\"),\n container,\n anchor\n );\n } else {\n n2.el = n1.el;\n }\n };\n const mountStaticNode = (n2, container, anchor, namespace) => {\n [n2.el, n2.anchor] = hostInsertStaticContent(\n n2.children,\n container,\n anchor,\n namespace,\n n2.el,\n n2.anchor\n );\n };\n const patchStaticNode = (n1, n2, container, namespace) => {\n if (n2.children !== n1.children) {\n const anchor = hostNextSibling(n1.anchor);\n removeStaticNode(n1);\n [n2.el, n2.anchor] = hostInsertStaticContent(\n n2.children,\n container,\n anchor,\n namespace\n );\n } else {\n n2.el = n1.el;\n n2.anchor = n1.anchor;\n }\n };\n const moveStaticNode = ({ el, anchor }, container, nextSibling) => {\n let next;\n while (el && el !== anchor) {\n next = hostNextSibling(el);\n hostInsert(el, container, nextSibling);\n el = next;\n }\n hostInsert(anchor, container, nextSibling);\n };\n const removeStaticNode = ({ el, anchor }) => {\n let next;\n while (el && el !== anchor) {\n next = hostNextSibling(el);\n hostRemove(el);\n el = next;\n }\n hostRemove(anchor);\n };\n const processElement = (n1, n2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized) => {\n if (n2.type === \"svg\") {\n namespace = \"svg\";\n } else if (n2.type === \"math\") {\n namespace = \"mathml\";\n }\n if (n1 == null) {\n mountElement(\n n2,\n container,\n anchor,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds,\n optimized\n );\n } else {\n const customElement = !!(n1.el && n1.el._isVueCE) ? n1.el : null;\n try {\n if (customElement) {\n customElement._beginPatch();\n }\n patchElement(\n n1,\n n2,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds,\n optimized\n );\n } finally {\n if (customElement) {\n customElement._endPatch();\n }\n }\n }\n };\n const mountElement = (vnode, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized) => {\n let el;\n let vnodeHook;\n const { props, shapeFlag, transition, dirs } = vnode;\n el = vnode.el = hostCreateElement(\n vnode.type,\n namespace,\n props && props.is,\n props\n );\n if (shapeFlag & 8) {\n hostSetElementText(el, vnode.children);\n } else if (shapeFlag & 16) {\n mountChildren(\n vnode.children,\n el,\n null,\n parentComponent,\n parentSuspense,\n resolveChildrenNamespace(vnode, namespace),\n slotScopeIds,\n optimized\n );\n }\n if (dirs) {\n invokeDirectiveHook(vnode, null, parentComponent, \"created\");\n }\n setScopeId(el, vnode, vnode.scopeId, slotScopeIds, parentComponent);\n if (props) {\n for (const key in props) {\n if (key !== \"value\" && !isReservedProp(key)) {\n hostPatchProp(el, key, null, props[key], namespace, parentComponent);\n }\n }\n if (\"value\" in props) {\n hostPatchProp(el, \"value\", null, props.value, namespace);\n }\n if (vnodeHook = props.onVnodeBeforeMount) {\n invokeVNodeHook(vnodeHook, parentComponent, vnode);\n }\n }\n if (!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_DEVTOOLS__) {\n def(el, \"__vnode\", vnode, true);\n def(el, \"__vueParentComponent\", parentComponent, true);\n }\n if (dirs) {\n invokeDirectiveHook(vnode, null, parentComponent, \"beforeMount\");\n }\n const needCallTransitionHooks = needTransition(parentSuspense, transition);\n if (needCallTransitionHooks) {\n transition.beforeEnter(el);\n }\n hostInsert(el, container, anchor);\n if ((vnodeHook = props && props.onVnodeMounted) || needCallTransitionHooks || dirs) {\n queuePostRenderEffect(() => {\n vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, vnode);\n needCallTransitionHooks && transition.enter(el);\n dirs && invokeDirectiveHook(vnode, null, parentComponent, \"mounted\");\n }, parentSuspense);\n }\n };\n const setScopeId = (el, vnode, scopeId, slotScopeIds, parentComponent) => {\n if (scopeId) {\n hostSetScopeId(el, scopeId);\n }\n if (slotScopeIds) {\n for (let i = 0; i < slotScopeIds.length; i++) {\n hostSetScopeId(el, slotScopeIds[i]);\n }\n }\n if (parentComponent) {\n let subTree = parentComponent.subTree;\n if (!!(process.env.NODE_ENV !== \"production\") && subTree.patchFlag > 0 && subTree.patchFlag & 2048) {\n subTree = filterSingleRoot(subTree.children) || subTree;\n }\n if (vnode === subTree || isSuspense(subTree.type) && (subTree.ssContent === vnode || subTree.ssFallback === vnode)) {\n const parentVNode = parentComponent.vnode;\n setScopeId(\n el,\n parentVNode,\n parentVNode.scopeId,\n parentVNode.slotScopeIds,\n parentComponent.parent\n );\n }\n }\n };\n const mountChildren = (children, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized, start = 0) => {\n for (let i = start; i < children.length; i++) {\n const child = children[i] = optimized ? cloneIfMounted(children[i]) : normalizeVNode(children[i]);\n patch(\n null,\n child,\n container,\n anchor,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds,\n optimized\n );\n }\n };\n const patchElement = (n1, n2, parentComponent, parentSuspense, namespace, slotScopeIds, optimized) => {\n const el = n2.el = n1.el;\n if (!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_DEVTOOLS__) {\n el.__vnode = n2;\n }\n let { patchFlag, dynamicChildren, dirs } = n2;\n patchFlag |= n1.patchFlag & 16;\n const oldProps = n1.props || EMPTY_OBJ;\n const newProps = n2.props || EMPTY_OBJ;\n let vnodeHook;\n parentComponent && toggleRecurse(parentComponent, false);\n if (vnodeHook = newProps.onVnodeBeforeUpdate) {\n invokeVNodeHook(vnodeHook, parentComponent, n2, n1);\n }\n if (dirs) {\n invokeDirectiveHook(n2, n1, parentComponent, \"beforeUpdate\");\n }\n parentComponent && toggleRecurse(parentComponent, true);\n if (!!(process.env.NODE_ENV !== \"production\") && isHmrUpdating) {\n patchFlag = 0;\n optimized = false;\n dynamicChildren = null;\n }\n if (oldProps.innerHTML && newProps.innerHTML == null || oldProps.textContent && newProps.textContent == null) {\n hostSetElementText(el, \"\");\n }\n if (dynamicChildren) {\n patchBlockChildren(\n n1.dynamicChildren,\n dynamicChildren,\n el,\n parentComponent,\n parentSuspense,\n resolveChildrenNamespace(n2, namespace),\n slotScopeIds\n );\n if (!!(process.env.NODE_ENV !== \"production\")) {\n traverseStaticChildren(n1, n2);\n }\n } else if (!optimized) {\n patchChildren(\n n1,\n n2,\n el,\n null,\n parentComponent,\n parentSuspense,\n resolveChildrenNamespace(n2, namespace),\n slotScopeIds,\n false\n );\n }\n if (patchFlag > 0) {\n if (patchFlag & 16) {\n patchProps(el, oldProps, newProps, parentComponent, namespace);\n } else {\n if (patchFlag & 2) {\n if (oldProps.class !== newProps.class) {\n hostPatchProp(el, \"class\", null, newProps.class, namespace);\n }\n }\n if (patchFlag & 4) {\n hostPatchProp(el, \"style\", oldProps.style, newProps.style, namespace);\n }\n if (patchFlag & 8) {\n const propsToUpdate = n2.dynamicProps;\n for (let i = 0; i < propsToUpdate.length; i++) {\n const key = propsToUpdate[i];\n const prev = oldProps[key];\n const next = newProps[key];\n if (next !== prev || key === \"value\") {\n hostPatchProp(el, key, prev, next, namespace, parentComponent);\n }\n }\n }\n }\n if (patchFlag & 1) {\n if (n1.children !== n2.children) {\n hostSetElementText(el, n2.children);\n }\n }\n } else if (!optimized && dynamicChildren == null) {\n patchProps(el, oldProps, newProps, parentComponent, namespace);\n }\n if ((vnodeHook = newProps.onVnodeUpdated) || dirs) {\n queuePostRenderEffect(() => {\n vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, n2, n1);\n dirs && invokeDirectiveHook(n2, n1, parentComponent, \"updated\");\n }, parentSuspense);\n }\n };\n const patchBlockChildren = (oldChildren, newChildren, fallbackContainer, parentComponent, parentSuspense, namespace, slotScopeIds) => {\n for (let i = 0; i < newChildren.length; i++) {\n const oldVNode = oldChildren[i];\n const newVNode = newChildren[i];\n const container = (\n // oldVNode may be an errored async setup() component inside Suspense\n // which will not have a mounted element\n oldVNode.el && // - In the case of a Fragment, we need to provide the actual parent\n // of the Fragment itself so it can move its children.\n (oldVNode.type === Fragment || // - In the case of different nodes, there is going to be a replacement\n // which also requires the correct parent container\n !isSameVNodeType(oldVNode, newVNode) || // - In the case of a component, it could contain anything.\n oldVNode.shapeFlag & (6 | 64 | 128)) ? hostParentNode(oldVNode.el) : (\n // In other cases, the parent container is not actually used so we\n // just pass the block element here to avoid a DOM parentNode call.\n fallbackContainer\n )\n );\n patch(\n oldVNode,\n newVNode,\n container,\n null,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds,\n true\n );\n }\n };\n const patchProps = (el, oldProps, newProps, parentComponent, namespace) => {\n if (oldProps !== newProps) {\n if (oldProps !== EMPTY_OBJ) {\n for (const key in oldProps) {\n if (!isReservedProp(key) && !(key in newProps)) {\n hostPatchProp(\n el,\n key,\n oldProps[key],\n null,\n namespace,\n parentComponent\n );\n }\n }\n }\n for (const key in newProps) {\n if (isReservedProp(key)) continue;\n const next = newProps[key];\n const prev = oldProps[key];\n if (next !== prev && key !== \"value\") {\n hostPatchProp(el, key, prev, next, namespace, parentComponent);\n }\n }\n if (\"value\" in newProps) {\n hostPatchProp(el, \"value\", oldProps.value, newProps.value, namespace);\n }\n }\n };\n const processFragment = (n1, n2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized) => {\n const fragmentStartAnchor = n2.el = n1 ? n1.el : hostCreateText(\"\");\n const fragmentEndAnchor = n2.anchor = n1 ? n1.anchor : hostCreateText(\"\");\n let { patchFlag, dynamicChildren, slotScopeIds: fragmentSlotScopeIds } = n2;\n if (!!(process.env.NODE_ENV !== \"production\") && // #5523 dev root fragment may inherit directives\n (isHmrUpdating || patchFlag & 2048)) {\n patchFlag = 0;\n optimized = false;\n dynamicChildren = null;\n }\n if (fragmentSlotScopeIds) {\n slotScopeIds = slotScopeIds ? slotScopeIds.concat(fragmentSlotScopeIds) : fragmentSlotScopeIds;\n }\n if (n1 == null) {\n hostInsert(fragmentStartAnchor, container, anchor);\n hostInsert(fragmentEndAnchor, container, anchor);\n mountChildren(\n // #10007\n // such fragment like `<></>` will be compiled into\n // a fragment which doesn't have a children.\n // In this case fallback to an empty array\n n2.children || [],\n container,\n fragmentEndAnchor,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds,\n optimized\n );\n } else {\n if (patchFlag > 0 && patchFlag & 64 && dynamicChildren && // #2715 the previous fragment could've been a BAILed one as a result\n // of renderSlot() with no valid children\n n1.dynamicChildren) {\n patchBlockChildren(\n n1.dynamicChildren,\n dynamicChildren,\n container,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds\n );\n if (!!(process.env.NODE_ENV !== \"production\")) {\n traverseStaticChildren(n1, n2);\n } else if (\n // #2080 if the stable fragment has a key, it's a <template v-for> that may\n // get moved around. Make sure all root level vnodes inherit el.\n // #2134 or if it's a component root, it may also get moved around\n // as the component is being moved.\n n2.key != null || parentComponent && n2 === parentComponent.subTree\n ) {\n traverseStaticChildren(\n n1,\n n2,\n true\n /* shallow */\n );\n }\n } else {\n patchChildren(\n n1,\n n2,\n container,\n fragmentEndAnchor,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds,\n optimized\n );\n }\n }\n };\n const processComponent = (n1, n2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized) => {\n n2.slotScopeIds = slotScopeIds;\n if (n1 == null) {\n if (n2.shapeFlag & 512) {\n parentComponent.ctx.activate(\n n2,\n container,\n anchor,\n namespace,\n optimized\n );\n } else {\n mountComponent(\n n2,\n container,\n anchor,\n parentComponent,\n parentSuspense,\n namespace,\n optimized\n );\n }\n } else {\n updateComponent(n1, n2, optimized);\n }\n };\n const mountComponent = (initialVNode, container, anchor, parentComponent, parentSuspense, namespace, optimized) => {\n const instance = (initialVNode.component = createComponentInstance(\n initialVNode,\n parentComponent,\n parentSuspense\n ));\n if (!!(process.env.NODE_ENV !== \"production\") && instance.type.__hmrId) {\n registerHMR(instance);\n }\n if (!!(process.env.NODE_ENV !== \"production\")) {\n pushWarningContext(initialVNode);\n startMeasure(instance, `mount`);\n }\n if (isKeepAlive(initialVNode)) {\n instance.ctx.renderer = internals;\n }\n {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n startMeasure(instance, `init`);\n }\n setupComponent(instance, false, optimized);\n if (!!(process.env.NODE_ENV !== \"production\")) {\n endMeasure(instance, `init`);\n }\n }\n if (!!(process.env.NODE_ENV !== \"production\") && isHmrUpdating) initialVNode.el = null;\n if (instance.asyncDep) {\n parentSuspense && parentSuspense.registerDep(instance, setupRenderEffect, optimized);\n if (!initialVNode.el) {\n const placeholder = instance.subTree = createVNode(Comment);\n processCommentNode(null, placeholder, container, anchor);\n initialVNode.placeholder = placeholder.el;\n }\n } else {\n setupRenderEffect(\n instance,\n initialVNode,\n container,\n anchor,\n parentSuspense,\n namespace,\n optimized\n );\n }\n if (!!(process.env.NODE_ENV !== \"production\")) {\n popWarningContext();\n endMeasure(instance, `mount`);\n }\n };\n const updateComponent = (n1, n2, optimized) => {\n const instance = n2.component = n1.component;\n if (shouldUpdateComponent(n1, n2, optimized)) {\n if (instance.asyncDep && !instance.asyncResolved) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n pushWarningContext(n2);\n }\n updateComponentPreRender(instance, n2, optimized);\n if (!!(process.env.NODE_ENV !== \"production\")) {\n popWarningContext();\n }\n return;\n } else {\n instance.next = n2;\n instance.update();\n }\n } else {\n n2.el = n1.el;\n instance.vnode = n2;\n }\n };\n const setupRenderEffect = (instance, initialVNode, container, anchor, parentSuspense, namespace, optimized) => {\n const componentUpdateFn = () => {\n if (!instance.isMounted) {\n let vnodeHook;\n const { el, props } = initialVNode;\n const { bm, m, parent, root, type } = instance;\n const isAsyncWrapperVNode = isAsyncWrapper(initialVNode);\n toggleRecurse(instance, false);\n if (bm) {\n invokeArrayFns(bm);\n }\n if (!isAsyncWrapperVNode && (vnodeHook = props && props.onVnodeBeforeMount)) {\n invokeVNodeHook(vnodeHook, parent, initialVNode);\n }\n toggleRecurse(instance, true);\n if (el && hydrateNode) {\n const hydrateSubTree = () => {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n startMeasure(instance, `render`);\n }\n instance.subTree = renderComponentRoot(instance);\n if (!!(process.env.NODE_ENV !== \"production\")) {\n endMeasure(instance, `render`);\n }\n if (!!(process.env.NODE_ENV !== \"production\")) {\n startMeasure(instance, `hydrate`);\n }\n hydrateNode(\n el,\n instance.subTree,\n instance,\n parentSuspense,\n null\n );\n if (!!(process.env.NODE_ENV !== \"production\")) {\n endMeasure(instance, `hydrate`);\n }\n };\n if (isAsyncWrapperVNode && type.__asyncHydrate) {\n type.__asyncHydrate(\n el,\n instance,\n hydrateSubTree\n );\n } else {\n hydrateSubTree();\n }\n } else {\n if (root.ce && // @ts-expect-error _def is private\n root.ce._def.shadowRoot !== false) {\n root.ce._injectChildStyle(type);\n }\n if (!!(process.env.NODE_ENV !== \"production\")) {\n startMeasure(instance, `render`);\n }\n const subTree = instance.subTree = renderComponentRoot(instance);\n if (!!(process.env.NODE_ENV !== \"production\")) {\n endMeasure(instance, `render`);\n }\n if (!!(process.env.NODE_ENV !== \"production\")) {\n startMeasure(instance, `patch`);\n }\n patch(\n null,\n subTree,\n container,\n anchor,\n instance,\n parentSuspense,\n namespace\n );\n if (!!(process.env.NODE_ENV !== \"production\")) {\n endMeasure(instance, `patch`);\n }\n initialVNode.el = subTree.el;\n }\n if (m) {\n queuePostRenderEffect(m, parentSuspense);\n }\n if (!isAsyncWrapperVNode && (vnodeHook = props && props.onVnodeMounted)) {\n const scopedInitialVNode = initialVNode;\n queuePostRenderEffect(\n () => invokeVNodeHook(vnodeHook, parent, scopedInitialVNode),\n parentSuspense\n );\n }\n if (initialVNode.shapeFlag & 256 || parent && isAsyncWrapper(parent.vnode) && parent.vnode.shapeFlag & 256) {\n instance.a && queuePostRenderEffect(instance.a, parentSuspense);\n }\n instance.isMounted = true;\n if (!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_DEVTOOLS__) {\n devtoolsComponentAdded(instance);\n }\n initialVNode = container = anchor = null;\n } else {\n let { next, bu, u, parent, vnode } = instance;\n {\n const nonHydratedAsyncRoot = locateNonHydratedAsyncRoot(instance);\n if (nonHydratedAsyncRoot) {\n if (next) {\n next.el = vnode.el;\n updateComponentPreRender(instance, next, optimized);\n }\n nonHydratedAsyncRoot.asyncDep.then(() => {\n if (!instance.isUnmounted) {\n componentUpdateFn();\n }\n });\n return;\n }\n }\n let originNext = next;\n let vnodeHook;\n if (!!(process.env.NODE_ENV !== \"production\")) {\n pushWarningContext(next || instance.vnode);\n }\n toggleRecurse(instance, false);\n if (next) {\n next.el = vnode.el;\n updateComponentPreRender(instance, next, optimized);\n } else {\n next = vnode;\n }\n if (bu) {\n invokeArrayFns(bu);\n }\n if (vnodeHook = next.props && next.props.onVnodeBeforeUpdate) {\n invokeVNodeHook(vnodeHook, parent, next, vnode);\n }\n toggleRecurse(instance, true);\n if (!!(process.env.NODE_ENV !== \"production\")) {\n startMeasure(instance, `render`);\n }\n const nextTree = renderComponentRoot(instance);\n if (!!(process.env.NODE_ENV !== \"production\")) {\n endMeasure(instance, `render`);\n }\n const prevTree = instance.subTree;\n instance.subTree = nextTree;\n if (!!(process.env.NODE_ENV !== \"production\")) {\n startMeasure(instance, `patch`);\n }\n patch(\n prevTree,\n nextTree,\n // parent may have changed if it's in a teleport\n hostParentNode(prevTree.el),\n // anchor may have changed if it's in a fragment\n getNextHostNode(prevTree),\n instance,\n parentSuspense,\n namespace\n );\n if (!!(process.env.NODE_ENV !== \"production\")) {\n endMeasure(instance, `patch`);\n }\n next.el = nextTree.el;\n if (originNext === null) {\n updateHOCHostEl(instance, nextTree.el);\n }\n if (u) {\n queuePostRenderEffect(u, parentSuspense);\n }\n if (vnodeHook = next.props && next.props.onVnodeUpdated) {\n queuePostRenderEffect(\n () => invokeVNodeHook(vnodeHook, parent, next, vnode),\n parentSuspense\n );\n }\n if (!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_DEVTOOLS__) {\n devtoolsComponentUpdated(instance);\n }\n if (!!(process.env.NODE_ENV !== \"production\")) {\n popWarningContext();\n }\n }\n };\n instance.scope.on();\n const effect = instance.effect = new ReactiveEffect(componentUpdateFn);\n instance.scope.off();\n const update = instance.update = effect.run.bind(effect);\n const job = instance.job = effect.runIfDirty.bind(effect);\n job.i = instance;\n job.id = instance.uid;\n effect.scheduler = () => queueJob(job);\n toggleRecurse(instance, true);\n if (!!(process.env.NODE_ENV !== \"production\")) {\n effect.onTrack = instance.rtc ? (e) => invokeArrayFns(instance.rtc, e) : void 0;\n effect.onTrigger = instance.rtg ? (e) => invokeArrayFns(instance.rtg, e) : void 0;\n }\n update();\n };\n const updateComponentPreRender = (instance, nextVNode, optimized) => {\n nextVNode.component = instance;\n const prevProps = instance.vnode.props;\n instance.vnode = nextVNode;\n instance.next = null;\n updateProps(instance, nextVNode.props, prevProps, optimized);\n updateSlots(instance, nextVNode.children, optimized);\n pauseTracking();\n flushPreFlushCbs(instance);\n resetTracking();\n };\n const patchChildren = (n1, n2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized = false) => {\n const c1 = n1 && n1.children;\n const prevShapeFlag = n1 ? n1.shapeFlag : 0;\n const c2 = n2.children;\n const { patchFlag, shapeFlag } = n2;\n if (patchFlag > 0) {\n if (patchFlag & 128) {\n patchKeyedChildren(\n c1,\n c2,\n container,\n anchor,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds,\n optimized\n );\n return;\n } else if (patchFlag & 256) {\n patchUnkeyedChildren(\n c1,\n c2,\n container,\n anchor,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds,\n optimized\n );\n return;\n }\n }\n if (shapeFlag & 8) {\n if (prevShapeFlag & 16) {\n unmountChildren(c1, parentComponent, parentSuspense);\n }\n if (c2 !== c1) {\n hostSetElementText(container, c2);\n }\n } else {\n if (prevShapeFlag & 16) {\n if (shapeFlag & 16) {\n patchKeyedChildren(\n c1,\n c2,\n container,\n anchor,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds,\n optimized\n );\n } else {\n unmountChildren(c1, parentComponent, parentSuspense, true);\n }\n } else {\n if (prevShapeFlag & 8) {\n hostSetElementText(container, \"\");\n }\n if (shapeFlag & 16) {\n mountChildren(\n c2,\n container,\n anchor,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds,\n optimized\n );\n }\n }\n }\n };\n const patchUnkeyedChildren = (c1, c2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized) => {\n c1 = c1 || EMPTY_ARR;\n c2 = c2 || EMPTY_ARR;\n const oldLength = c1.length;\n const newLength = c2.length;\n const commonLength = Math.min(oldLength, newLength);\n let i;\n for (i = 0; i < commonLength; i++) {\n const nextChild = c2[i] = optimized ? cloneIfMounted(c2[i]) : normalizeVNode(c2[i]);\n patch(\n c1[i],\n nextChild,\n container,\n null,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds,\n optimized\n );\n }\n if (oldLength > newLength) {\n unmountChildren(\n c1,\n parentComponent,\n parentSuspense,\n true,\n false,\n commonLength\n );\n } else {\n mountChildren(\n c2,\n container,\n anchor,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds,\n optimized,\n commonLength\n );\n }\n };\n const patchKeyedChildren = (c1, c2, container, parentAnchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized) => {\n let i = 0;\n const l2 = c2.length;\n let e1 = c1.length - 1;\n let e2 = l2 - 1;\n while (i <= e1 && i <= e2) {\n const n1 = c1[i];\n const n2 = c2[i] = optimized ? cloneIfMounted(c2[i]) : normalizeVNode(c2[i]);\n if (isSameVNodeType(n1, n2)) {\n patch(\n n1,\n n2,\n container,\n null,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds,\n optimized\n );\n } else {\n break;\n }\n i++;\n }\n while (i <= e1 && i <= e2) {\n const n1 = c1[e1];\n const n2 = c2[e2] = optimized ? cloneIfMounted(c2[e2]) : normalizeVNode(c2[e2]);\n if (isSameVNodeType(n1, n2)) {\n patch(\n n1,\n n2,\n container,\n null,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds,\n optimized\n );\n } else {\n break;\n }\n e1--;\n e2--;\n }\n if (i > e1) {\n if (i <= e2) {\n const nextPos = e2 + 1;\n const anchor = nextPos < l2 ? c2[nextPos].el : parentAnchor;\n while (i <= e2) {\n patch(\n null,\n c2[i] = optimized ? cloneIfMounted(c2[i]) : normalizeVNode(c2[i]),\n container,\n anchor,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds,\n optimized\n );\n i++;\n }\n }\n } else if (i > e2) {\n while (i <= e1) {\n unmount(c1[i], parentComponent, parentSuspense, true);\n i++;\n }\n } else {\n const s1 = i;\n const s2 = i;\n const keyToNewIndexMap = /* @__PURE__ */ new Map();\n for (i = s2; i <= e2; i++) {\n const nextChild = c2[i] = optimized ? cloneIfMounted(c2[i]) : normalizeVNode(c2[i]);\n if (nextChild.key != null) {\n if (!!(process.env.NODE_ENV !== \"production\") && keyToNewIndexMap.has(nextChild.key)) {\n warn$1(\n `Duplicate keys found during update:`,\n JSON.stringify(nextChild.key),\n `Make sure keys are unique.`\n );\n }\n keyToNewIndexMap.set(nextChild.key, i);\n }\n }\n let j;\n let patched = 0;\n const toBePatched = e2 - s2 + 1;\n let moved = false;\n let maxNewIndexSoFar = 0;\n const newIndexToOldIndexMap = new Array(toBePatched);\n for (i = 0; i < toBePatched; i++) newIndexToOldIndexMap[i] = 0;\n for (i = s1; i <= e1; i++) {\n const prevChild = c1[i];\n if (patched >= toBePatched) {\n unmount(prevChild, parentComponent, parentSuspense, true);\n continue;\n }\n let newIndex;\n if (prevChild.key != null) {\n newIndex = keyToNewIndexMap.get(prevChild.key);\n } else {\n for (j = s2; j <= e2; j++) {\n if (newIndexToOldIndexMap[j - s2] === 0 && isSameVNodeType(prevChild, c2[j])) {\n newIndex = j;\n break;\n }\n }\n }\n if (newIndex === void 0) {\n unmount(prevChild, parentComponent, parentSuspense, true);\n } else {\n newIndexToOldIndexMap[newIndex - s2] = i + 1;\n if (newIndex >= maxNewIndexSoFar) {\n maxNewIndexSoFar = newIndex;\n } else {\n moved = true;\n }\n patch(\n prevChild,\n c2[newIndex],\n container,\n null,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds,\n optimized\n );\n patched++;\n }\n }\n const increasingNewIndexSequence = moved ? getSequence(newIndexToOldIndexMap) : EMPTY_ARR;\n j = increasingNewIndexSequence.length - 1;\n for (i = toBePatched - 1; i >= 0; i--) {\n const nextIndex = s2 + i;\n const nextChild = c2[nextIndex];\n const anchorVNode = c2[nextIndex + 1];\n const anchor = nextIndex + 1 < l2 ? (\n // #13559, fallback to el placeholder for unresolved async component\n anchorVNode.el || anchorVNode.placeholder\n ) : parentAnchor;\n if (newIndexToOldIndexMap[i] === 0) {\n patch(\n null,\n nextChild,\n container,\n anchor,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds,\n optimized\n );\n } else if (moved) {\n if (j < 0 || i !== increasingNewIndexSequence[j]) {\n move(nextChild, container, anchor, 2);\n } else {\n j--;\n }\n }\n }\n }\n };\n const move = (vnode, container, anchor, moveType, parentSuspense = null) => {\n const { el, type, transition, children, shapeFlag } = vnode;\n if (shapeFlag & 6) {\n move(vnode.component.subTree, container, anchor, moveType);\n return;\n }\n if (shapeFlag & 128) {\n vnode.suspense.move(container, anchor, moveType);\n return;\n }\n if (shapeFlag & 64) {\n type.move(vnode, container, anchor, internals);\n return;\n }\n if (type === Fragment) {\n hostInsert(el, container, anchor);\n for (let i = 0; i < children.length; i++) {\n move(children[i], container, anchor, moveType);\n }\n hostInsert(vnode.anchor, container, anchor);\n return;\n }\n if (type === Static) {\n moveStaticNode(vnode, container, anchor);\n return;\n }\n const needTransition2 = moveType !== 2 && shapeFlag & 1 && transition;\n if (needTransition2) {\n if (moveType === 0) {\n transition.beforeEnter(el);\n hostInsert(el, container, anchor);\n queuePostRenderEffect(() => transition.enter(el), parentSuspense);\n } else {\n const { leave, delayLeave, afterLeave } = transition;\n const remove2 = () => {\n if (vnode.ctx.isUnmounted) {\n hostRemove(el);\n } else {\n hostInsert(el, container, anchor);\n }\n };\n const performLeave = () => {\n if (el._isLeaving) {\n el[leaveCbKey](\n true\n /* cancelled */\n );\n }\n leave(el, () => {\n remove2();\n afterLeave && afterLeave();\n });\n };\n if (delayLeave) {\n delayLeave(el, remove2, performLeave);\n } else {\n performLeave();\n }\n }\n } else {\n hostInsert(el, container, anchor);\n }\n };\n const unmount = (vnode, parentComponent, parentSuspense, doRemove = false, optimized = false) => {\n const {\n type,\n props,\n ref,\n children,\n dynamicChildren,\n shapeFlag,\n patchFlag,\n dirs,\n cacheIndex\n } = vnode;\n if (patchFlag === -2) {\n optimized = false;\n }\n if (ref != null) {\n pauseTracking();\n setRef(ref, null, parentSuspense, vnode, true);\n resetTracking();\n }\n if (cacheIndex != null) {\n parentComponent.renderCache[cacheIndex] = void 0;\n }\n if (shapeFlag & 256) {\n parentComponent.ctx.deactivate(vnode);\n return;\n }\n const shouldInvokeDirs = shapeFlag & 1 && dirs;\n const shouldInvokeVnodeHook = !isAsyncWrapper(vnode);\n let vnodeHook;\n if (shouldInvokeVnodeHook && (vnodeHook = props && props.onVnodeBeforeUnmount)) {\n invokeVNodeHook(vnodeHook, parentComponent, vnode);\n }\n if (shapeFlag & 6) {\n unmountComponent(vnode.component, parentSuspense, doRemove);\n } else {\n if (shapeFlag & 128) {\n vnode.suspense.unmount(parentSuspense, doRemove);\n return;\n }\n if (shouldInvokeDirs) {\n invokeDirectiveHook(vnode, null, parentComponent, \"beforeUnmount\");\n }\n if (shapeFlag & 64) {\n vnode.type.remove(\n vnode,\n parentComponent,\n parentSuspense,\n internals,\n doRemove\n );\n } else if (dynamicChildren && // #5154\n // when v-once is used inside a block, setBlockTracking(-1) marks the\n // parent block with hasOnce: true\n // so that it doesn't take the fast path during unmount - otherwise\n // components nested in v-once are never unmounted.\n !dynamicChildren.hasOnce && // #1153: fast path should not be taken for non-stable (v-for) fragments\n (type !== Fragment || patchFlag > 0 && patchFlag & 64)) {\n unmountChildren(\n dynamicChildren,\n parentComponent,\n parentSuspense,\n false,\n true\n );\n } else if (type === Fragment && patchFlag & (128 | 256) || !optimized && shapeFlag & 16) {\n unmountChildren(children, parentComponent, parentSuspense);\n }\n if (doRemove) {\n remove(vnode);\n }\n }\n if (shouldInvokeVnodeHook && (vnodeHook = props && props.onVnodeUnmounted) || shouldInvokeDirs) {\n queuePostRenderEffect(() => {\n vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, vnode);\n shouldInvokeDirs && invokeDirectiveHook(vnode, null, parentComponent, \"unmounted\");\n }, parentSuspense);\n }\n };\n const remove = (vnode) => {\n const { type, el, anchor, transition } = vnode;\n if (type === Fragment) {\n if (!!(process.env.NODE_ENV !== \"production\") && vnode.patchFlag > 0 && vnode.patchFlag & 2048 && transition && !transition.persisted) {\n vnode.children.forEach((child) => {\n if (child.type === Comment) {\n hostRemove(child.el);\n } else {\n remove(child);\n }\n });\n } else {\n removeFragment(el, anchor);\n }\n return;\n }\n if (type === Static) {\n removeStaticNode(vnode);\n return;\n }\n const performRemove = () => {\n hostRemove(el);\n if (transition && !transition.persisted && transition.afterLeave) {\n transition.afterLeave();\n }\n };\n if (vnode.shapeFlag & 1 && transition && !transition.persisted) {\n const { leave, delayLeave } = transition;\n const performLeave = () => leave(el, performRemove);\n if (delayLeave) {\n delayLeave(vnode.el, performRemove, performLeave);\n } else {\n performLeave();\n }\n } else {\n performRemove();\n }\n };\n const removeFragment = (cur, end) => {\n let next;\n while (cur !== end) {\n next = hostNextSibling(cur);\n hostRemove(cur);\n cur = next;\n }\n hostRemove(end);\n };\n const unmountComponent = (instance, parentSuspense, doRemove) => {\n if (!!(process.env.NODE_ENV !== \"production\") && instance.type.__hmrId) {\n unregisterHMR(instance);\n }\n const { bum, scope, job, subTree, um, m, a } = instance;\n invalidateMount(m);\n invalidateMount(a);\n if (bum) {\n invokeArrayFns(bum);\n }\n scope.stop();\n if (job) {\n job.flags |= 8;\n unmount(subTree, instance, parentSuspense, doRemove);\n }\n if (um) {\n queuePostRenderEffect(um, parentSuspense);\n }\n queuePostRenderEffect(() => {\n instance.isUnmounted = true;\n }, parentSuspense);\n if (!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_DEVTOOLS__) {\n devtoolsComponentRemoved(instance);\n }\n };\n const unmountChildren = (children, parentComponent, parentSuspense, doRemove = false, optimized = false, start = 0) => {\n for (let i = start; i < children.length; i++) {\n unmount(children[i], parentComponent, parentSuspense, doRemove, optimized);\n }\n };\n const getNextHostNode = (vnode) => {\n if (vnode.shapeFlag & 6) {\n return getNextHostNode(vnode.component.subTree);\n }\n if (vnode.shapeFlag & 128) {\n return vnode.suspense.next();\n }\n const el = hostNextSibling(vnode.anchor || vnode.el);\n const teleportEnd = el && el[TeleportEndKey];\n return teleportEnd ? hostNextSibling(teleportEnd) : el;\n };\n let isFlushing = false;\n const render = (vnode, container, namespace) => {\n if (vnode == null) {\n if (container._vnode) {\n unmount(container._vnode, null, null, true);\n }\n } else {\n patch(\n container._vnode || null,\n vnode,\n container,\n null,\n null,\n null,\n namespace\n );\n }\n container._vnode = vnode;\n if (!isFlushing) {\n isFlushing = true;\n flushPreFlushCbs();\n flushPostFlushCbs();\n isFlushing = false;\n }\n };\n const internals = {\n p: patch,\n um: unmount,\n m: move,\n r: remove,\n mt: mountComponent,\n mc: mountChildren,\n pc: patchChildren,\n pbc: patchBlockChildren,\n n: getNextHostNode,\n o: options\n };\n let hydrate;\n let hydrateNode;\n if (createHydrationFns) {\n [hydrate, hydrateNode] = createHydrationFns(\n internals\n );\n }\n return {\n render,\n hydrate,\n createApp: createAppAPI(render, hydrate)\n };\n}\nfunction resolveChildrenNamespace({ type, props }, currentNamespace) {\n return currentNamespace === \"svg\" && type === \"foreignObject\" || currentNamespace === \"mathml\" && type === \"annotation-xml\" && props && props.encoding && props.encoding.includes(\"html\") ? void 0 : currentNamespace;\n}\nfunction toggleRecurse({ effect, job }, allowed) {\n if (allowed) {\n effect.flags |= 32;\n job.flags |= 4;\n } else {\n effect.flags &= -33;\n job.flags &= -5;\n }\n}\nfunction needTransition(parentSuspense, transition) {\n return (!parentSuspense || parentSuspense && !parentSuspense.pendingBranch) && transition && !transition.persisted;\n}\nfunction traverseStaticChildren(n1, n2, shallow = false) {\n const ch1 = n1.children;\n const ch2 = n2.children;\n if (isArray(ch1) && isArray(ch2)) {\n for (let i = 0; i < ch1.length; i++) {\n const c1 = ch1[i];\n let c2 = ch2[i];\n if (c2.shapeFlag & 1 && !c2.dynamicChildren) {\n if (c2.patchFlag <= 0 || c2.patchFlag === 32) {\n c2 = ch2[i] = cloneIfMounted(ch2[i]);\n c2.el = c1.el;\n }\n if (!shallow && c2.patchFlag !== -2)\n traverseStaticChildren(c1, c2);\n }\n if (c2.type === Text && // avoid cached text nodes retaining detached dom nodes\n c2.patchFlag !== -1) {\n c2.el = c1.el;\n }\n if (c2.type === Comment && !c2.el) {\n c2.el = c1.el;\n }\n if (!!(process.env.NODE_ENV !== \"production\")) {\n c2.el && (c2.el.__vnode = c2);\n }\n }\n }\n}\nfunction getSequence(arr) {\n const p = arr.slice();\n const result = [0];\n let i, j, u, v, c;\n const len = arr.length;\n for (i = 0; i < len; i++) {\n const arrI = arr[i];\n if (arrI !== 0) {\n j = result[result.length - 1];\n if (arr[j] < arrI) {\n p[i] = j;\n result.push(i);\n continue;\n }\n u = 0;\n v = result.length - 1;\n while (u < v) {\n c = u + v >> 1;\n if (arr[result[c]] < arrI) {\n u = c + 1;\n } else {\n v = c;\n }\n }\n if (arrI < arr[result[u]]) {\n if (u > 0) {\n p[i] = result[u - 1];\n }\n result[u] = i;\n }\n }\n }\n u = result.length;\n v = result[u - 1];\n while (u-- > 0) {\n result[u] = v;\n v = p[v];\n }\n return result;\n}\nfunction locateNonHydratedAsyncRoot(instance) {\n const subComponent = instance.subTree.component;\n if (subComponent) {\n if (subComponent.asyncDep && !subComponent.asyncResolved) {\n return subComponent;\n } else {\n return locateNonHydratedAsyncRoot(subComponent);\n }\n }\n}\nfunction invalidateMount(hooks) {\n if (hooks) {\n for (let i = 0; i < hooks.length; i++)\n hooks[i].flags |= 8;\n }\n}\n\nconst isSuspense = (type) => type.__isSuspense;\nlet suspenseId = 0;\nconst SuspenseImpl = {\n name: \"Suspense\",\n // In order to make Suspense tree-shakable, we need to avoid importing it\n // directly in the renderer. The renderer checks for the __isSuspense flag\n // on a vnode's type and calls the `process` method, passing in renderer\n // internals.\n __isSuspense: true,\n process(n1, n2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized, rendererInternals) {\n if (n1 == null) {\n mountSuspense(\n n2,\n container,\n anchor,\n parentComponent,\n parentSuspense,\n namespace,\n slotScopeIds,\n optimized,\n rendererInternals\n );\n } else {\n if (parentSuspense && parentSuspense.deps > 0 && !n1.suspense.isInFallback) {\n n2.suspense = n1.suspense;\n n2.suspense.vnode = n2;\n n2.el = n1.el;\n return;\n }\n patchSuspense(\n n1,\n n2,\n container,\n anchor,\n parentComponent,\n namespace,\n slotScopeIds,\n optimized,\n rendererInternals\n );\n }\n },\n hydrate: hydrateSuspense,\n normalize: normalizeSuspenseChildren\n};\nconst Suspense = SuspenseImpl ;\nfunction triggerEvent(vnode, name) {\n const eventListener = vnode.props && vnode.props[name];\n if (isFunction(eventListener)) {\n eventListener();\n }\n}\nfunction mountSuspense(vnode, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized, rendererInternals) {\n const {\n p: patch,\n o: { createElement }\n } = rendererInternals;\n const hiddenContainer = createElement(\"div\");\n const suspense = vnode.suspense = createSuspenseBoundary(\n vnode,\n parentSuspense,\n parentComponent,\n container,\n hiddenContainer,\n anchor,\n namespace,\n slotScopeIds,\n optimized,\n rendererInternals\n );\n patch(\n null,\n suspense.pendingBranch = vnode.ssContent,\n hiddenContainer,\n null,\n parentComponent,\n suspense,\n namespace,\n slotScopeIds\n );\n if (suspense.deps > 0) {\n triggerEvent(vnode, \"onPending\");\n triggerEvent(vnode, \"onFallback\");\n patch(\n null,\n vnode.ssFallback,\n container,\n anchor,\n parentComponent,\n null,\n // fallback tree will not have suspense context\n namespace,\n slotScopeIds\n );\n setActiveBranch(suspense, vnode.ssFallback);\n } else {\n suspense.resolve(false, true);\n }\n}\nfunction patchSuspense(n1, n2, container, anchor, parentComponent, namespace, slotScopeIds, optimized, { p: patch, um: unmount, o: { createElement } }) {\n const suspense = n2.suspense = n1.suspense;\n suspense.vnode = n2;\n n2.el = n1.el;\n const newBranch = n2.ssContent;\n const newFallback = n2.ssFallback;\n const { activeBranch, pendingBranch, isInFallback, isHydrating } = suspense;\n if (pendingBranch) {\n suspense.pendingBranch = newBranch;\n if (isSameVNodeType(pendingBranch, newBranch)) {\n patch(\n pendingBranch,\n newBranch,\n suspense.hiddenContainer,\n null,\n parentComponent,\n suspense,\n namespace,\n slotScopeIds,\n optimized\n );\n if (suspense.deps <= 0) {\n suspense.resolve();\n } else if (isInFallback) {\n if (!isHydrating) {\n patch(\n activeBranch,\n newFallback,\n container,\n anchor,\n parentComponent,\n null,\n // fallback tree will not have suspense context\n namespace,\n slotScopeIds,\n optimized\n );\n setActiveBranch(suspense, newFallback);\n }\n }\n } else {\n suspense.pendingId = suspenseId++;\n if (isHydrating) {\n suspense.isHydrating = false;\n suspense.activeBranch = pendingBranch;\n } else {\n unmount(pendingBranch, parentComponent, suspense);\n }\n suspense.deps = 0;\n suspense.effects.length = 0;\n suspense.hiddenContainer = createElement(\"div\");\n if (isInFallback) {\n patch(\n null,\n newBranch,\n suspense.hiddenContainer,\n null,\n parentComponent,\n suspense,\n namespace,\n slotScopeIds,\n optimized\n );\n if (suspense.deps <= 0) {\n suspense.resolve();\n } else {\n patch(\n activeBranch,\n newFallback,\n container,\n anchor,\n parentComponent,\n null,\n // fallback tree will not have suspense context\n namespace,\n slotScopeIds,\n optimized\n );\n setActiveBranch(suspense, newFallback);\n }\n } else if (activeBranch && isSameVNodeType(activeBranch, newBranch)) {\n patch(\n activeBranch,\n newBranch,\n container,\n anchor,\n parentComponent,\n suspense,\n namespace,\n slotScopeIds,\n optimized\n );\n suspense.resolve(true);\n } else {\n patch(\n null,\n newBranch,\n suspense.hiddenContainer,\n null,\n parentComponent,\n suspense,\n namespace,\n slotScopeIds,\n optimized\n );\n if (suspense.deps <= 0) {\n suspense.resolve();\n }\n }\n }\n } else {\n if (activeBranch && isSameVNodeType(activeBranch, newBranch)) {\n patch(\n activeBranch,\n newBranch,\n container,\n anchor,\n parentComponent,\n suspense,\n namespace,\n slotScopeIds,\n optimized\n );\n setActiveBranch(suspense, newBranch);\n } else {\n triggerEvent(n2, \"onPending\");\n suspense.pendingBranch = newBranch;\n if (newBranch.shapeFlag & 512) {\n suspense.pendingId = newBranch.component.suspenseId;\n } else {\n suspense.pendingId = suspenseId++;\n }\n patch(\n null,\n newBranch,\n suspense.hiddenContainer,\n null,\n parentComponent,\n suspense,\n namespace,\n slotScopeIds,\n optimized\n );\n if (suspense.deps <= 0) {\n suspense.resolve();\n } else {\n const { timeout, pendingId } = suspense;\n if (timeout > 0) {\n setTimeout(() => {\n if (suspense.pendingId === pendingId) {\n suspense.fallback(newFallback);\n }\n }, timeout);\n } else if (timeout === 0) {\n suspense.fallback(newFallback);\n }\n }\n }\n }\n}\nlet hasWarned = false;\nfunction createSuspenseBoundary(vnode, parentSuspense, parentComponent, container, hiddenContainer, anchor, namespace, slotScopeIds, optimized, rendererInternals, isHydrating = false) {\n if (!!(process.env.NODE_ENV !== \"production\") && true && !hasWarned) {\n hasWarned = true;\n console[console.info ? \"info\" : \"log\"](\n `<Suspense> is an experimental feature and its API will likely change.`\n );\n }\n const {\n p: patch,\n m: move,\n um: unmount,\n n: next,\n o: { parentNode, remove }\n } = rendererInternals;\n let parentSuspenseId;\n const isSuspensible = isVNodeSuspensible(vnode);\n if (isSuspensible) {\n if (parentSuspense && parentSuspense.pendingBranch) {\n parentSuspenseId = parentSuspense.pendingId;\n parentSuspense.deps++;\n }\n }\n const timeout = vnode.props ? toNumber(vnode.props.timeout) : void 0;\n if (!!(process.env.NODE_ENV !== \"production\")) {\n assertNumber(timeout, `Suspense timeout`);\n }\n const initialAnchor = anchor;\n const suspense = {\n vnode,\n parent: parentSuspense,\n parentComponent,\n namespace,\n container,\n hiddenContainer,\n deps: 0,\n pendingId: suspenseId++,\n timeout: typeof timeout === \"number\" ? timeout : -1,\n activeBranch: null,\n pendingBranch: null,\n isInFallback: !isHydrating,\n isHydrating,\n isUnmounted: false,\n effects: [],\n resolve(resume = false, sync = false) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n if (!resume && !suspense.pendingBranch) {\n throw new Error(\n `suspense.resolve() is called without a pending branch.`\n );\n }\n if (suspense.isUnmounted) {\n throw new Error(\n `suspense.resolve() is called on an already unmounted suspense boundary.`\n );\n }\n }\n const {\n vnode: vnode2,\n activeBranch,\n pendingBranch,\n pendingId,\n effects,\n parentComponent: parentComponent2,\n container: container2,\n isInFallback\n } = suspense;\n let delayEnter = false;\n if (suspense.isHydrating) {\n suspense.isHydrating = false;\n } else if (!resume) {\n delayEnter = activeBranch && pendingBranch.transition && pendingBranch.transition.mode === \"out-in\";\n if (delayEnter) {\n activeBranch.transition.afterLeave = () => {\n if (pendingId === suspense.pendingId) {\n move(\n pendingBranch,\n container2,\n anchor === initialAnchor ? next(activeBranch) : anchor,\n 0\n );\n queuePostFlushCb(effects);\n if (isInFallback && vnode2.ssFallback) {\n vnode2.ssFallback.el = null;\n }\n }\n };\n }\n if (activeBranch) {\n if (parentNode(activeBranch.el) === container2) {\n anchor = next(activeBranch);\n }\n unmount(activeBranch, parentComponent2, suspense, true);\n if (!delayEnter && isInFallback && vnode2.ssFallback) {\n queuePostRenderEffect(() => vnode2.ssFallback.el = null, suspense);\n }\n }\n if (!delayEnter) {\n move(pendingBranch, container2, anchor, 0);\n }\n }\n setActiveBranch(suspense, pendingBranch);\n suspense.pendingBranch = null;\n suspense.isInFallback = false;\n let parent = suspense.parent;\n let hasUnresolvedAncestor = false;\n while (parent) {\n if (parent.pendingBranch) {\n parent.effects.push(...effects);\n hasUnresolvedAncestor = true;\n break;\n }\n parent = parent.parent;\n }\n if (!hasUnresolvedAncestor && !delayEnter) {\n queuePostFlushCb(effects);\n }\n suspense.effects = [];\n if (isSuspensible) {\n if (parentSuspense && parentSuspense.pendingBranch && parentSuspenseId === parentSuspense.pendingId) {\n parentSuspense.deps--;\n if (parentSuspense.deps === 0 && !sync) {\n parentSuspense.resolve();\n }\n }\n }\n triggerEvent(vnode2, \"onResolve\");\n },\n fallback(fallbackVNode) {\n if (!suspense.pendingBranch) {\n return;\n }\n const { vnode: vnode2, activeBranch, parentComponent: parentComponent2, container: container2, namespace: namespace2 } = suspense;\n triggerEvent(vnode2, \"onFallback\");\n const anchor2 = next(activeBranch);\n const mountFallback = () => {\n if (!suspense.isInFallback) {\n return;\n }\n patch(\n null,\n fallbackVNode,\n container2,\n anchor2,\n parentComponent2,\n null,\n // fallback tree will not have suspense context\n namespace2,\n slotScopeIds,\n optimized\n );\n setActiveBranch(suspense, fallbackVNode);\n };\n const delayEnter = fallbackVNode.transition && fallbackVNode.transition.mode === \"out-in\";\n if (delayEnter) {\n activeBranch.transition.afterLeave = mountFallback;\n }\n suspense.isInFallback = true;\n unmount(\n activeBranch,\n parentComponent2,\n null,\n // no suspense so unmount hooks fire now\n true\n // shouldRemove\n );\n if (!delayEnter) {\n mountFallback();\n }\n },\n move(container2, anchor2, type) {\n suspense.activeBranch && move(suspense.activeBranch, container2, anchor2, type);\n suspense.container = container2;\n },\n next() {\n return suspense.activeBranch && next(suspense.activeBranch);\n },\n registerDep(instance, setupRenderEffect, optimized2) {\n const isInPendingSuspense = !!suspense.pendingBranch;\n if (isInPendingSuspense) {\n suspense.deps++;\n }\n const hydratedEl = instance.vnode.el;\n instance.asyncDep.catch((err) => {\n handleError(err, instance, 0);\n }).then((asyncSetupResult) => {\n if (instance.isUnmounted || suspense.isUnmounted || suspense.pendingId !== instance.suspenseId) {\n return;\n }\n instance.asyncResolved = true;\n const { vnode: vnode2 } = instance;\n if (!!(process.env.NODE_ENV !== \"production\")) {\n pushWarningContext(vnode2);\n }\n handleSetupResult(instance, asyncSetupResult, false);\n if (hydratedEl) {\n vnode2.el = hydratedEl;\n }\n const placeholder = !hydratedEl && instance.subTree.el;\n setupRenderEffect(\n instance,\n vnode2,\n // component may have been moved before resolve.\n // if this is not a hydration, instance.subTree will be the comment\n // placeholder.\n parentNode(hydratedEl || instance.subTree.el),\n // anchor will not be used if this is hydration, so only need to\n // consider the comment placeholder case.\n hydratedEl ? null : next(instance.subTree),\n suspense,\n namespace,\n optimized2\n );\n if (placeholder) {\n vnode2.placeholder = null;\n remove(placeholder);\n }\n updateHOCHostEl(instance, vnode2.el);\n if (!!(process.env.NODE_ENV !== \"production\")) {\n popWarningContext();\n }\n if (isInPendingSuspense && --suspense.deps === 0) {\n suspense.resolve();\n }\n });\n },\n unmount(parentSuspense2, doRemove) {\n suspense.isUnmounted = true;\n if (suspense.activeBranch) {\n unmount(\n suspense.activeBranch,\n parentComponent,\n parentSuspense2,\n doRemove\n );\n }\n if (suspense.pendingBranch) {\n unmount(\n suspense.pendingBranch,\n parentComponent,\n parentSuspense2,\n doRemove\n );\n }\n }\n };\n return suspense;\n}\nfunction hydrateSuspense(node, vnode, parentComponent, parentSuspense, namespace, slotScopeIds, optimized, rendererInternals, hydrateNode) {\n const suspense = vnode.suspense = createSuspenseBoundary(\n vnode,\n parentSuspense,\n parentComponent,\n node.parentNode,\n // eslint-disable-next-line no-restricted-globals\n document.createElement(\"div\"),\n null,\n namespace,\n slotScopeIds,\n optimized,\n rendererInternals,\n true\n );\n const result = hydrateNode(\n node,\n suspense.pendingBranch = vnode.ssContent,\n parentComponent,\n suspense,\n slotScopeIds,\n optimized\n );\n if (suspense.deps === 0) {\n suspense.resolve(false, true);\n }\n return result;\n}\nfunction normalizeSuspenseChildren(vnode) {\n const { shapeFlag, children } = vnode;\n const isSlotChildren = shapeFlag & 32;\n vnode.ssContent = normalizeSuspenseSlot(\n isSlotChildren ? children.default : children\n );\n vnode.ssFallback = isSlotChildren ? normalizeSuspenseSlot(children.fallback) : createVNode(Comment);\n}\nfunction normalizeSuspenseSlot(s) {\n let block;\n if (isFunction(s)) {\n const trackBlock = isBlockTreeEnabled && s._c;\n if (trackBlock) {\n s._d = false;\n openBlock();\n }\n s = s();\n if (trackBlock) {\n s._d = true;\n block = currentBlock;\n closeBlock();\n }\n }\n if (isArray(s)) {\n const singleChild = filterSingleRoot(s);\n if (!!(process.env.NODE_ENV !== \"production\") && !singleChild && s.filter((child) => child !== NULL_DYNAMIC_COMPONENT).length > 0) {\n warn$1(`<Suspense> slots expect a single root node.`);\n }\n s = singleChild;\n }\n s = normalizeVNode(s);\n if (block && !s.dynamicChildren) {\n s.dynamicChildren = block.filter((c) => c !== s);\n }\n return s;\n}\nfunction queueEffectWithSuspense(fn, suspense) {\n if (suspense && suspense.pendingBranch) {\n if (isArray(fn)) {\n suspense.effects.push(...fn);\n } else {\n suspense.effects.push(fn);\n }\n } else {\n queuePostFlushCb(fn);\n }\n}\nfunction setActiveBranch(suspense, branch) {\n suspense.activeBranch = branch;\n const { vnode, parentComponent } = suspense;\n let el = branch.el;\n while (!el && branch.component) {\n branch = branch.component.subTree;\n el = branch.el;\n }\n vnode.el = el;\n if (parentComponent && parentComponent.subTree === vnode) {\n parentComponent.vnode.el = el;\n updateHOCHostEl(parentComponent, el);\n }\n}\nfunction isVNodeSuspensible(vnode) {\n const suspensible = vnode.props && vnode.props.suspensible;\n return suspensible != null && suspensible !== false;\n}\n\nconst Fragment = Symbol.for(\"v-fgt\");\nconst Text = Symbol.for(\"v-txt\");\nconst Comment = Symbol.for(\"v-cmt\");\nconst Static = Symbol.for(\"v-stc\");\nconst blockStack = [];\nlet currentBlock = null;\nfunction openBlock(disableTracking = false) {\n blockStack.push(currentBlock = disableTracking ? null : []);\n}\nfunction closeBlock() {\n blockStack.pop();\n currentBlock = blockStack[blockStack.length - 1] || null;\n}\nlet isBlockTreeEnabled = 1;\nfunction setBlockTracking(value, inVOnce = false) {\n isBlockTreeEnabled += value;\n if (value < 0 && currentBlock && inVOnce) {\n currentBlock.hasOnce = true;\n }\n}\nfunction setupBlock(vnode) {\n vnode.dynamicChildren = isBlockTreeEnabled > 0 ? currentBlock || EMPTY_ARR : null;\n closeBlock();\n if (isBlockTreeEnabled > 0 && currentBlock) {\n currentBlock.push(vnode);\n }\n return vnode;\n}\nfunction createElementBlock(type, props, children, patchFlag, dynamicProps, shapeFlag) {\n return setupBlock(\n createBaseVNode(\n type,\n props,\n children,\n patchFlag,\n dynamicProps,\n shapeFlag,\n true\n )\n );\n}\nfunction createBlock(type, props, children, patchFlag, dynamicProps) {\n return setupBlock(\n createVNode(\n type,\n props,\n children,\n patchFlag,\n dynamicProps,\n true\n )\n );\n}\nfunction isVNode(value) {\n return value ? value.__v_isVNode === true : false;\n}\nfunction isSameVNodeType(n1, n2) {\n if (!!(process.env.NODE_ENV !== \"production\") && n2.shapeFlag & 6 && n1.component) {\n const dirtyInstances = hmrDirtyComponents.get(n2.type);\n if (dirtyInstances && dirtyInstances.has(n1.component)) {\n n1.shapeFlag &= -257;\n n2.shapeFlag &= -513;\n return false;\n }\n }\n return n1.type === n2.type && n1.key === n2.key;\n}\nlet vnodeArgsTransformer;\nfunction transformVNodeArgs(transformer) {\n vnodeArgsTransformer = transformer;\n}\nconst createVNodeWithArgsTransform = (...args) => {\n return _createVNode(\n ...vnodeArgsTransformer ? vnodeArgsTransformer(args, currentRenderingInstance) : args\n );\n};\nconst normalizeKey = ({ key }) => key != null ? key : null;\nconst normalizeRef = ({\n ref,\n ref_key,\n ref_for\n}) => {\n if (typeof ref === \"number\") {\n ref = \"\" + ref;\n }\n return ref != null ? isString(ref) || isRef(ref) || isFunction(ref) ? { i: currentRenderingInstance, r: ref, k: ref_key, f: !!ref_for } : ref : null;\n};\nfunction createBaseVNode(type, props = null, children = null, patchFlag = 0, dynamicProps = null, shapeFlag = type === Fragment ? 0 : 1, isBlockNode = false, needFullChildrenNormalization = false) {\n const vnode = {\n __v_isVNode: true,\n __v_skip: true,\n type,\n props,\n key: props && normalizeKey(props),\n ref: props && normalizeRef(props),\n scopeId: currentScopeId,\n slotScopeIds: null,\n children,\n component: null,\n suspense: null,\n ssContent: null,\n ssFallback: null,\n dirs: null,\n transition: null,\n el: null,\n anchor: null,\n target: null,\n targetStart: null,\n targetAnchor: null,\n staticCount: 0,\n shapeFlag,\n patchFlag,\n dynamicProps,\n dynamicChildren: null,\n appContext: null,\n ctx: currentRenderingInstance\n };\n if (needFullChildrenNormalization) {\n normalizeChildren(vnode, children);\n if (shapeFlag & 128) {\n type.normalize(vnode);\n }\n } else if (children) {\n vnode.shapeFlag |= isString(children) ? 8 : 16;\n }\n if (!!(process.env.NODE_ENV !== \"production\") && vnode.key !== vnode.key) {\n warn$1(`VNode created with invalid key (NaN). VNode type:`, vnode.type);\n }\n if (isBlockTreeEnabled > 0 && // avoid a block node from tracking itself\n !isBlockNode && // has current parent block\n currentBlock && // presence of a patch flag indicates this node needs patching on updates.\n // component nodes also should always be patched, because even if the\n // component doesn't need to update, it needs to persist the instance on to\n // the next vnode so that it can be properly unmounted later.\n (vnode.patchFlag > 0 || shapeFlag & 6) && // the EVENTS flag is only for hydration and if it is the only flag, the\n // vnode should not be considered dynamic due to handler caching.\n vnode.patchFlag !== 32) {\n currentBlock.push(vnode);\n }\n return vnode;\n}\nconst createVNode = !!(process.env.NODE_ENV !== \"production\") ? createVNodeWithArgsTransform : _createVNode;\nfunction _createVNode(type, props = null, children = null, patchFlag = 0, dynamicProps = null, isBlockNode = false) {\n if (!type || type === NULL_DYNAMIC_COMPONENT) {\n if (!!(process.env.NODE_ENV !== \"production\") && !type) {\n warn$1(`Invalid vnode type when creating vnode: ${type}.`);\n }\n type = Comment;\n }\n if (isVNode(type)) {\n const cloned = cloneVNode(\n type,\n props,\n true\n /* mergeRef: true */\n );\n if (children) {\n normalizeChildren(cloned, children);\n }\n if (isBlockTreeEnabled > 0 && !isBlockNode && currentBlock) {\n if (cloned.shapeFlag & 6) {\n currentBlock[currentBlock.indexOf(type)] = cloned;\n } else {\n currentBlock.push(cloned);\n }\n }\n cloned.patchFlag = -2;\n return cloned;\n }\n if (isClassComponent(type)) {\n type = type.__vccOpts;\n }\n if (props) {\n props = guardReactiveProps(props);\n let { class: klass, style } = props;\n if (klass && !isString(klass)) {\n props.class = normalizeClass(klass);\n }\n if (isObject(style)) {\n if (isProxy(style) && !isArray(style)) {\n style = extend({}, style);\n }\n props.style = normalizeStyle(style);\n }\n }\n const shapeFlag = isString(type) ? 1 : isSuspense(type) ? 128 : isTeleport(type) ? 64 : isObject(type) ? 4 : isFunction(type) ? 2 : 0;\n if (!!(process.env.NODE_ENV !== \"production\") && shapeFlag & 4 && isProxy(type)) {\n type = toRaw(type);\n warn$1(\n `Vue received a Component that was made a reactive object. This can lead to unnecessary performance overhead and should be avoided by marking the component with \\`markRaw\\` or using \\`shallowRef\\` instead of \\`ref\\`.`,\n `\nComponent that was made reactive: `,\n type\n );\n }\n return createBaseVNode(\n type,\n props,\n children,\n patchFlag,\n dynamicProps,\n shapeFlag,\n isBlockNode,\n true\n );\n}\nfunction guardReactiveProps(props) {\n if (!props) return null;\n return isProxy(props) || isInternalObject(props) ? extend({}, props) : props;\n}\nfunction cloneVNode(vnode, extraProps, mergeRef = false, cloneTransition = false) {\n const { props, ref, patchFlag, children, transition } = vnode;\n const mergedProps = extraProps ? mergeProps(props || {}, extraProps) : props;\n const cloned = {\n __v_isVNode: true,\n __v_skip: true,\n type: vnode.type,\n props: mergedProps,\n key: mergedProps && normalizeKey(mergedProps),\n ref: extraProps && extraProps.ref ? (\n // #2078 in the case of <component :is=\"vnode\" ref=\"extra\"/>\n // if the vnode itself already has a ref, cloneVNode will need to merge\n // the refs so the single vnode can be set on multiple refs\n mergeRef && ref ? isArray(ref) ? ref.concat(normalizeRef(extraProps)) : [ref, normalizeRef(extraProps)] : normalizeRef(extraProps)\n ) : ref,\n scopeId: vnode.scopeId,\n slotScopeIds: vnode.slotScopeIds,\n children: !!(process.env.NODE_ENV !== \"production\") && patchFlag === -1 && isArray(children) ? children.map(deepCloneVNode) : children,\n target: vnode.target,\n targetStart: vnode.targetStart,\n targetAnchor: vnode.targetAnchor,\n staticCount: vnode.staticCount,\n shapeFlag: vnode.shapeFlag,\n // if the vnode is cloned with extra props, we can no longer assume its\n // existing patch flag to be reliable and need to add the FULL_PROPS flag.\n // note: preserve flag for fragments since they use the flag for children\n // fast paths only.\n patchFlag: extraProps && vnode.type !== Fragment ? patchFlag === -1 ? 16 : patchFlag | 16 : patchFlag,\n dynamicProps: vnode.dynamicProps,\n dynamicChildren: vnode.dynamicChildren,\n appContext: vnode.appContext,\n dirs: vnode.dirs,\n transition,\n // These should technically only be non-null on mounted VNodes. However,\n // they *should* be copied for kept-alive vnodes. So we just always copy\n // them since them being non-null during a mount doesn't affect the logic as\n // they will simply be overwritten.\n component: vnode.component,\n suspense: vnode.suspense,\n ssContent: vnode.ssContent && cloneVNode(vnode.ssContent),\n ssFallback: vnode.ssFallback && cloneVNode(vnode.ssFallback),\n placeholder: vnode.placeholder,\n el: vnode.el,\n anchor: vnode.anchor,\n ctx: vnode.ctx,\n ce: vnode.ce\n };\n if (transition && cloneTransition) {\n setTransitionHooks(\n cloned,\n transition.clone(cloned)\n );\n }\n return cloned;\n}\nfunction deepCloneVNode(vnode) {\n const cloned = cloneVNode(vnode);\n if (isArray(vnode.children)) {\n cloned.children = vnode.children.map(deepCloneVNode);\n }\n return cloned;\n}\nfunction createTextVNode(text = \" \", flag = 0) {\n return createVNode(Text, null, text, flag);\n}\nfunction createStaticVNode(content, numberOfNodes) {\n const vnode = createVNode(Static, null, content);\n vnode.staticCount = numberOfNodes;\n return vnode;\n}\nfunction createCommentVNode(text = \"\", asBlock = false) {\n return asBlock ? (openBlock(), createBlock(Comment, null, text)) : createVNode(Comment, null, text);\n}\nfunction normalizeVNode(child) {\n if (child == null || typeof child === \"boolean\") {\n return createVNode(Comment);\n } else if (isArray(child)) {\n return createVNode(\n Fragment,\n null,\n // #3666, avoid reference pollution when reusing vnode\n child.slice()\n );\n } else if (isVNode(child)) {\n return cloneIfMounted(child);\n } else {\n return createVNode(Text, null, String(child));\n }\n}\nfunction cloneIfMounted(child) {\n return child.el === null && child.patchFlag !== -1 || child.memo ? child : cloneVNode(child);\n}\nfunction normalizeChildren(vnode, children) {\n let type = 0;\n const { shapeFlag } = vnode;\n if (children == null) {\n children = null;\n } else if (isArray(children)) {\n type = 16;\n } else if (typeof children === \"object\") {\n if (shapeFlag & (1 | 64)) {\n const slot = children.default;\n if (slot) {\n slot._c && (slot._d = false);\n normalizeChildren(vnode, slot());\n slot._c && (slot._d = true);\n }\n return;\n } else {\n type = 32;\n const slotFlag = children._;\n if (!slotFlag && !isInternalObject(children)) {\n children._ctx = currentRenderingInstance;\n } else if (slotFlag === 3 && currentRenderingInstance) {\n if (currentRenderingInstance.slots._ === 1) {\n children._ = 1;\n } else {\n children._ = 2;\n vnode.patchFlag |= 1024;\n }\n }\n }\n } else if (isFunction(children)) {\n children = { default: children, _ctx: currentRenderingInstance };\n type = 32;\n } else {\n children = String(children);\n if (shapeFlag & 64) {\n type = 16;\n children = [createTextVNode(children)];\n } else {\n type = 8;\n }\n }\n vnode.children = children;\n vnode.shapeFlag |= type;\n}\nfunction mergeProps(...args) {\n const ret = {};\n for (let i = 0; i < args.length; i++) {\n const toMerge = args[i];\n for (const key in toMerge) {\n if (key === \"class\") {\n if (ret.class !== toMerge.class) {\n ret.class = normalizeClass([ret.class, toMerge.class]);\n }\n } else if (key === \"style\") {\n ret.style = normalizeStyle([ret.style, toMerge.style]);\n } else if (isOn(key)) {\n const existing = ret[key];\n const incoming = toMerge[key];\n if (incoming && existing !== incoming && !(isArray(existing) && existing.includes(incoming))) {\n ret[key] = existing ? [].concat(existing, incoming) : incoming;\n }\n } else if (key !== \"\") {\n ret[key] = toMerge[key];\n }\n }\n }\n return ret;\n}\nfunction invokeVNodeHook(hook, instance, vnode, prevVNode = null) {\n callWithAsyncErrorHandling(hook, instance, 7, [\n vnode,\n prevVNode\n ]);\n}\n\nconst emptyAppContext = createAppContext();\nlet uid = 0;\nfunction createComponentInstance(vnode, parent, suspense) {\n const type = vnode.type;\n const appContext = (parent ? parent.appContext : vnode.appContext) || emptyAppContext;\n const instance = {\n uid: uid++,\n vnode,\n type,\n parent,\n appContext,\n root: null,\n // to be immediately set\n next: null,\n subTree: null,\n // will be set synchronously right after creation\n effect: null,\n update: null,\n // will be set synchronously right after creation\n job: null,\n scope: new EffectScope(\n true\n /* detached */\n ),\n render: null,\n proxy: null,\n exposed: null,\n exposeProxy: null,\n withProxy: null,\n provides: parent ? parent.provides : Object.create(appContext.provides),\n ids: parent ? parent.ids : [\"\", 0, 0],\n accessCache: null,\n renderCache: [],\n // local resolved assets\n components: null,\n directives: null,\n // resolved props and emits options\n propsOptions: normalizePropsOptions(type, appContext),\n emitsOptions: normalizeEmitsOptions(type, appContext),\n // emit\n emit: null,\n // to be set immediately\n emitted: null,\n // props default value\n propsDefaults: EMPTY_OBJ,\n // inheritAttrs\n inheritAttrs: type.inheritAttrs,\n // state\n ctx: EMPTY_OBJ,\n data: EMPTY_OBJ,\n props: EMPTY_OBJ,\n attrs: EMPTY_OBJ,\n slots: EMPTY_OBJ,\n refs: EMPTY_OBJ,\n setupState: EMPTY_OBJ,\n setupContext: null,\n // suspense related\n suspense,\n suspenseId: suspense ? suspense.pendingId : 0,\n asyncDep: null,\n asyncResolved: false,\n // lifecycle hooks\n // not using enums here because it results in computed properties\n isMounted: false,\n isUnmounted: false,\n isDeactivated: false,\n bc: null,\n c: null,\n bm: null,\n m: null,\n bu: null,\n u: null,\n um: null,\n bum: null,\n da: null,\n a: null,\n rtg: null,\n rtc: null,\n ec: null,\n sp: null\n };\n if (!!(process.env.NODE_ENV !== \"production\")) {\n instance.ctx = createDevRenderContext(instance);\n } else {\n instance.ctx = { _: instance };\n }\n instance.root = parent ? parent.root : instance;\n instance.emit = emit.bind(null, instance);\n if (vnode.ce) {\n vnode.ce(instance);\n }\n return instance;\n}\nlet currentInstance = null;\nconst getCurrentInstance = () => currentInstance || currentRenderingInstance;\nlet internalSetCurrentInstance;\nlet setInSSRSetupState;\n{\n const g = getGlobalThis();\n const registerGlobalSetter = (key, setter) => {\n let setters;\n if (!(setters = g[key])) setters = g[key] = [];\n setters.push(setter);\n return (v) => {\n if (setters.length > 1) setters.forEach((set) => set(v));\n else setters[0](v);\n };\n };\n internalSetCurrentInstance = registerGlobalSetter(\n `__VUE_INSTANCE_SETTERS__`,\n (v) => currentInstance = v\n );\n setInSSRSetupState = registerGlobalSetter(\n `__VUE_SSR_SETTERS__`,\n (v) => isInSSRComponentSetup = v\n );\n}\nconst setCurrentInstance = (instance) => {\n const prev = currentInstance;\n internalSetCurrentInstance(instance);\n instance.scope.on();\n return () => {\n instance.scope.off();\n internalSetCurrentInstance(prev);\n };\n};\nconst unsetCurrentInstance = () => {\n currentInstance && currentInstance.scope.off();\n internalSetCurrentInstance(null);\n};\nconst isBuiltInTag = /* @__PURE__ */ makeMap(\"slot,component\");\nfunction validateComponentName(name, { isNativeTag }) {\n if (isBuiltInTag(name) || isNativeTag(name)) {\n warn$1(\n \"Do not use built-in or reserved HTML elements as component id: \" + name\n );\n }\n}\nfunction isStatefulComponent(instance) {\n return instance.vnode.shapeFlag & 4;\n}\nlet isInSSRComponentSetup = false;\nfunction setupComponent(instance, isSSR = false, optimized = false) {\n isSSR && setInSSRSetupState(isSSR);\n const { props, children } = instance.vnode;\n const isStateful = isStatefulComponent(instance);\n initProps(instance, props, isStateful, isSSR);\n initSlots(instance, children, optimized || isSSR);\n const setupResult = isStateful ? setupStatefulComponent(instance, isSSR) : void 0;\n isSSR && setInSSRSetupState(false);\n return setupResult;\n}\nfunction setupStatefulComponent(instance, isSSR) {\n const Component = instance.type;\n if (!!(process.env.NODE_ENV !== \"production\")) {\n if (Component.name) {\n validateComponentName(Component.name, instance.appContext.config);\n }\n if (Component.components) {\n const names = Object.keys(Component.components);\n for (let i = 0; i < names.length; i++) {\n validateComponentName(names[i], instance.appContext.config);\n }\n }\n if (Component.directives) {\n const names = Object.keys(Component.directives);\n for (let i = 0; i < names.length; i++) {\n validateDirectiveName(names[i]);\n }\n }\n if (Component.compilerOptions && isRuntimeOnly()) {\n warn$1(\n `\"compilerOptions\" is only supported when using a build of Vue that includes the runtime compiler. Since you are using a runtime-only build, the options should be passed via your build tool config instead.`\n );\n }\n }\n instance.accessCache = /* @__PURE__ */ Object.create(null);\n instance.proxy = new Proxy(instance.ctx, PublicInstanceProxyHandlers);\n if (!!(process.env.NODE_ENV !== \"production\")) {\n exposePropsOnRenderContext(instance);\n }\n const { setup } = Component;\n if (setup) {\n pauseTracking();\n const setupContext = instance.setupContext = setup.length > 1 ? createSetupContext(instance) : null;\n const reset = setCurrentInstance(instance);\n const setupResult = callWithErrorHandling(\n setup,\n instance,\n 0,\n [\n !!(process.env.NODE_ENV !== \"production\") ? shallowReadonly(instance.props) : instance.props,\n setupContext\n ]\n );\n const isAsyncSetup = isPromise(setupResult);\n resetTracking();\n reset();\n if ((isAsyncSetup || instance.sp) && !isAsyncWrapper(instance)) {\n markAsyncBoundary(instance);\n }\n if (isAsyncSetup) {\n setupResult.then(unsetCurrentInstance, unsetCurrentInstance);\n if (isSSR) {\n return setupResult.then((resolvedResult) => {\n handleSetupResult(instance, resolvedResult, isSSR);\n }).catch((e) => {\n handleError(e, instance, 0);\n });\n } else {\n instance.asyncDep = setupResult;\n if (!!(process.env.NODE_ENV !== \"production\") && !instance.suspense) {\n const name = formatComponentName(instance, Component);\n warn$1(\n `Component <${name}>: setup function returned a promise, but no <Suspense> boundary was found in the parent component tree. A component with async setup() must be nested in a <Suspense> in order to be rendered.`\n );\n }\n }\n } else {\n handleSetupResult(instance, setupResult, isSSR);\n }\n } else {\n finishComponentSetup(instance, isSSR);\n }\n}\nfunction handleSetupResult(instance, setupResult, isSSR) {\n if (isFunction(setupResult)) {\n if (instance.type.__ssrInlineRender) {\n instance.ssrRender = setupResult;\n } else {\n instance.render = setupResult;\n }\n } else if (isObject(setupResult)) {\n if (!!(process.env.NODE_ENV !== \"production\") && isVNode(setupResult)) {\n warn$1(\n `setup() should not return VNodes directly - return a render function instead.`\n );\n }\n if (!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_DEVTOOLS__) {\n instance.devtoolsRawSetupState = setupResult;\n }\n instance.setupState = proxyRefs(setupResult);\n if (!!(process.env.NODE_ENV !== \"production\")) {\n exposeSetupStateOnRenderContext(instance);\n }\n } else if (!!(process.env.NODE_ENV !== \"production\") && setupResult !== void 0) {\n warn$1(\n `setup() should return an object. Received: ${setupResult === null ? \"null\" : typeof setupResult}`\n );\n }\n finishComponentSetup(instance, isSSR);\n}\nlet compile;\nlet installWithProxy;\nfunction registerRuntimeCompiler(_compile) {\n compile = _compile;\n installWithProxy = (i) => {\n if (i.render._rc) {\n i.withProxy = new Proxy(i.ctx, RuntimeCompiledPublicInstanceProxyHandlers);\n }\n };\n}\nconst isRuntimeOnly = () => !compile;\nfunction finishComponentSetup(instance, isSSR, skipOptions) {\n const Component = instance.type;\n if (!instance.render) {\n if (!isSSR && compile && !Component.render) {\n const template = Component.template || __VUE_OPTIONS_API__ && resolveMergedOptions(instance).template;\n if (template) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n startMeasure(instance, `compile`);\n }\n const { isCustomElement, compilerOptions } = instance.appContext.config;\n const { delimiters, compilerOptions: componentCompilerOptions } = Component;\n const finalCompilerOptions = extend(\n extend(\n {\n isCustomElement,\n delimiters\n },\n compilerOptions\n ),\n componentCompilerOptions\n );\n Component.render = compile(template, finalCompilerOptions);\n if (!!(process.env.NODE_ENV !== \"production\")) {\n endMeasure(instance, `compile`);\n }\n }\n }\n instance.render = Component.render || NOOP;\n if (installWithProxy) {\n installWithProxy(instance);\n }\n }\n if (__VUE_OPTIONS_API__ && true) {\n const reset = setCurrentInstance(instance);\n pauseTracking();\n try {\n applyOptions(instance);\n } finally {\n resetTracking();\n reset();\n }\n }\n if (!!(process.env.NODE_ENV !== \"production\") && !Component.render && instance.render === NOOP && !isSSR) {\n if (!compile && Component.template) {\n warn$1(\n `Component provided template option but runtime compilation is not supported in this build of Vue.` + (` Configure your bundler to alias \"vue\" to \"vue/dist/vue.esm-bundler.js\".` )\n );\n } else {\n warn$1(`Component is missing template or render function: `, Component);\n }\n }\n}\nconst attrsProxyHandlers = !!(process.env.NODE_ENV !== \"production\") ? {\n get(target, key) {\n markAttrsAccessed();\n track(target, \"get\", \"\");\n return target[key];\n },\n set() {\n warn$1(`setupContext.attrs is readonly.`);\n return false;\n },\n deleteProperty() {\n warn$1(`setupContext.attrs is readonly.`);\n return false;\n }\n} : {\n get(target, key) {\n track(target, \"get\", \"\");\n return target[key];\n }\n};\nfunction getSlotsProxy(instance) {\n return new Proxy(instance.slots, {\n get(target, key) {\n track(instance, \"get\", \"$slots\");\n return target[key];\n }\n });\n}\nfunction createSetupContext(instance) {\n const expose = (exposed) => {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n if (instance.exposed) {\n warn$1(`expose() should be called only once per setup().`);\n }\n if (exposed != null) {\n let exposedType = typeof exposed;\n if (exposedType === \"object\") {\n if (isArray(exposed)) {\n exposedType = \"array\";\n } else if (isRef(exposed)) {\n exposedType = \"ref\";\n }\n }\n if (exposedType !== \"object\") {\n warn$1(\n `expose() should be passed a plain object, received ${exposedType}.`\n );\n }\n }\n }\n instance.exposed = exposed || {};\n };\n if (!!(process.env.NODE_ENV !== \"production\")) {\n let attrsProxy;\n let slotsProxy;\n return Object.freeze({\n get attrs() {\n return attrsProxy || (attrsProxy = new Proxy(instance.attrs, attrsProxyHandlers));\n },\n get slots() {\n return slotsProxy || (slotsProxy = getSlotsProxy(instance));\n },\n get emit() {\n return (event, ...args) => instance.emit(event, ...args);\n },\n expose\n });\n } else {\n return {\n attrs: new Proxy(instance.attrs, attrsProxyHandlers),\n slots: instance.slots,\n emit: instance.emit,\n expose\n };\n }\n}\nfunction getComponentPublicInstance(instance) {\n if (instance.exposed) {\n return instance.exposeProxy || (instance.exposeProxy = new Proxy(proxyRefs(markRaw(instance.exposed)), {\n get(target, key) {\n if (key in target) {\n return target[key];\n } else if (key in publicPropertiesMap) {\n return publicPropertiesMap[key](instance);\n }\n },\n has(target, key) {\n return key in target || key in publicPropertiesMap;\n }\n }));\n } else {\n return instance.proxy;\n }\n}\nconst classifyRE = /(?:^|[-_])\\w/g;\nconst classify = (str) => str.replace(classifyRE, (c) => c.toUpperCase()).replace(/[-_]/g, \"\");\nfunction getComponentName(Component, includeInferred = true) {\n return isFunction(Component) ? Component.displayName || Component.name : Component.name || includeInferred && Component.__name;\n}\nfunction formatComponentName(instance, Component, isRoot = false) {\n let name = getComponentName(Component);\n if (!name && Component.__file) {\n const match = Component.__file.match(/([^/\\\\]+)\\.\\w+$/);\n if (match) {\n name = match[1];\n }\n }\n if (!name && instance) {\n const inferFromRegistry = (registry) => {\n for (const key in registry) {\n if (registry[key] === Component) {\n return key;\n }\n }\n };\n name = inferFromRegistry(instance.components) || instance.parent && inferFromRegistry(\n instance.parent.type.components\n ) || inferFromRegistry(instance.appContext.components);\n }\n return name ? classify(name) : isRoot ? `App` : `Anonymous`;\n}\nfunction isClassComponent(value) {\n return isFunction(value) && \"__vccOpts\" in value;\n}\n\nconst computed = (getterOrOptions, debugOptions) => {\n const c = computed$1(getterOrOptions, debugOptions, isInSSRComponentSetup);\n if (!!(process.env.NODE_ENV !== \"production\")) {\n const i = getCurrentInstance();\n if (i && i.appContext.config.warnRecursiveComputed) {\n c._warnRecursive = true;\n }\n }\n return c;\n};\n\nfunction h(type, propsOrChildren, children) {\n try {\n setBlockTracking(-1);\n const l = arguments.length;\n if (l === 2) {\n if (isObject(propsOrChildren) && !isArray(propsOrChildren)) {\n if (isVNode(propsOrChildren)) {\n return createVNode(type, null, [propsOrChildren]);\n }\n return createVNode(type, propsOrChildren);\n } else {\n return createVNode(type, null, propsOrChildren);\n }\n } else {\n if (l > 3) {\n children = Array.prototype.slice.call(arguments, 2);\n } else if (l === 3 && isVNode(children)) {\n children = [children];\n }\n return createVNode(type, propsOrChildren, children);\n }\n } finally {\n setBlockTracking(1);\n }\n}\n\nfunction initCustomFormatter() {\n if (!!!(process.env.NODE_ENV !== \"production\") || typeof window === \"undefined\") {\n return;\n }\n const vueStyle = { style: \"color:#3ba776\" };\n const numberStyle = { style: \"color:#1677ff\" };\n const stringStyle = { style: \"color:#f5222d\" };\n const keywordStyle = { style: \"color:#eb2f96\" };\n const formatter = {\n __vue_custom_formatter: true,\n header(obj) {\n if (!isObject(obj)) {\n return null;\n }\n if (obj.__isVue) {\n return [\"div\", vueStyle, `VueInstance`];\n } else if (isRef(obj)) {\n pauseTracking();\n const value = obj.value;\n resetTracking();\n return [\n \"div\",\n {},\n [\"span\", vueStyle, genRefFlag(obj)],\n \"<\",\n formatValue(value),\n `>`\n ];\n } else if (isReactive(obj)) {\n return [\n \"div\",\n {},\n [\"span\", vueStyle, isShallow(obj) ? \"ShallowReactive\" : \"Reactive\"],\n \"<\",\n formatValue(obj),\n `>${isReadonly(obj) ? ` (readonly)` : ``}`\n ];\n } else if (isReadonly(obj)) {\n return [\n \"div\",\n {},\n [\"span\", vueStyle, isShallow(obj) ? \"ShallowReadonly\" : \"Readonly\"],\n \"<\",\n formatValue(obj),\n \">\"\n ];\n }\n return null;\n },\n hasBody(obj) {\n return obj && obj.__isVue;\n },\n body(obj) {\n if (obj && obj.__isVue) {\n return [\n \"div\",\n {},\n ...formatInstance(obj.$)\n ];\n }\n }\n };\n function formatInstance(instance) {\n const blocks = [];\n if (instance.type.props && instance.props) {\n blocks.push(createInstanceBlock(\"props\", toRaw(instance.props)));\n }\n if (instance.setupState !== EMPTY_OBJ) {\n blocks.push(createInstanceBlock(\"setup\", instance.setupState));\n }\n if (instance.data !== EMPTY_OBJ) {\n blocks.push(createInstanceBlock(\"data\", toRaw(instance.data)));\n }\n const computed = extractKeys(instance, \"computed\");\n if (computed) {\n blocks.push(createInstanceBlock(\"computed\", computed));\n }\n const injected = extractKeys(instance, \"inject\");\n if (injected) {\n blocks.push(createInstanceBlock(\"injected\", injected));\n }\n blocks.push([\n \"div\",\n {},\n [\n \"span\",\n {\n style: keywordStyle.style + \";opacity:0.66\"\n },\n \"$ (internal): \"\n ],\n [\"object\", { object: instance }]\n ]);\n return blocks;\n }\n function createInstanceBlock(type, target) {\n target = extend({}, target);\n if (!Object.keys(target).length) {\n return [\"span\", {}];\n }\n return [\n \"div\",\n { style: \"line-height:1.25em;margin-bottom:0.6em\" },\n [\n \"div\",\n {\n style: \"color:#476582\"\n },\n type\n ],\n [\n \"div\",\n {\n style: \"padding-left:1.25em\"\n },\n ...Object.keys(target).map((key) => {\n return [\n \"div\",\n {},\n [\"span\", keywordStyle, key + \": \"],\n formatValue(target[key], false)\n ];\n })\n ]\n ];\n }\n function formatValue(v, asRaw = true) {\n if (typeof v === \"number\") {\n return [\"span\", numberStyle, v];\n } else if (typeof v === \"string\") {\n return [\"span\", stringStyle, JSON.stringify(v)];\n } else if (typeof v === \"boolean\") {\n return [\"span\", keywordStyle, v];\n } else if (isObject(v)) {\n return [\"object\", { object: asRaw ? toRaw(v) : v }];\n } else {\n return [\"span\", stringStyle, String(v)];\n }\n }\n function extractKeys(instance, type) {\n const Comp = instance.type;\n if (isFunction(Comp)) {\n return;\n }\n const extracted = {};\n for (const key in instance.ctx) {\n if (isKeyOfType(Comp, key, type)) {\n extracted[key] = instance.ctx[key];\n }\n }\n return extracted;\n }\n function isKeyOfType(Comp, key, type) {\n const opts = Comp[type];\n if (isArray(opts) && opts.includes(key) || isObject(opts) && key in opts) {\n return true;\n }\n if (Comp.extends && isKeyOfType(Comp.extends, key, type)) {\n return true;\n }\n if (Comp.mixins && Comp.mixins.some((m) => isKeyOfType(m, key, type))) {\n return true;\n }\n }\n function genRefFlag(v) {\n if (isShallow(v)) {\n return `ShallowRef`;\n }\n if (v.effect) {\n return `ComputedRef`;\n }\n return `Ref`;\n }\n if (window.devtoolsFormatters) {\n window.devtoolsFormatters.push(formatter);\n } else {\n window.devtoolsFormatters = [formatter];\n }\n}\n\nfunction withMemo(memo, render, cache, index) {\n const cached = cache[index];\n if (cached && isMemoSame(cached, memo)) {\n return cached;\n }\n const ret = render();\n ret.memo = memo.slice();\n ret.cacheIndex = index;\n return cache[index] = ret;\n}\nfunction isMemoSame(cached, memo) {\n const prev = cached.memo;\n if (prev.length != memo.length) {\n return false;\n }\n for (let i = 0; i < prev.length; i++) {\n if (hasChanged(prev[i], memo[i])) {\n return false;\n }\n }\n if (isBlockTreeEnabled > 0 && currentBlock) {\n currentBlock.push(cached);\n }\n return true;\n}\n\nconst version = \"3.5.25\";\nconst warn = !!(process.env.NODE_ENV !== \"production\") ? warn$1 : NOOP;\nconst ErrorTypeStrings = ErrorTypeStrings$1 ;\nconst devtools = !!(process.env.NODE_ENV !== \"production\") || true ? devtools$1 : void 0;\nconst setDevtoolsHook = !!(process.env.NODE_ENV !== \"production\") || true ? setDevtoolsHook$1 : NOOP;\nconst _ssrUtils = {\n createComponentInstance,\n setupComponent,\n renderComponentRoot,\n setCurrentRenderingInstance,\n isVNode: isVNode,\n normalizeVNode,\n getComponentPublicInstance,\n ensureValidVNode,\n pushWarningContext,\n popWarningContext\n};\nconst ssrUtils = _ssrUtils ;\nconst resolveFilter = null;\nconst compatUtils = null;\nconst DeprecationTypes = null;\n\nexport { BaseTransition, BaseTransitionPropsValidators, Comment, DeprecationTypes, ErrorCodes, ErrorTypeStrings, Fragment, KeepAlive, Static, Suspense, Teleport, Text, assertNumber, callWithAsyncErrorHandling, callWithErrorHandling, cloneVNode, compatUtils, computed, createBlock, createCommentVNode, createElementBlock, createBaseVNode as createElementVNode, createHydrationRenderer, createPropsRestProxy, createRenderer, createSlots, createStaticVNode, createTextVNode, createVNode, defineAsyncComponent, defineComponent, defineEmits, defineExpose, defineModel, defineOptions, defineProps, defineSlots, devtools, getCurrentInstance, getTransitionRawChildren, guardReactiveProps, h, handleError, hasInjectionContext, hydrateOnIdle, hydrateOnInteraction, hydrateOnMediaQuery, hydrateOnVisible, initCustomFormatter, inject, isMemoSame, isRuntimeOnly, isVNode, mergeDefaults, mergeModels, mergeProps, nextTick, onActivated, onBeforeMount, onBeforeUnmount, onBeforeUpdate, onDeactivated, onErrorCaptured, onMounted, onRenderTracked, onRenderTriggered, onServerPrefetch, onUnmounted, onUpdated, openBlock, popScopeId, provide, pushScopeId, queuePostFlushCb, registerRuntimeCompiler, renderList, renderSlot, resolveComponent, resolveDirective, resolveDynamicComponent, resolveFilter, resolveTransitionHooks, setBlockTracking, setDevtoolsHook, setTransitionHooks, ssrContextKey, ssrUtils, toHandlers, transformVNodeArgs, useAttrs, useId, useModel, useSSRContext, useSlots, useTemplateRef, useTransitionState, version, warn, watch, watchEffect, watchPostEffect, watchSyncEffect, withAsyncContext, withCtx, withDefaults, withDirectives, withMemo, withScopeId };\n",
8
- "/**\n* vue v3.5.25\n* (c) 2018-present Yuxi (Evan) You and Vue contributors\n* @license MIT\n**/\nimport { initCustomFormatter, warn } from '@vue/runtime-dom';\nexport * from '@vue/runtime-dom';\n\nfunction initDev() {\n {\n initCustomFormatter();\n }\n}\n\nif (!!(process.env.NODE_ENV !== \"production\")) {\n initDev();\n}\nconst compile = () => {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warn(\n `Runtime compilation is not supported in this build of Vue.` + (` Configure your bundler to alias \"vue\" to \"vue/dist/vue.esm-bundler.js\".` )\n );\n }\n};\n\nexport { compile };\n",
9
- "/**\n * @packageDocumentation\n * Mathematical utilities for 2D and 3D point operations, vector calculations, and transformations.\n *\n * @remarks\n * This package provides essential mathematical operations for canvas applications including:\n * - Vector arithmetic (add, subtract, multiply, divide)\n * - Vector operations (dot product, cross product, magnitude, unit vectors)\n * - Geometric transformations (rotation, axis transformation)\n * - Angle calculations and normalization\n * - Point comparisons and interpolation\n * - Line intersection detection\n *\n * All operations support both 2D and 3D coordinates, with the z-axis being optional.\n *\n * @example\n * Basic vector operations\n * ```typescript\n * import { PointCal, Point } from '@ue-too/math';\n *\n * const a: Point = { x: 1, y: 2 };\n * const b: Point = { x: 3, y: 4 };\n *\n * // Add vectors\n * const sum = PointCal.addVector(a, b); // { x: 4, y: 6 }\n *\n * // Calculate magnitude\n * const mag = PointCal.magnitude(a); // 2.236...\n *\n * // Get unit vector\n * const unit = PointCal.unitVector(a); // { x: 0.447..., y: 0.894... }\n * ```\n *\n * @example\n * Rotation and transformation\n * ```typescript\n * import { PointCal, Point } from '@ue-too/math';\n *\n * const point: Point = { x: 10, y: 0 };\n * const angle = Math.PI / 2; // 90 degrees\n *\n * // Rotate point around origin\n * const rotated = PointCal.rotatePoint(point, angle); // { x: 0, y: 10 }\n *\n * // Rotate around a custom anchor\n * const anchor: Point = { x: 5, y: 5 };\n * const rotatedAroundAnchor = PointCal.transformPointWRTAnchor(point, anchor, angle);\n * ```\n */\n\n/**\n * Represents a 2D or 3D point with optional z-coordinate.\n *\n * @remarks\n * This is a lowercase variant maintained for backward compatibility.\n * Use {@link Point} for new code.\n *\n * @deprecated Use {@link Point} instead for better TypeScript conventions.\n */\nexport type point = {\n /** X-coordinate */\n x: number;\n /** Y-coordinate */\n y: number;\n /** Optional Z-coordinate for 3D operations */\n z?: number;\n}\n\n/**\n * Represents a 2D or 3D point with optional z-coordinate.\n *\n * @remarks\n * When z is undefined, operations treat the point as 2D (z = 0).\n * This type is used throughout the library for all point and vector operations.\n *\n * @example\n * ```typescript\n * // 2D point\n * const p2d: Point = { x: 10, y: 20 };\n *\n * // 3D point\n * const p3d: Point = { x: 10, y: 20, z: 30 };\n * ```\n */\nexport type Point = {\n /** X-coordinate */\n x: number;\n /** Y-coordinate */\n y: number;\n /** Optional Z-coordinate for 3D operations */\n z?: number;\n}\n\n\n/**\n * Utility class for point and vector calculations.\n *\n * @remarks\n * PointCal provides static methods for common 2D and 3D mathematical operations\n * used in canvas applications. All methods handle both 2D and 3D coordinates seamlessly.\n *\n * @example\n * ```typescript\n * import { PointCal, Point } from '@ue-too/math';\n *\n * const v1: Point = { x: 1, y: 2 };\n * const v2: Point = { x: 3, y: 4 };\n *\n * const sum = PointCal.addVector(v1, v2);\n * const dot = PointCal.dotProduct(v1, v2);\n * ```\n */\nexport class PointCal {\n\n /**\n * Adds two vectors together.\n *\n * @param a - First vector\n * @param b - Second vector\n * @returns The sum of vectors a and b\n *\n * @remarks\n * If either vector lacks a z-coordinate, it's treated as 0.\n * The result will include a z-coordinate if either input has one.\n *\n * @example\n * ```typescript\n * const a = { x: 1, y: 2 };\n * const b = { x: 3, y: 4 };\n * const sum = PointCal.addVector(a, b); // { x: 4, y: 6 }\n *\n * // With 3D coordinates\n * const a3d = { x: 1, y: 2, z: 3 };\n * const b3d = { x: 4, y: 5, z: 6 };\n * const sum3d = PointCal.addVector(a3d, b3d); // { x: 5, y: 7, z: 9 }\n * ```\n *\n * @group Vector Arithmetic\n */\n static addVector(a: point, b: point): Point {\n if (a.z == null && b.z == null) return {x: a.x + b.x, y: a.y + b.y};\n if (a.z == null || b.z == null) {\n if (a.z == null) a.z = 0;\n if (b.z == null) b.z = 0;\n }\n return {x: a.x + b.x, y: a.y + b.y, z: a.z + b.z}; \n }\n\n /**\n * Subtracts vector b from vector a.\n *\n * @param a - Vector to subtract from\n * @param b - Vector to subtract\n * @returns The difference (a - b)\n *\n * @remarks\n * If either vector lacks a z-coordinate, it's treated as 0.\n *\n * @example\n * ```typescript\n * const a = { x: 5, y: 7 };\n * const b = { x: 2, y: 3 };\n * const diff = PointCal.subVector(a, b); // { x: 3, y: 4 }\n * ```\n *\n * @group Vector Arithmetic\n */\n static subVector(a: point, b: point): Point {\n if (a.z == null && b.z == null) return {x: a.x - b.x, y: a.y - b.y};\n if (a.z == null || b.z == null) {\n if (a.z == null) a.z = 0;\n if (b.z == null) b.z = 0;\n }\n return {x: a.x - b.x, y: a.y - b.y, z: a.z - b.z};\n }\n\n /**\n * Multiplies a vector by a scalar value.\n *\n * @param a - Vector to multiply\n * @param b - Scalar multiplier\n * @returns The scaled vector\n *\n * @example\n * ```typescript\n * const v = { x: 2, y: 3 };\n * const scaled = PointCal.multiplyVectorByScalar(v, 2.5); // { x: 5, y: 7.5 }\n * ```\n *\n * @group Vector Arithmetic\n */\n static multiplyVectorByScalar(a: point, b: number): Point {\n if (a.z == null) return {x: a.x * b, y: a.y * b};\n return {x: a.x * b, y: a.y * b, z: a.z * b};\n }\n\n /**\n * Divides a vector by a scalar value.\n *\n * @param a - Vector to divide\n * @param b - Scalar divisor\n * @returns The divided vector, or the original vector if b is 0\n *\n * @remarks\n * Division by zero returns the original vector unchanged to prevent NaN values.\n *\n * @example\n * ```typescript\n * const v = { x: 10, y: 20 };\n * const divided = PointCal.divideVectorByScalar(v, 2); // { x: 5, y: 10 }\n * ```\n *\n * @group Vector Arithmetic\n */\n static divideVectorByScalar(a: point, b: number): Point {\n if (b == 0) return {x: a.x, y: a.y};\n if (a.z == null) return {x: a.x / b, y: a.y / b};\n return {x: a.x / b, y: a.y / b, z: a.z / b};\n }\n\n /**\n * Calculates the magnitude (length) of a vector.\n *\n * @param a - Vector to measure\n * @returns The magnitude of the vector\n *\n * @remarks\n * Uses the Euclidean distance formula: √(x² + y² + z²)\n *\n * @example\n * ```typescript\n * const v = { x: 3, y: 4 };\n * const mag = PointCal.magnitude(v); // 5\n *\n * const v3d = { x: 1, y: 2, z: 2 };\n * const mag3d = PointCal.magnitude(v3d); // 3\n * ```\n *\n * @group Vector Operations\n */\n static magnitude(a: point): number {\n if (a.z == null) a.z = 0;\n return Math.sqrt(a.x * a.x + a.y * a.y + a.z * a.z);\n }\n\n /**\n * Converts a vector to its unit vector (normalized to length 1).\n *\n * @param a - Vector to normalize\n * @returns Unit vector in the same direction, or zero vector if magnitude is 0\n *\n * @remarks\n * A unit vector has magnitude 1 and preserves the original direction.\n * Returns {x: 0, y: 0, z: 0} if the input vector has zero magnitude.\n *\n * **Performance note**: This method calls `magnitude()` twice. For better performance\n * when you need both magnitude and unit vector, calculate magnitude once and divide manually.\n *\n * @example\n * ```typescript\n * const v = { x: 3, y: 4 };\n * const unit = PointCal.unitVector(v); // { x: 0.6, y: 0.8 }\n * ```\n *\n * @group Vector Operations\n */\n static unitVector(a: point): Point {\n if (a.z == null) a.z = 0;\n return this.magnitude(a) != 0 ? {x: a.x / this.magnitude(a), y: a.y / this.magnitude(a), z: a.z / this.magnitude(a)} : {x: 0, y: 0, z: 0};\n }\n\n /**\n * Calculates the dot product of two vectors.\n *\n * @param a - First vector\n * @param b - Second vector\n * @returns The dot product (scalar value)\n *\n * @remarks\n * The dot product is: a.x * b.x + a.y * b.y + a.z * b.z\n *\n * **Use cases:**\n * - Determine if vectors are perpendicular (dot = 0)\n * - Calculate angle between vectors: θ = acos(dot / (|a| * |b|))\n * - Project one vector onto another\n *\n * @example\n * ```typescript\n * const a = { x: 1, y: 0 };\n * const b = { x: 0, y: 1 };\n * const dot = PointCal.dotProduct(a, b); // 0 (perpendicular vectors)\n *\n * const c = { x: 2, y: 3 };\n * const d = { x: 4, y: 5 };\n * const dot2 = PointCal.dotProduct(c, d); // 23\n * ```\n *\n * @group Vector Operations\n */\n static dotProduct(a: point, b: point): number {\n if (a.z == null && b.z == null) return a.x * b.x + a.y * b.y;\n if (a.z == null || b.z == null) {\n if (a.z == null) a.z = 0;\n if (b.z == null) b.z = 0;\n }\n return a.x * b.x + a.y * b.y + a.z * b.z;\n }\n\n /**\n * Calculates the cross product of two vectors.\n *\n * @param a - First vector\n * @param b - Second vector\n * @returns The cross product vector perpendicular to both inputs\n *\n * @remarks\n * The cross product is perpendicular to both input vectors, following the right-hand rule.\n * For 2D vectors (z undefined), z is treated as 0.\n *\n * **Properties:**\n * - Result is perpendicular to both input vectors\n * - Magnitude equals area of parallelogram formed by vectors\n * - Direction follows right-hand rule\n *\n * @example\n * ```typescript\n * const a = { x: 1, y: 0, z: 0 };\n * const b = { x: 0, y: 1, z: 0 };\n * const cross = PointCal.crossProduct(a, b); // { x: 0, y: 0, z: 1 }\n * ```\n *\n * @group Vector Operations\n */\n static crossProduct(a: point, b: point): Point {\n if (a.z == null || b.z == null) {\n if (a.z == null) a.z = 0;\n if (b.z == null) b.z = 0;\n }\n return {x: a.y * b.z - a.z * b.y, y: a.z * b.x - a.x * b.z, z: a.x * b.y - a.y * b.x};\n }\n\n /**\n * Calculates the unit vector pointing from point a to point b.\n *\n * @param a - Starting point\n * @param b - Ending point\n * @returns Unit vector in the direction from a to b\n *\n * @remarks\n * Equivalent to calling unitVector(subVector(b, a))\n *\n * @example\n * ```typescript\n * const a = { x: 0, y: 0 };\n * const b = { x: 3, y: 4 };\n * const direction = PointCal.unitVectorFromA2B(a, b); // { x: 0.6, y: 0.8 }\n * ```\n *\n * @group Geometric Calculations\n */\n static unitVectorFromA2B(a: point, b: point): Point {\n return this.unitVector(this.subVector(b, a));\n }\n\n /**\n * Rotates a point around the origin.\n *\n * @param point - Point to rotate\n * @param angle - Rotation angle in radians (counter-clockwise)\n * @returns Rotated point\n *\n * @remarks\n * Rotation is performed around the origin (0, 0).\n * Positive angles rotate counter-clockwise, negative angles rotate clockwise.\n * For rotation around a custom anchor, use {@link transformPointWRTAnchor}.\n *\n * **Performance**: Uses trigonometric functions (sin/cos). For many rotations with\n * the same angle, pre-calculate sin/cos values and apply the transformation manually.\n *\n * @example\n * ```typescript\n * const point = { x: 1, y: 0 };\n * const rotated = PointCal.rotatePoint(point, Math.PI / 2); // { x: 0, y: 1 }\n * ```\n *\n * @group Transformations\n */\n static rotatePoint(point: point, angle: number): Point {\n return {x: point.x * Math.cos(angle) - point.y * Math.sin(angle), y: point.x * Math.sin(angle) + point.y * Math.cos(angle)};\n }\n\n /**\n * Transforms a point's coordinates to a new rotated axis system.\n *\n * @param point - Point in original coordinate system\n * @param angleFromOriginalAxis2DestAxis - Rotation angle from original to destination axis (radians, CCW positive)\n * @returns Point coordinates in the new axis system\n *\n * @remarks\n * This performs an axis rotation transformation, converting coordinates from one\n * reference frame to another rotated by the specified angle.\n *\n * @example\n * ```typescript\n * const point = { x: 10, y: 0 };\n * const angle = Math.PI / 4; // 45 degrees\n * const transformed = PointCal.transform2NewAxis(point, angle);\n * ```\n *\n * @group Transformations\n */\n static transform2NewAxis(point: point, angleFromOriginalAxis2DestAxis: number): Point {\n // angle is the angle from the original axis to the destination axis ccw is positive as always\n return {x: point.x * Math.cos(angleFromOriginalAxis2DestAxis) + point.y * Math.sin(angleFromOriginalAxis2DestAxis), y: -point.x * Math.sin(angleFromOriginalAxis2DestAxis) + point.y * Math.cos(angleFromOriginalAxis2DestAxis)};\n }\n\n /**\n * Calculates the signed angle from vector a to vector b.\n *\n * @param a - First vector (starting direction)\n * @param b - Second vector (ending direction)\n * @returns The signed angle in radians, range: (-π, π]\n *\n * @remarks\n * - Positive angles indicate counter-clockwise rotation from a to b\n * - Negative angles indicate clockwise rotation from a to b\n * - Uses atan2 for proper quadrant handling\n *\n * @example\n * ```typescript\n * const right = { x: 1, y: 0 };\n * const up = { x: 0, y: 1 };\n * const angle = PointCal.angleFromA2B(right, up); // π/2 (90 degrees CCW)\n *\n * const down = { x: 0, y: -1 };\n * const angleDown = PointCal.angleFromA2B(right, down); // -π/2 (90 degrees CW)\n * ```\n *\n * @group Angle Utilities\n */\n static angleFromA2B(a: point, b: point): number {\n return Math.atan2(a.x * b.y - a.y * b.x, a.x * b.x + a.y * b.y);\n }\n\n /**\n * Rotates a point around a custom anchor point.\n *\n * @param point - Point to rotate\n * @param anchor - Anchor point to rotate around\n * @param angle - Rotation angle in radians (counter-clockwise)\n * @returns Rotated point\n *\n * @remarks\n * This is equivalent to:\n * 1. Translate point by -anchor\n * 2. Rotate around origin\n * 3. Translate back by +anchor\n *\n * @example\n * ```typescript\n * const point = { x: 10, y: 5 };\n * const anchor = { x: 5, y: 5 };\n * const angle = Math.PI / 2; // 90 degrees\n * const rotated = PointCal.transformPointWRTAnchor(point, anchor, angle);\n * // Rotates point around anchor (5, 5)\n * ```\n *\n * @group Transformations\n */\n static transformPointWRTAnchor(point: point, anchor: point, angle: number): Point {\n // angle is in radians\n let newPoint = this.rotatePoint(this.subVector(point, anchor), angle);\n return this.addVector(newPoint, anchor);\n }\n\n /**\n * Calculates the Euclidean distance between two points.\n *\n * @param a - First point\n * @param b - Second point\n * @returns The distance between the two points\n *\n * @remarks\n * Equivalent to calculating the magnitude of the vector from a to b.\n *\n * @example\n * ```typescript\n * const a = { x: 0, y: 0 };\n * const b = { x: 3, y: 4 };\n * const distance = PointCal.distanceBetweenPoints(a, b); // 5\n * ```\n *\n * @group Geometric Calculations\n */\n static distanceBetweenPoints(a: point, b: point): number {\n return this.magnitude(this.subVector(a, b));\n }\n\n /**\n * Flips a point's y-coordinate (mirrors across the x-axis).\n *\n * @param point - Point to flip\n * @returns Point with negated y-coordinate\n *\n * @remarks\n * Useful for converting between coordinate systems where the y-axis direction differs.\n * Common when converting between screen coordinates (y-down) and mathematical coordinates (y-up).\n *\n * @example\n * ```typescript\n * const point = { x: 10, y: 20 };\n * const flipped = PointCal.flipYAxis(point); // { x: 10, y: -20 }\n * ```\n *\n * @group Transformations\n */\n static flipYAxis(point: point): Point{\n return {x: point.x, y: -point.y, z: point.z};\n }\n\n /**\n * Performs linear interpolation between two points.\n *\n * @param a - Starting point (t = 0)\n * @param b - Ending point (t = 1)\n * @param t - Interpolation parameter (0 to 1)\n * @returns Interpolated point\n *\n * @remarks\n * - t = 0 returns point a\n * - t = 1 returns point b\n * - t = 0.5 returns the midpoint\n * - Values outside [0, 1] perform extrapolation\n *\n * **Performance**: Suitable for animation loops and real-time interpolation.\n *\n * @example\n * ```typescript\n * const a = { x: 0, y: 0 };\n * const b = { x: 10, y: 20 };\n * const mid = PointCal.linearInterpolation(a, b, 0.5); // { x: 5, y: 10 }\n * const quarter = PointCal.linearInterpolation(a, b, 0.25); // { x: 2.5, y: 5 }\n * ```\n *\n * @group Geometric Calculations\n */\n static linearInterpolation(a: point, b: point, t: number): point{\n if (a.z == null || b.z == null) {\n return {x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t};\n } else {\n return {x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t, z: a.z + (b.z - a.z) * t};\n }\n }\n\n /**\n * Checks if two points are exactly equal.\n *\n * @param a - First point\n * @param b - Second point\n * @returns True if all coordinates are exactly equal\n *\n * @remarks\n * Uses strict equality (===) for comparison.\n * For approximate equality with tolerance, use {@link samePoint} instead.\n * Missing z-coordinates are treated as 0.\n *\n * @example\n * ```typescript\n * const a = { x: 1, y: 2 };\n * const b = { x: 1, y: 2 };\n * PointCal.isEqual(a, b); // true\n *\n * const c = { x: 1.0000001, y: 2 };\n * PointCal.isEqual(a, c); // false (use samePoint for tolerance)\n * ```\n *\n * @group Geometric Calculations\n */\n static isEqual(a: point, b: point): boolean{\n if (a.z == null){\n a.z = 0;\n }\n if (b.z == null){\n b.z = 0;\n }\n return a.x == b.x && a.y == b.y && a.z == b.z;\n }\n\n /**\n * Calculates the intersection point of two line segments.\n *\n * @param startPoint - Start of first line segment\n * @param endPoint - End of first line segment\n * @param startPoint2 - Start of second line segment\n * @param endPoint2 - End of second line segment\n * @returns Object containing intersection status and details\n *\n * @remarks\n * Returns an object with:\n * - `intersects`: Boolean indicating if segments intersect\n * - `intersection`: The intersection point (only if intersects is true)\n * - `offset`: Parameter t where intersection occurs on first segment (0 to 1)\n *\n * The segments must actually cross within their bounds (not just their infinite extensions).\n *\n * **Use cases:**\n * - Collision detection between line segments\n * - Ray casting and visibility checks\n * - Path intersection detection\n *\n * @example\n * ```typescript\n * const line1Start = { x: 0, y: 0 };\n * const line1End = { x: 10, y: 10 };\n * const line2Start = { x: 0, y: 10 };\n * const line2End = { x: 10, y: 0 };\n *\n * const result = PointCal.getLineIntersection(line1Start, line1End, line2Start, line2End);\n * // { intersects: true, intersection: { x: 5, y: 5 }, offset: 0.5 }\n * ```\n *\n * @group Geometric Calculations\n */\n static getLineIntersection(startPoint: Point, endPoint: Point, startPoint2: Point, endPoint2: Point):{\n intersects: boolean,\n intersection?: Point,\n offset?: number\n }{\n const numerator = (endPoint2.x - startPoint2.x) * (startPoint.y - startPoint2.y) - (endPoint2.y - startPoint2.y) * (startPoint.x - startPoint2.x);\n const denominator = (endPoint2.y - startPoint2.y) * (endPoint.x - startPoint.x) - (endPoint2.x - startPoint2.x) * (endPoint.y - startPoint.y);\n \n if (denominator === 0){\n return {intersects: false};\n }\n const t = numerator / denominator;\n if (t >= 0 && t <= 1){\n return {\n intersects: true, \n intersection: PointCal.linearInterpolation(startPoint, endPoint, t),\n offset: t\n }\n } else {\n return {\n intersects: false,\n }\n }\n \n }\n \n}\n\n/**\n * Normalizes an angle to the range [0, 2π).\n *\n * @param angle - Angle in radians (can be any value)\n * @returns Normalized angle between 0 and 2π\n *\n * @remarks\n * This function wraps any angle to the range [0, 2π) by taking the modulo\n * and ensuring the result is positive.\n *\n * @example\n * ```typescript\n * normalizeAngleZero2TwoPI(Math.PI * 3); // π (180 degrees)\n * normalizeAngleZero2TwoPI(-Math.PI / 2); // 3π/2 (270 degrees)\n * normalizeAngleZero2TwoPI(0); // 0\n * ```\n *\n * @category Angle\n */\nexport function normalizeAngleZero2TwoPI(angle: number){\n // reduce the angle \n angle = angle % (Math.PI * 2);\n\n // force it to be the positive remainder, so that 0 <= angle < 2 * Math.PI \n angle = (angle + Math.PI * 2) % (Math.PI * 2); \n return angle;\n}\n\n/**\n * Calculates the smallest angular difference between two angles.\n *\n * @param from - Starting angle in radians\n * @param to - Ending angle in radians\n * @returns The smallest angle span from 'from' to 'to', in range (-π, π]\n *\n * @remarks\n * This function accounts for wrapping around 2π and always returns the shorter path.\n * Positive result means counter-clockwise rotation, negative means clockwise.\n *\n * @example\n * ```typescript\n * // From 0° to 90°\n * angleSpan(0, Math.PI / 2); // π/2 (90 degrees CCW)\n *\n * // From 350° to 10° (shorter to go CCW through 0°)\n * angleSpan(350 * Math.PI / 180, 10 * Math.PI / 180); // ≈ 20 degrees\n *\n * // From 10° to 350° (shorter to go CW through 0°)\n * angleSpan(10 * Math.PI / 180, 350 * Math.PI / 180); // ≈ -20 degrees\n * ```\n *\n * @category Angle\n */\nexport function angleSpan(from: number, to: number): number{\n // in radians\n from = normalizeAngleZero2TwoPI(from);\n to = normalizeAngleZero2TwoPI(to);\n let angleDiff = to - from;\n \n if(angleDiff > Math.PI){\n angleDiff = - (Math.PI * 2 - angleDiff);\n }\n\n if(angleDiff < -Math.PI){\n angleDiff += (Math.PI * 2);\n }\n return angleDiff;\n}\n\n/**\n * Checks if two numbers are approximately equal within a tolerance.\n *\n * @param a - First number\n * @param b - Second number\n * @param precision - Optional tolerance (defaults to 0.000001)\n * @returns True if the absolute difference is within the precision threshold\n *\n * @remarks\n * Useful for floating-point comparisons where exact equality is unreliable.\n *\n * @example\n * ```typescript\n * approximatelyTheSame(1.0, 1.0000001); // true (within default epsilon)\n * approximatelyTheSame(1.0, 1.1); // false\n * approximatelyTheSame(1.0, 1.01, 0.02); // true (within custom precision)\n * ```\n *\n * @category Comparison\n */\nexport function approximatelyTheSame(a: number, b: number, precision?: number): boolean {\n const epsilon = 0.000001\n return Math.abs(a - b) <= (precision || epsilon);\n}\n\n/**\n * Checks if two vectors point in the same direction.\n *\n * @param a - First vector\n * @param b - Second vector\n * @param precision - Tolerance for comparison (defaults to 0.001)\n * @returns True if vectors have the same direction (after normalization)\n *\n * @remarks\n * Normalizes both vectors to unit vectors and compares them.\n * Magnitude does not matter, only direction.\n *\n * @example\n * ```typescript\n * const a = { x: 1, y: 0 };\n * const b = { x: 10, y: 0 }; // Same direction, different magnitude\n * sameDirection(a, b); // true\n *\n * const c = { x: 1, y: 1 };\n * sameDirection(a, c); // false (different direction)\n * ```\n *\n * @category Comparison\n */\nexport function sameDirection(a: Point, b: Point, precision: number = 0.001): boolean{\n const aNormalized = PointCal.unitVector(a);\n const bNormalized = PointCal.unitVector(b);\n return samePoint(aNormalized, bNormalized, precision);\n}\n\n/**\n * Checks if a direction vector is aligned with a tangent vector.\n *\n * @param direction - Direction vector to check\n * @param tangent - Tangent vector reference\n * @returns True if direction aligns with tangent (within 90 degrees)\n *\n * @remarks\n * Returns true if the direction is within 90 degrees of either the tangent\n * or its reverse. Useful for determining if movement is along a path.\n *\n * @example\n * ```typescript\n * const direction = { x: 1, y: 0 };\n * const tangent = { x: 1, y: 0.1 }; // Slightly rotated\n * directionAlignedToTangent(direction, tangent); // true\n *\n * const perpendicular = { x: 0, y: 1 };\n * directionAlignedToTangent(perpendicular, tangent); // false\n * ```\n *\n * @category Comparison\n */\nexport function directionAlignedToTangent(direction: Point, tangent: Point): boolean {\n const directionNormalized = PointCal.unitVector(direction);\n const tangentNormalized = PointCal.unitVector(tangent);\n const reversedTangent = {x: -tangent.x, y: -tangent.y, z: tangent.z};\n const angle = PointCal.angleFromA2B(directionNormalized, tangentNormalized);\n const angle2 = PointCal.angleFromA2B(directionNormalized, reversedTangent);\n return (angle < Math.PI / 2 && angle > -Math.PI / 2) && (angle2 > Math.PI / 2 || angle2 < -Math.PI / 2);\n}\n\n/**\n * Checks if two points are approximately at the same location.\n *\n * @param a - First point\n * @param b - Second point\n * @param precision - Optional tolerance for coordinate comparison\n * @returns True if both x and y coordinates are within precision\n *\n * @remarks\n * Uses {@link approximatelyTheSame} for coordinate comparison.\n * For exact equality, use {@link PointCal.isEqual} instead.\n *\n * @example\n * ```typescript\n * const a = { x: 1.0, y: 2.0 };\n * const b = { x: 1.0000001, y: 2.0000001 };\n * samePoint(a, b); // true (within default precision)\n *\n * const c = { x: 1.1, y: 2.0 };\n * samePoint(a, c); // false\n * ```\n *\n * @category Comparison\n */\nexport function samePoint(a: Point, b: Point, precision?: number): boolean {\n if(approximatelyTheSame(a.x, b.x, precision) && approximatelyTheSame(a.y, b.y, precision)){\n return true;\n }\n return false;\n}\n",
10
- "/**\n * Type definition for an observer callback function.\n *\n * @typeParam T - Tuple type of arguments passed to the observer\n *\n * @remarks\n * Observers are callbacks that get notified when an Observable emits data.\n * The generic type T is a tuple representing the arguments passed to the callback.\n *\n * @example\n * ```typescript\n * // Observer that receives a single string\n * const stringObserver: Observer<[string]> = (message) => {\n * console.log(message);\n * };\n *\n * // Observer that receives multiple arguments\n * const multiObserver: Observer<[number, string, boolean]> = (num, str, flag) => {\n * console.log(num, str, flag);\n * };\n * ```\n *\n * @category Observable Pattern\n */\nexport type Observer<T extends any[]> = (...data: T) => void;\n\n/**\n * Options for subscribing to an Observable.\n *\n * @property signal - Optional AbortSignal for automatic unsubscription\n *\n * @remarks\n * Subscription options allow for automatic cleanup of subscriptions using\n * the AbortController API. When the signal is aborted, the subscription\n * is automatically removed.\n *\n * @example\n * ```typescript\n * const controller = new AbortController();\n *\n * observable.subscribe(\n * (data) => console.log(data),\n * { signal: controller.signal }\n * );\n *\n * // Later, abort to unsubscribe\n * controller.abort();\n * ```\n *\n * @category Observable Pattern\n */\nexport interface SubscriptionOptions {\n signal?: AbortSignal;\n}\n\n/**\n * Interface for the Observable pattern implementation.\n *\n * @typeParam T - Tuple type of data emitted to observers\n *\n * @remarks\n * Observables allow multiple observers to subscribe and receive notifications\n * when data is emitted. This is the pub-sub pattern for event handling.\n *\n * Implementations can be synchronous or asynchronous:\n * - {@link SynchronousObservable}: Notifies observers immediately\n * - {@link AsyncObservable}: Notifies observers via microtasks\n *\n * @category Observable Pattern\n */\nexport interface Observable<T extends any[]> {\n subscribe(observer: Observer<T>, options?: SubscriptionOptions): () => void;\n notify(...data: T): void;\n}\n\n/**\n * Asynchronous Observable implementation that notifies observers via microtasks.\n *\n * @typeParam T - Tuple type of data emitted to observers\n *\n * @remarks\n * This Observable uses `queueMicrotask` to defer observer notifications,\n * ensuring they execute after the current execution context completes but\n * before the next task. This prevents recursive notification issues and\n * allows the notifier to complete before observers run.\n *\n * Use AsyncObservable when:\n * - You want to prevent recursion issues in notifications\n * - Observer execution should not block the notifier\n * - You need guaranteed async behavior\n *\n * @example\n * ```typescript\n * const observable = new AsyncObservable<[string]>();\n *\n * observable.subscribe((message) => {\n * console.log('Observer received:', message);\n * });\n *\n * console.log('Before notify');\n * observable.notify('Hello');\n * console.log('After notify');\n *\n * // Output:\n * // Before notify\n * // After notify\n * // Observer received: Hello\n * ```\n *\n * @category Observable Pattern\n * @see {@link SynchronousObservable} for synchronous notifications\n */\nexport class AsyncObservable<T extends any[]> implements Observable<T> {\n private observers: Observer<T>[] = [];\n\n /**\n * Subscribes an observer to receive notifications.\n *\n * @param observer - The callback function to be notified\n * @param options - Optional subscription options including AbortSignal\n * @returns Unsubscribe function to remove this observer\n *\n * @remarks\n * If an AbortSignal is provided and is already aborted, the observer\n * is not added and the returned unsubscribe function is a no-op.\n */\n subscribe(observer: Observer<T>, options?: SubscriptionOptions): () => void {\n this.observers.push(observer);\n\n // Handle AbortSignal\n if (options?.signal) {\n // If signal is already aborted, don't add the observer\n if (options.signal.aborted) {\n this.observers = this.observers.filter(o => o !== observer);\n return () => {};\n }\n\n // Add abort handler\n const abortHandler = () => {\n this.observers = this.observers.filter(o => o !== observer);\n options.signal?.removeEventListener('abort', abortHandler);\n };\n\n options.signal.addEventListener('abort', abortHandler);\n }\n\n // Return unsubscribe function\n return () => {\n this.observers = this.observers.filter(o => o !== observer);\n };\n }\n\n /**\n * Notifies all observers with the provided data asynchronously.\n *\n * @param data - The data to pass to all observers\n *\n * @remarks\n * Each observer is called via `queueMicrotask`, ensuring async execution.\n * This method returns immediately; observers run later in the event loop.\n */\n notify(...data: T): void {\n this.observers.forEach(observer => queueMicrotask(() => observer(...data)));\n }\n}\n\n/**\n * Synchronous Observable implementation that notifies observers immediately.\n *\n * @typeParam T - Tuple type of data emitted to observers\n *\n * @remarks\n * This Observable calls all observers synchronously and immediately when\n * `notify()` is called. The notify method doesn't return until all observers\n * have executed.\n *\n * Use SynchronousObservable when:\n * - You need immediate, guaranteed execution of observers\n * - Observer execution order matters and must be predictable\n * - You're in a performance-critical path (no async overhead)\n *\n * Caution: Can lead to recursion issues if observers trigger notifications.\n *\n * @example\n * ```typescript\n * const observable = new SynchronousObservable<[string]>();\n *\n * observable.subscribe((message) => {\n * console.log('Observer received:', message);\n * });\n *\n * console.log('Before notify');\n * observable.notify('Hello');\n * console.log('After notify');\n *\n * // Output:\n * // Before notify\n * // Observer received: Hello\n * // After notify\n * ```\n *\n * @category Observable Pattern\n * @see {@link AsyncObservable} for asynchronous notifications\n */\nexport class SynchronousObservable<T extends any[]> implements Observable<T> {\n private observers: Observer<T>[] = [];\n\n /**\n * Subscribes an observer to receive notifications.\n *\n * @param observer - The callback function to be notified\n * @param options - Optional subscription options including AbortSignal\n * @returns Unsubscribe function to remove this observer\n *\n * @remarks\n * If an AbortSignal is provided and is already aborted, the observer\n * is not added and the returned unsubscribe function is a no-op.\n */\n subscribe(observer: Observer<T>, options?: SubscriptionOptions): () => void {\n this.observers.push(observer);\n\n // Handle AbortSignal\n if (options?.signal) {\n // If signal is already aborted, don't add the observer\n if (options.signal.aborted) {\n this.observers = this.observers.filter(o => o !== observer);\n return () => {};\n }\n\n // Add abort handler\n const abortHandler = () => {\n this.observers = this.observers.filter(o => o !== observer);\n options.signal?.removeEventListener('abort', abortHandler);\n };\n\n options.signal.addEventListener('abort', abortHandler);\n }\n\n // Return unsubscribe function\n return () => {\n this.observers = this.observers.filter(o => o !== observer);\n };\n }\n\n /**\n * Notifies all observers with the provided data synchronously.\n *\n * @param data - The data to pass to all observers\n *\n * @remarks\n * Each observer is called immediately in order. This method blocks until\n * all observers have completed execution.\n */\n notify(...data: T): void {\n this.observers.forEach(observer => observer(...data));\n }\n}\n\n// Usage example\n// const observable = new Observable<[string]>();\n\n// Create an AbortController\n// const controller = new AbortController();\n\n// Subscribe with AbortSignal\n// const unsubscribe = observable.subscribe(\n// (data) => console.log('Received:', data),\n// { signal: controller.signal }\n// );\n\n// Example notifications\n// observable.notify('Hello!'); // Observer will receive this\n\n// Abort the subscription\n// controller.abort();\n\n// Observer won't receive this notification\n// observable.notify('World!');\n\n// Alternative way to unsubscribe using the returned function\n// unsubscribe();\n",
11
- "import { Point } from \"@ue-too/math\";\nimport { AsyncObservable, Observable, Observer, SubscriptionOptions } from \"../utils/observable\";\n\n/**\n * Payload for camera pan (position change) events.\n *\n * @property diff - The displacement vector from previous to new position\n *\n * @category Camera\n */\nexport type CameraPanEventPayload = {\n /** Movement delta in world coordinates */\n diff: Point;\n}\n\n/**\n * Payload for camera zoom (scale change) events.\n *\n * @property deltaZoomAmount - Change in zoom level (positive = zoom in, negative = zoom out)\n *\n * @category Camera\n */\nexport type CameraZoomEventPayload = {\n /** Change in zoom level from previous value */\n deltaZoomAmount: number;\n}\n\n/**\n * Payload for camera rotation events.\n *\n * @property deltaRotation - Change in rotation angle in radians\n *\n * @category Camera\n */\nexport type CameraRotateEventPayload = {\n /** Change in rotation from previous value, in radians */\n deltaRotation: number;\n}\n\n/**\n * Mapping of camera event names to their payload types.\n * Used for type-safe event subscription.\n *\n * @category Camera\n */\nexport type CameraEventMap = {\n /** Position change event */\n \"pan\": CameraPanEventPayload,\n /** Zoom level change event */\n \"zoom\": CameraZoomEventPayload,\n /** Rotation change event */\n \"rotate\": CameraRotateEventPayload,\n /** Any camera change event (union of pan, zoom, rotate) */\n \"all\": AllCameraEventPayload,\n}\n\n/**\n * Rotation event with discriminated type field for 'all' event handling.\n * Includes type discriminator and rotation payload.\n *\n * @category Camera\n */\nexport type CameraRotateEvent = {\n /** Event type discriminator */\n type: \"rotate\",\n} & CameraRotateEventPayload;\n\n/**\n * Pan event with discriminated type field for 'all' event handling.\n * Includes type discriminator and pan payload.\n *\n * @category Camera\n */\nexport type CameraPanEvent = {\n /** Event type discriminator */\n type: \"pan\",\n} & CameraPanEventPayload;\n\n/**\n * Zoom event with discriminated type field for 'all' event handling.\n * Includes type discriminator and zoom payload.\n *\n * @category Camera\n */\nexport type CameraZoomEvent = {\n /** Event type discriminator */\n type: \"zoom\",\n} & CameraZoomEventPayload;\n\n/**\n * Snapshot of camera state at the time an event occurs.\n * Passed to all event callbacks alongside the event payload.\n *\n * @category Camera\n */\nexport type CameraState = {\n /** Camera position in world coordinates */\n position: Point;\n /** Current zoom level */\n zoomLevel: number;\n /** Current rotation in radians */\n rotation: number;\n}\n\n/**\n * Union type of all camera event payloads with type discriminators.\n * Used for the 'all' event which fires for any camera change.\n *\n * @category Camera\n */\nexport type AllCameraEventPayload = CameraRotateEvent | CameraPanEvent | CameraZoomEvent;\n\n/**\n * Generic callback function type for camera events.\n *\n * @typeParam K - The event type key from CameraEventMap\n * @param event - The event payload specific to this event type\n * @param cameraState - Current camera state snapshot at the time of the event\n *\n * @category Camera\n */\nexport type Callback<K extends keyof CameraEventMap> = (event: CameraEventMap[K], cameraState: CameraState)=>void;\n\n/**\n * Callback function type specifically for the 'all' camera event.\n * Receives a discriminated union of all camera events.\n *\n * @category Camera\n */\nexport type ConslidateCallback = (payload: AllCameraEventPayload, cameraState: CameraState) => void;\n\n/**\n * Function returned by event subscriptions that unsubscribes the callback when called.\n *\n * @category Camera\n */\nexport type UnSubscribe = () => void;\n\n/**\n * Callback type for pan (position change) events.\n *\n * @category Camera\n */\nexport type PanObserver = Callback<\"pan\">;\n\n/**\n * Callback type for zoom (scale change) events.\n *\n * @category Camera\n */\nexport type ZoomObserver = Callback<\"zoom\">;\n\n/**\n * Callback type for rotation events.\n *\n * @category Camera\n */\nexport type RotateObserver = Callback<\"rotate\">;\n\n/**\n * Callback type for the 'all' event that fires on any camera change.\n *\n * @category Camera\n */\nexport type AllObserver = Callback<\"all\">;\n\n/**\n * Event publisher for camera state changes using the Observable pattern.\n * Manages subscriptions and notifications for pan, zoom, and rotate events.\n *\n * @remarks\n * This class is used internally by {@link DefaultBoardCamera} to implement the event system.\n * You typically don't instantiate this directly unless building custom camera implementations.\n *\n * Each specific event (pan, zoom, rotate) also triggers the 'all' event, allowing\n * listeners to subscribe to any camera change with a single handler.\n *\n * @example\n * ```typescript\n * const publisher = new CameraUpdatePublisher();\n *\n * // Subscribe to pan events\n * publisher.on('pan', (event, state) => {\n * console.log('Camera panned:', event.diff);\n * });\n *\n * // Notify subscribers of a pan event\n * publisher.notifyPan(\n * { diff: { x: 10, y: 20 } },\n * { position: { x: 100, y: 200 }, zoomLevel: 1, rotation: 0 }\n * );\n * ```\n *\n * @category Camera\n * @see {@link DefaultBoardCamera} for the primary consumer of this class\n */\nexport class CameraUpdatePublisher {\n\n private pan: Observable<Parameters<Callback<\"pan\">>>;\n private zoom: Observable<Parameters<Callback<\"zoom\">>>;\n private rotate: Observable<Parameters<Callback<\"rotate\">>>;\n private all: Observable<Parameters<Callback<\"all\">>>;\n\n /**\n * Creates a new camera event publisher with async observables for each event type.\n */\n constructor() {\n this.pan = new AsyncObservable<Parameters<Callback<\"pan\">>>();\n this.zoom = new AsyncObservable<Parameters<Callback<\"zoom\">>>();\n this.rotate = new AsyncObservable<Parameters<Callback<\"rotate\">>>();\n this.all = new AsyncObservable<Parameters<Callback<\"all\">>>();\n }\n\n /**\n * Notifies all pan event subscribers.\n * Also triggers the 'all' event with type discrimination.\n *\n * @param event - Pan event payload containing position delta\n * @param cameraState - Current camera state snapshot\n */\n notifyPan(event: CameraEventMap[\"pan\"], cameraState: CameraState): void {\n this.pan.notify(event, cameraState);\n this.all.notify({type: \"pan\", diff: event.diff}, cameraState);\n }\n\n /**\n * Notifies all zoom event subscribers.\n * Also triggers the 'all' event with type discrimination.\n *\n * @param event - Zoom event payload containing zoom delta\n * @param cameraState - Current camera state snapshot\n */\n notifyZoom(event: CameraEventMap[\"zoom\"], cameraState: CameraState): void {\n this.zoom.notify(event, cameraState);\n this.all.notify({type: \"zoom\", deltaZoomAmount: event.deltaZoomAmount}, cameraState);\n }\n\n /**\n * Notifies all rotation event subscribers.\n * Also triggers the 'all' event with type discrimination.\n *\n * @param event - Rotation event payload containing rotation delta\n * @param cameraState - Current camera state snapshot\n */\n notifyRotate(event: CameraEventMap[\"rotate\"], cameraState: CameraState): void {\n this.rotate.notify(event, cameraState);\n this.all.notify({type: \"rotate\", deltaRotation: event.deltaRotation}, cameraState);\n }\n \n /**\n * Subscribes to camera events with type-safe callbacks and optional AbortController support.\n *\n * @typeParam K - The event type key from CameraEventMap\n * @param eventName - Event type to subscribe to ('pan', 'zoom', 'rotate', or 'all')\n * @param callback - Function called when the event occurs\n * @param options - Optional subscription options including AbortController signal\n * @returns Function that unsubscribes this callback when called\n *\n * @throws Error if an invalid event name is provided\n *\n * @remarks\n * Use the AbortController pattern for managing multiple subscriptions:\n *\n * @example\n * ```typescript\n * // Basic subscription\n * const unsubscribe = publisher.on('pan', (event, state) => {\n * console.log(`Panned by (${event.diff.x}, ${event.diff.y})`);\n * });\n *\n * // Later: unsubscribe\n * unsubscribe();\n *\n * // Using AbortController for batch management\n * const controller = new AbortController();\n * publisher.on('pan', handlePan, { signal: controller.signal });\n * publisher.on('zoom', handleZoom, { signal: controller.signal });\n *\n * // Unsubscribe all at once\n * controller.abort();\n *\n * // Subscribe to all events with type discrimination\n * publisher.on('all', (event, state) => {\n * switch (event.type) {\n * case 'pan':\n * console.log('Pan:', event.diff);\n * break;\n * case 'zoom':\n * console.log('Zoom:', event.deltaZoomAmount);\n * break;\n * case 'rotate':\n * console.log('Rotate:', event.deltaRotation);\n * break;\n * }\n * });\n * ```\n */\n on<K extends keyof CameraEventMap>(eventName: K, callback: (event: CameraEventMap[K], cameraState: CameraState)=>void, options?: SubscriptionOptions): UnSubscribe {\n switch (eventName){\n case \"pan\":\n return this.pan.subscribe(callback as Observer<Parameters<Callback<\"pan\">>>, options);\n case \"zoom\":\n return this.zoom.subscribe(callback as Observer<Parameters<Callback<\"zoom\">>>, options);\n case \"rotate\":\n return this.rotate.subscribe(callback as Observer<Parameters<Callback<\"rotate\">>>, options);\n case \"all\":\n return this.all.subscribe(callback as Observer<Parameters<Callback<\"all\">>>, options);\n default:\n throw new Error(`Invalid event name: ${eventName}`);\n }\n }\n}\n",
12
- "/**\n * 2D affine transformation matrix in standard CSS/Canvas format.\n *\n * Represents a 3x3 matrix in homogeneous coordinates, stored in the compact 6-parameter form:\n * ```\n * | a c e |\n * | b d f |\n * | 0 0 1 |\n * ```\n *\n * @property a - Horizontal scaling / rotation component (m11)\n * @property b - Vertical skewing / rotation component (m12)\n * @property c - Horizontal skewing / rotation component (m21)\n * @property d - Vertical scaling / rotation component (m22)\n * @property e - Horizontal translation (tx)\n * @property f - Vertical translation (ty)\n *\n * @remarks\n * This format is compatible with:\n * - Canvas 2D context: `ctx.setTransform(a, b, c, d, e, f)`\n * - CSS transforms: `matrix(a, b, c, d, e, f)`\n * - SVG transforms: `matrix(a b c d e f)`\n *\n * Common transformation types:\n * - **Translation**: `{a: 1, b: 0, c: 0, d: 1, e: tx, f: ty}`\n * - **Scaling**: `{a: sx, b: 0, c: 0, d: sy, e: 0, f: 0}`\n * - **Rotation**: `{a: cos(θ), b: sin(θ), c: -sin(θ), d: cos(θ), e: 0, f: 0}`\n *\n * @example\n * ```typescript\n * // Identity matrix (no transformation)\n * const identity: TransformationMatrix = {\n * a: 1, b: 0, c: 0, d: 1, e: 0, f: 0\n * };\n *\n * // Translation by (100, 50)\n * const translate: TransformationMatrix = {\n * a: 1, b: 0, c: 0, d: 1, e: 100, f: 50\n * };\n *\n * // 2x scale\n * const scale: TransformationMatrix = {\n * a: 2, b: 0, c: 0, d: 2, e: 0, f: 0\n * };\n *\n * // 45° rotation\n * const rotate: TransformationMatrix = {\n * a: 0.707, b: 0.707, c: -0.707, d: 0.707, e: 0, f: 0\n * };\n * ```\n *\n * @category Camera\n */\nexport type TransformationMatrix = {\n a: number;\n b: number;\n c: number;\n d: number;\n e: number;\n f: number;\n};\n\n/**\n * Decomposes a camera transformation matrix back to camera parameters.\n * Inverse operation of {@link createCameraMatrix}.\n *\n * @param transformMatrix - The combined transformation matrix to decompose\n * @param devicePixelRatio - Device pixel ratio used when creating the matrix\n * @param canvasWidth - Canvas width in CSS pixels\n * @param canvasHeight - Canvas height in CSS pixels\n * @returns Camera parameters: position, zoom, and rotation\n *\n * @remarks\n * This function reverses the transformation chain applied by {@link createCameraMatrix}:\n * 1. Scale by devicePixelRatio\n * 2. Translate to canvas center\n * 3. Rotate by -camera.rotation\n * 4. Scale by zoom level\n * 5. Translate by -camera.position\n *\n * Final matrix: M = Scale(DPR) * Translate(center) * Rotate * Scale(zoom) * Translate(-position)\n *\n * The decomposition extracts:\n * - **Rotation**: From the orientation of the transformation (atan2)\n * - **Zoom**: From the total scale after removing devicePixelRatio\n * - **Position**: By reversing the translation chain\n *\n * @example\n * ```typescript\n * // Create and then decompose a matrix\n * const matrix = createCameraMatrix(\n * { x: 100, y: 200 },\n * 2.0,\n * Math.PI / 4,\n * window.devicePixelRatio,\n * 1920, 1080\n * );\n *\n * const params = decomposeCameraMatrix(\n * matrix,\n * window.devicePixelRatio,\n * 1920, 1080\n * );\n * // params ≈ { position: {x: 100, y: 200}, zoom: 2.0, rotation: π/4 }\n * ```\n *\n * @category Camera\n * @see {@link createCameraMatrix} for the inverse operation\n */\n\nexport function decomposeCameraMatrix(transformMatrix: TransformationMatrix, devicePixelRatio: number, canvasWidth: number, canvasHeight: number) {\n // Extract matrix elements (assuming 2D transformation matrix)\n // [a c tx] [m00 m02 m04]\n // [b d ty] = [m01 m03 m05]\n // [0 0 1 ] [0 0 1 ]\n \n const a = transformMatrix.a; // m00\n const b = transformMatrix.b; // m01 \n const c = transformMatrix.c; // m02\n const d = transformMatrix.d; // m03\n const tx = transformMatrix.e; // m04\n const ty = transformMatrix.f; // m05\n \n // Step 1: Extract rotation\n // The rotation is preserved in the orientation of the transformation\n const rotation = -Math.atan2(b, a); // Negative because we applied -camera.rotation\n \n // Step 2: Extract total scale and zoom\n const totalScale = Math.sqrt(a * a + b * b);\n const zoom = totalScale / devicePixelRatio;\n \n // Step 3: Extract camera position\n // We need to reverse the transformation chain:\n // Final translation = DPR * (center + R * Z * (-camera_position))\n \n // Start with the matrix translation\n let reverse = [tx, ty];\n \n // Remove DPR scaling\n reverse = [reverse[0] / devicePixelRatio, reverse[1] / devicePixelRatio];\n \n // Remove canvas center translation\n reverse = [reverse[0] - canvasWidth/2, reverse[1] - canvasHeight/2];\n \n // Apply inverse rotation (rotate by positive camera rotation)\n const cos_r = Math.cos(rotation); // Note: positive for inverse\n const sin_r = Math.sin(rotation);\n reverse = [\n cos_r * reverse[0] - sin_r * reverse[1],\n sin_r * reverse[0] + cos_r * reverse[1]\n ];\n \n // Apply inverse zoom scaling\n reverse = [reverse[0] / zoom, reverse[1] / zoom];\n \n // Negate to get original camera position (since we applied -camera.position)\n const cameraX = -reverse[0];\n const cameraY = -reverse[1];\n \n return {\n position: { x: cameraX, y: cameraY },\n zoom: zoom,\n rotation: rotation\n };\n}\n\n// Alternative implementation using matrix operations for clarity\nfunction decomposeCameraMatrixVerbose(transformMatrix: TransformationMatrix, devicePixelRatio: number, canvasWidth: number, canvasHeight: number) {\n const a = transformMatrix.a;\n const b = transformMatrix.b;\n const c = transformMatrix.c;\n const d = transformMatrix.d;\n const tx = transformMatrix.e;\n const ty = transformMatrix.f;\n \n console.log('Input matrix:');\n console.log(`[${a.toFixed(3)}, ${c.toFixed(3)}, ${tx.toFixed(3)}]`);\n console.log(`[${b.toFixed(3)}, ${d.toFixed(3)}, ${ty.toFixed(3)}]`);\n console.log('[0.000, 0.000, 1.000]');\n \n // Extract rotation\n const rotation = -Math.atan2(b, a);\n console.log(`\\nExtracted rotation: ${(rotation * 180 / Math.PI).toFixed(2)}°`);\n \n // Extract zoom\n const totalScale = Math.sqrt(a * a + b * b);\n const zoom = totalScale / devicePixelRatio;\n console.log(`Extracted zoom: ${zoom.toFixed(3)}`);\n \n // Extract camera position\n const centerX = canvasWidth / 2;\n const centerY = canvasHeight / 2;\n \n // First remove DPR scaling from the final translation\n const unscaledTx = tx / devicePixelRatio;\n const unscaledTy = ty / devicePixelRatio;\n console.log(`After removing DPR: [${unscaledTx.toFixed(3)}, ${unscaledTy.toFixed(3)}]`);\n \n // Then remove canvas center offset\n const adjustedTx = unscaledTx - centerX;\n const adjustedTy = unscaledTy - centerY;\n console.log(`After removing canvas center: [${adjustedTx.toFixed(3)}, ${adjustedTy.toFixed(3)}]`);\n \n // Reverse rotation\n const cos_r = Math.cos(-rotation);\n const sin_r = Math.sin(-rotation);\n const rotatedBackX = cos_r * adjustedTx + sin_r * adjustedTy;\n const rotatedBackY = -sin_r * adjustedTx + cos_r * adjustedTy;\n console.log(`After inverse rotation: [${rotatedBackX.toFixed(3)}, ${rotatedBackY.toFixed(3)}]`);\n \n // Reverse zoom scaling and negate (because we applied -camera.position)\n const cameraX = -rotatedBackX / zoom;\n const cameraY = -rotatedBackY / zoom;\n console.log(`Final camera position: [${cameraX.toFixed(3)}, ${cameraY.toFixed(3)}]`);\n \n return {\n position: { x: cameraX, y: cameraY },\n zoom: zoom,\n rotation: rotation\n };\n}\n\n/**\n * Creates a camera transformation matrix from camera parameters.\n * This matrix transforms world coordinates to canvas pixel coordinates.\n *\n * @param cameraPos - Camera position in world coordinates\n * @param zoom - Zoom level (1.0 = 100%, 2.0 = 200%, etc.)\n * @param rotation - Camera rotation in radians\n * @param devicePixelRatio - Device pixel ratio (typically window.devicePixelRatio)\n * @param canvasWidth - Canvas width in CSS pixels (not canvas.width!)\n * @param canvasHeight - Canvas height in CSS pixels (not canvas.height!)\n * @returns Transformation matrix for world→canvas conversion\n *\n * @remarks\n * **Important**: canvasWidth and canvasHeight are CSS pixel dimensions,\n * not the internal canvas buffer size (canvas.width/canvas.height).\n * Use element.clientWidth/clientHeight or the CSS dimensions.\n *\n * Transformation order:\n * 1. Scale by devicePixelRatio (for high-DPI displays)\n * 2. Translate to canvas center\n * 3. Rotate by -camera.rotation (negated for correct direction)\n * 4. Scale by zoom\n * 5. Translate by -camera.position (world offset)\n *\n * The resulting matrix can be applied to a canvas context:\n * ```typescript\n * const {a, b, c, d, e, f} = createCameraMatrix(...);\n * ctx.setTransform(a, b, c, d, e, f);\n * // Now draw at world coordinates\n * ```\n *\n * @example\n * ```typescript\n * const matrix = createCameraMatrix(\n * { x: 100, y: 200 }, // camera position\n * 2.0, // 2x zoom\n * Math.PI / 6, // 30° rotation\n * window.devicePixelRatio,\n * canvas.clientWidth, // CSS width, not canvas.width!\n * canvas.clientHeight\n * );\n *\n * ctx.setTransform(matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f);\n * ctx.fillRect(100, 200, 50, 50); // Draws at world coordinates (100, 200)\n * ```\n *\n * @category Camera\n * @see {@link decomposeCameraMatrix} for extracting camera parameters from a matrix\n */\nexport function createCameraMatrix(cameraPos: {x: number, y: number}, zoom: number, rotation: number, devicePixelRatio: number, canvasWidth: number, canvasHeight: number) {\n // Step 1: Scale by device pixel ratio\n let matrix: TransformationMatrix = {\n a: devicePixelRatio,\n b: 0,\n c: 0,\n d: devicePixelRatio,\n e: 0,\n f: 0\n };\n \n // Step 2: Translate to canvas center\n const multipliedMatrix = multiplyMatrix(matrix, {\n a: 1,\n b: 0,\n c: 0,\n d: 1,\n e: canvasWidth/2,\n f: canvasHeight/2\n });\n \n // Step 3: Rotate (negative camera rotation)\n const cos_r = Math.cos(-rotation);\n const sin_r = Math.sin(-rotation);\n const rotatedMatrix = multiplyMatrix(multipliedMatrix, {\n a: cos_r,\n b: sin_r,\n c: -sin_r,\n d: cos_r,\n e: 0,\n f: 0\n });\n \n // Step 4: Scale by zoom\n const zoomedMatrix = multiplyMatrix(rotatedMatrix, {\n a: zoom,\n b: 0,\n c: 0,\n d: zoom,\n e: 0,\n f: 0\n });\n \n // Step 5: Translate by negative camera position\n const translatedMatrix = multiplyMatrix(zoomedMatrix, {\n a: 1,\n b: 0,\n c: 0,\n d: 1,\n e: -cameraPos.x,\n f: -cameraPos.y\n });\n return translatedMatrix;\n}\n\n/**\n * Multiplies two 2D transformation matrices.\n * Order matters: M = m1 × m2 applies m2 first, then m1.\n *\n * @param m1 - First transformation matrix (applied second)\n * @param m2 - Second transformation matrix (applied first)\n * @returns Combined transformation matrix\n *\n * @remarks\n * Matrix multiplication is not commutative: m1 × m2 ≠ m2 × m1\n *\n * The result applies transformations in right-to-left order:\n * - Result = m1 × m2\n * - Applying result to point P: (m1 × m2) × P = m1 × (m2 × P)\n * - m2 is applied first, then m1\n *\n * Common use: Building composite transformations\n * ```typescript\n * // Translate then rotate (rotate happens first!)\n * const translate = { a: 1, b: 0, c: 0, d: 1, e: 100, f: 0 };\n * const rotate = { a: 0, b: 1, c: -1, d: 0, e: 0, f: 0 }; // 90° ccw\n * const combined = multiplyMatrix(translate, rotate);\n * // Points are rotated, then translated\n * ```\n *\n * @example\n * ```typescript\n * // Combine scale and translation\n * const scale2x: TransformationMatrix = {\n * a: 2, b: 0, c: 0, d: 2, e: 0, f: 0\n * };\n * const translate: TransformationMatrix = {\n * a: 1, b: 0, c: 0, d: 1, e: 100, f: 50\n * };\n *\n * // Scale then translate\n * const combined = multiplyMatrix(translate, scale2x);\n * // Points are scaled by 2, then translated by (100, 50)\n *\n * // Chain multiple transformations\n * const m = multiplyMatrix(\n * multiplyMatrix(translate, rotate),\n * scale\n * );\n * // Equivalent to: scale → rotate → translate\n * ```\n *\n * @category Matrix\n */\nexport function multiplyMatrix(m1: TransformationMatrix, m2: TransformationMatrix) {\n const a1 = m1.a;\n const b1 = m1.b;\n const c1 = m1.c;\n const d1 = m1.d;\n const tx1 = m1.e;\n const ty1 = m1.f;\n\n const a2 = m2.a;\n const b2 = m2.b;\n const c2 = m2.c;\n const d2 = m2.d;\n const tx2 = m2.e;\n const ty2 = m2.f;\n\n return {\n a: a1 * a2 + c1 * b2, // a\n b: b1 * a2 + d1 * b2, // b\n c: a1 * c2 + c1 * d2, // c\n d: b1 * c2 + d1 * d2, // d\n e: a1 * tx2 + c1 * ty2 + tx1, // tx\n f: b1 * tx2 + d1 * ty2 + ty1 // ty\n };\n}\n\n/**\n * Decomposes a 2D transformation matrix into Translation, Rotation, and Scale (TRS)\n * \n * @param matrix - The transformation matrix to decompose\n * @returns Object containing translation, rotation (in radians), and scale components\n * \n * @category Matrix\n */\nexport function decomposeTRS(matrix: TransformationMatrix): {\n translation: { x: number; y: number };\n rotation: number;\n scale: { x: number; y: number };\n} {\n const { a, b, c, d, e, f } = matrix;\n \n // Translation is directly available in the matrix\n const translation = { x: e, y: f };\n \n // Extract rotation and scale using QR decomposition\n // For 2D matrices, we can use a simpler approach\n \n // Calculate the determinant to check if the matrix is valid\n const det = a * d - b * c;\n if (Math.abs(det) < 1e-10) {\n // Matrix is singular or nearly singular\n throw new Error('Matrix is singular and cannot be decomposed');\n }\n \n // Extract rotation using atan2\n // The rotation is the angle of the first column vector (a, b)\n const rotation = Math.atan2(b, a);\n \n // Extract scale by normalizing the rotation component\n const cos_r = Math.cos(rotation);\n const sin_r = Math.sin(rotation);\n \n // Remove rotation from the matrix to get pure scaling\n // R^(-1) * M = S\n const scaleX = a * cos_r + b * sin_r;\n const scaleY = c * (-sin_r) + d * cos_r;\n \n // Handle negative scales by adjusting rotation\n let finalRotation = rotation;\n let finalScaleX = scaleX;\n let finalScaleY = scaleY;\n \n if (scaleX < 0) {\n finalScaleX = -scaleX;\n finalRotation += Math.PI;\n }\n if (scaleY < 0) {\n finalScaleY = -scaleY;\n finalRotation += Math.PI;\n }\n \n // Normalize rotation to [-π, π]\n while (finalRotation > Math.PI) finalRotation -= 2 * Math.PI;\n while (finalRotation < -Math.PI) finalRotation += 2 * Math.PI;\n \n return {\n translation,\n rotation: finalRotation,\n scale: { x: finalScaleX, y: finalScaleY }\n };\n}\n\n/**\n * Creates a transformation matrix from Translation, Rotation, and Scale components.\n * Inverse of {@link decomposeTRS}.\n *\n * @param translation - Translation vector (tx, ty)\n * @param rotation - Rotation angle in radians (counter-clockwise)\n * @param scale - Scale vector (sx, sy)\n * @returns Transformation matrix combining TRS\n *\n * @remarks\n * Transformation order: Scale → Rotate → Translate\n *\n * The resulting matrix is in standard form compatible with Canvas/CSS/SVG.\n * Applying this matrix transforms points as:\n * 1. Scale by (sx, sy)\n * 2. Rotate by θ radians\n * 3. Translate by (tx, ty)\n *\n * @example\n * ```typescript\n * // Create a transform that scales 2x, rotates 45°, then moves to (100, 50)\n * const matrix = createTRSMatrix(\n * { x: 100, y: 50 }, // translation\n * Math.PI / 4, // 45° rotation\n * { x: 2, y: 2 } // 2x scale\n * );\n *\n * ctx.setTransform(matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f);\n * // Now drawing happens with scale→rotate→translate applied\n *\n * // Round-trip test\n * const decomposed = decomposeTRS(matrix);\n * // decomposed ≈ { translation: {x:100, y:50}, rotation: π/4, scale: {x:2, y:2} }\n * ```\n *\n * @category Matrix\n * @see {@link decomposeTRS} for extracting TRS from a matrix\n */\nexport function createTRSMatrix(\n translation: { x: number; y: number },\n rotation: number,\n scale: { x: number; y: number }\n): TransformationMatrix {\n const cos_r = Math.cos(rotation);\n const sin_r = Math.sin(rotation);\n \n return {\n a: scale.x * cos_r,\n b: scale.x * sin_r,\n c: -scale.y * sin_r,\n d: scale.y * cos_r,\n e: translation.x,\n f: translation.y\n };\n}\n\n/**\n * Decomposes a matrix using SVD (Singular Value Decomposition) approach\n * This is an alternative method that can handle more complex transformations\n * \n * @param matrix - The transformation matrix to decompose\n * @returns Object containing translation, rotation, and scale components\n * \n * @category Matrix\n */\nexport function decomposeTRSSVD(matrix: TransformationMatrix): {\n translation: { x: number; y: number };\n rotation: number;\n scale: { x: number; y: number };\n} {\n const { a, b, c, d, e, f } = matrix;\n \n // Translation is directly available\n const translation = { x: e, y: f };\n \n // Extract the 2x2 transformation part\n const m11 = a, m12 = c;\n const m21 = b, m22 = d;\n \n // Compute SVD: M = U * S * V^T\n // For 2x2 matrices, we can compute this analytically\n \n // Compute M^T * M = V * S^2 * V^T\n const mtm11 = m11 * m11 + m21 * m21;\n const mtm12 = m11 * m12 + m21 * m22;\n const mtm21 = mtm12;\n const mtm22 = m12 * m12 + m22 * m22;\n \n // Compute eigenvalues of M^T * M\n const trace = mtm11 + mtm22;\n const det = mtm11 * mtm22 - mtm12 * mtm21;\n const discriminant = trace * trace - 4 * det;\n \n if (discriminant < 0) {\n throw new Error('Invalid transformation matrix');\n }\n \n const sqrtDisc = Math.sqrt(discriminant);\n const lambda1 = (trace + sqrtDisc) / 2;\n const lambda2 = (trace - sqrtDisc) / 2;\n \n // Singular values are square roots of eigenvalues\n const s1 = Math.sqrt(Math.max(0, lambda1));\n const s2 = Math.sqrt(Math.max(0, lambda2));\n \n // Scale is the singular values\n const scale = { x: s1, y: s2 };\n \n // Compute rotation from U matrix\n // U = M * V * S^(-1)\n let rotation = 0;\n \n if (s1 > 1e-10) {\n // Compute V matrix (eigenvectors of M^T * M)\n const v11 = mtm12;\n const v12 = lambda1 - mtm11;\n const v21 = lambda2 - mtm22;\n const v22 = mtm21;\n \n // Normalize V\n const vNorm1 = Math.sqrt(v11 * v11 + v21 * v21);\n const vNorm2 = Math.sqrt(v12 * v12 + v22 * v22);\n \n if (vNorm1 > 1e-10 && vNorm2 > 1e-10) {\n const v11n = v11 / vNorm1;\n const v21n = v21 / vNorm1;\n const v12n = v12 / vNorm2;\n const v22n = v22 / vNorm2;\n \n // Compute U = M * V * S^(-1)\n const u11 = (m11 * v11n + m12 * v21n) / s1;\n const u21 = (m21 * v11n + m22 * v21n) / s1;\n \n rotation = Math.atan2(u21, u11);\n }\n }\n \n return {\n translation,\n rotation,\n scale\n };\n}\n\n// Example usage and test\nfunction testDecomposition() {\n // Test parameters\n const originalCamera = {\n position: { x: 100, y: 50 },\n zoom: 2.0,\n rotation: Math.PI / 6 // 30 degrees\n };\n const devicePixelRatio = 1.5;\n const canvasWidth = 800;\n const canvasHeight = 600;\n \n console.log('=== Testing Camera Matrix Decomposition ===');\n console.log('Original camera parameters:');\n console.log(`Position: (${originalCamera.position.x}, ${originalCamera.position.y})`);\n console.log(`Zoom: ${originalCamera.zoom}`);\n console.log(`Rotation: ${(originalCamera.rotation * 180 / Math.PI).toFixed(2)}°`);\n console.log(`Device Pixel Ratio: ${devicePixelRatio}`);\n console.log(`Canvas: ${canvasWidth}x${canvasHeight}`);\n \n // Create transformation matrix\n const matrix = createCameraMatrix(\n originalCamera.position, \n originalCamera.zoom, \n originalCamera.rotation, \n devicePixelRatio, \n canvasWidth, \n canvasHeight\n );\n \n console.log('\\n=== Decomposition Process ===');\n \n // Decompose the matrix\n const decomposed = decomposeCameraMatrixVerbose(\n matrix, \n devicePixelRatio, \n canvasWidth, \n canvasHeight\n );\n \n console.log('\\n=== Results ===');\n console.log('Decomposed camera parameters:');\n console.log(`Position: (${decomposed.position.x.toFixed(3)}, ${decomposed.position.y.toFixed(3)})`);\n console.log(`Zoom: ${decomposed.zoom.toFixed(3)}`);\n console.log(`Rotation: ${(decomposed.rotation * 180 / Math.PI).toFixed(2)}°`);\n \n // Check accuracy\n const posError = Math.sqrt(\n Math.pow(originalCamera.position.x - decomposed.position.x, 2) + \n Math.pow(originalCamera.position.y - decomposed.position.y, 2)\n );\n const zoomError = Math.abs(originalCamera.zoom - decomposed.zoom);\n const rotError = Math.abs(originalCamera.rotation - decomposed.rotation);\n \n console.log('\\n=== Accuracy Check ===');\n console.log(`Position error: ${posError.toFixed(6)}`);\n console.log(`Zoom error: ${zoomError.toFixed(6)}`);\n console.log(`Rotation error: ${rotError.toFixed(6)} radians`);\n}\n\n/**\n * Test function for TRS decomposition\n */\nfunction testTRSDecomposition() {\n console.log('=== Testing TRS Decomposition ===');\n \n // Test case 1: Simple translation\n console.log('\\n--- Test 1: Simple Translation ---');\n const translation = { x: 10, y: 20 };\n const rotation = 0;\n const scale = { x: 1, y: 1 };\n \n const matrix1 = createTRSMatrix(translation, rotation, scale);\n const decomposed1 = decomposeTRS(matrix1);\n \n console.log('Original:', { translation, rotation, scale });\n console.log('Decomposed:', decomposed1);\n \n // Test case 2: Translation + Rotation\n console.log('\\n--- Test 2: Translation + Rotation ---');\n const translation2 = { x: 15, y: 25 };\n const rotation2 = Math.PI / 4; // 45 degrees\n const scale2 = { x: 1, y: 1 };\n \n const matrix2 = createTRSMatrix(translation2, rotation2, scale2);\n const decomposed2 = decomposeTRS(matrix2);\n \n console.log('Original:', { translation: translation2, rotation: rotation2, scale: scale2 });\n console.log('Decomposed:', decomposed2);\n \n // Test case 3: Translation + Rotation + Scale\n console.log('\\n--- Test 3: Translation + Rotation + Scale ---');\n const translation3 = { x: 30, y: 40 };\n const rotation3 = Math.PI / 3; // 60 degrees\n const scale3 = { x: 2, y: 1.5 };\n \n const matrix3 = createTRSMatrix(translation3, rotation3, scale3);\n const decomposed3 = decomposeTRS(matrix3);\n \n console.log('Original:', { translation: translation3, rotation: rotation3, scale: scale3 });\n console.log('Decomposed:', decomposed3);\n \n // Test case 4: Negative scale\n console.log('\\n--- Test 4: Negative Scale ---');\n const translation4 = { x: 50, y: 60 };\n const rotation4 = Math.PI / 6; // 30 degrees\n const scale4 = { x: -1.5, y: 2 };\n \n const matrix4 = createTRSMatrix(translation4, rotation4, scale4);\n const decomposed4 = decomposeTRS(matrix4);\n \n console.log('Original:', { translation: translation4, rotation: rotation4, scale: scale4 });\n console.log('Decomposed:', decomposed4);\n \n // Test case 5: Compare with SVD method\n console.log('\\n--- Test 5: Compare TRS vs SVD ---');\n const decomposed5TRS = decomposeTRS(matrix3);\n const decomposed5SVD = decomposeTRSSVD(matrix3);\n \n console.log('TRS method:', decomposed5TRS);\n console.log('SVD method:', decomposed5SVD);\n \n // Test reconstruction\n console.log('\\n--- Test 6: Matrix Reconstruction ---');\n const reconstructed = createTRSMatrix(\n decomposed3.translation,\n decomposed3.rotation,\n decomposed3.scale\n );\n \n console.log('Original matrix:', matrix3);\n console.log('Reconstructed matrix:', reconstructed);\n \n const matrixError = Math.sqrt(\n Math.pow(matrix3.a - reconstructed.a, 2) +\n Math.pow(matrix3.b - reconstructed.b, 2) +\n Math.pow(matrix3.c - reconstructed.c, 2) +\n Math.pow(matrix3.d - reconstructed.d, 2) +\n Math.pow(matrix3.e - reconstructed.e, 2) +\n Math.pow(matrix3.f - reconstructed.f, 2)\n );\n \n console.log(`Matrix reconstruction error: ${matrixError.toFixed(10)}`);\n}\n\n// Run the test\n// testDecomposition();\n// testTRSDecomposition();\n",
13
- "import { Point, PointCal } from \"@ue-too/math\";\n\n/**\n * Converts a point from canvas space to viewport space.\n *\n * @param pointInCanvas - The point in canvas coordinates to convert\n * @param viewportOriginInCanvasSpace - The viewport's origin position in canvas coordinates (default: {0, 0})\n * @param viewportHasFlippedYAxis - Whether viewport uses inverted y-axis (default: false)\n * @returns The point in viewport coordinates\n *\n * @remarks\n * Canvas and viewport coordinate systems can differ in two ways:\n * 1. Origin position: Viewport origin may not be at canvas top-left (0,0)\n * 2. Y-axis direction: Viewport may use mathematical coordinates (y-up) vs canvas (y-down)\n *\n * The conversion process:\n * 1. Translate: Subtract viewport origin from point (shifts coordinate system)\n * 2. Flip Y (if needed): Negate y-coordinate for mathematical coordinate system\n *\n * Common use case: Converting mouse click positions (canvas space) to positions\n * relative to a centered viewport that uses mathematical coordinates.\n *\n * @example\n * ```typescript\n * // Canvas with centered viewport using mathematical coordinates\n * const canvasPoint = { x: 400, y: 300 }; // Click near center\n * const viewportOrigin = { x: 400, y: 300 }; // Viewport centered in 800x600 canvas\n *\n * // Convert to viewport space with flipped y-axis\n * const viewportPoint = convertFromCanvas2ViewPort(\n * canvasPoint,\n * viewportOrigin,\n * true // viewport has y-up\n * );\n * // Result: { x: 0, y: 0 } (center of viewport)\n * ```\n *\n * @category Coordinate Conversion\n * @see {@link convertFromViewPort2Canvas} for inverse conversion\n */\nexport function convertFromCanvas2ViewPort(pointInCanvas: Point, viewportOriginInCanvasSpace: Point = {x: 0, y: 0}, viewportHasFlippedYAxis: boolean = false): Point {\n const res = PointCal.subVector(pointInCanvas, viewportOriginInCanvasSpace);\n if(viewportHasFlippedYAxis){\n res.y = -res.y;\n }\n return res;\n}\n\n/**\n * Converts a point from viewport space to canvas space.\n *\n * @param pointInViewPort - The point in viewport coordinates to convert\n * @param viewportOriginInCanvasSpace - The viewport's origin position in canvas coordinates (default: {0, 0})\n * @param viewportHasFlippedYAxis - Whether viewport uses inverted y-axis (default: false)\n * @returns The point in canvas coordinates\n *\n * @remarks\n * This is the inverse of {@link convertFromCanvas2ViewPort}. It transforms points\n * from viewport-relative coordinates back to absolute canvas coordinates.\n *\n * The conversion process:\n * 1. Flip Y (if needed): Negate y-coordinate to convert from mathematical to canvas system\n * 2. Translate: Add viewport origin to convert from relative to absolute position\n *\n * This is essential for rendering viewport-space objects (like shapes drawn by user)\n * onto the actual canvas element.\n *\n * @example\n * ```typescript\n * // Viewport space point (centered viewport with y-up)\n * const viewportPoint = { x: 100, y: 50 }; // 100 right, 50 up from viewport center\n * const viewportOrigin = { x: 400, y: 300 }; // Viewport centered in canvas\n *\n * // Convert to canvas coordinates\n * const canvasPoint = convertFromViewPort2Canvas(\n * viewportPoint,\n * viewportOrigin,\n * true // viewport has y-up\n * );\n * // Result: { x: 500, y: 250 }\n * // (400 + 100 = 500 in x, 300 - 50 = 250 in y due to flip)\n * ```\n *\n * @category Coordinate Conversion\n * @see {@link convertFromCanvas2ViewPort} for inverse conversion\n */\nexport function convertFromViewPort2Canvas(pointInViewPort: Point, viewportOriginInCanvasSpace: Point = {x: 0, y: 0},viewportHasFlippedYAxis: boolean = false): Point {\n if(viewportHasFlippedYAxis){\n pointInViewPort.y = -pointInViewPort.y;\n }\n return PointCal.addVector(pointInViewPort, viewportOriginInCanvasSpace);\n}\n",
14
- "import { Point, PointCal } from \"@ue-too/math\";\n\n/**\n * Converts a point from viewport space to world space.\n *\n * @param pointInViewport - The point in viewport coordinates to convert\n * @param cameraPositionInWorldSpace - The camera's center position in world coordinates\n * @param cameraZoomLevel - The camera's zoom level (1.0 = normal, >1 = zoomed in, <1 = zoomed out)\n * @param cameraRotation - The camera's rotation angle in radians\n * @param worldHasFlippedYAxis - Whether world space uses inverted y-axis (default: false)\n * @returns The point in world coordinates\n *\n * @remarks\n * This function applies the inverse of the camera transformation to convert from\n * viewport coordinates to world coordinates. It's essential for translating user\n * interactions (clicks, drags) into world-space positions.\n *\n * The transformation applies these operations in reverse order:\n * 1. Unzoom: Divide by zoom level (world units per viewport pixel)\n * 2. Unrotate: Rotate by positive camera rotation (reverse the camera's rotation)\n * 3. Flip Y (if needed): Negate y if world uses mathematical coordinates\n * 4. Translate: Add camera position to get absolute world position\n *\n * Mathematical formula:\n * ```\n * worldPoint = rotate(pointInViewport / zoom, cameraRotation) + cameraPosition\n * ```\n *\n * @example\n * ```typescript\n * // Click at viewport center with zoomed and rotated camera\n * const viewportPoint = { x: 0, y: 0 }; // Center of viewport\n * const cameraPos = { x: 1000, y: 500 };\n * const zoom = 2.0; // Zoomed in 2x\n * const rotation = Math.PI / 4; // 45 degrees\n *\n * const worldPoint = convertFromViewport2World(\n * viewportPoint,\n * cameraPos,\n * zoom,\n * rotation,\n * false\n * );\n * // Result: { x: 1000, y: 500 } (camera position, since viewport center maps to camera position)\n * ```\n *\n * @category Coordinate Conversion\n * @see {@link convertFromWorld2Viewport} for inverse conversion\n */\nexport function convertFromViewport2World(pointInViewport: Point, cameraPositionInWorldSpace: Point, cameraZoomLevel: number, cameraRotation: number, worldHasFlippedYAxis: boolean = false): Point {\n const scaledBack = PointCal.multiplyVectorByScalar(pointInViewport, 1 / cameraZoomLevel);\n const rotatedBack = PointCal.rotatePoint(scaledBack, cameraRotation);\n if(worldHasFlippedYAxis){\n rotatedBack.y = -rotatedBack.y;\n }\n const withOffset = PointCal.addVector(rotatedBack, cameraPositionInWorldSpace);\n return withOffset;\n}\n\n/**\n * Converts a point from world space to viewport space.\n *\n * @param pointInWorld - The point in world coordinates to convert\n * @param cameraPositionInWorldSpace - The camera's center position in world coordinates\n * @param cameraZoomLevel - The camera's zoom level (1.0 = normal, >1 = zoomed in, <1 = zoomed out)\n * @param cameraRotation - The camera's rotation angle in radians\n * @param worldHasFlippedYAxis - Whether world space uses inverted y-axis (default: false)\n * @returns The point in viewport coordinates\n *\n * @remarks\n * This function applies the camera transformation to convert from world coordinates\n * to viewport coordinates. This is used for rendering world objects onto the viewport.\n *\n * The transformation applies these operations in order:\n * 1. Translate: Subtract camera position (make position relative to camera)\n * 2. Flip Y (if needed): Negate y if world uses mathematical coordinates\n * 3. Zoom: Multiply by zoom level (viewport pixels per world unit)\n * 4. Rotate: Rotate by negative camera rotation (to align with viewport)\n *\n * Mathematical formula:\n * ```\n * viewportPoint = rotate((pointInWorld - cameraPosition) * zoom, -cameraRotation)\n * ```\n *\n * The negative rotation ensures that when the camera rotates clockwise, the world\n * appears to rotate counter-clockwise (from the viewer's perspective), which is\n * the expected behavior.\n *\n * @example\n * ```typescript\n * // World object at (1100, 550) with camera at (1000, 500)\n * const worldPoint = { x: 1100, y: 550 };\n * const cameraPos = { x: 1000, y: 500 };\n * const zoom = 2.0; // Zoomed in 2x\n * const rotation = 0; // No rotation\n *\n * const viewportPoint = convertFromWorld2Viewport(\n * worldPoint,\n * cameraPos,\n * zoom,\n * rotation,\n * false\n * );\n * // Result: { x: 200, y: 100 }\n * // ((1100 - 1000) * 2 = 200, (550 - 500) * 2 = 100)\n * ```\n *\n * @category Coordinate Conversion\n * @see {@link convertFromViewport2World} for inverse conversion\n */\nexport function convertFromWorld2Viewport(pointInWorld: Point, cameraPositionInWorldSpace: Point, cameraZoomLevel: number, cameraRotation: number, worldHasFlippedYAxis: boolean = false): Point {\n const withOffset = PointCal.subVector(pointInWorld, cameraPositionInWorldSpace);\n if(worldHasFlippedYAxis){\n withOffset.y = -withOffset.y;\n }\n const scaled = PointCal.multiplyVectorByScalar(withOffset, cameraZoomLevel);\n const rotated = PointCal.rotatePoint(scaled, -cameraRotation);\n return rotated;\n}\n",
15
- "import { Point, PointCal } from \"@ue-too/math\";\nimport { multiplyMatrix, TransformationMatrix } from \"./matrix\";\nimport { convertFromCanvas2ViewPort, convertFromViewPort2Canvas } from \"../../utils/coordinate-conversions/canvas-viewport\";\nimport { convertFromViewport2World, convertFromWorld2Viewport } from \"../../utils/coordinate-conversions/viewport-world\";\n\n/**\n * Converts a viewport point to world space with respect to a hypothetical camera position.\n * \"WRT\" = \"With Respect To\" - calculates where a viewport point would be in world space\n * if the camera were at the target position.\n *\n * @param targetPosition - Hypothetical camera position in world coordinates\n * @param interestPoint - Point in canvas coordinates (origin at bottom-left)\n * @param viewPortWidth - Viewport width in CSS pixels\n * @param viewPortHeight - Viewport height in CSS pixels\n * @param cameraZoomLevel - Zoom level to apply\n * @param cameraRotation - Rotation to apply in radians\n * @returns World space coordinates of the interest point\n *\n * @remarks\n * This is useful for \"what-if\" calculations, such as:\n * - Predicting where a viewport corner would land if camera moves to a position\n * - Checking if moving to a position would show certain world objects\n *\n * The interest point uses canvas coordinates (bottom-left origin), not viewport coordinates (center origin).\n *\n * @example\n * ```typescript\n * // Where would the top-left viewport corner be in world space\n * // if camera moved to (100, 100)?\n * const worldCorner = convert2WorldSpaceWRT(\n * { x: 100, y: 100 }, // target camera position\n * { x: 0, y: 1080 }, // top-left in canvas coords\n * 1920, 1080, // viewport size\n * 1.0, // zoom\n * 0 // rotation\n * );\n * ```\n *\n * @category Camera\n */\nexport function convert2WorldSpaceWRT(targetPosition: Point, interestPoint: Point, viewPortWidth: number, viewPortHeight: number, cameraZoomLevel: number, cameraRotation: number): Point{\n const interestPointInViewPort = convertFromCanvas2ViewPort(interestPoint, {x: viewPortWidth / 2, y: viewPortHeight / 2}, false);\n return convertFromViewport2World(interestPointInViewPort, targetPosition, cameraZoomLevel, cameraRotation, false);\n}\n\n/**\n * Converts a canvas point to world space using current camera state.\n *\n * @param point - Point in canvas coordinates (origin at bottom-left)\n * @param viewPortWidth - Viewport width in CSS pixels\n * @param viewPortHeight - Viewport height in CSS pixels\n * @param cameraPosition - Current camera position in world coordinates\n * @param cameraZoomLevel - Current camera zoom level\n * @param cameraRotation - Current camera rotation in radians\n * @returns World space coordinates of the point\n *\n * @remarks\n * Input coordinates use canvas space with origin at bottom-left.\n * This is useful when working with canvas element coordinates directly.\n *\n * For points already in viewport space (origin at center), use\n * {@link convert2WorldSpaceAnchorAtCenter} instead.\n *\n * @example\n * ```typescript\n * // Convert bottom-left corner of canvas to world coords\n * const worldPos = convert2WorldSpace(\n * { x: 0, y: 0 },\n * 1920, 1080,\n * { x: 100, y: 200 }, // camera position\n * 1.5, // zoom\n * 0 // rotation\n * );\n * ```\n *\n * @category Camera\n */\nexport function convert2WorldSpace(point: Point, viewPortWidth: number, viewPortHeight: number, cameraPosition: Point, cameraZoomLevel: number, cameraRotation: number): Point{\n const pointInViewPort = convertFromCanvas2ViewPort(point, {x: viewPortWidth / 2, y: viewPortHeight / 2}, false);\n return convertFromViewport2World(pointInViewPort, cameraPosition, cameraZoomLevel, cameraRotation, false);\n}\n\n/**\n * Converts a viewport point (center-anchored) to world space.\n * This is the most commonly used viewport-to-world conversion function.\n *\n * @param point - Point in viewport coordinates (origin at viewport center)\n * @param cameraPosition - Camera position in world coordinates\n * @param cameraZoomLevel - Camera zoom level\n * @param cameraRotation - Camera rotation in radians\n * @returns World space coordinates of the point\n *\n * @remarks\n * Viewport coordinates have the origin at the center of the viewport, with:\n * - Positive x to the right\n * - Positive y upward\n * - Point (0, 0) is the center of the viewport\n *\n * This is the standard coordinate system for camera operations.\n *\n * @example\n * ```typescript\n * // Convert viewport center (0,0) to world space\n * const worldCenter = convert2WorldSpaceAnchorAtCenter(\n * { x: 0, y: 0 },\n * { x: 500, y: 300 }, // camera at world (500, 300)\n * 1.0,\n * 0\n * );\n * // worldCenter will be { x: 500, y: 300 }\n *\n * // Convert point 100 pixels right of center\n * const rightPoint = convert2WorldSpaceAnchorAtCenter(\n * { x: 100, y: 0 },\n * { x: 500, y: 300 },\n * 2.0, // 2x zoom\n * 0\n * );\n * // At 2x zoom, 100 viewport pixels = 50 world units\n * // Result: { x: 550, y: 300 }\n * ```\n *\n * @category Camera\n */\nexport function convert2WorldSpaceAnchorAtCenter(point: Point, cameraPosition: Point, cameraZoomLevel: number, cameraRotation: number): Point{\n return convertFromViewport2World(point, cameraPosition, cameraZoomLevel, cameraRotation, false);\n}\n\n/**\n * Converts a world point to viewport space (center-anchored).\n * Inverse of {@link convert2WorldSpaceAnchorAtCenter}.\n *\n * @param point - Point in world coordinates\n * @param cameraPosition - Camera position in world coordinates\n * @param cameraZoomLevel - Camera zoom level\n * @param cameraRotation - Camera rotation in radians\n * @returns Viewport coordinates (origin at center, in CSS pixels)\n *\n * @remarks\n * Use this to find where a world object appears on screen.\n * Result is in viewport space with origin at center, useful for:\n * - Positioning UI elements over world objects\n * - Checking if objects are on screen\n * - Converting click positions\n *\n * @example\n * ```typescript\n * // Where does world point (600, 300) appear in viewport?\n * const viewportPos = convert2ViewPortSpaceAnchorAtCenter(\n * { x: 600, y: 300 }, // world position\n * { x: 500, y: 300 }, // camera position\n * 1.0,\n * 0\n * );\n * // Result: { x: 100, y: 0 } (100 pixels right of center)\n *\n * // Position a DOM element at this world object\n * element.style.left = `${viewportPos.x + canvas.width/2}px`;\n * element.style.top = `${-viewportPos.y + canvas.height/2}px`;\n * ```\n *\n * @category Camera\n */\nexport function convert2ViewPortSpaceAnchorAtCenter(point: Point, cameraPosition: Point, cameraZoomLevel: number, cameraRotation: number): Point{\n return convertFromWorld2Viewport(point, cameraPosition, cameraZoomLevel, cameraRotation, false);\n}\n\n/**\n * Converts a world point to canvas coordinates (bottom-left origin).\n *\n * @param point - Point in world coordinates\n * @param viewPortWidth - Viewport width in CSS pixels\n * @param viewPortHeight - Viewport height in CSS pixels\n * @param cameraPosition - Camera position in world coordinates\n * @param cameraZoomLevel - Camera zoom level\n * @param cameraRotation - Camera rotation in radians\n * @returns Canvas coordinates (origin at bottom-left, in CSS pixels)\n *\n * @remarks\n * \"Invert\" in the function name refers to inverting the forward transformation\n * (world → viewport → canvas). The result uses canvas coordinates where:\n * - (0, 0) is at the bottom-left corner\n * - x increases to the right\n * - y increases upward\n *\n * @example\n * ```typescript\n * const canvasPos = invertFromWorldSpace(\n * { x: 500, y: 300 }, // world position\n * 1920, 1080,\n * { x: 500, y: 300 }, // camera at same position\n * 1.0,\n * 0\n * );\n * // Result: { x: 960, y: 540 } (center of 1920x1080 canvas)\n * ```\n *\n * @category Camera\n */\nexport function invertFromWorldSpace(point: Point, viewPortWidth: number, viewPortHeight: number, cameraPosition: Point, cameraZoomLevel: number, cameraRotation: number): Point{\n const pointInViewPort = convertFromWorld2Viewport(point, cameraPosition, cameraZoomLevel, cameraRotation, false);\n return convertFromViewPort2Canvas(pointInViewPort, {x: viewPortWidth / 2, y: viewPortHeight / 2}, false);\n}\n\n/**\n * Checks if a world point is currently visible in the viewport.\n *\n * @param point - Point in world coordinates\n * @param viewPortWidth - Viewport width in CSS pixels\n * @param viewPortHeight - Viewport height in CSS pixels\n * @param cameraPosition - Camera position in world coordinates\n * @param cameraZoomLevel - Camera zoom level\n * @param cameraRotation - Camera rotation in radians\n * @returns True if point is visible in viewport, false otherwise\n *\n * @remarks\n * A point is visible if it falls within the rectangular viewport bounds.\n * This uses canvas coordinates for the visibility check (0 to width/height).\n *\n * @example\n * ```typescript\n * const isVisible = pointIsInViewPort(\n * { x: 550, y: 300 }, // world point\n * 1920, 1080,\n * { x: 500, y: 300 }, // camera position\n * 1.0,\n * 0\n * );\n * // Returns true if point is within viewport bounds\n * ```\n *\n * @category Camera\n */\nexport function pointIsInViewPort(point: Point, viewPortWidth: number, viewPortHeight: number, cameraPosition: Point, cameraZoomLevel: number, cameraRotation: number): boolean{\n const pointInCameraFrame = invertFromWorldSpace(point, viewPortWidth, viewPortHeight, cameraPosition, cameraZoomLevel, cameraRotation);\n if(pointInCameraFrame.x < 0 || pointInCameraFrame.x > viewPortWidth || pointInCameraFrame.y < 0 || pointInCameraFrame.y > viewPortHeight){\n return false;\n }\n return true;\n}\n\n/**\n * Converts a displacement vector from viewport space to world space.\n * Use this for converting movement deltas, not absolute positions.\n *\n * @param delta - Displacement vector in viewport space (CSS pixels)\n * @param cameraZoomLevel - Camera zoom level\n * @param cameraRotation - Camera rotation in radians\n * @returns Displacement vector in world coordinates\n *\n * @remarks\n * This transforms a *relative* displacement, not an absolute point.\n * The conversion accounts for:\n * - Rotation: Delta is rotated by camera rotation\n * - Zoom: Delta is scaled by 1/zoom (viewport pixels → world units)\n *\n * Note: Camera position is NOT needed for delta transformations.\n *\n * @example\n * ```typescript\n * // User dragged 100 pixels to the right in viewport\n * const viewportDelta = { x: 100, y: 0 };\n * const worldDelta = convertDeltaInViewPortToWorldSpace(\n * viewportDelta,\n * 2.0, // 2x zoom\n * 0 // no rotation\n * );\n * // Result: { x: 50, y: 0 } (100 viewport pixels = 50 world units at 2x zoom)\n * ```\n *\n * @category Camera\n */\nexport function convertDeltaInViewPortToWorldSpace(delta: Point, cameraZoomLevel: number, cameraRotation: number): Point{\n return PointCal.multiplyVectorByScalar(PointCal.rotatePoint(delta, cameraRotation), 1 / cameraZoomLevel);\n}\n\n/**\n * Converts a displacement vector from world space to viewport space.\n * Use this for converting movement deltas, not absolute positions.\n * Inverse of {@link convertDeltaInViewPortToWorldSpace}.\n *\n * @param delta - Displacement vector in world coordinates\n * @param cameraZoomLevel - Camera zoom level\n * @param cameraRotation - Camera rotation in radians\n * @returns Displacement vector in viewport space (CSS pixels)\n *\n * @remarks\n * This transforms a *relative* displacement, not an absolute point.\n * The conversion accounts for:\n * - Rotation: Delta is rotated by -camera rotation\n * - Zoom: Delta is scaled by zoom (world units → viewport pixels)\n *\n * @example\n * ```typescript\n * // Object moved 50 units right in world space\n * const worldDelta = { x: 50, y: 0 };\n * const viewportDelta = convertDeltaInWorldToViewPortSpace(\n * worldDelta,\n * 2.0, // 2x zoom\n * 0 // no rotation\n * );\n * // Result: { x: 100, y: 0 } (50 world units = 100 viewport pixels at 2x zoom)\n * ```\n *\n * @category Camera\n */\nexport function convertDeltaInWorldToViewPortSpace(delta: Point, cameraZoomLevel: number, cameraRotation: number): Point{\n return PointCal.multiplyVectorByScalar(PointCal.rotatePoint(delta, -cameraRotation), cameraZoomLevel);\n}\n\n/**\n * Calculates the camera position needed to place a world point at a specific viewport location.\n * Useful for implementing \"zoom to point\" or \"focus on object\" features.\n *\n * @param pointInWorld - The world point to focus on\n * @param toPointInViewPort - Where in the viewport this point should appear (origin at center)\n * @param cameraZoomLevel - Target zoom level\n * @param cameraRotation - Target rotation in radians\n * @returns Camera position that achieves the desired framing\n *\n * @remarks\n * This is particularly useful for:\n * - Zoom-to-cursor: Make clicked point stay under cursor while zooming\n * - Pan-and-zoom: Smoothly navigate to show a specific object\n * - Focus features: Center camera on a world object\n *\n * The viewport point is in viewport coordinates (center origin).\n * To center on a world point, use toPointInViewPort = {x: 0, y: 0}.\n *\n * @example\n * ```typescript\n * // Center camera on world point (1000, 500)\n * const newCameraPos = cameraPositionToGet(\n * { x: 1000, y: 500 }, // world point to focus on\n * { x: 0, y: 0 }, // center of viewport\n * 2.0, // zoom level\n * 0 // rotation\n * );\n * camera.setPosition(newCameraPos);\n *\n * // Zoom to cursor position\n * // Keep world point under cursor at (viewportX, viewportY)\n * const cursorViewport = {\n * x: mouseX - canvas.width/2,\n * y: mouseY - canvas.height/2\n * };\n * const worldAtCursor = camera.convertFromViewPort2WorldSpace(cursorViewport);\n * const newPos = cameraPositionToGet(worldAtCursor, cursorViewport, newZoom, rotation);\n * camera.setPosition(newPos);\n * camera.setZoomLevel(newZoom);\n * ```\n *\n * @category Camera\n */\nexport function cameraPositionToGet(pointInWorld: Point, toPointInViewPort: Point, cameraZoomLevel: number, cameraRotation: number): Point {\n const scaled = PointCal.multiplyVectorByScalar(toPointInViewPort, 1 / cameraZoomLevel);\n const rotated = PointCal.rotatePoint(scaled, cameraRotation);\n return PointCal.subVector(pointInWorld, rotated);\n}\n\n/**\n * Creates a transformation matrix from camera parameters.\n * Combines position, zoom, and rotation into a single transform.\n *\n * @param cameraPosition - Camera position in world coordinates\n * @param cameraZoomLevel - Camera zoom level\n * @param cameraRotation - Camera rotation in radians\n * @returns Transformation matrix for viewport-to-world conversion\n *\n * @remarks\n * The resulting matrix can be used with {@link convert2WorldSpaceWithTransformationMatrix}\n * for efficient batch transformations when camera state doesn't change.\n *\n * Matrix composition order: Translation → Rotation → Scale(1/zoom)\n *\n * @category Camera\n */\nexport function transformationMatrixFromCamera(cameraPosition: Point, cameraZoomLevel: number, cameraRotation: number): TransformationMatrix{\n const cos = Math.cos(cameraRotation);\n const sin = Math.sin(cameraRotation);\n const trMatrix = multiplyMatrix({\n a: 1,\n b: 0,\n c: 0,\n d: 1,\n e: cameraPosition.x,\n f: cameraPosition.y\n }, {\n a: cos,\n b: sin,\n c: -sin,\n d: cos,\n e: 0,\n f: 0\n });\n const trsMatrix = multiplyMatrix(trMatrix, {\n a: 1 / cameraZoomLevel,\n b: 0,\n c: 0,\n d: 1 / cameraZoomLevel,\n e: 0,\n f: 0\n });\n return trsMatrix;\n}\n\n/**\n * Transforms a viewport point to world space using a precomputed transformation matrix.\n * Faster than repeated function calls when transforming many points with the same camera state.\n *\n * @param point - Point in viewport coordinates (origin at center)\n * @param transformationMatrix - Precomputed transformation matrix from {@link transformationMatrixFromCamera}\n * @returns World space coordinates of the point\n *\n * @remarks\n * Use this for batch transformations when the camera state is constant:\n * 1. Create matrix once with {@link transformationMatrixFromCamera}\n * 2. Transform many points with this function\n *\n * This avoids recalculating sin/cos and matrix operations for each point.\n *\n * @example\n * ```typescript\n * // Transform many points efficiently\n * const matrix = transformationMatrixFromCamera(\n * { x: 100, y: 200 },\n * 1.5,\n * Math.PI / 4\n * );\n *\n * const worldPoints = viewportPoints.map(vp =>\n * convert2WorldSpaceWithTransformationMatrix(vp, matrix)\n * );\n * ```\n *\n * @category Camera\n * @see {@link transformationMatrixFromCamera} to create the matrix\n */\nexport function convert2WorldSpaceWithTransformationMatrix(point: Point, transformationMatrix: TransformationMatrix): Point{\n return {\n x: point.x * transformationMatrix.a + point.y * transformationMatrix.c + transformationMatrix.e,\n y: point.x * transformationMatrix.b + point.y * transformationMatrix.d + transformationMatrix.f\n }\n}\n",
16
- "import { Point, PointCal } from \"@ue-too/math\";\nimport { convert2WorldSpaceWRT } from \"./coordinate-conversion\";\n\n/**\n * Position boundaries for camera movement in world space.\n * Allows optional constraints on x and y axes independently.\n *\n * @property min - Minimum position constraints (both x and y are optional)\n * @property max - Maximum position constraints (both x and y are optional)\n *\n * @remarks\n * All coordinates are in world space. Each axis (x, y) can be:\n * - Fully constrained: both min and max defined\n * - Partially constrained: only min or max defined\n * - Unconstrained: neither min nor max defined\n *\n * This allows for flexible boundary configurations like:\n * - Horizontal-only boundaries (x constrained, y free)\n * - Vertical-only boundaries (y constrained, x free)\n * - One-sided boundaries (e.g., minimum x but no maximum)\n *\n * @example\n * ```typescript\n * // Fully constrained rectangular boundary\n * const rect: Boundaries = {\n * min: { x: -1000, y: -1000 },\n * max: { x: 1000, y: 1000 }\n * };\n *\n * // Horizontal constraints only\n * const horizontal: Boundaries = {\n * min: { x: -500 },\n * max: { x: 500 }\n * };\n *\n * // One-sided constraint (can't go below y=0)\n * const floor: Boundaries = {\n * min: { y: 0 }\n * };\n * ```\n *\n * @category Camera\n */\nexport type Boundaries = {\n min?: {x?: number, y?: number};\n max?: {x?: number, y?: number};\n}\n\n/**\n * Checks if a point is within the specified boundaries.\n *\n * @param point - Point to check in world coordinates\n * @param boundaries - Optional boundary constraints\n * @returns True if point is within boundaries or no boundaries specified, false otherwise\n *\n * @remarks\n * Returns true if:\n * - No boundaries are defined (undefined)\n * - Point satisfies all defined constraints\n *\n * Each axis is checked independently. A missing constraint on an axis means\n * that axis is unbounded.\n *\n * @example\n * ```typescript\n * const bounds: Boundaries = {\n * min: { x: -100, y: -50 },\n * max: { x: 100, y: 50 }\n * };\n *\n * withinBoundaries({ x: 0, y: 0 }, bounds); // true (inside)\n * withinBoundaries({ x: 150, y: 0 }, bounds); // false (x too large)\n * withinBoundaries({ x: 0, y: -100 }, bounds); // false (y too small)\n * withinBoundaries({ x: 100, y: 50 }, bounds); // true (on boundary)\n * withinBoundaries({ x: 0, y: 0 }, undefined); // true (no bounds)\n * ```\n *\n * @category Camera\n */\nexport function withinBoundaries(point: Point, boundaries: Boundaries | undefined): boolean{\n if(boundaries == undefined){\n // no boundaries \n return true;\n }\n let leftSide = false;\n let rightSide = false;\n let topSide = false;\n let bottomSide = false;\n // check within boundaries horizontally\n if(boundaries.max == undefined || boundaries.max.x == undefined || point.x <= boundaries.max.x){\n rightSide = true;\n }\n if(boundaries.min == undefined || boundaries.min.x == undefined || point.x >= boundaries.min.x){\n leftSide = true;\n }\n if(boundaries.max == undefined || boundaries.max.y == undefined || point.y <= boundaries.max.y){\n topSide = true;\n }\n if(boundaries.min == undefined || boundaries.min.y == undefined || point.y >= boundaries.min.y){\n bottomSide = true;\n }\n return leftSide && rightSide && topSide && bottomSide;\n}\n\n/**\n * Validates that boundaries are logically consistent.\n *\n * @param boundaries - The boundaries to validate\n * @returns True if boundaries are valid or undefined, false if min >= max on any axis\n *\n * @remarks\n * Returns false if:\n * - On any axis, both min and max are defined AND min >= max\n *\n * Returns true if:\n * - Boundaries are undefined\n * - Only min or max is defined on an axis\n * - Both are defined and min < max on all axes\n *\n * @example\n * ```typescript\n * isValidBoundaries({ min: { x: 0, y: 0 }, max: { x: 100, y: 100 } }); // true\n * isValidBoundaries({ min: { x: 100 }, max: { x: 0 } }); // false (min > max)\n * isValidBoundaries({ min: { x: 50, y: 50 }, max: { x: 50, y: 60 } }); // false (x min == max)\n * isValidBoundaries({ min: { x: 0 } }); // true (partial)\n * isValidBoundaries(undefined); // true\n * ```\n *\n * @category Camera\n */\nexport function isValidBoundaries(boundaries: Boundaries | undefined): boolean{\n if(boundaries == undefined){\n return true;\n }\n const minX = boundaries.min?.x;\n const maxX = boundaries.max?.x;\n if (minX != undefined && maxX != undefined && minX >= maxX){\n return false;\n }\n const minY = boundaries.min?.y;\n const maxY = boundaries.max?.y;\n if (minY != undefined && maxY != undefined && minY >= maxY){\n return false;\n }\n return true;\n}\n\n/**\n * Checks if boundaries have all four constraints (min/max for both x and y) defined.\n *\n * @param boundaries - The boundaries to check\n * @returns True if all four constraints are defined, false otherwise\n *\n * @remarks\n * Returns true only if boundaries define a complete rectangular region:\n * - min.x, min.y, max.x, and max.y are all defined\n *\n * @example\n * ```typescript\n * boundariesFullyDefined({\n * min: { x: 0, y: 0 },\n * max: { x: 100, y: 100 }\n * }); // true\n *\n * boundariesFullyDefined({\n * min: { x: 0, y: 0 },\n * max: { x: 100 } // missing max.y\n * }); // false\n *\n * boundariesFullyDefined({ min: { x: 0 } }); // false\n * boundariesFullyDefined(undefined); // false\n * ```\n *\n * @category Camera\n */\nexport function boundariesFullyDefined(boundaries: Boundaries | undefined): boolean{\n if(boundaries == undefined){\n return false;\n }\n if(boundaries.max == undefined || boundaries.min == undefined){\n return false;\n }\n if(boundaries.max.x == undefined || boundaries.max.y == undefined || boundaries.min.x == undefined || boundaries.min.y == undefined){\n return false;\n }\n return true;\n}\n\n/**\n * Clamps a point to stay within specified boundaries.\n *\n * @param point - Point to clamp in world coordinates\n * @param boundaries - Optional boundary constraints\n * @returns Clamped point, or original if already within bounds or no boundaries\n *\n * @remarks\n * Each axis is clamped independently:\n * - If a min constraint exists on an axis, ensures point >= min\n * - If a max constraint exists on an axis, ensures point <= max\n * - If no constraint exists on an axis, that axis is unchanged\n *\n * @example\n * ```typescript\n * const bounds: Boundaries = {\n * min: { x: -100, y: -50 },\n * max: { x: 100, y: 50 }\n * };\n *\n * clampPoint({ x: 0, y: 0 }, bounds); // { x: 0, y: 0 } (inside)\n * clampPoint({ x: 150, y: 0 }, bounds); // { x: 100, y: 0 } (clamped x)\n * clampPoint({ x: 0, y: -100 }, bounds); // { x: 0, y: -50 } (clamped y)\n * clampPoint({ x: 200, y: -200 }, bounds); // { x: 100, y: -50 } (both clamped)\n * clampPoint({ x: 0, y: 0 }, undefined); // { x: 0, y: 0 } (no bounds)\n * ```\n *\n * @category Camera\n */\nexport function clampPoint(point: Point, boundaries: Boundaries | undefined): Point{\n if(withinBoundaries(point, boundaries) || boundaries == undefined){\n return point;\n }\n let manipulatePoint = {x: point.x, y: point.y};\n let limit = boundaries.min;\n if (limit != undefined){\n if(limit.x != undefined){\n manipulatePoint.x = Math.max(manipulatePoint.x, limit.x);\n }\n if(limit.y != undefined){\n manipulatePoint.y = Math.max(manipulatePoint.y, limit.y);\n }\n }\n limit = boundaries.max;\n if(limit != undefined){\n if(limit.x != undefined){\n manipulatePoint.x = Math.min(manipulatePoint.x, limit.x);\n }\n if(limit.y != undefined){\n manipulatePoint.y = Math.min(manipulatePoint.y, limit.y);\n }\n }\n return manipulatePoint;\n}\n\n/**\n * Calculates the width (x-axis span) of the boundaries.\n *\n * @param boundaries - The boundaries to measure\n * @returns Width in world units, or undefined if x boundaries are not fully defined\n *\n * @remarks\n * Returns undefined if boundaries don't have both min.x and max.x defined.\n * Result is always non-negative for valid boundaries (max.x - min.x).\n *\n * @example\n * ```typescript\n * translationWidthOf({\n * min: { x: -100, y: -50 },\n * max: { x: 100, y: 50 }\n * }); // 200\n *\n * translationWidthOf({ min: { x: 0 } }); // undefined (no max.x)\n * translationWidthOf(undefined); // undefined\n * ```\n *\n * @category Camera\n */\nexport function translationWidthOf(boundaries: Boundaries | undefined): number | undefined{\n if(boundaries == undefined || boundaries.min == undefined || boundaries.max == undefined || boundaries.min.x == undefined || boundaries.max.x == undefined){\n return undefined;\n }\n return boundaries.max.x - boundaries.min.x;\n}\n\n/**\n * Calculates half the width (x-axis half-span) of the boundaries.\n *\n * @param boundaries - The boundaries to measure\n * @returns Half-width in world units, or undefined if x boundaries are not fully defined\n *\n * @remarks\n * Useful for calculating radius or offset from center for x-axis.\n * Equivalent to `translationWidthOf(boundaries) / 2`.\n *\n * @example\n * ```typescript\n * halfTranslationWidthOf({\n * min: { x: -100, y: -50 },\n * max: { x: 100, y: 50 }\n * }); // 100\n * ```\n *\n * @category Camera\n */\nexport function halfTranslationWidthOf(boundaries: Boundaries | undefined): number | undefined{\n const translationWidth = translationWidthOf(boundaries);\n return translationWidth != undefined ? translationWidth / 2 : undefined;\n}\n\n/**\n * Calculates the height (y-axis span) of the boundaries.\n *\n * @param boundaries - The boundaries to measure\n * @returns Height in world units, or undefined if y boundaries are not fully defined\n *\n * @remarks\n * Returns undefined if boundaries don't have both min.y and max.y defined.\n * Result is always non-negative for valid boundaries (max.y - min.y).\n *\n * @example\n * ```typescript\n * translationHeightOf({\n * min: { x: -100, y: -50 },\n * max: { x: 100, y: 50 }\n * }); // 100\n *\n * translationHeightOf({ min: { y: 0 } }); // undefined (no max.y)\n * translationHeightOf(undefined); // undefined\n * ```\n *\n * @category Camera\n */\nexport function translationHeightOf(boundaries: Boundaries | undefined): number | undefined{\n if(boundaries == undefined || boundaries.min == undefined || boundaries.max == undefined || boundaries.min.y == undefined || boundaries.max.y == undefined){\n return undefined;\n }\n return boundaries.max.y - boundaries.min.y;\n}\n\n/**\n * Calculates half the height (y-axis half-span) of the boundaries.\n *\n * @param boundaries - The boundaries to measure\n * @returns Half-height in world units, or undefined if y boundaries are not fully defined\n *\n * @remarks\n * Useful for calculating radius or offset from center for y-axis.\n * Equivalent to `translationHeightOf(boundaries) / 2`.\n *\n * @example\n * ```typescript\n * halfTranslationHeightOf({\n * min: { x: -100, y: -50 },\n * max: { x: 100, y: 50 }\n * }); // 50\n * ```\n *\n * @category Camera\n */\nexport function halfTranslationHeightOf(boundaries: Boundaries | undefined): number | undefined{\n const translationHeight = translationHeightOf(boundaries);\n return translationHeight != undefined ? translationHeight / 2 : undefined;\n}\n\n/**\n * Clamps camera position to ensure the entire viewport stays within boundaries.\n * More restrictive than {@link clampPoint} as it considers viewport size and rotation.\n *\n * @param point - Proposed camera position in world coordinates\n * @param viewPortWidth - Width of the viewport in CSS pixels\n * @param viewPortHeight - Height of the viewport in CSS pixels\n * @param boundaries - Optional boundary constraints in world space\n * @param cameraZoomLevel - Current camera zoom level\n * @param cameraRotation - Current camera rotation in radians\n * @returns Adjusted camera position that keeps entire viewport within boundaries\n *\n * @remarks\n * This function ensures no part of the viewport extends outside the boundaries.\n * It accounts for:\n * - Viewport dimensions (width/height)\n * - Camera rotation (viewport corners rotate around camera center)\n * - Zoom level (affects world-space size of viewport)\n *\n * The algorithm:\n * 1. Calculates all four viewport corners in world space\n * 2. Clamps each corner to boundaries\n * 3. Finds the maximum displacement needed across all corners\n * 4. Adjusts camera position by that displacement\n *\n * Use this for \"edge-stop\" behavior where viewport cannot scroll past boundaries.\n * For \"center-stop\" behavior, use {@link clampPoint} instead.\n *\n * @example\n * ```typescript\n * const bounds: Boundaries = {\n * min: { x: 0, y: 0 },\n * max: { x: 1000, y: 1000 }\n * };\n *\n * // Camera at center of bounds, viewport extends outside\n * const adjusted = clampPointEntireViewPort(\n * { x: 100, y: 100 }, // camera position\n * 800, 600, // viewport size\n * bounds,\n * 1.0, // zoom\n * 0 // rotation\n * );\n * // Returns position that prevents viewport from exceeding bounds\n * ```\n *\n * @category Camera\n * @see {@link clampPoint} for clamping camera center only\n */\nexport function clampPointEntireViewPort(point: Point, viewPortWidth: number, viewPortHeight: number, boundaries: Boundaries | undefined, cameraZoomLevel: number, cameraRotation: number): Point{\n if(boundaries == undefined){\n return point;\n }\n let topLeftCorner = convert2WorldSpaceWRT(point, {x: 0, y: viewPortHeight}, viewPortWidth, viewPortHeight, cameraZoomLevel, cameraRotation);\n let bottomLeftCorner = convert2WorldSpaceWRT(point, {x: 0, y: 0}, viewPortWidth, viewPortHeight, cameraZoomLevel, cameraRotation);\n let topRightCorner = convert2WorldSpaceWRT(point, {x: viewPortWidth, y: viewPortHeight}, viewPortWidth, viewPortHeight, cameraZoomLevel, cameraRotation);\n let bottomRightCorner = convert2WorldSpaceWRT(point, {x: viewPortWidth, y: 0}, viewPortWidth, viewPortHeight, cameraZoomLevel, cameraRotation);\n let topLeftCornerClamped = clampPoint(topLeftCorner, boundaries);\n let topRightCornerClamped = clampPoint(topRightCorner, boundaries);\n let bottomLeftCornerClamped = clampPoint(bottomLeftCorner, boundaries);\n let bottomRightCornerClamped = clampPoint(bottomRightCorner, boundaries);\n let topLeftCornerDiff = PointCal.subVector(topLeftCornerClamped, topLeftCorner);\n let topRightCornerDiff = PointCal.subVector(topRightCornerClamped, topRightCorner);\n let bottomLeftCornerDiff = PointCal.subVector(bottomLeftCornerClamped, bottomLeftCorner);\n let bottomRightCornerDiff = PointCal.subVector(bottomRightCornerClamped, bottomRightCorner);\n let diffs = [topLeftCornerDiff, topRightCornerDiff, bottomLeftCornerDiff, bottomRightCornerDiff];\n let maxXDiff = Math.abs(diffs[0].x);\n let maxYDiff = Math.abs(diffs[0].y);\n let delta = diffs[0];\n diffs.forEach((diff)=>{\n if(Math.abs(diff.x) > maxXDiff){\n maxXDiff = Math.abs(diff.x);\n delta.x = diff.x;\n }\n if(Math.abs(diff.y) > maxYDiff){\n maxYDiff = Math.abs(diff.y);\n delta.y = diff.y;\n }\n });\n return PointCal.addVector(point, delta);\n}\n",
17
- "/**\n * Constraints for camera zoom level with optional minimum and maximum bounds.\n *\n * @property min - Minimum allowed zoom level (optional, e.g., 0.1 for 10% zoom)\n * @property max - Maximum allowed zoom level (optional, e.g., 10 for 1000% zoom)\n *\n * @remarks\n * Zoom level of 1.0 represents 100% (no zoom), values >1 zoom in, values <1 zoom out.\n * If both min and max are undefined, no constraints are applied.\n *\n * @category Camera\n */\nexport type ZoomLevelLimits = {min?: number, max?: number};\n\n/**\n * Validates that zoom level limits are logically consistent.\n *\n * @param zoomLevelLimits - The zoom limits to validate\n * @returns True if limits are valid or undefined, false if min > max\n *\n * @remarks\n * Returns true if:\n * - Limits are undefined (no constraints)\n * - Only min or max is defined\n * - Both are defined and min ≤ max\n *\n * @example\n * ```typescript\n * isValidZoomLevelLimits({ min: 0.5, max: 5 }); // true\n * isValidZoomLevelLimits({ min: 5, max: 0.5 }); // false\n * isValidZoomLevelLimits({ min: 0.5 }); // true\n * isValidZoomLevelLimits(undefined); // true\n * ```\n *\n * @category Camera\n */\nexport function isValidZoomLevelLimits(zoomLevelLimits: ZoomLevelLimits | undefined): boolean{\n if(zoomLevelLimits === undefined){\n return true;\n }\n if(zoomLevelLimits.min !== undefined && zoomLevelLimits.max !== undefined && zoomLevelLimits.min > zoomLevelLimits.max){\n return false;\n }\n return true;\n}\n\n/**\n * Clamps a zoom level to stay within specified limits.\n *\n * @param zoomLevel - The zoom level to clamp\n * @param zoomLevelLimits - Optional zoom constraints\n * @returns The clamped zoom level, or original value if already within limits\n *\n * @remarks\n * If the zoom level is already within limits, returns it unchanged.\n * If no limits are specified, returns the original value.\n *\n * @example\n * ```typescript\n * const limits = { min: 0.5, max: 4 };\n *\n * clampZoomLevel(2.0, limits); // 2.0 (within bounds)\n * clampZoomLevel(0.1, limits); // 0.5 (clamped to min)\n * clampZoomLevel(10, limits); // 4.0 (clamped to max)\n * clampZoomLevel(2.0); // 2.0 (no limits)\n * ```\n *\n * @category Camera\n */\nexport function clampZoomLevel(zoomLevel: number, zoomLevelLimits?: ZoomLevelLimits): number{\n if(zoomLevelWithinLimits(zoomLevel, zoomLevelLimits) || zoomLevelLimits === undefined){\n return zoomLevel;\n }\n if(zoomLevelLimits.max){\n zoomLevel = Math.min(zoomLevelLimits.max, zoomLevel);\n }\n if(zoomLevelLimits.min){\n zoomLevel = Math.max(zoomLevelLimits.min, zoomLevel);\n }\n return zoomLevel;\n}\n\n/**\n * Checks if a zoom level is within specified limits.\n *\n * @param zoomLevel - The zoom level to check\n * @param zoomLevelLimits - Optional zoom constraints\n * @returns True if zoom level is valid and within limits, false otherwise\n *\n * @remarks\n * Returns false if:\n * - Zoom level is ≤ 0 (invalid zoom)\n * - Zoom level exceeds maximum limit (if defined)\n * - Zoom level is below minimum limit (if defined)\n *\n * Returns true if no limits are defined or zoom is within bounds.\n *\n * @example\n * ```typescript\n * const limits = { min: 0.5, max: 4 };\n *\n * zoomLevelWithinLimits(2.0, limits); // true\n * zoomLevelWithinLimits(0.1, limits); // false (below min)\n * zoomLevelWithinLimits(10, limits); // false (above max)\n * zoomLevelWithinLimits(-1, limits); // false (negative zoom)\n * zoomLevelWithinLimits(0, limits); // false (zero zoom)\n * zoomLevelWithinLimits(2.0); // true (no limits)\n * ```\n *\n * @category Camera\n */\nexport function zoomLevelWithinLimits(zoomLevel: number, zoomLevelLimits?: ZoomLevelLimits): boolean{\n if(zoomLevelLimits === undefined){\n return true;\n }\n if(zoomLevel <= 0 || (zoomLevelLimits !== undefined &&\n ((zoomLevelLimits.max !== undefined && zoomLevelLimits.max < zoomLevel) ||\n (zoomLevelLimits.min !== undefined && zoomLevelLimits.min > zoomLevel)\n ))){\n return false;\n }\n return true;\n}\n",
18
- "/**\n * Constraints for camera rotation defining an angular range with direction.\n *\n * @property start - Starting angle of the allowed range in radians\n * @property end - Ending angle of the allowed range in radians\n * @property ccw - If true, the range is measured counter-clockwise from start to end. If false, clockwise\n * @property startAsTieBreaker - When clamping and distance to start equals distance to end, clamp to start if true, end if false\n *\n * @remarks\n * Rotation limits define an angular arc. The direction (ccw) determines which\n * way around the circle the range extends from start to end.\n *\n * For example:\n * - start=0, end=π/2, ccw=true: allows 0 to π/2 (0° to 90°)\n * - start=0, end=π/2, ccw=false: allows 0 to -3π/2 going clockwise (0° to 270° the other way)\n *\n * @category Camera\n */\nexport type RotationLimits = {start: number, end: number, ccw: boolean, startAsTieBreaker: boolean};\n\n/**\n * Experimental rotation boundary type with positive/negative direction semantics.\n *\n * @property start - Starting angle of the boundary in radians\n * @property end - Ending angle of the boundary in radians\n * @property positiveDirection - If true, range extends in positive angle direction. If false, negative direction\n * @property startAsTieBreaker - When equidistant from start and end, prefer start if true, end if false\n *\n * @remarks\n * This is an experimental alternative to {@link RotationLimits} with different direction semantics.\n *\n * @category Camera\n */\nexport type RotationBoundary = {start: number, end: number, positiveDirection: boolean, startAsTieBreaker: boolean};\n\n/**\n * Clamps a rotation angle to stay within specified angular limits.\n *\n * @param rotation - The rotation angle to clamp in radians\n * @param rotationLimits - Optional rotation constraints with direction\n * @returns The clamped rotation angle, or original if already within limits\n *\n * @remarks\n * If the rotation is outside the allowed arc, it's clamped to the nearest\n * boundary (start or end). When equidistant from both, the `startAsTieBreaker`\n * flag determines which boundary to use.\n *\n * The rotation is normalized to [0, 2π] before clamping.\n *\n * @example\n * ```typescript\n * const limits = { start: 0, end: Math.PI/2, ccw: true, startAsTieBreaker: true };\n *\n * clampRotation(Math.PI/4, limits); // π/4 (within range)\n * clampRotation(Math.PI, limits); // π/2 (clamped to end)\n * clampRotation(-0.1, limits); // 0 (clamped to start)\n * ```\n *\n * @category Camera\n */\nexport function clampRotation(rotation: number, rotationLimits?: RotationLimits): number{\n if(rotationWithinLimits(rotation, rotationLimits) || rotationLimits === undefined){\n return rotation;\n }\n rotation = normalizeAngleZero2TwoPI(rotation);\n const angleSpanFromStart = angleSpan(rotationLimits.start, rotation);\n const angleSpanFromEnd = angleSpan(rotationLimits.end, rotation);\n if((rotationLimits.ccw && (angleSpanFromStart < 0 || angleSpanFromEnd > 0)) || (!rotationLimits.ccw && (angleSpanFromStart > 0 || angleSpanFromEnd < 0))){\n // ccw out of bounds\n if(Math.abs(angleSpanFromStart) === Math.abs(angleSpanFromEnd)){\n // console.log(\"tie\", \"start:\", rotationLimits.start, \"end:\", rotationLimits.end, \"rotation:\", rotation);\n return rotationLimits.startAsTieBreaker ? rotationLimits.start : rotationLimits.end;\n }\n const closerToStart = Math.abs(angleSpanFromStart) < Math.abs(angleSpanFromEnd);\n return closerToStart ? rotationLimits.start : rotationLimits.end;\n }\n return rotation;\n}\n\n/**\n * Checks if a rotation angle is within specified angular limits.\n *\n * @param rotation - The rotation angle to check in radians\n * @param rotationLimits - Optional rotation constraints with direction\n * @returns True if rotation is within the allowed arc or no limits specified, false otherwise\n *\n * @remarks\n * Returns true if:\n * - No limits are specified (undefined)\n * - Start and end angles are effectively equal (full circle allowed)\n * - Rotation falls within the arc from start to end in the specified direction\n *\n * The rotation is normalized to [0, 2π] before checking.\n *\n * @example\n * ```typescript\n * const limits = { start: 0, end: Math.PI/2, ccw: true, startAsTieBreaker: true };\n *\n * rotationWithinLimits(Math.PI/4, limits); // true (within range)\n * rotationWithinLimits(Math.PI, limits); // false (outside range)\n * rotationWithinLimits(0, limits); // true (at start)\n * rotationWithinLimits(Math.PI/2, limits); // true (at end)\n * ```\n *\n * @category Camera\n */\nexport function rotationWithinLimits(rotation: number, rotationLimits?: RotationLimits): boolean{\n if(rotationLimits === undefined){\n return true;\n }\n if(normalizeAngleZero2TwoPI(rotationLimits.start) === normalizeAngleZero2TwoPI(rotationLimits.end)){\n return true;\n }\n if(normalizeAngleZero2TwoPI(rotationLimits.start + 0.01) === normalizeAngleZero2TwoPI(rotationLimits.end + 0.01)){\n return true;\n }\n const normalizedRotation = normalizeAngleZero2TwoPI(rotation);\n const angleSpanFromStart = angleSpan(rotationLimits.start, normalizedRotation);\n const angleSpanFromEnd = angleSpan(rotationLimits.end, normalizedRotation);\n if((rotationLimits.ccw && (angleSpanFromStart < 0 || angleSpanFromEnd > 0)) || (!rotationLimits.ccw && (angleSpanFromStart > 0 || angleSpanFromEnd < 0))){\n return false;\n }\n return true;\n}\n\n/**\n * Checks if a rotation angle is within an experimental rotation boundary.\n *\n * @param rotation - The rotation angle to check in radians\n * @param rotationBoundary - Rotation boundary with positive/negative direction\n * @returns True if rotation is within the boundary range, false otherwise\n *\n * @remarks\n * This is an experimental alternative to {@link rotationWithinLimits} using\n * positive/negative direction semantics instead of ccw/cw.\n *\n * @category Camera\n */\nexport function rotationWithinBoundary(rotation: number, rotationBoundary: RotationBoundary): boolean {\n if(normalizeAngleZero2TwoPI(rotationBoundary.start) === normalizeAngleZero2TwoPI(rotationBoundary.end)){\n return true;\n }\n if(normalizeAngleZero2TwoPI(rotationBoundary.start + 0.01) === normalizeAngleZero2TwoPI(rotationBoundary.end + 0.01)){\n return true;\n }\n const normalizedRotation = normalizeAngleZero2TwoPI(rotation);\n\n let angleFromStart = normalizedRotation - normalizeAngleZero2TwoPI(rotationBoundary.start);\n if (angleFromStart < 0){\n angleFromStart += (Math.PI * 2);\n }\n if (!rotationBoundary.positiveDirection && angleFromStart > 0){\n angleFromStart = Math.PI * 2 - angleFromStart;\n }\n\n let angleRange = normalizeAngleZero2TwoPI(rotationBoundary.end) - normalizeAngleZero2TwoPI(rotationBoundary.start);\n if(angleRange < 0){\n angleRange += (Math.PI * 2);\n }\n if(!rotationBoundary.positiveDirection && angleRange > 0){\n angleRange = Math.PI * 2 - angleRange;\n }\n\n return angleRange >= angleFromStart;\n}\n\n/**\n * Normalizes an angle to the range [0, 2π).\n *\n * @param angle - Angle in radians (can be any value)\n * @returns Equivalent angle in the range [0, 2π)\n *\n * @remarks\n * This function wraps angles to the standard [0, 2π) range. Useful for\n * ensuring consistent angle representation when comparing or storing angles.\n *\n * @example\n * ```typescript\n * normalizeAngleZero2TwoPI(0); // 0\n * normalizeAngleZero2TwoPI(Math.PI); // π\n * normalizeAngleZero2TwoPI(3 * Math.PI); // π (wraps around)\n * normalizeAngleZero2TwoPI(-Math.PI/2); // 3π/2 (negative becomes positive)\n * normalizeAngleZero2TwoPI(2 * Math.PI); // 0 (full rotation)\n * ```\n *\n * @category Camera\n */\nexport function normalizeAngleZero2TwoPI(angle: number){\n // reduce the angle\n angle = angle % (Math.PI * 2);\n\n // force it to be the positive remainder, so that 0 <= angle < 2 * Math.PI\n angle = (angle + Math.PI * 2) % (Math.PI * 2);\n return angle;\n}\n\n/**\n * Calculates the signed angular distance between two angles, taking the shorter path.\n *\n * @param from - Starting angle in radians\n * @param to - Target angle in radians\n * @returns Signed angular difference in radians, in the range (-π, π]\n *\n * @remarks\n * Returns the shortest angular path from `from` to `to`:\n * - Positive value: rotate counter-clockwise (positive direction)\n * - Negative value: rotate clockwise (negative direction)\n * - Always returns the smaller of the two possible paths\n *\n * @example\n * ```typescript\n * angleSpan(0, Math.PI/2); // π/2 (90° ccw)\n * angleSpan(Math.PI/2, 0); // -π/2 (90° cw)\n * angleSpan(0, 3*Math.PI/2); // -π/2 (shorter to go cw)\n * angleSpan(3*Math.PI/2, 0); // π/2 (shorter to go ccw)\n * angleSpan(0, Math.PI); // π (180°, ambiguous)\n * ```\n *\n * @category Camera\n */\nexport function angleSpan(from: number, to: number): number{\n // in radians\n from = normalizeAngleZero2TwoPI(from);\n to = normalizeAngleZero2TwoPI(to);\n let angleDiff = to - from;\n\n if(angleDiff > Math.PI){\n angleDiff = - (Math.PI * 2 - angleDiff);\n }\n\n if(angleDiff < -Math.PI){\n angleDiff += (Math.PI * 2);\n }\n return angleDiff;\n}\n\n/**\n * Converts degrees to radians.\n *\n * @param deg - Angle in degrees\n * @returns Equivalent angle in radians\n *\n * @example\n * ```typescript\n * deg2rad(0); // 0\n * deg2rad(90); // π/2\n * deg2rad(180); // π\n * deg2rad(360); // 2π\n * deg2rad(-45); // -π/4\n * ```\n *\n * @category Camera\n */\nexport function deg2rad(deg: number): number{\n return deg * Math.PI / 180;\n}\n\n/**\n * Converts radians to degrees.\n *\n * @param rad - Angle in radians\n * @returns Equivalent angle in degrees\n *\n * @example\n * ```typescript\n * rad2deg(0); // 0\n * rad2deg(Math.PI/2); // 90\n * rad2deg(Math.PI); // 180\n * rad2deg(2 * Math.PI); // 360\n * rad2deg(-Math.PI/4); // -45\n * ```\n *\n * @category Camera\n */\nexport function rad2deg(rad: number): number{\n return rad * 180 / Math.PI;\n}\n",
19
- "import { Point } from '@ue-too/math';\nimport { Boundaries, withinBoundaries } from './utils/position';\nimport { zoomLevelWithinLimits, ZoomLevelLimits, clampZoomLevel } from './utils/zoom';\nimport { RotationLimits, rotationWithinLimits, normalizeAngleZero2TwoPI, clampRotation } from './utils/rotation';\nimport { convert2WorldSpaceAnchorAtCenter, convert2ViewPortSpaceAnchorAtCenter } from './utils/coordinate-conversion';\nimport { PointCal } from '@ue-too/math';\nimport { BoardCamera } from './interface';\nimport { decomposeCameraMatrix, decomposeTRS, TransformationMatrix } from './utils/matrix';\n\n/**\n * Base camera implementation providing core functionality for an infinite canvas system.\n * This is the fundamental building block for camera management in the board package.\n *\n * @remarks\n * BaseCamera is non-observable and does not emit events when state changes.\n * For event-driven camera updates, use {@link DefaultBoardCamera} instead.\n *\n * The camera supports:\n * - Position, rotation, and zoom transformations\n * - Configurable boundaries for position, zoom, and rotation\n * - Coordinate conversion between viewport and world space\n * - Transformation matrix caching for performance\n * - High-DPI display support via devicePixelRatio\n *\n * @example\n * ```typescript\n * // Create a camera for a 1920x1080 viewport\n * const camera = new BaseCamera(1920, 1080, { x: 0, y: 0 }, 0, 1.0);\n *\n * // Set boundaries to constrain camera movement\n * camera.setHorizontalBoundaries(-5000, 5000);\n * camera.setVerticalBoundaries(-5000, 5000);\n *\n * // Update camera state\n * camera.setPosition({ x: 100, y: 200 });\n * camera.setZoomLevel(2.0);\n * camera.setRotation(Math.PI / 6);\n *\n * // Get transformation matrix for rendering\n * const transform = camera.getTransform(window.devicePixelRatio, true);\n * ctx.setTransform(transform.a, transform.b, transform.c, transform.d, transform.e, transform.f);\n * ```\n *\n * @category Camera\n * @see {@link DefaultBoardCamera} for observable camera with event support\n * @see {@link CameraRig} for high-level camera control with input handling\n */\nexport default class BaseCamera implements BoardCamera {\n\n private _position: Point;\n private _rotation: number;\n private _zoomLevel: number;\n\n private currentCachedTransform: {transform: {a: number, b: number, c: number, d: number, e: number, f: number}, position: Point, rotation: number, zoomLevel: number, alignCoorindate: boolean, devicePixelRatio: number, viewPortWidth: number, viewPortHeight: number} | undefined;\n\n private currentCachedTRS: {scale: {x: number, y: number}, rotation: number, translation: {x: number, y: number}, transformMatrix: TransformationMatrix} | undefined;\n\n private _viewPortWidth: number;\n private _viewPortHeight: number;\n\n private _boundaries?: Boundaries;\n private _zoomBoundaries?: ZoomLevelLimits;\n private _rotationBoundaries?: RotationLimits;\n\n /**\n * Creates a new BaseCamera instance with specified viewport size and optional constraints.\n *\n * @param viewPortWidth - Width of the viewport in CSS pixels (default: 1000)\n * @param viewPortHeight - Height of the viewport in CSS pixels (default: 1000)\n * @param position - Initial camera position in world coordinates (default: {x: 0, y: 0})\n * @param rotation - Initial rotation in radians (default: 0)\n * @param zoomLevel - Initial zoom level, where 1.0 = 100% (default: 1.0)\n * @param boundaries - Position constraints in world space (default: ±10000 on both axes)\n * @param zoomLevelBoundaries - Zoom constraints (default: 0.1 to 10)\n * @param rotationBoundaries - Optional rotation constraints (default: undefined, unrestricted)\n *\n * @example\n * ```typescript\n * // Basic camera with defaults\n * const camera = new BaseCamera();\n *\n * // Camera with custom viewport and position\n * const camera2 = new BaseCamera(\n * 1920, 1080,\n * { x: 500, y: 300 },\n * 0,\n * 1.5\n * );\n *\n * // Camera with all constraints\n * const camera3 = new BaseCamera(\n * 1920, 1080,\n * { x: 0, y: 0 },\n * 0,\n * 1.0,\n * { min: { x: -2000, y: -2000 }, max: { x: 2000, y: 2000 } },\n * { min: 0.5, max: 5 },\n * { start: 0, end: Math.PI / 2 }\n * );\n * ```\n */\n constructor(viewPortWidth: number = 1000, viewPortHeight: number = 1000, position: Point = {x: 0, y: 0}, rotation: number = 0, zoomLevel: number = 1, boundaries: Boundaries = {min: {x: -10000, y: -10000}, max: {x: 10000, y: 10000}}, zoomLevelBoundaries: ZoomLevelLimits = {min: 0.1, max: 10}, rotationBoundaries: RotationLimits | undefined = undefined){\n this._position = position;\n this._zoomLevel = zoomLevel;\n this._rotation = rotation;\n this._viewPortHeight = viewPortHeight;\n this._viewPortWidth = viewPortWidth;\n this._zoomBoundaries = zoomLevelBoundaries;\n this._rotationBoundaries = rotationBoundaries;\n this._boundaries = boundaries;\n }\n\n /**\n * Gets the current position boundaries that constrain camera movement in world coordinates.\n *\n * @returns The boundaries object or undefined if no boundaries are set\n */\n get boundaries(): Boundaries | undefined{\n return this._boundaries;\n }\n\n /**\n * Sets position boundaries to constrain camera movement in world coordinates.\n *\n * @param boundaries - Boundary constraints or undefined to remove all constraints\n */\n set boundaries(boundaries: Boundaries | undefined){\n this._boundaries = boundaries;\n }\n\n /**\n * Gets the viewport width in CSS pixels.\n *\n * @returns Current viewport width\n */\n get viewPortWidth(): number{\n return this._viewPortWidth;\n }\n\n /**\n * Sets the viewport width in CSS pixels.\n * Updates invalidate the cached transformation matrix.\n *\n * @param width - New viewport width in CSS pixels\n */\n set viewPortWidth(width: number){\n this._viewPortWidth = width;\n }\n\n /**\n * Gets the viewport height in CSS pixels.\n *\n * @returns Current viewport height\n */\n get viewPortHeight(): number{\n return this._viewPortHeight;\n }\n\n /**\n * Sets the viewport height in CSS pixels.\n * Updates invalidate the cached transformation matrix.\n *\n * @param height - New viewport height in CSS pixels\n */\n set viewPortHeight(height: number){\n this._viewPortHeight = height;\n }\n\n /**\n * Gets the current camera position in world coordinates.\n *\n * @returns A copy of the current position (center of viewport in world space)\n */\n get position(): Point{\n return {...this._position};\n }\n\n /**\n * Sets the camera position with boundary validation and floating-point jitter prevention.\n *\n * @param destination - Target position in world coordinates\n * @returns True if position was updated, false if rejected by boundaries or negligible change\n *\n * @remarks\n * Position updates are rejected if:\n * - The destination is outside the configured boundaries\n * - The change magnitude is less than 10E-10\n * - The change magnitude is less than 1/zoomLevel (prevents sub-pixel jitter)\n *\n * @example\n * ```typescript\n * camera.setHorizontalBoundaries(-1000, 1000);\n * camera.setVerticalBoundaries(-1000, 1000);\n *\n * camera.setPosition({ x: 500, y: 500 }); // returns true\n * camera.setPosition({ x: 2000, y: 0 }); // returns false (out of bounds)\n * ```\n */\n setPosition(destination: Point){\n if(!withinBoundaries(destination, this._boundaries)){\n return false;\n }\n const diff = PointCal.subVector(destination, this._position);\n if(PointCal.magnitude(diff) < 10E-10 && PointCal.magnitude(diff) < 1 / this._zoomLevel){\n return false;\n }\n this._position = destination;\n return true;\n }\n\n /**\n * Gets the current zoom level.\n *\n * @returns Current zoom level (1.0 = 100%, 2.0 = 200%, etc.)\n */\n get zoomLevel(): number{\n return this._zoomLevel;\n }\n\n /**\n * Gets the current zoom level constraints.\n *\n * @returns Zoom boundaries object or undefined if unconstrained\n */\n get zoomBoundaries(): ZoomLevelLimits | undefined{\n return this._zoomBoundaries;\n }\n\n /**\n * Sets zoom level constraints with automatic min/max swapping if needed.\n *\n * @param zoomBoundaries - Zoom constraints or undefined to remove constraints\n *\n * @remarks\n * If min > max, the values are automatically swapped.\n */\n set zoomBoundaries(zoomBoundaries: ZoomLevelLimits | undefined){\n const newZoomBoundaries = {...zoomBoundaries};\n if(newZoomBoundaries !== undefined && newZoomBoundaries.min !== undefined && newZoomBoundaries.max !== undefined && newZoomBoundaries.min > newZoomBoundaries.max){\n let temp = newZoomBoundaries.max;\n newZoomBoundaries.max = newZoomBoundaries.min;\n newZoomBoundaries.min = temp;\n }\n this._zoomBoundaries = newZoomBoundaries;\n }\n\n /**\n * Sets the maximum allowed zoom level.\n *\n * @param maxZoomLevel - New maximum zoom level\n * @returns True if successfully set, false if conflicts with existing min or current zoom\n *\n * @remarks\n * Returns false if:\n * - The new max is less than the current minimum boundary\n * - The current zoom level exceeds the new maximum\n */\n setMaxZoomLevel(maxZoomLevel: number){\n if(this._zoomBoundaries == undefined){\n this._zoomBoundaries = {min: undefined, max: undefined};\n }\n if((this._zoomBoundaries.min != undefined && this._zoomBoundaries.min > maxZoomLevel) || this._zoomLevel > maxZoomLevel){\n return false;\n }\n this._zoomBoundaries.max = maxZoomLevel;\n console.trace('setMaxZoomLevel', maxZoomLevel);\n return true\n }\n\n /**\n * Sets the minimum allowed zoom level.\n *\n * @param minZoomLevel - New minimum zoom level\n * @returns True if successfully set, false if conflicts with existing max\n *\n * @remarks\n * If the current zoom level is below the new minimum, the camera automatically\n * zooms in to match the minimum. Returns false if new min exceeds existing max boundary.\n */\n setMinZoomLevel(minZoomLevel: number){\n if(this._zoomBoundaries == undefined){\n this._zoomBoundaries = {min: undefined, max: undefined};\n }\n if((this._zoomBoundaries.max != undefined && this._zoomBoundaries.max < minZoomLevel)){\n return false;\n }\n this._zoomBoundaries.min = minZoomLevel;\n if(this._zoomLevel < minZoomLevel){\n this._zoomLevel = minZoomLevel;\n }\n console.trace('setMinZoomLevel', minZoomLevel);\n return true;\n }\n\n /**\n * Sets the camera zoom level with boundary validation.\n *\n * @param zoomLevel - Target zoom level (1.0 = 100%, 2.0 = 200%, etc.)\n * @returns True if zoom was updated, false if outside boundaries or already at limit\n *\n * @remarks\n * Returns false if:\n * - Zoom level is outside configured boundaries\n * - Already at maximum and trying to zoom beyond it\n * - Already at minimum and trying to zoom below it\n *\n * @example\n * ```typescript\n * camera.setZoomLevel(2.0); // 200% zoom\n * camera.setZoomLevel(0.5); // 50% zoom\n * ```\n */\n setZoomLevel(zoomLevel: number){\n if(!zoomLevelWithinLimits(zoomLevel, this._zoomBoundaries)){\n return false;\n }\n if(this._zoomBoundaries !== undefined && this._zoomBoundaries.max !== undefined && clampZoomLevel(zoomLevel, this._zoomBoundaries) == this._zoomBoundaries.max && this._zoomLevel == this._zoomBoundaries.max){\n return false;\n }\n if(this._zoomBoundaries !== undefined && this._zoomBoundaries.min !== undefined && clampZoomLevel(zoomLevel, this._zoomBoundaries) == this._zoomBoundaries.min && this._zoomLevel == this._zoomBoundaries.min){\n return false;\n }\n this._zoomLevel = zoomLevel;\n return true;\n }\n\n /**\n * Gets the current camera rotation in radians.\n *\n * @returns Current rotation angle (0 to 2π)\n */\n get rotation(): number{\n return this._rotation;\n }\n\n /**\n * Gets the current rotation constraints.\n *\n * @returns Rotation boundaries or undefined if unconstrained\n */\n get rotationBoundaries(): RotationLimits | undefined{\n return this._rotationBoundaries;\n }\n\n /**\n * Sets rotation constraints with automatic start/end swapping if needed.\n *\n * @param rotationBoundaries - Rotation limits or undefined to remove constraints\n *\n * @remarks\n * If start > end, the values are automatically swapped.\n */\n set rotationBoundaries(rotationBoundaries: RotationLimits | undefined){\n if(rotationBoundaries !== undefined && rotationBoundaries.start !== undefined && rotationBoundaries.end !== undefined && rotationBoundaries.start > rotationBoundaries.end){\n let temp = rotationBoundaries.end;\n rotationBoundaries.end = rotationBoundaries.start;\n rotationBoundaries.start = temp;\n }\n this._rotationBoundaries = rotationBoundaries;\n }\n\n /**\n * Computes the complete transformation matrix from world space to canvas pixel space.\n * Includes caching for performance optimization.\n *\n * @param devicePixelRatio - Device pixel ratio (typically window.devicePixelRatio)\n * @param alignCoorindate - If true, uses standard y-up coordinate system. If false, inverts y-axis\n * @returns Transformation matrix object {a, b, c, d, e, f} with optional cached flag\n *\n * @remarks\n * Transformation order applied:\n * 1. Scale by devicePixelRatio\n * 2. Translate to viewport center\n * 3. Rotate (negated if alignCoorindate is true)\n * 4. Scale by zoom level\n * 5. Translate by camera position\n *\n * The result is cached based on all parameters. Subsequent calls with identical parameters\n * return the cached matrix with `cached: true` flag.\n *\n * @example\n * ```typescript\n * const ctx = canvas.getContext('2d');\n * const transform = camera.getTransform(window.devicePixelRatio, true);\n * ctx.setTransform(transform.a, transform.b, transform.c, transform.d, transform.e, transform.f);\n *\n * // Now drawing at world coordinates (100, 200) appears correctly on canvas\n * ctx.fillRect(100, 200, 50, 50);\n * ```\n *\n * @see {@link getTRS} for decomposed transformation components\n */\n getTransform(devicePixelRatio: number = 1, alignCoorindate: boolean = true) {\n if(this.currentCachedTransform !== undefined\n && this.currentCachedTransform.devicePixelRatio === devicePixelRatio\n && this.currentCachedTransform.alignCoorindate === alignCoorindate\n && this.currentCachedTransform.position.x === this._position.x\n && this.currentCachedTransform.position.y === this._position.y\n && this.currentCachedTransform.rotation === this._rotation\n && this.currentCachedTransform.zoomLevel === this._zoomLevel\n && this.currentCachedTransform.viewPortWidth === this._viewPortWidth\n && this.currentCachedTransform.viewPortHeight === this._viewPortHeight\n ){\n return {...this.currentCachedTransform.transform, cached: true};\n }\n\n const tx = devicePixelRatio * this._viewPortWidth / 2; // 0 if the camera position represents the position at the top left corner of the canvas in the world\n const ty = devicePixelRatio * this._viewPortHeight / 2; // 0 if the camera position represents the position at the top left corner of the canvas in the world\n\n const tx2 = -this._position.x;\n const ty2 = alignCoorindate ? -this._position.y : this._position.y;\n\n const s = devicePixelRatio;\n const s2 = this._zoomLevel;\n const θ = alignCoorindate ? -this._rotation : this._rotation;\n\n const sin = Math.sin(θ);\n const cos = Math.cos(θ);\n\n const a = s2 * s * cos;\n const b = s2 * s * sin;\n const c = -s * s2 * sin;\n const d = s2 * s * cos;\n const e = s * s2 * cos * tx2 - s * s2 * sin * ty2 + tx;\n const f = s * s2 * sin * tx2 + s * s2 * cos * ty2 + ty;\n this.currentCachedTransform = {transform: {a, b, c, d, e, f}, position: this._position, rotation: this._rotation, zoomLevel: this._zoomLevel, alignCoorindate, devicePixelRatio, viewPortWidth: this._viewPortWidth, viewPortHeight: this._viewPortHeight};\n return {a, b, c, d, e, f, cached: false};\n }\n\n /**\n * Decomposes the transformation matrix into Translation, Rotation, and Scale components.\n *\n * @param devicePixelRatio - Device pixel ratio for high-DPI displays\n * @param alignCoorindate - If true, uses standard y-up coordinate system. If false, inverts y-axis\n * @returns Object containing separate scale, rotation, and translation values\n *\n * @remarks\n * This is useful when you need individual transformation components rather than\n * the combined matrix. Internally calls {@link getTransform} and decomposes the result.\n */\n getTRS(devicePixelRatio: number = 1, alignCoorindate: boolean = true){\n const transform = this.getTransform(devicePixelRatio, alignCoorindate);\n if(this.currentCachedTRS !== undefined && this.currentCachedTRS.transformMatrix.a === transform.a && this.currentCachedTRS.transformMatrix.b === transform.b && this.currentCachedTRS.transformMatrix.c === transform.c && this.currentCachedTRS.transformMatrix.d === transform.d && this.currentCachedTRS.transformMatrix.e === transform.e && this.currentCachedTRS.transformMatrix.f === transform.f){\n return {\n scale: this.currentCachedTRS.scale,\n rotation: this.currentCachedTRS.rotation,\n translation: this.currentCachedTRS.translation,\n cached: true\n }\n }\n const decompositionRes = decomposeTRS(transform);\n this.currentCachedTRS = {\n scale: decompositionRes.scale,\n rotation: decompositionRes.rotation,\n translation: decompositionRes.translation,\n transformMatrix: transform\n };\n return {\n scale: decompositionRes.scale,\n rotation: decompositionRes.rotation,\n translation: decompositionRes.translation,\n cached: false\n };\n }\n\n /**\n * Sets camera state by decomposing a transformation matrix.\n * Inverse operation of {@link getTransform}.\n *\n * @param transformationMatrix - 2D transformation matrix to decompose\n *\n * @remarks\n * The matrix is decomposed assuming the same transformation order as {@link getTransform}:\n * Scale(devicePixelRatio) → Translation(viewport center) → Rotation → Zoom → Translation(position)\n *\n * Extracted position, zoom, and rotation values are still validated against boundaries.\n *\n * @example\n * ```typescript\n * // Apply a transformation matrix from an external source\n * const matrix = { a: 2, b: 0, c: 0, d: 2, e: 100, f: 100 };\n * camera.setUsingTransformationMatrix(matrix);\n * ```\n */\n setUsingTransformationMatrix(transformationMatrix: TransformationMatrix, devicePixelRatio: number = 1){\n const decomposed = decomposeCameraMatrix(transformationMatrix, devicePixelRatio, this._viewPortWidth, this._viewPortHeight);\n\n // TODO clamp the attributes?\n this.setPosition(decomposed.position);\n this.setRotation(decomposed.rotation);\n this.setZoomLevel(decomposed.zoom);\n }\n\n /**\n * Sets the camera rotation with boundary validation and normalization.\n *\n * @param rotation - Target rotation in radians\n * @returns True if rotation was updated, false if outside boundaries or already at limit\n *\n * @remarks\n * Rotation is automatically normalized to 0-2π range. Returns false if:\n * - Rotation is outside configured boundaries\n * - Already at maximum boundary and trying to rotate beyond it\n * - Already at minimum boundary and trying to rotate below it\n *\n * @example\n * ```typescript\n * camera.setRotation(Math.PI / 4); // 45 degrees\n * camera.setRotation(Math.PI); // 180 degrees\n * ```\n */\n setRotation(rotation: number){\n if(!rotationWithinLimits(rotation, this._rotationBoundaries)){\n return false;\n }\n rotation = normalizeAngleZero2TwoPI(rotation);\n if(this._rotationBoundaries !== undefined && this._rotationBoundaries.end !== undefined && clampRotation(rotation, this._rotationBoundaries) == this._rotationBoundaries.end && this._rotation == this._rotationBoundaries.end){\n return false;\n }\n if(this._rotationBoundaries !== undefined && this._rotationBoundaries.start !== undefined && clampRotation(rotation, this._rotationBoundaries) == this._rotationBoundaries.start && this._rotation == this._rotationBoundaries.start){\n return false;\n }\n this._rotation = rotation;\n return true;\n }\n\n /**\n * Gets the camera origin in window coordinates.\n *\n * @deprecated This method is deprecated and will be removed in a future version.\n * Currently just returns the input unchanged.\n *\n * @param centerInWindow - Center point in window coordinates\n * @returns The same point (camera origin equals window center)\n */\n getCameraOriginInWindow(centerInWindow: Point): Point{\n return centerInWindow;\n }\n\n /**\n * Converts a point from viewport coordinates to world coordinates.\n *\n * @param point - Point in viewport space (relative to viewport center, in CSS pixels)\n * @returns Corresponding point in world coordinates\n *\n * @remarks\n * This accounts for camera position, zoom, and rotation. Useful for converting\n * mouse/touch input to world space.\n *\n * @example\n * ```typescript\n * // Convert mouse click to world position\n * const rect = canvas.getBoundingClientRect();\n * const viewportPoint = {\n * x: event.clientX - rect.left - rect.width / 2,\n * y: event.clientY - rect.top - rect.height / 2\n * };\n * const worldPoint = camera.convertFromViewPort2WorldSpace(viewportPoint);\n * ```\n */\n convertFromViewPort2WorldSpace(point: Point): Point{\n return convert2WorldSpaceAnchorAtCenter(point, this._position, this._zoomLevel, this._rotation);\n }\n\n /**\n * Converts a point from world coordinates to viewport coordinates.\n *\n * @param point - Point in world coordinates\n * @returns Corresponding point in viewport space (relative to viewport center, in CSS pixels)\n *\n * @remarks\n * This accounts for camera position, zoom, and rotation. Useful for positioning\n * UI elements at world object locations.\n *\n * @example\n * ```typescript\n * // Position a DOM element at a world object's location\n * const viewportPos = camera.convertFromWorld2ViewPort(objectWorldPos);\n * element.style.left = `${viewportPos.x + canvas.width / 2}px`;\n * element.style.top = `${viewportPos.y + canvas.height / 2}px`;\n * ```\n */\n convertFromWorld2ViewPort(point: Point): Point{\n return convert2ViewPortSpaceAnchorAtCenter(point, this._position, this._zoomLevel, this._rotation);\n }\n\n /**\n * Converts a point from world coordinates to viewport coordinates.\n * Alternative implementation of {@link convertFromWorld2ViewPort}.\n *\n * @param point - Point in world coordinates\n * @returns Corresponding point in viewport space (relative to viewport center, in CSS pixels)\n *\n * @remarks\n * This method provides an alternative calculation approach. In most cases,\n * prefer using {@link convertFromWorld2ViewPort} for consistency.\n */\n invertFromWorldSpace2ViewPort(point: Point): Point{\n let cameraFrameCenter = {x: this.viewPortWidth / 2, y: this._viewPortHeight / 2};\n let delta2Point = PointCal.subVector(point, this._position);\n delta2Point = PointCal.rotatePoint(delta2Point, -this._rotation);\n delta2Point = PointCal.multiplyVectorByScalar(delta2Point, this._zoomLevel);\n return PointCal.addVector(cameraFrameCenter, delta2Point);\n }\n\n /**\n * Sets horizontal (x-axis) position boundaries for camera movement.\n *\n * @param min - Minimum x coordinate in world space\n * @param max - Maximum x coordinate in world space\n *\n * @remarks\n * If min > max, the values are automatically swapped. The current camera position\n * is not automatically clamped when boundaries are set.\n *\n * @example\n * ```typescript\n * camera.setHorizontalBoundaries(-1000, 1000);\n * // Camera can now only move between x: -1000 and x: 1000\n * ```\n */\n setHorizontalBoundaries(min: number, max: number){\n if (min > max){\n let temp = max;\n max = min;\n min = temp;\n }\n if(this._boundaries == undefined){\n this._boundaries = {min: {x: undefined, y: undefined}, max: {x: undefined, y: undefined}};\n }\n if(this._boundaries.min == undefined){\n this._boundaries.min = {x: undefined, y: undefined};\n }\n if(this._boundaries.max == undefined){\n this._boundaries.max = {x: undefined, y: undefined};\n }\n this._boundaries.min.x = min;\n this._boundaries.max.x = max;\n //NOTE leave for future optimization when setting the boundaries if the camera lies outside the boundaries clamp the position of the camera\n // if(!this.withinBoundaries(this.position)){\n // this.position = this.clampPoint(this.position);\n // }\n }\n\n /**\n * Sets vertical (y-axis) position boundaries for camera movement.\n *\n * @param min - Minimum y coordinate in world space\n * @param max - Maximum y coordinate in world space\n *\n * @remarks\n * If min > max, the values are automatically swapped. The current camera position\n * is not automatically clamped when boundaries are set.\n *\n * @example\n * ```typescript\n * camera.setVerticalBoundaries(-500, 500);\n * // Camera can now only move between y: -500 and y: 500\n * ```\n */\n setVerticalBoundaries(min: number, max: number){\n if (min > max){\n let temp = max;\n max = min;\n min = temp;\n }\n if(this._boundaries == undefined){\n this._boundaries = {min: {x: undefined, y: undefined}, max: {x: undefined, y: undefined}};\n }\n if(this._boundaries.min == undefined){\n this._boundaries.min = {x: undefined, y: undefined};\n }\n if(this._boundaries.max == undefined){\n this._boundaries.max = {x: undefined, y: undefined};\n }\n this._boundaries.min.y = min;\n this._boundaries.max.y = max;\n }\n\n /**\n * Calculates the four corners of the viewport in world space, accounting for rotation.\n *\n * @param alignCoordinate - If true, uses standard y-up coordinate system. If false, inverts y-axis (default: true)\n * @returns Object containing the four corner points organized as top/bottom and left/right\n *\n * @remarks\n * Returns the actual rotated viewport corners. This is more precise than {@link viewPortAABB}\n * which returns the axis-aligned bounding box. Use this when you need the exact viewport bounds.\n *\n * @example\n * ```typescript\n * const corners = camera.viewPortInWorldSpace();\n * console.log(corners.top.left); // Top-left corner in world coords\n * console.log(corners.top.right); // Top-right corner\n * console.log(corners.bottom.left); // Bottom-left corner\n * console.log(corners.bottom.right);// Bottom-right corner\n * ```\n */\n viewPortInWorldSpace(alignCoordinate: boolean = true): {top: {left: Point, right: Point}, bottom: {left: Point, right: Point}}{\n const topLeftCorner = convert2WorldSpaceAnchorAtCenter({x: -this._viewPortWidth / 2, y: alignCoordinate ? -this._viewPortHeight / 2 : this._viewPortHeight / 2}, this._position, this._zoomLevel, this._rotation);\n const topRightCorner = convert2WorldSpaceAnchorAtCenter({x: this._viewPortWidth / 2, y: alignCoordinate ? -this._viewPortHeight / 2 : this._viewPortHeight / 2}, this._position, this._zoomLevel, this._rotation);\n const bottomLeftCorner = convert2WorldSpaceAnchorAtCenter({x: -this._viewPortWidth / 2, y: alignCoordinate ? this._viewPortHeight / 2 : -this._viewPortHeight / 2}, this._position, this._zoomLevel, this._rotation);\n const bottomRightCorner = convert2WorldSpaceAnchorAtCenter({x: this._viewPortWidth / 2, y: alignCoordinate ? this._viewPortHeight / 2 : -this._viewPortHeight / 2}, this._position, this._zoomLevel, this._rotation);\n\n return {\n top: {left: topLeftCorner, right: topRightCorner},\n bottom: {left: bottomLeftCorner, right: bottomRightCorner},\n }\n }\n\n /**\n * Calculates the axis-aligned bounding box (AABB) of the viewport in world space.\n *\n * @param alignCoordinate - If true, uses standard y-up coordinate system. If false, inverts y-axis\n * @returns Object with min and max points defining the AABB\n *\n * @remarks\n * This returns the smallest axis-aligned rectangle that contains the entire viewport.\n * When the camera is rotated, this AABB will be larger than the actual viewport.\n * For exact viewport bounds, use {@link viewPortInWorldSpace}.\n *\n * Useful for:\n * - Frustum culling (checking if objects are visible)\n * - Broad-phase collision detection\n * - Determining which tiles/chunks to load\n *\n * @example\n * ```typescript\n * const aabb = camera.viewPortAABB();\n * const isVisible = (\n * object.x >= aabb.min.x && object.x <= aabb.max.x &&\n * object.y >= aabb.min.y && object.y <= aabb.max.y\n * );\n * ```\n */\n viewPortAABB(alignCoordinate?: boolean): {min: Point, max: Point}{\n const {top: {left: topLeft, right: topRight}, bottom: {left: bottomLeft, right: bottomRight}} = this.viewPortInWorldSpace(alignCoordinate);\n\n return {\n min: {x: Math.min(topLeft.x, bottomLeft.x, topRight.x, bottomRight.x), y: Math.min(topLeft.y, bottomLeft.y, topRight.y, bottomRight.y)},\n max: {x: Math.max(topLeft.x, bottomLeft.x, topRight.x, bottomRight.x), y: Math.max(topLeft.y, bottomLeft.y, topRight.y, bottomRight.y)},\n };\n }\n}\n",
20
- "import { Point, PointCal } from '@ue-too/math';\nimport { Boundaries } from './utils/position';\nimport { TransformationMatrix } from './utils/matrix';\nimport { CameraUpdatePublisher, UnSubscribe } from './update-publisher';\nimport { ZoomLevelLimits } from './utils/zoom';\nimport { RotationLimits } from './utils/rotation';\nimport { convert2WorldSpaceAnchorAtCenter, convert2ViewPortSpaceAnchorAtCenter } from './utils/coordinate-conversion';\nimport { CameraEventMap, CameraState } from './update-publisher';\nimport { ObservableBoardCamera } from './interface';\nimport BaseCamera from './base';\nimport { SubscriptionOptions } from '../utils/observable';\n\n/** Default viewport width in CSS pixels */\nexport const DEFAULT_BOARD_CAMERA_VIEWPORT_WIDTH = 1000;\n\n/** Default viewport height in CSS pixels */\nexport const DEFAULT_BOARD_CAMERA_VIEWPORT_HEIGHT = 1000;\n\n/** Default zoom level constraints (0.1x to 10x) */\nexport const DEFAULT_BOARD_CAMERA_ZOOM_BOUNDARIES: ZoomLevelLimits = {min: 0.1, max: 10};\n\n/** Default position boundaries (±10000 on both axes) */\nexport const DEFAULT_BOARD_CAMERA_BOUNDARIES: Boundaries = {min: {x: -10000, y: -10000}, max: {x: 10000, y: 10000}};\n\n/** Default rotation boundaries (unrestricted) */\nexport const DEFAULT_BOARD_CAMERA_ROTATION_BOUNDARIES: RotationLimits | undefined = undefined;\n\n/**\n * Observable camera implementation that extends {@link BaseCamera} with event notification.\n * This is the recommended camera class for most applications.\n *\n * @remarks\n * DefaultBoardCamera wraps {@link BaseCamera} and adds an event system via {@link CameraUpdatePublisher}.\n * All camera state changes (pan, zoom, rotate) trigger corresponding events that observers can subscribe to.\n *\n * Use this class when you need to:\n * - React to camera changes in your UI or game logic\n * - Synchronize multiple systems with camera state\n * - Implement camera-dependent features (minimap, LOD, culling)\n *\n * For a non-observable camera without event overhead, use {@link BaseCamera} directly.\n *\n * @example\n * ```typescript\n * const camera = new DefaultBoardCamera(1920, 1080);\n *\n * // Subscribe to camera events\n * camera.on('zoom', (event, state) => {\n * console.log(`Zoomed by ${event.deltaZoomAmount}`);\n * console.log(`New zoom level: ${state.zoomLevel}`);\n * });\n *\n * camera.on('pan', (event, state) => {\n * console.log(`Panned by (${event.diff.x}, ${event.diff.y})`);\n * });\n *\n * // Camera updates trigger events\n * camera.setZoomLevel(2.0);\n * camera.setPosition({ x: 100, y: 200 });\n * ```\n *\n * @category Camera\n * @see {@link BaseCamera} for non-observable camera\n * @see {@link ObservableBoardCamera} for the interface definition\n */\nexport default class DefaultBoardCamera implements ObservableBoardCamera {\n\n private _baseCamera: BaseCamera;\n private _observer: CameraUpdatePublisher;\n /**\n * Creates a new observable camera with event notification capabilities.\n *\n * @param viewPortWidth - Width of the viewport in CSS pixels (default: 1000)\n * @param viewPortHeight - Height of the viewport in CSS pixels (default: 1000)\n * @param position - Initial camera position in world coordinates (default: {x: 0, y: 0})\n * @param rotation - Initial rotation in radians (default: 0)\n * @param zoomLevel - Initial zoom level (default: 1.0)\n * @param boundaries - Position constraints (default: ±10000 on both axes)\n * @param zoomLevelBoundaries - Zoom constraints (default: 0.1 to 10)\n * @param rotationBoundaries - Optional rotation constraints (default: unrestricted)\n *\n * @example\n * ```typescript\n * // Camera with default settings\n * const camera1 = new DefaultBoardCamera();\n *\n * // Camera with custom viewport\n * const camera2 = new DefaultBoardCamera(1920, 1080);\n *\n * // Camera with all options\n * const camera3 = new DefaultBoardCamera(\n * 1920, 1080,\n * { x: 0, y: 0 },\n * 0,\n * 1.0,\n * { min: { x: -5000, y: -5000 }, max: { x: 5000, y: 5000 } },\n * { min: 0.5, max: 4 },\n * { start: 0, end: Math.PI * 2 }\n * );\n * ```\n */\n constructor(viewPortWidth: number = DEFAULT_BOARD_CAMERA_VIEWPORT_WIDTH, viewPortHeight: number = DEFAULT_BOARD_CAMERA_VIEWPORT_HEIGHT, position: Point = {x: 0, y: 0}, rotation: number = 0, zoomLevel: number = 1, boundaries: Boundaries = DEFAULT_BOARD_CAMERA_BOUNDARIES, zoomLevelBoundaries: ZoomLevelLimits = DEFAULT_BOARD_CAMERA_ZOOM_BOUNDARIES, rotationBoundaries: RotationLimits | undefined = DEFAULT_BOARD_CAMERA_ROTATION_BOUNDARIES){\n this._baseCamera = new BaseCamera(viewPortWidth, viewPortHeight, position, rotation, zoomLevel, boundaries, zoomLevelBoundaries, rotationBoundaries);\n this._observer = new CameraUpdatePublisher();\n }\n\n /**\n * @description The boundaries of the camera in the world coordinate system.\n * \n * @category Camera\n */\n get boundaries(): Boundaries | undefined{\n return this._baseCamera.boundaries;\n }\n\n set boundaries(boundaries: Boundaries | undefined){\n this._baseCamera.boundaries = boundaries;\n }\n\n /**\n * @description The width of the viewport. (The width of the canvas in css pixels)\n * \n * @category Camera\n */\n get viewPortWidth(): number{\n return this._baseCamera.viewPortWidth;\n }\n\n set viewPortWidth(width: number){\n this._baseCamera.viewPortWidth = width;\n }\n\n /**\n * @description The height of the viewport. (The height of the canvas in css pixels)\n * \n * @category Camera\n */\n get viewPortHeight(): number{\n return this._baseCamera.viewPortHeight;\n }\n\n set viewPortHeight(height: number){\n this._baseCamera.viewPortHeight = height;\n }\n\n /**\n * @description The position of the camera in the world coordinate system.\n * \n * @category Camera\n */\n get position(): Point{\n return this._baseCamera.position;\n }\n\n /**\n * Sets the camera position and notifies observers if successful.\n *\n * @param destination - Target position in world coordinates\n * @returns True if position was updated, false if rejected by boundaries or negligible change\n *\n * @remarks\n * If the position changes, a 'pan' event is triggered with the position delta and new camera state.\n * All 'pan' and 'all' event subscribers will be notified.\n *\n * @example\n * ```typescript\n * camera.on('pan', (event, state) => {\n * console.log(`Camera moved by (${event.diff.x}, ${event.diff.y})`);\n * });\n *\n * camera.setPosition({ x: 100, y: 200 }); // Triggers pan event\n * ```\n */\n setPosition(destination: Point){\n const currentPosition = {...this._baseCamera.position};\n if(!this._baseCamera.setPosition(destination)){\n return false;\n }\n this._observer.notifyPan({diff: PointCal.subVector(destination, currentPosition)}, {position: this._baseCamera.position, rotation: this._baseCamera.rotation, zoomLevel: this._baseCamera.zoomLevel});\n return true;\n }\n\n /**\n * @description The zoom level of the camera.\n * \n * @category Camera\n */\n get zoomLevel(): number{\n return this._baseCamera.zoomLevel;\n }\n\n /**\n * @description The boundaries of the zoom level of the camera.\n * \n * @category Camera\n */\n get zoomBoundaries(): ZoomLevelLimits | undefined{\n return this._baseCamera.zoomBoundaries;\n }\n\n set zoomBoundaries(zoomBoundaries: ZoomLevelLimits | undefined){\n this._baseCamera.zoomBoundaries = zoomBoundaries;\n }\n\n setMaxZoomLevel(maxZoomLevel: number){\n const currentZoomLevel = this._baseCamera.zoomLevel;\n if(!this._baseCamera.setMaxZoomLevel(maxZoomLevel)){\n return false;\n }\n this._observer.notifyZoom({deltaZoomAmount: maxZoomLevel - currentZoomLevel}, {position: this._baseCamera.position, rotation: this._baseCamera.rotation, zoomLevel: this._baseCamera.zoomLevel});\n return true;\n }\n\n setMinZoomLevel(minZoomLevel: number){\n if(!this._baseCamera.setMinZoomLevel(minZoomLevel)){\n return false;\n }\n return true;\n }\n\n /**\n * Sets the camera zoom level and notifies observers if successful.\n *\n * @param zoomLevel - Target zoom level (1.0 = 100%, 2.0 = 200%, etc.)\n * @returns True if zoom was updated, false if outside boundaries or already at limit\n *\n * @remarks\n * If the zoom changes, a 'zoom' event is triggered with the zoom delta and new camera state.\n * All 'zoom' and 'all' event subscribers will be notified.\n *\n * @example\n * ```typescript\n * camera.on('zoom', (event, state) => {\n * console.log(`Zoom changed by ${event.deltaZoomAmount}`);\n * console.log(`New zoom: ${state.zoomLevel}`);\n * });\n *\n * camera.setZoomLevel(2.0); // Triggers zoom event\n * ```\n */\n setZoomLevel(zoomLevel: number){\n const currentZoomLevel = this._baseCamera.zoomLevel;\n if(!this._baseCamera.setZoomLevel(zoomLevel)){\n return false;\n }\n this._observer.notifyZoom({deltaZoomAmount: this._baseCamera.zoomLevel - currentZoomLevel}, {position: this._baseCamera.position, rotation: this._baseCamera.rotation, zoomLevel: this._baseCamera.zoomLevel});\n return true;\n }\n\n /**\n * Gets the current camera rotation in radians.\n *\n * @returns Current rotation angle (0 to 2π)\n */\n get rotation(): number{\n return this._baseCamera.rotation;\n }\n\n /**\n * @description The boundaries of the rotation of the camera.\n * \n * @category Camera\n */\n get rotationBoundaries(): RotationLimits | undefined{\n return this._baseCamera.rotationBoundaries;\n }\n\n set rotationBoundaries(rotationBoundaries: RotationLimits | undefined){\n this._baseCamera.rotationBoundaries = rotationBoundaries;\n }\n\n /**\n * @description The order of the transformation is as follows:\n * 1. Scale (scale the context using the device pixel ratio)\n * 2. Translation (move the origin of the context to the center of the canvas)\n * 3. Rotation (rotate the context negatively the rotation of the camera)\n * 4. Zoom (scale the context using the zoom level of the camera)\n * 5. Translation (move the origin of the context to the position of the camera in the context coordinate system)\n * \n * @param devicePixelRatio The device pixel ratio of the canvas\n * @param alignCoorindate Whether to align the coordinate system to the camera's position\n * @returns The transformation matrix\n */\n getTransform(devicePixelRatio: number = 1, alignCoorindate: boolean = true): TransformationMatrix {\n return this._baseCamera.getTransform(devicePixelRatio, alignCoorindate);\n }\n\n /**\n * Sets the camera rotation and notifies observers if successful.\n *\n * @param rotation - Target rotation in radians\n * @returns True if rotation was updated, false if outside boundaries or already at limit\n *\n * @remarks\n * If the rotation changes, a 'rotate' event is triggered with the rotation delta and new camera state.\n * All 'rotate' and 'all' event subscribers will be notified.\n * Rotation is automatically normalized to 0-2π range.\n *\n * @example\n * ```typescript\n * camera.on('rotate', (event, state) => {\n * console.log(`Camera rotated by ${event.deltaRotation} radians`);\n * });\n *\n * camera.setRotation(Math.PI / 4); // Triggers rotate event\n * ```\n */\n setRotation(rotation: number){\n const currentRotation = this._baseCamera.rotation;\n if(!this._baseCamera.setRotation(rotation)){\n return false;\n }\n this._observer.notifyRotate({deltaRotation: rotation - currentRotation}, {position: this._baseCamera.position, rotation: this._baseCamera.rotation, zoomLevel: this._baseCamera.zoomLevel});\n return true;\n }\n\n /**\n * @description The origin of the camera in the window coordinate system.\n * @deprecated\n * \n * @param centerInWindow The center of the camera in the window coordinate system.\n * @returns The origin of the camera in the window coordinate system.\n */\n getCameraOriginInWindow(centerInWindow: Point): Point{\n return centerInWindow;\n }\n\n /**\n * @description Converts a point from the viewport coordinate system to the world coordinate system.\n * \n * @param point The point in the viewport coordinate system.\n * @returns The point in the world coordinate system.\n */\n convertFromViewPort2WorldSpace(point: Point): Point{\n return convert2WorldSpaceAnchorAtCenter(point, this._baseCamera.position, this._baseCamera.zoomLevel, this._baseCamera.rotation);\n }\n\n /**\n * @description Converts a point from the world coordinate system to the viewport coordinate system.\n * \n * @param point The point in the world coordinate system.\n * @returns The point in the viewport coordinate system.\n */\n convertFromWorld2ViewPort(point: Point): Point{\n return convert2ViewPortSpaceAnchorAtCenter(point, this._baseCamera.position, this._baseCamera.zoomLevel, this._baseCamera.rotation);\n }\n\n /**\n * @description Inverts a point from the world coordinate system to the viewport coordinate system.\n * \n * @param point The point in the world coordinate system.\n * @returns The point in the viewport coordinate system.\n */\n invertFromWorldSpace2ViewPort(point: Point): Point{\n let cameraFrameCenter = {x: this._baseCamera.viewPortWidth / 2, y: this._baseCamera.viewPortHeight / 2};\n let delta2Point = PointCal.subVector(point, this._baseCamera.position);\n delta2Point = PointCal.rotatePoint(delta2Point, -this._baseCamera.rotation);\n delta2Point = PointCal.multiplyVectorByScalar(delta2Point, this._baseCamera.zoomLevel);\n return PointCal.addVector(cameraFrameCenter, delta2Point);\n }\n\n setHorizontalBoundaries(min: number, max: number){\n if (min > max){\n let temp = max;\n max = min;\n min = temp;\n }\n if(this._baseCamera.boundaries == undefined){\n this._baseCamera.boundaries = {min: undefined, max: undefined};\n }\n if(this._baseCamera.boundaries.min == undefined){\n this._baseCamera.boundaries.min = {x: undefined, y: undefined};\n }\n if(this._baseCamera.boundaries.max == undefined){\n this._baseCamera.boundaries.max = {x: undefined, y: undefined};\n }\n this._baseCamera.boundaries.min.x = min;\n this._baseCamera.boundaries.max.x = max;\n //NOTE leave for future optimization when setting the boundaries if the camera lies outside the boundaries clamp the position of the camera\n // if(!this.withinBoundaries(this.position)){\n // this.position = this.clampPoint(this.position);\n // }\n }\n\n setVerticalBoundaries(min: number, max: number){\n if (min > max){\n let temp = max;\n max = min;\n min = temp;\n }\n if(this._baseCamera.boundaries == undefined){\n this._baseCamera.boundaries = {min: undefined, max: undefined};\n }\n if(this._baseCamera.boundaries.min == undefined){\n this._baseCamera.boundaries.min = {x: undefined, y: undefined};\n }\n if(this._baseCamera.boundaries.max == undefined){\n this._baseCamera.boundaries.max = {x: undefined, y: undefined};\n }\n this._baseCamera.boundaries.min.y = min;\n this._baseCamera.boundaries.max.y = max;\n }\n\n /**\n * Subscribes to camera events with optional AbortController for cancellation.\n *\n * @typeParam K - The event type key from CameraEventMap\n * @param eventName - Event type to listen for: 'pan', 'zoom', 'rotate', or 'all'\n * @param callback - Function called when event occurs, receives event data and camera state\n * @param options - Optional subscription configuration including AbortController signal\n * @returns Function to unsubscribe from this event\n *\n * @remarks\n * Available events:\n * - 'pan': Triggered when camera position changes\n * - 'zoom': Triggered when zoom level changes\n * - 'rotate': Triggered when rotation changes\n * - 'all': Triggered for any camera change (pan, zoom, or rotate)\n *\n * Use the AbortController pattern to manage multiple subscriptions:\n *\n * @example\n * ```typescript\n * // Basic subscription\n * const unsubscribe = camera.on('pan', (event, state) => {\n * console.log(`Panned by (${event.diff.x}, ${event.diff.y})`);\n * console.log(`New position: (${state.position.x}, ${state.position.y})`);\n * });\n *\n * // Later: unsubscribe\n * unsubscribe();\n *\n * // Subscribe to all events\n * camera.on('all', (event, state) => {\n * if (event.type === 'pan') {\n * console.log('Pan event:', event.diff);\n * } else if (event.type === 'zoom') {\n * console.log('Zoom event:', event.deltaZoomAmount);\n * } else if (event.type === 'rotate') {\n * console.log('Rotate event:', event.deltaRotation);\n * }\n * });\n *\n * // Using AbortController for batch unsubscribe\n * const controller = new AbortController();\n * camera.on('pan', handlePan, { signal: controller.signal });\n * camera.on('zoom', handleZoom, { signal: controller.signal });\n * camera.on('rotate', handleRotate, { signal: controller.signal });\n *\n * // Unsubscribe all at once\n * controller.abort();\n * ```\n */\n on<K extends keyof CameraEventMap>(eventName: K, callback: (event: CameraEventMap[K], cameraState: CameraState)=>void, options?: SubscriptionOptions): UnSubscribe {\n return this._observer.on(eventName, callback, options);\n }\n\n getTRS(devicePixelRatio: number = 1, alignCoordinateSystem: boolean = true): {scale: {x: number, y: number}, rotation: number, translation: {x: number, y: number}, cached: boolean} {\n return this._baseCamera.getTRS(devicePixelRatio, alignCoordinateSystem);\n }\n\n setUsingTransformationMatrix(transformationMatrix: TransformationMatrix, devicePixelRatio: number = 1){\n this._baseCamera.setUsingTransformationMatrix(transformationMatrix, devicePixelRatio);\n }\n\n viewPortInWorldSpace(alignCoordinate: boolean = true): {top: {left: Point, right: Point}, bottom: {left: Point, right: Point}}{\n return this._baseCamera.viewPortInWorldSpace(alignCoordinate);\n }\n\n viewPortAABB(alignCoordinate: boolean = true): {min: Point, max: Point}{\n return this._baseCamera.viewPortAABB(alignCoordinate);\n }\n}\n",
21
- "import type { EventArgs } from \"@ue-too/being\";\nimport type { KmtInputEventMapping, KmtInputStateMachine } from \"../../input-interpretation/input-state-machine\";\nimport type { InputOrchestrator } from \"../input-orchestrator\";\n\n/**\n * Interface for KMT (Keyboard/Mouse/Trackpad) event parsers.\n *\n * @remarks\n * Event parsers bridge the gap between DOM events and the state machine.\n * They listen for raw DOM events, convert them to state machine events,\n * and coordinate with the orchestrator for output processing.\n *\n * @category Raw Input Parser\n */\nexport interface KMTEventParser {\n /** Whether the parser is currently disabled */\n disabled: boolean;\n /** Initializes event listeners */\n setUp(): void;\n /** Removes event listeners and cleans up */\n tearDown(): void;\n /** Attaches to a new canvas element */\n attach(canvas: HTMLCanvasElement): void;\n /** The state machine that processes parsed events */\n stateMachine: KmtInputStateMachine;\n /** The orchestrator that handles state machine outputs */\n orchestrator: InputOrchestrator;\n}\n\n/**\n * Minimal pointer event interface for framework interoperability.\n *\n * @remarks\n * This subset of the DOM PointerEvent interface allows the parser to work with\n * both vanilla JavaScript PointerEvents and framework-wrapped events (e.g., PixiJS).\n *\n * @category Raw Input Parser\n */\nexport type MinimumPointerEvent = {\n /** Mouse button number (0=left, 1=middle, 2=right) */\n button: number;\n /** Pointer type (\"mouse\", \"pen\", \"touch\") */\n pointerType: string;\n /** X coordinate in window space */\n clientX: number;\n /** Y coordinate in window space */\n clientY: number;\n /** Bitmask of currently pressed buttons */\n buttons: number;\n}\n\n/**\n * Minimal wheel event interface for framework interoperability.\n *\n * @remarks\n * This subset of the DOM WheelEvent interface allows the parser to work with\n * both vanilla JavaScript WheelEvents and framework-wrapped events.\n *\n * @category Raw Input Parser\n */\nexport type MinimumWheelEvent = {\n /** Prevents default scroll behavior */\n preventDefault: () => void;\n /** Horizontal scroll delta */\n deltaX: number;\n /** Vertical scroll delta */\n deltaY: number;\n /** Whether Ctrl key is pressed (for zoom) */\n ctrlKey: boolean;\n /** X coordinate in window space */\n clientX: number;\n /** Y coordinate in window space */\n clientY: number;\n}\n\n/**\n * Minimal keyboard event interface for framework interoperability.\n *\n * @remarks\n * This subset of the DOM KeyboardEvent interface allows the parser to work with\n * both vanilla JavaScript KeyboardEvents and framework-wrapped events.\n *\n * @category Raw Input Parser\n */\nexport type MinimumKeyboardEvent = {\n /** Prevents default keyboard behavior */\n preventDefault: () => void;\n /** The key that was pressed */\n key: string;\n};\n\n/**\n * Minimal event target interface for framework interoperability.\n *\n * @remarks\n * This interface allows the parser to attach event listeners to different\n * types of event targets (HTMLElement, Canvas, PixiJS Container, etc.).\n *\n * @category Raw Input Parser\n */\nexport type EventTargetWithPointerEvents = {\n addEventListener: (type: string, listener: (event: any) => void, options?: {passive: boolean}) => void;\n removeEventListener: (type: string, listener: (event: any) => void) => void;\n};\n\n\n/**\n * DOM event parser for Keyboard/Mouse/Trackpad input.\n *\n * @remarks\n * This parser converts raw DOM events into state machine events and coordinates with\n * the orchestrator to process outputs. It serves as the entry point for all KMT input\n * in the input interpretation pipeline.\n *\n * **Event Flow**:\n * ```\n * DOM Events → Parser → State Machine → Parser → Orchestrator → Camera/Observers\n * ```\n *\n * **Responsibilities**:\n * 1. Listen for DOM pointer, wheel, and keyboard events\n * 2. Convert DOM events to state machine event format\n * 3. Send events to the state machine\n * 4. Forward state machine outputs to the orchestrator\n *\n * **Handled DOM Events**:\n * - pointerdown/up/move (canvas-scoped)\n * - wheel (canvas-scoped)\n * - keydown/up (window-scoped for spacebar)\n *\n * **Keyboard Handling**:\n * Keyboard events are only processed when `document.body` is the target,\n * preventing interference with text inputs and other UI elements.\n *\n * The parser can be disabled to temporarily stop input processing (e.g., during\n * modal dialogs or animations).\n *\n * @category Raw Input Parser\n *\n * @example\n * ```typescript\n * const canvasElement = document.getElementById(\"canvas\");\n * const stateMachine = createKmtInputStateMachine(context);\n * const orchestrator = new InputOrchestrator(cameraMux, cameraRig, publisher);\n * const parser = new VanillaKMTEventParser(stateMachine, orchestrator, canvasElement);\n *\n * parser.setUp(); // Starts listening for events\n *\n * // Later, to disable input temporarily\n * parser.disabled = true;\n *\n * // Cleanup when done\n * parser.tearDown();\n * ```\n */\nexport class VanillaKMTEventParser implements KMTEventParser {\n\n private _disabled: boolean = false;\n private _stateMachine: KmtInputStateMachine;\n private _orchestrator: InputOrchestrator;\n private _keyfirstPressed: Map<string, boolean>;\n private _abortController: AbortController;\n private _canvas?: HTMLCanvasElement | SVGSVGElement;\n\n\n constructor(kmtInputStateMachine: KmtInputStateMachine, orchestrator: InputOrchestrator, canvas?: HTMLCanvasElement | SVGSVGElement){\n this._canvas = canvas;\n this.bindFunctions();\n this._abortController = new AbortController();\n this._stateMachine = kmtInputStateMachine;\n this._orchestrator = orchestrator;\n this._keyfirstPressed = new Map();\n }\n\n get disabled(): boolean {\n return this._disabled;\n }\n\n set disabled(value: boolean){\n this._disabled = value;\n }\n\n get stateMachine(): KmtInputStateMachine {\n return this._stateMachine;\n }\n\n get orchestrator(): InputOrchestrator {\n return this._orchestrator;\n }\n\n addEventListeners(signal: AbortSignal){\n if(this._canvas == undefined){\n return;\n }\n this._canvas.addEventListener('pointerdown', this.pointerDownHandler as EventListener, {signal});\n this._canvas.addEventListener('pointerup', this.pointerUpHandler as EventListener, {signal});\n this._canvas.addEventListener('pointermove', this.pointerMoveHandler as EventListener, {signal});\n this._canvas.addEventListener('wheel', this.scrollHandler as EventListener, {signal});\n window.addEventListener('keydown', this.keypressHandler, {signal});\n window.addEventListener('keyup', this.keyupHandler, {signal});\n }\n \n setUp(): void {\n if(this._abortController.signal.aborted){\n this._abortController = new AbortController();\n }\n this.addEventListeners(this._abortController.signal);\n }\n\n tearDown(): void {\n this._abortController.abort();\n this._abortController = new AbortController();\n this._canvas = undefined;\n }\n\n bindFunctions(): void {\n this.pointerDownHandler = this.pointerDownHandler.bind(this);\n this.pointerUpHandler = this.pointerUpHandler.bind(this);\n this.pointerMoveHandler = this.pointerMoveHandler.bind(this);\n this.scrollHandler = this.scrollHandler.bind(this);\n this.keypressHandler = this.keypressHandler.bind(this);\n this.keyupHandler = this.keyupHandler.bind(this);\n }\n\n private processEvent<K extends keyof KmtInputEventMapping>(\n ...args: EventArgs<KmtInputEventMapping, K>\n ): void {\n const result = this._stateMachine.happens(...args);\n if (result.handled && \"output\" in result) {\n this._orchestrator.processInputEventOutput(result.output);\n }\n }\n\n pointerDownHandler(e: PointerEvent){\n if(this._disabled){\n return;\n }\n if(e.button === 0 && e.pointerType === \"mouse\"){\n this.processEvent(\"leftPointerDown\", {x: e.clientX, y: e.clientY});\n return;\n }\n if(e.button === 1 && e.pointerType === \"mouse\"){\n this.processEvent(\"middlePointerDown\", {x: e.clientX, y: e.clientY});\n return;\n }\n }\n\n pointerUpHandler(e: PointerEvent){\n if(this._disabled){\n return;\n }\n if(e.button === 0 && e.pointerType === \"mouse\"){\n this.processEvent(\"leftPointerUp\", {x: e.clientX, y: e.clientY});\n return;\n }\n if(e.button === 1 && e.pointerType === \"mouse\"){\n this.processEvent(\"middlePointerUp\", {x: e.clientX, y: e.clientY});\n return;\n }\n }\n\n pointerMoveHandler(e: PointerEvent){\n if(this._disabled){\n return;\n }\n if((e.buttons === 1) && e.pointerType === \"mouse\"){\n this.processEvent(\"leftPointerMove\", {x: e.clientX, y: e.clientY});\n return;\n }\n if((e.buttons === 4) && e.pointerType === \"mouse\"){\n this.processEvent(\"middlePointerMove\", {x: e.clientX, y: e.clientY});\n return;\n }\n this.processEvent(\"pointerMove\", {x: e.clientX, y: e.clientY});\n }\n\n scrollHandler(e: WheelEvent){\n if(this._disabled) return;\n e.preventDefault();\n if(e.ctrlKey){\n this.processEvent(\"scrollWithCtrl\", {x: e.clientX, y: e.clientY, deltaX: e.deltaX, deltaY: e.deltaY});\n } else {\n this.processEvent(\"scroll\", {x: e.clientX, y: e.clientY, deltaX: e.deltaX, deltaY: e.deltaY});\n }\n }\n\n keypressHandler(e: KeyboardEvent){\n if(e.target !== document.body){\n return;\n }\n if(this._keyfirstPressed.has(e.key)){\n return;\n }\n this._keyfirstPressed.set(e.key, true);\n if(e.key === \" \"){\n this.processEvent(\"spacebarDown\");\n }\n }\n\n keyupHandler(e: KeyboardEvent){\n if(this._keyfirstPressed.has(e.key)){\n this._keyfirstPressed.delete(e.key);\n }\n if(e.key === \" \"){\n this.processEvent(\"spacebarUp\");\n }\n }\n\n attach(canvas: HTMLCanvasElement){\n this.tearDown();\n this._canvas = canvas;\n this.setUp();\n }\n}\n",
22
- "import { TouchEventMapping, TouchInputStateMachine } from \"../../input-interpretation/input-state-machine/touch-input-state-machine\";\nimport { TouchPoints } from \"../../input-interpretation/input-state-machine/touch-input-context\";\nimport type { InputOrchestrator } from \"../input-orchestrator\";\nimport { EventArgs } from \"@ue-too/being\";\n\n/**\n * Interface for touch event parsers.\n *\n * @remarks\n * Touch event parsers bridge DOM TouchEvents and the touch state machine.\n * They provide granular control over which gesture types are enabled.\n *\n * @category Raw Input Parser\n */\nexport interface TouchEventParser {\n /** Whether all touch input is disabled */\n disabled: boolean;\n /** Whether pan gestures are disabled */\n panDisabled: boolean;\n /** Whether zoom gestures are disabled */\n zoomDisabled: boolean;\n /** Whether rotation gestures are disabled (currently unused) */\n rotateDisabled: boolean;\n /** Initializes event listeners */\n setUp(): void;\n /** Removes event listeners and cleans up */\n tearDown(): void;\n /** Attaches to a new canvas element */\n attach(canvas: HTMLCanvasElement): void;\n /** The state machine that processes parsed events */\n stateMachine: TouchInputStateMachine;\n /** The orchestrator that handles state machine outputs */\n orchestrator: InputOrchestrator;\n}\n\n/**\n * DOM event parser for touch input.\n *\n * @remarks\n * This parser converts raw DOM TouchEvents into state machine events and coordinates\n * with the orchestrator to process outputs. It serves as the entry point for all touch\n * input in the input interpretation pipeline.\n *\n * **Event Flow**:\n * ```\n * DOM TouchEvents → Parser → State Machine → Parser → Orchestrator → Camera/Observers\n * ```\n *\n * **Responsibilities**:\n * 1. Listen for DOM touch events (touchstart/move/end/cancel)\n * 2. Extract touch point data (identifier, x, y)\n * 3. Convert to state machine event format\n * 4. Send events to the state machine\n * 5. Forward state machine outputs to the orchestrator\n *\n * **Touch Point Extraction**:\n * - touchstart/touchend: Uses `changedTouches` (only new/removed touches)\n * - touchmove: Uses `targetTouches` (all touches on the canvas)\n *\n * **Gesture Control**:\n * Individual gesture types (pan, zoom, rotate) can be disabled independently,\n * though currently the state machine outputs are filtered by the orchestrator\n * rather than the parser.\n *\n * The parser prevents default touch behavior to avoid browser scroll/zoom\n * interfering with canvas gestures.\n *\n * @category Raw Input Parser\n *\n * @example\n * ```typescript\n * const canvasElement = document.getElementById(\"canvas\");\n * const stateMachine = createTouchInputStateMachine(context);\n * const orchestrator = new InputOrchestrator(cameraMux, cameraRig, publisher);\n * const parser = new VanillaTouchEventParser(stateMachine, orchestrator, canvasElement);\n *\n * parser.setUp(); // Starts listening for touch events\n *\n * // Disable zoom gestures temporarily\n * parser.zoomDisabled = true;\n *\n * // Cleanup when done\n * parser.tearDown();\n * ```\n */\nexport class VanillaTouchEventParser implements TouchEventParser {\n\n private _canvas?: HTMLCanvasElement;\n private _disabled: boolean;\n private _panDisabled: boolean = false;\n private _zoomDisabled: boolean = false;\n private _rotateDisabled: boolean = false;\n\n private _stateMachine: TouchInputStateMachine;\n private _orchestrator: InputOrchestrator;\n\n private _abortController: AbortController;\n\n constructor(touchInputStateMachine: TouchInputStateMachine, orchestrator: InputOrchestrator, canvas?: HTMLCanvasElement){\n this._canvas = canvas;\n this._disabled = false;\n this._stateMachine = touchInputStateMachine;\n this._orchestrator = orchestrator;\n this._abortController = new AbortController();\n\n this.bindListeners();\n }\n\n get stateMachine(): TouchInputStateMachine {\n return this._stateMachine;\n }\n\n get orchestrator(): InputOrchestrator {\n return this._orchestrator;\n }\n\n get touchStateMachine(): TouchInputStateMachine {\n return this._stateMachine;\n }\n\n bindListeners(): void{\n this.touchstartHandler = this.touchstartHandler.bind(this);\n this.touchendHandler = this.touchendHandler.bind(this);\n this.touchcancelHandler = this.touchcancelHandler.bind(this);\n this.touchmoveHandler = this.touchmoveHandler.bind(this);\n }\n\n enableStrategy(): void {\n this._disabled = false;\n }\n\n disableStrategy(): void {\n this._disabled = true;\n }\n\n setUp(): void {\n if(this._canvas == undefined){\n return;\n }\n if(this._abortController.signal.aborted){\n this._abortController = new AbortController();\n }\n this._canvas.addEventListener('touchstart', this.touchstartHandler, {signal: this._abortController.signal});\n this._canvas.addEventListener('touchend', this.touchendHandler, {signal: this._abortController.signal});\n this._canvas.addEventListener('touchcancel', this.touchcancelHandler, {signal: this._abortController.signal});\n this._canvas.addEventListener('touchmove', this.touchmoveHandler, {signal: this._abortController.signal});\n }\n\n tearDown(): void {\n this._abortController.abort();\n this._abortController = new AbortController();\n this._canvas = undefined;\n }\n\n get disabled(): boolean {\n return this._disabled;\n }\n\n get panDisabled(): boolean {\n return this._panDisabled;\n }\n\n set panDisabled(panDisabled: boolean){\n this._panDisabled = panDisabled;\n }\n\n get zoomDisabled(): boolean {\n return this._zoomDisabled;\n }\n\n set zoomDisabled(zoomDisabled: boolean){\n this._zoomDisabled = zoomDisabled;\n }\n\n get rotateDisabled(): boolean {\n return this._rotateDisabled;\n }\n\n set rotateDisabled(rotateDisabled: boolean){\n this._rotateDisabled = rotateDisabled;\n }\n\n private processEvent<K extends keyof TouchEventMapping>(\n ...args: EventArgs<TouchEventMapping, K>\n ): void {\n const result = this._stateMachine.happens(...args);\n if (result.handled && \"output\" in result) {\n this._orchestrator.processInputEventOutput(result.output);\n }\n }\n\n touchstartHandler(e: TouchEvent){\n if(this._disabled) {\n return;\n }\n\n const pointsAdded: TouchPoints[] = [];\n for (let i = 0; i < e.changedTouches.length; i++) {\n pointsAdded.push({ident: e.changedTouches[i].identifier, x: e.changedTouches[i].clientX, y: e.changedTouches[i].clientY});\n }\n this.processEvent(\"touchstart\", {points: pointsAdded});\n e.preventDefault();\n }\n\n touchcancelHandler(e: TouchEvent){\n if(this._disabled) {\n return;\n }\n const pointsRemoved: TouchPoints[] = [];\n for (let i = 0; i < e.changedTouches.length; i++) {\n pointsRemoved.push({ident: e.changedTouches[i].identifier, x: e.changedTouches[i].clientX, y: e.changedTouches[i].clientY});\n }\n this.processEvent(\"touchend\", {points: pointsRemoved});\n }\n\n touchendHandler(e: TouchEvent){\n if(this._disabled) {\n return;\n }\n const pointsRemoved: TouchPoints[] = [];\n for (let i = 0; i < e.changedTouches.length; i++) {\n pointsRemoved.push({ident: e.changedTouches[i].identifier, x: e.changedTouches[i].clientX, y: e.changedTouches[i].clientY});\n }\n this.processEvent(\"touchend\", {points: pointsRemoved});\n }\n\n touchmoveHandler(e: TouchEvent){\n if(this._disabled) {\n return;\n }\n e.preventDefault();\n const pointsMoved: TouchPoints[] = [];\n for (let i = 0; i < e.targetTouches.length; i++) {\n pointsMoved.push({ident: e.targetTouches[i].identifier, x: e.targetTouches[i].clientX, y: e.targetTouches[i].clientY});\n }\n this.processEvent(\"touchmove\", {points: pointsMoved});\n }\n\n attach(canvas: HTMLCanvasElement){\n this.tearDown();\n this._canvas = canvas;\n this.setUp();\n }\n}\n",
23
- "import { Point, PointCal } from \"@ue-too/math\";\nimport { Canvas } from \"../../input-interpretation/input-state-machine/kmt-input-context\";\n\n/**\n * Converts a point from browser window coordinates to canvas coordinates.\n *\n * @param pointInWindow - The point in window coordinates (relative to browser viewport)\n * @param canvas - The canvas object containing position information\n * @returns The point in canvas coordinates (relative to canvas element)\n *\n * @remarks\n * Window coordinates are relative to the browser's viewport (top-left = 0,0).\n * Canvas coordinates are relative to the canvas element's top-left corner.\n *\n * This conversion is essential for processing mouse and touch events, which\n * provide coordinates relative to the window, not the canvas element.\n *\n * The conversion simply subtracts the canvas position from the window position:\n * ```\n * canvasPoint = windowPoint - canvasPosition\n * ```\n *\n * Note: This function expects the canvas object to have a `position` property\n * containing the canvas element's position in window coordinates (typically\n * from getBoundingClientRect()).\n *\n * @example\n * ```typescript\n * // Mouse click at window position (500, 300)\n * const clickPos = { x: 500, y: 300 };\n *\n * // Canvas positioned at (100, 50) in window\n * const canvas = {\n * position: { x: 100, y: 50 },\n * width: 800,\n * height: 600\n * };\n *\n * const canvasPos = convertFromWindow2Canvas(clickPos, canvas);\n * // Result: { x: 400, y: 250 }\n * // (500 - 100 = 400, 300 - 50 = 250)\n * ```\n *\n * @category Coordinate Conversion\n * @see {@link convertFromCanvas2Window} for inverse conversion\n */\nexport function convertFromWindow2Canvas(pointInWindow: Point, canvas: Canvas): Point {\n return PointCal.subVector(pointInWindow, canvas.position);\n}\n\n/**\n * Converts a point from canvas coordinates to browser window coordinates.\n *\n * @param pointInCanvas - The point in canvas coordinates (relative to canvas element)\n * @param canvas - The canvas object containing position information\n * @returns The point in window coordinates (relative to browser viewport)\n *\n * @remarks\n * This is the inverse of {@link convertFromWindow2Canvas}. It translates canvas-relative\n * coordinates to window-relative coordinates.\n *\n * The conversion adds the canvas position to the canvas-relative point:\n * ```\n * windowPoint = canvasPoint + canvasPosition\n * ```\n *\n * This is useful for positioning DOM elements (like tooltips or menus) at specific\n * canvas coordinates, as DOM elements use window coordinates.\n *\n * @example\n * ```typescript\n * // Point on canvas at (400, 250)\n * const canvasPos = { x: 400, y: 250 };\n *\n * // Canvas positioned at (100, 50) in window\n * const canvas = {\n * position: { x: 100, y: 50 },\n * width: 800,\n * height: 600\n * };\n *\n * const windowPos = convertFromCanvas2Window(canvasPos, canvas);\n * // Result: { x: 500, y: 300 }\n * // (400 + 100 = 500, 250 + 50 = 300)\n *\n * // Use for positioning a tooltip\n * tooltip.style.left = `${windowPos.x}px`;\n * tooltip.style.top = `${windowPos.y}px`;\n * ```\n *\n * @category Coordinate Conversion\n * @see {@link convertFromWindow2Canvas} for inverse conversion\n */\nexport function convertFromCanvas2Window(pointInCanvas: Point, canvas: Canvas): Point {\n return PointCal.addVector(pointInCanvas, canvas.position);\n}\n\n",
24
- "import { Point } from \"@ue-too/math\";\nimport { Canvas } from \"../input-interpretation/input-state-machine/kmt-input-context\";\nimport { convertFromWindow2Canvas } from \"./coordinate-conversions/window-canvas\";\nimport { convertFromCanvas2ViewPort } from \"./coordinate-conversions/canvas-viewport\";\n\n/**\n * Converts an isometric 3D point to a flat 2D world point.\n *\n * @param point - The 3D point in isometric space (with optional z coordinate)\n * @returns The 2D point in flat world coordinates\n *\n * @remarks\n * This function performs an isometric projection transformation, converting 3D\n * coordinates to 2D using standard isometric angles (30 degrees).\n *\n * The transformation uses:\n * - cos(30°) ≈ 0.866 for x-axis projection\n * - cos(60°) = 0.5 for y-axis projection\n * - Z-coordinate is added directly to the y-axis (height)\n *\n * Mathematical formulas:\n * ```\n * x_2d = (x_3d * cos30) - (y_3d * cos30)\n * y_2d = (x_3d * cos60) + (y_3d * cos60) + z_3d\n * ```\n *\n * This creates the classic isometric diamond grid appearance where:\n * - Moving along +X goes down-right\n * - Moving along +Y goes down-left\n * - Moving along +Z goes straight up\n *\n * @example\n * ```typescript\n * // Convert a 3D cube corner to 2D isometric projection\n * const point3D = { x: 10, y: 10, z: 5 };\n * const point2D = pointConversion(point3D);\n * // Result: { x: 0, y: 15 }\n * // x: (10 * 0.866) - (10 * 0.866) = 0\n * // y: (10 * 0.5) + (10 * 0.5) + 5 = 15\n *\n * // 2D point without z-coordinate\n * const flatPoint = { x: 20, y: 0 };\n * const projected = pointConversion(flatPoint);\n * // Result: { x: 17.32, y: 10 }\n * ```\n *\n * @category Coordinate Conversion\n */\nexport function pointConversion(point: Point) {\n const cos30 = Math.cos(Math.PI / 6);\n const cos60 = Math.cos(Math.PI / 3);\n\n return {\n x: point.x * cos30 - point.y * cos30,\n y: point.x * cos60 + point.y * cos60 + (point.z ?? 0)\n }\n}\n\n/**\n * Converts a point from window coordinates to viewport coordinates in one step.\n *\n * @param point - The point in window coordinates (browser viewport)\n * @param canvas - The canvas object with position and dimensions\n * @param viewportOriginInCanvasSpace - Viewport origin in canvas space (default: canvas center)\n * @param viewportHasFlippedYAxis - Whether viewport uses mathematical y-axis (default: false)\n * @returns The point in viewport coordinates\n *\n * @remarks\n * This is a convenience function that combines two conversions:\n * 1. Window to Canvas: {@link convertFromWindow2Canvas}\n * 2. Canvas to Viewport: {@link convertFromCanvas2ViewPort}\n *\n * It's particularly useful for processing input events (mouse clicks, touches)\n * that need to be converted directly to viewport space for interaction handling.\n *\n * The default viewport origin is the canvas center, which is common for\n * mathematical/engineering applications where (0,0) should be in the middle.\n *\n * @example\n * ```typescript\n * // Mouse click event\n * const clickPos = { x: event.clientX, y: event.clientY };\n *\n * const canvas = {\n * position: { x: 100, y: 50 },\n * width: 800,\n * height: 600\n * };\n *\n * // Convert to centered viewport with y-up\n * const viewportPos = convertFromWindow2ViewPortWithCanvasOperator(\n * clickPos,\n * canvas,\n * { x: 400, y: 300 }, // center of canvas\n * true // mathematical coordinates\n * );\n *\n * // viewportPos is now relative to viewport center with y-up\n * ```\n *\n * @category Coordinate Conversion\n * @see {@link convertFromWindow2Canvas} for window to canvas conversion\n * @see {@link convertFromCanvas2ViewPort} for canvas to viewport conversion\n */\nexport function convertFromWindow2ViewPortWithCanvasOperator(point: Point, canvas: Canvas, viewportOriginInCanvasSpace: Point = {x: canvas.width / 2, y: canvas.height / 2}, viewportHasFlippedYAxis: boolean = false): Point {\n const pointInCanvas = convertFromWindow2Canvas(point, canvas);\n return convertFromCanvas2ViewPort(pointInCanvas, viewportOriginInCanvasSpace, viewportHasFlippedYAxis);\n}",
25
- "/**\n * @description Type definition for a handler function that takes a generic value and additional arguments\n * The handler must return the same type as its first argument\n * This is a utility type to be used in the handler pipeline. (Probably don't need to use this directly)\n * Using the {@link createHandlerChain} function to create a handler chain would have typescript infer the correct type for the handler chain.\n * \n * @category Utils\n */\nexport type Handler<T, Args extends any[]> = (value: T, ...args: Args) => T;\n\n/**\n * @description Creates a handler chain from an array of handlers.\n * \n * Use it like this:\n * ```typescript\n * const handlerChain = createHandlerChain(handler1, handler2, handler3);\n * ```\n * or like this:\n * ```typescript\n * const handlers = [handler1, handler2, handler3];\n * const handlerChain = createHandlerChain(handlers);\n * ```\n * \n * The function signature of all the handlers must be the same. (if they're not, you need to explicitly specify the type for the handler chain)\n * \n * @param handlers Array of handler functions to be chained\n * @returns A single handler function that executes all handlers in sequence\n * \n * @category Utils\n */\nexport function createHandlerChain<T, Args extends any[]>(\n ...handlers: Handler<T, Args>[] | [Handler<T, Args>[]]\n): Handler<T, Args> {\n const normalizedHandlers = Array.isArray(handlers[0]) ? handlers[0] : handlers as Handler<T, Args>[];\n return (value: T, ...args: Args): T => {\n return normalizedHandlers.reduce(\n (acc, handler) => handler(acc, ...args),\n value\n );\n };\n}\n",
26
- "import { Observer, SubscriptionOptions, SynchronousObservable } from \"../utils/observable\";\n\n/**\n * Monitors and publishes position and dimension changes for SVG elements.\n *\n * @remarks\n * This class tracks SVG element position and dimensions using multiple browser APIs\n * to ensure comprehensive detection of all changes:\n * - ResizeObserver: Detects size changes\n * - IntersectionObserver: Detects visibility and position changes\n * - MutationObserver: Detects attribute changes (width, height, style)\n * - Window scroll/resize events: Detects changes from page layout\n *\n * The reported DOMRect excludes padding and borders to provide the actual\n * content dimensions using {@link getTrueRect}.\n *\n * Position and dimension changes are published synchronously to all subscribers,\n * ensuring immediate updates for coordinate transformations and rendering logic.\n *\n * @example\n * ```typescript\n * const svg = document.querySelector('svg');\n * const publisher = new SvgPositionDimensionPublisher(svg);\n *\n * // Subscribe to position/dimension updates\n * publisher.onPositionUpdate((rect) => {\n * console.log(`SVG at (${rect.x}, ${rect.y}) with size ${rect.width}x${rect.height}`);\n * });\n *\n * // Clean up when done\n * publisher.dispose();\n * ```\n *\n * @category Canvas Position\n */\nexport class SvgPositionDimensionPublisher {\n\n private lastRect?: DOMRect;\n private resizeObserver: ResizeObserver;\n private intersectionObserver: IntersectionObserver;\n private mutationObserver: MutationObserver;\n private scrollHandler?: (() => void);\n private resizeHandler?: (() => void);\n private _observers: SynchronousObservable<[DOMRect]>;\n\n /**\n * Creates a new SVG position/dimension publisher.\n *\n * @param canvas - Optional SVG element to immediately attach to\n *\n * @remarks\n * If a canvas is provided, observers are immediately attached and monitoring begins.\n * Otherwise, call {@link attach} later to begin monitoring.\n */\n constructor(canvas?: SVGSVGElement) {\n this._observers = new SynchronousObservable<[DOMRect]>();\n\n this.resizeObserver = new ResizeObserver(((entries: ResizeObserverEntry[]) => {\n for (const entry of entries) {\n const newRect = entry.target.getBoundingClientRect();\n const trueRect = getTrueRect(newRect, window.getComputedStyle(entry.target));\n if (rectChanged(this.lastRect, trueRect)) {\n this.publishPositionUpdate(trueRect);\n this.lastRect = trueRect;\n }\n }\n }).bind(this));\n\n this.intersectionObserver = new IntersectionObserver(((entries: IntersectionObserverEntry[]) => {\n if(this.lastRect === undefined){\n return;\n }\n for (const entry of entries) {\n if (entry.isIntersecting) {\n const newRect = entry.boundingClientRect;\n const trueRect = getTrueRect(newRect, window.getComputedStyle(entry.target));\n if (rectChanged(this.lastRect, trueRect)) {\n this.publishPositionUpdate(trueRect);\n this.lastRect = trueRect;\n }\n }\n }\n }).bind(this));\n\n this.attributeCallBack = this.attributeCallBack.bind(this);\n this.mutationObserver = new MutationObserver(this.attributeCallBack);\n\n if(canvas){\n this.attach(canvas);\n }\n }\n \n /**\n * Cleans up all observers and event listeners.\n *\n * @remarks\n * Disconnects all observers (ResizeObserver, IntersectionObserver, MutationObserver)\n * and removes window event listeners (scroll, resize). Always call this method\n * when the publisher is no longer needed to prevent memory leaks.\n */\n public dispose(): void {\n this.resizeObserver.disconnect();\n this.intersectionObserver.disconnect();\n this.mutationObserver.disconnect();\n if(this.scrollHandler){\n window.removeEventListener('scroll', this.scrollHandler);\n }\n if(this.resizeHandler){\n window.removeEventListener('resize', this.resizeHandler);\n }\n }\n\n /**\n * Attaches observers to an SVG element and begins monitoring.\n *\n * @param canvas - The SVG element to monitor\n *\n * @remarks\n * Automatically calls {@link dispose} first to clean up any previous attachments.\n * Sets up all observers and records the initial position/dimensions.\n *\n * The initial rect is calculated immediately and stored, but no notification\n * is sent to observers for this initial state.\n */\n attach(canvas: SVGSVGElement) {\n this.dispose();\n this.resizeObserver.observe(canvas);\n this.intersectionObserver.observe(canvas);\n this.mutationObserver.observe(canvas, {\n attributes: true,\n attributeFilter: [\"width\", \"height\", \"style\"]\n });\n const boundingRect = canvas.getBoundingClientRect();\n const trueRect = getTrueRect(boundingRect, window.getComputedStyle(canvas));\n this.lastRect = trueRect;\n\n this.scrollHandler = (() => {\n if(this.lastRect === undefined){\n return;\n }\n const newRect = canvas.getBoundingClientRect();\n const trueRect = getTrueRect(newRect, window.getComputedStyle(canvas));\n if (rectChanged(this.lastRect, trueRect)) {\n this.publishPositionUpdate(trueRect);\n this.lastRect = trueRect;\n }\n }).bind(this);\n this.resizeHandler = (() => {\n if(this.lastRect === undefined){\n return;\n }\n const newRect = canvas.getBoundingClientRect();\n const trueRect = getTrueRect(newRect, window.getComputedStyle(canvas));\n if (rectChanged(this.lastRect, trueRect)) {\n this.publishPositionUpdate(trueRect);\n this.lastRect = trueRect;\n }\n }).bind(this);\n window.addEventListener(\"scroll\", this.scrollHandler, { passive: true });\n window.addEventListener(\"resize\", this.resizeHandler, { passive: true });\n }\n\n private publishPositionUpdate(rect: DOMRect) {\n this._observers.notify(rect);\n }\n\n /**\n * Subscribes to position and dimension updates.\n *\n * @param observer - Callback function that receives the updated DOMRect\n * @param options - Optional subscription options (e.g., AbortSignal for cleanup)\n * @returns Unsubscribe function to remove this observer\n *\n * @remarks\n * The observer is called synchronously whenever the SVG's position or dimensions change.\n * The DOMRect parameter represents the actual content area (excluding padding and borders).\n *\n * @example\n * ```typescript\n * const unsubscribe = publisher.onPositionUpdate((rect) => {\n * console.log(`Position: ${rect.x}, ${rect.y}`);\n * console.log(`Size: ${rect.width}x${rect.height}`);\n * });\n *\n * // Later, when done:\n * unsubscribe();\n * ```\n */\n onPositionUpdate(observer: Observer<[DOMRect]>, options?: SubscriptionOptions) {\n return this._observers.subscribe(observer, options);\n }\n\n private attributeCallBack(mutationsList: MutationRecord[], observer: MutationObserver){\n for(let mutation of mutationsList){\n if(mutation.type === \"attributes\"){\n if(mutation.attributeName === \"width\"){\n const canvas = mutation.target as SVGSVGElement;\n const newRect = canvas.getBoundingClientRect();\n const trueRect = getTrueRect(newRect, window.getComputedStyle(canvas));\n if (rectChanged(this.lastRect, trueRect)) {\n this.publishPositionUpdate(trueRect);\n this.lastRect = trueRect;\n }\n } else if(mutation.attributeName === \"height\"){\n const canvas = mutation.target as SVGSVGElement;\n const newRect = canvas.getBoundingClientRect();\n const trueRect = getTrueRect(newRect, window.getComputedStyle(canvas));\n if (rectChanged(this.lastRect, trueRect)) {\n this.publishPositionUpdate(trueRect);\n this.lastRect = trueRect;\n }\n } else if (mutation.attributeName === \"style\"){\n const canvas = mutation.target as SVGSVGElement;\n const newRect = canvas.getBoundingClientRect();\n const trueRect = getTrueRect(newRect, window.getComputedStyle(canvas));\n if (rectChanged(this.lastRect, trueRect)) {\n this.publishPositionUpdate(trueRect);\n this.lastRect = trueRect;\n }\n }\n }\n }\n }\n}\n\n/**\n * Monitors and publishes position and dimension changes for HTML Canvas elements.\n *\n * @remarks\n * Similar to {@link SvgPositionDimensionPublisher} but specifically for HTMLCanvasElement.\n * Automatically handles device pixel ratio adjustments to maintain crisp rendering\n * at different screen densities.\n *\n * Key differences from SVG version:\n * - Automatically adjusts canvas.width/height attributes based on devicePixelRatio\n * - Synchronizes CSS dimensions (style.width/height) with canvas buffer size\n * - Ensures canvas maintains proper resolution on high-DPI displays\n *\n * The class uses multiple browser APIs for comprehensive change detection:\n * - ResizeObserver: Detects size changes\n * - IntersectionObserver: Detects visibility and position changes\n * - MutationObserver: Detects attribute changes and synchronizes dimensions\n * - Window scroll/resize events: Detects changes from page layout\n *\n * @example\n * ```typescript\n * const canvas = document.querySelector('canvas');\n * const publisher = new CanvasPositionDimensionPublisher(canvas);\n *\n * // Subscribe to updates\n * publisher.onPositionUpdate((rect) => {\n * // Canvas dimensions automatically adjusted for devicePixelRatio\n * console.log(`Canvas at (${rect.x}, ${rect.y})`);\n * console.log(`Display size: ${rect.width}x${rect.height}`);\n * });\n *\n * publisher.dispose();\n * ```\n *\n * @category Canvas Position\n * @see {@link SvgPositionDimensionPublisher} for SVG elements\n */\nexport class CanvasPositionDimensionPublisher {\n\n private lastRect?: DOMRect;\n private resizeObserver: ResizeObserver;\n private intersectionObserver: IntersectionObserver;\n private mutationObserver: MutationObserver;\n private scrollHandler?: (() => void);\n private resizeHandler?: (() => void);\n private _observers: SynchronousObservable<[DOMRect]>;\n\n /**\n * Creates a new Canvas position/dimension publisher.\n *\n * @param canvas - Optional canvas element to immediately attach to\n *\n * @remarks\n * If a canvas is provided, observers are immediately attached and monitoring begins.\n * The canvas dimensions are automatically adjusted for devicePixelRatio.\n */\n constructor(canvas?: HTMLCanvasElement) {\n this._observers = new SynchronousObservable<[DOMRect]>();\n\n this.resizeObserver = new ResizeObserver(((entries: ResizeObserverEntry[]) => {\n for (const entry of entries) {\n const newRect = entry.target.getBoundingClientRect();\n const trueRect = getTrueRect(newRect, window.getComputedStyle(entry.target));\n if (rectChanged(this.lastRect, trueRect)) {\n this.publishPositionUpdate(trueRect);\n this.lastRect = trueRect;\n }\n }\n }).bind(this));\n\n this.intersectionObserver = new IntersectionObserver(((entries: IntersectionObserverEntry[]) => {\n if(this.lastRect === undefined){\n return;\n }\n for (const entry of entries) {\n if (entry.isIntersecting) {\n const newRect = entry.boundingClientRect;\n const trueRect = getTrueRect(newRect, window.getComputedStyle(entry.target));\n if (rectChanged(this.lastRect, trueRect)) {\n this.publishPositionUpdate(trueRect);\n this.lastRect = trueRect;\n }\n }\n }\n }).bind(this));\n\n this.attributeCallBack = this.attributeCallBack.bind(this);\n this.mutationObserver = new MutationObserver(this.attributeCallBack);\n\n if(canvas){\n this.attach(canvas);\n }\n }\n \n /**\n * Cleans up all observers and event listeners.\n *\n * @remarks\n * Disconnects all observers and removes window event listeners.\n * Always call this method when the publisher is no longer needed to prevent memory leaks.\n */\n public dispose(): void {\n this.resizeObserver.disconnect();\n this.intersectionObserver.disconnect();\n this.mutationObserver.disconnect();\n if(this.scrollHandler){\n window.removeEventListener('scroll', this.scrollHandler);\n }\n if(this.resizeHandler){\n window.removeEventListener('resize', this.resizeHandler);\n }\n }\n\n /**\n * Attaches observers to a canvas element and begins monitoring.\n *\n * @param canvas - The canvas element to monitor\n *\n * @remarks\n * Automatically calls {@link dispose} first to clean up any previous attachments.\n * Sets up all observers, adjusts canvas dimensions for devicePixelRatio,\n * and records the initial position/dimensions.\n */\n attach(canvas: HTMLCanvasElement) {\n this.dispose();\n this.resizeObserver.observe(canvas);\n this.intersectionObserver.observe(canvas);\n this.mutationObserver.observe(canvas, {\n attributes: true,\n attributeFilter: [\"width\", \"height\", \"style\"]\n });\n const boundingRect = canvas.getBoundingClientRect();\n const trueRect = getTrueRect(boundingRect, window.getComputedStyle(canvas));\n this.lastRect = trueRect;\n\n this.scrollHandler = (() => {\n if(this.lastRect === undefined){\n return;\n }\n const newRect = canvas.getBoundingClientRect();\n const trueRect = getTrueRect(newRect, window.getComputedStyle(canvas));\n if (rectChanged(this.lastRect, trueRect)) {\n this.publishPositionUpdate(trueRect);\n this.lastRect = trueRect;\n }\n }).bind(this);\n this.resizeHandler = (() => {\n if(this.lastRect === undefined){\n return;\n }\n const newRect = canvas.getBoundingClientRect();\n const trueRect = getTrueRect(newRect, window.getComputedStyle(canvas));\n if (rectChanged(this.lastRect, trueRect)) {\n this.publishPositionUpdate(trueRect);\n this.lastRect = trueRect;\n }\n }).bind(this);\n window.addEventListener(\"scroll\", this.scrollHandler, { passive: true });\n window.addEventListener(\"resize\", this.resizeHandler, { passive: true });\n }\n\n private publishPositionUpdate(rect: DOMRect) {\n this._observers.notify(rect);\n }\n\n /**\n * Subscribes to position and dimension updates.\n *\n * @param observer - Callback function that receives the updated DOMRect\n * @param options - Optional subscription options (e.g., AbortSignal for cleanup)\n * @returns Unsubscribe function to remove this observer\n *\n * @remarks\n * The observer is called synchronously whenever the canvas position or dimensions change.\n * The DOMRect represents the actual content area (excluding padding and borders).\n * Canvas buffer dimensions are automatically adjusted for devicePixelRatio.\n */\n onPositionUpdate(observer: Observer<[DOMRect]>, options?: SubscriptionOptions) {\n return this._observers.subscribe(observer, options);\n }\n\n /**\n * Handles attribute mutations on the canvas element.\n *\n * @param mutationsList - List of mutations detected\n * @param observer - The MutationObserver instance\n *\n * @remarks\n * This callback synchronizes canvas buffer size with CSS dimensions:\n * - When width/height attributes change: Updates CSS dimensions based on devicePixelRatio\n * - When style changes: Updates buffer size to match CSS dimensions\n *\n * This ensures the canvas maintains proper resolution on all displays.\n */\n private attributeCallBack(mutationsList: MutationRecord[], observer: MutationObserver){\n for(let mutation of mutationsList){\n if(mutation.type === \"attributes\"){\n if(mutation.attributeName === \"width\"){\n const canvas = mutation.target as HTMLCanvasElement;\n // canvas.style.width = canvas.width / window.devicePixelRatio + \"px\";\n const newRect = canvas.getBoundingClientRect();\n const trueRect = getTrueRect(newRect, window.getComputedStyle(canvas));\n if (rectChanged(this.lastRect, trueRect)) {\n this.publishPositionUpdate(trueRect);\n this.lastRect = trueRect;\n }\n } else if(mutation.attributeName === \"height\"){\n const canvas = mutation.target as HTMLCanvasElement;\n // canvas.style.height = canvas.height / window.devicePixelRatio + \"px\";\n const newRect = canvas.getBoundingClientRect();\n const trueRect = getTrueRect(newRect, window.getComputedStyle(canvas));\n if (rectChanged(this.lastRect, trueRect)) {\n this.publishPositionUpdate(trueRect);\n this.lastRect = trueRect;\n }\n } else if (mutation.attributeName === \"style\"){\n const canvas = mutation.target as HTMLCanvasElement;\n // const styleWidth = parseFloat(canvas.style.width);\n // const styleHeight = parseFloat(canvas.style.height);\n // const newWidth = styleWidth * window.devicePixelRatio;\n // const newHeight = styleHeight * window.devicePixelRatio;\n // if(newWidth != canvas.width){\n // canvas.width = newWidth;\n // }\n // if(newHeight != canvas.height){\n // canvas.height = newHeight;\n // }\n const newRect = canvas.getBoundingClientRect();\n const trueRect = getTrueRect(newRect, window.getComputedStyle(canvas));\n if (rectChanged(this.lastRect, trueRect)) {\n this.publishPositionUpdate(trueRect);\n this.lastRect = trueRect;\n }\n }\n }\n }\n }\n}\n\n/**\n * Calculates the actual content rectangle excluding padding and borders.\n *\n * @param rect - The element's bounding client rectangle\n * @param computedStyle - The computed CSS styles for the element\n * @returns DOMRect representing the content area only\n *\n * @remarks\n * Browser's getBoundingClientRect() includes padding and borders, but for\n * coordinate transformations we need the actual drawable content area.\n *\n * This function subtracts padding and border from all four sides to get\n * the \"true\" content rectangle. This is essential for accurate coordinate\n * conversions between window and canvas space.\n *\n * @example\n * ```typescript\n * const canvas = document.querySelector('canvas');\n * const rect = canvas.getBoundingClientRect();\n * const style = window.getComputedStyle(canvas);\n * const contentRect = getTrueRect(rect, style);\n *\n * // contentRect.width is less than rect.width if padding/borders exist\n * console.log(`Full size: ${rect.width}x${rect.height}`);\n * console.log(`Content size: ${contentRect.width}x${contentRect.height}`);\n * ```\n *\n * @category Canvas Position\n */\nexport function getTrueRect(rect: DOMRect, computedStyle: CSSStyleDeclaration) {\n const paddingLeft = parseFloat(computedStyle.paddingLeft);\n const paddingTop = parseFloat(computedStyle.paddingTop);\n const paddingRight = parseFloat(computedStyle.paddingRight);\n const paddingBottom = parseFloat(computedStyle.paddingBottom);\n\n const borderLeft = parseFloat(computedStyle.borderLeftWidth);\n const borderTop = parseFloat(computedStyle.borderTopWidth);\n const borderRight = parseFloat(computedStyle.borderRightWidth);\n const borderBottom = parseFloat(computedStyle.borderBottomWidth);\n\n const trueLeft = rect.left + paddingLeft + borderLeft;\n const trueTop = rect.top + paddingTop + borderTop;\n const trueWidth = rect.width - paddingLeft - paddingRight - borderLeft - borderRight;\n const trueHeight = rect.height - paddingTop - paddingBottom - borderTop - borderBottom;\n return new DOMRect(trueLeft, trueTop, trueWidth, trueHeight);\n}\n\n/**\n * Checks if two rectangles differ in position or dimensions.\n *\n * @param r1 - First rectangle (or undefined for initial state)\n * @param r2 - Second rectangle to compare\n * @returns True if rectangles differ or r1 is undefined\n *\n * @remarks\n * Used internally to avoid redundant notifications when position/dimensions\n * haven't actually changed. Compares top, left, width, and height.\n *\n * Returns true if r1 is undefined (initial state always counts as \"changed\").\n */\nfunction rectChanged(r1: DOMRect | undefined, r2: DOMRect) {\n if(r1 === undefined){\n return true;\n }\n return r1.top !== r2.top || r1.left !== r2.left ||\n r1.width !== r2.width || r1.height !== r2.height;\n}\n\n/**\n * Maps canvas context methods to the indices of their y-coordinate parameters.\n *\n * @remarks\n * Used by {@link reverseYAxis} to identify which method parameters need y-flipping\n * when converting from standard canvas coordinates (top-left origin, y-down)\n * to mathematical coordinates (center origin, y-up).\n *\n * Array values indicate the parameter indices that contain y-coordinates.\n * For example, fillRect(x, y, width, height) has y at index 1 and height at index 3.\n *\n * @internal\n * @category Canvas Position\n */\nconst methodsToFlip: Record<string, number[]> = {\n fillRect: [1, 3], // [yIndex] - indices of y-coordinates to flip\n strokeRect: [1, 3],\n fillText: [2],\n strokeText: [1],\n lineTo: [1],\n moveTo: [1],\n quadraticCurveTo: [1, 3],\n bezierCurveTo: [1, 3, 5],\n arc: [1],\n drawImage: [2], // Base case for first two signatures\n rect: [1, 3],\n roundRect: [1, 3],\n};\n\n/**\n * Creates a proxy that automatically flips y-coordinates for canvas context methods.\n *\n * @param context - The canvas 2D rendering context to wrap\n * @returns Proxied context that handles y-axis reversal automatically\n *\n * @remarks\n * Standard HTML canvas uses a top-left origin with y-axis pointing down.\n * This proxy inverts the y-axis to create a mathematical coordinate system\n * with y-axis pointing up.\n *\n * The proxy intercepts drawing methods (fillRect, strokeRect, moveTo, lineTo, etc.)\n * and automatically negates y-coordinates and height values. This allows you to\n * work in mathematical coordinates while still rendering correctly.\n *\n * Special handling for complex methods:\n * - drawImage with 9 args: Properly inverts source and destination rectangles\n * - drawImage with 5 args: Adjusts for image height\n * - All methods in {@link methodsToFlip}: Y-coordinates negated automatically\n *\n * @example\n * ```typescript\n * const canvas = document.querySelector('canvas');\n * const ctx = canvas.getContext('2d');\n * const flippedCtx = reverseYAxis(ctx);\n *\n * // Draw with mathematical coordinates (y-up)\n * flippedCtx.fillRect(0, 0, 100, 100); // Square in first quadrant\n * flippedCtx.moveTo(0, 0);\n * flippedCtx.lineTo(50, 100); // Line going upward\n * ```\n *\n * @category Canvas Position\n * @see {@link methodsToFlip} for list of intercepted methods\n * @see {@link invertYAxisForDrawImageWith9Args} for drawImage special handling\n */\nexport function reverseYAxis(context: CanvasRenderingContext2D): CanvasRenderingContext2D {\n return new Proxy(context, {\n get(target: CanvasRenderingContext2D, prop: string | symbol, receiver: any): any {\n const value = Reflect.get(target, prop, target);\n \n // Check if this is a method that needs y-coordinate flipping\n if (typeof prop === 'string' && prop in methodsToFlip && typeof value === 'function') {\n return function(...args: any[]) {\n // Create a copy of the arguments\n const newArgs = [...args];\n \n // Special handling for drawImage with 9 arguments (third signature of drawImage)\n if (prop === 'drawImage' && args.length === 9) {\n const convertedArgs = invertYAxisForDrawImageWith9Args(args);\n return value.apply(target, convertedArgs);\n } else {\n // Flip the y-coordinates based on methodsToFlip configuration\n const yIndices = methodsToFlip[prop];\n for (const index of yIndices) {\n if (index < newArgs.length) {\n newArgs[index] = -newArgs[index];\n }\n }\n // Special handling for drawImage with 5 arguments (first signature of drawImage)\n if(prop === \"drawImage\" && args.length === 5){\n newArgs[2] -= newArgs[4];\n }\n }\n \n // Call the original method with the modified arguments\n return value.apply(target, newArgs);\n };\n }\n \n // Return the original value for properties and methods that don't need modification\n if (typeof value === 'function') {\n return function(...args: any[]) {\n return value.apply(target, args);\n };\n }\n \n return value;\n },\n set(target, prop, value): boolean {\n return Reflect.set(target, prop, value);\n }\n });\n}\n\n/**\n * Inverts y-coordinates for the 9-argument variant of drawImage.\n *\n * @param args - The arguments array for drawImage\n * @returns Modified arguments with inverted y-coordinates\n *\n * @remarks\n * The 9-argument drawImage signature is:\n * drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)\n *\n * When inverting y-axis, we need to adjust:\n * - sy (source y): Flip relative to image height\n * - sHeight: Negate (height becomes negative in flipped space)\n * - dy (destination y): Negate\n * - dy offset: Subtract destination height\n *\n * This ensures images render correctly when the canvas y-axis is flipped.\n *\n * @example\n * ```typescript\n * // Original call (top-left origin):\n * ctx.drawImage(img, 0, 0, 100, 100, 50, 50, 200, 200);\n *\n * // With flipped y-axis, this becomes:\n * // sy = imageHeight - 0, sHeight = -100, dy = -50 - 200, dHeight = -200\n * ```\n *\n * @category Canvas Position\n * @see {@link reverseYAxis} for the main y-axis flipping proxy\n */\nexport function invertYAxisForDrawImageWith9Args(args: any[]): typeof args {\n if(args.length !== 9){\n return args;\n }\n const newArgs = [...args];\n const imageHeight = args[0].height;\n if(imageHeight !== undefined){\n newArgs[2] = imageHeight - newArgs[2];\n newArgs[6] = -newArgs[6];\n newArgs[6] -= newArgs[8];\n newArgs[4] = -newArgs[4];\n }\n return newArgs;\n}\n",
27
- "import { Point, PointCal } from \"@ue-too/math\";\nimport { calculateOrderOfMagnitude } from \"./ruler\";\n\n/**\n * Draws an arrow from start to end point with an arrowhead.\n *\n * @param context - The canvas 2D rendering context\n * @param cameraZoomLevel - Current camera zoom level for scale-independent sizing\n * @param startPoint - Arrow tail position in world coordinates\n * @param endPoint - Arrow head position in world coordinates\n * @param width - Line width in world units (default: 1)\n * @param arrowRatio - Ratio of arrowhead size to total length (default: 0.3, unused in implementation)\n *\n * @remarks\n * The arrow consists of a line segment and a triangular arrowhead. The arrowhead\n * size is adaptive:\n * - Maximum 10 pixels in viewport space\n * - Minimum half the arrow length\n *\n * This ensures arrows look good at all zoom levels and lengths.\n *\n * The arrowhead is constructed perpendicular to the arrow direction, creating\n * a filled triangle at the end point.\n *\n * @example\n * ```typescript\n * const ctx = canvas.getContext('2d');\n * const zoom = 1.5;\n *\n * // Draw a simple arrow\n * ctx.fillStyle = 'blue';\n * ctx.strokeStyle = 'blue';\n * drawArrow(ctx, zoom, { x: 0, y: 0 }, { x: 100, y: 50 });\n *\n * // Draw a thicker arrow\n * ctx.fillStyle = 'red';\n * ctx.strokeStyle = 'red';\n * drawArrow(ctx, zoom, { x: 0, y: 0 }, { x: 100, y: -50 }, 3);\n * ```\n *\n * @category Drawing Utilities\n */\nexport function drawArrow(context: CanvasRenderingContext2D, cameraZoomLevel: number, startPoint: Point, endPoint: Point, width: number = 1, arrowRatio: number = 0.3) {\n const length = PointCal.distanceBetweenPoints(startPoint, endPoint);\n const arrowHeight = 10 < length * cameraZoomLevel * 0.5 ? 10 / cameraZoomLevel : length * 0.5;\n const offsetLength = length - arrowHeight;\n const offsetPoint = PointCal.linearInterpolation(startPoint, endPoint, offsetLength / length);\n context.beginPath();\n context.lineWidth = width / cameraZoomLevel;\n context.moveTo(startPoint.x, startPoint.y);\n context.lineTo(offsetPoint.x, offsetPoint.y);\n context.stroke();\n const unitVector = PointCal.rotatePoint(PointCal.unitVectorFromA2B(endPoint, startPoint), Math.PI / 2);\n const arrowPoint1 = PointCal.addVector(offsetPoint, PointCal.multiplyVectorByScalar(unitVector, arrowHeight * 0.5));\n const arrowPoint2 = PointCal.subVector(offsetPoint, PointCal.multiplyVectorByScalar(unitVector, arrowHeight * 0.5));\n context.beginPath();\n context.moveTo(endPoint.x, endPoint.y);\n context.lineTo(arrowPoint1.x, arrowPoint1.y);\n context.lineTo(arrowPoint2.x, arrowPoint2.y);\n context.closePath();\n context.fill();\n}\n\n/**\n * Length of major tick marks in pixels (viewport space).\n * @category Drawing Utilities\n */\nexport const MAJOR_TICK_LENGTH = 30;\n\n/**\n * Length of minor tick marks in pixels (viewport space).\n * @category Drawing Utilities\n */\nexport const MINOR_TICK_LENGTH = MAJOR_TICK_LENGTH * 0.3;\n\n/**\n * Length of half-step tick marks in pixels (viewport space).\n * @category Drawing Utilities\n */\nexport const HALF_TICK_LENGTH = MAJOR_TICK_LENGTH * 0.5;\n\n/**\n * Offset for major tick labels in pixels (viewport space).\n * @category Drawing Utilities\n */\nexport const TEXT_MAJOR_TICK_OFFSET = 10;\n\n/**\n * Offset for half-step tick labels in pixels (viewport space).\n * @category Drawing Utilities\n */\nexport const TEXT_HALF_TICK_OFFSET = 2.5;\n\n/**\n * Font size for major tick labels in pixels (viewport space).\n * @category Drawing Utilities\n */\nexport const TEXT_MAJOR_TICK_FONT_SIZE = 20;\n\n/**\n * Font size for half-step tick labels in pixels (viewport space).\n * @category Drawing Utilities\n */\nexport const TEXT_HALF_TICK_FONT_SIZE = 10;\n\n/**\n * Draws calibrated rulers along the edges of the viewport.\n *\n * @param context - The canvas 2D rendering context\n * @param topLeftCorner - Top-left corner of viewport in world coordinates\n * @param topRightCorner - Top-right corner of viewport in world coordinates\n * @param bottomLeftCorner - Bottom-left corner of viewport in world coordinates\n * @param alignCoordinateSystem - Whether coordinates align with canvas (y-down) or are mathematical (y-up)\n * @param cameraZoomLevel - Current camera zoom level\n *\n * @remarks\n * This function draws rulers with three levels of tick marks:\n * - Major ticks: At powers of 10 (1, 10, 100, etc.) with large labels\n * - Half ticks: At half-steps (5, 50, 500, etc.) with small labels\n * - Minor ticks: At 1/10 steps with no labels\n *\n * The ruler automatically adapts to the zoom level by calculating appropriate\n * tick spacing using {@link calculateOrderOfMagnitude} and {@link calculateTickValues}.\n *\n * Rulers are drawn along:\n * - Top edge (horizontal ruler, red)\n * - Left edge (vertical ruler, green)\n *\n * Tick positions are calibrated to align with round numbers in world space,\n * making it easy to read coordinates at any zoom level.\n *\n * @example\n * ```typescript\n * const ctx = canvas.getContext('2d');\n * const zoom = 2.0;\n *\n * // Viewport corners in world space\n * const topLeft = { x: -100, y: 100 };\n * const topRight = { x: 100, y: 100 };\n * const bottomLeft = { x: -100, y: -100 };\n *\n * drawRuler(ctx, topLeft, topRight, bottomLeft, false, zoom);\n * // Draws rulers with ticks at -100, -50, 0, 50, 100\n * ```\n *\n * @category Drawing Utilities\n * @see {@link calculateTickValues} for tick calculation logic\n * @see {@link calculateOrderOfMagnitude} for order of magnitude calculation\n */\nexport function drawRuler(\n context: CanvasRenderingContext2D,\n topLeftCorner: Point,\n topRightCorner: Point,\n bottomLeftCorner: Point,\n alignCoordinateSystem: boolean,\n cameraZoomLevel: number,\n): void{\n\n // NOTE horizontal ruler\n const {\n minMajorTickValue, \n maxMajorTickValue, \n majorTickStep, \n minMinTickValue, \n maxMaxTickValue, \n minTickStep, \n minHalfTickValue, \n maxHalfTickValue, \n halfTickStep, \n calibrationMultiplier, \n normalizedOrderOfMagnitude,\n } = calculateTickValues(topLeftCorner.x, topRightCorner.x);\n\n context.save();\n context.strokeStyle = 'red';\n for(let i = minMajorTickValue; i <= maxMajorTickValue; i += majorTickStep){\n const majorTickPoint = {x: i * calibrationMultiplier, y: topLeftCorner.y};\n const majorTickLength = alignCoordinateSystem ? MAJOR_TICK_LENGTH / cameraZoomLevel : -MAJOR_TICK_LENGTH / cameraZoomLevel;\n const textOffset = alignCoordinateSystem ? TEXT_MAJOR_TICK_OFFSET / cameraZoomLevel : -TEXT_MAJOR_TICK_OFFSET / cameraZoomLevel;\n drawXAxisTick(context, cameraZoomLevel, majorTickPoint, majorTickLength, i * calibrationMultiplier, {textOffset, fontSize: TEXT_MAJOR_TICK_FONT_SIZE});\n }\n\n for(let i = minMinTickValue; i <= maxMaxTickValue; i += minTickStep){\n if(i % majorTickStep === 0){\n continue;\n }\n if(i % halfTickStep === 0){\n continue;\n }\n const minTickPoint = {x: i * calibrationMultiplier, y: topLeftCorner.y};\n const minTickLength = alignCoordinateSystem ? MINOR_TICK_LENGTH / cameraZoomLevel : -MINOR_TICK_LENGTH / cameraZoomLevel;\n drawXAxisTick(context, cameraZoomLevel, minTickPoint, minTickLength, i);\n }\n\n for(let i = minHalfTickValue; i <= maxHalfTickValue; i += halfTickStep){\n if(i % majorTickStep === 0){\n continue;\n }\n const halfTickPoint = {x: i * calibrationMultiplier, y: topLeftCorner.y};\n const halfTickLength = alignCoordinateSystem ? HALF_TICK_LENGTH / cameraZoomLevel : -HALF_TICK_LENGTH / cameraZoomLevel;\n const textOffset = alignCoordinateSystem ? TEXT_HALF_TICK_OFFSET / cameraZoomLevel : -TEXT_HALF_TICK_OFFSET / cameraZoomLevel;\n drawXAxisTick(context, cameraZoomLevel, halfTickPoint, halfTickLength, i * calibrationMultiplier, {textOffset, fontSize: TEXT_HALF_TICK_FONT_SIZE, color: 'red'});\n }\n\n context.restore();\n\n // NOTE vertical ruler\n const {\n minMajorTickValue: vMinMajorTickValue, maxMajorTickValue: vMaxMajorTickValue, majorTickStep: vMajorTickStep, \n minMinTickValue: vMinMinTickValue, maxMaxTickValue: vMaxMaxTickValue, \n minTickStep: vMinTickStep, \n minHalfTickValue: vMinHalfTickValue, maxHalfTickValue: vMaxHalfTickValue, \n halfTickStep: vHalfTickStep, \n calibrationMultiplier: vCalibrationMultiplier,\n } = calculateTickValues(topLeftCorner.y, bottomLeftCorner.y, normalizedOrderOfMagnitude);\n\n context.save();\n context.strokeStyle = 'green';\n for(let i = vMinMajorTickValue; i <= vMaxMajorTickValue; i += vMajorTickStep){\n const majorTickPoint = {x: topLeftCorner.x, y: i * vCalibrationMultiplier};\n const majorTickLength = MAJOR_TICK_LENGTH / cameraZoomLevel;\n const textOffset = TEXT_MAJOR_TICK_OFFSET / cameraZoomLevel;\n drawYAxisTick(context, cameraZoomLevel, majorTickPoint, majorTickLength, i, {textOffset, fontSize: TEXT_MAJOR_TICK_FONT_SIZE});\n }\n\n for(let i = vMinHalfTickValue; i <= vMaxHalfTickValue; i += vHalfTickStep){\n if(i % vMajorTickStep === 0){\n continue;\n }\n const halfTickPoint = {x: topLeftCorner.x, y: i * vCalibrationMultiplier};\n const halfTickLength = HALF_TICK_LENGTH / cameraZoomLevel;\n const textOffset = TEXT_HALF_TICK_OFFSET / cameraZoomLevel;\n drawYAxisTick(context, cameraZoomLevel, halfTickPoint, halfTickLength, i, {textOffset, fontSize: TEXT_HALF_TICK_FONT_SIZE});\n }\n\n for(let i = vMinMinTickValue; i <= vMaxMaxTickValue; i += vMinTickStep){\n if(i % vMajorTickStep === 0){\n continue;\n }\n const minTickPoint = {x: topLeftCorner.x, y: i * vCalibrationMultiplier};\n const minTickLength = MINOR_TICK_LENGTH / cameraZoomLevel;\n drawYAxisTick(context, cameraZoomLevel, minTickPoint, minTickLength, i);\n }\n context.restore();\n}\n\nfunction drawYAxisTick(\n context: CanvasRenderingContext2D, \n cameraZoomLevel: number, \n majorTickPoint: { x: number; y: number; }, \n majorTickLength: number, \n tickValue: number, \n textOption?: {\n textOffset: number,\n fontSize: number,\n color?: string,\n }\n) {\n const drawText = textOption !== undefined;\n context.save();\n context.lineWidth = 1 / cameraZoomLevel;\n context.beginPath();\n context.moveTo(majorTickPoint.x, majorTickPoint.y);\n context.lineTo(majorTickPoint.x + majorTickLength, majorTickPoint.y);\n context.stroke();\n context.restore();\n if(!drawText){\n return;\n }\n const color = textOption.color ?? 'green';\n context.save();\n context.textAlign = \"left\";\n context.textBaseline = \"middle\";\n context.fillStyle = color;\n context.font = `${textOption.fontSize / cameraZoomLevel}px Arial`;\n const tickValueText = tickValue % 1 == 0 ? tickValue : tickValue.toFixed(2);\n context.fillText(`${tickValueText}`, majorTickPoint.x + majorTickLength + textOption.textOffset, majorTickPoint.y);\n context.restore();\n}\n\nfunction drawXAxisTick(\n context: CanvasRenderingContext2D, \n cameraZoomLevel: number, \n majorTickPoint: { x: number; y: number; }, \n majorTickLength: number, \n tickValue: number, \n textOption?: {\n textOffset: number,\n fontSize: number,\n color?: string,\n }\n) {\n const drawText = textOption !== undefined;\n context.save();\n context.lineWidth = 1 / cameraZoomLevel;\n context.beginPath();\n context.moveTo(majorTickPoint.x, majorTickPoint.y);\n context.lineTo(majorTickPoint.x, majorTickPoint.y + majorTickLength);\n context.stroke();\n context.restore();\n if(!drawText){\n return;\n }\n const color = textOption.color ?? 'red';\n context.save();\n context.textAlign = \"center\";\n context.textBaseline = \"top\";\n context.fillStyle = color;\n context.font = `${textOption.fontSize / cameraZoomLevel}px Arial`;\n const tickValueText = tickValue % 1 == 0 ? tickValue : tickValue.toFixed(2);\n context.fillText(`${tickValueText}`, majorTickPoint.x, majorTickPoint.y + majorTickLength + textOption.textOffset);\n context.restore();\n}\n\n/**\n * Calculates tick mark positions and spacing for a ruler.\n *\n * @param minValue - Minimum value on the ruler axis\n * @param maxValue - Maximum value on the ruler axis\n * @param orderOfMagnitude - Optional pre-calculated order of magnitude (for consistency across axes)\n * @returns Object containing tick positions and spacing for major, half, and minor ticks\n *\n * @remarks\n * This function determines where to place tick marks on a ruler to show round\n * numbers at appropriate intervals. It calculates three levels of ticks:\n *\n * 1. Major ticks: At powers of 10 (step = 10^n)\n * 2. Half ticks: At half the major step (step = 5×10^(n-1))\n * 3. Minor ticks: At 1/10 the major step (step = 10^(n-1))\n *\n * The calibration multiplier handles cases where the order of magnitude is very\n * small (< 1), ensuring tick positions are calculated correctly for zoomed-in views.\n *\n * For consistency between x and y axes, you can provide a pre-calculated\n * orderOfMagnitude. Otherwise, it's calculated from the range width.\n *\n * @example\n * ```typescript\n * // Ruler showing -100 to 100\n * const ticks = calculateTickValues(-100, 100);\n * // Result:\n * // majorTickStep: 100\n * // minMajorTickValue: -100, maxMajorTickValue: 100\n * // halfTickStep: 50\n * // minorTickStep: 10\n * // calibrationMultiplier: 1\n *\n * // Zoomed in view: 0.001 to 0.01\n * const zoomedTicks = calculateTickValues(0.001, 0.01);\n * // Result:\n * // majorTickStep: 10 (calibrated)\n * // calibrationMultiplier: 0.001 (multiply tick values by this)\n * ```\n *\n * @category Drawing Utilities\n * @see {@link calculateOrderOfMagnitude} for order calculation\n * @see {@link drawRuler} for usage in ruler drawing\n */\nexport function calculateTickValues(minValue: number, maxValue: number, orderOfMagnitude?: number){\n const trueMinValue = Math.min(minValue, maxValue);\n const trueMaxValue = Math.max(minValue, maxValue);\n\n const width = trueMaxValue - trueMinValue;\n const trueOrderOfMagnitude = orderOfMagnitude ? orderOfMagnitude : calculateOrderOfMagnitude(width);\n\n const normalizedOrderOfMagnitude = Math.max(1, trueOrderOfMagnitude);\n const calibrationMultiplier = Math.pow(10, normalizedOrderOfMagnitude - trueOrderOfMagnitude); // this is the multiplier to calibrate the ruler to the correct length\n\n const minMajorTickMultiplier = \n minValue > 0 ? \n Math.floor(trueMinValue * calibrationMultiplier / Math.pow(10, normalizedOrderOfMagnitude)) : \n Math.ceil(trueMinValue * calibrationMultiplier / Math.pow(10, normalizedOrderOfMagnitude));\n const minMajorTickValue = minMajorTickMultiplier * Math.pow(10, normalizedOrderOfMagnitude);\n const maxMajorTickMultiplier = \n maxValue > 0 ? \n Math.floor(trueMaxValue * calibrationMultiplier / Math.pow(10, normalizedOrderOfMagnitude)) : \n Math.ceil(trueMaxValue * calibrationMultiplier / Math.pow(10, normalizedOrderOfMagnitude));\n const maxMajorTickValue = maxMajorTickMultiplier * Math.pow(10, normalizedOrderOfMagnitude);\n const majorTickStep = Math.pow(10, normalizedOrderOfMagnitude);\n\n // minor tick\n const minTickOrderOfMagnitude = normalizedOrderOfMagnitude - 1;\n const minMinTickMultiplier = \n minValue > 0 ? \n Math.floor(trueMinValue * calibrationMultiplier / Math.pow(10, minTickOrderOfMagnitude)) : \n Math.ceil(trueMinValue * calibrationMultiplier / Math.pow(10, minTickOrderOfMagnitude));\n const minMinTickValue = minMinTickMultiplier * Math.pow(10, minTickOrderOfMagnitude);\n const maxMaxTickMultiplier = \n maxValue > 0 ? \n Math.floor(trueMaxValue * calibrationMultiplier / Math.pow(10, minTickOrderOfMagnitude)) :\n Math.ceil(trueMaxValue * calibrationMultiplier / Math.pow(10, minTickOrderOfMagnitude));\n const maxMaxTickValue = maxMaxTickMultiplier * Math.pow(10, minTickOrderOfMagnitude);\n const minTickStep = Math.pow(10, minTickOrderOfMagnitude);\n\n const halfTickStep = majorTickStep / 2;\n const minHalfTickMultiplier = \n minValue > 0 ? \n Math.floor(trueMinValue * calibrationMultiplier / halfTickStep) : \n Math.ceil(trueMinValue * calibrationMultiplier / halfTickStep);\n const minHalfTickValue = minHalfTickMultiplier * halfTickStep;\n const maxHalfTickMultiplier = \n maxValue > 0 ? \n Math.floor(trueMaxValue * calibrationMultiplier / halfTickStep) : \n Math.ceil(trueMaxValue * calibrationMultiplier / halfTickStep);\n const maxHalfTickValue = maxHalfTickMultiplier * halfTickStep;\n\n return {\n minMajorTickValue,\n maxMajorTickValue,\n majorTickStep,\n minMinTickValue,\n maxMaxTickValue,\n minTickStep,\n minHalfTickValue,\n maxHalfTickValue,\n halfTickStep,\n calibrationMultiplier: 1 / calibrationMultiplier,\n normalizedOrderOfMagnitude,\n }\n}\n",
28
- "import { Boundaries, translationHeightOf, translationWidthOf } from \"../camera/utils/position\";\nimport { ZoomLevelLimits } from \"../camera/utils/zoom\";\n\n/**\n * Calculates minimum zoom level to fit boundaries within canvas at any rotation.\n *\n * @param boundaries - The world-space boundaries to fit\n * @param canvasWidth - Canvas width in pixels\n * @param canvasHeight - Canvas height in pixels\n * @param cameraRotation - Camera rotation angle in radians\n * @returns Minimum zoom level, or undefined if boundaries are incomplete\n *\n * @remarks\n * This function ensures the entire boundary region remains visible regardless\n * of camera rotation. It considers both width and height projections of the\n * rotated boundaries.\n *\n * When boundaries are rotated, they occupy a larger axis-aligned bounding box.\n * This function calculates the minimum zoom needed to fit that box:\n *\n * For each dimension (width/height):\n * 1. Project boundary width onto canvas width axis: `width * cos(rotation)`\n * 2. Project boundary height onto canvas width axis: `height * cos(rotation)`\n * 3. Calculate zoom needed for each projection\n * 4. Take the maximum of all zoom levels\n *\n * Returns undefined if boundaries don't have both width and height defined.\n *\n * Used when canvas is resized to automatically adjust zoom to keep content visible.\n *\n * @example\n * ```typescript\n * const boundaries = {\n * min: { x: 0, y: 0 },\n * max: { x: 1000, y: 500 }\n * };\n *\n * // No rotation, 800x600 canvas\n * const zoom1 = minZoomLevelBaseOnDimensions(boundaries, 800, 600, 0);\n * // Result: 1.2 (600/500, height is limiting)\n *\n * // 45 degree rotation\n * const zoom2 = minZoomLevelBaseOnDimensions(\n * boundaries, 800, 600, Math.PI / 4\n * );\n * // Result: higher zoom (rotated bounds need more space)\n * ```\n *\n * @category Camera\n * @see {@link minZoomLevelBaseOnWidth} for width-only calculation\n * @see {@link minZoomLevelBaseOnHeight} for height-only calculation\n */\nexport function minZoomLevelBaseOnDimensions(boundaries: Boundaries | undefined, canvasWidth: number, canvasHeight: number, cameraRotation: number): number | undefined{\n const width = translationWidthOf(boundaries);\n const height = translationHeightOf(boundaries);\n if(width == undefined || height == undefined){\n return undefined;\n }\n // console.log(canvasHeight, canvasWidth);\n const widthWidthProjection = Math.abs(width * Math.cos(cameraRotation));\n const heightWidthProjection = Math.abs(height * Math.cos(cameraRotation));\n const widthHeightProjection = Math.abs(width * Math.sin(cameraRotation));\n const heightHeightProjection = Math.abs(height * Math.sin(cameraRotation));\n let minZoomLevelWidthWidth = canvasWidth / widthWidthProjection;\n let minZoomLevelHeightWidth = canvasWidth / heightWidthProjection;\n let minZoomLevelWidthHeight = canvasHeight / widthHeightProjection;\n let minZoomLevelHeightHeight = canvasHeight / heightHeightProjection;\n if(minZoomLevelWidthWidth == Infinity){\n minZoomLevelWidthWidth = 0;\n }\n if(minZoomLevelHeightWidth == Infinity){\n minZoomLevelHeightWidth = 0;\n }\n if(minZoomLevelWidthHeight == Infinity){\n minZoomLevelWidthHeight = 0;\n }\n if(minZoomLevelHeightHeight == Infinity){\n minZoomLevelHeightHeight = 0;\n }\n\n // console.log(minZoomLevelWidthWidth, minZoomLevelHeightWidth, minZoomLevelWidthHeight, minZoomLevelHeightHeight);\n\n const minZoomLevelHeight = canvasHeight / height;\n const minZoomLevelWidth = canvasWidth / width;\n const minZoomLevel = Math.max(minZoomLevelHeight, minZoomLevelWidth, minZoomLevelWidthWidth, minZoomLevelHeightWidth, minZoomLevelWidthHeight, minZoomLevelHeightHeight);\n return minZoomLevel;\n}\n\n/**\n * Determines if zoom level boundaries should be updated.\n *\n * @param zoomLevelBoundaries - Current zoom level limits\n * @param targetMinZoomLevel - Proposed new minimum zoom level\n * @returns True if boundaries should be updated (type guard for targetMinZoomLevel)\n *\n * @remarks\n * Zoom level boundary updates only tighten (increase minimum zoom), never relax.\n * This prevents the camera from zooming out too far when boundaries shrink.\n *\n * Returns true (update needed) when:\n * - No current boundaries exist (first-time setup)\n * - Target minimum is higher than current minimum (tightening)\n *\n * Returns false (no update) when:\n * - Target is undefined (invalid/incomplete)\n * - Target is Infinity (invalid state)\n * - Target is lower than current minimum (would relax, not allowed)\n *\n * This function is a type guard: when it returns true, TypeScript knows\n * targetMinZoomLevel is a number (not undefined).\n *\n * @example\n * ```typescript\n * const currentLimits = { min: 0.5, max: 10 };\n * const newMin = 0.8;\n *\n * if (zoomLevelBoundariesShouldUpdate(currentLimits, newMin)) {\n * // Safe to use newMin as number here\n * currentLimits.min = newMin; // Tighten the limit\n * }\n *\n * // No update for lower values\n * zoomLevelBoundariesShouldUpdate(currentLimits, 0.3); // false\n * ```\n *\n * @category Camera\n */\nexport function zoomLevelBoundariesShouldUpdate(zoomLevelBoundaries: ZoomLevelLimits | undefined, targetMinZoomLevel: number | undefined): targetMinZoomLevel is number{\n if(targetMinZoomLevel == undefined){\n return false;\n }\n if(zoomLevelBoundaries == undefined){\n return true;\n }\n if(targetMinZoomLevel == Infinity){\n return false;\n }\n if(zoomLevelBoundaries !== undefined && (zoomLevelBoundaries.min == undefined || targetMinZoomLevel > zoomLevelBoundaries.min)){\n return true;\n }\n return false;\n}\n\n/**\n * Calculates minimum zoom level based only on boundary width.\n *\n * @param boundaries - The world-space boundaries\n * @param canvasWidth - Canvas width in pixels\n * @param canvasHeight - Canvas height in pixels\n * @param cameraRotation - Camera rotation angle in radians\n * @returns Minimum zoom level, or undefined if width is not defined\n *\n * @remarks\n * Similar to {@link minZoomLevelBaseOnDimensions} but only considers the\n * width constraint. Useful when height is unbounded or not relevant.\n *\n * Calculates zoom needed to fit the boundary width within the canvas,\n * accounting for rotation:\n * - Width projection on canvas X-axis: `width * cos(rotation)`\n * - Width projection on canvas Y-axis: `width * sin(rotation)`\n *\n * Takes the maximum of these to ensure the width fits regardless of\n * how rotation distributes it across canvas axes.\n *\n * @example\n * ```typescript\n * const boundaries = {\n * min: { x: 0 },\n * max: { x: 1000 }\n * };\n *\n * const zoom = minZoomLevelBaseOnWidth(boundaries, 800, 600, 0);\n * // Result: 0.8 (800/1000)\n * ```\n *\n * @category Camera\n * @see {@link minZoomLevelBaseOnDimensions} for full calculation\n */\nexport function minZoomLevelBaseOnWidth(boundaries: Boundaries | undefined, canvasWidth: number, canvasHeight: number, cameraRotation: number): number | undefined{\n const width = translationWidthOf(boundaries);\n if(width == undefined){\n return undefined;\n }\n const widthWidthProjection = Math.abs(width * Math.cos(cameraRotation));\n const widthHeightProjection = Math.abs(width * Math.sin(cameraRotation));\n const minZoomLevelWidthWidth = canvasWidth / widthWidthProjection;\n const minZoomLevelWidthHeight = canvasHeight / widthHeightProjection;\n if(minZoomLevelWidthWidth == Infinity){\n return minZoomLevelWidthHeight;\n }\n const minZoomLevel = Math.max(canvasWidth / widthWidthProjection, canvasHeight / widthHeightProjection);\n return minZoomLevel;\n}\n\n/**\n * Calculates minimum zoom level based only on boundary height.\n *\n * @param boundaries - The world-space boundaries\n * @param canvasWidth - Canvas width in pixels\n * @param canvasHeight - Canvas height in pixels\n * @param cameraRotation - Camera rotation angle in radians\n * @returns Minimum zoom level, or undefined if height is not defined\n *\n * @remarks\n * Similar to {@link minZoomLevelBaseOnDimensions} but only considers the\n * height constraint. Useful when width is unbounded or not relevant.\n *\n * Calculates zoom needed to fit the boundary height within the canvas,\n * accounting for rotation:\n * - Height projection on canvas X-axis: `height * cos(rotation)`\n * - Height projection on canvas Y-axis: `height * sin(rotation)`\n *\n * Takes the maximum of these to ensure the height fits regardless of\n * how rotation distributes it across canvas axes.\n *\n * @example\n * ```typescript\n * const boundaries = {\n * min: { y: 0 },\n * max: { y: 500 }\n * };\n *\n * const zoom = minZoomLevelBaseOnHeight(boundaries, 800, 600, 0);\n * // Result: 1.2 (600/500)\n * ```\n *\n * @category Camera\n * @see {@link minZoomLevelBaseOnDimensions} for full calculation\n */\nexport function minZoomLevelBaseOnHeight(boundaries: Boundaries | undefined, canvasWidth: number, canvasHeight: number, cameraRotation: number): number | undefined{\n const height = translationHeightOf(boundaries);\n if(height == undefined){\n return undefined;\n }\n const heightWidthProjection = Math.abs(height * Math.cos(cameraRotation));\n const heightHeightProjection = Math.abs(height * Math.sin(cameraRotation));\n const minZoomLevelHeightWidth = canvasWidth / heightWidthProjection;\n const minZoomLevelHeightHeight = canvasHeight / heightHeightProjection;\n if(minZoomLevelHeightHeight == Infinity){\n return minZoomLevelHeightWidth;\n }\n const minZoomLevel = Math.max(minZoomLevelHeightWidth, minZoomLevelHeightHeight);\n return minZoomLevel;\n}\n",
29
- "import type { Point } from \"@ue-too/math\";\nimport { AsyncObservable, Observable, Observer } from \"../../utils/observable\";\n\n/**\n * Function to unsubscribe from raw user input events.\n *\n * @remarks\n * Calling this function removes the subscriber from the event stream.\n *\n * @category Raw Input Publisher\n */\nexport type UnsubscribeToUserRawInput = () => void;\n\n/**\n * Payload for pan input events.\n *\n * @property diff - The pan delta in viewport pixels\n *\n * @category Raw Input Publisher\n */\nexport type RawUserPanInputEventPayload = {\n diff: Point;\n}\n\n/**\n * Pan input event with discriminated type.\n *\n * @remarks\n * The `type` property allows TypeScript discriminated unions to distinguish\n * between different event types when subscribing to the \"all\" event stream.\n *\n * @category Raw Input Publisher\n */\nexport type RawUserPanInputEvent = {\n type: \"pan\",\n} & RawUserPanInputEventPayload;\n\n/**\n * Payload for zoom input events.\n *\n * @property deltaZoomAmount - The zoom delta (scale change)\n * @property anchorPoint - The zoom anchor point in viewport coordinates\n *\n * @category Raw Input Publisher\n */\nexport type RawUserZoomInputEventPayload = {\n deltaZoomAmount: number;\n anchorPoint: Point;\n}\n\n/**\n * Zoom input event with discriminated type.\n *\n * @remarks\n * The `type` property allows TypeScript discriminated unions to distinguish\n * between different event types when subscribing to the \"all\" event stream.\n *\n * @category Raw Input Publisher\n */\nexport type RawUserZoomInputEvent = {\n type: \"zoom\",\n} & RawUserZoomInputEventPayload;\n\n/**\n * Payload for rotate input events.\n *\n * @property deltaRotation - The rotation delta in radians\n *\n * @category Raw Input Publisher\n */\nexport type RawUserRotateInputEventPayload = {\n deltaRotation: number;\n}\n\n/**\n * Rotate input event with discriminated type.\n *\n * @remarks\n * The `type` property allows TypeScript discriminated unions to distinguish\n * between different event types when subscribing to the \"all\" event stream.\n *\n * @category Raw Input Publisher\n */\nexport type RawUserRotateInputEvent = {\n type: \"rotate\",\n} & RawUserRotateInputEventPayload;\n\n/**\n * Mapping of event names to their payload types.\n *\n * @remarks\n * This type enables type-safe event subscription:\n * - Subscribe to specific events (\"pan\", \"zoom\", \"rotate\") to receive only those payloads\n * - Subscribe to \"all\" to receive all events with discriminated type property\n *\n * @category Raw Input Publisher\n */\nexport type RawUserInputEventMap = {\n \"pan\": RawUserPanInputEventPayload,\n \"zoom\": RawUserZoomInputEventPayload,\n \"rotate\": RawUserRotateInputEventPayload,\n \"all\": RawUserInputEvent,\n}\n\n/**\n * Union type of all raw user input events.\n *\n * @remarks\n * Use the `type` discriminator property to determine which event variant you have.\n *\n * @category Raw Input Publisher\n */\nexport type RawUserInputEvent = RawUserPanInputEvent | RawUserZoomInputEvent | RawUserRotateInputEvent;\n\n/**\n * Callback function type for raw user input events.\n *\n * @typeParam K - The event name key from RawUserInputEventMap\n *\n * @category Raw Input Publisher\n */\nexport type RawUserInputCallback<K extends keyof RawUserInputEventMap> = (event: RawUserInputEventMap[K])=>void;\n\n/**\n * Interface for publishing raw user input events to observers.\n *\n * @remarks\n * This interface defines the contract for broadcasting user input events\n * to external subscribers. Implementations provide the observable pattern\n * for input event distribution.\n *\n * @category Raw Input Publisher\n */\nexport interface UserInputPublisher {\n /** Notifies subscribers of a pan gesture */\n notifyPan(diff: Point): void;\n /** Notifies subscribers of a zoom gesture */\n notifyZoom(deltaZoomAmount: number, anchorPoint: Point): void;\n /** Notifies subscribers of a rotate gesture */\n notifyRotate(deltaRotation: number): void;\n /** Subscribes to input events */\n on<K extends keyof RawUserInputEventMap>(eventName: K, callback: (event: RawUserInputEventMap[K])=>void): UnsubscribeToUserRawInput;\n}\n\n/**\n * Publisher for broadcasting raw user input events to observers.\n *\n * @remarks\n * This class implements the observable pattern to distribute user input events\n * to external subscribers. It operates in parallel to camera control - the\n * orchestrator both sends events to this publisher AND controls the camera.\n *\n * **Architecture**:\n * ```\n * Orchestrator → Publisher → Observers (UI, analytics, etc.)\n * ↓\n * CameraMux → CameraRig\n * ```\n *\n * **Event Streams**:\n * - **Specific streams**: Subscribe to \"pan\", \"zoom\", or \"rotate\" for typed events\n * - **Unified stream**: Subscribe to \"all\" for all events with type discriminator\n *\n * **Use Cases**:\n * - Update UI elements based on user interactions\n * - Log analytics about user gestures\n * - Synchronize secondary views or previews\n * - Implement custom gesture reactions independent of camera\n *\n * **Observable Implementation**:\n * Uses AsyncObservable for asynchronous event delivery, preventing observers\n * from blocking the input processing pipeline.\n *\n * @category Raw Input Publisher\n *\n * @example\n * ```typescript\n * const publisher = new RawUserInputPublisher();\n *\n * // Subscribe to pan events\n * const unsubscribe = publisher.on(\"pan\", (event) => {\n * console.log(\"User panned by:\", event.diff);\n * updateMinimap(event.diff);\n * });\n *\n * // Subscribe to all events\n * publisher.on(\"all\", (event) => {\n * switch (event.type) {\n * case \"pan\":\n * analytics.log(\"pan\", event.diff);\n * break;\n * case \"zoom\":\n * analytics.log(\"zoom\", event.deltaZoomAmount, event.anchorPoint);\n * break;\n * case \"rotate\":\n * analytics.log(\"rotate\", event.deltaRotation);\n * break;\n * }\n * });\n *\n * // Later, unsubscribe\n * unsubscribe();\n * ```\n */\nexport class RawUserInputPublisher implements UserInputPublisher {\n\n private pan: Observable<Parameters<RawUserInputCallback<\"pan\">>>;\n private zoom: Observable<Parameters<RawUserInputCallback<\"zoom\">>>;\n private rotate: Observable<Parameters<RawUserInputCallback<\"rotate\">>>;\n private all: Observable<Parameters<RawUserInputCallback<\"all\">>>;\n\n constructor(){\n this.pan = new AsyncObservable<Parameters<RawUserInputCallback<\"pan\">>>();\n this.zoom = new AsyncObservable<Parameters<RawUserInputCallback<\"zoom\">>>();\n this.rotate = new AsyncObservable<Parameters<RawUserInputCallback<\"rotate\">>>();\n this.all = new AsyncObservable<Parameters<RawUserInputCallback<\"all\">>>();\n }\n\n notifyPan(diff: Point): void {\n this.pan.notify({diff: diff});\n this.all.notify({type: \"pan\", diff: diff});\n }\n\n notifyZoom(deltaZoomAmount: number, anchorPoint: Point): void {\n this.zoom.notify({deltaZoomAmount: deltaZoomAmount, anchorPoint: anchorPoint});\n this.all.notify({type: \"zoom\", deltaZoomAmount: deltaZoomAmount, anchorPoint: anchorPoint});\n }\n\n notifyRotate(deltaRotation: number): void {\n this.rotate.notify({deltaRotation: deltaRotation});\n this.all.notify({type: \"rotate\", deltaRotation: deltaRotation});\n }\n\n on<K extends keyof RawUserInputEventMap>(eventName: K, callback: (event: RawUserInputEventMap[K])=>void): UnsubscribeToUserRawInput {\n switch (eventName){\n case \"pan\":\n return this.pan.subscribe(callback as Observer<Parameters<RawUserInputCallback<\"pan\">>>);\n case \"zoom\":\n return this.zoom.subscribe(callback as Observer<Parameters<RawUserInputCallback<\"zoom\">>>);\n case \"rotate\":\n return this.rotate.subscribe(callback as Observer<Parameters<RawUserInputCallback<\"rotate\">>>);\n case \"all\":\n return this.all.subscribe(callback as Observer<Parameters<RawUserInputCallback<\"all\">>>);\n default:\n throw new Error(\"Invalid raw user input event name\");\n }\n }\n}\n\n/**\n * Creates a default raw user input publisher.\n *\n * @returns A new RawUserInputPublisher instance\n *\n * @remarks\n * Factory function for creating a standard publisher. Useful for dependency injection\n * and testing scenarios where you want to swap implementations.\n *\n * @category Raw Input Publisher\n */\nexport function createDefaultRawUserInputPublisher(): RawUserInputPublisher {\n return new RawUserInputPublisher();\n}\n\nexport class RawUserInputPublisherWithWebWorkerRelay implements UserInputPublisher {\n\n private pan: Observable<Parameters<RawUserInputCallback<\"pan\">>>;\n private zoom: Observable<Parameters<RawUserInputCallback<\"zoom\">>>;\n private rotate: Observable<Parameters<RawUserInputCallback<\"rotate\">>>;\n private all: Observable<Parameters<RawUserInputCallback<\"all\">>>;\n private webWorker: Worker;\n\n constructor(webWorker: Worker){\n this.pan = new AsyncObservable<Parameters<RawUserInputCallback<\"pan\">>>();\n this.zoom = new AsyncObservable<Parameters<RawUserInputCallback<\"zoom\">>>();\n this.rotate = new AsyncObservable<Parameters<RawUserInputCallback<\"rotate\">>>();\n this.all = new AsyncObservable<Parameters<RawUserInputCallback<\"all\">>>();\n this.webWorker = webWorker;\n }\n\n notifyPan(diff: Point): void {\n this.webWorker.postMessage({type: \"notifyUserInput\", payload: {type: \"pan\", diff: diff}});\n this.pan.notify({diff: diff});\n this.all.notify({type: \"pan\", diff: diff});\n }\n\n notifyZoom(deltaZoomAmount: number, anchorPoint: Point): void {\n this.webWorker.postMessage({type: \"notifyUserInput\", payload: {type: \"zoom\", deltaZoomAmount: deltaZoomAmount, anchorPoint: anchorPoint}});\n this.zoom.notify({deltaZoomAmount: deltaZoomAmount, anchorPoint: anchorPoint});\n this.all.notify({type: \"zoom\", deltaZoomAmount: deltaZoomAmount, anchorPoint: anchorPoint});\n }\n\n notifyRotate(deltaRotation: number): void {\n this.webWorker.postMessage({type: \"notifyUserInput\", payload: {type: \"rotate\", deltaRotation: deltaRotation}});\n this.rotate.notify({deltaRotation: deltaRotation});\n this.all.notify({type: \"rotate\", deltaRotation: deltaRotation});\n }\n \n on<K extends keyof RawUserInputEventMap>(eventName: K, callback: (event: RawUserInputEventMap[K])=>void): UnsubscribeToUserRawInput {\n switch (eventName){\n case \"pan\":\n return this.pan.subscribe(callback as Observer<Parameters<RawUserInputCallback<\"pan\">>>);\n case \"zoom\":\n return this.zoom.subscribe(callback as Observer<Parameters<RawUserInputCallback<\"zoom\">>>);\n case \"rotate\":\n return this.rotate.subscribe(callback as Observer<Parameters<RawUserInputCallback<\"rotate\">>>);\n case \"all\":\n return this.all.subscribe(callback as Observer<Parameters<RawUserInputCallback<\"all\">>>);\n default:\n throw new Error(\"Invalid raw user input event name\");\n }\n }\n}\n",
30
- "/**\n * Base context interface for state machines.\n *\n * @remarks\n * The context is shared across all states in a state machine and can be used to store data\n * that persists between state transitions. All custom contexts must extend this interface.\n *\n * The setup and cleanup methods provide lifecycle hooks for resource management:\n * - `setup()`: Called when the context is initialized\n * - `cleanup()`: Called when the context is destroyed\n *\n * @example\n * ```typescript\n * interface MyContext extends BaseContext {\n * counter: number;\n * data: string[];\n * setup() {\n * this.counter = 0;\n * this.data = [];\n * }\n * cleanup() {\n * this.data = [];\n * }\n * }\n * ```\n *\n * @category Core\n */\nexport interface BaseContext {\n setup(): void;\n cleanup(): void;\n}\n\ntype NOOP = () => void;\n\n/**\n * Utility type to check if an object type is empty.\n * @internal\n */\ntype IsEmptyObject<T> = T extends {} ? {} extends T ? true : false : false;\n\n/**\n * Utility type to derive a string literal union from a readonly array of string literals.\n *\n * @remarks\n * This helper type extracts the element types from a readonly array to create a union type.\n * Useful for defining state machine states from an array.\n *\n * @example\n * ```typescript\n * const TEST_STATES = [\"one\", \"two\", \"three\"] as const;\n * type TestStates = CreateStateType<typeof TEST_STATES>; // \"one\" | \"two\" | \"three\"\n * ```\n *\n * @category Utilities\n */\nexport type CreateStateType<ArrayLiteral extends readonly string[]> = ArrayLiteral[number];\n\n/**\n * Type for event arguments with conditional payload requirement.\n *\n * @remarks\n * This utility type determines whether an event requires a payload argument based on the\n * event payload mapping. If the payload is an empty object, no payload is required.\n *\n * @typeParam EventPayloadMapping - Mapping of event names to their payload types\n * @typeParam K - The event key\n *\n * @category Utilities\n */\nexport type EventArgs<EventPayloadMapping, K> =\n K extends keyof EventPayloadMapping\n ? IsEmptyObject<EventPayloadMapping[K]> extends true\n ? [event: K] // No payload needed\n : [event: K, payload: EventPayloadMapping[K]] // Payload required\n : [event: K, payload?: unknown]; // Unknown events\n\n/**\n * No-operation function constant used as a placeholder for optional actions.\n *\n * @remarks\n * Use this when you need to provide a function but don't want it to do anything,\n * such as for default state transition actions that have no side effects.\n *\n * @category Core\n */\nexport const NO_OP: NOOP = ()=>{};\n\n/**\n * Result type indicating an event was not handled by the current state.\n *\n * @remarks\n * When a state doesn't have a handler defined for a particular event, it returns this type.\n * The state machine will not transition and the event is effectively ignored.\n *\n * @category Core\n */\nexport type EventNotHandled = {\n handled: false;\n}\n\n/**\n * Helper type that conditionally includes the output property.\n * @internal\n */\ntype WithOutput<Output> = Output extends void ? {} : { output?: Output };\n\n/**\n * Result type when an event is successfully handled by a state.\n *\n * @remarks\n * This type represents a successful event handling result. It can optionally include:\n * - `nextState`: The state to transition to (if different from current)\n * - `output`: A return value from the event handler (only present when Output is not void)\n *\n * @typeParam States - Union of all possible state names in the state machine\n * @typeParam Output - The output type for this event (defaults to void)\n *\n * @example\n * ```typescript\n * // Simple transition without output\n * const result: EventHandled<\"IDLE\" | \"ACTIVE\"> = {\n * handled: true,\n * nextState: \"ACTIVE\"\n * // output property does not exist when Output is void\n * };\n *\n * // With output value\n * const resultWithOutput: EventHandled<\"IDLE\" | \"ACTIVE\", number> = {\n * handled: true,\n * nextState: \"IDLE\",\n * output: 42\n * };\n * ```\n *\n * @category Core\n */\nexport type EventHandled<States extends string, Output = void> = {\n handled: true;\n nextState?: States;\n} & WithOutput<Output>;\n\n/**\n * Discriminated union representing the result of event handling.\n *\n * @remarks\n * Every event handler returns an EventResult, which is either:\n * - {@link EventHandled}: The event was processed successfully\n * - {@link EventNotHandled}: The event was not recognized/handled\n *\n * Use the `handled` discriminant to narrow the type in TypeScript.\n *\n * @typeParam States - Union of all possible state names\n * @typeParam Output - The output type for handled events\n *\n * @category Core\n */\nexport type EventResult<States extends string, Output = void> = EventNotHandled | EventHandled<States, Output>;\n\n/**\n * @description A default output mapping that maps all events to void.\n * Used as default when no output mapping is provided.\n * \n * @category Types\n */\nexport type DefaultOutputMapping<EventPayloadMapping> = {\n [K in keyof EventPayloadMapping]: void;\n};\n\n/**\n * @description This is the interface for the state machine. The interface takes in a few generic parameters.\n * \n * Generic parameters:\n * - EventPayloadMapping: A mapping of events to their payloads.\n * - Context: The context of the state machine. (which can be used by each state to do calculations that would persist across states)\n * - States: All of the possible states that the state machine can be in. e.g. a string literal union like \"IDLE\" | \"SELECTING\" | \"PAN\" | \"ZOOM\"\n * - EventOutputMapping: A mapping of events to their output types. Defaults to void for all events.\n * \n * You can probably get by using the TemplateStateMachine class.\n * The naming is that an event would \"happen\" and the state of the state machine would \"handle\" it.\n *\n * @see {@link TemplateStateMachine}\n * @see {@link KmtInputStateMachine}\n * \n * @category Types\n */\nexport interface StateMachine<\n EventPayloadMapping, \n Context extends BaseContext, \n States extends string = 'IDLE',\n EventOutputMapping extends Partial<Record<keyof EventPayloadMapping, unknown>> = DefaultOutputMapping<EventPayloadMapping>\n> {\n switchTo(state: States): void;\n // Overload for known events - provides IntelliSense with typed output\n happens<K extends keyof EventPayloadMapping>(\n ...args: EventArgs<EventPayloadMapping, K>\n ): EventResult<States, K extends keyof EventOutputMapping ? EventOutputMapping[K] : void>;\n // Overload for unknown events - maintains backward compatibility\n happens<K extends string>(\n ...args: EventArgs<EventPayloadMapping, K>\n ): EventResult<States, unknown>;\n setContext(context: Context): void;\n states: Record<States, State<EventPayloadMapping, Context, string extends States ? string : States, EventOutputMapping>>;\n onStateChange(callback: StateChangeCallback<States>): void;\n possibleStates: States[];\n onHappens(callback: (args: EventArgs<EventPayloadMapping, keyof EventPayloadMapping | string>, context: Context) => void): void;\n reset(): void;\n start(): void;\n wrapup(): void;\n}\n\n/**\n * @description This is the type for the callback that is called when the state changes.\n *\n * @category Types\n */\nexport type StateChangeCallback<States extends string = 'IDLE'> = (currentState: States, nextState: States) => void;\n\n/**\n * @description This is the interface for the state. The interface takes in a few generic parameters:\n * You can probably get by extending the TemplateState class. \n *\n * Generic parameters:\n * - EventPayloadMapping: A mapping of events to their payloads.\n * - Context: The context of the state machine. (which can be used by each state to do calculations that would persist across states)\n * - States: All of the possible states that the state machine can be in. e.g. a string literal union like \"IDLE\" | \"SELECTING\" | \"PAN\" | \"ZOOM\"\n * - EventOutputMapping: A mapping of events to their output types. Defaults to void for all events.\n * \n * A state's all possible states can be only a subset of the possible states of the state machine. (a state only needs to know what states it can transition to)\n * This allows for a state to be reusable across different state machines.\n *\n * @see {@link TemplateState}\n * \n * @category Types\n */\nexport interface State<\n EventPayloadMapping, \n Context extends BaseContext, \n States extends string = 'IDLE',\n EventOutputMapping extends Partial<Record<keyof EventPayloadMapping, unknown>> = DefaultOutputMapping<EventPayloadMapping>\n> { \n uponEnter(context: Context, stateMachine: StateMachine<EventPayloadMapping, Context, States, EventOutputMapping>, from: States | \"INITIAL\"): void;\n beforeExit(context: Context, stateMachine: StateMachine<EventPayloadMapping, Context, States, EventOutputMapping>, to: States | \"TERMINAL\"): void;\n handles<K extends (keyof EventPayloadMapping | string)>(args: EventArgs<EventPayloadMapping, K>, context: Context, stateMachine: StateMachine<EventPayloadMapping, Context, States, EventOutputMapping>): EventResult<States, K extends keyof EventOutputMapping ? EventOutputMapping[K] : void>;\n eventReactions: EventReactions<EventPayloadMapping, Context, States, EventOutputMapping>;\n guards: Guard<Context>;\n eventGuards: Partial<EventGuards<EventPayloadMapping, States, Context, Guard<Context>>>;\n delay: Delay<Context, EventPayloadMapping, States, EventOutputMapping> | undefined;\n}\n\n/**\n * @description This is the type for the event reactions of a state.\n * \n * Generic parameters:\n * - EventPayloadMapping: A mapping of events to their payloads.\n * - Context: The context of the state machine. (which can be used by each state to do calculations that would persist across states)\n * - States: All of the possible states that the state machine can be in. e.g. a string literal union like \"IDLE\" | \"SELECTING\" | \"PAN\" | \"ZOOM\"\n * - EventOutputMapping: A mapping of events to their output types. Defaults to void for all events.\n * \n * The action function can now return an output value that will be included in the EventHandledResult.\n * \n * @category Types\n */\nexport type EventReactions<\n EventPayloadMapping, \n Context extends BaseContext, \n States extends string,\n EventOutputMapping extends Partial<Record<keyof EventPayloadMapping, unknown>> = DefaultOutputMapping<EventPayloadMapping>\n> = {\n [K in keyof Partial<EventPayloadMapping>]: { \n action: (\n context: Context, \n event: EventPayloadMapping[K], \n stateMachine: StateMachine<EventPayloadMapping, Context, States, EventOutputMapping>\n ) => K extends keyof EventOutputMapping ? (EventOutputMapping[K] | void) : void;\n defaultTargetState?: States;\n };\n};\n\n/**\n * @description This is the type for the guard evaluation when a state transition is happening.\n * \n * Guard evaluations are evaluated after the state has handled the event with the action.\n * Guard evaluations can be defined in an array and the first guard that evaluates to true will be used to determine the next state.\n * \n * Generic parameters:\n * - Context: The context of the state machine. (which can be used by each state to do calculations that would persist across states)\n * \n * @category Types\n */\nexport type GuardEvaluation<Context extends BaseContext> = (context: Context) => boolean;\n\n/**\n * @description This is the type for the guard of a state.\n * \n * guard is an object that maps a key to a guard evaluation.\n * K is all the possible keys that can be used to evaluate the guard.\n * K is optional but if it is not provided, typescript won't be able to type guard in the EventGuards type.\n * \n * @category Types\n */\nexport type Guard<Context extends BaseContext, K extends string = string> = {\n [P in K]: GuardEvaluation<Context>;\n}\n\nexport type Action<\n Context extends BaseContext, \n EventPayloadMapping, \n States extends string,\n EventOutputMapping extends Partial<Record<keyof EventPayloadMapping, unknown>> = DefaultOutputMapping<EventPayloadMapping>,\n Output = void\n> = {\n action: (context: Context, event: EventPayloadMapping[keyof EventPayloadMapping], stateMachine: StateMachine<EventPayloadMapping, Context, States, EventOutputMapping>) => Output | void;\n defaultTargetState?: States;\n}\n\nexport type Delay<\n Context extends BaseContext, \n EventPayloadMapping, \n States extends string,\n EventOutputMapping extends Partial<Record<keyof EventPayloadMapping, unknown>> = DefaultOutputMapping<EventPayloadMapping>\n> = {\n time: number;\n action: Action<Context, EventPayloadMapping, States, EventOutputMapping>;\n}\n\n/**\n * @description This is a mapping of a guard to a target state.\n * \n * Generic parameters:\n * - Context: The context of the state machine. (which can be used by each state to do calculations that would persist across states)\n * - G: The guard type.\n * - States: All of the possible states that the state machine can be in. e.g. a string literal union like \"IDLE\" | \"SELECTING\" | \"PAN\" | \"ZOOM\"\n * \n * You probably don't need to use this type directly.\n * \n * @see {@link TemplateState['eventGuards']}\n * \n * @category Types\n */\nexport type GuardMapping<Context extends BaseContext, G, States extends string> = {\n guard: G extends Guard<Context, infer K> ? K : never;\n target: States;\n}\n\n/**\n * @description This is a mapping of an event to a guard evaluation.\n * \n * Generic parameters:\n * - EventPayloadMapping: A mapping of events to their payloads.\n * - States: All of the possible states that the state machine can be in. e.g. a string literal union like \"IDLE\" | \"SELECTING\" | \"PAN\" | \"ZOOM\"\n * - Context: The context of the state machine. (which can be used by each state to do calculations that would persist across states)\n * - T: The guard type.\n * \n * You probably don't need to use this type directly.\n * This is a mapping of an event to a guard evaluation.\n * \n * @see {@link TemplateState['eventGuards']}\n * \n * @category Types\n */\nexport type EventGuards<EventPayloadMapping, States extends string, Context extends BaseContext, T extends Guard<Context>> = {\n [K in keyof EventPayloadMapping]: GuardMapping<Context, T, States>[];\n}\n\n/**\n * Concrete implementation of a finite state machine.\n *\n * @remarks\n * This class provides a complete, ready-to-use state machine implementation. It's generic enough\n * to handle most use cases without requiring custom extensions.\n *\n * ## Features\n *\n * - **Type-safe events**: Events and their payloads are fully typed via the EventPayloadMapping\n * - **State transitions**: Automatic state transitions based on event handlers\n * - **Event outputs**: Handlers can return values that are included in the result\n * - **Lifecycle hooks**: States can define `uponEnter` and `beforeExit` callbacks\n * - **State change listeners**: Subscribe to state transitions\n * - **Shared context**: All states access the same context object for persistent data\n *\n * ## Usage Pattern\n *\n * 1. Define your event payload mapping type\n * 2. Define your states as a string union type\n * 3. Create state classes extending {@link TemplateState}\n * 4. Instantiate TemplateStateMachine with your states and initial state\n *\n * @typeParam EventPayloadMapping - Object mapping event names to their payload types\n * @typeParam Context - Context type shared across all states\n * @typeParam States - Union of all possible state names (string literals)\n * @typeParam EventOutputMapping - Optional mapping of events to their output types\n *\n * @example\n * Basic vending machine state machine\n * ```typescript\n * type Events = {\n * insertCoin: { amount: number };\n * selectItem: { itemId: string };\n * cancel: {};\n * };\n *\n * type States = \"IDLE\" | \"PAYMENT\" | \"DISPENSING\";\n *\n * interface VendingContext extends BaseContext {\n * balance: number;\n * setup() { this.balance = 0; }\n * cleanup() {}\n * }\n *\n * const context: VendingContext = {\n * balance: 0,\n * setup() { this.balance = 0; },\n * cleanup() {}\n * };\n *\n * const machine = new TemplateStateMachine<Events, VendingContext, States>(\n * {\n * IDLE: new IdleState(),\n * PAYMENT: new PaymentState(),\n * DISPENSING: new DispensingState()\n * },\n * \"IDLE\",\n * context\n * );\n *\n * // Trigger events\n * machine.happens(\"insertCoin\", { amount: 100 });\n * machine.happens(\"selectItem\", { itemId: \"A1\" });\n * ```\n *\n * @category State Machine Core\n * @see {@link TemplateState} for creating state implementations\n * @see {@link StateMachine} for the interface definition\n */\nexport class TemplateStateMachine<\n EventPayloadMapping, \n Context extends BaseContext, \n States extends string = 'IDLE',\n EventOutputMapping extends Partial<Record<keyof EventPayloadMapping, unknown>> = DefaultOutputMapping<EventPayloadMapping>\n> implements StateMachine<EventPayloadMapping, Context, States, EventOutputMapping> {\n\n protected _currentState: States | \"INITIAL\" | \"TERMINAL\";\n protected _states: Record<States, State<EventPayloadMapping, Context, States, EventOutputMapping>>;\n protected _context: Context;\n protected _statesArray: States[];\n protected _stateChangeCallbacks: StateChangeCallback<States>[];\n protected _happensCallbacks: ((args: EventArgs<EventPayloadMapping, keyof EventPayloadMapping | string>, context: Context) => void)[];\n protected _timeouts: ReturnType<typeof setTimeout> | undefined = undefined;\n protected _initialState: States;\n\n constructor(states: Record<States, State<EventPayloadMapping, Context, States, EventOutputMapping>>, initialState: States, context: Context, autoStart: boolean = true){\n this._states = states;\n this._currentState = \"INITIAL\";\n this._initialState = initialState;\n this._context = context;\n this._statesArray = Object.keys(states) as States[];\n this._stateChangeCallbacks = [];\n this._happensCallbacks = [];\n if(autoStart){\n this.start();\n }\n }\n\n reset(): void {\n this.wrapup();\n this.switchTo(\"INITIAL\");\n this.start();\n }\n\n start(): void {\n if(this.currentState !== \"INITIAL\"){\n return;\n }\n this._context.setup();\n this.switchTo(this._initialState);\n this._states[this._initialState].uponEnter(this._context, this, this._initialState);\n }\n\n wrapup(): void {\n if(this._currentState === \"TERMINAL\") {\n return;\n }\n const originalState = this._currentState;\n if(originalState !== \"INITIAL\") {\n this._states[originalState].beforeExit(this._context, this, \"TERMINAL\");\n }\n this._context.cleanup();\n this.switchTo(\"TERMINAL\");\n }\n\n switchTo(state: States | \"INITIAL\" | \"TERMINAL\"): void {\n this._currentState = state;\n }\n \n // Implementation signature - matches both overloads\n happens<K extends keyof EventPayloadMapping>(...args: EventArgs<EventPayloadMapping, K>): EventResult<States, K extends keyof EventOutputMapping ? EventOutputMapping[K] : void>;\n happens<K extends string>(...args: EventArgs<EventPayloadMapping, K>): EventResult<States, unknown>;\n happens<K extends keyof EventPayloadMapping | string>(...args: EventArgs<EventPayloadMapping, K>): EventResult<States, unknown> {\n if(this._timeouts){\n clearTimeout(this._timeouts);\n }\n if(this._currentState === \"INITIAL\" || this._currentState === \"TERMINAL\"){\n return { handled: false };\n }\n this._happensCallbacks.forEach(callback => callback(args, this._context));\n const result = this._states[this._currentState].handles(args, this._context, this);\n if(result.handled && result.nextState !== undefined && result.nextState !== this._currentState){ // TODO: whether or not to transition to the same state (currently no, uponEnter and beforeExit will not be called if the state is the same)\n const originalState = this._currentState;\n this._states[this._currentState].beforeExit(this._context, this, result.nextState);\n this.switchTo(result.nextState);\n this._states[this._currentState].uponEnter(this._context, this, originalState);\n for(const callback of this._stateChangeCallbacks){\n callback(originalState, this._currentState);\n }\n }\n return result;\n }\n\n onStateChange(callback: StateChangeCallback<States>): void {\n this._stateChangeCallbacks.push(callback);\n }\n\n onHappens(callback: (args: EventArgs<EventPayloadMapping, keyof EventPayloadMapping | string>, context: Context) => void): void {\n this._happensCallbacks.push(callback);\n }\n\n get currentState(): States | \"INITIAL\" | \"TERMINAL\" {\n return this._currentState;\n }\n\n setContext(context: Context): void {\n this._context = context;\n }\n\n get possibleStates(): States[] {\n return this._statesArray;\n }\n\n get states(): Record<States, State<EventPayloadMapping, Context, States, EventOutputMapping>> {\n return this._states;\n }\n}\n/**\n * Abstract base class for state machine states.\n *\n * @remarks\n * This abstract class provides the foundation for implementing individual states in a state machine.\n * Each state defines how it responds to events through the `eventReactions` object.\n *\n * ## Key Concepts\n *\n * - **Event Reactions**: Define handlers for events this state cares about. Unhandled events are ignored.\n * - **Guards**: Conditional logic that determines which state to transition to based on context\n * - **Lifecycle Hooks**: `uponEnter` and `beforeExit` callbacks for state transition side effects\n * - **Selective Handling**: Only define reactions for events relevant to this state\n *\n * ## Implementation Pattern\n *\n * 1. Extend this class for each state in your state machine\n * 2. Implement the `eventReactions` property with handlers for relevant events\n * 3. Optionally override `uponEnter` and `beforeExit` for lifecycle logic\n * 4. Optionally define `guards` and `eventGuards` for conditional transitions\n *\n * @typeParam EventPayloadMapping - Object mapping event names to their payload types\n * @typeParam Context - Context type shared across all states\n * @typeParam States - Union of all possible state names (string literals)\n * @typeParam EventOutputMapping - Optional mapping of events to their output types\n *\n * @example\n * Simple state implementation\n * ```typescript\n * class IdleState extends TemplateState<MyEvents, MyContext, MyStates> {\n * eventReactions = {\n * start: {\n * action: (context, event) => {\n * console.log('Starting...');\n * context.startTime = Date.now();\n * },\n * defaultTargetState: \"ACTIVE\"\n * },\n * reset: {\n * action: (context, event) => {\n * context.counter = 0;\n * }\n * // No state transition - stays in IDLE\n * }\n * };\n *\n * uponEnter(context, stateMachine, fromState) {\n * console.log(`Entered IDLE from ${fromState}`);\n * }\n * }\n * ```\n *\n * @example\n * State with guards for conditional transitions\n * ```typescript\n * class PaymentState extends TemplateState<Events, VendingContext, States> {\n * guards = {\n * hasEnoughMoney: (context) => context.balance >= context.itemPrice,\n * needsChange: (context) => context.balance > context.itemPrice\n * };\n *\n * eventReactions = {\n * selectItem: {\n * action: (context, event) => {\n * context.selectedItem = event.itemId;\n * context.itemPrice = getPrice(event.itemId);\n * },\n * defaultTargetState: \"IDLE\" // Fallback if no guard matches\n * }\n * };\n *\n * eventGuards = {\n * selectItem: [\n * { guard: 'hasEnoughMoney', target: 'DISPENSING' },\n * // If hasEnoughMoney is false, uses defaultTargetState (IDLE)\n * ]\n * };\n * }\n * ```\n *\n * @category State Machine Core\n * @see {@link TemplateStateMachine} for the state machine implementation\n * @see {@link EventReactions} for defining event handlers\n */\nexport abstract class TemplateState<\n EventPayloadMapping, \n Context extends BaseContext, \n States extends string = 'IDLE',\n EventOutputMapping extends Partial<Record<keyof EventPayloadMapping, unknown>> = DefaultOutputMapping<EventPayloadMapping>\n> implements State<EventPayloadMapping, Context, States, EventOutputMapping> {\n\n public abstract eventReactions: EventReactions<EventPayloadMapping, Context, States, EventOutputMapping>;\n protected _guards: Guard<Context> = {} as Guard<Context>;\n protected _eventGuards: Partial<EventGuards<EventPayloadMapping, States, Context, Guard<Context>>> = {} as Partial<EventGuards<EventPayloadMapping, States, Context, Guard<Context>>>;\n protected _delay: Delay<Context, EventPayloadMapping, States, EventOutputMapping> | undefined = undefined;\n\n get guards(): Guard<Context> {\n return this._guards;\n }\n\n get eventGuards(): Partial<EventGuards<EventPayloadMapping, States, Context, Guard<Context>>> {\n return this._eventGuards;\n }\n\n get delay(): Delay<Context, EventPayloadMapping, States, EventOutputMapping> | undefined {\n return this._delay;\n }\n\n uponEnter(context: Context, stateMachine: StateMachine<EventPayloadMapping, Context, States, EventOutputMapping>, from: States | \"INITIAL\"): void {\n // console.log(\"enter\");\n }\n\n beforeExit(context: Context, stateMachine: StateMachine<EventPayloadMapping, Context, States, EventOutputMapping>, to: States | \"TERMINAL\"): void {\n // console.log('leave');\n }\n\n handles<K extends (keyof EventPayloadMapping | string)>(args: EventArgs<EventPayloadMapping, K>, context: Context, stateMachine: StateMachine<EventPayloadMapping, Context, States, EventOutputMapping>): EventResult<States, K extends keyof EventOutputMapping ? EventOutputMapping[K] : void>{\n const eventKey = args[0] as keyof EventPayloadMapping;\n const eventPayload = args[1] as EventPayloadMapping[keyof EventPayloadMapping];\n if (this.eventReactions[eventKey]) {\n // Capture the output from the action\n const output = this.eventReactions[eventKey].action(context, eventPayload, stateMachine);\n const targetState = this.eventReactions[eventKey].defaultTargetState;\n const guardsToEvaluate = this._eventGuards[eventKey];\n const baseResult = { handled: true as const, nextState: targetState };\n const resultWithOutput = output !== undefined \n ? { ...baseResult, output } \n : baseResult;\n \n if(guardsToEvaluate){\n const target = guardsToEvaluate.find((guard)=>{\n if(this.guards[guard.guard]){\n return this.guards[guard.guard](context);\n }\n return false;\n });\n const finalResult = target \n ? { ...resultWithOutput, nextState: target.target }\n : resultWithOutput;\n return finalResult as EventResult<States, K extends keyof EventOutputMapping ? EventOutputMapping[K] : void>;\n }\n return resultWithOutput as EventResult<States, K extends keyof EventOutputMapping ? EventOutputMapping[K] : void>;\n }\n return {handled: false};\n }\n}\n\n\n/**\n * Creates a type guard function for checking if a value belongs to a specific set of states.\n *\n * @remarks\n * This utility function generates a TypeScript type guard that narrows a string type\n * to a specific union of string literals. Useful when you have multiple state types\n * and need to distinguish between them at runtime.\n *\n * @typeParam T - String literal type to guard for\n * @param set - Readonly array of string literals defining the valid states\n * @returns A type guard function that checks if a string is in the set\n *\n * @example\n * Creating state guards for hierarchical state machines\n * ```typescript\n * type MainStates = \"idle\" | \"active\" | \"paused\";\n * type SubStates = \"loading\" | \"processing\" | \"complete\";\n * type AllStates = MainStates | SubStates;\n *\n * const MAIN_STATES = [\"idle\", \"active\", \"paused\"] as const;\n * const isMainState = createStateGuard(MAIN_STATES);\n *\n * function handleState(state: AllStates) {\n * if (isMainState(state)) {\n * // TypeScript knows state is MainStates here\n * console.log('Main state:', state);\n * } else {\n * // TypeScript knows state is SubStates here\n * console.log('Sub state:', state);\n * }\n * }\n * ```\n *\n * @category Utilities\n */\nexport function createStateGuard<T extends string>(set: readonly T[]) {\n return (s: string): s is T => set.includes(s as T);\n}\n",
31
- "import { Point } from \"@ue-too/math\";\nimport type { EventReactions, State, BaseContext } from \"@ue-too/being\";\nimport { NO_OP, TemplateState, TemplateStateMachine } from \"@ue-too/being\";\n\n/**\n * State identifiers for the pan control state machine.\n *\n * @remarks\n * Three states manage pan input and animations:\n * - `ACCEPTING_USER_INPUT`: Normal state, accepts user pan input\n * - `TRANSITION`: Animation/transition state, may block user input\n * - `LOCKED_ON_OBJECT`: Camera locked to follow a specific object/position\n *\n * @category Input Flow Control\n */\nexport type PanControlStates = \"ACCEPTING_USER_INPUT\" | \"TRANSITION\" | \"LOCKED_ON_OBJECT\";\n\n/**\n * Payload for pan-by input events (relative panning).\n * @category Input Flow Control\n */\nexport type PanByInputEventPayload = {\n /** Pan displacement in viewport coordinates */\n diff: Point;\n};\n\n/**\n * Payload for pan-to input events (absolute panning).\n * @category Input Flow Control\n */\nexport type PanToInputEventPayload = {\n /** Target position to pan to */\n target: Point;\n};\n\n/** Empty payload for events that don't need data */\ntype EmptyPayload = {};\n\n/**\n * Event payload type mapping for the pan control state machine.\n *\n * @remarks\n * Maps event names to their payload types. Events include:\n * - User input events (`userPanByInput`, `userPanToInput`)\n * - Transition/animation events (`transitionPanByInput`, `transitionPanToInput`)\n * - Locked object events (`lockedOnObjectPanByInput`, `lockedOnObjectPanToInput`)\n * - Control events (`unlock`, `initateTransition`)\n *\n * @category Input Flow Control\n */\nexport type PanEventPayloadMapping = {\n \"userPanByInput\": PanByInputEventPayload,\n \"userPanToInput\": PanToInputEventPayload,\n \"transitionPanByInput\": PanByInputEventPayload,\n \"transitionPanToInput\": PanToInputEventPayload,\n \"lockedOnObjectPanByInput\": PanByInputEventPayload,\n \"lockedOnObjectPanToInput\": PanToInputEventPayload,\n \"unlock\": EmptyPayload,\n \"initateTransition\": EmptyPayload,\n};\n\n/**\n * Discriminated union of output events from pan control state machine.\n *\n * @remarks\n * Output events instruct the camera system what pan operation to perform:\n * - `panByViewPort`: Relative pan in viewport coordinates\n * - `panToWorld`: Absolute pan to world position\n * - `none`: No operation (input blocked)\n *\n * @category Input Flow Control\n */\nexport type PanControlOutputEvent =\n | { type: \"panByViewPort\", delta: Point }\n | { type: \"panToWorld\", target: Point }\n | { type: \"none\" };\n\n/**\n * Output event type mapping for pan control events.\n * Maps input event names to their corresponding output event types.\n *\n * @category Input Flow Control\n */\nexport type PanControlOutputMapping = {\n \"userPanByInput\": PanControlOutputEvent,\n \"userPanToInput\": PanControlOutputEvent,\n \"transitionPanByInput\": PanControlOutputEvent,\n \"transitionPanToInput\": PanControlOutputEvent,\n \"lockedOnObjectPanByInput\": PanControlOutputEvent,\n \"lockedOnObjectPanToInput\": PanControlOutputEvent,\n};\n\n\n/**\n * State machine controlling pan input flow and animations.\n *\n * @remarks\n * This state machine manages the lifecycle of pan operations:\n * - **User input handling**: Accepts or blocks user pan gestures based on state\n * - **Animation control**: Manages smooth pan-to animations\n * - **Object tracking**: Supports locking camera to follow objects\n *\n * **State transitions:**\n * - `ACCEPTING_USER_INPUT` → `TRANSITION`: Start animation (`initateTransition`)\n * - `ACCEPTING_USER_INPUT` → `LOCKED_ON_OBJECT`: Lock to object (`lockedOnObjectPan...`)\n * - `TRANSITION` → `ACCEPTING_USER_INPUT`: User input interrupts animation\n * - `LOCKED_ON_OBJECT` → `ACCEPTING_USER_INPUT`: Unlock (`unlock` event)\n *\n * Helper methods simplify event dispatching without memorizing event names.\n *\n * @example\n * ```typescript\n * const stateMachine = createDefaultPanControlStateMachine(cameraRig);\n *\n * // User pans - accepted in ACCEPTING_USER_INPUT state\n * const result = stateMachine.notifyPanInput({ x: 50, y: 30 });\n *\n * // Start animation - transitions to TRANSITION state\n * stateMachine.notifyPanToAnimationInput({ x: 1000, y: 500 });\n *\n * // User input now blocked while animating\n * ```\n *\n * @category Input Flow Control\n * @see {@link createDefaultPanControlStateMachine} for factory function\n */\nexport class PanControlStateMachine extends TemplateStateMachine<PanEventPayloadMapping, BaseContext, PanControlStates, PanControlOutputMapping> {\n\n constructor(states: Record<PanControlStates, State<PanEventPayloadMapping, BaseContext, PanControlStates, PanControlOutputMapping>>, initialState: PanControlStates, context: BaseContext){\n super(states, initialState, context);\n }\n\n /**\n * Notifies the state machine of user pan input.\n *\n * @param diff - Pan displacement in viewport coordinates\n * @returns Event handling result with output event\n *\n * @remarks\n * Dispatches `userPanByInput` event. Accepted in `ACCEPTING_USER_INPUT` and `TRANSITION` states,\n * where it may transition back to `ACCEPTING_USER_INPUT` (user interrupting animation).\n */\n notifyPanInput(diff: Point) {\n return this.happens(\"userPanByInput\", {diff: diff});\n }\n\n /**\n * Initiates a pan animation to a target position.\n *\n * @param target - Target position in world coordinates\n * @returns Event handling result\n *\n * @remarks\n * Dispatches `transitionPanToInput` event, starting a pan animation.\n * Transitions to `TRANSITION` state where animation updates occur.\n */\n notifyPanToAnimationInput(target: Point) {\n return this.happens(\"transitionPanToInput\", {target: target});\n }\n\n /**\n * Initiates transition to `TRANSITION` state.\n *\n * @remarks\n * Forces state change to begin animation or transition sequence.\n * Called when starting programmatic camera movements.\n */\n initateTransition() {\n return this.happens(\"initateTransition\");\n }\n}\n\n/**\n * State implementation for accepting user pan input (idle/normal state).\n * Accepts user pan input and can transition to animation or locked states.\n * @category Input Flow Control\n */\nexport class AcceptingUserInputState extends TemplateState<PanEventPayloadMapping, BaseContext, PanControlStates, PanControlOutputMapping> {\n\n constructor(){\n super();\n }\n\n eventReactions: EventReactions<PanEventPayloadMapping, BaseContext, PanControlStates, PanControlOutputMapping> = {\n userPanByInput: {action: this.userPanByInputHandler, defaultTargetState: \"ACCEPTING_USER_INPUT\"},\n userPanToInput: {action: this.userPanToInputHandler, defaultTargetState: \"ACCEPTING_USER_INPUT\"},\n lockedOnObjectPanByInput: {action: this.lockedOnObjectPanByInputHandler, defaultTargetState: \"LOCKED_ON_OBJECT\"},\n lockedOnObjectPanToInput: {action: this.lockedOnObjectPanToInputHandler, defaultTargetState: \"LOCKED_ON_OBJECT\"},\n initateTransition: {action: NO_OP, defaultTargetState: \"TRANSITION\"},\n }\n\n userPanByInputHandler(context: BaseContext, payload: PanByInputEventPayload): PanControlOutputEvent {\n return { type: \"panByViewPort\", delta: payload.diff };\n }\n\n userPanToInputHandler(context: BaseContext, payload: PanToInputEventPayload): PanControlOutputEvent {\n return { type: \"panToWorld\", target: payload.target };\n }\n\n lockedOnObjectPanByInputHandler(context: BaseContext, payload: PanByInputEventPayload): PanControlOutputEvent {\n return { type: \"panByViewPort\", delta: payload.diff };\n }\n\n lockedOnObjectPanToInputHandler(context: BaseContext, payload: PanToInputEventPayload): PanControlOutputEvent {\n return { type: \"panToWorld\", target: payload.target };\n }\n\n}\n\n/**\n * State implementation for pan animations and transitions.\n * Processes animation updates and allows user input to interrupt.\n * @category Input Flow Control\n */\nexport class TransitionState extends TemplateState<PanEventPayloadMapping, BaseContext, PanControlStates, PanControlOutputMapping> {\n\n constructor(){\n super();\n }\n\n eventReactions: EventReactions<PanEventPayloadMapping, BaseContext, PanControlStates, PanControlOutputMapping> = {\n userPanByInput: {action: this.userPanByInputHandler, defaultTargetState: \"ACCEPTING_USER_INPUT\"},\n userPanToInput: {action: this.userPanToInputHandler, defaultTargetState: \"ACCEPTING_USER_INPUT\"},\n transitionPanByInput: {action: this.transitionPanByInputHandler, defaultTargetState: \"TRANSITION\"},\n transitionPanToInput: {action: this.transitionPanToInputHandler, defaultTargetState: \"TRANSITION\"},\n lockedOnObjectPanByInput: {action: this.lockedOnObjectPanByInputHandler, defaultTargetState: \"LOCKED_ON_OBJECT\"},\n lockedOnObjectPanToInput: {action: this.lockedOnObjectPanToInputHandler, defaultTargetState: \"LOCKED_ON_OBJECT\"},\n }\n\n userPanByInputHandler(context: BaseContext, payload: PanByInputEventPayload): PanControlOutputEvent {\n return { type: \"panByViewPort\", delta: payload.diff };\n }\n\n userPanToInputHandler(context: BaseContext, payload: PanToInputEventPayload): PanControlOutputEvent {\n return { type: \"panToWorld\", target: payload.target };\n }\n\n transitionPanByInputHandler(context: BaseContext, payload: PanByInputEventPayload): PanControlOutputEvent {\n return { type: \"panByViewPort\", delta: payload.diff };\n }\n\n transitionPanToInputHandler(context: BaseContext, payload: PanToInputEventPayload): PanControlOutputEvent {\n return { type: \"panToWorld\", target: payload.target };\n }\n\n lockedOnObjectPanByInputHandler(context: BaseContext, payload: PanByInputEventPayload): PanControlOutputEvent {\n return { type: \"panByViewPort\", delta: payload.diff };\n }\n\n lockedOnObjectPanToInputHandler(context: BaseContext, payload: PanToInputEventPayload): PanControlOutputEvent {\n return { type: \"panToWorld\", target: payload.target };\n }\n\n}\n\n/**\n * State implementation for camera locked to follow an object.\n * Only accepts locked object pan events until unlocked.\n * @category Input Flow Control\n */\nexport class LockedOnObjectState extends TemplateState<PanEventPayloadMapping, BaseContext, PanControlStates, PanControlOutputMapping> {\n\n constructor(){\n super();\n }\n\n eventReactions: EventReactions<PanEventPayloadMapping, BaseContext, PanControlStates, PanControlOutputMapping> = {\n unlock: {action: NO_OP, defaultTargetState: \"ACCEPTING_USER_INPUT\"},\n lockedOnObjectPanByInput: {action: this.lockedOnObjectPanByInputHandler, defaultTargetState: \"LOCKED_ON_OBJECT\"},\n lockedOnObjectPanToInput: {action: this.lockedOnObjectPanToInputHandler, defaultTargetState: \"LOCKED_ON_OBJECT\"},\n }\n\n lockedOnObjectPanByInputHandler(context: BaseContext, payload: PanByInputEventPayload): PanControlOutputEvent {\n return { type: \"panByViewPort\", delta: payload.diff };\n }\n\n lockedOnObjectPanToInputHandler(context: BaseContext, payload: PanToInputEventPayload): PanControlOutputEvent {\n return { type: \"panToWorld\", target: payload.target };\n }\n\n}\n\n/**\n * Creates the default set of pan control states.\n * @returns State instances for all pan control states\n * @category Input Flow Control\n */\nexport function createDefaultPanControlStates(): Record<PanControlStates, State<PanEventPayloadMapping, BaseContext, PanControlStates, PanControlOutputMapping>> {\n return {\n ACCEPTING_USER_INPUT: new AcceptingUserInputState(),\n TRANSITION: new TransitionState(),\n LOCKED_ON_OBJECT: new LockedOnObjectState(),\n }\n}\n\n/**\n * Creates a pan control state machine with default configuration.\n *\n * @param context - Camera rig or context for pan operations\n * @returns Configured pan control state machine starting in `ACCEPTING_USER_INPUT` state\n *\n * @remarks\n * Factory function for creating a pan state machine with sensible defaults.\n * The machine starts in `ACCEPTING_USER_INPUT` state, ready to accept user pan gestures.\n *\n * @example\n * ```typescript\n * const cameraRig = createDefaultCameraRig(camera);\n * const panSM = createDefaultPanControlStateMachine(cameraRig);\n * ```\n *\n * @category Input Flow Control\n */\nexport function createDefaultPanControlStateMachine(context: BaseContext = {setup: NO_OP, cleanup: NO_OP}): PanControlStateMachine {\n return new PanControlStateMachine(createDefaultPanControlStates(), \"ACCEPTING_USER_INPUT\", context);\n}\n",
32
- "import type { State, EventReactions, BaseContext } from \"@ue-too/being\";\nimport { NO_OP, TemplateState, TemplateStateMachine } from \"@ue-too/being\";\nimport { Point } from \"@ue-too/math\";\n\n/**\n * State identifiers for the zoom control state machine.\n *\n * @remarks\n * Three states manage zoom input and animations:\n * - `ACCEPTING_USER_INPUT`: Normal state, accepts user zoom input\n * - `TRANSITION`: Animation/transition state, may block user input\n * - `LOCKED_ON_OBJECT`: Camera locked to follow a specific object with zoom\n *\n * @category Input Flow Control\n */\nexport type ZoomControlStates = \"ACCEPTING_USER_INPUT\" | \"TRANSITION\" | \"LOCKED_ON_OBJECT\";\n\n/**\n * Payload for zoom-by-at input events (relative zoom around a point).\n * @category Input Flow Control\n */\nexport type ZoomByAtInputPayload = {\n /** Zoom delta amount (multiplier) */\n deltaZoom: number;\n /** Anchor point for zoom operation */\n anchorPoint: Point;\n}\n\n/**\n * Payload for zoom-to-at input events (absolute zoom to target around a point).\n * @category Input Flow Control\n */\nexport type ZoomToAtInputPayload = {\n /** Target zoom level */\n targetZoom: number;\n /** Anchor point for zoom operation */\n anchorPoint: Point;\n}\n\n/**\n * Payload for zoom-by input events (relative zoom without anchor).\n * @category Input Flow Control\n */\nexport type ZoomByPayload = {\n /** Zoom delta amount (multiplier) */\n deltaZoom: number;\n}\n\n/**\n * Payload for zoom-to input events (absolute zoom to target level).\n * @category Input Flow Control\n */\nexport type ZoomToPayload = {\n /** Target zoom level */\n targetZoom: number;\n}\n\n/**\n * Event payload type mapping for the zoom control state machine.\n *\n * @remarks\n * Maps event names to their payload types. Events include:\n * - User input events (`userZoomByAtInput`, `userZoomToAtInput`)\n * - Transition/animation events (`transitionZoomByAtInput`, `transitionZoomToAtInput`, etc.)\n * - Locked object events (`lockedOnObjectZoomByAtInput`, `lockedOnObjectZoomToAtInput`)\n * - Control events (`unlock`, `initiateTransition`)\n *\n * @category Input Flow Control\n */\nexport type ZoomEventPayloadMapping = {\n \"userZoomByAtInput\": ZoomByAtInputPayload,\n \"userZoomToAtInput\": ZoomToAtInputPayload,\n \"transitionZoomByAtInput\": ZoomByAtInputPayload,\n \"transitionZoomToAtInput\": ZoomToAtInputPayload,\n \"transitionZoomByAtCenterInput\": ZoomByPayload,\n \"transitionZoomToAtCenterInput\": ZoomToAtInputPayload,\n \"transitionZoomToAtWorldInput\": ZoomToAtInputPayload,\n \"lockedOnObjectZoomByAtInput\": ZoomByAtInputPayload,\n \"lockedOnObjectZoomToAtInput\": ZoomToAtInputPayload,\n \"unlock\": {},\n \"initiateTransition\": {},\n};\n\n/**\n * Discriminated union of output events from zoom control state machine.\n *\n * @remarks\n * Output events instruct the camera system what zoom operation to perform:\n * - `zoomByAt`: Relative zoom around anchor point\n * - `zoomToAt`: Absolute zoom to target level around anchor point\n * - `zoomBy`: Relative zoom without anchor\n * - `zoomTo`: Absolute zoom to target level without anchor\n * - `zoomByAtWorld`: Relative zoom around world anchor point\n * - `zoomToAtWorld`: Absolute zoom to target level around world anchor point\n * - `none`: No operation (input blocked)\n *\n * @category Input Flow Control\n */\nexport type ZoomControlOutputEvent =\n | { type: \"zoomByAt\", deltaZoom: number, anchorPoint: Point }\n | { type: \"zoomToAt\", targetZoom: number, anchorPoint: Point }\n | { type: \"zoomBy\", deltaZoom: number }\n | { type: \"zoomTo\", targetZoom: number }\n | { type: \"zoomByAtWorld\", deltaZoom: number, anchorPoint: Point }\n | { type: \"zoomToAtWorld\", targetZoom: number, anchorPoint: Point }\n | { type: \"none\" };\n\n/**\n * Output event type mapping for zoom control events.\n * Maps input event names to their corresponding output event types.\n *\n * @category Input Flow Control\n */\nexport type ZoomControlOutputMapping = {\n \"userZoomByAtInput\": ZoomControlOutputEvent,\n \"userZoomToAtInput\": ZoomControlOutputEvent,\n \"transitionZoomByAtInput\": ZoomControlOutputEvent,\n \"transitionZoomToAtInput\": ZoomControlOutputEvent,\n \"transitionZoomByAtCenterInput\": ZoomControlOutputEvent,\n \"transitionZoomToAtCenterInput\": ZoomControlOutputEvent,\n \"transitionZoomToAtWorldInput\": ZoomControlOutputEvent,\n \"lockedOnObjectZoomByAtInput\": ZoomControlOutputEvent,\n \"lockedOnObjectZoomToAtInput\": ZoomControlOutputEvent,\n};\n\n/**\n * State implementation for accepting user zoom input (idle/normal state).\n * Accepts user zoom input and can transition to animation or locked states.\n * @category Input Flow Control\n */\nexport class ZoomAcceptingUserInputState extends TemplateState<ZoomEventPayloadMapping, BaseContext, ZoomControlStates, ZoomControlOutputMapping> {\n\n private _eventReactions: EventReactions<ZoomEventPayloadMapping, BaseContext, ZoomControlStates, ZoomControlOutputMapping> = {\n userZoomByAtInput: {action: this.userZoomByAtInput, defaultTargetState: \"ACCEPTING_USER_INPUT\"},\n userZoomToAtInput: {action: this.userZoomToAtInput, defaultTargetState: \"ACCEPTING_USER_INPUT\"},\n initiateTransition: {action: NO_OP, defaultTargetState: \"TRANSITION\"},\n };\n\n get eventReactions(): EventReactions<ZoomEventPayloadMapping, BaseContext, ZoomControlStates, ZoomControlOutputMapping> {\n return this._eventReactions;\n }\n\n userZoomByAtInput(context: BaseContext, payload: ZoomEventPayloadMapping[\"userZoomByAtInput\"]): ZoomControlOutputEvent {\n return { type: \"zoomByAt\", deltaZoom: payload.deltaZoom, anchorPoint: payload.anchorPoint };\n }\n\n userZoomToAtInput(context: BaseContext, payload: ZoomEventPayloadMapping[\"userZoomToAtInput\"]): ZoomControlOutputEvent {\n return { type: \"zoomToAt\", targetZoom: payload.targetZoom, anchorPoint: payload.anchorPoint };\n }\n}\n\n/**\n * State implementation for zoom animations and transitions.\n * Processes animation updates and allows user input to interrupt.\n * @category Input Flow Control\n */\nexport class ZoomTransitionState extends TemplateState<ZoomEventPayloadMapping, BaseContext, ZoomControlStates, ZoomControlOutputMapping> {\n\n constructor(){\n super();\n }\n\n private _eventReactions: EventReactions<ZoomEventPayloadMapping, BaseContext, ZoomControlStates, ZoomControlOutputMapping> = {\n lockedOnObjectZoomByAtInput: {action: this.lockedOnObjectZoomByAtInput, defaultTargetState: \"LOCKED_ON_OBJECT\"},\n lockedOnObjectZoomToAtInput: {action: this.lockedOnObjectZoomToAtInput, defaultTargetState: \"LOCKED_ON_OBJECT\"},\n transitionZoomByAtInput: {action: this.transitionZoomByAtInput, defaultTargetState: \"TRANSITION\"},\n transitionZoomToAtInput: {action: this.transitionZoomToAtInput, defaultTargetState: \"TRANSITION\"},\n transitionZoomToAtCenterInput: {action: this.transitionZoomToAtCenterInput, defaultTargetState: \"TRANSITION\"},\n transitionZoomToAtWorldInput: {action: this.transitionZoomToAtWorldInput, defaultTargetState: \"TRANSITION\"},\n userZoomByAtInput: {action: this.userZoomByAtInput, defaultTargetState: \"ACCEPTING_USER_INPUT\"},\n userZoomToAtInput: {action: this.userZoomToAtInput, defaultTargetState: \"ACCEPTING_USER_INPUT\"},\n }\n\n get eventReactions(): EventReactions<ZoomEventPayloadMapping, BaseContext, ZoomControlStates, ZoomControlOutputMapping> {\n return this._eventReactions;\n }\n\n lockedOnObjectZoomByAtInput(context: BaseContext, payload: ZoomEventPayloadMapping[\"lockedOnObjectZoomByAtInput\"]): ZoomControlOutputEvent {\n return { type: \"zoomBy\", deltaZoom: payload.deltaZoom };\n }\n\n lockedOnObjectZoomToAtInput(context: BaseContext, payload: ZoomEventPayloadMapping[\"lockedOnObjectZoomToAtInput\"]): ZoomControlOutputEvent {\n return { type: \"zoomTo\", targetZoom: payload.targetZoom };\n }\n\n userZoomByAtInput(context: BaseContext, payload: ZoomEventPayloadMapping[\"userZoomByAtInput\"]): ZoomControlOutputEvent {\n return { type: \"zoomByAt\", deltaZoom: payload.deltaZoom, anchorPoint: payload.anchorPoint };\n }\n\n userZoomToAtInput(context: BaseContext, payload: ZoomEventPayloadMapping[\"userZoomToAtInput\"]): ZoomControlOutputEvent {\n return { type: \"zoomToAt\", targetZoom: payload.targetZoom, anchorPoint: payload.anchorPoint };\n }\n\n transitionZoomByAtInput(context: BaseContext, payload: ZoomEventPayloadMapping[\"transitionZoomByAtInput\"]): ZoomControlOutputEvent {\n return { type: \"zoomByAt\", deltaZoom: payload.deltaZoom, anchorPoint: payload.anchorPoint };\n }\n\n transitionZoomByAtCenterInput(context: BaseContext, payload: ZoomEventPayloadMapping[\"transitionZoomByAtCenterInput\"]): ZoomControlOutputEvent {\n return { type: \"zoomBy\", deltaZoom: payload.deltaZoom };\n }\n\n transitionZoomToAtInput(context: BaseContext, payload: ZoomEventPayloadMapping[\"transitionZoomToAtInput\"]): ZoomControlOutputEvent {\n return { type: \"zoomToAt\", targetZoom: payload.targetZoom, anchorPoint: payload.anchorPoint };\n }\n\n transitionZoomToAtCenterInput(context: BaseContext, payload: ZoomEventPayloadMapping[\"transitionZoomToAtCenterInput\"]): ZoomControlOutputEvent {\n return { type: \"zoomTo\", targetZoom: payload.targetZoom };\n }\n\n transitionZoomToAtWorldInput(context: BaseContext, payload: ZoomEventPayloadMapping[\"transitionZoomToAtWorldInput\"]): ZoomControlOutputEvent {\n return { type: \"zoomToAtWorld\", targetZoom: payload.targetZoom, anchorPoint: payload.anchorPoint };\n }\n}\n\n/**\n * State implementation for camera locked to follow an object with zoom.\n * Accepts locked object zoom events and user input to unlock.\n * @category Input Flow Control\n */\nexport class ZoomLockedOnObjectState extends TemplateState<ZoomEventPayloadMapping, BaseContext, ZoomControlStates, ZoomControlOutputMapping> {\n\n constructor(){\n super();\n }\n\n private _eventReactions: EventReactions<ZoomEventPayloadMapping, BaseContext, ZoomControlStates, ZoomControlOutputMapping> = {\n lockedOnObjectZoomByAtInput: {action: this.lockedOnObjectZoomByAtInput, defaultTargetState: \"LOCKED_ON_OBJECT\"},\n lockedOnObjectZoomToAtInput: {action: this.lockedOnObjectZoomToAtInput, defaultTargetState: \"LOCKED_ON_OBJECT\"},\n userZoomByAtInput: {action: this.userZoomByAtInput, defaultTargetState: \"ACCEPTING_USER_INPUT\"},\n userZoomToAtInput: {action: this.userZoomToAtInput, defaultTargetState: \"ACCEPTING_USER_INPUT\"},\n }\n\n get eventReactions(): EventReactions<ZoomEventPayloadMapping, BaseContext, ZoomControlStates, ZoomControlOutputMapping> {\n return this._eventReactions;\n }\n\n lockedOnObjectZoomByAtInput(context: BaseContext, payload: ZoomEventPayloadMapping[\"lockedOnObjectZoomByAtInput\"]): ZoomControlOutputEvent {\n return { type: \"zoomByAt\", deltaZoom: payload.deltaZoom, anchorPoint: payload.anchorPoint };\n }\n\n lockedOnObjectZoomToAtInput(context: BaseContext, payload: ZoomEventPayloadMapping[\"lockedOnObjectZoomToAtInput\"]): ZoomControlOutputEvent {\n return { type: \"zoomToAt\", targetZoom: payload.targetZoom, anchorPoint: payload.anchorPoint };\n }\n\n userZoomByAtInput(context: BaseContext, payload: ZoomEventPayloadMapping[\"userZoomByAtInput\"]): ZoomControlOutputEvent {\n return { type: \"zoomByAt\", deltaZoom: payload.deltaZoom, anchorPoint: payload.anchorPoint };\n }\n\n userZoomToAtInput(context: BaseContext, payload: ZoomEventPayloadMapping[\"userZoomToAtInput\"]): ZoomControlOutputEvent {\n return { type: \"zoomToAt\", targetZoom: payload.targetZoom, anchorPoint: payload.anchorPoint };\n }\n}\n\n/**\n * State machine controlling zoom input flow and animations.\n *\n * @remarks\n * This state machine manages the lifecycle of zoom operations:\n * - **User input handling**: Accepts or blocks user zoom gestures based on state\n * - **Animation control**: Manages smooth zoom-to animations\n * - **Object tracking**: Supports locking camera to follow objects with zoom\n *\n * **State transitions:**\n * - `ACCEPTING_USER_INPUT` → `TRANSITION`: Start animation (`initiateTransition`)\n * - `ACCEPTING_USER_INPUT` → `LOCKED_ON_OBJECT`: Lock to object (`lockedOnObjectZoom...`)\n * - `TRANSITION` → `ACCEPTING_USER_INPUT`: User input interrupts animation\n * - `LOCKED_ON_OBJECT` → `ACCEPTING_USER_INPUT`: User input unlocks\n *\n * Helper methods simplify event dispatching without memorizing event names.\n *\n * @example\n * ```typescript\n * const stateMachine = createDefaultZoomControlStateMachine(cameraRig);\n *\n * // User zooms - accepted in ACCEPTING_USER_INPUT state\n * const result = stateMachine.notifyZoomByAtInput(1.2, { x: 400, y: 300 });\n *\n * // Start animation - transitions to TRANSITION state\n * stateMachine.notifyZoomToAtWorldInput(2.0, { x: 1000, y: 500 });\n *\n * // User input now may interrupt animation\n * ```\n *\n * @category Input Flow Control\n * @see {@link createDefaultZoomControlStateMachine} for factory function\n */\nexport class ZoomControlStateMachine extends TemplateStateMachine<ZoomEventPayloadMapping, BaseContext, ZoomControlStates, ZoomControlOutputMapping> {\n\n constructor(states: Record<ZoomControlStates, State<ZoomEventPayloadMapping, BaseContext, ZoomControlStates, ZoomControlOutputMapping>>, initialState: ZoomControlStates, context: BaseContext){\n super(states, initialState, context);\n }\n\n /**\n * Notifies the state machine of user zoom input around an anchor point.\n *\n * @param delta - Zoom delta (multiplier)\n * @param at - Anchor point for zoom\n * @returns Event handling result with output event\n *\n * @remarks\n * Dispatches `userZoomByAtInput` event. Accepted in `ACCEPTING_USER_INPUT` and `TRANSITION` states.\n */\n notifyZoomByAtInput(delta: number, at: Point) {\n return this.happens(\"userZoomByAtInput\", {deltaZoom: delta, anchorPoint: at});\n }\n\n /**\n * Initiates a zoom animation around an anchor point.\n *\n * @param delta - Zoom delta (multiplier)\n * @param at - Anchor point for zoom\n * @returns Event handling result\n *\n * @remarks\n * Dispatches `transitionZoomByAtInput` event, starting a zoom animation.\n */\n notifyZoomByAtInputAnimation(delta: number, at: Point) {\n return this.happens(\"transitionZoomByAtInput\", {deltaZoom: delta, anchorPoint: at});\n }\n\n /**\n * Initiates a zoom animation to target level around center anchor.\n *\n * @param targetZoom - Target zoom level\n * @param at - Anchor point for zoom\n * @returns Event handling result\n *\n * @remarks\n * Dispatches `transitionZoomToAtCenterInput` event for center-anchored zoom animation.\n */\n notifyZoomToAtCenterInput(targetZoom: number, at: Point) {\n return this.happens(\"transitionZoomToAtCenterInput\", {targetZoom: targetZoom, anchorPoint: at});\n }\n\n /**\n * Initiates a zoom animation to target level around world anchor.\n *\n * @param targetZoom - Target zoom level\n * @param at - World anchor point for zoom\n * @returns Event handling result\n *\n * @remarks\n * Dispatches `transitionZoomToAtWorldInput` event for world-anchored zoom animation.\n */\n notifyZoomToAtWorldInput(targetZoom: number, at: Point) {\n return this.happens(\"transitionZoomToAtWorldInput\", {targetZoom: targetZoom, anchorPoint: at});\n }\n\n /**\n * Initiates transition to `TRANSITION` state.\n *\n * @remarks\n * Forces state change to begin animation or transition sequence.\n * Called when starting programmatic camera movements.\n */\n initateTransition() {\n return this.happens(\"initiateTransition\");\n }\n}\n\n/**\n * Creates the default set of zoom control states.\n * @returns State instances for all zoom control states\n * @category Input Flow Control\n */\nexport function createDefaultZoomControlStates(): Record<ZoomControlStates, State<ZoomEventPayloadMapping, BaseContext, ZoomControlStates, ZoomControlOutputMapping>> {\n return {\n ACCEPTING_USER_INPUT: new ZoomAcceptingUserInputState(),\n TRANSITION: new ZoomTransitionState(),\n LOCKED_ON_OBJECT: new ZoomLockedOnObjectState(),\n }\n}\n\n/**\n * Creates a zoom control state machine with default configuration.\n *\n * @param context - Camera rig or context for zoom operations\n * @returns Configured zoom control state machine starting in `ACCEPTING_USER_INPUT` state\n *\n * @remarks\n * Factory function for creating a zoom state machine with sensible defaults.\n * The machine starts in `ACCEPTING_USER_INPUT` state, ready to accept user zoom gestures.\n *\n * @example\n * ```typescript\n * const cameraRig = createDefaultCameraRig(camera);\n * const zoomSM = createDefaultZoomControlStateMachine(cameraRig);\n * ```\n *\n * @category Input Flow Control\n */\nexport function createDefaultZoomControlStateMachine(context: BaseContext = {setup: NO_OP, cleanup: NO_OP}): ZoomControlStateMachine {\n return new ZoomControlStateMachine(createDefaultZoomControlStates(), \"ACCEPTING_USER_INPUT\", context);\n}\n",
33
- "import type { EventReactions, State, BaseContext } from \"@ue-too/being\";\nimport { NO_OP, TemplateState, TemplateStateMachine } from \"@ue-too/being\";\n\n/**\n * State identifiers for the rotation control state machine.\n *\n * @remarks\n * Three states manage rotation input and animations:\n * - `ACCEPTING_USER_INPUT`: Normal state, accepts user rotation input\n * - `TRANSITION`: Animation/transition state, may block user input\n * - `LOCKED_ON_OBJECT`: Camera locked to follow a specific object rotation\n *\n * @category Input Flow Control\n */\nexport type RotateControlStates = \"ACCEPTING_USER_INPUT\" | \"TRANSITION\" | \"LOCKED_ON_OBJECT\";\n\n/**\n * Payload for rotate-by input events (relative rotation).\n * @category Input Flow Control\n */\nexport type RotateByInputEventPayload = {\n /** Rotation angle delta in radians */\n diff: number;\n};\n\n/**\n * Payload for rotate-to input events (absolute rotation).\n * @category Input Flow Control\n */\nexport type RotateToInputEventPayload = {\n /** Target rotation angle in radians */\n target: number;\n};\n\n/** Empty payload for events that don't need data */\ntype EmptyPayload = {};\n\n/**\n * Event payload type mapping for the rotation control state machine.\n *\n * @remarks\n * Maps event names to their payload types. Events include:\n * - User input events (`userRotateByInput`, `userRotateToInput`)\n * - Transition/animation events (`transitionRotateByInput`, `transitionRotateToInput`)\n * - Locked object events (`lockedOnObjectRotateByInput`, `lockedOnObjectRotateToInput`)\n * - Control events (`unlock`, `initateTransition`)\n *\n * @category Input Flow Control\n */\nexport type RotateEventPayloadMapping = {\n \"userRotateByInput\": RotateByInputEventPayload,\n \"userRotateToInput\": RotateToInputEventPayload,\n \"transitionRotateByInput\": RotateByInputEventPayload,\n \"transitionRotateToInput\": RotateToInputEventPayload,\n \"lockedOnObjectRotateByInput\": RotateByInputEventPayload,\n \"lockedOnObjectRotateToInput\": RotateToInputEventPayload,\n \"unlock\": EmptyPayload,\n \"initateTransition\": EmptyPayload,\n};\n\n/**\n * Discriminated union of output events from rotation control state machine.\n *\n * @remarks\n * Output events instruct the camera system what rotation operation to perform:\n * - `rotateBy`: Relative rotation by delta angle\n * - `rotateTo`: Absolute rotation to target angle\n * - `none`: No operation (input blocked)\n *\n * @category Input Flow Control\n */\nexport type RotateControlOutputEvent =\n | { type: \"rotateBy\", delta: number }\n | { type: \"rotateTo\", target: number }\n | { type: \"none\" };\n\n/**\n * Output event type mapping for rotation control events.\n * Maps input event names to their corresponding output event types.\n *\n * @category Input Flow Control\n */\nexport type RotateControlOutputMapping = {\n \"userRotateByInput\": RotateControlOutputEvent,\n \"userRotateToInput\": RotateControlOutputEvent,\n \"transitionRotateByInput\": RotateControlOutputEvent,\n \"transitionRotateToInput\": RotateControlOutputEvent,\n \"lockedOnObjectRotateByInput\": RotateControlOutputEvent,\n \"lockedOnObjectRotateToInput\": RotateControlOutputEvent,\n};\n\n/**\n * State machine controlling rotation input flow and animations.\n *\n * @remarks\n * This state machine manages the lifecycle of rotation operations:\n * - **User input handling**: Accepts or blocks user rotation gestures based on state\n * - **Animation control**: Manages smooth rotate-to animations\n * - **Object tracking**: Supports locking camera to follow objects with rotation\n *\n * **State transitions:**\n * - `ACCEPTING_USER_INPUT` → `TRANSITION`: Start animation (`initateTransition`)\n * - `ACCEPTING_USER_INPUT` → `LOCKED_ON_OBJECT`: Lock to object (`lockedOnObjectRotate...`)\n * - `TRANSITION` → `ACCEPTING_USER_INPUT`: User input interrupts animation\n * - `LOCKED_ON_OBJECT` → `ACCEPTING_USER_INPUT`: Unlock (`unlock` event)\n *\n * Helper methods simplify event dispatching without memorizing event names.\n *\n * @example\n * ```typescript\n * const stateMachine = createDefaultRotateControlStateMachine(cameraRig);\n *\n * // User rotates - accepted in ACCEPTING_USER_INPUT state\n * const result = stateMachine.notifyRotateByInput(Math.PI / 4);\n *\n * // Start animation - transitions to TRANSITION state\n * stateMachine.notifyRotateToAnimationInput(Math.PI);\n *\n * // User input now blocked while animating\n * ```\n *\n * @category Input Flow Control\n * @see {@link createDefaultRotateControlStateMachine} for factory function\n */\nexport class RotateControlStateMachine extends TemplateStateMachine<RotateEventPayloadMapping, BaseContext, RotateControlStates, RotateControlOutputMapping> {\n\n constructor(states: Record<RotateControlStates, State<RotateEventPayloadMapping, BaseContext, RotateControlStates, RotateControlOutputMapping>>, initialState: RotateControlStates, context: BaseContext){\n super(states, initialState, context);\n }\n\n /**\n * Notifies the state machine of user rotation input.\n *\n * @param diff - Rotation angle delta in radians\n * @returns Event handling result with output event\n *\n * @remarks\n * Dispatches `userRotateByInput` event. Accepted in `ACCEPTING_USER_INPUT` and `TRANSITION` states,\n * where it may transition back to `ACCEPTING_USER_INPUT` (user interrupting animation).\n */\n notifyRotateByInput(diff: number) {\n return this.happens(\"userRotateByInput\", {diff: diff});\n }\n\n /**\n * Initiates a rotation animation to a target angle.\n *\n * @param target - Target rotation angle in radians\n * @returns Event handling result\n *\n * @remarks\n * Dispatches `transitionRotateToInput` event, starting a rotation animation.\n * Transitions to `TRANSITION` state where animation updates occur.\n */\n notifyRotateToAnimationInput(target: number) {\n return this.happens(\"transitionRotateToInput\", {target: target});\n }\n\n /**\n * Initiates transition to `TRANSITION` state.\n *\n * @remarks\n * Forces state change to begin animation or transition sequence.\n * Called when starting programmatic camera movements.\n */\n initateTransition(): void{\n this.happens(\"initateTransition\");\n }\n\n}\n\n/**\n * State implementation for accepting user rotation input (idle/normal state).\n * Accepts user rotation input and can transition to animation or locked states.\n * @category Input Flow Control\n */\nexport class RotationAcceptingUserInputState extends TemplateState<RotateEventPayloadMapping, BaseContext, RotateControlStates, RotateControlOutputMapping> {\n\n constructor(){\n super();\n }\n\n eventReactions: EventReactions<RotateEventPayloadMapping, BaseContext, RotateControlStates, RotateControlOutputMapping> = {\n userRotateByInput: {action: this.userRotateByInputHandler, defaultTargetState: \"ACCEPTING_USER_INPUT\"},\n userRotateToInput: {action: this.userRotateToInputHandler, defaultTargetState: \"ACCEPTING_USER_INPUT\"},\n lockedOnObjectRotateByInput: {action: this.lockedOnObjectRotateByInputHandler, defaultTargetState: \"LOCKED_ON_OBJECT\"},\n lockedOnObjectRotateToInput: {action: this.lockedOnObjectRotateToInputHandler, defaultTargetState: \"LOCKED_ON_OBJECT\"},\n initateTransition: {action: NO_OP, defaultTargetState: \"TRANSITION\"},\n }\n\n userRotateByInputHandler(context: BaseContext, payload: RotateByInputEventPayload): RotateControlOutputEvent {\n return { type: \"rotateBy\", delta: payload.diff };\n }\n\n userRotateToInputHandler(context: BaseContext, payload: RotateToInputEventPayload): RotateControlOutputEvent {\n return { type: \"rotateTo\", target: payload.target };\n }\n\n lockedOnObjectRotateByInputHandler(context: BaseContext, payload: RotateByInputEventPayload): RotateControlOutputEvent {\n return { type: \"rotateBy\", delta: payload.diff };\n }\n\n lockedOnObjectRotateToInputHandler(context: BaseContext, payload: RotateToInputEventPayload): RotateControlOutputEvent {\n return { type: \"rotateTo\", target: payload.target };\n }\n\n}\n\n/**\n * State implementation for rotation animations and transitions.\n * Processes animation updates and allows user input to interrupt.\n * @category Input Flow Control\n */\nexport class RotationTransitionState extends TemplateState<RotateEventPayloadMapping, BaseContext, RotateControlStates, RotateControlOutputMapping> {\n\n constructor(){\n super();\n }\n\n eventReactions: EventReactions<RotateEventPayloadMapping, BaseContext, RotateControlStates, RotateControlOutputMapping> = {\n userRotateByInput: {action: this.userRotateByInputHandler, defaultTargetState: \"ACCEPTING_USER_INPUT\"},\n userRotateToInput: {action: this.userRotateToInputHandler, defaultTargetState: \"ACCEPTING_USER_INPUT\"},\n transitionRotateByInput: {action: this.transitionRotateByInputHandler, defaultTargetState: \"TRANSITION\"},\n transitionRotateToInput: {action: this.transitionRotateToInputHandler, defaultTargetState: \"TRANSITION\"},\n lockedOnObjectRotateByInput: {action: this.lockedOnObjectRotateByInputHandler, defaultTargetState: \"LOCKED_ON_OBJECT\"},\n lockedOnObjectRotateToInput: {action: this.lockedOnObjectRotateToInputHandler, defaultTargetState: \"LOCKED_ON_OBJECT\"},\n }\n\n userRotateByInputHandler(context: BaseContext, payload: RotateByInputEventPayload): RotateControlOutputEvent {\n return { type: \"rotateBy\", delta: payload.diff };\n }\n\n userRotateToInputHandler(context: BaseContext, payload: RotateToInputEventPayload): RotateControlOutputEvent {\n return { type: \"rotateTo\", target: payload.target };\n }\n\n transitionRotateByInputHandler(context: BaseContext, payload: RotateByInputEventPayload): RotateControlOutputEvent {\n return { type: \"rotateBy\", delta: payload.diff };\n }\n\n transitionRotateToInputHandler(context: BaseContext, payload: RotateToInputEventPayload): RotateControlOutputEvent {\n return { type: \"rotateTo\", target: payload.target };\n }\n\n lockedOnObjectRotateByInputHandler(context: BaseContext, payload: RotateByInputEventPayload): RotateControlOutputEvent {\n return { type: \"rotateBy\", delta: payload.diff };\n }\n\n lockedOnObjectRotateToInputHandler(context: BaseContext, payload: RotateToInputEventPayload): RotateControlOutputEvent {\n return { type: \"rotateTo\", target: payload.target };\n }\n\n}\n\n/**\n * State implementation for camera locked to follow an object rotation.\n * Only accepts locked object rotation events until unlocked.\n * @category Input Flow Control\n */\nexport class RotationLockedOnObjectState extends TemplateState<RotateEventPayloadMapping, BaseContext, RotateControlStates, RotateControlOutputMapping> {\n\n constructor(){\n super();\n }\n\n eventReactions: EventReactions<RotateEventPayloadMapping, BaseContext, RotateControlStates, RotateControlOutputMapping> = {\n unlock: {action: NO_OP, defaultTargetState: \"ACCEPTING_USER_INPUT\"},\n lockedOnObjectRotateByInput: {action: this.lockedOnObjectRotateByInputHandler, defaultTargetState: \"LOCKED_ON_OBJECT\"},\n lockedOnObjectRotateToInput: {action: this.lockedOnObjectRotateToInputHandler, defaultTargetState: \"LOCKED_ON_OBJECT\"},\n }\n\n lockedOnObjectRotateByInputHandler(context: BaseContext, payload: RotateByInputEventPayload): RotateControlOutputEvent {\n return { type: \"rotateBy\", delta: payload.diff };\n }\n\n lockedOnObjectRotateToInputHandler(context: BaseContext, payload: RotateToInputEventPayload): RotateControlOutputEvent {\n return { type: \"rotateTo\", target: payload.target };\n }\n\n}\n\n/**\n * Creates the default set of rotation control states.\n * @returns State instances for all rotation control states\n * @category Input Flow Control\n */\nexport function createDefaultRotateControlStates(): Record<RotateControlStates, State<RotateEventPayloadMapping, BaseContext, RotateControlStates, RotateControlOutputMapping>> {\n return {\n ACCEPTING_USER_INPUT: new RotationAcceptingUserInputState(),\n TRANSITION: new RotationTransitionState(),\n LOCKED_ON_OBJECT: new RotationLockedOnObjectState(),\n }\n}\n\n/**\n * Creates a rotation control state machine with default configuration.\n *\n * @param context - Camera rig or context for rotation operations\n * @returns Configured rotation control state machine starting in `ACCEPTING_USER_INPUT` state\n *\n * @remarks\n * Factory function for creating a rotation state machine with sensible defaults.\n * The machine starts in `ACCEPTING_USER_INPUT` state, ready to accept user rotation gestures.\n *\n * @example\n * ```typescript\n * const cameraRig = createDefaultCameraRig(camera);\n * const rotateSM = createDefaultRotateControlStateMachine(cameraRig);\n * ```\n *\n * @category Input Flow Control\n */\nexport function createDefaultRotateControlStateMachine(context: BaseContext = {setup: NO_OP, cleanup: NO_OP}): RotateControlStateMachine {\n return new RotateControlStateMachine(createDefaultRotateControlStates(), \"ACCEPTING_USER_INPUT\", context);\n}\n",
34
- "\nimport { CameraMux, CameraMuxPanOutput, CameraMuxZoomOutput, CameraMuxRotationOutput } from \"../interface\";\nimport { Point } from \"@ue-too/math\";\nimport { ObservableBoardCamera } from \"../../interface\";\nimport { createDefaultPanControlStateMachine, PanControlStateMachine, PanControlOutputEvent } from \"./pan-control-state-machine\";\nimport { createDefaultZoomControlStateMachine, ZoomControlStateMachine, ZoomControlOutputEvent } from \"./zoom-control-state-machine\";\nimport { createDefaultRotateControlStateMachine, RotateControlStateMachine, RotateControlOutputEvent } from \"./rotation-control-state-machine\";\nimport { CameraRig } from \"../../camera-rig\";\nimport { createDefaultCameraRig } from \"../../camera-rig\";\n\n/**\n * Advanced camera input multiplexer with animation support and input locking via state machines.\n *\n * @remarks\n * This {@link CameraMux} implementation provides sophisticated input flow control using\n * separate state machines for pan, zoom, and rotation. Each state machine can:\n * - Block user input during camera animations\n * - Manage animation playback\n * - Arbitrate between user input and programmatic camera control\n * - Handle transitions between different camera control states\n *\n * **Key features:**\n * - **Animation system**: Support for smooth camera animations (pan-to, zoom-to, rotate-to)\n * - **Input locking**: Automatically block user input during animations\n * - **State-based control**: Each camera operation (pan/zoom/rotate) has its own state machine\n * - **Flexible transitions**: Initiate transitions to interrupt or chain animations\n *\n * **Architecture:**\n * - Three independent state machines: {@link PanControlStateMachine}, {@link ZoomControlStateMachine}, {@link RotateControlStateMachine}\n * - Each state machine decides whether to allow or block input based on current state\n * - State machines receive events and produce output events for camera operations\n *\n * **When to use:**\n * - Applications requiring smooth camera animations (e.g., \"focus on object\", \"zoom to region\")\n * - UI where user input should be blocked during programmatic camera movements\n * - Games or interactive experiences with scripted camera sequences\n *\n * **Alternatives:**\n * - Use {@link Relay} for simple passthrough without animation support\n * - Implement custom {@link CameraMux} for different state management approaches\n *\n * @example\n * ```typescript\n * const camera = new DefaultBoardCamera();\n * const mux = createCameraMuxWithAnimationAndLock(camera);\n *\n * // Start a pan animation - user input will be blocked\n * mux.notifyPanToAnimationInput({ x: 1000, y: 500 });\n *\n * // User tries to pan during animation - will be blocked\n * const result = mux.notifyPanInput({ x: 50, y: 30 });\n * // result.allowPassThrough = false (blocked during animation)\n *\n * // After animation completes, user input allowed again\n * ```\n *\n * @category Input Flow Control\n * @see {@link CameraMux} for the interface definition\n * @see {@link Relay} for simpler passthrough implementation\n * @see {@link createCameraMuxWithAnimationAndLock} for factory function\n */\nexport class CameraMuxWithAnimationAndLock implements CameraMux {\n\n private _panStateMachine: PanControlStateMachine;\n private _zoomStateMachine: ZoomControlStateMachine;\n private _rotateStateMachine: RotateControlStateMachine;\n\n /**\n * Creates a new camera mux with animation and locking capabilities.\n *\n * @param panStateMachine - State machine controlling pan operations and animations\n * @param zoomStateMachine - State machine controlling zoom operations and animations\n * @param rotateStateMachine - State machine controlling rotation operations and animations\n *\n * @remarks\n * Typically created via factory functions like {@link createCameraMuxWithAnimationAndLock}\n * rather than direct instantiation.\n */\n constructor(panStateMachine: PanControlStateMachine, zoomStateMachine: ZoomControlStateMachine, rotateStateMachine: RotateControlStateMachine){\n this._panStateMachine = panStateMachine;\n this._zoomStateMachine = zoomStateMachine;\n this._rotateStateMachine = rotateStateMachine;\n }\n\n /**\n * Initiates a pan animation to a target position.\n *\n * @param target - Target position in world coordinates\n * @returns Pan output indicating whether animation was initiated\n *\n * @remarks\n * This method starts a camera pan animation to the specified world position.\n * The state machine handles:\n * - Starting the animation\n * - Blocking user input during animation\n * - Producing incremental pan deltas each frame\n *\n * The animation continues until the camera reaches the target or is interrupted.\n *\n * @example\n * ```typescript\n * // Animate camera to world position\n * mux.notifyPanToAnimationInput({ x: 1000, y: 500 });\n * ```\n */\n notifyPanToAnimationInput(target: Point): CameraMuxPanOutput {\n const res = this._panStateMachine.notifyPanToAnimationInput(target);\n\n if(res.handled) {\n const output = res.output;\n if(output !== undefined){\n switch(output.type){\n case 'panByViewPort':\n return { allowPassThrough: true, delta: output.delta };\n case 'panToWorld':\n return { allowPassThrough: true, delta: output.target };\n default:\n return { allowPassThrough: false };\n }\n\n }\n }\n return { allowPassThrough: false };\n }\n\n /**\n * Processes user pan input (implements {@link CameraMux}).\n *\n * @param delta - Pan delta in viewport coordinates\n * @returns Output indicating whether pan is allowed\n *\n * @remarks\n * This method is called when the user attempts to pan the camera (e.g., mouse drag).\n * The pan state machine determines whether to allow the input based on current state:\n * - **Allowed**: When in idle state or user control state\n * - **Blocked**: When camera animation is playing\n *\n * @example\n * ```typescript\n * // User drags mouse\n * const result = mux.notifyPanInput({ x: 50, y: 30 });\n * if (result.allowPassThrough) {\n * // Apply pan to camera\n * cameraRig.panByViewPort(result.delta);\n * }\n * ```\n */\n notifyPanInput(delta: Point): CameraMuxPanOutput {\n const result = this._panStateMachine.happens(\"userPanByInput\", { diff: delta });\n if (result.handled && 'output' in result && result.output) {\n const output = result.output as PanControlOutputEvent;\n if (output.type !== \"none\") {\n return { allowPassThrough: true, delta: delta };\n }\n }\n return { allowPassThrough: false };\n }\n\n /**\n * Processes user zoom input (implements {@link CameraMux}).\n *\n * @param delta - Zoom delta (change in zoom level)\n * @param at - Anchor point in viewport coordinates\n * @returns Output indicating whether zoom is allowed\n *\n * @remarks\n * This method is called when the user attempts to zoom (e.g., mouse wheel).\n * The zoom state machine determines whether to allow the input based on current state:\n * - **Allowed**: When in idle state or user control state\n * - **Blocked**: When zoom animation is playing\n *\n * @example\n * ```typescript\n * // User scrolls mouse wheel\n * const result = mux.notifyZoomInput(0.1, mousePosition);\n * if (result.allowPassThrough) {\n * // Apply zoom to camera\n * cameraRig.zoomByAt(result.delta, result.anchorPoint);\n * }\n * ```\n */\n notifyZoomInput(delta: number, at: Point): CameraMuxZoomOutput {\n const result = this._zoomStateMachine.happens(\"userZoomByAtInput\", { deltaZoom: delta, anchorPoint: at });\n if (result.handled && 'output' in result && result.output) {\n const output = result.output as ZoomControlOutputEvent;\n if (output.type !== \"none\") {\n return { allowPassThrough: true, delta: delta, anchorPoint: at };\n }\n }\n return { allowPassThrough: false };\n }\n\n /**\n * Processes user rotation input (rotate-by variant).\n *\n * @param delta - Rotation delta in radians\n * @returns Output from rotation state machine\n *\n * @remarks\n * Delegates to the rotation state machine's rotate-by handler.\n * The state machine determines whether to allow rotation based on current state.\n */\n notifyRotateByInput(delta: number) {\n return this._rotateStateMachine.notifyRotateByInput(delta);\n }\n\n /**\n * Initiates a rotation animation to a target angle.\n *\n * @param target - Target rotation angle in radians\n * @returns Output from rotation state machine\n *\n * @remarks\n * Starts a camera rotation animation to the specified angle.\n * User input will be blocked during the animation.\n */\n notifyRotateToAnimationInput(target: number) {\n return this._rotateStateMachine.notifyRotateToAnimationInput(target);\n }\n\n /**\n * Initiates a zoom animation to a target level at a viewport position.\n *\n * @param targetZoom - Target zoom level\n * @param at - Anchor point in viewport coordinates (defaults to origin)\n *\n * @remarks\n * Starts a zoom animation that zooms to the specified level while keeping\n * the anchor point stationary (zoom-to-cursor behavior).\n * User input will be blocked during the animation.\n */\n notifyZoomInputAnimation(targetZoom: number, at: Point = {x: 0, y: 0}): void {\n this._zoomStateMachine.notifyZoomToAtCenterInput(targetZoom, at);\n }\n\n /**\n * Initiates a zoom animation to a target level at a world position.\n *\n * @param targetZoom - Target zoom level\n * @param at - Anchor point in world coordinates (defaults to origin)\n *\n * @remarks\n * Similar to {@link notifyZoomInputAnimation} but accepts world-space coordinates\n * for the anchor point instead of viewport coordinates.\n */\n notifyZoomInputAnimationWorld(targetZoom: number, at: Point = {x: 0, y: 0}): void {\n this._zoomStateMachine.notifyZoomToAtWorldInput(targetZoom, at);\n }\n\n /**\n * Processes user rotation input (implements {@link CameraMux}).\n *\n * @param delta - Rotation delta in radians\n * @returns Output indicating whether rotation is allowed\n *\n * @remarks\n * This method is called when the user attempts to rotate the camera.\n * The rotation state machine determines whether to allow the input based on current state:\n * - **Allowed**: When in idle state or user control state\n * - **Blocked**: When rotation animation is playing\n *\n * @example\n * ```typescript\n * // User rotates camera\n * const result = mux.notifyRotationInput(0.1);\n * if (result.allowPassThrough) {\n * cameraRig.rotateBy(result.delta);\n * }\n * ```\n */\n notifyRotationInput(delta: number): CameraMuxRotationOutput {\n const result = this._rotateStateMachine.happens(\"userRotateByInput\", { diff: delta });\n if (result.handled && 'output' in result && result.output) {\n const output = result.output as RotateControlOutputEvent;\n if (output.type !== \"none\") {\n return { allowPassThrough: true, delta: delta };\n }\n }\n return { allowPassThrough: false };\n }\n\n /**\n * Initiates a transition in the pan state machine.\n *\n * @remarks\n * This method forces the pan state machine to transition to its next state.\n * Can be used to interrupt animations or force state changes.\n */\n initatePanTransition(): void {\n this._panStateMachine.initateTransition();\n }\n\n /**\n * Initiates a transition in the zoom state machine.\n *\n * @remarks\n * This method forces the zoom state machine to transition to its next state.\n * Can be used to interrupt animations or force state changes.\n */\n initateZoomTransition(): void {\n this._zoomStateMachine.initateTransition();\n }\n\n /**\n * Initiates a transition in the rotation state machine.\n *\n * @remarks\n * This method forces the rotation state machine to transition to its next state.\n * Can be used to interrupt animations or force state changes.\n */\n initateRotateTransition(): void {\n this._rotateStateMachine.initateTransition();\n }\n\n /**\n * Gets the rotation state machine.\n *\n * @returns The rotation state machine instance\n *\n * @remarks\n * Provides direct access to the rotation state machine for advanced control\n * or state inspection.\n */\n get rotateStateMachine(): RotateControlStateMachine {\n return this._rotateStateMachine;\n }\n\n /**\n * Gets the pan state machine.\n *\n * @returns The pan state machine instance\n *\n * @remarks\n * Provides direct access to the pan state machine for advanced control\n * or state inspection.\n */\n get panStateMachine(): PanControlStateMachine {\n return this._panStateMachine;\n }\n\n /**\n * Gets the zoom state machine.\n *\n * @returns The zoom state machine instance\n *\n * @remarks\n * Provides direct access to the zoom state machine for advanced control\n * or state inspection.\n */\n get zoomStateMachine(): ZoomControlStateMachine {\n return this._zoomStateMachine;\n }\n}\n\n/**\n * Creates a camera mux with animation and locking capabilities from a camera instance.\n *\n * @param camera - Observable camera to control\n * @returns Configured camera mux with animation support\n *\n * @remarks\n * This factory function creates a complete camera input flow control system with:\n * 1. A default {@link CameraRig} wrapping the provided camera\n * 2. Three state machines (pan, zoom, rotation) for animation control\n * 3. A {@link CameraMuxWithAnimationAndLock} coordinating the state machines\n *\n * **What you get:**\n * - Smooth camera animations (pan-to, zoom-to, rotate-to)\n * - Automatic input blocking during animations\n * - State-based input arbitration\n * - All with sensible default configurations\n *\n * **Use this when:**\n * - You have a camera and want animation support out-of-the-box\n * - You don't need custom camera rig configuration\n * - You want the simplest setup for animated camera control\n *\n * @example\n * ```typescript\n * const camera = new DefaultBoardCamera(1920, 1080);\n * const mux = createCameraMuxWithAnimationAndLock(camera);\n *\n * // Start a pan animation\n * mux.notifyPanToAnimationInput({ x: 1000, y: 500 });\n *\n * // User input is blocked during animation\n * const result = mux.notifyPanInput({ x: 50, y: 30 });\n * console.log(result.allowPassThrough); // false during animation\n * ```\n *\n * @category Input Flow Control\n * @see {@link CameraMuxWithAnimationAndLock} for the implementation\n * @see {@link createCameraMuxWithAnimationAndLockWithCameraRig} for custom rig version\n */\nexport function createCameraMuxWithAnimationAndLock(): CameraMux {\n const panStateMachine = createDefaultPanControlStateMachine();\n const zoomStateMachine = createDefaultZoomControlStateMachine();\n const rotateStateMachine = createDefaultRotateControlStateMachine();\n return new CameraMuxWithAnimationAndLock(panStateMachine, zoomStateMachine, rotateStateMachine);\n}\n",
35
- "import { BoardCamera } from \"../interface\";\nimport { createHandlerChain } from \"../../utils/handler-pipeline\";\nimport { clampZoomLevel } from \"../utils/zoom\";\n\n/**\n * Combined configuration for zoom handler behavior, merging restriction and clamping settings.\n *\n * @remarks\n * This type combines {@link ZoomHandlerClampConfig} and {@link ZoomHandlerRestrictConfig}\n * to provide complete control over camera zoom behavior.\n *\n * Zoom handlers use this configuration to:\n * - Completely disable zoom operations (restriction)\n * - Clamp zoom level to stay within defined limits (min/max bounds)\n *\n * @category Camera Rig\n * @see {@link ZoomHandlerClampConfig} for boundary clamping options\n * @see {@link ZoomHandlerRestrictConfig} for zoom disabling options\n */\nexport type ZoomHandlerConfig = ZoomHandlerClampConfig & ZoomHandlerRestrictConfig;\n\n/**\n * Configuration for zoom level boundary clamping.\n *\n * @remarks\n * Controls whether zoom operations should be constrained to camera's zoom boundaries.\n *\n * When `clampZoom` is true, zoom handlers enforce {@link BoardCamera.zoomBoundaries}\n * limits (min/max zoom levels). When false, zoom can exceed configured boundaries.\n *\n * @example\n * ```typescript\n * const config: ZoomHandlerClampConfig = {\n * clampZoom: true // Enforce zoom boundaries\n * };\n *\n * camera.zoomBoundaries = { min: 0.5, max: 4.0 };\n * // Zoom will be clamped to [0.5, 4.0] range\n * ```\n *\n * @category Camera Rig\n */\nexport type ZoomHandlerClampConfig = {\n /**\n * Whether to enforce zoom level boundaries.\n */\n clampZoom: boolean;\n};\n\n/**\n * Configuration for completely disabling zoom operations.\n *\n * @remarks\n * Provides a global \"zoom lock\" to prevent any zoom changes.\n *\n * When `restrictZoom` is true:\n * - Zoom-to operations return current zoom level (no change)\n * - Zoom-by operations return zero delta (no change)\n *\n * This is useful for:\n * - Locking zoom during specific application states\n * - Fixed-zoom viewing modes\n * - Preventing user zoom in certain contexts\n *\n * @example\n * ```typescript\n * const config: ZoomHandlerRestrictConfig = {\n * restrictZoom: true // Disable all zoom operations\n * };\n *\n * // Any zoom attempt will be ignored\n * ```\n *\n * @category Camera Rig\n */\nexport type ZoomHandlerRestrictConfig = {\n /**\n * Whether to completely prevent zoom operations.\n */\n restrictZoom: boolean;\n};\n\n/**\n * Handler function type for absolute \"zoom to\" camera operations.\n *\n * @param destination - Target zoom level\n * @param camera - Current camera instance\n * @param config - Zoom behavior configuration\n * @returns Transformed zoom level (after applying restrictions and clamping)\n *\n * @remarks\n * Zoom-to handlers process absolute zoom level requests. They form a pipeline\n * that can apply restrictions, clamping, and other transformations.\n *\n * Handler pipeline pattern:\n * - Each handler receives the target zoom, camera state, and config\n * - Returns a potentially modified zoom level\n * - Handlers can be chained using {@link createHandlerChain}\n *\n * Common transformations:\n * - Boundary clamping (enforce min/max zoom limits)\n * - Zoom locking (prevent any zoom changes)\n * - Custom zoom constraints or snapping\n *\n * @example\n * ```typescript\n * const myZoomToHandler: ZoomToHandlerFunction = (target, camera, config) => {\n * // Custom logic: snap to integer zoom levels\n * return Math.round(target);\n * };\n * ```\n *\n * @category Camera Rig\n * @see {@link createHandlerChain} for composing handler pipelines\n * @see {@link createDefaultZoomToOnlyHandler} for the default implementation\n */\nexport type ZoomToHandlerFunction = (destination: number, camera: BoardCamera, config: ZoomHandlerConfig) => number;\n\n/**\n * Handler function type for relative \"zoom by\" camera operations.\n *\n * @param delta - Zoom level change (added to current zoom)\n * @param camera - Current camera instance\n * @param config - Zoom behavior configuration\n * @returns Transformed zoom delta (after applying restrictions and clamping)\n *\n * @remarks\n * Zoom-by handlers process relative zoom change requests. They form a pipeline\n * that can apply restrictions, clamping, and other transformations to the delta.\n *\n * Handler pipeline pattern:\n * - Each handler receives the zoom delta, camera state, and config\n * - Returns a potentially modified delta\n * - Handlers can be chained using {@link createHandlerChain}\n *\n * Common transformations:\n * - Boundary clamping (prevent exceeding min/max zoom)\n * - Zoom locking (return zero delta)\n * - Delta dampening or acceleration\n *\n * @example\n * ```typescript\n * const myZoomByHandler: ZoomByHandlerFunction = (delta, camera, config) => {\n * // Custom logic: dampen large zoom changes\n * if (Math.abs(delta) > 1.0) {\n * return delta * 0.5; // 50% dampening\n * }\n * return delta;\n * };\n * ```\n *\n * @category Camera Rig\n * @see {@link createHandlerChain} for composing handler pipelines\n * @see {@link createDefaultZoomByOnlyHandler} for the default implementation\n */\nexport type ZoomByHandlerFunction = (delta: number, camera: BoardCamera, config: ZoomHandlerConfig) => number;\n\n/**\n * Handler pipeline step that clamps \"zoom to\" targets to camera zoom boundaries.\n *\n * @param destination - Target zoom level\n * @param camera - Current camera instance (provides zoomBoundaries)\n * @param config - Clamping configuration\n * @returns Clamped zoom level\n *\n * @remarks\n * This handler enforces zoom level limits on absolute zoom requests.\n *\n * Behavior:\n * - If `clampZoom` is false: Returns destination unchanged\n * - If `clampZoom` is true: Clamps destination to {@link BoardCamera.zoomBoundaries} (min/max)\n *\n * The clamping is performed by {@link clampZoomLevel}, which handles:\n * - Missing boundaries (undefined min/max)\n * - One-sided constraints (only min or only max)\n * - Full range constraints\n *\n * Can be used standalone, but typically composed into a handler pipeline via\n * {@link createDefaultZoomToOnlyHandler} or {@link createHandlerChain}.\n *\n * @example\n * ```typescript\n * camera.zoomBoundaries = { min: 0.5, max: 3.0 };\n *\n * const config: ZoomHandlerClampConfig = {\n * clampZoom: true\n * };\n *\n * const target = 5.0; // Exceeds max\n * const clamped = clampZoomToHandler(target, camera, config);\n * // clamped = 3.0 (clamped to max boundary)\n * ```\n *\n * @category Camera Rig\n * @see {@link clampZoomLevel} for clamping implementation\n * @see {@link createDefaultZoomToOnlyHandler} for default pipeline usage\n */\nexport function clampZoomToHandler(destination: number, camera: BoardCamera, config: ZoomHandlerClampConfig): number {\n if(!config.clampZoom){\n return destination;\n }\n return clampZoomLevel(destination, camera.zoomBoundaries);\n}\n\n/**\n * Handler pipeline step that clamps \"zoom by\" deltas to prevent boundary violations.\n *\n * @param delta - Zoom level change\n * @param camera - Current camera instance (provides current zoom and boundaries)\n * @param config - Clamping configuration\n * @returns Adjusted delta that respects zoom boundaries\n *\n * @remarks\n * This handler ensures that applying the delta won't exceed zoom boundaries.\n *\n * Algorithm:\n * 1. Calculate potential new zoom level (current + delta)\n * 2. Clamp that level to boundaries\n * 3. Return the difference (clamped - current) as the new delta\n *\n * Behavior:\n * - If `clampZoom` is false: Returns delta unchanged\n * - If `clampZoom` is true: Adjusts delta to stay within boundaries\n *\n * The resulting delta may be zero if already at a boundary and trying to zoom further.\n *\n * Can be used standalone, but typically composed into a handler pipeline via\n * {@link createDefaultZoomByOnlyHandler} or {@link createHandlerChain}.\n *\n * @example\n * ```typescript\n * camera.zoomLevel = 2.8;\n * camera.zoomBoundaries = { max: 3.0 };\n *\n * const config: ZoomHandlerClampConfig = {\n * clampZoom: true\n * };\n *\n * const delta = 0.5; // Would exceed max\n * const clamped = clampZoomByHandler(delta, camera, config);\n * // clamped = 0.2 (only zoom to boundary, not beyond)\n * ```\n *\n * @category Camera Rig\n * @see {@link clampZoomLevel} for clamping implementation\n * @see {@link createDefaultZoomByOnlyHandler} for default pipeline usage\n */\nexport function clampZoomByHandler(delta: number, camera: BoardCamera, config: ZoomHandlerClampConfig): number {\n if(!config.clampZoom){\n return delta;\n }\n let targetZoom = camera.zoomLevel + delta;\n targetZoom = clampZoomLevel(targetZoom, camera.zoomBoundaries);\n delta = targetZoom - camera.zoomLevel;\n return delta;\n}\n\n/**\n * Handler pipeline step that prevents \"zoom to\" operations when zoom is locked.\n *\n * @param destination - Target zoom level\n * @param camera - Current camera instance\n * @param config - Restriction configuration\n * @returns Current zoom level (if locked) or destination (if unlocked)\n *\n * @remarks\n * This handler implements a global zoom lock for absolute zoom operations.\n *\n * Behavior:\n * - If `restrictZoom` is true: Returns current zoom level (prevents any change)\n * - If `restrictZoom` is false: Returns destination unchanged\n *\n * Use this for:\n * - Disabling zoom during specific application states\n * - Fixed-zoom viewing modes\n * - Read-only camera modes\n *\n * Can be used standalone, but typically composed into a handler pipeline via\n * {@link createDefaultZoomToOnlyHandler} or {@link createHandlerChain}.\n *\n * @example\n * ```typescript\n * camera.zoomLevel = 2.0;\n *\n * const config: ZoomHandlerRestrictConfig = {\n * restrictZoom: true // Lock zoom\n * };\n *\n * const target = 3.0;\n * const result = restrictZoomToHandler(target, camera, config);\n * // result = 2.0 (zoom locked, returns current level)\n * ```\n *\n * @category Camera Rig\n * @see {@link createDefaultZoomToOnlyHandler} for default pipeline usage\n */\nexport function restrictZoomToHandler(destination: number, camera: BoardCamera, config: ZoomHandlerRestrictConfig): number {\n if(config.restrictZoom){\n return camera.zoomLevel;\n }\n return destination;\n}\n\n/**\n * Handler pipeline step that prevents \"zoom by\" operations when zoom is locked.\n *\n * @param delta - Zoom level change\n * @param camera - Current camera instance\n * @param config - Restriction configuration\n * @returns Zero (if locked) or delta (if unlocked)\n *\n * @remarks\n * This handler implements a global zoom lock for relative zoom operations.\n *\n * Behavior:\n * - If `restrictZoom` is true: Returns 0 (prevents any change)\n * - If `restrictZoom` is false: Returns delta unchanged\n *\n * Use this for:\n * - Disabling zoom during specific application states\n * - Fixed-zoom viewing modes\n * - Read-only camera modes\n *\n * Can be used standalone, but typically composed into a handler pipeline via\n * {@link createDefaultZoomByOnlyHandler} or {@link createHandlerChain}.\n *\n * @example\n * ```typescript\n * const config: ZoomHandlerRestrictConfig = {\n * restrictZoom: true // Lock zoom\n * };\n *\n * const delta = 0.5;\n * const result = restrictZoomByHandler(delta, camera, config);\n * // result = 0 (zoom locked, no change allowed)\n * ```\n *\n * @category Camera Rig\n * @see {@link createDefaultZoomByOnlyHandler} for default pipeline usage\n */\nexport function restrictZoomByHandler(delta: number, camera: BoardCamera, config: ZoomHandlerRestrictConfig): number {\n if(config.restrictZoom){\n return 0;\n }\n return delta;\n}\n\n/**\n * Creates a default \"zoom to\" handler pipeline for absolute zoom operations.\n *\n * @returns Zoom-to handler function with clamping and restriction\n *\n * @remarks\n * The default handler pipeline applies transformations in this order:\n * 1. **Clamping** ({@link clampZoomToHandler}): Clamps zoom to configured boundaries\n * 2. **Restriction** ({@link restrictZoomToHandler}): Prevents zoom if locked\n *\n * This ensures that:\n * - Zoom level stays within configured min/max boundaries\n * - Zoom can be completely disabled via `restrictZoom` flag\n *\n * The pipeline is specifically for zoom operations without pan compensation.\n * For zoom-at-point operations, use {@link DefaultCameraRig.zoomToAt} which combines\n * zoom and pan handlers.\n *\n * @example\n * ```typescript\n * const zoomTo = createDefaultZoomToOnlyHandler();\n *\n * camera.zoomBoundaries = { min: 0.5, max: 4.0 };\n *\n * // Use in camera rig\n * const target = 5.0; // Exceeds max\n * const constrained = zoomTo(target, camera, {\n * clampZoom: true,\n * restrictZoom: false\n * });\n * // constrained = 4.0 (clamped to max boundary)\n * camera.setZoomLevel(constrained);\n * ```\n *\n * @example\n * ```typescript\n * // Create custom pipeline\n * const customZoomTo = createHandlerChain<number, [BoardCamera, ZoomHandlerConfig]>(\n * clampZoomToHandler, // From default\n * myCustomZoomHandler, // Your custom logic\n * restrictZoomToHandler // From default\n * );\n * ```\n *\n * @category Camera Rig\n * @see {@link createHandlerChain} for creating custom handler pipelines\n * @see {@link clampZoomToHandler} for the clamping step\n * @see {@link restrictZoomToHandler} for the restriction step\n */\nexport function createDefaultZoomToOnlyHandler(): ZoomToHandlerFunction {\n return createHandlerChain<number, [BoardCamera, ZoomHandlerConfig]>(\n clampZoomToHandler,\n restrictZoomToHandler,\n );\n}\n\n/**\n * Creates a default \"zoom by\" handler pipeline for relative zoom operations.\n *\n * @returns Zoom-by handler function with clamping and restriction\n *\n * @remarks\n * The default handler pipeline applies transformations in this order:\n * 1. **Clamping** ({@link clampZoomByHandler}): Adjusts delta to respect boundaries\n * 2. **Restriction** ({@link restrictZoomByHandler}): Returns zero delta if locked\n *\n * This ensures that:\n * - Resulting zoom level stays within configured min/max boundaries\n * - Zoom can be completely disabled via `restrictZoom` flag\n * - Delta is adjusted to prevent boundary violations\n *\n * The pipeline is specifically for zoom operations without pan compensation.\n * For zoom-at-point operations, use {@link DefaultCameraRig.zoomByAt} which combines\n * zoom and pan handlers.\n *\n * @example\n * ```typescript\n * const zoomBy = createDefaultZoomByOnlyHandler();\n *\n * camera.zoomLevel = 3.5;\n * camera.zoomBoundaries = { max: 4.0 };\n *\n * // Use in camera rig\n * const delta = 1.0; // Would exceed max\n * const constrained = zoomBy(delta, camera, {\n * clampZoom: true,\n * restrictZoom: false\n * });\n * // constrained = 0.5 (adjusted to reach boundary exactly)\n * camera.setZoomLevel(camera.zoomLevel + constrained);\n * ```\n *\n * @example\n * ```typescript\n * // Create custom pipeline with dampening\n * const dampenedZoomBy = createHandlerChain<number, [BoardCamera, ZoomHandlerConfig]>(\n * (delta) => delta * 0.7, // 30% dampening\n * clampZoomByHandler, // From default\n * restrictZoomByHandler // From default\n * );\n * ```\n *\n * @category Camera Rig\n * @see {@link createHandlerChain} for creating custom handler pipelines\n * @see {@link clampZoomByHandler} for the clamping step\n * @see {@link restrictZoomByHandler} for the restriction step\n */\nexport function createDefaultZoomByOnlyHandler(): ZoomByHandlerFunction {\n return createHandlerChain<number, [BoardCamera, ZoomHandlerConfig]>(\n clampZoomByHandler,\n restrictZoomByHandler,\n );\n}\n",
36
- "import { Point, PointCal } from \"@ue-too/math\";\nimport { BoardCamera } from \"../interface\";\nimport { createHandlerChain } from \"../../utils/handler-pipeline\";\nimport { clampPoint, clampPointEntireViewPort } from \"../utils/position\";\n\n/**\n * Combined configuration for pan handler behavior, merging restriction and clamping settings.\n *\n * @remarks\n * This type combines {@link PanHandlerRestrictionConfig} and {@link PanHandlerClampConfig}\n * to provide complete control over camera panning behavior.\n *\n * Pan handlers use this configuration to:\n * - Restrict movement along specific axes (world or viewport-relative)\n * - Clamp camera position to stay within boundaries\n * - Control whether entire viewport or just center must stay in bounds\n *\n * @category Camera Rig\n * @see {@link PanHandlerRestrictionConfig} for movement restriction options\n * @see {@link PanHandlerClampConfig} for boundary clamping options\n */\nexport type PanHandlerConfig = PanHandlerRestrictionConfig & PanHandlerClampConfig;\n\n/**\n * Configuration for boundary clamping behavior during camera panning.\n *\n * @remarks\n * Controls how camera position is constrained to stay within defined boundaries.\n *\n * @property limitEntireViewPort - When true, ensures the entire viewport rectangle stays within boundaries.\n * When false, only the camera center point (position) is constrained.\n * This affects how {@link BoardCamera.boundaries} are interpreted.\n *\n * @property clampTranslation - When true, enforces boundary constraints on pan operations.\n * When false, camera can pan freely outside boundaries.\n *\n * @example\n * ```typescript\n * const config: PanHandlerClampConfig = {\n * limitEntireViewPort: true, // Entire view must stay in bounds\n * clampTranslation: true // Enforce boundaries\n * };\n * ```\n *\n * @category Camera Rig\n */\nexport type PanHandlerClampConfig = {\n /**\n * Whether to constrain the entire viewport or just the camera center.\n */\n limitEntireViewPort: boolean;\n /**\n * Whether to enforce boundary constraints on panning.\n */\n clampTranslation: boolean;\n};\n\n/**\n * Configuration for restricting camera movement along specific axes.\n *\n * @remarks\n * Provides fine-grained control over which directions the camera can move.\n * Supports both world-space restrictions (absolute X/Y) and viewport-relative\n * restrictions (screen-space horizontal/vertical, accounting for rotation).\n *\n * **World-space restrictions:**\n * - `restrictXTranslation`: Prevents movement along world X axis\n * - `restrictYTranslation`: Prevents movement along world Y axis\n *\n * **Viewport-relative restrictions (rotation-aware):**\n * - `restrictRelativeXTranslation`: Prevents horizontal movement (screen-space)\n * - `restrictRelativeYTranslation`: Prevents vertical movement (screen-space)\n *\n * Use cases:\n * - Side-scrolling games: `restrictYTranslation = true`\n * - Locked vertical scrolling: `restrictRelativeYTranslation = true`\n * - Fixed-axis pan tools in editors\n *\n * @example\n * ```typescript\n * // Side-scroller: only allow horizontal movement in world space\n * const config: PanHandlerRestrictionConfig = {\n * restrictXTranslation: false,\n * restrictYTranslation: true,\n * restrictRelativeXTranslation: false,\n * restrictRelativeYTranslation: false\n * };\n *\n * // Lock to vertical screen movement only (with camera rotation)\n * const screenConfig: PanHandlerRestrictionConfig = {\n * restrictXTranslation: false,\n * restrictYTranslation: false,\n * restrictRelativeXTranslation: true,\n * restrictRelativeYTranslation: false\n * };\n * ```\n *\n * @category Camera Rig\n */\nexport type PanHandlerRestrictionConfig = {\n /**\n * Whether to prevent movement along the world X axis.\n */\n restrictXTranslation: boolean;\n /**\n * Whether to prevent movement along the world Y axis.\n */\n restrictYTranslation: boolean;\n /**\n * Whether to prevent horizontal movement in viewport/screen space.\n * Accounts for camera rotation - locks movement perpendicular to screen's vertical direction.\n */\n restrictRelativeXTranslation: boolean;\n /**\n * Whether to prevent vertical movement in viewport/screen space.\n * Accounts for camera rotation - locks movement perpendicular to screen's horizontal direction.\n */\n restrictRelativeYTranslation: boolean;\n};\n\n/**\n * Handler function type for absolute \"pan to\" camera operations.\n *\n * @param destination - Target camera position in world space\n * @param camera - Current camera instance\n * @param config - Pan behavior configuration\n * @returns Transformed destination position (after applying restrictions and clamping)\n *\n * @remarks\n * Pan-to handlers process absolute camera positioning requests. They form a pipeline\n * that can apply restrictions, clamping, and other transformations to the target position.\n *\n * Handler pipeline pattern:\n * - Each handler receives the current destination, camera state, and config\n * - Returns a potentially modified destination point\n * - Handlers can be chained using {@link createHandlerChain}\n *\n * Common transformations:\n * - Axis restrictions (prevent movement on specific axes)\n * - Boundary clamping (keep position within bounds)\n * - Viewport constraints (ensure entire viewport stays in bounds)\n *\n * @example\n * ```typescript\n * const myPanToHandler: PanToHandlerFunction = (dest, camera, config) => {\n * // Custom logic: snap to grid\n * return {\n * x: Math.round(dest.x / 100) * 100,\n * y: Math.round(dest.y / 100) * 100\n * };\n * };\n * ```\n *\n * @category Camera Rig\n * @see {@link createHandlerChain} for composing handler pipelines\n * @see {@link createDefaultPanToHandler} for the default implementation\n */\nexport type PanToHandlerFunction = (destination: Point, camera: BoardCamera, config: PanHandlerConfig) => Point;\n\n/**\n * Handler function type for relative \"pan by\" camera operations.\n *\n * @param delta - Movement delta in world space\n * @param camera - Current camera instance\n * @param config - Pan behavior configuration\n * @returns Transformed movement delta (after applying restrictions and clamping)\n *\n * @remarks\n * Pan-by handlers process relative camera movement requests. They form a pipeline\n * that can apply restrictions, clamping, and other transformations to the movement delta.\n *\n * Handler pipeline pattern:\n * - Each handler receives the current delta, camera state, and config\n * - Returns a potentially modified delta\n * - Handlers can be chained using {@link createHandlerChain}\n *\n * Common transformations:\n * - Axis restrictions (prevent movement on specific axes)\n * - Boundary clamping (prevent moving outside bounds)\n * - Delta dampening or acceleration\n *\n * @example\n * ```typescript\n * const myPanByHandler: PanByHandlerFunction = (delta, camera, config) => {\n * // Custom logic: dampen large movements\n * const magnitude = Math.sqrt(delta.x ** 2 + delta.y ** 2);\n * if (magnitude > 100) {\n * const scale = 100 / magnitude;\n * return { x: delta.x * scale, y: delta.y * scale };\n * }\n * return delta;\n * };\n * ```\n *\n * @category Camera Rig\n * @see {@link createHandlerChain} for composing handler pipelines\n * @see {@link createDefaultPanByHandler} for the default implementation\n */\nexport type PanByHandlerFunction = (delta: Point, camera: BoardCamera, config: PanHandlerConfig) => Point;\n\n/**\n * Creates a default \"pan to\" handler pipeline for absolute camera positioning.\n *\n * @returns Pan-to handler function with restriction and clamping\n *\n * @remarks\n * The default handler pipeline applies transformations in this order:\n * 1. **Restriction** ({@link restrictPanToHandler}): Applies axis restrictions based on config\n * 2. **Clamping** ({@link clampToHandler}): Clamps position to boundaries\n *\n * This ensures that:\n * - Camera respects axis lock settings (e.g., side-scroller constraints)\n * - Camera position stays within configured boundaries\n * - Entire viewport can be kept in bounds (if `limitEntireViewPort` is true)\n *\n * All operations work in world coordinate space.\n *\n * @example\n * ```typescript\n * const panTo = createDefaultPanToHandler();\n *\n * // Use in camera rig\n * const destination = { x: 1000, y: 500 };\n * const constrainedDest = panTo(destination, camera, {\n * restrictYTranslation: true, // Lock Y axis\n * clampTranslation: true,\n * limitEntireViewPort: true,\n * // ... other config\n * });\n * camera.setPosition(constrainedDest);\n * ```\n *\n * @example\n * ```typescript\n * // Create custom pipeline using default handlers\n * const customPanTo = createHandlerChain<Point, [BoardCamera, PanHandlerConfig]>(\n * restrictPanToHandler, // From default\n * myCustomHandler, // Your custom logic\n * clampToHandler // From default\n * );\n * ```\n *\n * @category Camera Rig\n * @see {@link createHandlerChain} for creating custom handler pipelines\n * @see {@link restrictPanToHandler} for the restriction step\n * @see {@link clampToHandler} for the clamping step\n */\nexport function createDefaultPanToHandler(): PanToHandlerFunction {\n return createHandlerChain<Point, [BoardCamera, PanHandlerConfig]>(\n restrictPanToHandler,\n clampToHandler,\n );\n}\n\n/**\n * Creates a default \"pan by\" handler pipeline for relative camera movement.\n *\n * @returns Pan-by handler function with restriction and clamping\n *\n * @remarks\n * The default handler pipeline applies transformations in this order:\n * 1. **Restriction** ({@link restrictPanByHandler}): Applies axis restrictions based on config\n * 2. **Clamping** ({@link clampByHandler}): Clamps resulting position to boundaries\n *\n * This ensures that:\n * - Camera movement respects axis lock settings\n * - Camera stays within configured boundaries after applying delta\n * - Delta is adjusted to prevent boundary violations\n *\n * The input delta is in world space. All operations work in world coordinates.\n *\n * @example\n * ```typescript\n * const panBy = createDefaultPanByHandler();\n *\n * // Use in camera rig\n * const delta = { x: 50, y: -30 };\n * const constrainedDelta = panBy(delta, camera, {\n * restrictRelativeYTranslation: true, // Lock screen-vertical movement\n * clampTranslation: true,\n * limitEntireViewPort: false,\n * // ... other config\n * });\n * camera.setPosition(PointCal.addVector(camera.position, constrainedDelta));\n * ```\n *\n * @example\n * ```typescript\n * // Create custom pipeline with dampening\n * const dampenedPanBy = createHandlerChain<Point, [BoardCamera, PanHandlerConfig]>(\n * restrictPanByHandler,\n * (delta) => ({ x: delta.x * 0.8, y: delta.y * 0.8 }), // 20% dampening\n * clampByHandler\n * );\n * ```\n *\n * @category Camera Rig\n * @see {@link createHandlerChain} for creating custom handler pipelines\n * @see {@link restrictPanByHandler} for the restriction step\n * @see {@link clampByHandler} for the clamping step\n */\nexport function createDefaultPanByHandler(): PanByHandlerFunction {\n return createHandlerChain<Point, [BoardCamera, PanHandlerConfig]>(\n restrictPanByHandler,\n clampByHandler,\n );\n}\n\n/**\n * Handler pipeline step that applies axis restrictions to \"pan to\" destinations.\n *\n * @param destination - Target camera position in world space\n * @param camera - Current camera instance\n * @param config - Restriction configuration\n * @returns Restricted destination position\n *\n * @remarks\n * This handler enforces axis-lock constraints on absolute camera positioning.\n * It converts the destination to a delta, applies restrictions, then converts back.\n *\n * Algorithm:\n * 1. Calculate delta from current position to destination\n * 2. Apply restrictions using {@link convertDeltaToComplyWithRestriction}\n * 3. If delta becomes zero, return original destination (already at target)\n * 4. Otherwise, return current position + restricted delta\n *\n * Can be used standalone, but typically composed into a handler pipeline via\n * {@link createDefaultPanToHandler} or {@link createHandlerChain}.\n *\n * @example\n * ```typescript\n * // Standalone usage\n * const config: PanHandlerRestrictionConfig = {\n * restrictYTranslation: true, // Lock Y axis\n * restrictXTranslation: false,\n * restrictRelativeXTranslation: false,\n * restrictRelativeYTranslation: false\n * };\n *\n * const destination = { x: 1000, y: 500 };\n * const restricted = restrictPanToHandler(destination, camera, config);\n * // If camera is at { x: 0, y: 200 }, result is { x: 1000, y: 200 }\n * ```\n *\n * @category Camera Rig\n * @see {@link convertDeltaToComplyWithRestriction} for restriction logic\n * @see {@link createDefaultPanToHandler} for default pipeline usage\n */\nexport function restrictPanToHandler(destination: Point, camera: BoardCamera, config: PanHandlerRestrictionConfig): Point {\n let delta = PointCal.subVector(destination, camera.position);\n delta = convertDeltaToComplyWithRestriction(delta, camera, config);\n if (delta.x === 0 && delta.y === 0) {\n return destination;\n }\n const dest = PointCal.addVector(camera.position, delta);\n return dest;\n}\n\n/**\n * Handler pipeline step that applies axis restrictions to \"pan by\" deltas.\n *\n * @param delta - Movement delta in world space\n * @param camera - Current camera instance\n * @param config - Restriction configuration\n * @returns Restricted movement delta\n *\n * @remarks\n * This handler enforces axis-lock constraints on relative camera movement.\n * It directly transforms the delta according to restriction rules.\n *\n * Restrictions applied by {@link convertDeltaToComplyWithRestriction}:\n * - World-space axis locks (X/Y)\n * - Viewport-relative axis locks (horizontal/vertical, accounting for rotation)\n *\n * Can be used standalone, but typically composed into a handler pipeline via\n * {@link createDefaultPanByHandler} or {@link createHandlerChain}.\n *\n * @example\n * ```typescript\n * // Standalone usage - lock to screen-horizontal movement\n * const config: PanHandlerRestrictionConfig = {\n * restrictXTranslation: false,\n * restrictYTranslation: false,\n * restrictRelativeXTranslation: false,\n * restrictRelativeYTranslation: true // Lock screen-vertical\n * };\n *\n * const delta = { x: 50, y: 30 };\n * const restricted = restrictPanByHandler(delta, camera, config);\n * // Result depends on camera rotation - only horizontal screen movement allowed\n * ```\n *\n * @category Camera Rig\n * @see {@link convertDeltaToComplyWithRestriction} for restriction logic\n * @see {@link createDefaultPanByHandler} for default pipeline usage\n */\nexport function restrictPanByHandler(delta: Point, camera: BoardCamera, config: PanHandlerRestrictionConfig): Point {\n delta = convertDeltaToComplyWithRestriction(delta, camera, config);\n return delta;\n}\n\n/**\n * Handler pipeline step that clamps \"pan to\" destinations to camera boundaries.\n *\n * @param destination - Target camera position in world space\n * @param camera - Current camera instance (provides boundaries and viewport dimensions)\n * @param config - Clamping configuration\n * @returns Clamped destination position\n *\n * @remarks\n * This handler enforces boundary constraints on absolute camera positioning.\n * Behavior depends on configuration:\n *\n * - If `clampTranslation` is false: Returns destination unchanged (no clamping)\n * - If `limitEntireViewPort` is false: Clamps camera center to boundaries\n * - If `limitEntireViewPort` is true: Ensures entire viewport rectangle stays in bounds\n *\n * The entire-viewport mode accounts for:\n * - Viewport dimensions (width/height)\n * - Current zoom level (affects viewport size in world space)\n * - Camera rotation (affects viewport orientation)\n *\n * Can be used standalone, but typically composed into a handler pipeline via\n * {@link createDefaultPanToHandler} or {@link createHandlerChain}.\n *\n * @example\n * ```typescript\n * // Standalone usage - ensure entire viewport stays in bounds\n * camera.boundaries = {\n * min: { x: 0, y: 0 },\n * max: { x: 2000, y: 1000 }\n * };\n *\n * const config: PanHandlerClampConfig = {\n * clampTranslation: true,\n * limitEntireViewPort: true\n * };\n *\n * const destination = { x: 2500, y: 500 }; // Outside bounds\n * const clamped = clampToHandler(destination, camera, config);\n * // Result keeps entire viewport within [0,0] to [2000,1000]\n * ```\n *\n * @category Camera Rig\n * @see {@link clampPoint} for center-point clamping\n * @see {@link clampPointEntireViewPort} for full-viewport clamping\n * @see {@link createDefaultPanToHandler} for default pipeline usage\n */\nexport function clampToHandler(destination: Point, camera: BoardCamera, config: PanHandlerClampConfig): Point {\n if(!config.clampTranslation){\n return destination;\n }\n let actualDest = clampPoint(destination, camera.boundaries);\n if(config.limitEntireViewPort){\n actualDest = clampPointEntireViewPort(destination, camera.viewPortWidth, camera.viewPortHeight, camera.boundaries, camera.zoomLevel, camera.rotation);\n }\n return actualDest;\n}\n\n/**\n * Handler pipeline step that clamps \"pan by\" deltas to prevent boundary violations.\n *\n * @param delta - Movement delta in world space\n * @param camera - Current camera instance (provides boundaries and viewport dimensions)\n * @param config - Clamping configuration\n * @returns Adjusted delta that respects boundaries\n *\n * @remarks\n * This handler ensures that applying the delta won't move the camera outside boundaries.\n * It works by:\n * 1. Calculating the potential new position (current + delta)\n * 2. Clamping that position to boundaries\n * 3. Returning the difference (clamped - current) as the new delta\n *\n * Behavior depends on configuration:\n * - If `clampTranslation` is false: Returns delta unchanged\n * - If `limitEntireViewPort` is false: Clamps based on camera center\n * - If `limitEntireViewPort` is true: Ensures entire viewport stays in bounds\n *\n * The resulting delta may be zero if the camera is already at a boundary\n * and trying to move further outside.\n *\n * Can be used standalone, but typically composed into a handler pipeline via\n * {@link createDefaultPanByHandler} or {@link createHandlerChain}.\n *\n * @example\n * ```typescript\n * // Standalone usage\n * camera.position = { x: 1950, y: 500 };\n * camera.boundaries = { max: { x: 2000 } };\n *\n * const config: PanHandlerClampConfig = {\n * clampTranslation: true,\n * limitEntireViewPort: false\n * };\n *\n * const delta = { x: 100, y: 0 }; // Try to move right\n * const clamped = clampByHandler(delta, camera, config);\n * // Result: { x: 50, y: 0 } - only move to boundary, not beyond\n * ```\n *\n * @category Camera Rig\n * @see {@link clampPoint} for center-point clamping\n * @see {@link clampPointEntireViewPort} for full-viewport clamping\n * @see {@link createDefaultPanByHandler} for default pipeline usage\n */\nexport function clampByHandler(delta: Point, camera: BoardCamera, config: PanHandlerClampConfig): Point {\n if(!config.clampTranslation){\n return delta;\n }\n let actualDelta = PointCal.subVector(clampPoint(PointCal.addVector(camera.position, delta), camera.boundaries), camera.position);\n if(config.limitEntireViewPort){\n actualDelta = PointCal.subVector(clampPointEntireViewPort(PointCal.addVector(camera.position, delta), camera.viewPortWidth, camera.viewPortHeight, camera.boundaries, camera.zoomLevel, camera.rotation), camera.position);\n }\n return actualDelta;\n}\n\n/**\n * Transforms a movement delta to comply with axis restriction configuration.\n *\n * @param delta - Original movement delta in world space\n * @param camera - Current camera instance (provides rotation for relative restrictions)\n * @param config - Restriction configuration\n * @returns Transformed delta that respects all enabled restrictions\n *\n * @remarks\n * This function applies axis-lock logic for both world-space and viewport-relative restrictions.\n * Restrictions are processed in priority order:\n *\n * 1. **Complete locks** (highest priority):\n * - Both world axes locked → return zero delta\n * - Both relative axes locked → return zero delta\n *\n * 2. **World-space axis locks**:\n * - `restrictXTranslation` → Zero out X component\n * - `restrictYTranslation` → Zero out Y component\n *\n * 3. **Viewport-relative axis locks** (rotation-aware):\n * - `restrictRelativeXTranslation` → Project delta onto screen-vertical direction\n * - `restrictRelativeYTranslation` → Project delta onto screen-horizontal direction\n *\n * For viewport-relative restrictions:\n * - \"Relative X\" = horizontal in viewport/screen space\n * - \"Relative Y\" = vertical in viewport/screen space\n * - These account for camera rotation by projecting onto rotated axes\n *\n * @example\n * ```typescript\n * // World-space restriction: lock Y axis\n * const config1 = {\n * restrictXTranslation: false,\n * restrictYTranslation: true,\n * restrictRelativeXTranslation: false,\n * restrictRelativeYTranslation: false\n * };\n *\n * const delta1 = { x: 50, y: 30 };\n * const result1 = convertDeltaToComplyWithRestriction(delta1, camera, config1);\n * // result1 = { x: 50, y: 0 } - Y component removed\n * ```\n *\n * @example\n * ```typescript\n * // Viewport-relative restriction: lock horizontal screen movement\n * const config2 = {\n * restrictXTranslation: false,\n * restrictYTranslation: false,\n * restrictRelativeXTranslation: true, // Lock screen-horizontal\n * restrictRelativeYTranslation: false\n * };\n *\n * // Camera rotated 45 degrees\n * const delta2 = { x: 100, y: 100 };\n * const result2 = convertDeltaToComplyWithRestriction(delta2, camera, config2);\n * // result2 projects delta onto screen-vertical direction\n * // (perpendicular to screen-horizontal)\n * ```\n *\n * @category Camera Rig\n * @see {@link restrictPanByHandler} for usage in pan-by pipeline\n * @see {@link restrictPanToHandler} for usage in pan-to pipeline\n */\nexport function convertDeltaToComplyWithRestriction(delta: Point, camera: BoardCamera, config: PanHandlerRestrictionConfig): Point {\n if(config.restrictXTranslation && config.restrictYTranslation){\n return {x: 0, y: 0};\n }\n if(config.restrictRelativeXTranslation && config.restrictRelativeYTranslation){\n return {x: 0, y: 0};\n }\n if(config.restrictXTranslation){\n delta.x = 0;\n }\n if(config.restrictYTranslation){\n delta.y = 0;\n }\n if(config.restrictRelativeXTranslation){\n const upDirection = PointCal.rotatePoint({x: 0, y: 1}, camera.rotation);\n const value = PointCal.dotProduct(upDirection, delta);\n delta = PointCal.multiplyVectorByScalar(upDirection, value);\n }\n if(config.restrictRelativeYTranslation){\n const rightDirection = PointCal.rotatePoint({x: 1, y: 0}, camera.rotation);\n const value = PointCal.dotProduct(rightDirection, delta);\n delta = PointCal.multiplyVectorByScalar(rightDirection, value);\n }\n return delta;\n}\n\n/**\n * Converts a user input delta (viewport space) to camera movement delta (world space).\n *\n * @param delta - Movement delta in viewport/screen coordinates (CSS pixels)\n * @param camera - Current camera instance (provides rotation and zoom)\n * @returns Equivalent delta in world space\n *\n * @remarks\n * This function performs the standard viewport-to-world delta conversion:\n * 1. Rotate delta by camera rotation (convert screen direction to world direction)\n * 2. Scale by inverse zoom (convert screen distance to world distance)\n *\n * Formula: `worldDelta = rotate(viewportDelta, cameraRotation) / zoomLevel`\n *\n * This is the core conversion used by {@link DefaultCameraRig.panByViewPort}.\n *\n * @example\n * ```typescript\n * // User drags mouse 100 pixels right, 50 pixels down\n * const viewportDelta = { x: 100, y: 50 };\n *\n * // Camera at 2x zoom, no rotation\n * camera.zoomLevel = 2.0;\n * camera.rotation = 0;\n *\n * const worldDelta = convertUserInputDeltaToCameraDelta(viewportDelta, camera);\n * // worldDelta = { x: 50, y: 25 } - half the viewport delta due to 2x zoom\n * ```\n *\n * @example\n * ```typescript\n * // With camera rotation\n * camera.zoomLevel = 1.0;\n * camera.rotation = Math.PI / 2; // 90 degrees\n *\n * const viewportDelta = { x: 100, y: 0 }; // Drag right\n * const worldDelta = convertUserInputDeltaToCameraDelta(viewportDelta, camera);\n * // worldDelta ≈ { x: 0, y: -100 } - rotated 90 degrees in world space\n * ```\n *\n * @category Camera Rig\n * @see {@link DefaultCameraRig.panByViewPort} for usage\n */\nexport function convertUserInputDeltaToCameraDelta(delta: Point, camera: BoardCamera): Point {\n return PointCal.multiplyVectorByScalar(PointCal.rotatePoint(delta, camera.rotation), 1 / camera.zoomLevel);\n}\n",
37
- "import { BoardCamera } from \"../interface\";\nimport { createHandlerChain } from \"../../utils/handler-pipeline\";\nimport { normalizeAngleZero2TwoPI, angleSpan, clampRotation } from \"../utils/rotation\";\n\n/**\n * Combined configuration for rotation handler behavior, merging restriction and clamping settings.\n *\n * @remarks\n * This type combines {@link RotationHandlerRestrictConfig} and {@link RotationHandlerClampConfig}\n * to provide complete control over camera rotation behavior.\n *\n * Rotation handlers use this configuration to:\n * - Completely disable rotation operations (restriction)\n * - Clamp rotation angle to stay within defined angular limits\n *\n * @category Camera Rig\n * @see {@link RotationHandlerRestrictConfig} for rotation locking options\n * @see {@link RotationHandlerClampConfig} for angular boundary options\n */\nexport type RotationHandlerConfig = RotationHandlerRestrictConfig & RotationHandlerClampConfig;\n\n/**\n * Configuration for completely disabling rotation operations.\n *\n * @remarks\n * Provides a global \"rotation lock\" to prevent any rotation changes.\n *\n * When `restrictRotation` is true:\n * - Rotate-to operations return current rotation (no change)\n * - Rotate-by operations return zero delta (no change)\n *\n * This is useful for:\n * - Locking rotation during specific application states\n * - Fixed-orientation viewing modes (north-up maps, etc.)\n * - Preventing user rotation in certain contexts\n *\n * @example\n * ```typescript\n * const config: RotationHandlerRestrictConfig = {\n * restrictRotation: true // Lock rotation\n * };\n *\n * // Any rotation attempt will be ignored\n * ```\n *\n * @category Camera Rig\n */\nexport type RotationHandlerRestrictConfig = {\n /**\n * Whether to completely prevent rotation operations.\n */\n restrictRotation: boolean;\n}\n\n/**\n * Configuration for rotation angle boundary clamping.\n *\n * @remarks\n * Controls whether rotation operations should be constrained to camera's rotation boundaries.\n *\n * When `clampRotation` is true, rotation handlers enforce {@link BoardCamera.rotationBoundaries}\n * limits (min/max angles in radians). When false, rotation can exceed configured boundaries.\n *\n * Rotation boundaries allow limiting camera rotation to a specific angular range,\n * useful for scenarios like:\n * - Restricting rotation to ±45 degrees from north\n * - Allowing only certain cardinal directions\n * - Preventing full 360-degree rotation\n *\n * @example\n * ```typescript\n * const config: RotationHandlerClampConfig = {\n * clampRotation: true // Enforce rotation boundaries\n * };\n *\n * camera.rotationBoundaries = { min: 0, max: Math.PI / 2 };\n * // Rotation clamped to [0, 90 degrees] range\n * ```\n *\n * @category Camera Rig\n */\nexport type RotationHandlerClampConfig = {\n /**\n * Whether to enforce rotation angle boundaries.\n */\n clampRotation: boolean;\n}\n\n/**\n * Handler function type for relative \"rotate by\" camera operations.\n *\n * @param delta - Rotation angle change in radians (positive = counter-clockwise)\n * @param camera - Current camera instance\n * @param config - Rotation behavior configuration\n * @returns Transformed rotation delta (after applying restrictions and clamping)\n *\n * @remarks\n * Rotate-by handlers process relative rotation change requests. They form a pipeline\n * that can apply restrictions, clamping, and other transformations to the delta.\n *\n * Handler pipeline pattern:\n * - Each handler receives the rotation delta, camera state, and config\n * - Returns a potentially modified delta\n * - Handlers can be chained using {@link createHandlerChain}\n *\n * Common transformations:\n * - Angular boundary clamping (prevent exceeding min/max angles)\n * - Rotation locking (return zero delta)\n * - Delta dampening or snapping\n *\n * Rotation angles are in radians where:\n * - 0 = North (no rotation)\n * - Positive values = Counter-clockwise rotation\n * - Negative values = Clockwise rotation\n *\n * @example\n * ```typescript\n * const myRotateByHandler: RotateByHandlerFunction = (delta, camera, config) => {\n * // Custom logic: snap to 45-degree increments\n * const totalRotation = camera.rotation + delta;\n * const snapped = Math.round(totalRotation / (Math.PI / 4)) * (Math.PI / 4);\n * return snapped - camera.rotation;\n * };\n * ```\n *\n * @category Camera Rig\n * @see {@link createHandlerChain} for composing handler pipelines\n * @see {@link createDefaultRotateByHandler} for the default implementation\n */\nexport type RotateByHandlerFunction = (delta: number, camera: BoardCamera, config: RotationHandlerConfig) => number;\n\n/**\n * Handler function type for absolute \"rotate to\" camera operations.\n *\n * @param targetRotation - Target rotation angle in radians\n * @param camera - Current camera instance\n * @param config - Rotation behavior configuration\n * @returns Transformed rotation angle (after applying restrictions and clamping)\n *\n * @remarks\n * Rotate-to handlers process absolute rotation angle requests. They form a pipeline\n * that can apply restrictions, clamping, and other transformations.\n *\n * Handler pipeline pattern:\n * - Each handler receives the target angle, camera state, and config\n * - Returns a potentially modified angle\n * - Handlers can be chained using {@link createHandlerChain}\n *\n * Common transformations:\n * - Angular boundary clamping (enforce min/max angles)\n * - Rotation locking (return current angle)\n * - Angle snapping or normalization\n *\n * Rotation angles are in radians where:\n * - 0 = North (no rotation)\n * - π/2 = West (90° counter-clockwise)\n * - π = South (180°)\n * - 3π/2 = East (270° counter-clockwise)\n *\n * @example\n * ```typescript\n * const myRotateToHandler: RotateToHandlerFunction = (target, camera, config) => {\n * // Custom logic: snap to cardinal directions\n * const cardinals = [0, Math.PI/2, Math.PI, 3*Math.PI/2];\n * return cardinals.reduce((prev, curr) =>\n * Math.abs(curr - target) < Math.abs(prev - target) ? curr : prev\n * );\n * };\n * ```\n *\n * @category Camera Rig\n * @see {@link createHandlerChain} for composing handler pipelines\n * @see {@link createDefaultRotateToHandler} for the default implementation\n */\nexport type RotateToHandlerFunction = (targetRotation: number, camera: BoardCamera, config: RotationHandlerConfig) => number;\n\n/**\n * Handler pipeline step that clamps \"rotate by\" deltas to prevent angular boundary violations.\n *\n * @param delta - Rotation angle change in radians\n * @param camera - Current camera instance (provides current rotation and boundaries)\n * @param config - Clamping configuration\n * @returns Adjusted delta that respects rotation boundaries\n *\n * @remarks\n * This handler ensures that applying the delta won't exceed rotation boundaries.\n *\n * Algorithm:\n * 1. Calculate potential new rotation (current + delta)\n * 2. Normalize angle to [0, 2π) range\n * 3. Clamp to rotation boundaries\n * 4. Calculate shortest angular distance from current to clamped angle\n * 5. Return that distance as the new delta\n *\n * Behavior:\n * - If `clampRotation` is false: Returns delta unchanged\n * - If `clampRotation` is true: Adjusts delta to stay within boundaries\n *\n * The resulting delta may be zero if already at a boundary and trying to rotate further.\n *\n * @example\n * ```typescript\n * camera.rotation = Math.PI * 0.4; // 72 degrees\n * camera.rotationBoundaries = { max: Math.PI / 2 }; // Max 90 degrees\n *\n * const config: RotationHandlerClampConfig = {\n * clampRotation: true\n * };\n *\n * const delta = Math.PI * 0.2; // Try to rotate 36 degrees (would exceed max)\n * const clamped = clampRotateByHandler(delta, camera, config);\n * // clamped ≈ 0.314 radians (18 degrees - only rotate to boundary)\n * ```\n *\n * @category Camera Rig\n * @see {@link normalizeAngleZero2TwoPI} for angle normalization\n * @see {@link clampRotation} for boundary clamping\n * @see {@link angleSpan} for calculating angular distance\n */\nexport function clampRotateByHandler(delta: number, camera: BoardCamera, config: RotationHandlerClampConfig): number {\n if(!config.clampRotation){\n return delta;\n }\n const targetRotation = normalizeAngleZero2TwoPI(camera.rotation + delta);\n const clampedRotation = clampRotation(targetRotation, camera.rotationBoundaries);\n const diff = angleSpan(camera.rotation, clampedRotation);\n return diff;\n}\n\n/**\n * Handler pipeline step that prevents \"rotate by\" operations when rotation is locked.\n *\n * @param delta - Rotation angle change in radians\n * @param camera - Current camera instance\n * @param config - Restriction configuration\n * @returns Zero (if locked) or delta (if unlocked)\n *\n * @remarks\n * This handler implements a global rotation lock for relative rotation operations.\n *\n * Behavior:\n * - If `restrictRotation` is true: Returns 0 (prevents any change)\n * - If `restrictRotation` is false: Returns delta unchanged\n *\n * @example\n * ```typescript\n * const config: RotationHandlerRestrictConfig = {\n * restrictRotation: true // Lock rotation\n * };\n *\n * const delta = Math.PI / 4; // Try to rotate 45 degrees\n * const result = restrictRotateByHandler(delta, camera, config);\n * // result = 0 (rotation locked, no change allowed)\n * ```\n *\n * @category Camera Rig\n * @see {@link createDefaultRotateByHandler} for default pipeline usage\n */\nexport function restrictRotateByHandler(delta: number, camera: BoardCamera, config: RotationHandlerRestrictConfig): number {\n if(config.restrictRotation){\n return 0;\n }\n return delta;\n}\n\n/**\n * Handler pipeline step that clamps \"rotate to\" targets to camera rotation boundaries.\n *\n * @param targetRotation - Target rotation angle in radians\n * @param camera - Current camera instance (provides rotationBoundaries)\n * @param config - Clamping configuration\n * @returns Clamped rotation angle\n *\n * @remarks\n * This handler enforces angular limits on absolute rotation requests.\n *\n * Behavior:\n * - If `clampRotation` is false: Returns target unchanged\n * - If `clampRotation` is true: Clamps target to {@link BoardCamera.rotationBoundaries}\n *\n * The clamping handles:\n * - Missing boundaries (undefined min/max)\n * - One-sided constraints (only min or only max)\n * - Full range constraints\n *\n * @example\n * ```typescript\n * camera.rotationBoundaries = { min: 0, max: Math.PI }; // [0°, 180°]\n *\n * const config: RotationHandlerClampConfig = {\n * clampRotation: true\n * };\n *\n * const target = Math.PI * 1.5; // 270 degrees (exceeds max)\n * const clamped = clampRotateToHandler(target, camera, config);\n * // clamped = π (180 degrees - clamped to max boundary)\n * ```\n *\n * @category Camera Rig\n * @see {@link clampRotation} for clamping implementation\n * @see {@link createDefaultRotateToHandler} for default pipeline usage\n */\nexport function clampRotateToHandler(targetRotation: number, camera: BoardCamera, config: RotationHandlerClampConfig): number {\n if(!config.clampRotation){\n return targetRotation;\n }\n const clampedRotation = clampRotation(targetRotation, camera.rotationBoundaries);\n return clampedRotation;\n}\n\n/**\n * Handler pipeline step that prevents \"rotate to\" operations when rotation is locked.\n *\n * @param targetRotation - Target rotation angle in radians\n * @param camera - Current camera instance\n * @param config - Restriction configuration\n * @returns Current rotation (if locked) or target (if unlocked)\n *\n * @remarks\n * This handler implements a global rotation lock for absolute rotation operations.\n *\n * Behavior:\n * - If `restrictRotation` is true: Returns current rotation (prevents any change)\n * - If `restrictRotation` is false: Returns target unchanged\n *\n * @example\n * ```typescript\n * camera.rotation = Math.PI / 2; // Currently at 90 degrees\n *\n * const config: RotationHandlerRestrictConfig = {\n * restrictRotation: true // Lock rotation\n * };\n *\n * const target = Math.PI; // Try to rotate to 180 degrees\n * const result = restrictRotateToHandler(target, camera, config);\n * // result = π/2 (rotation locked, returns current angle)\n * ```\n *\n * @category Camera Rig\n * @see {@link createDefaultRotateToHandler} for default pipeline usage\n */\nexport function restrictRotateToHandler(targetRotation: number, camera: BoardCamera, config: RotationHandlerRestrictConfig): number {\n if(config.restrictRotation){\n return camera.rotation;\n }\n return targetRotation;\n}\n\n/**\n * Creates a default \"rotate by\" handler pipeline for relative rotation operations.\n *\n * @returns Rotate-by handler function with restriction and clamping\n *\n * @remarks\n * The default handler pipeline applies transformations in this order:\n * 1. **Restriction** ({@link restrictRotateByHandler}): Returns zero delta if locked\n * 2. **Clamping** ({@link clampRotateByHandler}): Adjusts delta to respect boundaries\n *\n * This ensures that:\n * - Rotation can be completely disabled via `restrictRotation` flag\n * - Resulting rotation angle stays within configured angular boundaries\n * - Delta is adjusted to prevent boundary violations\n *\n * @example\n * ```typescript\n * const rotateBy = createDefaultRotateByHandler();\n *\n * camera.rotation = Math.PI * 0.4; // 72 degrees\n * camera.rotationBoundaries = { max: Math.PI / 2 }; // Max 90 degrees\n *\n * const delta = Math.PI * 0.3; // Try to rotate 54 degrees (would exceed max)\n * const constrained = rotateBy(delta, camera, {\n * clampRotation: true,\n * restrictRotation: false\n * });\n * // constrained adjusted to only rotate to boundary\n * camera.setRotation(camera.rotation + constrained);\n * ```\n *\n * @category Camera Rig\n * @see {@link createHandlerChain} for creating custom handler pipelines\n * @see {@link restrictRotateByHandler} for the restriction step\n * @see {@link clampRotateByHandler} for the clamping step\n */\nexport function createDefaultRotateByHandler(): RotateByHandlerFunction {\n return createHandlerChain<number, [BoardCamera, RotationHandlerConfig]>(\n restrictRotateByHandler,\n clampRotateByHandler,\n );\n}\n\n/**\n * Creates a default \"rotate to\" handler pipeline for absolute rotation operations.\n *\n * @returns Rotate-to handler function with restriction and clamping\n *\n * @remarks\n * The default handler pipeline applies transformations in this order:\n * 1. **Restriction** ({@link restrictRotateToHandler}): Returns current angle if locked\n * 2. **Clamping** ({@link clampRotateToHandler}): Clamps angle to configured boundaries\n *\n * This ensures that:\n * - Rotation can be completely disabled via `restrictRotation` flag\n * - Rotation angle stays within configured angular boundaries\n *\n * @example\n * ```typescript\n * const rotateTo = createDefaultRotateToHandler();\n *\n * camera.rotationBoundaries = { min: 0, max: Math.PI }; // [0°, 180°]\n *\n * const target = Math.PI * 1.5; // 270 degrees (exceeds max)\n * const constrained = rotateTo(target, camera, {\n * clampRotation: true,\n * restrictRotation: false\n * });\n * // constrained = π (clamped to max boundary of 180 degrees)\n * camera.setRotation(constrained);\n * ```\n *\n * @example\n * ```typescript\n * // Create custom pipeline with snapping\n * const cardinalRotateTo = createHandlerChain<number, [BoardCamera, RotationHandlerConfig]>(\n * restrictRotateToHandler,\n * (angle) => {\n * // Snap to cardinal directions (0°, 90°, 180°, 270°)\n * const cardinals = [0, Math.PI/2, Math.PI, 3*Math.PI/2];\n * return cardinals.reduce((prev, curr) =>\n * Math.abs(curr - angle) < Math.abs(prev - angle) ? curr : prev\n * );\n * },\n * clampRotateToHandler\n * );\n * ```\n *\n * @category Camera Rig\n * @see {@link createHandlerChain} for creating custom handler pipelines\n * @see {@link restrictRotateToHandler} for the restriction step\n * @see {@link clampRotateToHandler} for the clamping step\n */\nexport function createDefaultRotateToHandler(): RotateToHandlerFunction {\n return createHandlerChain<number, [BoardCamera, RotationHandlerConfig]>(\n restrictRotateToHandler,\n clampRotateToHandler,\n );\n}\n",
38
- "import { PointCal } from \"@ue-too/math\";\n\nimport { \n createDefaultPanByHandler, \n createDefaultPanToHandler, \n PanByHandlerFunction, \n PanHandlerConfig, \n PanToHandlerFunction } from \"./pan-handler\";\nimport { \n ZoomHandlerConfig, \n ZoomToHandlerFunction, \n createDefaultZoomToOnlyHandler, \n ZoomByHandlerFunction, \n createDefaultZoomByOnlyHandler, \n} from \"./zoom-handler\";\nimport DefaultBoardCamera from \"../default-camera\";\nimport { createDefaultRotateToHandler, createDefaultRotateByHandler } from \"./rotation-handler\";\nimport type { RotateToHandlerFunction, RotateByHandlerFunction, RotationHandlerConfig } from \"./rotation-handler\";\nimport { ObservableBoardCamera } from \"../interface\";\nimport { Point } from \"@ue-too/math\";\nimport { convertDeltaInViewPortToWorldSpace } from \"../utils\";\nimport type { BaseContext } from \"@ue-too/being\";\n\n/**\n * Configuration for camera rig behavior combining pan, zoom, and rotation settings.\n * Composed from individual handler configs.\n *\n * @remarks\n * This type merges configuration from:\n * - {@link PanHandlerConfig} - Pan clamping and boundaries\n * - {@link ZoomHandlerConfig} - Zoom limits and restrictions\n * - {@link RotationHandlerConfig} - Rotation constraints\n *\n * @category Camera Rig\n * @see {@link PanHandlerConfig}\n * @see {@link ZoomHandlerConfig}\n * @see {@link RotationHandlerConfig}\n */\nexport type CameraRigConfig = PanHandlerConfig & ZoomHandlerConfig & RotationHandlerConfig;\n\n/**\n * High-level camera control interface providing intuitive methods for pan, zoom, and rotation.\n * The camera rig acts as a facade over the camera, handling coordinate conversions and constraints.\n *\n * @remarks\n * CameraRig provides:\n * - **Coordinate-aware methods**: Separate methods for viewport and world coordinates\n * - **Anchor-point zooming**: Keep points stationary during zoom (zoom-to-cursor)\n * - **Configuration management**: Unified config for all camera operations\n * - **Handler composition**: Combines pan, zoom, rotation handlers with proper sequencing\n *\n * The rig ensures correct transformation order when combining operations\n * (e.g., zoom-at-point requires zoom followed by pan compensation).\n *\n * @category Camera Rig\n * @see {@link DefaultCameraRig} for the default implementation\n * @see {@link createDefaultCameraRig} for a factory function\n */\nexport interface CameraRig extends BaseContext {\n /** The underlying observable camera being controlled */\n camera: ObservableBoardCamera;\n\n /** Current configuration for all camera operations */\n config: CameraRigConfig;\n\n /**\n * Updates the camera rig configuration.\n * @param config - Partial configuration to merge with current config\n */\n configure(config: Partial<CameraRigConfig>): void;\n\n /**\n * Updates the camera rig state (called per frame if needed).\n */\n update(): void;\n\n /**\n * Pans the camera by a delta in viewport coordinates.\n * @param delta - Movement delta in viewport space (CSS pixels, origin at center)\n */\n panByViewPort: (delta: Point) => void;\n\n /**\n * Pans the camera to a target position in viewport coordinates.\n * @param target - Target position in viewport space\n */\n panToViewPort: (target: Point) => void;\n\n /**\n * Pans the camera by a delta in world coordinates.\n * @param delta - Movement delta in world space\n */\n panByWorld: (delta: Point) => void;\n\n /**\n * Pans the camera to a target position in world coordinates.\n * @param target - Target position in world space\n */\n panToWorld: (target: Point) => void;\n\n /**\n * Rotates the camera by a delta angle.\n * @param delta - Rotation delta in radians\n */\n rotateBy: (delta: number) => void;\n\n /**\n * Rotates the camera to a target angle.\n * @param target - Target rotation in radians\n */\n rotateTo: (target: number) => void;\n\n /**\n * Zooms to a target level, keeping a viewport point stationary.\n * @param targetZoom - Target zoom level\n * @param at - Anchor point in viewport coordinates\n */\n zoomToAt: (targetZoom: number, at: Point) => void;\n\n /**\n * Zooms by a delta, keeping a viewport point stationary.\n * @param delta - Zoom delta\n * @param at - Anchor point in viewport coordinates\n */\n zoomByAt: (delta: number, at: Point) => void;\n\n /**\n * Zooms to a target level at viewport center.\n * @param targetZoom - Target zoom level\n */\n zoomTo: (targetZoom: number) => void;\n\n /**\n * Zooms by a delta at viewport center.\n * @param delta - Zoom delta\n */\n zoomBy: (delta: number) => void;\n\n /**\n * Zooms to a target level, keeping a world point stationary.\n * @param targetZoom - Target zoom level\n * @param at - Anchor point in world coordinates\n */\n zoomToAtWorld: (targetZoom: number, at: Point) => void;\n\n /**\n * Zooms by a delta, keeping a world point stationary.\n * @param delta - Zoom delta\n * @param at - Anchor point in world coordinates\n */\n zoomByAtWorld: (delta: number, at: Point) => void;\n}\n\n/**\n * Default implementation of the camera rig providing comprehensive camera control.\n * Composes pan, zoom, and rotation handlers into a unified, easy-to-use API.\n *\n * @remarks\n * DefaultCameraRig serves as:\n * - **Context for state machines**: Passed to pan/zoom state machines as execution context\n * - **Handler composition**: Combines individual pan/zoom/rotation handlers\n * - **Coordinate conversion**: Manages conversions between viewport and world space\n * - **Configuration management**: Applies constraints and limits through handlers\n *\n * The rig ensures proper transformation sequencing:\n * 1. For anchor-point zoom: Apply zoom, then compensate camera position to keep anchor stationary\n * 2. For rotation: Transform coordinates based on current camera rotation\n * 3. For pan: Apply clamping and boundary constraints\n *\n * @example\n * ```typescript\n * const camera = new DefaultBoardCamera();\n * const rig = new DefaultCameraRig({\n * limitEntireViewPort: true,\n * clampTranslation: true,\n * clampZoom: true,\n * restrictZoom: false\n * }, camera);\n *\n * // Pan in viewport coordinates\n * rig.panByViewPort({ x: 50, y: -30 });\n *\n * // Zoom at cursor position\n * rig.zoomByAt(0.1, mousePosition);\n *\n * // Rotate camera\n * rig.rotateBy(Math.PI / 4);\n * ```\n *\n * @category Camera Rig\n * @see {@link CameraRig} for the interface definition\n * @see {@link createDefaultCameraRig} for a convenient factory function\n */\nexport class DefaultCameraRig implements CameraRig {\n\n private _panBy: PanByHandlerFunction;\n private _panTo: PanToHandlerFunction;\n private _zoomTo: ZoomToHandlerFunction;\n private _zoomBy: ZoomByHandlerFunction;\n private _rotateBy: RotateByHandlerFunction;\n private _rotateTo: RotateToHandlerFunction;\n private _config: CameraRigConfig;\n private _camera: ObservableBoardCamera;\n\n /**\n * Creates a new DefaultCameraRig with specified configuration and camera.\n *\n * @param config - Camera rig configuration for pan and zoom constraints\n * @param camera - Observable camera instance to control (defaults to new DefaultBoardCamera)\n *\n * @remarks\n * The constructor initializes:\n * - Default pan, zoom, and rotation handler functions\n * - Rotation config with `restrictRotation: false` and `clampRotation: true`\n * - Handler functions that will be used to process and constrain all camera operations\n *\n * @example\n * ```typescript\n * const rig = new DefaultCameraRig({\n * limitEntireViewPort: true,\n * clampTranslation: true,\n * clampZoom: true,\n * restrictZoom: false,\n * restrictXTranslation: false,\n * restrictYTranslation: false\n * });\n * ```\n */\n constructor(config: PanHandlerConfig & ZoomHandlerConfig, camera: ObservableBoardCamera = new DefaultBoardCamera()){\n this._panBy = createDefaultPanByHandler();\n this._panTo = createDefaultPanToHandler();\n this._zoomTo = createDefaultZoomToOnlyHandler();\n this._zoomBy = createDefaultZoomByOnlyHandler();\n this._rotateBy = createDefaultRotateByHandler();\n this._rotateTo = createDefaultRotateToHandler();\n this._config = {...config, restrictRotation: false, clampRotation: true};\n this._camera = camera;\n }\n\n /**\n * Zooms to a target level while keeping a viewport point stationary (zoom-to-cursor).\n *\n * @param targetZoom - Target zoom level to reach\n * @param at - Anchor point in viewport coordinates (center-anchored, CSS pixels)\n *\n * @remarks\n * This implements the \"zoom to cursor\" behavior commonly seen in map applications.\n * The algorithm:\n * 1. Converts anchor point from viewport to world space (before zoom)\n * 2. Applies zoom transformation (may be clamped by config)\n * 3. Converts anchor point from viewport to world space (after zoom)\n * 4. Calculates position difference and pans camera to compensate\n *\n * The anchor point remains stationary on screen, while the world zooms around it.\n *\n * @example\n * ```typescript\n * // Zoom to 2x at mouse cursor position\n * rig.zoomToAt(2.0, { x: mouseX, y: mouseY });\n *\n * // The world point under the cursor stays in place\n * ```\n */\n zoomToAt(targetZoom: number, at: Point): void {\n let originalAnchorInWorld = this._camera.convertFromViewPort2WorldSpace(at);\n const transformTarget = this._zoomTo(targetZoom, this._camera, this._config);\n this._camera.setZoomLevel(transformTarget);\n let anchorInWorldAfterZoom = this._camera.convertFromViewPort2WorldSpace(at);\n const cameraPositionDiff = PointCal.subVector(originalAnchorInWorld, anchorInWorldAfterZoom);\n const transformedCameraPositionDiff = this._panBy(cameraPositionDiff, this._camera, this._config);\n this._camera.setPosition(PointCal.addVector(this._camera.position, transformedCameraPositionDiff));\n }\n\n /**\n * Zooms by a relative delta while keeping a viewport point stationary.\n *\n * @param delta - Relative zoom delta (multiplied by current zoom level)\n * @param at - Anchor point in viewport coordinates (center-anchored, CSS pixels)\n *\n * @remarks\n * This method is ideal for mouse wheel zoom interactions where the delta\n * represents a relative change rather than an absolute target.\n *\n * The delta is scaled by current zoom level: `actualDelta = delta * currentZoom`\n * This provides consistent zoom \"speed\" regardless of current zoom level.\n *\n * Like {@link zoomToAt}, this keeps the anchor point stationary during zoom.\n *\n * @example\n * ```typescript\n * // Zoom in by 10% at cursor position (mouse wheel up)\n * rig.zoomByAt(0.1, cursorPosition);\n *\n * // Zoom out by 10% at cursor position (mouse wheel down)\n * rig.zoomByAt(-0.1, cursorPosition);\n * ```\n *\n * @see {@link zoomToAt} for zooming to an absolute level\n */\n zoomByAt(delta: number, at: Point): void {\n const convertedDelta = delta * this._camera.zoomLevel;\n let originalAnchorInWorld = this._camera.convertFromViewPort2WorldSpace(at);\n const transformedDelta = this._zoomBy(convertedDelta, this._camera, this._config);\n this._camera.setZoomLevel(this._camera.zoomLevel + transformedDelta);\n let anchorInWorldAfterZoom = this._camera.convertFromViewPort2WorldSpace(at);\n const diff = PointCal.subVector(originalAnchorInWorld, anchorInWorldAfterZoom);\n const transformedDiff = this._panBy(diff, this._camera, this._config);\n this._camera.setPosition(PointCal.addVector(this._camera.position, transformedDiff));\n }\n\n /**\n * Zooms to a target level with the viewport center as the anchor point.\n *\n * @param targetZoom - Target zoom level to reach\n *\n * @remarks\n * This is a simpler version of {@link zoomToAt} that always zooms relative to the\n * viewport center. The camera position remains unchanged, so the center point of\n * the viewport stays fixed in world space.\n *\n * Use this when you want straightforward zoom without anchor-point tracking,\n * such as zoom controls in a UI toolbar.\n *\n * @example\n * ```typescript\n * // Zoom to 2x, centered on current view\n * rig.zoomTo(2.0);\n *\n * // Zoom to fit (100%)\n * rig.zoomTo(1.0);\n * ```\n *\n * @see {@link zoomToAt} for zoom with custom anchor point\n */\n zoomTo(targetZoom: number): void {\n const transformedTarget = this._zoomTo(targetZoom, this._camera, this._config);\n this._camera.setZoomLevel(transformedTarget);\n }\n\n /**\n * Zooms by a relative delta with the viewport center as the anchor point.\n *\n * @param delta - Zoom delta (added to current zoom level)\n *\n * @remarks\n * Unlike {@link zoomByAt}, the delta is NOT scaled by current zoom level.\n * This provides absolute delta changes, useful for programmatic zoom adjustments.\n *\n * The camera position remains unchanged, keeping the viewport center fixed in world space.\n *\n * @example\n * ```typescript\n * // Increase zoom by 0.5\n * rig.zoomBy(0.5);\n *\n * // Decrease zoom by 0.2\n * rig.zoomBy(-0.2);\n * ```\n *\n * @see {@link zoomByAt} for zoom with custom anchor point and scaling\n */\n zoomBy(delta: number): void {\n const transformedDelta = this._zoomBy(delta, this._camera, this._config);\n this._camera.setZoomLevel(this._camera.zoomLevel + transformedDelta);\n }\n\n /**\n * Zooms to a target level while keeping a world-space point stationary.\n *\n * @param targetZoom - Target zoom level to reach\n * @param at - Anchor point in world coordinates\n *\n * @remarks\n * Similar to {@link zoomToAt}, but accepts world-space coordinates instead of viewport coordinates.\n * Useful when you want to zoom to keep a specific world object or location centered,\n * rather than a screen position.\n *\n * The algorithm:\n * 1. Converts world anchor to viewport space (before zoom)\n * 2. Applies zoom transformation\n * 3. Converts world anchor to viewport space (after zoom)\n * 4. Calculates viewport movement and converts to world space\n * 5. Pans camera to compensate\n *\n * @example\n * ```typescript\n * // Zoom to 3x while keeping a specific world object in place\n * const objectWorldPos = { x: 1000, y: 500 };\n * rig.zoomToAtWorld(3.0, objectWorldPos);\n * ```\n *\n * @see {@link zoomToAt} for viewport-space variant\n */\n zoomToAtWorld(targetZoom: number, at: Point): void {\n let originalAnchorInViewPort = this._camera.convertFromWorld2ViewPort(at);\n const transformedTarget = this._zoomTo(targetZoom, this._camera, this._config);\n this._camera.setZoomLevel(transformedTarget);\n let anchorInViewPortAfterZoom = this._camera.convertFromWorld2ViewPort(at);\n const cameraPositionDiffInViewPort = PointCal.subVector(anchorInViewPortAfterZoom, originalAnchorInViewPort);\n const cameraPositionDiffInWorld = convertDeltaInViewPortToWorldSpace(cameraPositionDiffInViewPort, this._camera.zoomLevel, this._camera.rotation);\n const transformedCameraPositionDiff = this._panBy(cameraPositionDiffInWorld, this._camera, this._config);\n this._camera.setPosition(PointCal.addVector(this._camera.position, transformedCameraPositionDiff));\n }\n\n /**\n * Zooms by a delta while keeping a world-space point stationary.\n *\n * @param delta - Zoom delta (added to current zoom level, not scaled)\n * @param at - Anchor point in world coordinates\n *\n * @remarks\n * World-space variant of {@link zoomByAt}. The delta is NOT scaled by current zoom level,\n * unlike the viewport-space version.\n *\n * Use this when programmatically zooming around specific world objects or coordinates.\n *\n * @example\n * ```typescript\n * // Zoom in by 0.5 while keeping a world landmark stationary\n * const landmarkPos = { x: 2000, y: 1500 };\n * rig.zoomByAtWorld(0.5, landmarkPos);\n * ```\n *\n * @see {@link zoomByAt} for viewport-space variant with scaled delta\n */\n zoomByAtWorld(delta: number, at: Point): void {\n let anchorInViewPortBeforeZoom = this._camera.convertFromWorld2ViewPort(at);\n const transformedDelta = this._zoomBy(delta, this._camera, this._config);\n this._camera.setZoomLevel(this._camera.zoomLevel + transformedDelta);\n let anchorInViewPortAfterZoom = this._camera.convertFromWorld2ViewPort(at);\n const diffInViewPort = PointCal.subVector(anchorInViewPortAfterZoom, anchorInViewPortBeforeZoom);\n const diffInWorld = convertDeltaInViewPortToWorldSpace(diffInViewPort, this._camera.zoomLevel, this._camera.rotation);\n const transformedDiff = this._panBy(diffInWorld, this._camera, this._config);\n this._camera.setPosition(PointCal.addVector(this._camera.position, transformedDiff));\n }\n\n /**\n * Pans the camera by a delta in viewport coordinates.\n *\n * @param delta - Movement delta in viewport space (center-anchored, CSS pixels)\n *\n * @remarks\n * This is the most common pan method for user input (mouse drag, touch pan).\n * The delta is in screen/viewport coordinates and gets converted to world space\n * accounting for current camera rotation and zoom.\n *\n * Conversion formula:\n * 1. Rotate delta by camera rotation\n * 2. Scale by inverse zoom (1 / zoomLevel)\n * 3. Apply as world-space pan\n *\n * @example\n * ```typescript\n * // Pan camera when user drags mouse\n * canvas.addEventListener('mousemove', (e) => {\n * if (isDragging) {\n * const delta = { x: e.movementX, y: e.movementY };\n * rig.panByViewPort(delta);\n * }\n * });\n * ```\n *\n * @see {@link panByWorld} for world-space panning\n */\n panByViewPort(delta: Point): void {\n const diffInWorld = PointCal.multiplyVectorByScalar(PointCal.rotatePoint(delta, this._camera.rotation), 1 / this._camera.zoomLevel);\n this.panByWorld(diffInWorld);\n }\n\n /**\n * Pans the camera by a delta in world coordinates.\n *\n * @param delta - Movement delta in world space\n *\n * @remarks\n * Use this for programmatic camera movement or when you already have world-space\n * coordinates (e.g., moving camera to follow a world object).\n *\n * The delta is passed through the pan handler which may apply:\n * - Boundary clamping\n * - Movement restrictions (restrictXTranslation, restrictYTranslation)\n * - Other constraints from {@link CameraRigConfig}\n *\n * @example\n * ```typescript\n * // Move camera 100 units right, 50 units up in world space\n * rig.panByWorld({ x: 100, y: -50 });\n *\n * // Follow a moving object\n * const objectMovement = { x: obj.dx, y: obj.dy };\n * rig.panByWorld(objectMovement);\n * ```\n *\n * @see {@link panByViewPort} for viewport-space panning\n */\n panByWorld(delta: Point): void {\n const transformedDelta = this._panBy(delta, this._camera, this._config);\n this._camera.setPosition(PointCal.addVector(this._camera.position, transformedDelta));\n }\n\n /**\n * Pans the camera to an absolute position in world coordinates.\n *\n * @param target - Target camera position in world space\n *\n * @remarks\n * Sets the camera position directly (subject to constraints).\n * Unlike pan-by methods, this is an absolute positioning operation.\n *\n * The target is passed through the pan handler which may apply:\n * - Boundary clamping\n * - Position restrictions\n *\n * Use this for:\n * - \"Go to location\" features\n * - Centering camera on specific world coordinates\n * - Resetting camera to a known position\n *\n * @example\n * ```typescript\n * // Center camera on world origin\n * rig.panToWorld({ x: 0, y: 0 });\n *\n * // Go to specific landmark\n * const landmark = { x: 1000, y: 500 };\n * rig.panToWorld(landmark);\n * ```\n *\n * @see {@link panToViewPort} for viewport-space variant\n */\n panToWorld(target: Point): void {\n const transformedTarget = this._panTo(target, this._camera, this._config);\n this._camera.setPosition(transformedTarget);\n }\n\n /**\n * Pans the camera to position a viewport point at a specific location.\n *\n * @param target - Target position in viewport coordinates (center-anchored, CSS pixels)\n *\n * @remarks\n * Moves the camera so that the specified viewport point ends up at the viewport center.\n * This is less commonly used than world-space pan-to operations.\n *\n * The method converts the viewport target to world space, then uses {@link panToWorld}.\n *\n * @example\n * ```typescript\n * // Center the camera on what's currently at the top-left of viewport\n * rig.panToViewPort({ x: -400, y: -300 });\n * ```\n *\n * @see {@link panToWorld} for world-space variant (more commonly used)\n */\n panToViewPort(target: Point): void {\n const targetInWorld = this._camera.convertFromViewPort2WorldSpace(target);\n this.panToWorld(targetInWorld);\n }\n\n /**\n * Rotates the camera by a delta angle.\n *\n * @param delta - Rotation delta in radians (positive = counter-clockwise)\n *\n * @remarks\n * Applies a relative rotation to the camera. The delta is passed through the\n * rotation handler which may apply clamping or restrictions based on {@link CameraRigConfig}.\n *\n * Camera rotation affects:\n * - How viewport coordinates map to world coordinates\n * - The orientation of pan operations\n * - Visual rendering of the world\n *\n * @example\n * ```typescript\n * // Rotate 45 degrees counter-clockwise\n * rig.rotateBy(Math.PI / 4);\n *\n * // Rotate 90 degrees clockwise\n * rig.rotateBy(-Math.PI / 2);\n * ```\n *\n * @see {@link rotateTo} for absolute rotation\n */\n rotateBy(delta: number): void {\n const transformedDelta = this._rotateBy(delta, this._camera, this._config);\n this._camera.setRotation(this._camera.rotation + transformedDelta);\n }\n\n /**\n * Rotates the camera to an absolute angle.\n *\n * @param target - Target rotation in radians (0 = no rotation, positive = counter-clockwise)\n *\n * @remarks\n * Sets the camera rotation to a specific angle (subject to constraints).\n * The target is passed through the rotation handler which may apply clamping.\n *\n * Use this for:\n * - Resetting camera to north-up orientation (0 radians)\n * - Snapping to cardinal directions\n * - Setting rotation from UI controls\n *\n * @example\n * ```typescript\n * // Reset to north-up\n * rig.rotateTo(0);\n *\n * // Rotate to 90 degrees\n * rig.rotateTo(Math.PI / 2);\n * ```\n *\n * @see {@link rotateBy} for relative rotation\n */\n rotateTo(target: number): void {\n const transformedTarget = this._rotateTo(target, this._camera, this._config);\n this._camera.setRotation(transformedTarget);\n }\n\n /**\n * Sets whether the entire viewport must remain within boundaries.\n *\n * @remarks\n * When true, pan boundaries ensure the entire viewport stays within configured limits.\n * When false, only the camera center point is constrained.\n *\n * This is a convenience setter for {@link CameraRigConfig}.limitEntireViewPort.\n */\n set limitEntireViewPort(limit: boolean){\n this._config.limitEntireViewPort = limit;\n }\n\n /**\n * Gets whether the entire viewport must remain within boundaries.\n *\n * @returns True if entire viewport is constrained, false if only center is constrained\n */\n get limitEntireViewPort(): boolean {\n return this._config.limitEntireViewPort;\n }\n\n /**\n * Gets the underlying observable camera instance.\n *\n * @returns The camera being controlled by this rig\n */\n get camera(): ObservableBoardCamera {\n return this._camera;\n }\n\n /**\n * Sets the underlying camera instance.\n *\n * @param camera - New camera to control\n *\n * @remarks\n * Use this to swap cameras at runtime, though this is uncommon.\n * Usually you create a new rig instead.\n */\n set camera(camera: ObservableBoardCamera){\n this._camera = camera;\n }\n\n /**\n * Gets the current camera rig configuration.\n *\n * @returns Current configuration object\n *\n * @remarks\n * Returns a reference to the internal config. Modifications will affect rig behavior.\n * For safer updates, use {@link configure} instead.\n */\n get config(): CameraRigConfig {\n return this._config;\n }\n\n /**\n * Sets the camera rig configuration.\n *\n * @param config - New configuration object\n *\n * @remarks\n * Creates a shallow copy of the provided config.\n * For partial updates, use {@link configure} instead.\n */\n set config(config: CameraRigConfig){\n this._config = {...config};\n }\n\n /**\n * Updates camera rig configuration with partial settings.\n *\n * @param config - Partial configuration to merge with current config\n *\n * @remarks\n * This is the recommended way to update configuration at runtime.\n * Only provided properties are updated; others remain unchanged.\n *\n * @example\n * ```typescript\n * // Enable zoom restrictions without changing other settings\n * rig.configure({\n * restrictZoom: true,\n * zoomLevelLimits: { min: 0.5, max: 5.0 }\n * });\n *\n * // Disable position clamping\n * rig.configure({ clampTranslation: false });\n * ```\n */\n configure(config: Partial<CameraRigConfig>){\n this._config = {...this._config, ...config};\n }\n\n /**\n * Cleans up resources used by the camera rig.\n *\n * @remarks\n * Currently a no-op as DefaultCameraRig has no resources to clean up.\n * Implements {@link BaseContext} interface for consistency with other systems.\n */\n cleanup(): void {\n }\n\n /**\n * Sets up the camera rig.\n *\n * @remarks\n * Currently a no-op as DefaultCameraRig requires no setup.\n * Implements {@link BaseContext} interface for consistency with other systems.\n */\n setup(): void {\n }\n\n /**\n * Updates the camera rig state.\n *\n * @remarks\n * Currently a no-op as DefaultCameraRig has no per-frame update logic.\n * Implements {@link BaseContext} interface for consistency with other systems.\n *\n * In stateful rig implementations, this might handle:\n * - Animation interpolation\n * - Momentum/inertia\n * - Smooth camera following\n */\n update(): void {\n }\n}\n\n/**\n * Creates a camera rig with sensible default configuration.\n *\n * @param camera - Observable camera instance to control\n * @returns Configured camera rig ready for use\n *\n * @remarks\n * This factory function creates a {@link DefaultCameraRig} with a balanced default configuration:\n *\n * **Enabled by default:**\n * - `limitEntireViewPort: true` - Entire viewport stays within boundaries\n * - `clampTranslation: true` - Position is clamped to boundaries\n * - `clampZoom: true` - Zoom is clamped to limits\n *\n * **Disabled by default:**\n * - All movement restrictions (`restrictXTranslation`, `restrictYTranslation`, etc.)\n * - Zoom restrictions (`restrictZoom`)\n * - Relative translation restrictions\n *\n * This configuration allows free camera movement with boundary enforcement,\n * suitable for most infinite canvas applications.\n *\n * @example\n * ```typescript\n * const camera = new DefaultBoardCamera(1920, 1080);\n * const rig = createDefaultCameraRig(camera);\n *\n * // Ready to use with sensible defaults\n * rig.configure({\n * boundaries: {\n * min: { x: -1000, y: -1000 },\n * max: { x: 1000, y: 1000 }\n * }\n * });\n *\n * rig.panByViewPort({ x: 100, y: 50 });\n * rig.zoomByAt(0.1, mousePosition);\n * ```\n *\n * @category Camera Rig\n * @see {@link DefaultCameraRig} for the implementation\n * @see {@link CameraRigConfig} for all available configuration options\n */\nexport function createDefaultCameraRig(camera: ObservableBoardCamera): CameraRig{\n return new DefaultCameraRig({\n limitEntireViewPort: true,\n restrictRelativeXTranslation: false,\n restrictRelativeYTranslation: false,\n restrictXTranslation: false,\n restrictYTranslation: false,\n restrictZoom: false,\n clampTranslation: true,\n clampZoom: true,\n }, camera);\n}\n",
39
- "import { Point } from \"@ue-too/math\";\nimport { BaseContext, NO_OP } from \"@ue-too/being\";\nimport { CanvasPositionDimensionPublisher, getTrueRect, Observable, Observer, SubscriptionOptions, SvgPositionDimensionPublisher, SynchronousObservable } from \"../../utils\";\n\n/**\n * Cursor styles used to provide visual feedback for different input states.\n *\n * @remarks\n * These cursor styles indicate the current interaction mode to users:\n * - **GRAB**: Indicates the canvas is ready to be panned (spacebar pressed, no drag yet)\n * - **GRABBING**: Indicates active panning is in progress\n * - **DEFAULT**: Normal cursor state when no special interaction is active\n *\n * @category Input State Machine\n */\nexport enum CursorStyle {\n GRAB = \"grab\",\n DEFAULT = \"default\",\n GRABBING = \"grabbing\"\n}\n\n/**\n * Canvas dimension and position information.\n *\n * @property width - The canvas width in CSS pixels\n * @property height - The canvas height in CSS pixels\n * @property position - The top-left position of the canvas in window coordinates\n *\n * @category Input State Machine\n */\nexport type CanvasDimensions = {width: number, height: number, position: Point};\n\n/**\n * Abstraction interface for canvas element access and manipulation.\n *\n * @remarks\n * This interface provides a decoupled way to access canvas properties without direct DOM access.\n * Multiple implementations exist to support different use cases:\n * - **CanvasProxy**: Full implementation for HTML canvas elements with dimension tracking\n * - **SvgProxy**: Implementation for SVG elements\n * - **DummyCanvas**: No-op implementation for web worker contexts\n * - **WorkerRelayCanvas**: Relays canvas dimension updates to web workers\n * - **CanvasCacheInWebWorker**: Caches canvas dimensions within a web worker\n *\n * The abstraction enables:\n * - Coordinate system transformations (window → canvas → viewport)\n * - Canvas dimension tracking without repeated DOM queries\n * - Cursor style management\n * - Support for both canvas and SVG rendering contexts\n *\n * @category Input State Machine\n */\nexport interface Canvas {\n /** The canvas width in CSS pixels */\n width: number;\n /** The canvas height in CSS pixels */\n height: number;\n /** The top-left position of the canvas in window coordinates */\n position: Point;\n /** Sets the CSS cursor style for visual feedback */\n setCursor: (style: CursorStyle) => void;\n /** Combined dimensions and position information */\n dimensions: CanvasDimensions;\n /** Whether the canvas is currently detached from the DOM */\n detached: boolean;\n /** Cleanup method to dispose of resources and event listeners */\n tearDown: () => void;\n}\n\n/**\n * No-op implementation of Canvas interface for web worker relay contexts.\n *\n * @remarks\n * This class is used when an input state machine is configured to relay events to a web worker\n * rather than perform actual canvas operations. The state machine requires a Canvas in its context,\n * but in the relay scenario, no actual canvas operations are needed - events are simply forwarded\n * to the worker thread.\n *\n * All properties return default/empty values and all methods are no-ops.\n *\n * @category Input State Machine\n *\n * @see {@link DummyKmtInputContext}\n */\nexport class DummyCanvas implements Canvas {\n width: number = 0;\n height: number = 0;\n position: Point = {x: 0, y: 0};\n setCursor: (style: CursorStyle) => void = NO_OP;\n dimensions: {width: number, height: number, position: Point} = {width: 0, height: 0, position: {x: 0, y: 0}};\n detached: boolean = false;\n tearDown: () => void = NO_OP;\n}\n\nexport class CanvasCacheInWebWorker implements Canvas {\n\n private _width: number;\n private _height: number;\n private _position: Point;\n private _postMessageFunction: typeof postMessage;\n\n constructor(postMessageFunction: typeof postMessage){\n this._width = 0;\n this._height = 0;\n this._position = {x: 0, y: 0};\n this._postMessageFunction = postMessageFunction;\n }\n\n get dimensions(): {width: number, height: number, position: Point} {\n return {width: this._width, height: this._height, position: this._position};\n }\n\n tearDown(): void {\n }\n\n set width(width: number){\n this._width = width;\n }\n\n set height(height: number){\n this._height = height;\n }\n\n set position(position: Point){\n this._position = position;\n }\n\n get width(): number {\n return this._width;\n }\n\n get height(): number {\n return this._height;\n }\n\n get position(): Point {\n return this._position;\n }\n\n setCursor(style: \"grab\" | \"default\" | \"grabbing\"): void {\n this._postMessageFunction({type: \"setCursor\", style});\n }\n\n get detached(): boolean {\n return false;\n }\n}\n\n/**\n * A proxy for the canvas element to prevent constant invoking of the getBoundingClientRect method.\n * @remarks This is mainly used as a proxy to the canvas to prevent invoking the getBoundingClientRect method on the canvas every time a pointer event is triggered or a coordinate conversion is needed. Also to autoscale the canvas buffer depending on the device pixel ratio. It's important to note that in normal circumstances, you would not need to set the size of the canvas manually; you should use the css style width and height to set the size of the canvas.\n * @category Input State Machine\n * @see {@link Canvas} for the interface that this class implements\n * @see {@link Observable} for the observable that this class emits\n * @see {@link Observer} for the observer that can subscribe to the observable\n * @see {@link SubscriptionOptions} for the options that can be passed to the subscribe method\n * @see {@link SynchronousObservable} for the synchronous observable that this class emits\n * @see {@link CanvasPositionDimensionPublisher} for the publisher that is used to publish the canvas dimensions\n */\nexport class CanvasProxy implements Canvas, Observable<[CanvasDimensions]> {\n\n private _width: number = 0;\n private _height: number = 0;\n private _position: Point = {x: 0, y: 0};\n private _canvasPositionDimensionPublisher: CanvasPositionDimensionPublisher;\n private _canvas: HTMLCanvasElement | undefined;\n private _internalSizeUpdateObservable: Observable<[CanvasDimensions]>;\n\n constructor(canvas?: HTMLCanvasElement) {\n this._internalSizeUpdateObservable = new SynchronousObservable<[CanvasDimensions]>();\n\n if(canvas){\n const boundingRect = canvas.getBoundingClientRect();\n const trueRect = getTrueRect(boundingRect, window.getComputedStyle(canvas));\n this._width = trueRect.width;\n this._height = trueRect.height;\n this._position = {x: trueRect.left, y: trueRect.top};\n this._canvas = canvas;\n }\n\n this._canvasPositionDimensionPublisher = new CanvasPositionDimensionPublisher(canvas);\n this._canvasPositionDimensionPublisher.onPositionUpdate((rect)=>{\n // the rect is the canvas dimension in the DOM (the width and height attribute would need to multiply by the device pixel ratio)\n if(this._canvas == undefined){\n console.error('is not attached to any canvas should not have getting any updates');\n return;\n }\n\n this._width = rect.width;\n this._height = rect.height;\n this._position = {x: rect.left, y: rect.top};\n\n this._internalSizeUpdateObservable.notify({\n width: this._width,\n height: this._height,\n position: this._position\n });\n });\n }\n\n subscribe(observer: Observer<[CanvasDimensions]>, options?: SubscriptionOptions): () => void {\n return this._internalSizeUpdateObservable.subscribe(observer, options);\n }\n\n notify(...data: [CanvasDimensions]): void {\n this._internalSizeUpdateObservable.notify(...data);\n }\n\n get detached(): boolean {\n return this._canvas === undefined;\n }\n\n get dimensions(): {width: number, height: number, position: Point} {\n return {width: this._width, height: this._height, position: this._position};\n }\n\n get width(): number {\n return this._width;\n }\n\n /**\n * set the width of the canvas\n * the width is synonymous with the canvas style width not the canvas width\n */\n setWidth(width: number){\n if(this._canvas){\n this._canvas.width = width * window.devicePixelRatio;\n this._canvas.style.width = width + \"px\";\n }\n }\n\n setCanvasWidth(width: number){\n if(this._canvas){\n this._canvas.width = width * window.devicePixelRatio;\n }\n }\n\n /**\n * set the height of the canvas\n * the height is synonymous with the canvas style height not the canvas height\n */\n setHeight(height: number){\n if(this._canvas){\n this._canvas.height = height * window.devicePixelRatio;\n this._canvas.style.height = height + \"px\";\n }\n }\n\n setCanvasHeight(height: number){\n if(this._canvas){\n this._canvas.height = height * window.devicePixelRatio;\n }\n }\n\n get height(): number {\n return this._height;\n }\n\n get position(): Point {\n return this._position;\n }\n\n setCursor(style: \"grab\" | \"default\" | \"grabbing\"): void {\n if(this._canvas){\n this._canvas.style.cursor = style;\n }\n }\n\n tearDown(): void {\n this._canvasPositionDimensionPublisher.dispose();\n this._canvas = undefined;\n this._width = 0;\n this._height = 0;\n this._position = {x: 0, y: 0};\n }\n\n attach(canvas: HTMLCanvasElement){\n this._canvasPositionDimensionPublisher.attach(canvas);\n this._canvas = canvas;\n const boundingRect = canvas.getBoundingClientRect();\n const trueRect = getTrueRect(boundingRect, window.getComputedStyle(canvas));\n this._canvas.width = trueRect.width * window.devicePixelRatio;\n this._canvas.height = trueRect.height * window.devicePixelRatio;\n const aspectRatio = trueRect.width / trueRect.height;\n this._canvas.style.aspectRatio = aspectRatio.toString();\n this._width = trueRect.width;\n this._height = trueRect.height;\n this._position = {x: trueRect.left, y: trueRect.top};\n this._internalSizeUpdateObservable.notify({\n width: this._width,\n height: this._height,\n position: this._position\n });\n }\n\n logCanvasTrueSize(){\n if(this._canvas === undefined){\n return;\n }\n console.log('canvas true size');\n console.log('style width', this._canvas.style.width);\n console.log('style height', this._canvas.style.height);\n console.log('width', this._canvas.width);\n console.log('height', this._canvas.height);\n console.log('proxy width', this._width);\n console.log('proxy height', this._height);\n }\n\n}\n\nexport class SvgProxy implements Canvas, Observable<[CanvasDimensions]> {\n\n private _width: number = 0;\n private _height: number = 0;\n private _position: Point = {x: 0, y: 0};\n private _svgPositionDimensionPublisher: SvgPositionDimensionPublisher;\n private _svg: SVGSVGElement | undefined;\n private _internalSizeUpdateObservable: Observable<[CanvasDimensions]>;\n\n constructor(svg?: SVGSVGElement) {\n this._internalSizeUpdateObservable = new SynchronousObservable<[CanvasDimensions]>();\n\n if(svg){\n const boundingRect = svg.getBoundingClientRect();\n const trueRect = getTrueRect(boundingRect, window.getComputedStyle(svg));\n this._width = trueRect.width;\n this._height = trueRect.height;\n this._position = {x: trueRect.left, y: trueRect.top};\n this._svg = svg;\n }\n\n this._svgPositionDimensionPublisher = new SvgPositionDimensionPublisher(svg);\n this._svgPositionDimensionPublisher.onPositionUpdate((rect)=>{\n // the rect is the canvas dimension in the DOM (the width and height attribute would need to multiply by the device pixel ratio)\n if(this._svg == undefined){\n console.error('is not attached to any canvas should not have getting any updates');\n return;\n }\n\n this._width = rect.width;\n this._height = rect.height;\n this._position = {x: rect.left, y: rect.top};\n\n this._internalSizeUpdateObservable.notify({\n width: this._width,\n height: this._height,\n position: this._position\n });\n });\n }\n\n subscribe(observer: Observer<[CanvasDimensions]>, options?: SubscriptionOptions): () => void {\n return this._internalSizeUpdateObservable.subscribe(observer, options);\n }\n\n notify(...data: [CanvasDimensions]): void {\n this._internalSizeUpdateObservable.notify(...data);\n }\n\n get detached(): boolean {\n return this._svg === undefined;\n }\n\n get dimensions(): {width: number, height: number, position: Point} {\n return {width: this._width, height: this._height, position: this._position};\n }\n\n get width(): number {\n return this._width;\n }\n\n /**\n * set the width of the canvas\n * the width is synonymous with the canvas style width not the canvas width\n */\n setWidth(width: number){\n if(this._svg){\n this._svg.style.width = width + \"px\";\n }\n }\n\n /**\n * set the height of the canvas\n * the height is synonymous with the canvas style height not the canvas height\n */\n setHeight(height: number){\n if(this._svg){\n this._svg.style.height = height + \"px\";\n }\n }\n\n get height(): number {\n return this._height;\n }\n\n get position(): Point {\n return this._position;\n }\n\n setCursor(style: \"grab\" | \"default\" | \"grabbing\"): void {\n if(this._svg){\n this._svg.style.cursor = style;\n }\n }\n\n tearDown(): void {\n this._svgPositionDimensionPublisher.dispose();\n this._svg = undefined;\n this._width = 0;\n this._height = 0;\n this._position = {x: 0, y: 0};\n }\n\n attach(svg: SVGSVGElement){\n this._svgPositionDimensionPublisher.attach(svg);\n this._svg = svg;\n const boundingRect = svg.getBoundingClientRect();\n const trueRect = getTrueRect(boundingRect, window.getComputedStyle(svg));\n this._svg.style.width = trueRect.width + \"px\";\n this._svg.style.height = trueRect.height + \"px\";\n this._width = trueRect.width;\n this._height = trueRect.height;\n this._position = {x: trueRect.left, y: trueRect.top};\n this._internalSizeUpdateObservable.notify({\n width: this._width,\n height: this._height,\n position: this._position\n });\n }\n\n logCanvasTrueSize(){\n if(this._svg === undefined){\n return;\n }\n console.log('canvas true size');\n console.log('style width', this._svg.style.width);\n console.log('style height', this._svg.style.height);\n console.log('width', this._svg.width);\n console.log('height', this._svg.height);\n console.log('proxy width', this._width);\n console.log('proxy height', this._height);\n }\n\n}\n\n/**\n * @description A proxy for the canvas that is used to communicate with the web worker.\n * The primary purpose of this class is to cache the canvas dimensions and position in the DOM to reduce the calling of the getBoundingClientRect method.\n * This class only serves as a relay of the updated canvas dimensions and position to the web worker.\n * \n */\nexport class WorkerRelayCanvas implements Canvas {\n\n private _width: number;\n private _height: number;\n private _position: Point;\n private _webWorker: Worker;\n private _canvas: HTMLCanvasElement;\n private _canvasDiemsionPublisher: CanvasPositionDimensionPublisher;\n\n constructor(canvas: HTMLCanvasElement, webWorker: Worker, canvasDiemsionPublisher: CanvasPositionDimensionPublisher){\n const boundingRect = canvas.getBoundingClientRect();\n this._canvas = canvas;\n this._webWorker = webWorker;\n const trueRect = getTrueRect(boundingRect, window.getComputedStyle(canvas));\n this._width = trueRect.width;\n this._height = trueRect.height;\n this._position = {x: trueRect.left, y: trueRect.top};\n this._webWorker.postMessage({type: \"setCanvasDimensions\", width: boundingRect.width, height: boundingRect.height, position: {x: boundingRect.left, y: boundingRect.top}});\n canvasDiemsionPublisher.onPositionUpdate((rect)=>{\n this._width = rect.width;\n this._height = rect.height;\n this._position = {x: rect.left, y: rect.top};\n this._webWorker.postMessage({type: \"updateCanvasDimensions\", width: rect.width, height: rect.height, position: {x: rect.left, y: rect.top}});\n });\n this._canvasDiemsionPublisher = canvasDiemsionPublisher;\n }\n\n get width(): number {\n return this._width;\n }\n\n get height(): number {\n return this._height;\n }\n\n tearDown(): void {\n this._canvasDiemsionPublisher.dispose();\n }\n\n get position(): Point {\n return this._position;\n }\n\n get dimensions(): {width: number, height: number, position: Point} {\n return {width: this._width, height: this._height, position: this._position};\n }\n\n get detached(): boolean {\n return false;\n }\n\n setCursor(style: \"grab\" | \"default\" | \"grabbing\"): void {\n this._canvas.style.cursor = style;\n }\n}\n\n/**\n * Context interface for the Keyboard/Mouse/Trackpad (KMT) input state machine.\n *\n * @remarks\n * This context provides the state and behavior needed by the KMT state machine to:\n * 1. Track cursor positions for calculating pan deltas\n * 2. Distinguish between mouse and trackpad input modalities\n * 3. Access canvas dimensions for coordinate transformations\n * 4. Manage coordinate system alignment (inverted Y-axis handling)\n *\n * **Input Modality Detection**:\n * The context uses a scoring system (`kmtTrackpadTrackScore`) to differentiate between\n * mouse and trackpad input, which have different zoom behaviors:\n * - Mouse: Ctrl+Scroll = zoom, Scroll = pan\n * - Trackpad: Scroll = zoom (no Ctrl needed), Two-finger gesture = pan\n *\n * **Coordinate System**:\n * The `alignCoordinateSystem` flag determines Y-axis orientation:\n * - `true`: Standard screen coordinates (Y increases downward)\n * - `false`: Inverted coordinates (Y increases upward)\n *\n * This interface extends BaseContext from the \\@ue-too/being state machine library,\n * inheriting setup() and cleanup() lifecycle methods.\n *\n * @category Input State Machine\n */\nexport interface KmtInputContext extends BaseContext {\n /** Whether to use standard screen coordinate system (vs inverted Y-axis) */\n alignCoordinateSystem: boolean;\n /** Canvas accessor for dimensions and cursor control */\n canvas: Canvas;\n /** Sets the initial cursor position when starting a pan gesture */\n setInitialCursorPosition: (position: Point) => void;\n /** Cancels the current action and resets cursor position */\n cancelCurrentAction: () => void;\n /** The cursor position when a pan gesture started */\n initialCursorPosition: Point;\n /** Score tracking input modality: >0 for mouse, <0 for trackpad, 0 for undetermined */\n kmtTrackpadTrackScore: number;\n /** Decreases the score toward trackpad */\n subtractKmtTrackpadTrackScore: () => void;\n /** Increases the score toward mouse */\n addKmtTrackpadTrackScore: () => void;\n /** Sets the determined input modality */\n setMode: (mode: 'kmt' | 'trackpad' | 'TBD') => void;\n /** The current input modality: 'kmt' (mouse), 'trackpad', or 'TBD' (to be determined) */\n mode: 'kmt' | 'trackpad' | 'TBD';\n}\n\n/**\n * No-op implementation of KmtInputContext for web worker relay scenarios.\n *\n * @remarks\n * Used when the input state machine is configured to relay events to a web worker\n * rather than process them locally. The state machine requires a context, but in\n * the relay scenario, no actual state tracking is needed - events are simply forwarded.\n *\n * All methods are no-ops and all properties return default values.\n *\n * @category Input State Machine\n *\n * @see {@link DummyCanvas}\n */\nexport class DummyKmtInputContext implements KmtInputContext {\n\n public alignCoordinateSystem: boolean = false;\n public canvas: Canvas = new DummyCanvas();\n public initialCursorPosition: Point = {x: 0, y: 0};\n\n constructor(){\n\n }\n\n toggleOnEdgeAutoCameraInput: () => void = NO_OP;\n toggleOffEdgeAutoCameraInput: () => void = NO_OP;\n setCursorPosition: (position: Point) => void = NO_OP;\n\n setInitialCursorPosition(position: Point): void {\n }\n\n cleanup(): void {\n }\n\n setup(): void {\n }\n\n get kmtTrackpadTrackScore(): number {\n return 0;\n }\n\n subtractKmtTrackpadTrackScore(): void {\n }\n\n addKmtTrackpadTrackScore(): void {\n }\n\n setMode(mode: 'kmt' | 'trackpad' | 'TBD'): void {\n }\n\n get mode(): 'kmt' | 'trackpad' | 'TBD' {\n return 'kmt';\n }\n\n cancelCurrentAction(): void {\n }\n}\n\n/**\n * Production implementation of KmtInputContext that tracks input state for the state machine.\n *\n * @remarks\n * This class provides the concrete implementation of the KMT input context, maintaining\n * all state required by the state machine to recognize and track gestures:\n *\n * **State Tracking**:\n * - Initial cursor position for calculating pan deltas\n * - Input modality score to distinguish mouse vs trackpad\n * - Determined input mode (kmt/trackpad/TBD)\n * - Coordinate system alignment preference\n *\n * **Input Modality Detection**:\n * The `kmtTrackpadTrackScore` accumulates evidence about the input device:\n * - Positive values indicate mouse behavior (middle-click, no horizontal scroll)\n * - Negative values indicate trackpad behavior (horizontal scroll, two-finger gestures)\n * - Score is used to determine zoom behavior (Ctrl+Scroll for mouse vs Scroll for trackpad)\n *\n * **Design Pattern**:\n * This class follows the Context pattern from the @ue-too/being state machine library,\n * providing stateful data and operations that states can access and modify during transitions.\n *\n * @category Input State Machine\n *\n * @example\n * ```typescript\n * const canvasProxy = new CanvasProxy(canvasElement);\n * const context = new ObservableInputTracker(canvasProxy);\n * const stateMachine = createKmtInputStateMachine(context);\n *\n * // Context tracks state as the state machine processes events\n * stateMachine.happens(\"leftPointerDown\", {x: 100, y: 200});\n * console.log(context.initialCursorPosition); // {x: 100, y: 200}\n * ```\n */\nexport class ObservableInputTracker implements KmtInputContext {\n\n private _alignCoordinateSystem: boolean;\n private _canvasOperator: Canvas;\n private _initialCursorPosition: Point;\n private _kmtTrackpadTrackScore: number; // > 0 for kmt; < 0 for trackpad; 0 for TBD;\n private _mode: 'kmt' | 'trackpad' | 'TBD';\n private _deciding: boolean = true;\n\n constructor(canvasOperator: Canvas){\n this._alignCoordinateSystem = true;\n this._canvasOperator = canvasOperator;\n this._initialCursorPosition = {x: 0, y: 0};\n this._kmtTrackpadTrackScore = 0;\n this._mode = 'TBD';\n }\n\n get mode(): 'kmt' | 'trackpad' | 'TBD' {\n return this._mode;\n }\n\n setMode(mode: 'kmt' | 'trackpad' | 'TBD'): void {\n this._deciding = false;\n this._mode = mode;\n }\n\n enableInputModeDetection(): void {\n this._deciding = true;\n this._kmtTrackpadTrackScore = 0;\n }\n\n get kmtTrackpadTrackScore(): number {\n return this._kmtTrackpadTrackScore;\n }\n\n subtractKmtTrackpadTrackScore(): void {\n if(!this._deciding){\n return;\n }\n this._kmtTrackpadTrackScore--;\n if(this._kmtTrackpadTrackScore < -5){\n this._kmtTrackpadTrackScore = 0;\n this._mode = 'trackpad';\n }\n }\n\n addKmtTrackpadTrackScore(): void {\n if(!this._deciding){\n return;\n }\n this._kmtTrackpadTrackScore++;\n if(this._kmtTrackpadTrackScore > 5){\n this._kmtTrackpadTrackScore = 0;\n this._mode = 'kmt';\n }\n }\n\n get alignCoordinateSystem(): boolean {\n return this._alignCoordinateSystem;\n }\n\n get canvas(): Canvas {\n return this._canvasOperator;\n }\n\n get initialCursorPosition(): Point {\n return this._initialCursorPosition;\n }\n\n set alignCoordinateSystem(value: boolean){\n this._alignCoordinateSystem = value;\n }\n\n cancelCurrentAction(): void {\n this._initialCursorPosition = {x: 0, y: 0};\n }\n\n setInitialCursorPosition(position: Point): void {\n this._initialCursorPosition = position;\n }\n\n cleanup(): void {\n }\n\n setup(): void {\n }\n}\n\nfunction withinEdgeOfCanvas(position: Point, boundingBox: {left: number, top: number, width: number, height: number}, padding: number): boolean {\n return position.x <= boundingBox.left + padding || position.x >= boundingBox.left + boundingBox.width - padding || position.y <= boundingBox.top + padding || position.y >= boundingBox.top + boundingBox.height - padding;\n}\n\nfunction pointInWhichHorizontalEdgeOfCanvas(position: Point, boundingBox: {left: number, top: number, width: number, height: number}, padding: number): 'left' | 'right' | 'none' {\n if(position.x <= boundingBox.left + padding){\n return 'left';\n }\n if(position.x >= boundingBox.left + boundingBox.width - padding){\n return 'right';\n }\n return 'none';\n}\n\nfunction pointInWhichVerticalEdgeOfCanvas(position: Point, boundingBox: {left: number, top: number, width: number, height: number}, padding: number): 'up' | 'down' | 'none' {\n if(position.y <= boundingBox.top + padding){\n return 'up';\n }\n if(position.y >= boundingBox.top + boundingBox.height - padding){\n return 'down';\n }\n return 'none';\n}\n",
40
- "import { BaseContext } from \"@ue-too/being\";\nimport { Canvas } from \"./kmt-input-context\";\n\n/**\n * Represents a single touch point in window coordinates.\n *\n * @property ident - The unique identifier for this touch point (from TouchEvent.identifier)\n * @property x - X coordinate in window space\n * @property y - Y coordinate in window space\n *\n * @remarks\n * Touch points are tracked by their identifiers to maintain consistency across touch events.\n * Each finger/contact point maintains its identifier for the duration of the touch interaction.\n *\n * @category Input State Machine - Touch\n */\nexport type TouchPoints = {\n ident: number,\n x: number,\n y: number,\n}\n\n/**\n * Context interface for the touch input state machine.\n *\n * @remarks\n * This context manages the state required for multi-touch gesture recognition:\n *\n * **Touch Point Tracking**:\n * - Maintains a map of active touch points by identifier\n * - Stores initial positions to calculate deltas for pan gestures\n * - Stores initial distances to calculate zoom factors\n *\n * **Gesture Recognition**:\n * - Single-finger: Not handled (reserved for UI interactions)\n * - Two-finger: Pan and pinch-to-zoom gestures\n * - Three+ fingers: Currently not handled\n *\n * **Coordinate System**:\n * Similar to KMT, the `alignCoordinateSystem` flag controls Y-axis orientation.\n *\n * This interface extends BaseContext from the @ue-too/being state machine library.\n *\n * @category Input State Machine - Touch\n */\nexport interface TouchContext extends BaseContext{\n /** Adds new touch points to tracking */\n addTouchPoints: (points: TouchPoints[]) => void;\n /** Removes touch points from tracking by identifier */\n removeTouchPoints: (idents: number[]) => void;\n /** Returns the current number of active touch points */\n getCurrentTouchPointsCount: () => number;\n /** Retrieves the initial positions of specific touch points */\n getInitialTouchPointsPositions: (idents: number[]) => TouchPoints[];\n /** Updates the current positions of touch points */\n updateTouchPoints: (pointsMoved: TouchPoints[]) => void;\n /** Whether to use standard screen coordinate system (vs inverted Y-axis) */\n alignCoordinateSystem: boolean;\n /** Canvas accessor for dimensions and coordinate transformations */\n canvas: Canvas;\n}\n\n/**\n * Production implementation of TouchContext that tracks multi-touch state.\n *\n * @remarks\n * This class maintains a map of active touch points, storing their initial positions\n * to enable gesture recognition. The state machine uses this context to:\n *\n * - Calculate pan deltas (difference between initial and current midpoint)\n * - Calculate zoom factors (change in distance between two touch points)\n * - Determine gesture type (pan vs zoom based on relative magnitudes)\n *\n * **Touch Point Lifecycle**:\n * 1. `addTouchPoints`: Called on touchstart to register new touches\n * 2. `updateTouchPoints`: Called on touchmove to update current positions\n * 3. `removeTouchPoints`: Called on touchend/touchcancel to unregister touches\n *\n * The initial positions are preserved until the touch ends, allowing continuous\n * calculation of deltas throughout the gesture.\n *\n * @category Input State Machine - Touch\n *\n * @example\n * ```typescript\n * const canvasProxy = new CanvasProxy(canvasElement);\n * const context = new TouchInputTracker(canvasProxy);\n * const stateMachine = createTouchInputStateMachine(context);\n *\n * // When a two-finger touch starts\n * context.addTouchPoints([\n * {ident: 0, x: 100, y: 200},\n * {ident: 1, x: 300, y: 200}\n * ]);\n * console.log(context.getCurrentTouchPointsCount()); // 2\n * ```\n */\nexport class TouchInputTracker implements TouchContext {\n\n private _touchPointsMap: Map<number, TouchPoints> = new Map<number, TouchPoints>();\n private _canvas: Canvas;\n private _alignCoordinateSystem: boolean;\n\n constructor(canvas: Canvas) {\n this._canvas = canvas;\n this._alignCoordinateSystem = true;\n }\n\n addTouchPoints(points: TouchPoints[]): void {\n points.forEach((point)=>{\n this._touchPointsMap.set(point.ident, {...point});\n });\n }\n\n removeTouchPoints(identifiers: number[]): void {\n identifiers.forEach((ident)=>{\n if(this._touchPointsMap.has(ident)){\n this._touchPointsMap.delete(ident);\n }\n });\n }\n\n getCurrentTouchPointsCount(): number {\n return this._touchPointsMap.size;\n }\n\n getInitialTouchPointsPositions(idents: number[]): TouchPoints[] {\n const res: TouchPoints[] = [];\n idents.forEach((ident)=>{\n if(this._touchPointsMap.has(ident)){\n const point = this._touchPointsMap.get(ident);\n if(point){\n res.push(point);\n }\n }\n });\n return res; \n }\n\n updateTouchPoints(pointsMoved: TouchPoints[]): void {\n pointsMoved.forEach((point)=>{\n if(this._touchPointsMap.has(point.ident)){\n this._touchPointsMap.set(point.ident, {...point});\n }\n });\n }\n\n get alignCoordinateSystem(): boolean {\n return this._alignCoordinateSystem;\n }\n\n set alignCoordinateSystem(value: boolean) {\n this._alignCoordinateSystem = value;\n }\n\n get canvas(): Canvas {\n return this._canvas;\n }\n\n cleanup(): void {\n }\n\n setup(): void {\n }\n}\n",
41
- "import { PointCal } from \"@ue-too/math\";\nimport { EventReactions, EventGuards, Guard, TemplateState, TemplateStateMachine } from \"@ue-too/being\";\nimport { TouchContext, TouchPoints } from \"./touch-input-context\";\nimport type { Point } from \"@ue-too/math\";\n\n/**\n * Possible states of the touch input state machine.\n *\n * @remarks\n * State transitions:\n * - **IDLE**: No touches active, or single touch (reserved for UI)\n * - **PENDING**: Exactly two touches active, waiting for movement to determine gesture type\n * - **IN_PROGRESS**: Two-finger gesture in progress (pan or zoom)\n *\n * The state machine only handles two-finger gestures. Single-finger touches are ignored\n * to avoid interfering with UI interactions (button clicks, text selection, etc.).\n *\n * @category Input State Machine - Touch\n */\nexport type TouchStates = \"IDLE\" | \"PENDING\" | \"IN_PROGRESS\";\n\n/**\n * Payload for touch events containing active touch points.\n *\n * @property points - Array of touch points involved in this event\n *\n * @category Input State Machine - Touch\n */\nexport type TouchEventPayload = {\n points: TouchPoints[];\n};\n\n/**\n * Output events produced by the touch state machine for the orchestrator.\n *\n * @remarks\n * Touch gestures are recognized from two-finger interactions:\n *\n * **Pan Gesture**:\n * - Two fingers move in the same direction\n * - Delta is calculated from the midpoint movement\n * - Triggers when midpoint delta > distance delta\n *\n * **Zoom Gesture**:\n * - Two fingers move toward/away from each other (pinch)\n * - Delta is calculated from distance change between fingers\n * - Anchor point is the midpoint between fingers\n * - Triggers when distance delta > midpoint delta\n *\n * **Coordinate Spaces**:\n * - Pan delta is in window pixels\n * - Zoom anchor point is in viewport coordinates\n *\n * @category Input State Machine - Touch\n */\nexport type TouchOutputEvent =\n | { type: \"pan\", delta: Point }\n | { type: \"zoom\", delta: number, anchorPointInViewPort: Point }\n | { type: \"none\" };\n\n/**\n * Event mapping for the touch input state machine.\n *\n * @remarks\n * Maps touch event names to their payload types. The state machine handles\n * the three core touch events: touchstart, touchmove, and touchend.\n *\n * @category Input State Machine - Touch\n */\nexport type TouchEventMapping = {\n touchstart: TouchEventPayload;\n touchmove: TouchEventPayload;\n touchend: TouchEventPayload;\n}\n\n/**\n * Mapping of events to their output types.\n *\n * @remarks\n * Only touchmove produces outputs (pan or zoom gestures).\n * touchstart and touchend only manage state transitions.\n *\n * @category Input State Machine - Touch\n */\nexport type TouchInputEventOutputMapping = {\n touchmove: TouchOutputEvent;\n}\n\n/**\n * IDLE state - waiting for two-finger touch.\n *\n * @remarks\n * This state handles touch lifecycle but only transitions to PENDING when exactly\n * two touches are active. Single touches and three+ touches are ignored.\n *\n * **Guard Condition**:\n * Transitions to PENDING only when `getCurrentTouchPointsCount() === 2`.\n * This ensures the state machine only handles two-finger gestures.\n *\n * @category Input State Machine - Touch\n */\nexport class IdleState extends TemplateState<TouchEventMapping, TouchContext, TouchStates, TouchInputEventOutputMapping> {\n\n private _eventReactions: EventReactions<TouchEventMapping, TouchContext, TouchStates, TouchInputEventOutputMapping> = {\n touchstart: {\n action: this.touchstart,\n defaultTargetState: \"IDLE\",\n },\n touchend: {\n action: this.touchend,\n defaultTargetState: \"IDLE\",\n },\n };\n\n protected _guards: Guard<TouchContext, \"touchPointsCount\"> = {\n touchPointsCount: ((context: TouchContext) => {\n return context.getCurrentTouchPointsCount() === 2;\n }).bind(this)\n };\n\n protected _eventGuards: Partial<EventGuards<TouchEventMapping, TouchStates, TouchContext, typeof this._guards>> = {\n touchstart: [{\n guard: \"touchPointsCount\",\n target: \"PENDING\",\n }],\n touchend: [{\n guard: \"touchPointsCount\",\n target: \"PENDING\",\n }],\n };\n\n get eventReactions(): EventReactions<TouchEventMapping, TouchContext, TouchStates, TouchInputEventOutputMapping> {\n return this._eventReactions;\n }\n\n touchstart(context: TouchContext, payload: TouchEventPayload): void {\n context.addTouchPoints(payload.points);\n }\n\n touchend(context: TouchContext, payload: TouchEventPayload): void {\n context.removeTouchPoints(payload.points.map(p => p.ident));\n }\n}\n\n/**\n * @description The pending state of the touch input state machine.\n *\n * @category Input State Machine\n */\nexport class PendingState extends TemplateState<TouchEventMapping, TouchContext, TouchStates, TouchInputEventOutputMapping> {\n\n private _eventReactions: EventReactions<TouchEventMapping, TouchContext, TouchStates, TouchInputEventOutputMapping> = {\n touchstart: {\n action: this.touchstart,\n defaultTargetState: \"IDLE\",\n },\n touchend: {\n action: this.touchend,\n defaultTargetState: \"IDLE\",\n },\n touchmove: {\n action: this.touchmove,\n defaultTargetState: \"IN_PROGRESS\",\n },\n };\n\n get eventReactions(): EventReactions<TouchEventMapping, TouchContext, TouchStates, TouchInputEventOutputMapping> {\n return this._eventReactions;\n }\n\n touchstart(context: TouchContext, payload: TouchEventPayload): void {\n context.addTouchPoints(payload.points);\n }\n\n touchend(context: TouchContext, payload: TouchEventPayload): void {\n context.removeTouchPoints(payload.points.map(p => p.ident));\n }\n\n touchmove(context: TouchContext, payload: TouchEventPayload): TouchOutputEvent {\n const idents = payload.points.map(p => p.ident);\n const initialPositions = context.getInitialTouchPointsPositions(idents);\n const currentPositions = payload.points;\n const initialStartAndEndDistance = PointCal.distanceBetweenPoints(initialPositions[0], initialPositions[1]);\n const currentStartAndEndDistance = PointCal.distanceBetweenPoints(currentPositions[0], currentPositions[1]);\n const midPoint = PointCal.linearInterpolation(initialPositions[0], initialPositions[1], 0.5);\n const currentMidPoint = PointCal.linearInterpolation(currentPositions[0], currentPositions[1], 0.5);\n const midPointDelta = PointCal.subVector(midPoint, currentMidPoint);\n const cameraCenterInWindow = {x: context.canvas.position.x + context.canvas.width / 2, y: context.canvas.position.y + context.canvas.height / 2};\n const midPointInViewPort = PointCal.subVector(midPoint, cameraCenterInWindow);\n let panZoom = Math.abs(currentStartAndEndDistance - initialStartAndEndDistance) > PointCal.distanceBetweenPoints(midPoint, currentMidPoint) ? \"ZOOMING\" : \"PANNING\";\n\n context.updateTouchPoints(currentPositions);\n switch(panZoom){\n case \"ZOOMING\":\n return {\n type: \"zoom\",\n delta: (currentStartAndEndDistance - initialStartAndEndDistance) * 0.005,\n anchorPointInViewPort: midPointInViewPort\n };\n case \"PANNING\":\n return {\n type: \"pan\",\n delta: midPointDelta\n };\n default:\n console.warn(\"Unknown panZoom state\", panZoom);\n return { type: \"none\" };\n }\n }\n}\n\n/**\n * @description The in progress state of the touch input state machine.\n *\n * @category Input State Machine\n */\nexport class InProgressState extends TemplateState<TouchEventMapping, TouchContext, TouchStates, TouchInputEventOutputMapping> {\n\n private _eventReactions: EventReactions<TouchEventMapping, TouchContext, TouchStates, TouchInputEventOutputMapping> = {\n touchmove: {\n action: this.touchmove,\n defaultTargetState: \"IN_PROGRESS\",\n },\n touchend: {\n action: this.touchend,\n defaultTargetState: \"IDLE\",\n },\n touchstart: {\n action: ()=> \"IDLE\",\n defaultTargetState: \"IDLE\",\n },\n };\n\n get eventReactions(): EventReactions<TouchEventMapping, TouchContext, TouchStates, TouchInputEventOutputMapping> {\n return this._eventReactions;\n }\n\n touchmove(context: TouchContext, payload: TouchEventPayload): TouchOutputEvent {\n const idents = payload.points.map(p => p.ident);\n const initialPositions = context.getInitialTouchPointsPositions(idents);\n const currentPositions = payload.points;\n const initialStartAndEndDistance = PointCal.distanceBetweenPoints(initialPositions[0], initialPositions[1]);\n const currentStartAndEndDistance = PointCal.distanceBetweenPoints(currentPositions[0], currentPositions[1]);\n const midPoint = PointCal.linearInterpolation(initialPositions[0], initialPositions[1], 0.5);\n const currentMidPoint = PointCal.linearInterpolation(currentPositions[0], currentPositions[1], 0.5);\n const midPointDelta = PointCal.subVector(midPoint, currentMidPoint);\n const cameraCenterInWindow = {x: context.canvas.position.x + context.canvas.width / 2, y: context.canvas.position.y + context.canvas.height / 2};\n const midPointInViewPort = PointCal.subVector(midPoint, cameraCenterInWindow);\n let panZoom = Math.abs(currentStartAndEndDistance - initialStartAndEndDistance) > PointCal.distanceBetweenPoints(midPoint, currentMidPoint) ? \"ZOOMING\" : \"PANNING\";\n\n context.updateTouchPoints(currentPositions);\n switch(panZoom){\n case \"ZOOMING\":\n if(!context.alignCoordinateSystem){\n midPointInViewPort.y = -midPointInViewPort.y;\n }\n return {\n type: \"zoom\",\n delta: -(initialStartAndEndDistance - currentStartAndEndDistance) * 0.005,\n anchorPointInViewPort: midPointInViewPort\n };\n case \"PANNING\":\n if(!context.alignCoordinateSystem){\n midPointDelta.y = -midPointDelta.y;\n }\n return {\n type: \"pan\",\n delta: midPointDelta\n };\n default:\n console.warn(\"Unknown panZoom state\", panZoom);\n return { type: \"none\" };\n }\n }\n\n touchend(context: TouchContext, payload: TouchEventPayload): void {\n context.removeTouchPoints(payload.points.map(p => p.ident));\n }\n}\n\n/**\n * Type alias for the touch input state machine.\n *\n * @category Input State Machine - Touch\n */\nexport type TouchInputStateMachine = TemplateStateMachine<TouchEventMapping, TouchContext, TouchStates, TouchInputEventOutputMapping>;\n\n/**\n * Creates a new touch input state machine for multi-touch gesture recognition.\n *\n * @param context - The context providing touch point tracking and canvas access\n * @returns A configured state machine ready to process touch events\n *\n * @remarks\n * This factory creates a state machine that recognizes two-finger pan and pinch-to-zoom gestures.\n *\n * **State Flow**:\n * ```\n * IDLE → (2 touches start) → PENDING → (touch move) → IN_PROGRESS\n * IN_PROGRESS → (touch end) → IDLE\n * ```\n *\n * **Gesture Recognition Algorithm**:\n * 1. Wait for exactly 2 touches (IDLE → PENDING)\n * 2. On first move, determine gesture type:\n * - If distance change > midpoint change: ZOOM\n * - If midpoint change > distance change: PAN\n * 3. Continue producing pan/zoom outputs until touches end\n *\n * **Pan Gesture**:\n * Delta = current midpoint - initial midpoint\n *\n * **Zoom Gesture**:\n * Delta = (current distance - initial distance) * 0.005\n * Anchor = midpoint in viewport coordinates\n *\n * @category Input State Machine - Touch\n *\n * @example\n * ```typescript\n * const canvasProxy = new CanvasProxy(canvasElement);\n * const context = new TouchInputTracker(canvasProxy);\n * const stateMachine = createTouchInputStateMachine(context);\n *\n * // Process a touch start event with 2 fingers\n * const result = stateMachine.happens(\"touchstart\", {\n * points: [\n * {ident: 0, x: 100, y: 200},\n * {ident: 1, x: 300, y: 200}\n * ]\n * });\n * console.log(result.nextState); // \"PENDING\"\n * ```\n */\nexport function createTouchInputStateMachine(context: TouchContext): TouchInputStateMachine {\n return new TemplateStateMachine<TouchEventMapping, TouchContext, TouchStates, TouchInputEventOutputMapping>(\n {\n IDLE: new IdleState(),\n PENDING: new PendingState(),\n IN_PROGRESS: new InProgressState(),\n }, \"IDLE\", context);\n}\n",
42
- "import { EventReactions, EventGuards, Guard, TemplateState, TemplateStateMachine, NO_OP, EventArgs, EventResult, CreateStateType } from \"@ue-too/being\";\nimport type { Point } from \"@ue-too/math\";\nimport { Canvas, CursorStyle, DummyKmtInputContext, KmtInputContext, ObservableInputTracker } from \"./kmt-input-context\";\nimport { convertFromWindow2ViewPortWithCanvasOperator } from \"../../utils/coorindate-conversion\";\n\nconst KMT_INPUT_STATES = [\"IDLE\", \"READY_TO_PAN_VIA_SPACEBAR\", \"READY_TO_PAN_VIA_SCROLL_WHEEL\", \"PAN\", \"INITIAL_PAN\", \"PAN_VIA_SCROLL_WHEEL\", \"DISABLED\"] as const;\n\n/**\n * Possible states of the Keyboard/Mouse/Trackpad input state machine.\n *\n * @remarks\n * State transitions:\n * - **IDLE**: Default state, waiting for user input\n * - **READY_TO_PAN_VIA_SPACEBAR**: Spacebar pressed, ready to pan with left-click drag\n * - **INITIAL_PAN**: First frame of pan via spacebar (detects accidental clicks)\n * - **PAN**: Active panning via spacebar + left-click drag\n * - **READY_TO_PAN_VIA_SCROLL_WHEEL**: Middle mouse button pressed, ready to pan\n * - **PAN_VIA_SCROLL_WHEEL**: Active panning via middle-click drag\n * - **DISABLED**: Input temporarily disabled (e.g., during UI interactions)\n *\n * @category Input State Machine - KMT\n */\nexport type KmtInputStates = CreateStateType<typeof KMT_INPUT_STATES>;\n\n/**\n * Payload for pointer events (mouse button press/release/move).\n *\n * @property x - X coordinate in window space\n * @property y - Y coordinate in window space\n *\n * @category Input State Machine - KMT\n */\nexport type PointerEventPayload = {\n x: number;\n y: number;\n}\n\n/**\n * @internal\n */\ntype EmptyPayload = {};\n\n/**\n * Payload for scroll wheel events.\n *\n * @property deltaX - Horizontal scroll delta\n * @property deltaY - Vertical scroll delta\n *\n * @category Input State Machine - KMT\n */\nexport type ScrollEventPayload = {\n deltaX: number;\n deltaY: number;\n}\n\n/**\n * Payload for scroll events combined with ctrl key (zoom gesture).\n *\n * @property deltaX - Horizontal scroll delta\n * @property deltaY - Vertical scroll delta\n * @property x - Cursor X coordinate in window space (zoom anchor point)\n * @property y - Cursor Y coordinate in window space (zoom anchor point)\n *\n * @category Input State Machine - KMT\n */\nexport type ScrollWithCtrlEventPayload = {\n deltaX: number;\n deltaY: number;\n x: number;\n y: number;\n}\n\n/**\n * Event mapping for the KMT input state machine.\n *\n * @remarks\n * Maps event names to their payload types. Used by the state machine framework\n * to provide type-safe event handling.\n *\n * Key events:\n * - **leftPointerDown/Up/Move**: Left mouse button interactions\n * - **middlePointerDown/Up/Move**: Middle mouse button interactions (pan)\n * - **spacebarDown/Up**: Spacebar for pan mode\n * - **scroll**: Regular scroll (pan or zoom depending on device)\n * - **scrollWithCtrl**: Ctrl + scroll (always zoom)\n * - **disable/enable**: Temporarily disable/enable input processing\n *\n * @category Input State Machine - KMT\n */\nexport type KmtInputEventMapping = {\n leftPointerDown: PointerEventPayload;\n leftPointerUp: PointerEventPayload;\n leftPointerMove: PointerEventPayload;\n spacebarDown: EmptyPayload;\n spacebarUp: EmptyPayload;\n stayIdle: EmptyPayload;\n cursorOnElement: EmptyPayload;\n scroll: ScrollWithCtrlEventPayload;\n scrollWithCtrl: ScrollWithCtrlEventPayload;\n middlePointerDown: PointerEventPayload;\n middlePointerUp: PointerEventPayload;\n middlePointerMove: PointerEventPayload;\n disable: EmptyPayload;\n enable: EmptyPayload;\n pointerMove: PointerEventPayload;\n}\n\n/**\n * @internal\n */\ntype PanEventOutput = {\n type: \"pan\";\n delta: Point;\n};\n\n/**\n * @internal\n */\ntype ZoomEventOutput = {\n type: \"zoom\";\n delta: number;\n anchorPoint: Point;\n};\n\n/**\n * Output events produced by the KMT state machine for the orchestrator.\n *\n * @remarks\n * These high-level gesture events are the result of recognizing patterns in raw DOM events.\n * The orchestrator receives these events and coordinates camera control and observer notification.\n *\n * **Event Types**:\n * - **pan**: Camera translation with delta in viewport coordinates\n * - **zoom**: Camera scale change with anchor point in viewport coordinates\n * - **rotate**: Camera rotation change (currently unused in KMT)\n * - **cursor**: Cursor style change request (handled by state uponEnter/beforeExit)\n * - **none**: No action required\n *\n * **Coordinate Spaces**:\n * - Pan delta is in viewport pixels\n * - Zoom anchor point is in viewport coordinates (origin at viewport center)\n *\n * @category Input State Machine - KMT\n */\nexport type KmtOutputEvent =\n | { type: \"pan\", delta: Point }\n | { type: \"zoom\", delta: number, anchorPointInViewPort: Point }\n | { type: \"rotate\", deltaRotation: number }\n | { type: \"cursor\", style: CursorStyle }\n | { type: \"none\" };\n\n/**\n * Mapping of events to their output types.\n *\n * @remarks\n * Defines which events produce outputs. Not all events produce outputs - some only\n * cause state transitions. This mapping is used by the state machine framework for\n * type-safe output handling.\n *\n * @category Input State Machine - KMT\n */\nexport type KmtInputEventOutputMapping = {\n spacebarDown: number;\n middlePointerMove: KmtOutputEvent;\n scroll: KmtOutputEvent;\n scrollWithCtrl: KmtOutputEvent;\n leftPointerMove: KmtOutputEvent;\n}\n\n/**\n * @internal\n */\nexport type KmtIdleStatePossibleTargetStates = \"IDLE\" | \"READY_TO_PAN_VIA_SPACEBAR\" | \"READY_TO_PAN_VIA_SCROLL_WHEEL\" | \"DISABLED\";\n\n/**\n * IDLE state - default state waiting for user input.\n *\n * @remarks\n * This is the default state of the KMT input state machine. It handles scroll events\n * for panning and zooming, and transitions to pan-ready states when the user presses\n * spacebar or middle-click.\n *\n * **Responsibilities**:\n * - Process scroll events (pan or zoom depending on device and modifiers)\n * - Detect spacebar press to enter pan mode\n * - Detect middle-click to enter pan mode\n * - Distinguish between mouse and trackpad input modalities\n *\n * **Scroll Behavior**:\n * - Ctrl + Scroll: Always zoom (both mouse and trackpad)\n * - Scroll (no Ctrl): Pan (trackpad) or Zoom (mouse, determined by modality detection)\n *\n * **Input Modality Detection**:\n * The state tracks horizontal scroll deltas to distinguish trackpads (which produce deltaX)\n * from mice (which typically only produce deltaY). This affects zoom behavior.\n *\n * @category Input State Machine - KMT\n */\nexport class KmtIdleState extends TemplateState<KmtInputEventMapping, KmtInputContext, KmtInputStates, KmtInputEventOutputMapping> {\n\n constructor() {\n super();\n }\n\n protected _guards: Guard<KmtInputContext, \"isIdle\"> = {\n isIdle: () => true,\n }\n\n protected _eventGuards: Partial<EventGuards<KmtInputEventMapping, KmtInputStates, KmtInputContext, Guard<KmtInputContext>>> = {\n }\n\n // Arrow function properties must be defined before _eventReactions to ensure proper initialization order\n scrollPan = (context: KmtInputContext, payload: ScrollEventPayload): KmtOutputEvent => {\n const delta = {...payload}\n if(!context.alignCoordinateSystem){\n delta.deltaY = -delta.deltaY;\n }\n return {\n type: \"pan\",\n delta: {x: delta.deltaX, y: delta.deltaY}\n };\n }\n\n scrollZoom = (context: KmtInputContext, payload: ScrollWithCtrlEventPayload): KmtOutputEvent => {\n let scrollSensitivity = 0.005;\n if(Math.abs(payload.deltaY) > 100){\n scrollSensitivity = 0.0005;\n }\n const zoomAmount = payload.deltaY * scrollSensitivity;\n const cursorPosition = {x: payload.x, y: payload.y};\n const anchorPointInViewPort = convertFromWindow2ViewPortWithCanvasOperator(cursorPosition, context.canvas, {x: context.canvas.width / 2, y: context.canvas.height / 2}, !context.alignCoordinateSystem);\n return {\n type: \"zoom\",\n delta: -(zoomAmount * 5),\n anchorPointInViewPort,\n };\n }\n\n scrollHandler = (context: KmtInputContext, payload: ScrollWithCtrlEventPayload): KmtOutputEvent => {\n if(payload.deltaX === 0 && payload.deltaY !== 0){\n context.addKmtTrackpadTrackScore();\n } else if (payload.deltaX !== 0 && payload.deltaY !== 0){\n context.subtractKmtTrackpadTrackScore();\n }\n if(context.mode === \"kmt\"){\n return this.scrollZoom(context, payload);\n } else {\n return this.scrollPan(context, payload);\n }\n }\n\n scrollWithCtrlHandler = (context: KmtInputContext, payload: ScrollWithCtrlEventPayload): KmtOutputEvent => {\n return this.scrollZoom(context, payload);\n }\n\n get eventReactions(): EventReactions<KmtInputEventMapping, KmtInputContext, KmtInputStates, KmtInputEventOutputMapping> {\n return this._eventReactions;\n }\n\n protected _eventReactions: EventReactions<KmtInputEventMapping, KmtInputContext, KmtInputStates, KmtInputEventOutputMapping> = {\n spacebarDown: {\n action: this.spacebarDownHandler,\n defaultTargetState: \"READY_TO_PAN_VIA_SPACEBAR\",\n },\n scroll: {\n action: this.scrollHandler,\n defaultTargetState: \"IDLE\",\n },\n scrollWithCtrl: {\n action: this.scrollWithCtrlHandler,\n defaultTargetState: \"IDLE\",\n },\n middlePointerDown: {\n action: this.middlePointerDownHandler,\n defaultTargetState: \"READY_TO_PAN_VIA_SCROLL_WHEEL\",\n },\n disable: {\n action: NO_OP,\n defaultTargetState: \"DISABLED\",\n },\n }\n\n uponEnter(context: KmtInputContext): void {\n context.canvas.setCursor(CursorStyle.DEFAULT);\n }\n\n spacebarDownHandler(context: KmtInputContext, payload: EmptyPayload): number {\n // context.canvas.setCursor(CursorStyle.GRAB);\n return 1;\n }\n\n middlePointerDownHandler(context: KmtInputContext, payload: PointerEventPayload): void {\n // probably from kmt\n context.addKmtTrackpadTrackScore();\n if(context.mode === \"TBD\") {\n context.setMode(\"kmt\");\n }\n context.setInitialCursorPosition({x: payload.x, y: payload.y});\n }\n\n}\n\nexport class DisabledState extends TemplateState<KmtInputEventMapping, KmtInputContext, KmtInputStates, KmtInputEventOutputMapping> {\n constructor() {\n super();\n }\n\n uponEnter(context: KmtInputContext): void {\n context.canvas.setCursor(CursorStyle.DEFAULT);\n // context.toggleOnEdgeAutoCameraInput();\n }\n\n beforeExit(context: KmtInputContext): void {\n // context.toggleOffEdgeAutoCameraInput();\n }\n\n get eventReactions(): EventReactions<KmtInputEventMapping, KmtInputContext, KmtInputStates, KmtInputEventOutputMapping> {\n return {\n \"enable\": {\n action: NO_OP,\n defaultTargetState: \"IDLE\",\n },\n };\n }\n}\n\n/**\n * @description The ready to pan via space bar state of the keyboard mouse and trackpad input state machine.\n * \n * @category Input State Machine\n */\nexport class ReadyToPanViaSpaceBarState extends TemplateState<KmtInputEventMapping, KmtInputContext, KmtInputStates, KmtInputEventOutputMapping> {\n\n constructor() {\n super();\n }\n\n protected _eventReactions: EventReactions<KmtInputEventMapping, KmtInputContext, KmtInputStates, KmtInputEventOutputMapping> = {\n spacebarUp: {\n action: NO_OP,\n defaultTargetState: \"IDLE\",\n },\n leftPointerDown: {\n action: this.leftPointerDownHandler,\n defaultTargetState: \"INITIAL_PAN\",\n },\n disable: {\n action: (context) => context.cancelCurrentAction(),\n defaultTargetState: \"DISABLED\",\n },\n leftPointerMove: {\n action: NO_OP,\n defaultTargetState: \"READY_TO_PAN_VIA_SPACEBAR\",\n }\n }\n\n uponEnter(context: KmtInputContext): void {\n context.canvas.setCursor(CursorStyle.GRAB);\n }\n\n get eventReactions(): EventReactions<KmtInputEventMapping, KmtInputContext, KmtInputStates, KmtInputEventOutputMapping> {\n return this._eventReactions;\n }\n\n leftPointerDownHandler(context: KmtInputContext, payload: PointerEventPayload): void {\n context.setInitialCursorPosition({x: payload.x, y: payload.y});\n }\n}\n\n/**\n * @description The initial pan state of the keyboard mouse and trackpad input state machine.\n * \n * @category Input State Machine\n */\nexport class InitialPanState extends TemplateState<KmtInputEventMapping, KmtInputContext, KmtInputStates, KmtInputEventOutputMapping> {\n\n constructor() {\n super();\n }\n\n protected _eventReactions: EventReactions<KmtInputEventMapping, KmtInputContext, KmtInputStates, KmtInputEventOutputMapping> = {\n leftPointerUp: {\n action: NO_OP,\n defaultTargetState: \"READY_TO_PAN_VIA_SPACEBAR\",\n },\n leftPointerMove: {\n action: this.leftPointerMoveHandler,\n defaultTargetState: \"PAN\",\n },\n spacebarUp: {\n action: () => \"IDLE\",\n defaultTargetState: \"IDLE\",\n },\n leftPointerDown: {\n action: () => \"PAN\",\n defaultTargetState: \"PAN\",\n },\n }\n\n get eventReactions(): EventReactions<KmtInputEventMapping, KmtInputContext, KmtInputStates, KmtInputEventOutputMapping> {\n return this._eventReactions;\n }\n\n uponEnter(context: KmtInputContext): void {\n context.canvas.setCursor(CursorStyle.GRABBING);\n }\n\n leftPointerMoveHandler(context: KmtInputContext, payload: PointerEventPayload): KmtOutputEvent {\n const delta = {\n x: context.initialCursorPosition.x - payload.x,\n y: context.initialCursorPosition.y - payload.y,\n };\n if(!context.alignCoordinateSystem){\n delta.y = -delta.y;\n }\n context.setInitialCursorPosition({x: payload.x, y: payload.y});\n return {\n type: \"pan\",\n delta: delta\n };\n }\n}\n\n/**\n * @description The ready to pan via scroll wheel state of the keyboard mouse and trackpad input state machine.\n * \n * @category Input State Machine\n */\nexport class ReadyToPanViaScrollWheelState extends TemplateState<KmtInputEventMapping, KmtInputContext, KmtInputStates, KmtInputEventOutputMapping> {\n\n constructor() {\n super();\n }\n\n protected _eventReactions: EventReactions<KmtInputEventMapping, KmtInputContext, KmtInputStates, KmtInputEventOutputMapping> = {\n middlePointerUp: {\n action: NO_OP,\n defaultTargetState: \"IDLE\",\n },\n middlePointerMove: {\n action: NO_OP,\n defaultTargetState: \"PAN_VIA_SCROLL_WHEEL\",\n },\n }\n\n get eventReactions(): EventReactions<KmtInputEventMapping, KmtInputContext, KmtInputStates, KmtInputEventOutputMapping> {\n return this._eventReactions;\n }\n\n uponEnter(context: KmtInputContext): void {\n context.canvas.setCursor(CursorStyle.GRABBING);\n }\n}\n\n/**\n * @description The pan state of the keyboard mouse and trackpad input state machine.\n * \n * @category Input State Machine\n */\nexport class PanState extends TemplateState<KmtInputEventMapping, KmtInputContext, KmtInputStates, KmtInputEventOutputMapping> {\n\n constructor() {\n super();\n }\n\n protected _eventReactions: EventReactions<KmtInputEventMapping, KmtInputContext, KmtInputStates, KmtInputEventOutputMapping> = {\n leftPointerUp: {\n action: NO_OP,\n defaultTargetState: \"READY_TO_PAN_VIA_SPACEBAR\",\n },\n leftPointerMove: {\n action: this.leftPointerMoveHandler,\n defaultTargetState: \"PAN\",\n },\n spacebarUp: {\n action: NO_OP, \n defaultTargetState: \"IDLE\",\n },\n }\n\n get eventReactions(): EventReactions<KmtInputEventMapping, KmtInputContext, KmtInputStates, KmtInputEventOutputMapping> {\n return this._eventReactions;\n }\n\n uponEnter(context: KmtInputContext): void {\n context.canvas.setCursor(CursorStyle.GRABBING);\n }\n\n beforeExit(context: KmtInputContext): void {\n context.canvas.setCursor(CursorStyle.DEFAULT);\n }\n\n leftPointerMoveHandler(context: KmtInputContext, payload: PointerEventPayload): KmtOutputEvent {\n const delta = {\n x: context.initialCursorPosition.x - payload.x,\n y: context.initialCursorPosition.y - payload.y,\n };\n if(!context.alignCoordinateSystem){\n delta.y = -delta.y;\n }\n context.setInitialCursorPosition({x: payload.x, y: payload.y});\n return {\n type: \"pan\",\n delta: delta\n };\n }\n}\n\n/**\n * @description The pan via scroll wheel state of the keyboard mouse and trackpad input state machine.\n * \n * @category Input State Machine\n */\nexport class PanViaScrollWheelState extends TemplateState<KmtInputEventMapping, KmtInputContext, KmtInputStates, KmtInputEventOutputMapping> {\n\n protected _eventReactions: EventReactions<KmtInputEventMapping, KmtInputContext, KmtInputStates, KmtInputEventOutputMapping> = {\n middlePointerUp: {\n action: NO_OP,\n defaultTargetState: \"IDLE\",\n },\n middlePointerMove: {\n action: this.middlePointerMoveHandler,\n defaultTargetState: \"PAN_VIA_SCROLL_WHEEL\",\n },\n }\n\n get eventReactions(): EventReactions<KmtInputEventMapping, KmtInputContext, KmtInputStates, KmtInputEventOutputMapping> {\n return this._eventReactions;\n }\n\n middlePointerMoveHandler(context: KmtInputContext, payload: PointerEventPayload): KmtOutputEvent {\n const delta = {\n x: context.initialCursorPosition.x - payload.x,\n y: context.initialCursorPosition.y - payload.y,\n };\n if(!context.alignCoordinateSystem){\n delta.y = -delta.y;\n }\n context.setInitialCursorPosition({x: payload.x, y: payload.y});\n return {\n type: \"pan\",\n delta: delta,\n };\n }\n\n uponEnter(context: KmtInputContext): void {\n context.canvas.setCursor(CursorStyle.GRABBING);\n }\n}\n\nexport class KmtEmptyState extends TemplateState<KmtInputEventMapping, KmtInputContext, KmtInputStates, KmtInputEventOutputMapping> {\n\n constructor() {\n super();\n }\n\n get eventReactions(): EventReactions<KmtInputEventMapping, KmtInputContext, KmtInputStates, KmtInputEventOutputMapping> {\n return {};\n }\n \n}\n\n/**\n * Type alias for the KMT input state machine.\n *\n * @category Input State Machine - KMT\n */\nexport type KmtInputStateMachine = TemplateStateMachine<KmtInputEventMapping, KmtInputContext, KmtInputStates, KmtInputEventOutputMapping>;\n\n/**\n * Creates a new KMT (Keyboard/Mouse/Trackpad) input state machine.\n *\n * @param context - The context providing state and canvas access for the state machine\n * @returns A configured state machine ready to process KMT input events\n *\n * @remarks\n * This factory function creates a fully configured state machine with all KMT gesture\n * recognition states. The state machine processes raw input events and produces\n * high-level gesture outputs (pan, zoom, rotate).\n *\n * **State Flow**:\n * ```\n * IDLE → (spacebar) → READY_TO_PAN_VIA_SPACEBAR → (click) → INITIAL_PAN → PAN\n * IDLE → (middle-click) → READY_TO_PAN_VIA_SCROLL_WHEEL → PAN_VIA_SCROLL_WHEEL\n * IDLE → (scroll) → [produces pan or zoom output, stays in IDLE]\n * ```\n *\n * **Gesture Recognition**:\n * - **Pan via spacebar**: Spacebar + left-click drag\n * - **Pan via middle-click**: Middle-click drag\n * - **Zoom**: Ctrl + scroll (mouse) or scroll (trackpad, auto-detected)\n * - **Pan via scroll**: Scroll (trackpad) or scroll without Ctrl (varies by device)\n *\n * @category Input State Machine - KMT\n *\n * @example\n * ```typescript\n * const canvasProxy = new CanvasProxy(canvasElement);\n * const context = new ObservableInputTracker(canvasProxy);\n * const stateMachine = createKmtInputStateMachine(context);\n *\n * // Process an event\n * const result = stateMachine.happens(\"scroll\", {\n * deltaX: 0,\n * deltaY: 10,\n * x: 500,\n * y: 300\n * });\n *\n * // Check for output\n * if (result.output) {\n * console.log(\"Gesture recognized:\", result.output.type);\n * }\n * ```\n */\nexport function createKmtInputStateMachine(context: KmtInputContext): KmtInputStateMachine {\n const states = {\n IDLE: new KmtIdleState(),\n READY_TO_PAN_VIA_SPACEBAR: new ReadyToPanViaSpaceBarState(),\n INITIAL_PAN: new InitialPanState(),\n PAN: new PanState(),\n READY_TO_PAN_VIA_SCROLL_WHEEL: new ReadyToPanViaScrollWheelState(),\n PAN_VIA_SCROLL_WHEEL: new PanViaScrollWheelState(),\n DISABLED: new DisabledState(),\n }\n return new TemplateStateMachine<KmtInputEventMapping, KmtInputContext, KmtInputStates, KmtInputEventOutputMapping>(states, \"IDLE\", context);\n}\n\nexport function createKmtInputStateMachineWithCanvas(canvas: Canvas): KmtInputStateMachine {\n const context = new ObservableInputTracker(canvas);\n\n return createKmtInputStateMachine(context);\n}\n\nexport class KmtInputStateMachineWebWorkerProxy extends TemplateStateMachine<KmtInputEventMapping, KmtInputContext, KmtInputStates, KmtInputEventOutputMapping> {\n\n private _webworker: Worker;\n\n constructor(webworker: Worker){\n super({\n \"IDLE\": new KmtEmptyState(),\n \"READY_TO_PAN_VIA_SPACEBAR\": new KmtEmptyState(),\n \"INITIAL_PAN\": new KmtEmptyState(),\n \"PAN\": new KmtEmptyState(),\n \"READY_TO_PAN_VIA_SCROLL_WHEEL\": new KmtEmptyState(),\n \"PAN_VIA_SCROLL_WHEEL\": new KmtEmptyState(),\n \"DISABLED\": new DisabledState(),\n }, \"IDLE\", new DummyKmtInputContext());\n this._webworker = webworker;\n }\n\n happens(...args: EventArgs<KmtInputEventMapping, keyof KmtInputEventMapping | string>): EventResult<KmtInputStates> { \n this._webworker.postMessage({\n type: \"kmtInputStateMachine\",\n event: args[0],\n payload: args[1],\n });\n return {handled: true, nextState: \"IDLE\"};\n }\n}\n",
43
- "import type {Point} from \"@ue-too/math\";\nimport {KmtOutputEvent} from \"./input-state-machine/kmt-input-state-machine\";\nimport {TouchOutputEvent} from \"./input-state-machine/touch-input-state-machine\";\nimport {UserInputPublisher} from \"./raw-input-publisher/raw-input-publisher\";\nimport {CameraMux, CameraMuxPanOutput, CameraMuxZoomOutput, CameraMuxRotationOutput} from \"../camera/camera-mux\";\nimport {CameraRig} from \"../camera/camera-rig\";\n\n/**\n * Union type of all output events from state machines.\n *\n * @remarks\n * This type represents the unified output from both KMT (Keyboard/Mouse/Trackpad) and Touch state machines.\n * By unifying these outputs, the orchestrator can handle events from different input modalities uniformly.\n *\n * @category Input Interpretation\n */\nexport type OutputEvent = KmtOutputEvent | TouchOutputEvent;\n\n/**\n * Central orchestrator that coordinates input interpretation and camera control for the infinite canvas.\n *\n * @remarks\n * The InputOrchestrator serves as the mediator between input state machines and camera control systems.\n * It implements a permission-based architecture where:\n *\n * 1. **Event Flow**: State machines produce high-level gesture events (pan, zoom, rotate)\n * 2. **Permission Check**: Events are sent to CameraMux for permission validation\n * 3. **Execution**: If allowed, gestures are executed on CameraRig\n * 4. **Broadcasting**: Raw events are simultaneously broadcast to observers via UserInputPublisher\n *\n * **Architecture Pattern**:\n * ```\n * State Machines → Orchestrator → CameraMux (permission) → CameraRig (execution)\n * ↓\n * UserInputPublisher (observers)\n * ```\n *\n * This design decouples state machines from camera control, allowing state machines to focus solely\n * on gesture recognition while the orchestrator handles the complexities of camera coordination,\n * permission management, and event distribution.\n *\n * **Key Benefits**:\n * - Single point of control for all camera operations\n * - State machines remain unaware of camera implementation\n * - Parallel path for observers to react to raw input events\n * - Consistent handling of KMT and Touch input modalities\n *\n * @category Input Interpretation\n *\n * @example\n * ```typescript\n * // Create the orchestrator\n * const cameraMux = new CameraMux();\n * const cameraRig = new CameraRig(camera, viewport);\n * const publisher = new RawUserInputPublisher();\n * const orchestrator = new InputOrchestrator(cameraMux, cameraRig, publisher);\n *\n * // State machines send their output to the orchestrator\n * const kmtStateMachine = createKmtInputStateMachine(kmtContext);\n * const result = kmtStateMachine.happens(\"leftPointerMove\", {x: 100, y: 200});\n * orchestrator.processInputEventOutput(result.output);\n *\n * // Observers can subscribe to raw input events\n * publisher.on(\"pan\", (event) => {\n * console.log(\"Pan gesture detected:\", event.diff);\n * });\n * ```\n */\nexport class InputOrchestrator {\n private _cameraMux: CameraMux;\n private _cameraRig: CameraRig;\n private _publisher?: UserInputPublisher;\n\n /**\n * Creates a new InputOrchestrator instance.\n *\n * @param cameraMux - The camera multiplexer that validates and controls camera operation permissions\n * @param cameraRig - The camera rig that executes camera transformations\n * @param publisher - Optional publisher for broadcasting raw input events to observers\n *\n * @remarks\n * The publisher parameter is optional to support scenarios where event broadcasting is not needed.\n * When provided, all input events are broadcast in parallel to camera control execution.\n */\n constructor(cameraMux: CameraMux, cameraRig: CameraRig, publisher?: UserInputPublisher) {\n this._cameraMux = cameraMux;\n this._cameraRig = cameraRig;\n this._publisher = publisher;\n }\n\n /**\n * Processes output events from state machines and routes them to camera control and observers.\n *\n * @param output - The output from a state machine, can be a single event, array of events, or any value\n *\n * @remarks\n * This method serves as the main entry point for state machine outputs. It:\n * 1. Validates whether the output is a valid OutputEvent\n * 2. Handles both single events and arrays of events\n * 3. Routes each valid event through the camera control pipeline\n * 4. Broadcasts events to observers via the publisher\n *\n * Called by event parsers after the state machine processes an input and produces output.\n * The method uses type guards to ensure type safety when handling dynamic output types.\n *\n * @example\n * ```typescript\n * const result = stateMachine.happens(\"scroll\", {deltaX: 0, deltaY: 10, x: 100, y: 200});\n * orchestrator.processInputEventOutput(result.output);\n * ```\n */\n public processInputEventOutput(output: any): void {\n // Handle different output types\n if (this.isOutputEvent(output)) {\n this.handleStateMachineOutput(output);\n } else if (Array.isArray(output)) {\n // Handle multiple outputs\n output.forEach(item => {\n if (this.isOutputEvent(item)) {\n this.handleStateMachineOutput(item);\n }\n });\n }\n }\n\n public processInputEvent(input: OutputEvent): void {\n this.handleStateMachineOutput(input);\n }\n\n /**\n * Type guard to check if an output value is a valid OutputEvent.\n *\n * @param output - The value to check\n * @returns True if the output is a valid OutputEvent with a type property\n *\n * @remarks\n * This type guard ensures type safety when processing state machine outputs.\n * It checks for the presence of a 'type' property which is common to all OutputEvent variants.\n */\n private isOutputEvent(output: any): output is OutputEvent {\n return output && typeof output === 'object' && 'type' in output;\n }\n\n /**\n * Handles individual output events from state machines by routing to camera control and observers.\n *\n * @param event - The output event from a state machine (pan, zoom, rotate, cursor, or none)\n *\n * @remarks\n * This method implements a dual-path architecture:\n *\n * **Parallel Path 1 - Observer Notification**:\n * - Immediately broadcasts the event to all subscribers via UserInputPublisher\n * - This allows external systems to react to user input in real-time\n * - Independent of camera permission/execution\n *\n * **Parallel Path 2 - Camera Control**:\n * - Requests permission from CameraMux for the operation\n * - CameraMux may modify the event (e.g., clamp values, deny operation)\n * - If permitted, executes the transformation on CameraRig\n *\n * Event types:\n * - **pan**: Translates the camera viewport\n * - **zoom**: Scales the camera around an anchor point\n * - **rotate**: Rotates the camera view\n * - **cursor**: Changes cursor appearance (handled by state machine)\n * - **none**: No operation needed\n */\n private handleStateMachineOutput(event: OutputEvent): void {\n switch (event.type) {\n case \"pan\":\n // Publish to observers (parallel path)\n this._publisher?.notifyPan(event.delta);\n // Ask CameraMux for permission and process its output\n const panOutput = this._cameraMux.notifyPanInput(event.delta);\n this.processPanMuxOutput(panOutput);\n break;\n case \"zoom\":\n // Publish to observers (parallel path)\n this._publisher?.notifyZoom(event.delta, event.anchorPointInViewPort);\n // Ask CameraMux for permission and process its output\n const zoomOutput = this._cameraMux.notifyZoomInput(event.delta, event.anchorPointInViewPort);\n this.processZoomMuxOutput(zoomOutput);\n break;\n case \"rotate\":\n // Publish to observers (parallel path)\n this._publisher?.notifyRotate(event.deltaRotation);\n // Ask CameraMux for permission and process its output\n const rotateOutput = this._cameraMux.notifyRotationInput(event.deltaRotation);\n this.processRotateMuxOutput(rotateOutput);\n break;\n case \"cursor\":\n // Cursor changes are handled by the state machine's uponEnter/beforeExit methods\n // This case is here for future extension\n break;\n case \"none\":\n // No action needed\n break;\n }\n }\n\n /**\n * Processes pan output from CameraMux and executes the pan operation if permitted.\n *\n * @param output - The pan output from CameraMux containing permission and potentially modified delta\n *\n * @remarks\n * CameraMux may deny the operation (allowPassThrough = false) or modify the delta value\n * to enforce constraints like viewport bounds or animation states.\n * Only when permission is granted does the pan execute on CameraRig.\n */\n private processPanMuxOutput(output: CameraMuxPanOutput): void {\n if (output.allowPassThrough) {\n this._cameraRig.panByViewPort(output.delta);\n }\n }\n\n /**\n * Processes zoom output from CameraMux and executes the zoom operation if permitted.\n *\n * @param output - The zoom output from CameraMux containing permission and potentially modified parameters\n *\n * @remarks\n * CameraMux may deny the operation or modify zoom parameters to enforce constraints\n * like minimum/maximum zoom levels or animation states. The anchor point determines\n * the center of the zoom transformation in viewport coordinates.\n */\n private processZoomMuxOutput(output: CameraMuxZoomOutput): void {\n if (output.allowPassThrough) {\n this._cameraRig.zoomByAt(output.delta, output.anchorPoint);\n }\n }\n\n /**\n * Processes rotation output from CameraMux and executes the rotation operation if permitted.\n *\n * @param output - The rotation output from CameraMux containing permission and potentially modified delta\n *\n * @remarks\n * CameraMux may deny the operation or modify the rotation delta to enforce constraints\n * like rotation limits or animation states.\n */\n private processRotateMuxOutput(output: CameraMuxRotationOutput): void {\n if (output.allowPassThrough) {\n this._cameraRig.rotateBy(output.delta);\n }\n }\n\n /**\n * Gets the UserInputPublisher for direct access to event subscription.\n *\n * @returns The publisher instance, or undefined if not configured\n *\n * @remarks\n * Allows external code to subscribe to raw input events without going through the orchestrator.\n */\n get publisher(): UserInputPublisher | undefined {\n return this._publisher;\n }\n\n /**\n * Gets the CameraMux instance for direct access to permission control.\n *\n * @returns The camera multiplexer instance\n */\n get cameraMux(): CameraMux {\n return this._cameraMux;\n }\n\n /**\n * Sets a new CameraMux instance.\n *\n * @param cameraMux - The new camera multiplexer to use for permission control\n *\n * @remarks\n * Allows dynamic reconfiguration of camera permission logic at runtime.\n */\n set cameraMux(cameraMux: CameraMux){\n this._cameraMux = cameraMux;\n }\n}\n",
44
- "import { ObservableBoardCamera } from '../camera/interface';\nimport DefaultBoardCamera from '../camera/default-camera';\nimport { halfTranslationHeightOf, halfTranslationWidthOf } from '../camera/utils/position';\nimport { KMTEventParser, VanillaKMTEventParser } from '../input-interpretation/raw-input-parser';\nimport { TouchEventParser, VanillaTouchEventParser } from '../input-interpretation/raw-input-parser';\nimport { Point } from '@ue-too/math';\nimport { reverseYAxis } from '../utils';\nimport { PointCal } from '@ue-too/math';\n\nimport { CameraEventMap, CameraState, UnSubscribe } from '../camera/update-publisher';\nimport { minZoomLevelBaseOnDimensions, minZoomLevelBaseOnWidth, zoomLevelBoundariesShouldUpdate } from '../utils';\nimport { UnsubscribeToUserRawInput, RawUserInputEventMap, RawUserInputPublisher } from '../input-interpretation/raw-input-publisher';\n\nimport { CameraMux, createCameraMuxWithAnimationAndLock } from '../camera/camera-mux';\nimport { CameraRig, DefaultCameraRig } from '../camera/camera-rig';\nimport { CanvasDimensions, CanvasProxy, createKmtInputStateMachine, createTouchInputStateMachine, ObservableInputTracker, TouchInputTracker } from '../input-interpretation/input-state-machine';\nimport { InputOrchestrator } from '../input-interpretation/input-orchestrator';\n\n/**\n * Main user-facing API class that provides an infinite canvas with pan, zoom, and rotate capabilities.\n *\n * The Board class is the primary entry point for using the board package. It integrates all subsystems\n * including camera management, input handling, and state machines into a simple, unified API for\n * creating interactive 2D canvases with advanced camera controls.\n *\n * @remarks\n * ## Architecture Overview\n *\n * The Board class orchestrates several subsystems:\n *\n * - **Camera System**: Manages viewport transformations (pan/zoom/rotate) through {@link ObservableBoardCamera}.\n * The camera can be configured with boundaries, zoom limits, and various movement constraints.\n *\n * - **Input System**: Processes user input through state machines for both mouse/keyboard/trackpad (KMT)\n * and touch events. Input is parsed, interpreted, and translated into camera movements.\n *\n * - **Camera Rig**: Enforces constraints and restrictions on camera movement (boundaries, zoom limits,\n * clamping behavior). See {@link CameraRig} for details.\n *\n * - **Camera Multiplexer**: Coordinates between different camera control sources (user input, animations,\n * programmatic control) to ensure smooth transitions. See {@link CameraMux} for details.\n *\n * ## Coordinate Systems\n *\n * The Board supports three coordinate systems:\n *\n * 1. **World Coordinates**: The infinite canvas space where your content lives. When the camera is at\n * position (0, 0) with no zoom or rotation, world coordinates map directly to viewport coordinates.\n *\n * 2. **Viewport Coordinates**: The visible area of the canvas relative to the camera center. The camera\n * center is at (0, 0) in viewport space, with coordinates extending in both directions based on the\n * canvas size.\n *\n * 3. **Window/Canvas Coordinates**: The browser's coordinate system, with (0, 0) at the top-left corner\n * of the canvas element. Use {@link convertWindowPoint2WorldCoord} to convert from window to world space.\n *\n * By default, {@link alignCoordinateSystem} is `true`, which means the Y-axis points down (standard HTML\n * canvas orientation). Set it to `false` to use a mathematical coordinate system where Y points up.\n *\n * ## Main Features\n *\n * - **Camera Control**: Pan, zoom, and rotate the viewport through user input or programmatic API\n * - **Boundaries**: Define world-space boundaries to constrain camera movement\n * - **Zoom Limits**: Set minimum and maximum zoom levels\n * - **Input Modes**: Support for mouse/keyboard/trackpad and touch input with customizable parsers\n * - **Event System**: Subscribe to camera events (pan, zoom, rotate) and input events\n * - **Coordinate Conversion**: Convert between window and world coordinates\n * - **Flexible Configuration**: Extensive options for restricting/clamping camera movement\n *\n * @example\n * Basic setup with drawing\n * ```typescript\n * const canvasElement = document.querySelector(\"canvas\") as HTMLCanvasElement;\n * const board = new Board(canvasElement);\n *\n * function draw(timestamp: number) {\n * board.step(timestamp);\n *\n * // Because board can be initialized without a canvas element,\n * // the context can be undefined until the canvas is attached\n * if(board.context == undefined) {\n * return;\n * }\n *\n * // Draw after the board has stepped\n * // The coordinate system has (0, 0) at the center of the canvas when camera position is at (0, 0)\n * board.context.beginPath();\n * board.context.rect(0, 0, 100, 100);\n * board.context.fill();\n *\n * requestAnimationFrame(draw);\n * }\n *\n * requestAnimationFrame(draw);\n * ```\n *\n * @example\n * Handling camera and input events\n * ```typescript\n * const board = new Board(canvasElement);\n *\n * // Listen to camera pan events\n * board.on('pan', (event, cameraState) => {\n * console.log('Camera panned to:', cameraState.position);\n * });\n *\n * // Listen to camera zoom events\n * board.on('zoom', (event, cameraState) => {\n * console.log('Camera zoom level:', cameraState.zoomLevel);\n * });\n *\n * // Listen to raw input events (before camera movement)\n * board.onInput('pan', (event) => {\n * console.log('User is panning');\n * });\n * ```\n *\n * @example\n * Configuring boundaries and zoom limits\n * ```typescript\n * const board = new Board(canvasElement);\n *\n * // Set world boundaries\n * board.camera.boundaries = {\n * min: { x: -1000, y: -1000 },\n * max: { x: 1000, y: 1000 }\n * };\n *\n * // Set zoom limits\n * board.camera.setMinZoomLevel(0.1);\n * board.camera.setMaxZoomLevel(5.0);\n *\n * // Ensure entire viewport stays within boundaries\n * board.limitEntireViewPort = true;\n *\n * // Clamp camera position to boundaries\n * board.clampTranslation = true;\n * board.clampZoom = true;\n * ```\n *\n * @example\n * Converting window coordinates to world coordinates\n * ```typescript\n * const board = new Board(canvasElement);\n *\n * canvasElement.addEventListener('click', (event) => {\n * const windowPoint = { x: event.clientX, y: event.clientY };\n * const worldPoint = board.convertWindowPoint2WorldCoord(windowPoint);\n * console.log('Clicked at world position:', worldPoint);\n * });\n * ```\n *\n * @example\n * Using fullscreen mode\n * ```typescript\n * const board = new Board();\n * board.fullScreen = true; // Canvas will resize with window\n *\n * // Attach canvas later\n * const canvasElement = document.createElement('canvas');\n * document.body.appendChild(canvasElement);\n * board.attach(canvasElement);\n * ```\n *\n * @category Board\n * @see {@link ObservableBoardCamera} for camera API details\n * @see {@link CameraRig} for camera constraint configuration\n * @see {@link CameraMux} for camera control coordination\n */\nexport default class Board {\n \n private _context?: CanvasRenderingContext2D;\n private _reversedContext?: CanvasRenderingContext2D;\n private _canvasProxy: CanvasProxy;\n\n private _kmtParser: KMTEventParser;\n private _touchParser: TouchEventParser;\n\n private _alignCoordinateSystem: boolean = true;\n private _fullScreen: boolean = false;\n \n private cameraRig: CameraRig;\n private _cameraMux: CameraMux;\n private boardInputPublisher: RawUserInputPublisher;\n private _observableInputTracker: ObservableInputTracker;\n private _touchInputTracker: TouchInputTracker;\n private _inputOrchestrator: InputOrchestrator;\n\n private _cachedCanvasWidth: number = 0;\n private _cachedCanvasHeight: number = 0;\n\n private lastUpdateTime: number = 0;\n\n /**\n * Creates a new Board instance with an optional canvas element.\n *\n * The constructor initializes all subsystems including the camera, input parsers, state machines,\n * and event publishers. The board can be created with or without a canvas element - if no canvas\n * is provided, you can attach one later using {@link attach}.\n *\n * @param canvas - Optional HTMLCanvasElement to attach to the board. If provided, the board will\n * immediately initialize with this canvas. If omitted, you must call {@link attach} before the\n * board can be used.\n * @param debug - Optional debug flag that enables `willReadFrequently` hint on the canvas context,\n * which optimizes the canvas for frequent readback operations. Default is `false`. Only use this\n * if you need to frequently read pixel data from the canvas.\n *\n * @remarks\n * ## Initialization Sequence\n *\n * When the constructor is called, it performs the following initialization:\n *\n * 1. **Camera Setup**: Creates a {@link DefaultBoardCamera} with default boundaries of ±50,000 units\n * in both X and Y directions. This provides a large working area for most use cases.\n *\n * 2. **Canvas Proxy**: Initializes a {@link CanvasProxy} that observes canvas dimension changes and\n * automatically updates the camera's viewport dimensions.\n *\n * 3. **Camera Rig**: Creates a {@link CameraRig} with default configuration:\n * - `limitEntireViewPort: true` - Entire viewport is constrained within boundaries\n * - `clampTranslation: true` - Camera position is clamped to boundaries\n * - `clampZoom: true` - Zoom level is clamped to min/max limits\n * - All translation restrictions are disabled by default\n *\n * 4. **Input System**: Initializes both keyboard/mouse/trackpad (KMT) and touch input parsers,\n * state machines, and the input orchestrator that coordinates camera control.\n *\n * 5. **Canvas Attachment** (if canvas provided): If a canvas element is provided, it's immediately\n * attached and the viewport dimensions are synchronized with the canvas size.\n *\n * ## Default Configuration\n *\n * The board is created with sensible defaults:\n * - World boundaries: (-50000, -50000) to (50000, 50000)\n * - Coordinate system: Aligned with HTML canvas (Y-axis points down)\n * - Camera position: (0, 0)\n * - Zoom level: 1.0\n * - Rotation: 0 radians\n * - Full screen: disabled\n *\n * You can customize these defaults after construction by setting properties on the board or camera.\n *\n * @example\n * Create board with canvas element\n * ```typescript\n * const canvas = document.querySelector('canvas') as HTMLCanvasElement;\n * const board = new Board(canvas);\n * // Board is ready to use immediately\n * ```\n *\n * @example\n * Create board without canvas, attach later\n * ```typescript\n * const board = new Board();\n * // ... later, when canvas is ready\n * const canvas = document.createElement('canvas');\n * document.body.appendChild(canvas);\n * board.attach(canvas);\n * ```\n *\n * @example\n * Enable debug mode for pixel readback\n * ```typescript\n * const board = new Board(canvas, true);\n * // Now getImageData() and similar operations will be optimized\n * ```\n *\n * @group LifeCycle\n * @see {@link attach} for attaching a canvas after construction\n * @see {@link tearDown} for cleanup when done with the board\n */\n constructor(canvas?: HTMLCanvasElement, debug: boolean = false){\n const camera = new DefaultBoardCamera();\n const bound = 50000;\n camera.boundaries = {min: {x: -bound, y: -bound}, max: {x: bound, y: bound}};\n\n this.bindFunctions();\n\n this._canvasProxy = new CanvasProxy(canvas);\n\n this._canvasProxy.subscribe((canvasDimensions)=>{\n this.syncViewPortDimensions(canvasDimensions);\n this.syncCameraZoomLevel(canvasDimensions);\n });\n\n this.cameraRig = new DefaultCameraRig({\n limitEntireViewPort: true,\n restrictRelativeXTranslation: false,\n restrictRelativeYTranslation: false,\n restrictXTranslation: false,\n restrictYTranslation: false,\n restrictZoom: false,\n clampTranslation: true,\n clampZoom: true,\n }, camera);\n\n this._cameraMux = createCameraMuxWithAnimationAndLock();\n this.boardInputPublisher = new RawUserInputPublisher();\n\n // this._edgeAutoCameraInput = new EdgeAutoCameraInput(this._cameraMux);\n this._observableInputTracker = new ObservableInputTracker(this._canvasProxy);\n this._touchInputTracker = new TouchInputTracker(this._canvasProxy);\n\n const kmtInputStateMachine = createKmtInputStateMachine(this._observableInputTracker);\n const touchInputStateMachine = createTouchInputStateMachine(this._touchInputTracker);\n\n // Create single orchestrator as the point of camera control for both KMT and touch inputs\n // Since both state machines output the same event types (pan, zoom), one orchestrator handles both\n // Orchestrator receives CameraRig to execute camera operations when CameraMux allows passthrough\n this._inputOrchestrator = new InputOrchestrator(this._cameraMux, this.cameraRig, this.boardInputPublisher);\n\n // Parsers have direct dependency on state machines, shared orchestrator processes outputs and controls camera\n this._kmtParser = new VanillaKMTEventParser(kmtInputStateMachine, this._inputOrchestrator, canvas);\n this._touchParser = new VanillaTouchEventParser(touchInputStateMachine, this._inputOrchestrator, canvas);\n\n if(canvas != undefined){\n console.log('canvas exists on creation of board');\n this.attach(canvas, debug);\n this.syncViewPortDimensions({width: canvas.width, height: canvas.height});\n }\n }\n\n private syncViewPortDimensions(canvasDimensions: {width: number, height: number}){\n this.camera.viewPortHeight = canvasDimensions.height;\n this.camera.viewPortWidth = canvasDimensions.width;\n }\n\n /**\n * Attaches a canvas element to the board, enabling rendering and input handling.\n *\n * This method connects a canvas element to the board's rendering and input systems. It must be\n * called before the board can be used if no canvas was provided to the constructor. If a canvas\n * was already attached, this method will replace it with the new canvas.\n *\n * @param canvas - The HTMLCanvasElement to attach to the board. This canvas will be used for\n * rendering and will receive all input events.\n * @param debug - Optional debug flag that enables `willReadFrequently` hint on the canvas context.\n * Default is `false`. Set to `true` if you need to frequently read pixel data from the canvas,\n * which will optimize the context for readback operations.\n *\n * @remarks\n * When a canvas is attached, the following happens:\n *\n * 1. **Context Creation**: A 2D rendering context is obtained from the canvas with the specified\n * debug settings.\n *\n * 2. **Input Parser Attachment**: Both KMT (keyboard/mouse/trackpad) and touch input parsers are\n * attached to the canvas to begin receiving input events.\n *\n * 3. **Canvas Proxy Attachment**: The canvas proxy begins observing the canvas for dimension changes,\n * automatically updating the camera's viewport dimensions when the canvas is resized.\n *\n * 4. **Zoom Level Synchronization**: If {@link limitEntireViewPort} is enabled, the minimum zoom\n * level is calculated and set to ensure the entire viewport can fit within the camera boundaries.\n *\n * 5. **Coordinate System Setup**: Both standard and Y-reversed rendering contexts are created to\n * support both coordinate system modes (see {@link alignCoordinateSystem}).\n *\n * @example\n * Attach canvas during construction\n * ```typescript\n * const canvas = document.querySelector('canvas') as HTMLCanvasElement;\n * const board = new Board(canvas);\n * // No need to call attach() - already attached\n * ```\n *\n * @example\n * Attach canvas after construction\n * ```typescript\n * const board = new Board();\n *\n * // Later, when canvas is ready...\n * const canvas = document.createElement('canvas');\n * canvas.width = 800;\n * canvas.height = 600;\n * document.body.appendChild(canvas);\n *\n * board.attach(canvas);\n * // Board is now ready to use\n * ```\n *\n * @example\n * Switch to a different canvas\n * ```typescript\n * const board = new Board(canvas1);\n *\n * // Later, switch to a different canvas\n * const canvas2 = document.querySelector('#other-canvas') as HTMLCanvasElement;\n * board.attach(canvas2);\n * // Board is now rendering to canvas2\n * ```\n *\n * @group LifeCycle\n * @see {@link tearDown} for detaching and cleaning up\n * @see {@link context} for accessing the rendering context\n */\n attach(canvas: HTMLCanvasElement, debug: boolean = false){\n const newContext = canvas.getContext('2d', {willReadFrequently: debug});\n if(newContext == null){\n console.error(\"new canvas context is null\");\n return;\n }\n this._kmtParser.attach(canvas);\n this._touchParser.attach(canvas);\n this._canvasProxy.attach(canvas);\n\n if(this.limitEntireViewPort) {\n this.syncCameraZoomLevel(this._canvasProxy.dimensions);\n }\n\n this._context = newContext;\n this._reversedContext = reverseYAxis(this._context);\n }\n\n disableEventListeners(){\n this._kmtParser.tearDown();\n this._touchParser.tearDown();\n }\n\n enableEventListeners(){\n this._kmtParser.setUp();\n this._touchParser.setUp();\n }\n\n get inputOrchestrator(): InputOrchestrator{\n return this._inputOrchestrator;\n }\n\n /**\n * @group LifeCycle\n * @description This function is used to clean up the board. It removes all the event listeners and disconnects the resize observer and the attribute observer. \n */\n tearDown(){\n this._kmtParser.tearDown();\n this._touchParser.tearDown();\n this._canvasProxy.tearDown();\n }\n\n private bindFunctions(){\n this.step = this.step.bind(this);\n }\n\n get width(): number {\n return this._canvasProxy.width;\n }\n\n get height(): number {\n return this._canvasProxy.height;\n }\n\n /**\n * @description This is an attribute that determines if the coordinate system should be aligned with the one of the HTML canvas element. The default is true.\n * If you set this to true, the coordinate system will be aligned with the one of the HTML canvas element.\n * If you change this value during runtime, you should update the context to be aligned with the new coordinate system. (just call board.context again)\n */\n set alignCoordinateSystem(align: boolean){\n this._alignCoordinateSystem = align;\n this._observableInputTracker.alignCoordinateSystem = align;\n this._touchInputTracker.alignCoordinateSystem = align;\n }\n\n get alignCoordinateSystem(): boolean{\n return this._alignCoordinateSystem;\n }\n\n /**\n * @description Determines if the board should be full screen. If this is set to true, the width and height of the board will be set to the window's inner width and inner height respectively, \n * and the width and height of the board will resize with the window.\n */\n get fullScreen(): boolean {\n return this._fullScreen;\n }\n\n set fullScreen(value: boolean) {\n this._fullScreen = value;\n if(this._fullScreen){\n this._canvasProxy.setWidth(window.innerWidth);\n this._canvasProxy.setHeight(window.innerHeight);\n }\n }\n\n /**\n * @description The context used to draw on the canvas.\n * If alignCoordinateSystem is false, this returns a proxy that automatically negates y-coordinates for relevant drawing methods.\n */\n get context(): CanvasRenderingContext2D | undefined {\n if (!this._alignCoordinateSystem) {\n return this._reversedContext;\n }\n return this._context;\n }\n\n /**\n * @description Determines the behavior of the camera when the camera is at the edge of the boundaries. If set to true, the entire view port would not move beyond the boundaries.\n * If set to false, only the center of the camera is bounded by the boundaries.\n */\n set limitEntireViewPort(value: boolean){\n this.cameraRig.config.limitEntireViewPort = value;\n if(this._canvasProxy.detached){\n return;\n }\n if(value){\n this.syncCameraZoomLevel(this._canvasProxy.dimensions);\n }\n }\n\n get limitEntireViewPort(): boolean{\n return this.cameraRig.config.limitEntireViewPort;\n }\n\n /**\n * @description The strategy used to handle the keyboard, mouse events. The default strategy is the DefaultBoardKMTStrategy. \n * You can implement your own strategy by implementing the BoardKMTStrategy interface.\n */\n set kmtParser(parser: KMTEventParser){\n this._kmtParser.tearDown();\n parser.setUp();\n this._kmtParser = parser;\n }\n\n get kmtParser(): KMTEventParser{\n return this._kmtParser;\n }\n\n /**\n * @description The parser used to handle touch events. The default parser is the DefaultTouchParser.\n * You can have your own parser by implementing the BoardTouchParser interface.\n */\n set touchParser(parser: TouchEventParser){\n this._touchParser.tearDown();\n parser.setUp();\n this._touchParser = parser;\n }\n\n get touchParser(): TouchEventParser{\n return this._touchParser;\n }\n\n /**\n * @description The underlying camera of the board. The camera of the board can be switched.\n * The boundaries are based on camera meaning you can have cameras with different boundaries, and you can switch between them during runtime.\n */\n get camera(): ObservableBoardCamera{\n return this.cameraRig.camera;\n }\n\n set camera(camera: ObservableBoardCamera){\n if(!this._canvasProxy.detached){\n camera.viewPortHeight = this._canvasProxy.height / window.devicePixelRatio;\n camera.viewPortWidth = this._canvasProxy.width / window.devicePixelRatio;\n }\n this.cameraRig.camera = camera;\n }\n\n get cameraMux(): CameraMux{\n return this._cameraMux;\n }\n\n set cameraMux(cameraMux: CameraMux){\n this._cameraMux = cameraMux;\n // Update all components that depend on cameraMux\n // Note: TouchInputTracker and Orchestrator would need to be recreated or have setter methods\n\n // input orchestrator\n this._inputOrchestrator.cameraMux = cameraMux;\n }\n\n /**\n * @description This is the step function that is called in the animation frame. This function is responsible for updating the canvas context and the camera state.\n * @param timestamp \n */\n public step(timestamp: number){\n if(this._canvasProxy.detached || this._context == undefined){\n return;\n }\n\n this.cameraRig.update();\n let deltaTime = timestamp - this.lastUpdateTime;\n this.lastUpdateTime = timestamp;\n deltaTime = deltaTime / 1000;\n\n this._context.reset();\n this._context.clearRect(0, 0, this._canvasProxy.width * window.devicePixelRatio, this._canvasProxy.height * window.devicePixelRatio);\n\n if(this._fullScreen && (this._canvasProxy.width != window.innerWidth || this._canvasProxy.height != window.innerHeight)){\n this._canvasProxy.setWidth(window.innerWidth);\n this._canvasProxy.setHeight(window.innerHeight);\n } else {\n if(this._cachedCanvasWidth !== this._canvasProxy.width){\n this._cachedCanvasWidth = this._canvasProxy.width;\n this._canvasProxy.setCanvasWidth(this._canvasProxy.width);\n }\n if(this._cachedCanvasHeight !== this._canvasProxy.height){\n this._cachedCanvasHeight = this._canvasProxy.height;\n this._canvasProxy.setCanvasHeight(this._canvasProxy.height);\n }\n }\n\n\n const transfromMatrix = this.camera.getTransform(window.devicePixelRatio, this._alignCoordinateSystem);\n this._context.setTransform(transfromMatrix.a, transfromMatrix.b, transfromMatrix.c, transfromMatrix.d, transfromMatrix.e, transfromMatrix.f);\n }\n\n /**\n * TODO add the option to make the camera position to be at the top left corner of the canvas; or better yet any point in the viewport (within the viewport boundaries)\n * @description Converts a point from window coordinates to world coordinates.\n * @param clickPointInWindow The point in window coordinates to convert.\n * @returns The converted point in world coordinates.\n */\n convertWindowPoint2WorldCoord(clickPointInWindow: Point): Point {\n const boundingRect = this._canvasProxy.dimensions;\n const cameraCenterInWindow = {x: boundingRect.position.x + boundingRect.width / 2, y: boundingRect.position.y + boundingRect.height / 2};\n const pointInViewPort = PointCal.subVector(clickPointInWindow, cameraCenterInWindow);\n if(!this._alignCoordinateSystem){\n pointInViewPort.y = -pointInViewPort.y;\n }\n return this.camera.convertFromViewPort2WorldSpace(pointInViewPort);\n }\n\n /**\n * @description Add an camera movement event listener. The events are \"pan\", \"zoom\", and \"rotate\".\n * There's also an \"all\" event that will be triggered when any of the above events are triggered.\n * @param eventName The event name to listen for. The events are \"pan\", \"zoom\", and \"rotate\".\n * @param callback The callback function to call when the event is triggered. The event provided to the callback is different for the different events.\n * @returns The converted point in world coordinates.\n */\n on<K extends keyof CameraEventMap>(eventName: K, callback: (event: CameraEventMap[K], cameraState: CameraState)=>void): UnSubscribe {\n return this.camera.on(eventName, callback);\n }\n\n /**\n * @description Add an input event listener. The events are \"pan\", \"zoom\", and \"rotate\". This is different from the camera event listener as this is for input events. \n * There's also an \"all\" event that will be triggered when any of the above events are triggered.\n * Input event does not necesarily mean that the camera will move. The input events are the events triggered when the user interacts with the board.\n * @param eventName \n * @param callback \n * @returns \n */\n onInput<K extends keyof RawUserInputEventMap>(eventName: K, callback: (event: RawUserInputEventMap[K])=> void): UnsubscribeToUserRawInput {\n return this.boardInputPublisher.on(eventName, callback);\n }\n\n /**\n * @description The max translation height of the camera. This is the maximum distance the camera can move in the vertical direction.\n */\n get maxHalfTransHeight(): number | undefined{\n return halfTranslationHeightOf(this.camera.boundaries);\n }\n\n /**\n * @description The max translation width of the camera. This is the maximum distance the camera can move in the horizontal direction.\n */\n get maxHalfTransWidth(): number | undefined{\n return halfTranslationWidthOf(this.camera.boundaries);\n }\n\n private syncCameraZoomLevel(canvasDimensions: CanvasDimensions){\n if(this.limitEntireViewPort){\n const targetMinZoomLevel = minZoomLevelBaseOnDimensions(this.camera.boundaries, canvasDimensions.width, canvasDimensions.height, this.camera.rotation);\n if(targetMinZoomLevel != undefined && zoomLevelBoundariesShouldUpdate(this.camera.zoomBoundaries, targetMinZoomLevel)){\n this.camera.setMinZoomLevel(targetMinZoomLevel);\n }\n }\n\n }\n\n /**\n * @group Helper Methods\n * @description This function sets the max translation width of the camera while fixing the minimum x boundary.\n */\n setMaxTransWidthWithFixedMinBoundary(value: number){\n const curBoundaries = this.camera.boundaries;\n const curMin = curBoundaries == undefined ? undefined: curBoundaries.min;\n const curHorizontalMin = curMin == undefined ? undefined: curMin.x;\n if(curHorizontalMin == undefined){\n this.camera.setHorizontalBoundaries(-value, value);\n } else {\n this.camera.setHorizontalBoundaries(curHorizontalMin, curHorizontalMin + value * 2);\n }\n if(this.limitEntireViewPort){\n const targetMinZoomLevel = minZoomLevelBaseOnWidth(this.camera.boundaries, this.camera.viewPortWidth, this.camera.viewPortHeight, this.camera.rotation);\n if(zoomLevelBoundariesShouldUpdate(this.camera.zoomBoundaries, targetMinZoomLevel)){\n this.camera.setMinZoomLevel(targetMinZoomLevel);\n }\n }\n }\n\n /**\n * @group Helper Methods\n * @description This function sets the max translation width of the camera while fixing the minimum x boundary.\n */\n setMaxTransWidthWithFixedMaxBoundary(value: number){\n const curBoundaries = this.camera.boundaries;\n const curMax = curBoundaries == undefined ? undefined: curBoundaries.max;\n const curHorizontalMax = curMax == undefined ? undefined: curMax.x;\n if(curHorizontalMax == undefined){\n this.camera.setHorizontalBoundaries(-value, value);\n } else {\n this.camera.setHorizontalBoundaries(curHorizontalMax - value * 2, curHorizontalMax);\n }\n if(this.limitEntireViewPort){\n const targetMinZoomLevel = minZoomLevelBaseOnWidth(this.camera.boundaries, this.camera.viewPortWidth, this.camera.viewPortHeight, this.camera.rotation);\n if(zoomLevelBoundariesShouldUpdate(this.camera.zoomBoundaries, targetMinZoomLevel)){\n this.camera.setMinZoomLevel(targetMinZoomLevel);\n }\n }\n }\n\n get restrictRelativeXTranslation(): boolean{\n return this.cameraRig.config.restrictRelativeXTranslation;\n }\n\n get restrictRelativeYTranslation(): boolean{\n return this.cameraRig.config.restrictRelativeYTranslation;\n }\n\n get restrictXTranslation(): boolean{\n return this.cameraRig.config.restrictXTranslation;\n }\n\n get restrictYTranslation(): boolean{\n return this.cameraRig.config.restrictYTranslation;\n }\n \n set restrictRelativeXTranslation(value: boolean){\n this.cameraRig.config.restrictRelativeXTranslation = value;\n }\n\n set restrictRelativeYTranslation(value: boolean){\n this.cameraRig.configure({restrictRelativeYTranslation: value});\n }\n\n set restrictXTranslation(value: boolean){\n this.cameraRig.configure({restrictXTranslation: value});\n }\n \n set restrictYTranslation(value: boolean){\n this.cameraRig.configure({restrictYTranslation: value});\n }\n\n get restrictZoom(): boolean{\n return this.cameraRig.config.restrictZoom;\n }\n\n set restrictZoom(value: boolean){\n this.cameraRig.configure({restrictZoom: value});\n }\n\n get restrictRotation(): boolean{\n return this.cameraRig.config.restrictRotation;\n }\n\n set restrictRotation(value: boolean){\n this.cameraRig.configure({restrictRotation: value});\n }\n\n get clampTranslation(): boolean{\n return this.cameraRig.config.clampTranslation;\n }\n\n set clampTranslation(value: boolean){\n this.cameraRig.configure({clampTranslation: value});\n }\n \n get clampZoom(): boolean{\n return this.cameraRig.config.clampZoom;\n }\n\n set clampZoom(value: boolean){\n this.cameraRig.configure({clampZoom: value});\n }\n\n get clampRotation(): boolean{\n return this.cameraRig.config.clampRotation;\n }\n\n set clampRotation(value: boolean){\n this.cameraRig.configure({clampRotation: value});\n }\n\n getCameraRig(): CameraRig {\n return this.cameraRig;\n }\n\n setInputMode(mode: 'kmt' | 'trackpad'): void {\n this._observableInputTracker.setMode(mode);\n }\n\n onCanvasDimensionChange(callback: (dimensions: CanvasDimensions) => void) {\n return this._canvasProxy.subscribe(callback);\n }\n\n get canvasDimensions(): CanvasDimensions {\n return this._canvasProxy.dimensions;\n }\n}\n",
45
- "import { provide, inject, watch, onMounted, onUnmounted, computed, type ShallowRef, shallowRef } from \"vue\";\nimport { Board, CameraMux, CameraState } from \"@ue-too/board\";\nimport { type Ref } from \"vue\";\n\nexport const BOARD_SYMBOL = Symbol(\"BOARD\");\n\nexport function provideBoard() {\n provide(BOARD_SYMBOL, new Board());\n}\n\nexport function useBoard() {\n const board = inject<Board>(BOARD_SYMBOL);\n if (!board) {\n throw new Error(\n \"Board not found, are you using useBoard in a component that is not a child of a board provider?\"\n );\n }\n return board;\n}\n\nexport function useCustomCameraMux(cameraMux: CameraMux) {\n const board = useBoard();\n watch(\n () => cameraMux,\n (newMux) => {\n board.cameraMux = newMux;\n },\n { immediate: true }\n );\n}\n\nexport function useCameraState<K extends keyof CameraState>(state: K): ShallowRef<CameraState[K]>{\n const board = useBoard();\n const initialState: CameraState[K] = board.camera[state];\n const stateValue = shallowRef<CameraState[K]>(initialState);\n board.camera.on(state === \"position\" ? \"pan\" : state === \"zoomLevel\" ? \"zoom\" : \"rotate\", (newState, cameraState) => {\n stateValue.value = cameraState[state];\n });\n return stateValue as ShallowRef<CameraState[K]>;\n}\n\n\n/**\n * Hook to run a callback on every animation frame.\n * \n * @param callback - Function to call on each animation frame, receives the current timestamp\n */\nexport function useAnimationFrame(callback?: (timestamp: number) => void) {\n let animationFrameId: number | null = null;\n\n const step = (timestamp: number) => {\n callback?.(timestamp);\n animationFrameId = requestAnimationFrame(step);\n };\n\n onMounted(() => {\n animationFrameId = requestAnimationFrame(step);\n });\n\n onUnmounted(() => {\n if (animationFrameId !== null) {\n cancelAnimationFrame(animationFrameId);\n }\n });\n}\n\n/**\n * Hook to run an animation loop integrated with the Board's step function.\n * \n * @param callback - Optional function to call after board.step(), receives timestamp and canvas context\n */\nexport function useAnimationFrameWithBoard(\n callback?: (timestamp: number, ctx: CanvasRenderingContext2D) => void\n) {\n const board = useBoard();\n\n // Use computed to memoize the callback function (Vue's useCallback equivalent)\n const animationCallback = computed(() => {\n return (timestamp: number) => {\n board.step(timestamp);\n const ctx = board.context;\n if (ctx == undefined) {\n console.warn(\"Canvas context not available\");\n return;\n }\n callback?.(timestamp, ctx);\n };\n });\n\n useAnimationFrame((timestamp) => {\n animationCallback.value(timestamp);\n });\n}\n"
46
- ],
47
- "mappings": "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",
48
- "debugId": "CCBF64BEEE3AD23664756E2164756E21",
49
- "names": []
50
- }
1
+ {"version":3,"file":"index.js","sources":["../src/useBoard.ts","../src/board.vue","../src/Test.vue"],"sourcesContent":["import { provide, inject, watch, onMounted, onUnmounted, computed, type ShallowRef, shallowRef } from \"vue\";\nimport { Board, CameraMux, CameraState } from \"@ue-too/board\";\nimport { type Ref } from \"vue\";\n\nexport const BOARD_SYMBOL = Symbol(\"BOARD\");\n\nexport function provideBoard() {\n provide(BOARD_SYMBOL, new Board());\n}\n\nexport function useBoard() {\n const board = inject<Board>(BOARD_SYMBOL);\n if (!board) {\n throw new Error(\n \"Board not found, are you using useBoard in a component that is not a child of a board provider?\"\n );\n }\n return board;\n}\n\nexport function useCustomCameraMux(cameraMux: CameraMux) {\n const board = useBoard();\n watch(\n () => cameraMux,\n (newMux) => {\n board.cameraMux = newMux;\n },\n { immediate: true }\n );\n}\n\nexport function useCameraState<K extends keyof CameraState>(state: K): ShallowRef<CameraState[K]>{\n const board = useBoard();\n const initialState: CameraState[K] = board.camera[state];\n const stateValue = shallowRef<CameraState[K]>(initialState);\n board.camera.on(state === \"position\" ? \"pan\" : state === \"zoomLevel\" ? \"zoom\" : \"rotate\", (newState, cameraState) => {\n stateValue.value = cameraState[state];\n });\n return stateValue as ShallowRef<CameraState[K]>;\n}\n\n\n/**\n * Hook to run a callback on every animation frame.\n * \n * @param callback - Function to call on each animation frame, receives the current timestamp\n */\nexport function useAnimationFrame(callback?: (timestamp: number) => void) {\n let animationFrameId: number | null = null;\n\n const step = (timestamp: number) => {\n callback?.(timestamp);\n animationFrameId = requestAnimationFrame(step);\n };\n\n onMounted(() => {\n animationFrameId = requestAnimationFrame(step);\n });\n\n onUnmounted(() => {\n if (animationFrameId !== null) {\n cancelAnimationFrame(animationFrameId);\n }\n });\n}\n\n/**\n * Hook to run an animation loop integrated with the Board's step function.\n * \n * @param callback - Optional function to call after board.step(), receives timestamp and canvas context\n */\nexport function useAnimationFrameWithBoard(\n callback?: (timestamp: number, ctx: CanvasRenderingContext2D) => void\n) {\n const board = useBoard();\n\n // Use computed to memoize the callback function (Vue's useCallback equivalent)\n const animationCallback = computed(() => {\n return (timestamp: number) => {\n board.step(timestamp);\n const ctx = board.context;\n if (ctx == undefined) {\n console.warn(\"Canvas context not available\");\n return;\n }\n callback?.(timestamp, ctx);\n };\n });\n\n useAnimationFrame((timestamp) => {\n animationCallback.value(timestamp);\n });\n}\n","<script setup lang=\"ts\">\nimport { ref, onMounted } from \"vue\";\nimport { useAnimationFrameWithBoard, useBoard } from \"./useBoard\";\nimport { Board } from \"@ue-too/board\";\n\nconst canvas = ref<HTMLCanvasElement | null>(null);\nconst board = new Board();\n\nonMounted(() => {\n if (canvas.value) {\n board.attach(canvas.value);\n } else {\n board.tearDown();\n }\n});\n\nuseAnimationFrameWithBoard((timestamp, ctx) => {\n board.step(timestamp);\n ctx.fillStyle = \"red\";\n ctx.fillRect(0, 0, 100, 100);\n});\n</script>\n\n<template>\n <canvas ref=\"canvas\"> Your browser does not support the canvas tag. </canvas>\n</template>\n","<template>\n <div>Test</div>\n</template>\n\n<script setup lang=\"ts\">\n</script>\n"],"names":["BOARD_SYMBOL","provideBoard","provide","Board","useBoard","board","inject","useCustomCameraMux","cameraMux","watch","newMux","useCameraState","state","initialState","stateValue","shallowRef","newState","cameraState","useAnimationFrame","callback","animationFrameId","step","timestamp","onMounted","onUnmounted","useAnimationFrameWithBoard","animationCallback","computed","ctx","canvas","ref","_createElementBlock","_openBlock"],"mappings":";;AAIO,MAAMA,IAAe,OAAO,OAAO;AAEnC,SAASC,IAAe;AAC7B,EAAAC,EAAQF,GAAc,IAAIG,GAAO;AACnC;AAEO,SAASC,IAAW;AACzB,QAAMC,IAAQC,EAAcN,CAAY;AACxC,MAAI,CAACK;AACH,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAGJ,SAAOA;AACT;AAEO,SAASE,EAAmBC,GAAsB;AACvD,QAAMH,IAAQD,EAAA;AACd,EAAAK;AAAA,IACE,MAAMD;AAAA,IACN,CAACE,MAAW;AACV,MAAAL,EAAM,YAAYK;AAAA,IACpB;AAAA,IACA,EAAE,WAAW,GAAA;AAAA,EAAK;AAEtB;AAEO,SAASC,EAA4CC,GAAqC;AAC7F,QAAMP,IAAQD,EAAA,GACRS,IAA+BR,EAAM,OAAOO,CAAK,GACjDE,IAAaC,EAA2BF,CAAY;AAC1D,SAAAR,EAAM,OAAO,GAAGO,MAAU,aAAa,QAAQA,MAAU,cAAc,SAAS,UAAU,CAACI,GAAUC,MAAgB;AACjH,IAAAH,EAAW,QAAQG,EAAYL,CAAK;AAAA,EACxC,CAAC,GACME;AACX;AAQO,SAASI,EAAkBC,GAAwC;AACxE,MAAIC,IAAkC;AAEtC,QAAMC,IAAO,CAACC,MAAsB;AAClC,IAAAH,IAAWG,CAAS,GACpBF,IAAmB,sBAAsBC,CAAI;AAAA,EAC/C;AAEA,EAAAE,EAAU,MAAM;AACd,IAAAH,IAAmB,sBAAsBC,CAAI;AAAA,EAC/C,CAAC,GAEDG,EAAY,MAAM;AAChB,IAAIJ,MAAqB,QACvB,qBAAqBA,CAAgB;AAAA,EAEzC,CAAC;AACH;AAOO,SAASK,EACdN,GACA;AACA,QAAMd,IAAQD,EAAA,GAGRsB,IAAoBC,EAAS,MAC1B,CAACL,MAAsB;AAC5B,IAAAjB,EAAM,KAAKiB,CAAS;AACpB,UAAMM,IAAMvB,EAAM;AAClB,QAAIuB,KAAO,MAAW;AACpB,cAAQ,KAAK,8BAA8B;AAC3C;AAAA,IACF;AACA,IAAAT,IAAWG,GAAWM,CAAG;AAAA,EAC3B,CACD;AAED,EAAAV,EAAkB,CAACI,MAAc;AAC/B,IAAAI,EAAkB,MAAMJ,CAAS;AAAA,EACnC,CAAC;AACH;;;;ACvFA,UAAMO,IAASC,EAA8B,IAAI,GAC3CzB,IAAQ,IAAIF,EAAA;AAElB,WAAAoB,EAAU,MAAM;AACd,MAAIM,EAAO,QACTxB,EAAM,OAAOwB,EAAO,KAAK,IAEzBxB,EAAM,SAAA;AAAA,IAEV,CAAC,GAEDoB,EAA2B,CAACH,GAAWM,MAAQ;AAC7C,MAAAvB,EAAM,KAAKiB,CAAS,GACpBM,EAAI,YAAY,OAChBA,EAAI,SAAS,GAAG,GAAG,KAAK,GAAG;AAAA,IAC7B,CAAC,mBAICG,EAA6E,UAAA;AAAA,eAAjE;AAAA,MAAJ,KAAIF;AAAA,IAAA,GAAS,mDAA+C,GAAA;AAAA;;;;;;;;ACvBlE,SAAAG,EAAA,GAAAD,EAAe,aAAV,MAAI;;;"}