json-canvas-viewer 4.1.1 → 4.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/chimp.js +6 -5
  2. package/dist/index.d.ts +5 -5
  3. package/dist/index.js +1 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/kernel/BaseModule.d.ts +1 -2
  6. package/dist/kernel/BaseModule.js.map +1 -1
  7. package/dist/kernel/Controller.d.ts +12 -12
  8. package/dist/kernel/Controller.js +1 -1
  9. package/dist/kernel/Controller.js.map +1 -1
  10. package/dist/kernel/DataManager.d.ts +15 -15
  11. package/dist/kernel/DataManager.js +1 -1
  12. package/dist/kernel/DataManager.js.map +1 -1
  13. package/dist/kernel/InteractionHandler.d.ts +16 -16
  14. package/dist/kernel/InteractionHandler.js +1 -1
  15. package/dist/kernel/InteractionHandler.js.map +1 -1
  16. package/dist/kernel/OverlayManager.d.ts +29 -22
  17. package/dist/kernel/OverlayManager.js +1 -1
  18. package/dist/kernel/OverlayManager.js.map +1 -1
  19. package/dist/kernel/Renderer.d.ts +23 -22
  20. package/dist/kernel/Renderer.js +2 -1
  21. package/dist/kernel/Renderer.js.map +1 -1
  22. package/dist/kernel/StyleManager.d.ts +34 -34
  23. package/dist/kernel/StyleManager.js +1 -1
  24. package/dist/kernel/StyleManager.js.map +1 -1
  25. package/dist/kernel/index.d.ts +7 -7
  26. package/dist/kernel/index.js +1 -1
  27. package/dist/kernel/index.js.map +1 -1
  28. package/dist/kernel/types.d.ts +1 -1
  29. package/dist/kernel/utilities.d.ts +1 -27
  30. package/dist/kernel/utilities.js +1 -1
  31. package/dist/kernel/utilities.js.map +1 -1
  32. package/dist/modules/Controls/index.d.ts +21 -21
  33. package/dist/modules/Controls/index.js +1 -1
  34. package/dist/modules/Controls/index.js.map +1 -1
  35. package/dist/modules/DebugPanel/index.d.ts +4 -4
  36. package/dist/modules/DebugPanel/index.js +1 -1
  37. package/dist/modules/DebugPanel/index.js.map +1 -1
  38. package/dist/modules/Minimap/index.d.ts +17 -17
  39. package/dist/modules/Minimap/index.js +1 -1
  40. package/dist/modules/Minimap/index.js.map +1 -1
  41. package/dist/modules/MistouchPreventer/index.d.ts +11 -11
  42. package/dist/modules/MistouchPreventer/index.js +1 -1
  43. package/dist/modules/MistouchPreventer/index.js.map +1 -1
  44. package/dist/shared/index.d.ts +14 -14
  45. package/dist/utilities/{fetchCanvas.d.ts → fetch-canvas.d.ts} +2 -2
  46. package/dist/utilities/{fetchCanvas.js → fetch-canvas.js} +1 -1
  47. package/dist/utilities/fetch-canvas.js.map +1 -0
  48. package/dist/utilities/{renderToString.d.ts → render-to-string.d.ts} +2 -2
  49. package/dist/utilities/render-to-string.js +2 -0
  50. package/dist/utilities/render-to-string.js.map +1 -0
  51. package/package.json +1 -1
  52. package/dist/utilities/fetchCanvas.js.map +0 -1
  53. package/dist/utilities/renderToString.js +0 -2
  54. package/dist/utilities/renderToString.js.map +0 -1
@@ -1,2 +1,2 @@
1
- import{BaseModule as e}from"./BaseModule.js";import t from"./utilities.js";import n from"./DataManager.js";import r from"./OverlayManager.js";import{Click as i,Drag as a,Lubricator as o,MultitouchPanZoom as s,Pointeract as c,PreventDefault as l,WheelPanZoom as u,lubricatorDragPreset as d,lubricatorPanPreset as f,lubricatorZoomPreset as p}from"pointeract";var m=class extends e{pointeract;DM;onClick=t.makeHook();constructor(...e){super(...e),this.DM=this.container.get(n);let t=Object.assign(this.options.pointeract??{},{coordinateOutput:`relative`,element:this.DM.data.container,lubricator:{pan:f,zoom:p,drag:d}});this.pointeract=new c(t,[i,a,u,l,s,o]);let m=this.container.get(r);m.onInteractionStart.subscribe(this.stopInteract),m.onInteractionEnd.subscribe(this.startInteract),this.augment({pan:this.pan,panToCoords:this.panToCoords,zoom:this.zoom,zoomToScale:this.zoomToScale}),this.onStart(this.start),this.onDispose(this.dispose)}start=()=>{this.pointeract.on(`pan`,this.onPan).on(`drag`,this.onPan).on(`zoom`,this.onZoom).on(`trueClick`,this.onTrueClick).start()};startInteract=()=>{this.pointeract.start()};stopInteract=()=>{this.pointeract.stop()};onPan=e=>{this.truePan({x:e.deltaX,y:e.deltaY})};onZoom=e=>{this.trueZoom(e.factor,e)};trueZoom=(e,t)=>{let n=Math.max(Math.min(this.DM.data.scale*e,20),.05);if(n===this.DM.data.scale)return;let r=n/this.DM.data.scale,i=this.C2C(t);this.DM.data.offsetX=t.x-i.x*r,this.DM.data.offsetY=t.y-i.y*r,this.DM.data.scale=n};truePan=({x:e,y:t})=>{this.DM.data.offsetX=this.DM.data.offsetX+e,this.DM.data.offsetY=this.DM.data.offsetY+t};zoom=(e,t)=>{this.pointeract.dispatch(`zoom`,{factor:e,...t})};pan=({x:e,y:t})=>{this.pointeract.dispatch(`pan`,{deltaX:e,deltaY:t})};zoomToScale=(e,t)=>{let n=e/this.DM.data.scale;this.pointeract.dispatch(`zoom`,{factor:n,...t})};panToCoords=({x:e,y:t})=>{this.pointeract.dispatch(`pan`,{deltaX:e-this.DM.data.offsetX,deltaY:t-this.DM.data.offsetY})};C2C=({x:e,y:t})=>({x:e-this.DM.data.offsetX,y:t-this.DM.data.offsetY});onTrueClick=e=>{let t=e.target;if(this.isUIControl(t))return;let n=this.findNodeId(t);this.onClick(n)};isUIControl=e=>e?e.closest(`.controls`)||e.closest(`button`)||e.closest(`input`):!1;findNodeId=e=>{if(!e)return null;let t=e;for(;(!t.id||t.id===``)&&t.parentElement;)t=t.parentElement;return t.id===`overlays`||!t.id||t.id===``?null:t.id};dispose=()=>this.pointeract.dispose()};export{m as default};
1
+ import{BaseModule as e}from"./BaseModule.js";import{makeHook as t}from"./utilities.js";import n from"./DataManager.js";import r from"./OverlayManager.js";import{Click as i,Drag as a,Lubricator as o,MultitouchPanZoom as s,Pointeract as c,PreventDefault as l,WheelPanZoom as u,lubricatorDragPreset as d,lubricatorPanPreset as f,lubricatorZoomPreset as p}from"pointeract";var m=class extends e{pointeract;DM;onClick=t();constructor(...e){super(...e),this.DM=this.container.get(n);let t=Object.assign(this.options.pointeract??{},{coordinateOutput:`relative`,element:this.DM.data.container,lubricator:{drag:d,pan:f,zoom:p}});this.pointeract=new c(t,[i,a,u,l,s,o]);let m=this.container.get(r);m.onInteractionStart.subscribe(this.stopInteract),m.onInteractionEnd.subscribe(this.startInteract),this.augment({pan:this.pan,panToCoords:this.panToCoords,zoom:this.zoom,zoomToScale:this.zoomToScale}),this.onStart(this.start),this.onDispose(this.dispose)}start=()=>{this.pointeract.on(`pan`,this.onPan).on(`drag`,this.onPan).on(`zoom`,this.onZoom).on(`trueClick`,this.onTrueClick).start()};startInteract=()=>{this.pointeract.start()};stopInteract=()=>{this.pointeract.stop()};onPan=e=>{this.truePan({x:e.deltaX,y:e.deltaY})};onZoom=e=>{this.trueZoom(e.factor,e)};trueZoom=(e,t)=>{let n=Math.max(Math.min(this.DM.data.scale*e,20),.05);if(n===this.DM.data.scale)return;let r=n/this.DM.data.scale,i=this.C2C(t);this.DM.data.offsetX=t.x-i.x*r,this.DM.data.offsetY=t.y-i.y*r,this.DM.data.scale=n};truePan=({x:e,y:t})=>{this.DM.data.offsetX+=e,this.DM.data.offsetY+=t};zoom=(e,t)=>{this.pointeract.dispatch(`zoom`,{factor:e,...t})};pan=({x:e,y:t})=>{this.pointeract.dispatch(`pan`,{deltaX:e,deltaY:t})};zoomToScale=(e,t)=>{let n=e/this.DM.data.scale;this.pointeract.dispatch(`zoom`,{factor:n,...t})};panToCoords=({x:e,y:t})=>{this.pointeract.dispatch(`pan`,{deltaX:e-this.DM.data.offsetX,deltaY:t-this.DM.data.offsetY})};C2C=({x:e,y:t})=>({x:e-this.DM.data.offsetX,y:t-this.DM.data.offsetY});onTrueClick=e=>{let t=e.target?e.target:void 0;if(this.isUIControl(t))return;let n=this.findNodeId(t);this.onClick(n)};isUIControl=e=>e?e.closest(`.controls`)||e.closest(`button`)||e.closest(`input`):!1;findNodeId=e=>{if(!e)return;let t=e;for(;(!t.id||t.id===``)&&t.parentElement;)t=t.parentElement;if(!(t.id===`overlays`||!t.id||t.id===``))return t.id};dispose=()=>this.pointeract.dispose()};export{m as default};
2
2
  //# sourceMappingURL=InteractionHandler.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"InteractionHandler.js","names":["utilities"],"sources":["../../src/kernel/InteractionHandler.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { Coordinates } from '$/types';\nimport { type BaseArgs, BaseModule } from '$/BaseModule';\nimport DataManager from '$/DataManager';\nimport OverlayManager from '$/OverlayManager';\nimport utilities from '$/utilities';\nimport {\n\tClick,\n\tDrag,\n\tMultitouchPanZoom,\n\tPointeract,\n\ttype Options as PointeractOptions,\n\tPreventDefault,\n\ttype Events,\n\tWheelPanZoom,\n\tLubricator,\n\tlubricatorPanPreset as pan,\n\tlubricatorZoomPreset as zoom,\n\tlubricatorDragPreset as drag,\n\ttype PointeractInterface,\n} from 'pointeract';\n\ntype LoadedModules = [Click, Drag, WheelPanZoom, PreventDefault, MultitouchPanZoom, Lubricator];\n\ntype LoadedEvents = Events<LoadedModules>;\n\ninterface Options extends BaseOptions {\n\tpointeract?: PointeractOptions<LoadedModules>;\n}\n\ninterface Augmentation {\n\tpan: InteractionHandler['pan'];\n\tpanToCoords: InteractionHandler['panToCoords'];\n\tzoom: InteractionHandler['zoom'];\n\tzoomToScale: InteractionHandler['zoomToScale'];\n}\n\nexport default class InteractionHandler extends BaseModule<Options, Augmentation> {\n\tpointeract: PointeractInterface<LoadedModules>;\n\tprivate DM: DataManager;\n\tonClick = utilities.makeHook<[string | null]>();\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tthis.DM = this.container.get(DataManager);\n\t\tconst options = Object.assign(this.options.pointeract ?? {}, {\n\t\t\tcoordinateOutput: 'relative',\n\t\t\telement: this.DM.data.container,\n\t\t\tlubricator: { pan, zoom, drag },\n\t\t} satisfies PointeractOptions<LoadedModules>);\n\t\tthis.pointeract = new Pointeract(options, [\n\t\t\tClick,\n\t\t\tDrag,\n\t\t\tWheelPanZoom,\n\t\t\tPreventDefault,\n\t\t\tMultitouchPanZoom,\n\t\t\tLubricator,\n\t\t]);\n\t\tconst OM = this.container.get(OverlayManager);\n\t\tOM.onInteractionStart.subscribe(this.stopInteract);\n\t\tOM.onInteractionEnd.subscribe(this.startInteract);\n\n\t\tthis.augment({\n\t\t\tpan: this.pan,\n\t\t\tpanToCoords: this.panToCoords,\n\t\t\tzoom: this.zoom,\n\t\t\tzoomToScale: this.zoomToScale,\n\t\t});\n\t\tthis.onStart(this.start);\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\tprivate start = () => {\n\t\tthis.pointeract\n\t\t\t.on('pan', this.onPan)\n\t\t\t.on('drag', this.onPan)\n\t\t\t.on('zoom', this.onZoom)\n\t\t\t.on('trueClick', this.onTrueClick)\n\t\t\t.start();\n\t};\n\n\tprivate startInteract = () => {\n\t\tthis.pointeract.start();\n\t};\n\tprivate stopInteract = () => {\n\t\tthis.pointeract.stop();\n\t};\n\n\tprivate onPan = (event: LoadedEvents['pan']) => {\n\t\tthis.truePan({\n\t\t\tx: event.deltaX,\n\t\t\ty: event.deltaY,\n\t\t});\n\t};\n\tprivate onZoom = (event: LoadedEvents['zoom']) => {\n\t\tthis.trueZoom(event.factor, event);\n\t};\n\n\ttrueZoom = (_factor: number, origin: Coordinates) => {\n\t\tconst newScale = Math.max(Math.min(this.DM.data.scale * _factor, 20), 0.05);\n\t\tconst scale = this.DM.data.scale;\n\t\tif (newScale === scale) return;\n\t\tconst factor = newScale / this.DM.data.scale;\n\t\tconst canvasCoords = this.C2C(origin);\n\t\tthis.DM.data.offsetX = origin.x - canvasCoords.x * factor;\n\t\tthis.DM.data.offsetY = origin.y - canvasCoords.y * factor;\n\t\tthis.DM.data.scale = newScale;\n\t};\n\ttruePan = ({ x, y }: Coordinates) => {\n\t\tthis.DM.data.offsetX = this.DM.data.offsetX + x;\n\t\tthis.DM.data.offsetY = this.DM.data.offsetY + y;\n\t};\n\n\tzoom = (_factor: number, origin: Coordinates) => {\n\t\tthis.pointeract.dispatch('zoom', { factor: _factor, ...origin });\n\t};\n\tpan = ({ x, y }: Coordinates) => {\n\t\tthis.pointeract.dispatch('pan', { deltaX: x, deltaY: y });\n\t};\n\tzoomToScale = (newScale: number, origin: Coordinates) => {\n\t\tconst factor = newScale / this.DM.data.scale;\n\t\tthis.pointeract.dispatch('zoom', { factor, ...origin });\n\t};\n\tpanToCoords = ({ x, y }: Coordinates) => {\n\t\tthis.pointeract.dispatch('pan', {\n\t\t\tdeltaX: x - this.DM.data.offsetX,\n\t\t\tdeltaY: y - this.DM.data.offsetY,\n\t\t});\n\t};\n\n\t// Container Coords to Canvas Coords relative to the top-left corner of the scaled canvas\n\tprivate C2C = ({ x: containerX, y: containerY }: Coordinates) => ({\n\t\tx: containerX - this.DM.data.offsetX,\n\t\ty: containerY - this.DM.data.offsetY,\n\t});\n\n\tprivate onTrueClick = (e: LoadedEvents['trueClick']) => {\n\t\tconst element = e.target as HTMLElement | null;\n\t\tif (this.isUIControl(element)) return;\n\t\tconst node = this.findNodeId(element);\n\t\tthis.onClick(node);\n\t};\n\n\tprivate isUIControl = (target: HTMLElement | null) => {\n\t\tif (!target) return false;\n\t\treturn target.closest('.controls') || target.closest('button') || target.closest('input');\n\t};\n\n\tprivate findNodeId = (element: HTMLElement | null) => {\n\t\tif (!element) return null;\n\t\tlet ele = element;\n\t\twhile (!ele.id || ele.id === '') {\n\t\t\tif (!ele.parentElement) break;\n\t\t\tele = ele.parentElement;\n\t\t}\n\t\tif (ele.id === 'overlays' || !ele.id || ele.id === '') return null;\n\t\treturn ele.id;\n\t};\n\n\tprivate dispose = () => this.pointeract.dispose();\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"InteractionHandler.js","names":[],"sources":["../../src/kernel/InteractionHandler.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { BaseArgs } from '$/BaseModule';\nimport type { Coordinates } from '$/types';\nimport type { Options as PointeractOptions, Events, PointeractInterface } from 'pointeract';\nimport { BaseModule } from '$/BaseModule';\nimport DataManager from '$/DataManager';\nimport OverlayManager from '$/OverlayManager';\nimport { makeHook } from '$/utilities';\nimport {\n\tClick,\n\tDrag,\n\tMultitouchPanZoom,\n\tPointeract,\n\tPreventDefault,\n\tWheelPanZoom,\n\tLubricator,\n\tlubricatorPanPreset as pan,\n\tlubricatorZoomPreset as zoom,\n\tlubricatorDragPreset as drag,\n} from 'pointeract';\n\ntype LoadedModules = [Click, Drag, WheelPanZoom, PreventDefault, MultitouchPanZoom, Lubricator];\n\ntype LoadedEvents = Events<LoadedModules>;\n\ntype Options = {\n\tpointeract?: PointeractOptions<LoadedModules>;\n} & BaseOptions;\n\ntype Augmentation = {\n\tpan: InteractionHandler['pan'];\n\tpanToCoords: InteractionHandler['panToCoords'];\n\tzoom: InteractionHandler['zoom'];\n\tzoomToScale: InteractionHandler['zoomToScale'];\n};\n\nexport default class InteractionHandler extends BaseModule<Options, Augmentation> {\n\tpointeract: PointeractInterface<LoadedModules>;\n\tprivate readonly DM: DataManager;\n\tonClick = makeHook<[string | undefined]>();\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tthis.DM = this.container.get(DataManager);\n\t\tconst options = Object.assign(this.options.pointeract ?? {}, {\n\t\t\tcoordinateOutput: 'relative',\n\t\t\telement: this.DM.data.container,\n\t\t\tlubricator: { drag, pan, zoom },\n\t\t} satisfies PointeractOptions<LoadedModules>);\n\t\tthis.pointeract = new Pointeract(options, [\n\t\t\tClick,\n\t\t\tDrag,\n\t\t\tWheelPanZoom,\n\t\t\tPreventDefault,\n\t\t\tMultitouchPanZoom,\n\t\t\tLubricator,\n\t\t]);\n\t\tconst OM = this.container.get(OverlayManager);\n\t\tOM.onInteractionStart.subscribe(this.stopInteract);\n\t\tOM.onInteractionEnd.subscribe(this.startInteract);\n\n\t\tthis.augment({\n\t\t\tpan: this.pan,\n\t\t\tpanToCoords: this.panToCoords,\n\t\t\tzoom: this.zoom,\n\t\t\tzoomToScale: this.zoomToScale,\n\t\t});\n\t\tthis.onStart(this.start);\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\tprivate readonly start = () => {\n\t\tthis.pointeract\n\t\t\t.on('pan', this.onPan)\n\t\t\t.on('drag', this.onPan)\n\t\t\t.on('zoom', this.onZoom)\n\t\t\t.on('trueClick', this.onTrueClick)\n\t\t\t.start();\n\t};\n\n\tprivate readonly startInteract = () => {\n\t\tthis.pointeract.start();\n\t};\n\tprivate readonly stopInteract = () => {\n\t\tthis.pointeract.stop();\n\t};\n\n\tprivate readonly onPan = (event: LoadedEvents['pan']) => {\n\t\tthis.truePan({\n\t\t\tx: event.deltaX,\n\t\t\ty: event.deltaY,\n\t\t});\n\t};\n\tprivate readonly onZoom = (event: LoadedEvents['zoom']) => {\n\t\tthis.trueZoom(event.factor, event);\n\t};\n\n\ttrueZoom = (_factor: number, origin: Coordinates) => {\n\t\tconst newScale = Math.max(Math.min(this.DM.data.scale * _factor, 20), 0.05);\n\t\tconst scale = this.DM.data.scale;\n\t\tif (newScale === scale) return;\n\t\tconst factor = newScale / this.DM.data.scale;\n\t\tconst canvasCoords = this.C2C(origin);\n\t\tthis.DM.data.offsetX = origin.x - canvasCoords.x * factor;\n\t\tthis.DM.data.offsetY = origin.y - canvasCoords.y * factor;\n\t\tthis.DM.data.scale = newScale;\n\t};\n\ttruePan = ({ x, y }: Coordinates) => {\n\t\tthis.DM.data.offsetX += x;\n\t\tthis.DM.data.offsetY += y;\n\t};\n\n\tzoom = (_factor: number, origin: Coordinates) => {\n\t\tthis.pointeract.dispatch('zoom', { factor: _factor, ...origin });\n\t};\n\tpan = ({ x, y }: Coordinates) => {\n\t\tthis.pointeract.dispatch('pan', { deltaX: x, deltaY: y });\n\t};\n\tzoomToScale = (newScale: number, origin: Coordinates) => {\n\t\tconst factor = newScale / this.DM.data.scale;\n\t\tthis.pointeract.dispatch('zoom', { factor, ...origin });\n\t};\n\tpanToCoords = ({ x, y }: Coordinates) => {\n\t\tthis.pointeract.dispatch('pan', {\n\t\t\tdeltaX: x - this.DM.data.offsetX,\n\t\t\tdeltaY: y - this.DM.data.offsetY,\n\t\t});\n\t};\n\n\t// Container Coords to Canvas Coords relative to the top-left corner of the scaled canvas\n\tprivate readonly C2C = ({ x: containerX, y: containerY }: Coordinates) => ({\n\t\tx: containerX - this.DM.data.offsetX,\n\t\ty: containerY - this.DM.data.offsetY,\n\t});\n\n\tprivate readonly onTrueClick = (e: LoadedEvents['trueClick']) => {\n\t\tconst element = e.target ? (e.target as HTMLElement) : undefined;\n\t\tif (this.isUIControl(element)) return;\n\t\tconst node = this.findNodeId(element);\n\t\tthis.onClick(node);\n\t};\n\n\tprivate readonly isUIControl = (target?: HTMLElement) => {\n\t\tif (!target) return false;\n\t\treturn target.closest('.controls') || target.closest('button') || target.closest('input');\n\t};\n\n\tprivate readonly findNodeId = (element?: HTMLElement) => {\n\t\tif (!element) return;\n\t\tlet ele = element;\n\t\twhile (!ele.id || ele.id === '') {\n\t\t\tif (!ele.parentElement) break;\n\t\t\tele = ele.parentElement;\n\t\t}\n\t\tif (ele.id === 'overlays' || !ele.id || ele.id === '') return;\n\t\treturn ele.id;\n\t};\n\n\tprivate readonly dispose = () => this.pointeract.dispose();\n}\n"],"mappings":"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"}
@@ -4,15 +4,22 @@ import { BaseArgs, BaseModule } from "./BaseModule.js";
4
4
  import { BaseOptions } from "./index.js";
5
5
 
6
6
  //#region src/kernel/OverlayManager.d.ts
7
- interface Options extends BaseOptions {
7
+ type Options = {
8
8
  parser?: Parser;
9
9
  nodeComponents?: Partial<ComponentDict>;
10
- }
11
- interface Augmentation {
10
+ } & BaseOptions;
11
+ type Augmentation = {
12
12
  onNodeActive: OverlayManager['onNodeActive'];
13
13
  onNodeLosesActive: OverlayManager['onNodeLosesActive'];
14
- }
15
- type NodeComponentHook<N extends JSONCanvasNode> = (container: HTMLDivElement, content: string, node: N, onBeforeUnmount: Hook, onActive: Hook, onLoseActive: Hook) => void | Promise<void>;
14
+ };
15
+ type NodeComponentHook<N extends JSONCanvasNode> = (options: {
16
+ container: HTMLDivElement;
17
+ content: string;
18
+ node: N;
19
+ onBeforeUnmount: Hook;
20
+ onActive: Hook;
21
+ onLoseActive: Hook;
22
+ }) => void | Promise<void>;
16
23
  type ComponentNodeMap = {
17
24
  text: JSONCanvasTextNode;
18
25
  markdown: JSONCanvasFileNode;
@@ -23,32 +30,32 @@ type ComponentNodeMap = {
23
30
  };
24
31
  type ComponentDict = { [K in keyof ComponentNodeMap]: NodeComponentHook<ComponentNodeMap[K]> };
25
32
  declare class OverlayManager extends BaseModule<Options, Augmentation> {
26
- private _overlaysLayer;
33
+ private _overlaysLayer?;
27
34
  private overlays;
28
- private selectedId;
35
+ private selectedId?;
29
36
  private aborted;
30
37
  private eventListeners;
31
- private DM;
32
- private SM;
33
- private parse;
34
- private componentDict;
38
+ private readonly DM;
39
+ private readonly SM;
40
+ private readonly parse;
41
+ private readonly componentDict;
35
42
  private get overlaysLayer();
36
43
  onInteractionStart: Hook<[], false>;
37
44
  onInteractionEnd: Hook<[], false>;
38
45
  onNodeActive: Hook<[JSONCanvasNode], false>;
39
46
  onNodeLosesActive: Hook<[JSONCanvasNode], false>;
40
47
  constructor(...args: BaseArgs);
41
- private start;
42
- private restart;
43
- private renderOverlays;
44
- private themeChanged;
45
- private select;
46
- private updateOverlays;
47
- private createOverlay;
48
- private constructOverlay;
49
- private setOverlayColor;
50
- private clearOverlays;
51
- private dispose;
48
+ private readonly start;
49
+ private readonly restart;
50
+ private readonly renderOverlays;
51
+ private readonly themeChanged;
52
+ private readonly select;
53
+ private readonly updateOverlays;
54
+ private readonly createOverlay;
55
+ private readonly constructOverlay;
56
+ private readonly setOverlayColor;
57
+ private readonly clearOverlays;
58
+ private readonly dispose;
52
59
  }
53
60
  //#endregion
54
61
  export { OverlayManager };
@@ -1,2 +1,2 @@
1
- import{BaseModule as e}from"./BaseModule.js";import t,{destroyError as n}from"./utilities.js";import r from"./DataManager.js";import i from"./StyleManager.js";import a from"./Controller.js";import o from"./InteractionHandler.js";const s={markdown:/\.(md|mdx|markdown|txt)$/i,image:/\.(png|jpg|jpeg|gif|svg|webp|avif|bmp|ico|heic|heif)$/i,audio:/\.(mp3|wav|ogg|opus|aac|m4a|flac)$/i,video:/\.(mp4|webm|ogv|mov|m3u8|mpd)$/i},c=[`markdown`,`image`,`audio`,`video`];var l=class extends e{_overlaysLayer=document.createElement(`div`);overlays={};selectedId=null;aborted=!1;eventListeners={};DM;SM;parse;componentDict={text:(e,t)=>{e.classList.add(`JCV-markdown-content`);let n=document.createElement(`div`);n.innerHTML=t,n.classList.add(`JCV-parsed-content-wrapper`),e.appendChild(n)},markdown:async(e,t)=>{e.classList.add(`JCV-markdown-content`);let n=document.createElement(`div`);n.textContent=`Loading...`,n.classList.add(`JCV-parsed-content-wrapper`),e.appendChild(n);let r;try{let e=await(await fetch(t)).text(),n=e.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);r=n?await this.parse(n[2]):await this.parse(e)}catch(e){console.error(`[JSON Canvas Viewer] Failed to load markdown:`,e),r=`Failed to load content.`}n.innerHTML=r},link:(e,t)=>{let n=document.createElement(`iframe`);n.src=t,n.sandbox=`allow-scripts allow-same-origin`,n.className=`JCV-link-iframe`,n.loading=`lazy`,e.appendChild(n)},audio:(e,t)=>{let n=document.createElement(`audio`);n.className=`JCV-audio`,n.src=t,n.controls=!0,e.appendChild(n)},image:(e,t)=>{let n=document.createElement(`img`);n.className=`JCV-img`,n.src=t,n.loading=`lazy`,e.appendChild(n)},video:(e,t)=>{let n=document.createElement(`video`);n.className=`JCV-video`,n.src=t,n.controls=!0,e.appendChild(n)}};get overlaysLayer(){if(!this._overlaysLayer)throw n;return this._overlaysLayer}onInteractionStart=t.makeHook();onInteractionEnd=t.makeHook();onNodeActive=t.makeHook();onNodeLosesActive=t.makeHook();constructor(...e){super(...e),this.parse=this.options.parser||(e=>e),this.DM=this.container.get(r),this.SM=this.container.get(i),this.container.get(a).onRefresh.subscribe(this.updateOverlays),this.SM.onChangeTheme.subscribe(this.themeChanged),this._overlaysLayer=document.createElement(`div`),this._overlaysLayer.className=`JCV-overlays`,this._overlaysLayer.id=`overlays`,this.DM.data.container.appendChild(this.overlaysLayer);let t=this.options.nodeComponents;t&&Object.assign(this.componentDict,t),this.augment({onNodeActive:this.onNodeActive,onNodeLosesActive:this.onNodeLosesActive}),this.onStart(this.start),this.onRestart(this.restart),this.onDispose(this.dispose)}start=()=>{this.container.get(o).onClick.subscribe(this.select),this.renderOverlays()};restart=()=>{this.clearOverlays(),this.renderOverlays()};renderOverlays=()=>{let e=async e=>{switch(e.type){case`text`:this.createOverlay(e,await this.parse(e.text),`text`);break;case`file`:for(let t of c)if(e.file.match(s[t])){this.createOverlay(e,e.file,t);break}break;case`link`:this.createOverlay(e,e.url,`link`);break}};Object.values(this.DM.data.nodeMap).forEach(async t=>{await e(t.ref)})};themeChanged=()=>{Object.values(this.overlays).forEach(e=>{let t=this.DM.data.nodeMap[e.id].ref,n=this.SM.getColor(t.color);this.setOverlayColor(e,n)})};select=e=>{let t=this.selectedId,n=t?this.overlays[t]:null,r=e?this.overlays[e]:null;if(n&&t){n.classList.remove(`JCV-active`);let e=this.DM.data.nodeMap[t];this.onNodeLosesActive(e.ref),e.onLoseActive?.()}if(r&&e){r.classList.add(`JCV-active`),this.onInteractionStart();let t=this.DM.data.nodeMap[e];this.onNodeActive(t.ref),t.onActive?.()}else this.onInteractionEnd();this.selectedId=e};updateOverlays=()=>{let e=this.DM.data;this.overlaysLayer.style.transform=`translate(${e.offsetX}px, ${e.offsetY}px) scale(${e.scale})`};createOverlay=(...e)=>{if(this.aborted)return;let t=e[0],n=this.overlays[t.id];if(!n){if(n=this.constructOverlay(...e),this.aborted)return;this.overlaysLayer.appendChild(n),this.overlays[t.id]=n,n.style.left=`${t.x}px`,n.style.top=`${t.y}px`,n.style.width=`${t.width}px`,n.style.height=`${t.height}px`}};constructOverlay=(...e)=>{let n=e[0],r=document.createElement(`div`);r.classList.add(`JCV-overlay-container`),r.id=n.id,this.setOverlayColor(r,this.SM.getColor(n.color));let i=document.createElement(`div`);i.classList.add(`JCV-content`),r.appendChild(i);let a=document.createElement(`div`);a.className=`JCV-click-layer`,r.appendChild(a);let o=document.createElement(`div`);o.className=`JCV-overlay-border`,r.appendChild(o);let s=this.DM.data.nodeMap[n.id];s.onActive=t.makeHook(),s.onLoseActive=t.makeHook(),s.onBeforeUnmount=t.makeHook(),this.componentDict[e[2]](i,e[1],e[0],s.onBeforeUnmount,s.onActive,s.onLoseActive);let c=()=>{n.id===this.selectedId&&this.onInteractionStart()},l=()=>{n.id===this.selectedId&&this.onInteractionEnd()};return r.addEventListener(`pointerenter`,c),r.addEventListener(`pointerleave`,l),r.addEventListener(`touchstart`,c),r.addEventListener(`touchend`,l),this.eventListeners[n.id]=[c,l],r};setOverlayColor=(e,t)=>{Object.entries(t).forEach(([t,n])=>{e.style.setProperty(`--overlay-${t}`,n)})};clearOverlays=()=>{Object.entries(this.overlays).forEach(([e,t])=>{if(this.DM.data.nodeMap[e].onBeforeUnmount?.(),this.eventListeners[e]){let r=this.eventListeners[e][0],i=this.eventListeners[e][1];if(!r||!i)throw n;t.removeEventListener(`pointerenter`,r),t.removeEventListener(`pointerleave`,i),t.removeEventListener(`touchstart`,r),t.removeEventListener(`touchend`,i),this.eventListeners[e][0]=null,this.eventListeners[e][1]=null}t.remove(),delete this.overlays[e]})};dispose=()=>{this.aborted=!0,this.clearOverlays(),this.overlaysLayer.remove(),this._overlaysLayer=null}};export{l as default};
1
+ import{BaseModule as e}from"./BaseModule.js";import{destroyError as t,makeHook as n}from"./utilities.js";import r from"./DataManager.js";import i from"./StyleManager.js";import a from"./Controller.js";import o from"./InteractionHandler.js";const s={audio:/\.(mp3|wav|ogg|opus|aac|m4a|flac)$/i,image:/\.(png|jpg|jpeg|gif|svg|webp|avif|bmp|ico|heic|heif)$/i,markdown:/\.(md|mdx|markdown|txt)$/i,video:/\.(mp4|webm|ogv|mov|m3u8|mpd)$/i},c=[`markdown`,`image`,`audio`,`video`];var l=class extends e{_overlaysLayer=document.createElement(`div`);overlays={};selectedId;aborted=!1;eventListeners={};DM;SM;parse;componentDict={audio:({container:e,content:t})=>{let n=document.createElement(`audio`);n.className=`JCV-audio`,n.src=t,n.controls=!0,e.appendChild(n)},image:({container:e,content:t})=>{let n=document.createElement(`img`);n.className=`JCV-img`,n.src=t,n.loading=`lazy`,e.appendChild(n)},link:({container:e,content:t})=>{let n=document.createElement(`iframe`);n.src=t,n.sandbox=`allow-scripts allow-same-origin`,n.className=`JCV-link-iframe`,n.loading=`lazy`,e.appendChild(n)},markdown:async({container:e,content:t})=>{e.classList.add(`JCV-markdown-content`);let n=document.createElement(`div`);n.textContent=`Loading...`,n.classList.add(`JCV-parsed-content-wrapper`),e.appendChild(n);let r;try{let e=await(await fetch(t)).text(),n=/^---\n([\s\S]*?)\n---\n([\s\S]*)$/.exec(e);r=await this.parse(n?n[2]:e)}catch(e){console.error(`[JSON Canvas Viewer] Failed to load markdown:`,e),r=`Failed to load content.`}n.innerHTML=r},text:({container:e,content:t})=>{e.classList.add(`JCV-markdown-content`);let n=document.createElement(`div`);n.innerHTML=t,n.classList.add(`JCV-parsed-content-wrapper`),e.appendChild(n)},video:({container:e,content:t})=>{let n=document.createElement(`video`);n.className=`JCV-video`,n.src=t,n.controls=!0,e.appendChild(n)}};get overlaysLayer(){if(!this._overlaysLayer)throw t;return this._overlaysLayer}onInteractionStart=n();onInteractionEnd=n();onNodeActive=n();onNodeLosesActive=n();constructor(...e){super(...e),this.parse=this.options.parser??(e=>e),this.DM=this.container.get(r),this.SM=this.container.get(i),this.container.get(a).onRefresh.subscribe(this.updateOverlays),this.SM.onChangeTheme.subscribe(this.themeChanged),this._overlaysLayer=document.createElement(`div`),this._overlaysLayer.className=`JCV-overlays`,this._overlaysLayer.id=`overlays`,this.DM.data.container.appendChild(this.overlaysLayer);let t=this.options.nodeComponents;t&&Object.assign(this.componentDict,t),this.augment({onNodeActive:this.onNodeActive,onNodeLosesActive:this.onNodeLosesActive}),this.onStart(this.start),this.onRestart(this.restart),this.onDispose(this.dispose)}start=()=>{this.container.get(o).onClick.subscribe(this.select),this.renderOverlays()};restart=()=>{this.clearOverlays(),this.renderOverlays()};renderOverlays=()=>{let e=async e=>{switch(e.type){case`text`:this.createOverlay(e,await this.parse(e.text),`text`);break;case`file`:for(let t of c)if(e.file.match(s[t])){this.createOverlay(e,e.file,t);break}break;case`link`:this.createOverlay(e,e.url,`link`);break}};Object.values(this.DM.data.nodeMap).forEach(async t=>{await e(t.ref)})};themeChanged=()=>{Object.values(this.overlays).forEach(e=>{let t=this.DM.data.nodeMap[e.id].ref,n=this.SM.getColor(t.color);this.setOverlayColor(e,n)})};select=e=>{let t=this.selectedId,n=t?this.overlays[t]:void 0,r=e?this.overlays[e]:void 0;if(n&&t){n.classList.remove(`JCV-active`);let e=this.DM.data.nodeMap[t];this.onNodeLosesActive(e.ref),e.onLoseActive?.()}if(r&&e){r.classList.add(`JCV-active`),this.onInteractionStart();let t=this.DM.data.nodeMap[e];this.onNodeActive(t.ref),t.onActive?.()}else this.onInteractionEnd();this.selectedId=e};updateOverlays=()=>{let e=this.DM.data;this.overlaysLayer.style.transform=`translate(${e.offsetX}px, ${e.offsetY}px) scale(${e.scale})`};createOverlay=(...e)=>{if(this.aborted)return;let t=e[0],n=this.overlays[t.id];if(!n){if(n=this.constructOverlay(...e),this.aborted)return;this.overlaysLayer.appendChild(n),this.overlays[t.id]=n,n.style.left=`${t.x}px`,n.style.top=`${t.y}px`,n.style.width=`${t.width}px`,n.style.height=`${t.height}px`}};constructOverlay=(...e)=>{let t=e[0],r=document.createElement(`div`);r.classList.add(`JCV-overlay-container`),r.id=t.id,this.setOverlayColor(r,this.SM.getColor(t.color));let i=document.createElement(`div`);i.classList.add(`JCV-content`),r.appendChild(i);let a=document.createElement(`div`);a.className=`JCV-click-layer`,r.appendChild(a);let o=document.createElement(`div`);o.className=`JCV-overlay-border`,r.appendChild(o);let s=this.DM.data.nodeMap[t.id];s.onActive=n(),s.onLoseActive=n(),s.onBeforeUnmount=n(),this.componentDict[e[2]]({container:i,content:e[1],node:e[0],onActive:s.onActive,onBeforeUnmount:s.onBeforeUnmount,onLoseActive:s.onLoseActive});let c=()=>{t.id===this.selectedId&&this.onInteractionStart()},l=()=>{t.id===this.selectedId&&this.onInteractionEnd()};return r.addEventListener(`pointerenter`,c),r.addEventListener(`pointerleave`,l),r.addEventListener(`touchstart`,c),r.addEventListener(`touchend`,l),this.eventListeners[t.id]=[c,l],r};setOverlayColor=(e,t)=>{Object.entries(t).forEach(([t,n])=>{e.style.setProperty(`--overlay-${t}`,n)})};clearOverlays=()=>{Object.entries(this.overlays).forEach(([e,n])=>{if(this.DM.data.nodeMap[e].onBeforeUnmount?.(),this.eventListeners[e]){let r=this.eventListeners[e][0],i=this.eventListeners[e][1];if(!r||!i)throw t;n.removeEventListener(`pointerenter`,r),n.removeEventListener(`pointerleave`,i),n.removeEventListener(`touchstart`,r),n.removeEventListener(`touchend`,i),this.eventListeners[e][0]=void 0,this.eventListeners[e][1]=void 0}n.remove(),delete this.overlays[e]})};dispose=()=>{this.aborted=!0,this.clearOverlays(),this.overlaysLayer.remove(),this._overlaysLayer=void 0}};export{l as default};
2
2
  //# sourceMappingURL=OverlayManager.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"OverlayManager.js","names":["utilities"],"sources":["../../src/kernel/OverlayManager.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type {\n\tJSONCanvasFileNode,\n\tJSONCanvasLinkNode,\n\tJSONCanvasNode,\n\tJSONCanvasTextNode,\n\tParser,\n} from '@repo/shared';\nimport { type BaseArgs, BaseModule } from '$/BaseModule';\nimport Controller from '$/Controller';\nimport DataManager from '$/DataManager';\nimport InteractionHandler from '$/InteractionHandler';\nimport StyleManager, { type WithBorderWidth as Color } from '$/StyleManager';\nimport utilities, { destroyError, type Hook } from '$/utilities';\n\ninterface Options extends BaseOptions {\n\tparser?: Parser;\n\tnodeComponents?: Partial<ComponentDict>;\n}\n\ninterface Augmentation {\n\tonNodeActive: OverlayManager['onNodeActive'];\n\tonNodeLosesActive: OverlayManager['onNodeLosesActive'];\n}\n\nconst fileRegex = {\n\tmarkdown: /\\.(md|mdx|markdown|txt)$/i,\n\timage: /\\.(png|jpg|jpeg|gif|svg|webp|avif|bmp|ico|heic|heif)$/i,\n\taudio: /\\.(mp3|wav|ogg|opus|aac|m4a|flac)$/i,\n\tvideo: /\\.(mp4|webm|ogv|mov|m3u8|mpd)$/i,\n};\n\ntype NodeComponentHook<N extends JSONCanvasNode> = (\n\tcontainer: HTMLDivElement,\n\tcontent: string,\n\tnode: N,\n\tonBeforeUnmount: Hook,\n\tonActive: Hook,\n\tonLoseActive: Hook,\n) => void | Promise<void>;\n\ntype CreateOverlayArgs =\n\t| [ComponentNodeMap['text'], string, 'text']\n\t| [ComponentNodeMap['markdown'], string, 'markdown']\n\t| [ComponentNodeMap['image'], string, 'image']\n\t| [ComponentNodeMap['audio'], string, 'audio']\n\t| [ComponentNodeMap['video'], string, 'video']\n\t| [ComponentNodeMap['link'], string, 'link'];\n\ntype ComponentNodeMap = {\n\ttext: JSONCanvasTextNode;\n\tmarkdown: JSONCanvasFileNode;\n\timage: JSONCanvasFileNode;\n\taudio: JSONCanvasFileNode;\n\tvideo: JSONCanvasFileNode;\n\tlink: JSONCanvasLinkNode;\n};\n\ntype ComponentDict = {\n\t[K in keyof ComponentNodeMap]: NodeComponentHook<ComponentNodeMap[K]>;\n};\n\nconst supportedTypes = ['markdown', 'image', 'audio', 'video'] as const;\n\nexport default class OverlayManager extends BaseModule<Options, Augmentation> {\n\tprivate _overlaysLayer: HTMLDivElement | null = document.createElement('div');\n\tprivate overlays: Record<string, HTMLDivElement> = {}; // { id: node } the overlays in viewport\n\tprivate selectedId: string | null = null;\n\tprivate aborted = false;\n\tprivate eventListeners: Record<string, Array<EventListener | null>> = {};\n\tprivate DM: DataManager;\n\tprivate SM: StyleManager;\n\tprivate parse: Parser;\n\tprivate componentDict: ComponentDict = {\n\t\ttext: (container, content) => {\n\t\t\tcontainer.classList.add('JCV-markdown-content');\n\t\t\tconst parsedContentWrapper = document.createElement('div');\n\t\t\tparsedContentWrapper.innerHTML = content;\n\t\t\tparsedContentWrapper.classList.add('JCV-parsed-content-wrapper');\n\t\t\tcontainer.appendChild(parsedContentWrapper);\n\t\t},\n\t\tmarkdown: async (container, content) => {\n\t\t\tcontainer.classList.add('JCV-markdown-content');\n\t\t\tconst parsedContentWrapper = document.createElement('div');\n\t\t\tparsedContentWrapper.textContent = 'Loading...';\n\t\t\tparsedContentWrapper.classList.add('JCV-parsed-content-wrapper');\n\t\t\tcontainer.appendChild(parsedContentWrapper);\n\t\t\tlet parsedContent: string;\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(content);\n\t\t\t\tconst result = await response.text();\n\t\t\t\tconst frontmatterMatch = result.match(/^---\\n([\\s\\S]*?)\\n---\\n([\\s\\S]*)$/);\n\t\t\t\tif (frontmatterMatch) parsedContent = await this.parse(frontmatterMatch[2]);\n\t\t\t\telse parsedContent = await this.parse(result);\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error('[JSON Canvas Viewer] Failed to load markdown:', err);\n\t\t\t\tparsedContent = 'Failed to load content.';\n\t\t\t}\n\t\t\tparsedContentWrapper.innerHTML = parsedContent;\n\t\t},\n\t\tlink: (container, content) => {\n\t\t\tconst iframe = document.createElement('iframe');\n\t\t\tiframe.src = content;\n\t\t\tiframe.sandbox = 'allow-scripts allow-same-origin';\n\t\t\tiframe.className = 'JCV-link-iframe';\n\t\t\tiframe.loading = 'lazy';\n\t\t\tcontainer.appendChild(iframe);\n\t\t},\n\t\taudio: (container, content) => {\n\t\t\tconst audio = document.createElement('audio');\n\t\t\taudio.className = 'JCV-audio';\n\t\t\taudio.src = content;\n\t\t\taudio.controls = true;\n\t\t\tcontainer.appendChild(audio);\n\t\t},\n\t\timage: (container, content) => {\n\t\t\tconst img = document.createElement('img');\n\t\t\timg.className = 'JCV-img';\n\t\t\timg.src = content;\n\t\t\timg.loading = 'lazy';\n\t\t\tcontainer.appendChild(img);\n\t\t},\n\t\tvideo: (container, content) => {\n\t\t\tconst video = document.createElement('video');\n\t\t\tvideo.className = 'JCV-video';\n\t\t\tvideo.src = content;\n\t\t\tvideo.controls = true;\n\t\t\tcontainer.appendChild(video);\n\t\t},\n\t};\n\n\tprivate get overlaysLayer() {\n\t\tif (!this._overlaysLayer) throw destroyError;\n\t\treturn this._overlaysLayer;\n\t}\n\n\tonInteractionStart = utilities.makeHook();\n\tonInteractionEnd = utilities.makeHook();\n\tonNodeActive = utilities.makeHook<[JSONCanvasNode]>();\n\tonNodeLosesActive = utilities.makeHook<[JSONCanvasNode]>();\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tthis.parse = this.options.parser || ((markdown: string) => markdown);\n\t\tthis.DM = this.container.get(DataManager);\n\t\tthis.SM = this.container.get(StyleManager);\n\t\tconst controller = this.container.get(Controller);\n\t\tcontroller.onRefresh.subscribe(this.updateOverlays);\n\t\tthis.SM.onChangeTheme.subscribe(this.themeChanged);\n\n\t\tthis._overlaysLayer = document.createElement('div');\n\t\tthis._overlaysLayer.className = 'JCV-overlays';\n\t\tthis._overlaysLayer.id = 'overlays';\n\t\tthis.DM.data.container.appendChild(this.overlaysLayer);\n\n\t\tconst components = this.options.nodeComponents;\n\t\tif (components) Object.assign(this.componentDict, components);\n\n\t\tthis.augment({\n\t\t\tonNodeActive: this.onNodeActive,\n\t\t\tonNodeLosesActive: this.onNodeLosesActive,\n\t\t});\n\t\tthis.onStart(this.start);\n\t\tthis.onRestart(this.restart);\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\tprivate start = () => {\n\t\tthis.container.get(InteractionHandler).onClick.subscribe(this.select);\n\t\tthis.renderOverlays();\n\t};\n\n\tprivate restart = () => {\n\t\tthis.clearOverlays();\n\t\tthis.renderOverlays();\n\t};\n\n\tprivate renderOverlays = () => {\n\t\tconst overlayMatcher = async (node: JSONCanvasNode) => {\n\t\t\tswitch (node.type) {\n\t\t\t\tcase 'text': {\n\t\t\t\t\tthis.createOverlay(node, await this.parse(node.text), 'text');\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'file': {\n\t\t\t\t\tfor (const type of supportedTypes) {\n\t\t\t\t\t\tif (!node.file.match(fileRegex[type])) continue;\n\t\t\t\t\t\tthis.createOverlay(node, node.file, type);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'link': {\n\t\t\t\t\tthis.createOverlay(node, node.url, 'link');\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tObject.values(this.DM.data.nodeMap).forEach(async (node) => {\n\t\t\tawait overlayMatcher(node.ref);\n\t\t});\n\t};\n\n\tprivate themeChanged = () => {\n\t\tObject.values(this.overlays).forEach((overlay) => {\n\t\t\tconst node = this.DM.data.nodeMap[overlay.id].ref;\n\t\t\tconst color = this.SM.getColor(node.color);\n\t\t\tthis.setOverlayColor(overlay, color);\n\t\t});\n\t};\n\n\tprivate select = (id: string | null) => {\n\t\tconst previousId = this.selectedId;\n\t\tconst previous = !previousId ? null : this.overlays[previousId];\n\t\tconst current = !id ? null : this.overlays[id];\n\t\tif (previous && previousId) {\n\t\t\tprevious.classList.remove('JCV-active');\n\t\t\tconst nodeItem = this.DM.data.nodeMap[previousId];\n\t\t\tthis.onNodeLosesActive(nodeItem.ref);\n\t\t\tnodeItem.onLoseActive?.();\n\t\t}\n\t\tif (current && id) {\n\t\t\tcurrent.classList.add('JCV-active');\n\t\t\tthis.onInteractionStart();\n\t\t\tconst nodeItem = this.DM.data.nodeMap[id];\n\t\t\tthis.onNodeActive(nodeItem.ref);\n\t\t\tnodeItem.onActive?.();\n\t\t} else this.onInteractionEnd();\n\t\tthis.selectedId = id;\n\t};\n\n\tprivate updateOverlays = () => {\n\t\tconst data = this.DM.data;\n\t\tthis.overlaysLayer.style.transform = `translate(${data.offsetX}px, ${data.offsetY}px) scale(${data.scale})`;\n\t};\n\n\tprivate createOverlay = (...args: CreateOverlayArgs) => {\n\t\tif (this.aborted) return;\n\t\tconst node = args[0];\n\t\tlet element = this.overlays[node.id];\n\t\tif (!element) {\n\t\t\telement = this.constructOverlay(...args);\n\t\t\tif (this.aborted) return;\n\t\t\tthis.overlaysLayer.appendChild(element);\n\t\t\tthis.overlays[node.id] = element;\n\t\t\telement.style.left = `${node.x}px`;\n\t\t\telement.style.top = `${node.y}px`;\n\t\t\telement.style.width = `${node.width}px`;\n\t\t\telement.style.height = `${node.height}px`;\n\t\t}\n\t};\n\n\tprivate constructOverlay = (...args: CreateOverlayArgs) => {\n\t\tconst node = args[0];\n\t\tconst overlay = document.createElement('div');\n\t\toverlay.classList.add('JCV-overlay-container');\n\t\toverlay.id = node.id;\n\t\tthis.setOverlayColor(overlay, this.SM.getColor(node.color));\n\t\tconst contentWrapper = document.createElement('div');\n\t\tcontentWrapper.classList.add('JCV-content');\n\t\toverlay.appendChild(contentWrapper);\n\t\tconst clickLayer = document.createElement('div');\n\t\tclickLayer.className = 'JCV-click-layer';\n\t\toverlay.appendChild(clickLayer);\n\t\tconst overlayBorder = document.createElement('div');\n\t\toverlayBorder.className = 'JCV-overlay-border';\n\t\toverlay.appendChild(overlayBorder);\n\t\tconst nodeItem = this.DM.data.nodeMap[node.id];\n\n\t\tnodeItem.onActive = utilities.makeHook();\n\t\tnodeItem.onLoseActive = utilities.makeHook();\n\t\tnodeItem.onBeforeUnmount = utilities.makeHook();\n\n\t\tvoid this.componentDict[args[2]](\n\t\t\tcontentWrapper,\n\t\t\targs[1],\n\t\t\targs[0] as never,\n\t\t\tnodeItem.onBeforeUnmount,\n\t\t\tnodeItem.onActive,\n\t\t\tnodeItem.onLoseActive,\n\t\t);\n\t\tconst onStart = () => {\n\t\t\tif (node.id === this.selectedId) this.onInteractionStart();\n\t\t};\n\t\tconst onEnd = () => {\n\t\t\tif (node.id === this.selectedId) this.onInteractionEnd();\n\t\t};\n\t\toverlay.addEventListener('pointerenter', onStart);\n\t\toverlay.addEventListener('pointerleave', onEnd);\n\t\toverlay.addEventListener('touchstart', onStart);\n\t\toverlay.addEventListener('touchend', onEnd);\n\t\tthis.eventListeners[node.id] = [onStart, onEnd];\n\t\treturn overlay;\n\t};\n\n\tprivate setOverlayColor = (overlay: HTMLDivElement, color: Color) => {\n\t\tObject.entries(color).forEach(([key, value]) => {\n\t\t\toverlay.style.setProperty(`--overlay-${key}`, value);\n\t\t});\n\t};\n\n\tprivate clearOverlays = () => {\n\t\tObject.entries(this.overlays).forEach(([id, overlay]) => {\n\t\t\tthis.DM.data.nodeMap[id].onBeforeUnmount?.();\n\t\t\tif (this.eventListeners[id]) {\n\t\t\t\tconst onStart = this.eventListeners[id][0];\n\t\t\t\tconst onEnd = this.eventListeners[id][1];\n\t\t\t\tif (!onStart || !onEnd) throw destroyError;\n\t\t\t\toverlay.removeEventListener('pointerenter', onStart);\n\t\t\t\toverlay.removeEventListener('pointerleave', onEnd);\n\t\t\t\toverlay.removeEventListener('touchstart', onStart);\n\t\t\t\toverlay.removeEventListener('touchend', onEnd);\n\t\t\t\tthis.eventListeners[id][0] = null;\n\t\t\t\tthis.eventListeners[id][1] = null;\n\t\t\t}\n\t\t\toverlay.remove();\n\t\t\tdelete this.overlays[id];\n\t\t});\n\t};\n\n\tprivate dispose = () => {\n\t\tthis.aborted = true;\n\t\tthis.clearOverlays();\n\t\tthis.overlaysLayer.remove();\n\t\tthis._overlaysLayer = null;\n\t};\n}\n"],"mappings":"qOAyBA,MAAM,EAAY,CACjB,SAAU,4BACV,MAAO,yDACP,MAAO,sCACP,MAAO,kCACP,CAgCK,EAAiB,CAAC,WAAY,QAAS,QAAS,QAAQ,CAE9D,IAAqB,EAArB,cAA4C,CAAkC,CAC7E,eAAgD,SAAS,cAAc,MAAM,CAC7E,SAAmD,EAAE,CACrD,WAAoC,KACpC,QAAkB,GAClB,eAAsE,EAAE,CACxE,GACA,GACA,MACA,cAAuC,CACtC,MAAO,EAAW,IAAY,CAC7B,EAAU,UAAU,IAAI,uBAAuB,CAC/C,IAAM,EAAuB,SAAS,cAAc,MAAM,CAC1D,EAAqB,UAAY,EACjC,EAAqB,UAAU,IAAI,6BAA6B,CAChE,EAAU,YAAY,EAAqB,EAE5C,SAAU,MAAO,EAAW,IAAY,CACvC,EAAU,UAAU,IAAI,uBAAuB,CAC/C,IAAM,EAAuB,SAAS,cAAc,MAAM,CAC1D,EAAqB,YAAc,aACnC,EAAqB,UAAU,IAAI,6BAA6B,CAChE,EAAU,YAAY,EAAqB,CAC3C,IAAI,EACJ,GAAI,CAEH,IAAM,EAAS,MAAM,MADE,MAAM,EAAQ,EACP,MAAM,CAC9B,EAAmB,EAAO,MAAM,oCAAoC,CAC1E,AACK,EADD,EAAkC,MAAM,KAAK,MAAM,EAAiB,GAAG,CACtD,MAAM,KAAK,MAAM,EAAO,OACrC,EAAK,CACb,QAAQ,MAAM,gDAAiD,EAAI,CACnE,EAAgB,0BAEjB,EAAqB,UAAY,GAElC,MAAO,EAAW,IAAY,CAC7B,IAAM,EAAS,SAAS,cAAc,SAAS,CAC/C,EAAO,IAAM,EACb,EAAO,QAAU,kCACjB,EAAO,UAAY,kBACnB,EAAO,QAAU,OACjB,EAAU,YAAY,EAAO,EAE9B,OAAQ,EAAW,IAAY,CAC9B,IAAM,EAAQ,SAAS,cAAc,QAAQ,CAC7C,EAAM,UAAY,YAClB,EAAM,IAAM,EACZ,EAAM,SAAW,GACjB,EAAU,YAAY,EAAM,EAE7B,OAAQ,EAAW,IAAY,CAC9B,IAAM,EAAM,SAAS,cAAc,MAAM,CACzC,EAAI,UAAY,UAChB,EAAI,IAAM,EACV,EAAI,QAAU,OACd,EAAU,YAAY,EAAI,EAE3B,OAAQ,EAAW,IAAY,CAC9B,IAAM,EAAQ,SAAS,cAAc,QAAQ,CAC7C,EAAM,UAAY,YAClB,EAAM,IAAM,EACZ,EAAM,SAAW,GACjB,EAAU,YAAY,EAAM,EAE7B,CAED,IAAY,eAAgB,CAC3B,GAAI,CAAC,KAAK,eAAgB,MAAM,EAChC,OAAO,KAAK,eAGb,mBAAqBA,EAAU,UAAU,CACzC,iBAAmBA,EAAU,UAAU,CACvC,aAAeA,EAAU,UAA4B,CACrD,kBAAoBA,EAAU,UAA4B,CAE1D,YAAY,GAAG,EAAgB,CAC9B,MAAM,GAAG,EAAK,CACd,KAAK,MAAQ,KAAK,QAAQ,SAAY,GAAqB,GAC3D,KAAK,GAAK,KAAK,UAAU,IAAI,EAAY,CACzC,KAAK,GAAK,KAAK,UAAU,IAAI,EAAa,CACvB,KAAK,UAAU,IAAI,EAC5B,CAAC,UAAU,UAAU,KAAK,eAAe,CACnD,KAAK,GAAG,cAAc,UAAU,KAAK,aAAa,CAElD,KAAK,eAAiB,SAAS,cAAc,MAAM,CACnD,KAAK,eAAe,UAAY,eAChC,KAAK,eAAe,GAAK,WACzB,KAAK,GAAG,KAAK,UAAU,YAAY,KAAK,cAAc,CAEtD,IAAM,EAAa,KAAK,QAAQ,eAC5B,GAAY,OAAO,OAAO,KAAK,cAAe,EAAW,CAE7D,KAAK,QAAQ,CACZ,aAAc,KAAK,aACnB,kBAAmB,KAAK,kBACxB,CAAC,CACF,KAAK,QAAQ,KAAK,MAAM,CACxB,KAAK,UAAU,KAAK,QAAQ,CAC5B,KAAK,UAAU,KAAK,QAAQ,CAG7B,UAAsB,CACrB,KAAK,UAAU,IAAI,EAAmB,CAAC,QAAQ,UAAU,KAAK,OAAO,CACrE,KAAK,gBAAgB,EAGtB,YAAwB,CACvB,KAAK,eAAe,CACpB,KAAK,gBAAgB,EAGtB,mBAA+B,CAC9B,IAAM,EAAiB,KAAO,IAAyB,CACtD,OAAQ,EAAK,KAAb,CACC,IAAK,OACJ,KAAK,cAAc,EAAM,MAAM,KAAK,MAAM,EAAK,KAAK,CAAE,OAAO,CAC7D,MAED,IAAK,OACJ,IAAK,IAAM,KAAQ,EACb,KAAK,KAAK,MAAM,EAAU,GAAM,CACrC,MAAK,cAAc,EAAM,EAAK,KAAM,EAAK,CACzC,MAED,MAED,IAAK,OACJ,KAAK,cAAc,EAAM,EAAK,IAAK,OAAO,CAC1C,QAIH,OAAO,OAAO,KAAK,GAAG,KAAK,QAAQ,CAAC,QAAQ,KAAO,IAAS,CAC3D,MAAM,EAAe,EAAK,IAAI,EAC7B,EAGH,iBAA6B,CAC5B,OAAO,OAAO,KAAK,SAAS,CAAC,QAAS,GAAY,CACjD,IAAM,EAAO,KAAK,GAAG,KAAK,QAAQ,EAAQ,IAAI,IACxC,EAAQ,KAAK,GAAG,SAAS,EAAK,MAAM,CAC1C,KAAK,gBAAgB,EAAS,EAAM,EACnC,EAGH,OAAkB,GAAsB,CACvC,IAAM,EAAa,KAAK,WAClB,EAAY,EAAoB,KAAK,SAAS,GAArB,KACzB,EAAW,EAAY,KAAK,SAAS,GAArB,KACtB,GAAI,GAAY,EAAY,CAC3B,EAAS,UAAU,OAAO,aAAa,CACvC,IAAM,EAAW,KAAK,GAAG,KAAK,QAAQ,GACtC,KAAK,kBAAkB,EAAS,IAAI,CACpC,EAAS,gBAAgB,CAE1B,GAAI,GAAW,EAAI,CAClB,EAAQ,UAAU,IAAI,aAAa,CACnC,KAAK,oBAAoB,CACzB,IAAM,EAAW,KAAK,GAAG,KAAK,QAAQ,GACtC,KAAK,aAAa,EAAS,IAAI,CAC/B,EAAS,YAAY,MACf,KAAK,kBAAkB,CAC9B,KAAK,WAAa,GAGnB,mBAA+B,CAC9B,IAAM,EAAO,KAAK,GAAG,KACrB,KAAK,cAAc,MAAM,UAAY,aAAa,EAAK,QAAQ,MAAM,EAAK,QAAQ,YAAY,EAAK,MAAM,IAG1G,eAAyB,GAAG,IAA4B,CACvD,GAAI,KAAK,QAAS,OAClB,IAAM,EAAO,EAAK,GACd,EAAU,KAAK,SAAS,EAAK,IACjC,GAAI,CAAC,EAAS,CAEb,GADA,EAAU,KAAK,iBAAiB,GAAG,EAAK,CACpC,KAAK,QAAS,OAClB,KAAK,cAAc,YAAY,EAAQ,CACvC,KAAK,SAAS,EAAK,IAAM,EACzB,EAAQ,MAAM,KAAO,GAAG,EAAK,EAAE,IAC/B,EAAQ,MAAM,IAAM,GAAG,EAAK,EAAE,IAC9B,EAAQ,MAAM,MAAQ,GAAG,EAAK,MAAM,IACpC,EAAQ,MAAM,OAAS,GAAG,EAAK,OAAO,MAIxC,kBAA4B,GAAG,IAA4B,CAC1D,IAAM,EAAO,EAAK,GACZ,EAAU,SAAS,cAAc,MAAM,CAC7C,EAAQ,UAAU,IAAI,wBAAwB,CAC9C,EAAQ,GAAK,EAAK,GAClB,KAAK,gBAAgB,EAAS,KAAK,GAAG,SAAS,EAAK,MAAM,CAAC,CAC3D,IAAM,EAAiB,SAAS,cAAc,MAAM,CACpD,EAAe,UAAU,IAAI,cAAc,CAC3C,EAAQ,YAAY,EAAe,CACnC,IAAM,EAAa,SAAS,cAAc,MAAM,CAChD,EAAW,UAAY,kBACvB,EAAQ,YAAY,EAAW,CAC/B,IAAM,EAAgB,SAAS,cAAc,MAAM,CACnD,EAAc,UAAY,qBAC1B,EAAQ,YAAY,EAAc,CAClC,IAAM,EAAW,KAAK,GAAG,KAAK,QAAQ,EAAK,IAE3C,EAAS,SAAWA,EAAU,UAAU,CACxC,EAAS,aAAeA,EAAU,UAAU,CAC5C,EAAS,gBAAkBA,EAAU,UAAU,CAE1C,KAAK,cAAc,EAAK,IAC5B,EACA,EAAK,GACL,EAAK,GACL,EAAS,gBACT,EAAS,SACT,EAAS,aACT,CACD,IAAM,MAAgB,CACjB,EAAK,KAAO,KAAK,YAAY,KAAK,oBAAoB,EAErD,MAAc,CACf,EAAK,KAAO,KAAK,YAAY,KAAK,kBAAkB,EAOzD,OALA,EAAQ,iBAAiB,eAAgB,EAAQ,CACjD,EAAQ,iBAAiB,eAAgB,EAAM,CAC/C,EAAQ,iBAAiB,aAAc,EAAQ,CAC/C,EAAQ,iBAAiB,WAAY,EAAM,CAC3C,KAAK,eAAe,EAAK,IAAM,CAAC,EAAS,EAAM,CACxC,GAGR,iBAA2B,EAAyB,IAAiB,CACpE,OAAO,QAAQ,EAAM,CAAC,SAAS,CAAC,EAAK,KAAW,CAC/C,EAAQ,MAAM,YAAY,aAAa,IAAO,EAAM,EACnD,EAGH,kBAA8B,CAC7B,OAAO,QAAQ,KAAK,SAAS,CAAC,SAAS,CAAC,EAAI,KAAa,CAExD,GADA,KAAK,GAAG,KAAK,QAAQ,GAAI,mBAAmB,CACxC,KAAK,eAAe,GAAK,CAC5B,IAAM,EAAU,KAAK,eAAe,GAAI,GAClC,EAAQ,KAAK,eAAe,GAAI,GACtC,GAAI,CAAC,GAAW,CAAC,EAAO,MAAM,EAC9B,EAAQ,oBAAoB,eAAgB,EAAQ,CACpD,EAAQ,oBAAoB,eAAgB,EAAM,CAClD,EAAQ,oBAAoB,aAAc,EAAQ,CAClD,EAAQ,oBAAoB,WAAY,EAAM,CAC9C,KAAK,eAAe,GAAI,GAAK,KAC7B,KAAK,eAAe,GAAI,GAAK,KAE9B,EAAQ,QAAQ,CAChB,OAAO,KAAK,SAAS,IACpB,EAGH,YAAwB,CACvB,KAAK,QAAU,GACf,KAAK,eAAe,CACpB,KAAK,cAAc,QAAQ,CAC3B,KAAK,eAAiB"}
1
+ {"version":3,"file":"OverlayManager.js","names":[],"sources":["../../src/kernel/OverlayManager.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { BaseArgs } from '$/BaseModule';\nimport type { WithBorderWidth as Color } from '$/StyleManager';\nimport type { Hook } from '$/utilities';\nimport type {\n\tJSONCanvasFileNode,\n\tJSONCanvasLinkNode,\n\tJSONCanvasNode,\n\tJSONCanvasTextNode,\n\tParser,\n} from '@repo/shared';\nimport { BaseModule } from '$/BaseModule';\nimport Controller from '$/Controller';\nimport DataManager from '$/DataManager';\nimport InteractionHandler from '$/InteractionHandler';\nimport StyleManager from '$/StyleManager';\nimport { destroyError, makeHook } from '$/utilities';\n\ntype Options = {\n\tparser?: Parser;\n\tnodeComponents?: Partial<ComponentDict>;\n} & BaseOptions;\n\ntype Augmentation = {\n\tonNodeActive: OverlayManager['onNodeActive'];\n\tonNodeLosesActive: OverlayManager['onNodeLosesActive'];\n};\n\nconst fileRegex = {\n\taudio: /\\.(mp3|wav|ogg|opus|aac|m4a|flac)$/i,\n\timage: /\\.(png|jpg|jpeg|gif|svg|webp|avif|bmp|ico|heic|heif)$/i,\n\tmarkdown: /\\.(md|mdx|markdown|txt)$/i,\n\tvideo: /\\.(mp4|webm|ogv|mov|m3u8|mpd)$/i,\n};\n\ntype NodeComponentHook<N extends JSONCanvasNode> = (options: {\n\tcontainer: HTMLDivElement;\n\tcontent: string;\n\tnode: N;\n\tonBeforeUnmount: Hook;\n\tonActive: Hook;\n\tonLoseActive: Hook;\n}) => void | Promise<void>;\n\ntype CreateOverlayArgs =\n\t| [ComponentNodeMap['text'], string, 'text']\n\t| [ComponentNodeMap['markdown'], string, 'markdown']\n\t| [ComponentNodeMap['image'], string, 'image']\n\t| [ComponentNodeMap['audio'], string, 'audio']\n\t| [ComponentNodeMap['video'], string, 'video']\n\t| [ComponentNodeMap['link'], string, 'link'];\n\ntype ComponentNodeMap = {\n\ttext: JSONCanvasTextNode;\n\tmarkdown: JSONCanvasFileNode;\n\timage: JSONCanvasFileNode;\n\taudio: JSONCanvasFileNode;\n\tvideo: JSONCanvasFileNode;\n\tlink: JSONCanvasLinkNode;\n};\n\ntype ComponentDict = {\n\t[K in keyof ComponentNodeMap]: NodeComponentHook<ComponentNodeMap[K]>;\n};\n\nconst supportedTypes = ['markdown', 'image', 'audio', 'video'] as const;\n\nexport default class OverlayManager extends BaseModule<Options, Augmentation> {\n\tprivate _overlaysLayer?: HTMLDivElement = document.createElement('div');\n\tprivate overlays: Record<string, HTMLDivElement> = {}; // { id: node } the overlays in viewport\n\tprivate selectedId?: string;\n\tprivate aborted = false;\n\tprivate eventListeners: Record<string, Array<EventListener | undefined>> = {};\n\tprivate readonly DM: DataManager;\n\tprivate readonly SM: StyleManager;\n\tprivate readonly parse: Parser;\n\tprivate readonly componentDict: ComponentDict = {\n\t\taudio: ({ container, content }) => {\n\t\t\tconst audio = document.createElement('audio');\n\t\t\taudio.className = 'JCV-audio';\n\t\t\taudio.src = content;\n\t\t\taudio.controls = true;\n\t\t\tcontainer.appendChild(audio);\n\t\t},\n\t\timage: ({ container, content }) => {\n\t\t\tconst img = document.createElement('img');\n\t\t\timg.className = 'JCV-img';\n\t\t\timg.src = content;\n\t\t\timg.loading = 'lazy';\n\t\t\tcontainer.appendChild(img);\n\t\t},\n\t\tlink: ({ container, content }) => {\n\t\t\tconst iframe = document.createElement('iframe');\n\t\t\tiframe.src = content;\n\t\t\tiframe.sandbox = 'allow-scripts allow-same-origin';\n\t\t\tiframe.className = 'JCV-link-iframe';\n\t\t\tiframe.loading = 'lazy';\n\t\t\tcontainer.appendChild(iframe);\n\t\t},\n\t\tmarkdown: async ({ container, content }) => {\n\t\t\tcontainer.classList.add('JCV-markdown-content');\n\t\t\tconst parsedContentWrapper = document.createElement('div');\n\t\t\tparsedContentWrapper.textContent = 'Loading...';\n\t\t\tparsedContentWrapper.classList.add('JCV-parsed-content-wrapper');\n\t\t\tcontainer.appendChild(parsedContentWrapper);\n\t\t\tlet parsedContent: string;\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(content);\n\t\t\t\tconst result = await response.text();\n\t\t\t\tconst frontmatterMatch = /^---\\n([\\s\\S]*?)\\n---\\n([\\s\\S]*)$/.exec(result);\n\t\t\t\tparsedContent = await this.parse(frontmatterMatch ? frontmatterMatch[2] : result);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error('[JSON Canvas Viewer] Failed to load markdown:', error);\n\t\t\t\tparsedContent = 'Failed to load content.';\n\t\t\t}\n\t\t\tparsedContentWrapper.innerHTML = parsedContent;\n\t\t},\n\t\ttext: ({ container, content }) => {\n\t\t\tcontainer.classList.add('JCV-markdown-content');\n\t\t\tconst parsedContentWrapper = document.createElement('div');\n\t\t\tparsedContentWrapper.innerHTML = content;\n\t\t\tparsedContentWrapper.classList.add('JCV-parsed-content-wrapper');\n\t\t\tcontainer.appendChild(parsedContentWrapper);\n\t\t},\n\t\tvideo: ({ container, content }) => {\n\t\t\tconst video = document.createElement('video');\n\t\t\tvideo.className = 'JCV-video';\n\t\t\tvideo.src = content;\n\t\t\tvideo.controls = true;\n\t\t\tcontainer.appendChild(video);\n\t\t},\n\t};\n\n\tprivate get overlaysLayer() {\n\t\tif (!this._overlaysLayer) throw destroyError;\n\t\treturn this._overlaysLayer;\n\t}\n\n\tonInteractionStart = makeHook();\n\tonInteractionEnd = makeHook();\n\tonNodeActive = makeHook<[JSONCanvasNode]>();\n\tonNodeLosesActive = makeHook<[JSONCanvasNode]>();\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tthis.parse = this.options.parser ?? ((markdown: string) => markdown);\n\t\tthis.DM = this.container.get(DataManager);\n\t\tthis.SM = this.container.get(StyleManager);\n\t\tconst controller = this.container.get(Controller);\n\t\tcontroller.onRefresh.subscribe(this.updateOverlays);\n\t\tthis.SM.onChangeTheme.subscribe(this.themeChanged);\n\n\t\tthis._overlaysLayer = document.createElement('div');\n\t\tthis._overlaysLayer.className = 'JCV-overlays';\n\t\tthis._overlaysLayer.id = 'overlays';\n\t\tthis.DM.data.container.appendChild(this.overlaysLayer);\n\n\t\tconst components = this.options.nodeComponents;\n\t\tif (components) Object.assign(this.componentDict, components);\n\n\t\tthis.augment({\n\t\t\tonNodeActive: this.onNodeActive,\n\t\t\tonNodeLosesActive: this.onNodeLosesActive,\n\t\t});\n\t\tthis.onStart(this.start);\n\t\tthis.onRestart(this.restart);\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\tprivate readonly start = () => {\n\t\tthis.container.get(InteractionHandler).onClick.subscribe(this.select);\n\t\tthis.renderOverlays();\n\t};\n\n\tprivate readonly restart = () => {\n\t\tthis.clearOverlays();\n\t\tthis.renderOverlays();\n\t};\n\n\tprivate readonly renderOverlays = () => {\n\t\tconst overlayMatcher = async (node: JSONCanvasNode) => {\n\t\t\tswitch (node.type) {\n\t\t\t\tcase 'text': {\n\t\t\t\t\tthis.createOverlay(node, await this.parse(node.text), 'text');\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'file': {\n\t\t\t\t\tfor (const type of supportedTypes) {\n\t\t\t\t\t\tif (!node.file.match(fileRegex[type])) continue;\n\t\t\t\t\t\tthis.createOverlay(node, node.file, type);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'link': {\n\t\t\t\t\tthis.createOverlay(node, node.url, 'link');\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tObject.values(this.DM.data.nodeMap).forEach(async (node) => {\n\t\t\tawait overlayMatcher(node.ref);\n\t\t});\n\t};\n\n\tprivate readonly themeChanged = () => {\n\t\tObject.values(this.overlays).forEach((overlay) => {\n\t\t\tconst node = this.DM.data.nodeMap[overlay.id].ref;\n\t\t\tconst color = this.SM.getColor(node.color);\n\t\t\tthis.setOverlayColor(overlay, color);\n\t\t});\n\t};\n\n\tprivate readonly select = (id?: string) => {\n\t\tconst previousId = this.selectedId;\n\t\tconst previous = previousId ? this.overlays[previousId] : undefined;\n\t\tconst current = id ? this.overlays[id] : undefined;\n\t\tif (previous && previousId) {\n\t\t\tprevious.classList.remove('JCV-active');\n\t\t\tconst nodeItem = this.DM.data.nodeMap[previousId];\n\t\t\tthis.onNodeLosesActive(nodeItem.ref);\n\t\t\tnodeItem.onLoseActive?.();\n\t\t}\n\t\tif (current && id) {\n\t\t\tcurrent.classList.add('JCV-active');\n\t\t\tthis.onInteractionStart();\n\t\t\tconst nodeItem = this.DM.data.nodeMap[id];\n\t\t\tthis.onNodeActive(nodeItem.ref);\n\t\t\tnodeItem.onActive?.();\n\t\t} else this.onInteractionEnd();\n\t\tthis.selectedId = id;\n\t};\n\n\tprivate readonly updateOverlays = () => {\n\t\tconst data = this.DM.data;\n\t\tthis.overlaysLayer.style.transform = `translate(${data.offsetX}px, ${data.offsetY}px) scale(${data.scale})`;\n\t};\n\n\tprivate readonly createOverlay = (...args: CreateOverlayArgs) => {\n\t\tif (this.aborted) return;\n\t\tconst node = args[0];\n\t\tlet element = this.overlays[node.id];\n\t\tif (!element) {\n\t\t\telement = this.constructOverlay(...args);\n\t\t\tif (this.aborted) return;\n\t\t\tthis.overlaysLayer.appendChild(element);\n\t\t\tthis.overlays[node.id] = element;\n\t\t\telement.style.left = `${node.x}px`;\n\t\t\telement.style.top = `${node.y}px`;\n\t\t\telement.style.width = `${node.width}px`;\n\t\t\telement.style.height = `${node.height}px`;\n\t\t}\n\t};\n\n\tprivate readonly constructOverlay = (...args: CreateOverlayArgs) => {\n\t\tconst node = args[0];\n\t\tconst overlay = document.createElement('div');\n\t\toverlay.classList.add('JCV-overlay-container');\n\t\toverlay.id = node.id;\n\t\tthis.setOverlayColor(overlay, this.SM.getColor(node.color));\n\t\tconst contentWrapper = document.createElement('div');\n\t\tcontentWrapper.classList.add('JCV-content');\n\t\toverlay.appendChild(contentWrapper);\n\t\tconst clickLayer = document.createElement('div');\n\t\tclickLayer.className = 'JCV-click-layer';\n\t\toverlay.appendChild(clickLayer);\n\t\tconst overlayBorder = document.createElement('div');\n\t\toverlayBorder.className = 'JCV-overlay-border';\n\t\toverlay.appendChild(overlayBorder);\n\t\tconst nodeItem = this.DM.data.nodeMap[node.id];\n\n\t\tnodeItem.onActive = makeHook();\n\t\tnodeItem.onLoseActive = makeHook();\n\t\tnodeItem.onBeforeUnmount = makeHook();\n\n\t\tvoid this.componentDict[args[2]]({\n\t\t\tcontainer: contentWrapper,\n\t\t\tcontent: args[1],\n\t\t\tnode: args[0] as never,\n\t\t\tonActive: nodeItem.onActive,\n\t\t\tonBeforeUnmount: nodeItem.onBeforeUnmount,\n\t\t\tonLoseActive: nodeItem.onLoseActive,\n\t\t});\n\t\tconst onStart = () => {\n\t\t\tif (node.id === this.selectedId) this.onInteractionStart();\n\t\t};\n\t\tconst onEnd = () => {\n\t\t\tif (node.id === this.selectedId) this.onInteractionEnd();\n\t\t};\n\t\toverlay.addEventListener('pointerenter', onStart);\n\t\toverlay.addEventListener('pointerleave', onEnd);\n\t\toverlay.addEventListener('touchstart', onStart);\n\t\toverlay.addEventListener('touchend', onEnd);\n\t\tthis.eventListeners[node.id] = [onStart, onEnd];\n\t\treturn overlay;\n\t};\n\n\tprivate readonly setOverlayColor = (overlay: HTMLDivElement, color: Color) => {\n\t\tObject.entries(color).forEach(([key, value]) => {\n\t\t\toverlay.style.setProperty(`--overlay-${key}`, value);\n\t\t});\n\t};\n\n\tprivate readonly clearOverlays = () => {\n\t\tObject.entries(this.overlays).forEach(([id, overlay]) => {\n\t\t\tthis.DM.data.nodeMap[id].onBeforeUnmount?.();\n\t\t\tif (this.eventListeners[id]) {\n\t\t\t\tconst onStart = this.eventListeners[id][0];\n\t\t\t\tconst onEnd = this.eventListeners[id][1];\n\t\t\t\tif (!onStart || !onEnd) throw destroyError;\n\t\t\t\toverlay.removeEventListener('pointerenter', onStart);\n\t\t\t\toverlay.removeEventListener('pointerleave', onEnd);\n\t\t\t\toverlay.removeEventListener('touchstart', onStart);\n\t\t\t\toverlay.removeEventListener('touchend', onEnd);\n\t\t\t\tthis.eventListeners[id][0] = undefined;\n\t\t\t\tthis.eventListeners[id][1] = undefined;\n\t\t\t}\n\t\t\toverlay.remove();\n\t\t\tdelete this.overlays[id];\n\t\t});\n\t};\n\n\tprivate readonly dispose = () => {\n\t\tthis.aborted = true;\n\t\tthis.clearOverlays();\n\t\tthis.overlaysLayer.remove();\n\t\tthis._overlaysLayer = undefined;\n\t};\n}\n"],"mappings":"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"}
@@ -2,34 +2,35 @@ import { BaseArgs, BaseModule } from "./BaseModule.js";
2
2
  import { BaseOptions } from "./index.js";
3
3
 
4
4
  //#region src/kernel/Renderer.d.ts
5
- interface Options extends BaseOptions {
5
+ type Options = {
6
6
  zoomInOptimization?: boolean;
7
- }
7
+ } & BaseOptions;
8
8
  declare class Renderer extends BaseModule<Options> {
9
- private _canvas;
10
- private ctx;
11
- private DM;
12
- private SM;
13
- private zoomInOptimize;
9
+ private _canvas?;
10
+ private readonly ctx;
11
+ private readonly DM;
12
+ private readonly SM;
13
+ private readonly zoomInOptimize;
14
14
  private get canvas();
15
15
  constructor(...args: BaseArgs);
16
- private optimizeDPR;
17
- private redraw;
16
+ private readonly optimizeDPR;
17
+ private readonly redraw;
18
18
  private trueRedraw;
19
19
  private fakeRedraw;
20
- private isInside;
21
- private isOutside;
22
- private getCurrentViewport;
23
- private drawLabelBar;
24
- private drawNodeBackground;
25
- private drawGroup;
26
- private drawFile;
27
- private drawEdge;
28
- private getControlPoints;
29
- private drawGridDots;
30
- private drawCurvedPath;
31
- private drawArrowhead;
32
- private dispose;
20
+ private readonly isInside;
21
+ private readonly isOutside;
22
+ private readonly getCurrentViewport;
23
+ private readonly drawLabelBar;
24
+ private readonly drawNodeBackground;
25
+ private readonly drawGroup;
26
+ private readonly drawFile;
27
+ private readonly drawEdge;
28
+ private readonly drawEdgeLabel;
29
+ private readonly getControlPoints;
30
+ private readonly drawGridDots;
31
+ private readonly drawCurvedPath;
32
+ private readonly drawArrowhead;
33
+ private readonly dispose;
33
34
  }
34
35
  //#endregion
35
36
  export { Renderer };
@@ -1,2 +1,3 @@
1
- import{BaseModule as e}from"./BaseModule.js";import t,{destroyError as n}from"./utilities.js";import r from"./DataManager.js";import i from"./StyleManager.js";import a from"./Controller.js";var o=class extends e{_canvas;ctx;DM;SM;zoomInOptimize={lastDrawnScale:0,lastDrawnViewport:{left:0,right:0,top:0,bottom:0},timeout:null,lastCallTime:0};get canvas(){if(!this._canvas)throw n;return this._canvas}constructor(...e){super(...e);let t=this.container.get(a);this.SM=this.container.get(i),t.onRefresh.subscribe(this.redraw),t.onResize.subscribe(this.optimizeDPR),this.DM=this.container.get(r),this._canvas=document.createElement(`canvas`),this._canvas.className=`JCV-main-canvas`,this.ctx=this._canvas.getContext(`2d`),this.DM.data.container.appendChild(this._canvas),this.onDispose(this.dispose)}optimizeDPR=()=>{let e=this.DM.data.container;t.resizeCanvasForDPR(this.canvas,e.offsetWidth,e.offsetHeight)};redraw=()=>{let e=this.DM.data.offsetX,t=this.DM.data.offsetY,n=this.DM.data.scale,r=this.getCurrentViewport(e,t,n);if(!this.options.zoomInOptimization){this.trueRedraw(e,t,n,r);return}this.zoomInOptimize.timeout&&(clearTimeout(this.zoomInOptimize.timeout),this.zoomInOptimize.timeout=null);let i=Date.now();if(this.isInside(r,this.zoomInOptimize.lastDrawnViewport)&&n!==this.zoomInOptimize.lastDrawnScale&&i-this.zoomInOptimize.lastCallTime<500){this.zoomInOptimize.timeout=window.setTimeout(()=>{this.trueRedraw(e,t,n,r),this.zoomInOptimize.lastCallTime=i,this.zoomInOptimize.timeout=null},60),this.fakeRedraw(r,n);return}this.zoomInOptimize.lastCallTime=i,this.trueRedraw(e,t,n,r)};trueRedraw(e,t,n,r){this.zoomInOptimize.lastDrawnViewport=r,this.zoomInOptimize.lastDrawnScale=n,this.canvas.style.transform=``,this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.save(),this.drawGridDots(n,e,t),this.ctx.translate(e,t),this.ctx.scale(n,n),Object.values(this.DM.data.nodeMap).forEach(e=>{if(this.isOutside(e.box,r))return;let t=e.ref;t.type===`file`?this.drawFile(e):t.type===`group`&&this.drawGroup(t,n)}),Object.values(this.DM.data.edgeMap).forEach(e=>{this.isOutside(e.box,r)||this.drawEdge(e)}),this.ctx.restore()}fakeRedraw(e,t){let n=t/this.zoomInOptimize.lastDrawnScale,r=(this.zoomInOptimize.lastDrawnViewport.left-e.left)*t,i=(this.zoomInOptimize.lastDrawnViewport.top-e.top)*t;this.canvas.style.transform=`translate(${r}px, ${i}px) scale(${n})`}isInside=(e,t)=>e.left>t.left&&e.top>t.top&&e.right<t.right&&e.bottom<t.bottom;isOutside=(e,t)=>e.right<t.left||e.bottom<t.top||e.left>t.right||e.top>t.bottom;getCurrentViewport=(e,t,n)=>{let r=-e/n,i=-t/n,a=this.DM.data.container;return{left:r,top:i,right:r+a.clientWidth/n,bottom:i+a.clientHeight/n}};drawLabelBar=(e,t,n,r,i,a)=>{let o=30*a,s=6*a,c=8*a,l=16*a,u=6*a;this.ctx.save(),this.ctx.translate(e,t),this.ctx.scale(1/a,1/a),this.ctx.font=`${l}px 'Inter', sans-serif`;let d=this.ctx.measureText(n).width+2*u;this.ctx.translate(0,-o-c),this.ctx.fillStyle=r,this.ctx.beginPath(),this.ctx.moveTo(s,0),this.ctx.lineTo(d-s,0),this.ctx.quadraticCurveTo(d,0,d,s),this.ctx.lineTo(d,o-s),this.ctx.quadraticCurveTo(d,o,d-s,o),this.ctx.lineTo(s,o),this.ctx.quadraticCurveTo(0,o,0,o-s),this.ctx.lineTo(0,s),this.ctx.quadraticCurveTo(0,0,s,0),this.ctx.closePath(),this.ctx.fill(),this.ctx.fillStyle=i,this.ctx.fillText(n,u,o*.65),this.ctx.restore()};drawNodeBackground=e=>{let n=this.SM.getColor(e.color);this.ctx.globalAlpha=1,this.ctx.fillStyle=n.background,t.drawRoundRect(this.ctx,e.x+1,e.y+1,e.width-2,e.height-2,12),this.ctx.fill(),this.ctx.strokeStyle=n.border,this.ctx.lineWidth=2,t.drawRoundRect(this.ctx,e.x,e.y,e.width,e.height,12),this.ctx.stroke()};drawGroup=(e,t)=>{if(this.drawNodeBackground(e),e.label){let n=this.SM.getColor(e.color);this.drawLabelBar(e.x,e.y,e.label,n.active,n.text,t)}};drawFile=e=>{this.ctx.fillStyle=this.SM.getColor().text;let t=e.ref;this.ctx.font=`16px sans-serif`,this.ctx.fillText(e.fileName??``,t.x+5,t.y-10)};drawEdge=e=>{let n=e.ref,r=this.DM.data.nodeMap[n.fromNode].ref,i=this.DM.data.nodeMap[n.toNode].ref,a=t.getAnchorCoord,{x:o,y:s}=a(r,n.fromSide),{x:c,y:l}=a(i,n.toSide),u=this.SM.getColor(n.color),[d,f,p,m]=[0,0,0,0];if(e.controlPoints?[d,f,p,m]=e.controlPoints:([d,f,p,m]=this.getControlPoints(o,s,c,l,n.fromSide,n.toSide),e.controlPoints=[d,f,p,m]),this.drawCurvedPath(o,s,c,l,d,f,p,m,u.active),this.drawArrowhead(c,l,p,m,u.active),n.label){let e=.5,r=(1-e)**3*o+3*(1-e)**2*e*d+3*(1-e)*e*e*p+e**3*c,i=(1-e)**3*s+3*(1-e)**2*e*f+3*(1-e)*e*e*m+e**3*l;this.ctx.font=`18px sans-serif`;let a=this.ctx.measureText(n.label).width+16;this.ctx.fillStyle=u.active,this.ctx.beginPath(),t.drawRoundRect(this.ctx,r-a/2,i-20/2-2,a,20,4),this.ctx.fill(),this.ctx.fillStyle=u.text,this.ctx.textAlign=`center`,this.ctx.textBaseline=`middle`,this.ctx.fillText(n.label,r,i-2),this.ctx.textAlign=`left`,this.ctx.textBaseline=`alphabetic`}};getControlPoints=(e,t,n,r,i,a)=>{let o=n-e,s=r-t,c=((e,t,n)=>Math.max(t,Math.min(n,e)))((Math.min(Math.abs(o),Math.abs(s))+.3*Math.max(Math.abs(o),Math.abs(s)))*.5,60,300),l=e,u=t,d=n,f=r;switch(i){case`top`:u=t-c;break;case`bottom`:u=t+c;break;case`left`:l=e-c;break;case`right`:l=e+c;break}switch(a){case`top`:f=r-c;break;case`bottom`:f=r+c;break;case`left`:d=n-c;break;case`right`:d=n+c;break}return[l,u,d,f]};drawGridDots=(e,t,n)=>{let r=10*2**-Math.floor(Math.log2(e))*e,i=this.canvas.width,a=this.canvas.height,o=t%r,s=n%r;this.ctx.fillStyle=this.SM.getNamedColor(`dots`);for(let e=o;e<=i;e+=r)for(let t=s;t<=a;t+=r)this.ctx.beginPath(),this.ctx.arc(e,t,1,0,2*Math.PI),this.ctx.fill()};drawCurvedPath=(e,t,n,r,i,a,o,s,c)=>{this.ctx.beginPath(),this.ctx.moveTo(e,t),this.ctx.bezierCurveTo(i,a,o,s,n,r),this.ctx.strokeStyle=c,this.ctx.lineWidth=2,this.ctx.stroke()};drawArrowhead=(e,t,n,r,i)=>{let a=e-n,o=t-r,s=Math.sqrt(a*a+o*o);if(s===0)return;let c=a/s,l=o/s,u=e-c*12-l*4,d=t-l*12+c*4,f=e-c*12+l*4,p=t-l*12-c*4;this.ctx.beginPath(),this.ctx.fillStyle=i,this.ctx.moveTo(e,t),this.ctx.lineTo(u,d),this.ctx.lineTo(f,p),this.ctx.closePath(),this.ctx.fill()};dispose=()=>{this.zoomInOptimize.timeout&&(clearTimeout(this.zoomInOptimize.timeout),this.zoomInOptimize.timeout=null),this.canvas.remove(),this._canvas=null}};export{o as default};
1
+ import{BaseModule as e}from"./BaseModule.js";import{destroyError as t,drawRoundRect as n,getAnchorCoord as r,resizeCanvasForDPR as i}from"./utilities.js";import a from"./DataManager.js";import o from"./StyleManager.js";import s from"./Controller.js";var c=class extends e{_canvas;ctx;DM;SM;zoomInOptimize={lastCallTime:0,lastDrawnScale:0,lastDrawnViewport:{bottom:0,left:0,right:0,top:0}};get canvas(){if(!this._canvas)throw t;return this._canvas}constructor(...e){super(...e);let t=this.container.get(s);this.SM=this.container.get(o),t.onRefresh.subscribe(this.redraw),t.onResize.subscribe(this.optimizeDPR),this.DM=this.container.get(a),this._canvas=document.createElement(`canvas`),this._canvas.className=`JCV-main-canvas`,this.ctx=this._canvas.getContext(`2d`),this.DM.data.container.appendChild(this._canvas),this.onDispose(this.dispose)}optimizeDPR=()=>{let e=this.DM.data.container;i(this.canvas,e.offsetWidth,e.offsetHeight)};redraw=()=>{let e=this.DM.data.offsetX,t=this.DM.data.offsetY,n=this.DM.data.scale,r=this.getCurrentViewport(e,t,n);if(!this.options.zoomInOptimization){this.trueRedraw(e,t,n,r);return}this.zoomInOptimize.timeout&&(clearTimeout(this.zoomInOptimize.timeout),this.zoomInOptimize.timeout=void 0);let i=Date.now();if(this.isInside(r,this.zoomInOptimize.lastDrawnViewport)&&n!==this.zoomInOptimize.lastDrawnScale&&i-this.zoomInOptimize.lastCallTime<500){this.zoomInOptimize.timeout=window.setTimeout(()=>{this.trueRedraw(e,t,n,r),this.zoomInOptimize.lastCallTime=i,this.zoomInOptimize.timeout=void 0},60),this.fakeRedraw(r,n);return}this.zoomInOptimize.lastCallTime=i,this.trueRedraw(e,t,n,r)};trueRedraw(e,t,n,r){this.zoomInOptimize.lastDrawnViewport=r,this.zoomInOptimize.lastDrawnScale=n,this.canvas.style.transform=``,this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.save(),this.drawGridDots(n,e,t),this.ctx.translate(e,t),this.ctx.scale(n,n),Object.values(this.DM.data.nodeMap).forEach(e=>{if(this.isOutside(e.box,r))return;let t=e.ref;t.type===`file`?this.drawFile(e):t.type===`group`&&this.drawGroup(t,n)}),Object.values(this.DM.data.edgeMap).forEach(e=>{this.isOutside(e.box,r)||this.drawEdge(e)}),this.ctx.restore()}fakeRedraw(e,t){let n=t/this.zoomInOptimize.lastDrawnScale,r=(this.zoomInOptimize.lastDrawnViewport.left-e.left)*t,i=(this.zoomInOptimize.lastDrawnViewport.top-e.top)*t;this.canvas.style.transform=`translate(${r}px, ${i}px) scale(${n})`}isInside=(e,t)=>e.left>t.left&&e.top>t.top&&e.right<t.right&&e.bottom<t.bottom;isOutside=(e,t)=>e.right<t.left||e.bottom<t.top||e.left>t.right||e.top>t.bottom;getCurrentViewport=(e,t,n)=>{let r=-e/n,i=-t/n,a=this.DM.data.container,o=r+a.clientWidth/n;return{bottom:i+a.clientHeight/n,left:r,right:o,top:i}};drawLabelBar=(e,t,n,r,i,a)=>{let o=30*a,s=6*a,c=8*a,l=16*a,u=6*a;this.ctx.save(),this.ctx.translate(e,t),this.ctx.scale(1/a,1/a),this.ctx.font=`${l}px 'Inter', sans-serif`;let d=this.ctx.measureText(n).width+2*u;this.ctx.translate(0,-o-c),this.ctx.fillStyle=r,this.ctx.beginPath(),this.ctx.moveTo(s,0),this.ctx.lineTo(d-s,0),this.ctx.quadraticCurveTo(d,0,d,s),this.ctx.lineTo(d,o-s),this.ctx.quadraticCurveTo(d,o,d-s,o),this.ctx.lineTo(s,o),this.ctx.quadraticCurveTo(0,o,0,o-s),this.ctx.lineTo(0,s),this.ctx.quadraticCurveTo(0,0,s,0),this.ctx.closePath(),this.ctx.fill(),this.ctx.fillStyle=i,this.ctx.fillText(n,u,o*.65),this.ctx.restore()};drawNodeBackground=e=>{let t=this.SM.getColor(e.color);this.ctx.globalAlpha=1,this.ctx.fillStyle=t.background,n(this.ctx,e.x+1,e.y+1,e.width-2,e.height-2,12),this.ctx.fill(),this.ctx.strokeStyle=t.border,this.ctx.lineWidth=2,n(this.ctx,e.x,e.y,e.width,e.height,12),this.ctx.stroke()};drawGroup=(e,t)=>{if(this.drawNodeBackground(e),e.label){let n=this.SM.getColor(e.color);this.drawLabelBar(e.x,e.y,e.label,n.active,n.text,t)}};drawFile=e=>{this.ctx.fillStyle=this.SM.getColor().text;let t=e.ref;this.ctx.font=`16px sans-serif`,this.ctx.fillText(e.fileName??``,t.x+5,t.y-10)};drawEdge=e=>{let t=e.ref,n=this.DM.data.nodeMap[t.fromNode].ref,i=this.DM.data.nodeMap[t.toNode].ref,{x:a,y:o}=r(n,t.fromSide),{x:s,y:c}=r(i,t.toSide),l=this.SM.getColor(t.color),u,d,f,p;e.controlPoints?[u,d,f,p]=e.controlPoints:([u,d,f,p]=this.getControlPoints(a,o,s,c,t.fromSide,t.toSide),e.controlPoints=[u,d,f,p]),this.drawCurvedPath(a,o,s,c,u,d,f,p,l.active),this.drawArrowhead(s,c,f,p,l.active),t.label&&this.drawEdgeLabel(a,o,s,c,u,d,f,p,t.label,l.active,l.text)};drawEdgeLabel=(e,t,r,i,a,o,s,c,l,u,d)=>{let f=.5,p=(1-f)**3*e+3*(1-f)**2*f*a+3*(1-f)*f*f*s+f**3*r,m=(1-f)**3*t+3*(1-f)**2*f*o+3*(1-f)*f*f*c+f**3*i;this.ctx.font=`18px sans-serif`;let h=l.split(`
2
+ `),g=0;for(let e of h){let t=this.ctx.measureText(e).width;t>g&&(g=t)}let _=g+16,v=h.length*17+6;this.ctx.fillStyle=u,this.ctx.beginPath(),n(this.ctx,p-_/2,m-v/2-2,_,v,4),this.ctx.fill(),this.ctx.fillStyle=d,this.ctx.textAlign=`center`,this.ctx.textBaseline=`middle`;for(let e=0;e<h.length;e++){let t=(e-(h.length-1)/2)*17;this.ctx.fillText(h[e],p,m-2+t)}this.ctx.textAlign=`left`,this.ctx.textBaseline=`alphabetic`};getControlPoints=(e,t,n,r,i,a)=>{let o=n-e,s=r-t,c=((e,t,n)=>Math.max(t,Math.min(n,e)))((Math.min(Math.abs(o),Math.abs(s))+.3*Math.max(Math.abs(o),Math.abs(s)))*.5,60,300),l=e,u=t,d=n,f=r;switch(i){case`top`:u=t-c;break;case`bottom`:u=t+c;break;case`left`:l=e-c;break;case`right`:l=e+c;break}switch(a){case`top`:f=r-c;break;case`bottom`:f=r+c;break;case`left`:d=n-c;break;case`right`:d=n+c;break}return[l,u,d,f]};drawGridDots=(e,t,n)=>{let r=10*2**-Math.floor(Math.log2(e))*e,i=this.canvas.width,a=this.canvas.height,o=t%r,s=n%r;this.ctx.fillStyle=this.SM.getNamedColor(`dots`);for(let e=o;e<=i;e+=r)for(let t=s;t<=a;t+=r)this.ctx.beginPath(),this.ctx.arc(e,t,1,0,2*Math.PI),this.ctx.fill()};drawCurvedPath=(e,t,n,r,i,a,o,s,c)=>{this.ctx.beginPath(),this.ctx.moveTo(e,t),this.ctx.bezierCurveTo(i,a,o,s,n,r),this.ctx.strokeStyle=c,this.ctx.lineWidth=2,this.ctx.stroke()};drawArrowhead=(e,t,n,r,i)=>{let a=e-n,o=t-r,s=Math.sqrt(a*a+o*o);if(s===0)return;let c=a/s,l=o/s,u=e-c*12-l*4,d=t-l*12+c*4,f=e-c*12+l*4,p=t-l*12-c*4;this.ctx.beginPath(),this.ctx.fillStyle=i,this.ctx.moveTo(e,t),this.ctx.lineTo(u,d),this.ctx.lineTo(f,p),this.ctx.closePath(),this.ctx.fill()};dispose=()=>{this.zoomInOptimize.timeout&&(clearTimeout(this.zoomInOptimize.timeout),this.zoomInOptimize.timeout=void 0),this.canvas.remove(),this._canvas=void 0}};export{c as default};
2
3
  //# sourceMappingURL=Renderer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Renderer.js","names":["utilities"],"sources":["../../src/kernel/Renderer.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { Box } from '$/types';\nimport type { JSONCanvasGroupNode, JSONCanvasNode } from '@repo/shared';\nimport { type BaseArgs, BaseModule } from '$/BaseModule';\nimport Controller from '$/Controller';\nimport DataManager, { type EdgeItem, type NodeItem } from '$/DataManager';\nimport StyleManager from '$/StyleManager';\nimport utilities, { destroyError } from '$/utilities';\n\nconst ARROW_LENGTH = 12;\nconst ARROW_WIDTH = 4;\nconst NODE_RADIUS = 12;\nconst CSS_ZOOM_REDRAW_INTERVAL = 500;\nconst NODE_BORDER_WIDTH = 2;\nconst DOT_RADIUS = 1; // Dot radius in CSS pixels\nconst DOT_BASE_GAP = 10; // Base gap between dots in CSS pixels\n\nconst NODE_BORDER_HALF_WIDTH = NODE_BORDER_WIDTH / 2;\n\ninterface Options extends BaseOptions {\n\tzoomInOptimization?: boolean;\n}\n\nexport default class Renderer extends BaseModule<Options> {\n\tprivate _canvas: HTMLCanvasElement | null;\n\tprivate ctx: CanvasRenderingContext2D;\n\tprivate DM: DataManager;\n\tprivate SM: StyleManager;\n\tprivate zoomInOptimize: {\n\t\tlastDrawnScale: number;\n\t\tlastDrawnViewport: Box;\n\t\ttimeout: number | null;\n\t\tlastCallTime: number;\n\t} = {\n\t\tlastDrawnScale: 0,\n\t\tlastDrawnViewport: {\n\t\t\tleft: 0,\n\t\t\tright: 0,\n\t\t\ttop: 0,\n\t\t\tbottom: 0,\n\t\t},\n\t\ttimeout: null,\n\t\tlastCallTime: 0,\n\t};\n\n\tprivate get canvas() {\n\t\tif (!this._canvas) throw destroyError;\n\t\treturn this._canvas;\n\t}\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tconst controller = this.container.get(Controller);\n\t\tthis.SM = this.container.get(StyleManager);\n\t\tcontroller.onRefresh.subscribe(this.redraw);\n\t\tcontroller.onResize.subscribe(this.optimizeDPR);\n\t\tthis.DM = this.container.get(DataManager);\n\t\tthis._canvas = document.createElement('canvas');\n\t\tthis._canvas.className = 'JCV-main-canvas';\n\t\tthis.ctx = this._canvas.getContext('2d') as CanvasRenderingContext2D;\n\t\tthis.DM.data.container.appendChild(this._canvas);\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\tprivate optimizeDPR = () => {\n\t\tconst container = this.DM.data.container;\n\t\tutilities.resizeCanvasForDPR(this.canvas, container.offsetWidth, container.offsetHeight);\n\t};\n\n\tprivate redraw = () => {\n\t\tconst offsetX = this.DM.data.offsetX;\n\t\tconst offsetY = this.DM.data.offsetY;\n\t\tconst scale = this.DM.data.scale;\n\t\tconst currentViewport = this.getCurrentViewport(offsetX, offsetY, scale);\n\t\tif (!this.options.zoomInOptimization) {\n\t\t\tthis.trueRedraw(offsetX, offsetY, scale, currentViewport);\n\t\t\treturn;\n\t\t}\n\t\tif (this.zoomInOptimize.timeout) {\n\t\t\tclearTimeout(this.zoomInOptimize.timeout);\n\t\t\tthis.zoomInOptimize.timeout = null;\n\t\t}\n\t\tconst now = Date.now();\n\t\tif (\n\t\t\tthis.isInside(currentViewport, this.zoomInOptimize.lastDrawnViewport) &&\n\t\t\tscale !== this.zoomInOptimize.lastDrawnScale\n\t\t) {\n\t\t\tconst timeSinceLast = now - this.zoomInOptimize.lastCallTime;\n\t\t\tif (timeSinceLast < CSS_ZOOM_REDRAW_INTERVAL) {\n\t\t\t\tthis.zoomInOptimize.timeout = window.setTimeout(() => {\n\t\t\t\t\tthis.trueRedraw(offsetX, offsetY, scale, currentViewport);\n\t\t\t\t\tthis.zoomInOptimize.lastCallTime = now;\n\t\t\t\t\tthis.zoomInOptimize.timeout = null;\n\t\t\t\t}, 60);\n\t\t\t\tthis.fakeRedraw(currentViewport, scale);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tthis.zoomInOptimize.lastCallTime = now;\n\t\tthis.trueRedraw(offsetX, offsetY, scale, currentViewport);\n\t};\n\n\tprivate trueRedraw(offsetX: number, offsetY: number, scale: number, currentViewport: Box) {\n\t\tthis.zoomInOptimize.lastDrawnViewport = currentViewport;\n\t\tthis.zoomInOptimize.lastDrawnScale = scale;\n\t\tthis.canvas.style.transform = '';\n\t\tthis.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\n\t\tthis.ctx.save();\n\t\tthis.drawGridDots(scale, offsetX, offsetY);\n\t\tthis.ctx.translate(offsetX, offsetY);\n\t\tthis.ctx.scale(scale, scale);\n\t\tObject.values(this.DM.data.nodeMap).forEach((item) => {\n\t\t\tif (this.isOutside(item.box, currentViewport)) return;\n\t\t\tconst node = item.ref;\n\t\t\tif (node.type === 'file') this.drawFile(item);\n\t\t\telse if (node.type === 'group') this.drawGroup(node, scale);\n\t\t});\n\t\tObject.values(this.DM.data.edgeMap).forEach((item) => {\n\t\t\tif (this.isOutside(item.box, currentViewport)) return;\n\t\t\tthis.drawEdge(item);\n\t\t});\n\t\tthis.ctx.restore();\n\t}\n\n\tprivate fakeRedraw(currentViewport: Box, scale: number) {\n\t\tconst cssScale = scale / this.zoomInOptimize.lastDrawnScale;\n\t\tconst currentOffsetX =\n\t\t\t(this.zoomInOptimize.lastDrawnViewport.left - currentViewport.left) * scale;\n\t\tconst currentOffsetY =\n\t\t\t(this.zoomInOptimize.lastDrawnViewport.top - currentViewport.top) * scale;\n\t\tthis.canvas.style.transform = `translate(${currentOffsetX}px, ${currentOffsetY}px) scale(${cssScale})`;\n\t}\n\n\tprivate isInside = (inner: Box, outer: Box) =>\n\t\tinner.left > outer.left &&\n\t\tinner.top > outer.top &&\n\t\tinner.right < outer.right &&\n\t\tinner.bottom < outer.bottom;\n\n\tprivate isOutside = (inner: Box, outer: Box) =>\n\t\tinner.right < outer.left ||\n\t\tinner.bottom < outer.top ||\n\t\tinner.left > outer.right ||\n\t\tinner.top > outer.bottom;\n\n\tprivate getCurrentViewport = (offsetX: number, offsetY: number, scale: number) => {\n\t\tconst left = -offsetX / scale;\n\t\tconst top = -offsetY / scale;\n\t\tconst container = this.DM.data.container;\n\t\tconst right = left + container.clientWidth / scale;\n\t\tconst bottom = top + container.clientHeight / scale;\n\t\treturn { left, top, right, bottom };\n\t};\n\n\tprivate drawLabelBar = (\n\t\tx: number,\n\t\ty: number,\n\t\tlabel: string,\n\t\tcolor: string,\n\t\ttextColor: string,\n\t\tscale: number,\n\t) => {\n\t\tconst barHeight = 30 * scale;\n\t\tconst radius = 6 * scale;\n\t\tconst yOffset = 8 * scale;\n\t\tconst fontSize = 16 * scale;\n\t\tconst xPadding = 6 * scale;\n\t\tthis.ctx.save();\n\t\tthis.ctx.translate(x, y);\n\t\tthis.ctx.scale(1 / scale, 1 / scale);\n\t\tthis.ctx.font = `${fontSize}px 'Inter', sans-serif`;\n\t\tconst barWidth = this.ctx.measureText(label).width + 2 * xPadding;\n\t\tthis.ctx.translate(0, -barHeight - yOffset);\n\t\tthis.ctx.fillStyle = color;\n\t\tthis.ctx.beginPath();\n\t\tthis.ctx.moveTo(radius, 0);\n\t\tthis.ctx.lineTo(barWidth - radius, 0);\n\t\tthis.ctx.quadraticCurveTo(barWidth, 0, barWidth, radius);\n\t\tthis.ctx.lineTo(barWidth, barHeight - radius);\n\t\tthis.ctx.quadraticCurveTo(barWidth, barHeight, barWidth - radius, barHeight);\n\t\tthis.ctx.lineTo(radius, barHeight);\n\t\tthis.ctx.quadraticCurveTo(0, barHeight, 0, barHeight - radius);\n\t\tthis.ctx.lineTo(0, radius);\n\t\tthis.ctx.quadraticCurveTo(0, 0, radius, 0);\n\t\tthis.ctx.closePath();\n\t\tthis.ctx.fill();\n\t\tthis.ctx.fillStyle = textColor;\n\t\tthis.ctx.fillText(label, xPadding, barHeight * 0.65);\n\t\tthis.ctx.restore();\n\t};\n\n\tprivate drawNodeBackground = (node: JSONCanvasNode) => {\n\t\tconst colors = this.SM.getColor(node.color);\n\t\tconst radius = NODE_RADIUS;\n\t\tthis.ctx.globalAlpha = 1.0;\n\t\tthis.ctx.fillStyle = colors.background;\n\t\tutilities.drawRoundRect(\n\t\t\tthis.ctx,\n\t\t\tnode.x + NODE_BORDER_HALF_WIDTH,\n\t\t\tnode.y + NODE_BORDER_HALF_WIDTH,\n\t\t\tnode.width - NODE_BORDER_WIDTH,\n\t\t\tnode.height - NODE_BORDER_WIDTH,\n\t\t\tradius,\n\t\t);\n\t\tthis.ctx.fill();\n\t\tthis.ctx.strokeStyle = colors.border;\n\t\tthis.ctx.lineWidth = NODE_BORDER_WIDTH;\n\t\tutilities.drawRoundRect(this.ctx, node.x, node.y, node.width, node.height, radius);\n\t\tthis.ctx.stroke();\n\t};\n\n\tprivate drawGroup = (node: JSONCanvasGroupNode, scale: number) => {\n\t\tthis.drawNodeBackground(node);\n\t\tif (node.label) {\n\t\t\tconst color = this.SM.getColor(node.color);\n\t\t\tthis.drawLabelBar(node.x, node.y, node.label, color.active, color.text, scale);\n\t\t}\n\t};\n\n\tprivate drawFile = (item: NodeItem) => {\n\t\tthis.ctx.fillStyle = this.SM.getColor().text;\n\t\tconst node = item.ref;\n\t\tthis.ctx.font = '16px sans-serif';\n\t\tthis.ctx.fillText(item.fileName ?? '', node.x + 5, node.y - 10);\n\t};\n\n\tprivate drawEdge = (item: EdgeItem) => {\n\t\tconst edge = item.ref;\n\t\tconst fromNode = this.DM.data.nodeMap[edge.fromNode].ref;\n\t\tconst toNode = this.DM.data.nodeMap[edge.toNode].ref;\n\t\tconst gac = utilities.getAnchorCoord;\n\t\tconst { x: startX, y: startY } = gac(fromNode, edge.fromSide);\n\t\tconst { x: endX, y: endY } = gac(toNode, edge.toSide);\n\t\tconst color = this.SM.getColor(edge.color);\n\t\tlet [startControlX, startControlY, endControlX, endControlY] = [0, 0, 0, 0];\n\t\tif (!item.controlPoints) {\n\t\t\t[startControlX, startControlY, endControlX, endControlY] = this.getControlPoints(\n\t\t\t\tstartX,\n\t\t\t\tstartY,\n\t\t\t\tendX,\n\t\t\t\tendY,\n\t\t\t\tedge.fromSide,\n\t\t\t\tedge.toSide,\n\t\t\t);\n\t\t\titem.controlPoints = [startControlX, startControlY, endControlX, endControlY];\n\t\t} else [startControlX, startControlY, endControlX, endControlY] = item.controlPoints;\n\t\tthis.drawCurvedPath(\n\t\t\tstartX,\n\t\t\tstartY,\n\t\t\tendX,\n\t\t\tendY,\n\t\t\tstartControlX,\n\t\t\tstartControlY,\n\t\t\tendControlX,\n\t\t\tendControlY,\n\t\t\tcolor.active,\n\t\t);\n\t\tthis.drawArrowhead(endX, endY, endControlX, endControlY, color.active);\n\t\tif (edge.label) {\n\t\t\tconst t = 0.5;\n\t\t\tconst x =\n\t\t\t\t(1 - t) ** 3 * startX +\n\t\t\t\t3 * (1 - t) ** 2 * t * startControlX +\n\t\t\t\t3 * (1 - t) * t * t * endControlX +\n\t\t\t\tt ** 3 * endX;\n\t\t\tconst y =\n\t\t\t\t(1 - t) ** 3 * startY +\n\t\t\t\t3 * (1 - t) ** 2 * t * startControlY +\n\t\t\t\t3 * (1 - t) * t * t * endControlY +\n\t\t\t\tt ** 3 * endY;\n\t\t\tthis.ctx.font = '18px sans-serif';\n\t\t\tconst metrics = this.ctx.measureText(edge.label);\n\t\t\tconst padding = 8;\n\t\t\tconst labelWidth = metrics.width + padding * 2;\n\t\t\tconst labelHeight = 20;\n\t\t\tthis.ctx.fillStyle = color.active;\n\t\t\tthis.ctx.beginPath();\n\t\t\tutilities.drawRoundRect(\n\t\t\t\tthis.ctx,\n\t\t\t\tx - labelWidth / 2,\n\t\t\t\ty - labelHeight / 2 - 2,\n\t\t\t\tlabelWidth,\n\t\t\t\tlabelHeight,\n\t\t\t\t4,\n\t\t\t);\n\t\t\tthis.ctx.fill();\n\t\t\tthis.ctx.fillStyle = color.text;\n\t\t\tthis.ctx.textAlign = 'center';\n\t\t\tthis.ctx.textBaseline = 'middle';\n\t\t\tthis.ctx.fillText(edge.label, x, y - 2);\n\t\t\tthis.ctx.textAlign = 'left';\n\t\t\tthis.ctx.textBaseline = 'alphabetic';\n\t\t}\n\t};\n\n\tprivate getControlPoints = (\n\t\tstartX: number,\n\t\tstartY: number,\n\t\tendX: number,\n\t\tendY: number,\n\t\tfromSide: string,\n\t\ttoSide: string,\n\t) => {\n\t\tconst distanceX = endX - startX;\n\t\tconst distanceY = endY - startY;\n\t\tconst realDistance =\n\t\t\tMath.min(Math.abs(distanceX), Math.abs(distanceY)) +\n\t\t\t0.3 * Math.max(Math.abs(distanceX), Math.abs(distanceY));\n\t\tconst clamp = (val: number, min: number, max: number) => Math.max(min, Math.min(max, val));\n\t\tconst PADDING = clamp(realDistance * 0.5, 60, 300);\n\t\tlet startControlX = startX;\n\t\tlet startControlY = startY;\n\t\tlet endControlX = endX;\n\t\tlet endControlY = endY;\n\t\tswitch (fromSide) {\n\t\t\tcase 'top':\n\t\t\t\tstartControlY = startY - PADDING;\n\t\t\t\tbreak;\n\t\t\tcase 'bottom':\n\t\t\t\tstartControlY = startY + PADDING;\n\t\t\t\tbreak;\n\t\t\tcase 'left':\n\t\t\t\tstartControlX = startX - PADDING;\n\t\t\t\tbreak;\n\t\t\tcase 'right':\n\t\t\t\tstartControlX = startX + PADDING;\n\t\t\t\tbreak;\n\t\t}\n\t\tswitch (toSide) {\n\t\t\tcase 'top':\n\t\t\t\tendControlY = endY - PADDING;\n\t\t\t\tbreak;\n\t\t\tcase 'bottom':\n\t\t\t\tendControlY = endY + PADDING;\n\t\t\t\tbreak;\n\t\t\tcase 'left':\n\t\t\t\tendControlX = endX - PADDING;\n\t\t\t\tbreak;\n\t\t\tcase 'right':\n\t\t\t\tendControlX = endX + PADDING;\n\t\t\t\tbreak;\n\t\t}\n\t\treturn [startControlX, startControlY, endControlX, endControlY];\n\t};\n\n\tprivate drawGridDots = (scale: number, offsetX: number, offsetY: number) => {\n\t\tconst scaleLevel = -Math.floor(Math.log2(scale));\n\t\tconst actualGap = DOT_BASE_GAP * 2 ** scaleLevel * scale;\n\t\tconst width = this.canvas.width;\n\t\tconst height = this.canvas.height;\n\t\tconst startX = offsetX % actualGap;\n\t\tconst startY = offsetY % actualGap;\n\t\tthis.ctx.fillStyle = this.SM.getNamedColor('dots');\n\t\tfor (let x = startX; x <= width; x += actualGap) {\n\t\t\tfor (let y = startY; y <= height; y += actualGap) {\n\t\t\t\tthis.ctx.beginPath();\n\t\t\t\tthis.ctx.arc(x, y, DOT_RADIUS, 0, 2 * Math.PI);\n\t\t\t\tthis.ctx.fill();\n\t\t\t}\n\t\t}\n\t};\n\n\tprivate drawCurvedPath = (\n\t\tstartX: number,\n\t\tstartY: number,\n\t\tendX: number,\n\t\tendY: number,\n\t\tc1x: number,\n\t\tc1y: number,\n\t\tc2x: number,\n\t\tc2y: number,\n\t\tcolor: string,\n\t) => {\n\t\tthis.ctx.beginPath();\n\t\tthis.ctx.moveTo(startX, startY);\n\t\tthis.ctx.bezierCurveTo(c1x, c1y, c2x, c2y, endX, endY);\n\t\tthis.ctx.strokeStyle = color;\n\t\tthis.ctx.lineWidth = 2;\n\t\tthis.ctx.stroke();\n\t};\n\n\tprivate drawArrowhead = (\n\t\ttipX: number,\n\t\ttipY: number,\n\t\tfromX: number,\n\t\tfromY: number,\n\t\tcolor: string,\n\t) => {\n\t\tconst dx = tipX - fromX;\n\t\tconst dy = tipY - fromY;\n\t\tconst length = Math.sqrt(dx * dx + dy * dy);\n\t\tif (length === 0) return;\n\t\tconst unitX = dx / length;\n\t\tconst unitY = dy / length;\n\t\tconst leftX = tipX - unitX * ARROW_LENGTH - unitY * ARROW_WIDTH;\n\t\tconst leftY = tipY - unitY * ARROW_LENGTH + unitX * ARROW_WIDTH;\n\t\tconst rightX = tipX - unitX * ARROW_LENGTH + unitY * ARROW_WIDTH;\n\t\tconst rightY = tipY - unitY * ARROW_LENGTH - unitX * ARROW_WIDTH;\n\t\tthis.ctx.beginPath();\n\t\tthis.ctx.fillStyle = color;\n\t\tthis.ctx.moveTo(tipX, tipY);\n\t\tthis.ctx.lineTo(leftX, leftY);\n\t\tthis.ctx.lineTo(rightX, rightY);\n\t\tthis.ctx.closePath();\n\t\tthis.ctx.fill();\n\t};\n\n\tprivate dispose = () => {\n\t\tif (this.zoomInOptimize.timeout) {\n\t\t\tclearTimeout(this.zoomInOptimize.timeout);\n\t\t\tthis.zoomInOptimize.timeout = null;\n\t\t}\n\t\tthis.canvas.remove();\n\t\tthis._canvas = null;\n\t};\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Renderer.js","names":[],"sources":["../../src/kernel/Renderer.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { BaseArgs } from '$/BaseModule';\nimport type { EdgeItem, NodeItem } from '$/DataManager';\nimport type { Box } from '$/types';\nimport type { JSONCanvasGroupNode, JSONCanvasNode } from '@repo/shared';\nimport { BaseModule } from '$/BaseModule';\nimport Controller from '$/Controller';\nimport DataManager from '$/DataManager';\nimport StyleManager from '$/StyleManager';\nimport { destroyError, drawRoundRect, getAnchorCoord, resizeCanvasForDPR } from '$/utilities';\n\nconst ARROW_LENGTH = 12;\nconst ARROW_WIDTH = 4;\nconst NODE_RADIUS = 12;\nconst CSS_ZOOM_REDRAW_INTERVAL = 500;\nconst NODE_BORDER_WIDTH = 2;\nconst DOT_RADIUS = 1; // Dot radius in CSS pixels\nconst DOT_BASE_GAP = 10; // Base gap between dots in CSS pixels\n\nconst NODE_BORDER_HALF_WIDTH = NODE_BORDER_WIDTH / 2;\n\ntype Options = {\n\tzoomInOptimization?: boolean;\n} & BaseOptions;\n\nexport default class Renderer extends BaseModule<Options> {\n\tprivate _canvas?: HTMLCanvasElement;\n\tprivate readonly ctx: CanvasRenderingContext2D;\n\tprivate readonly DM: DataManager;\n\tprivate readonly SM: StyleManager;\n\tprivate readonly zoomInOptimize: {\n\t\tlastDrawnScale: number;\n\t\tlastDrawnViewport: Box;\n\t\ttimeout?: number;\n\t\tlastCallTime: number;\n\t} = {\n\t\tlastCallTime: 0,\n\t\tlastDrawnScale: 0,\n\t\tlastDrawnViewport: {\n\t\t\tbottom: 0,\n\t\t\tleft: 0,\n\t\t\tright: 0,\n\t\t\ttop: 0,\n\t\t},\n\t};\n\n\tprivate get canvas() {\n\t\tif (!this._canvas) throw destroyError;\n\t\treturn this._canvas;\n\t}\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tconst controller = this.container.get(Controller);\n\t\tthis.SM = this.container.get(StyleManager);\n\t\tcontroller.onRefresh.subscribe(this.redraw);\n\t\tcontroller.onResize.subscribe(this.optimizeDPR);\n\t\tthis.DM = this.container.get(DataManager);\n\t\tthis._canvas = document.createElement('canvas');\n\t\tthis._canvas.className = 'JCV-main-canvas';\n\t\tthis.ctx = this._canvas.getContext('2d') as CanvasRenderingContext2D;\n\t\tthis.DM.data.container.appendChild(this._canvas);\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\tprivate readonly optimizeDPR = () => {\n\t\tconst container = this.DM.data.container;\n\t\tresizeCanvasForDPR(this.canvas, container.offsetWidth, container.offsetHeight);\n\t};\n\n\tprivate readonly redraw = () => {\n\t\tconst offsetX = this.DM.data.offsetX;\n\t\tconst offsetY = this.DM.data.offsetY;\n\t\tconst scale = this.DM.data.scale;\n\t\tconst currentViewport = this.getCurrentViewport(offsetX, offsetY, scale);\n\t\tif (!this.options.zoomInOptimization) {\n\t\t\tthis.trueRedraw(offsetX, offsetY, scale, currentViewport);\n\t\t\treturn;\n\t\t}\n\t\tif (this.zoomInOptimize.timeout) {\n\t\t\tclearTimeout(this.zoomInOptimize.timeout);\n\t\t\tthis.zoomInOptimize.timeout = undefined;\n\t\t}\n\t\tconst now = Date.now();\n\t\tif (\n\t\t\tthis.isInside(currentViewport, this.zoomInOptimize.lastDrawnViewport) &&\n\t\t\tscale !== this.zoomInOptimize.lastDrawnScale\n\t\t) {\n\t\t\tconst timeSinceLast = now - this.zoomInOptimize.lastCallTime;\n\t\t\tif (timeSinceLast < CSS_ZOOM_REDRAW_INTERVAL) {\n\t\t\t\tthis.zoomInOptimize.timeout = window.setTimeout(() => {\n\t\t\t\t\tthis.trueRedraw(offsetX, offsetY, scale, currentViewport);\n\t\t\t\t\tthis.zoomInOptimize.lastCallTime = now;\n\t\t\t\t\tthis.zoomInOptimize.timeout = undefined;\n\t\t\t\t}, 60);\n\t\t\t\tthis.fakeRedraw(currentViewport, scale);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tthis.zoomInOptimize.lastCallTime = now;\n\t\tthis.trueRedraw(offsetX, offsetY, scale, currentViewport);\n\t};\n\n\tprivate trueRedraw(offsetX: number, offsetY: number, scale: number, currentViewport: Box) {\n\t\tthis.zoomInOptimize.lastDrawnViewport = currentViewport;\n\t\tthis.zoomInOptimize.lastDrawnScale = scale;\n\t\tthis.canvas.style.transform = '';\n\t\tthis.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\n\t\tthis.ctx.save();\n\t\tthis.drawGridDots(scale, offsetX, offsetY);\n\t\tthis.ctx.translate(offsetX, offsetY);\n\t\tthis.ctx.scale(scale, scale);\n\t\tObject.values(this.DM.data.nodeMap).forEach((item) => {\n\t\t\tif (this.isOutside(item.box, currentViewport)) return;\n\t\t\tconst node = item.ref;\n\t\t\tif (node.type === 'file') this.drawFile(item);\n\t\t\telse if (node.type === 'group') this.drawGroup(node, scale);\n\t\t});\n\t\tObject.values(this.DM.data.edgeMap).forEach((item) => {\n\t\t\tif (this.isOutside(item.box, currentViewport)) return;\n\t\t\tthis.drawEdge(item);\n\t\t});\n\t\tthis.ctx.restore();\n\t}\n\n\tprivate fakeRedraw(currentViewport: Box, scale: number) {\n\t\tconst cssScale = scale / this.zoomInOptimize.lastDrawnScale;\n\t\tconst currentOffsetX =\n\t\t\t(this.zoomInOptimize.lastDrawnViewport.left - currentViewport.left) * scale;\n\t\tconst currentOffsetY =\n\t\t\t(this.zoomInOptimize.lastDrawnViewport.top - currentViewport.top) * scale;\n\t\tthis.canvas.style.transform = `translate(${currentOffsetX}px, ${currentOffsetY}px) scale(${cssScale})`;\n\t}\n\n\tprivate readonly isInside = (inner: Box, outer: Box) =>\n\t\tinner.left > outer.left &&\n\t\tinner.top > outer.top &&\n\t\tinner.right < outer.right &&\n\t\tinner.bottom < outer.bottom;\n\n\tprivate readonly isOutside = (inner: Box, outer: Box) =>\n\t\tinner.right < outer.left ||\n\t\tinner.bottom < outer.top ||\n\t\tinner.left > outer.right ||\n\t\tinner.top > outer.bottom;\n\n\tprivate readonly getCurrentViewport = (offsetX: number, offsetY: number, scale: number) => {\n\t\tconst left = -offsetX / scale;\n\t\tconst top = -offsetY / scale;\n\t\tconst container = this.DM.data.container;\n\t\tconst right = left + container.clientWidth / scale;\n\t\tconst bottom = top + container.clientHeight / scale;\n\t\treturn { bottom, left, right, top };\n\t};\n\n\tprivate readonly drawLabelBar = (\n\t\tx: number,\n\t\ty: number,\n\t\tlabel: string,\n\t\tcolor: string,\n\t\ttextColor: string,\n\t\tscale: number,\n\t) => {\n\t\tconst barHeight = 30 * scale;\n\t\tconst radius = 6 * scale;\n\t\tconst yOffset = 8 * scale;\n\t\tconst fontSize = 16 * scale;\n\t\tconst xPadding = 6 * scale;\n\t\tthis.ctx.save();\n\t\tthis.ctx.translate(x, y);\n\t\tthis.ctx.scale(1 / scale, 1 / scale);\n\t\tthis.ctx.font = `${fontSize}px 'Inter', sans-serif`;\n\t\tconst barWidth = this.ctx.measureText(label).width + 2 * xPadding;\n\t\tthis.ctx.translate(0, -barHeight - yOffset);\n\t\tthis.ctx.fillStyle = color;\n\t\tthis.ctx.beginPath();\n\t\tthis.ctx.moveTo(radius, 0);\n\t\tthis.ctx.lineTo(barWidth - radius, 0);\n\t\tthis.ctx.quadraticCurveTo(barWidth, 0, barWidth, radius);\n\t\tthis.ctx.lineTo(barWidth, barHeight - radius);\n\t\tthis.ctx.quadraticCurveTo(barWidth, barHeight, barWidth - radius, barHeight);\n\t\tthis.ctx.lineTo(radius, barHeight);\n\t\tthis.ctx.quadraticCurveTo(0, barHeight, 0, barHeight - radius);\n\t\tthis.ctx.lineTo(0, radius);\n\t\tthis.ctx.quadraticCurveTo(0, 0, radius, 0);\n\t\tthis.ctx.closePath();\n\t\tthis.ctx.fill();\n\t\tthis.ctx.fillStyle = textColor;\n\t\tthis.ctx.fillText(label, xPadding, barHeight * 0.65);\n\t\tthis.ctx.restore();\n\t};\n\n\tprivate readonly drawNodeBackground = (node: JSONCanvasNode) => {\n\t\tconst colors = this.SM.getColor(node.color);\n\t\tconst radius = NODE_RADIUS;\n\t\tthis.ctx.globalAlpha = 1;\n\t\tthis.ctx.fillStyle = colors.background;\n\t\tdrawRoundRect(\n\t\t\tthis.ctx,\n\t\t\tnode.x + NODE_BORDER_HALF_WIDTH,\n\t\t\tnode.y + NODE_BORDER_HALF_WIDTH,\n\t\t\tnode.width - NODE_BORDER_WIDTH,\n\t\t\tnode.height - NODE_BORDER_WIDTH,\n\t\t\tradius,\n\t\t);\n\t\tthis.ctx.fill();\n\t\tthis.ctx.strokeStyle = colors.border;\n\t\tthis.ctx.lineWidth = NODE_BORDER_WIDTH;\n\t\tdrawRoundRect(this.ctx, node.x, node.y, node.width, node.height, radius);\n\t\tthis.ctx.stroke();\n\t};\n\n\tprivate readonly drawGroup = (node: JSONCanvasGroupNode, scale: number) => {\n\t\tthis.drawNodeBackground(node);\n\t\tif (node.label) {\n\t\t\tconst color = this.SM.getColor(node.color);\n\t\t\tthis.drawLabelBar(node.x, node.y, node.label, color.active, color.text, scale);\n\t\t}\n\t};\n\n\tprivate readonly drawFile = (item: NodeItem) => {\n\t\tthis.ctx.fillStyle = this.SM.getColor().text;\n\t\tconst node = item.ref;\n\t\tthis.ctx.font = '16px sans-serif';\n\t\tthis.ctx.fillText(item.fileName ?? '', node.x + 5, node.y - 10);\n\t};\n\n\tprivate readonly drawEdge = (item: EdgeItem) => {\n\t\tconst edge = item.ref;\n\t\tconst fromNode = this.DM.data.nodeMap[edge.fromNode].ref;\n\t\tconst toNode = this.DM.data.nodeMap[edge.toNode].ref;\n\t\tconst { x: startX, y: startY } = getAnchorCoord(fromNode, edge.fromSide);\n\t\tconst { x: endX, y: endY } = getAnchorCoord(toNode, edge.toSide);\n\t\tconst color = this.SM.getColor(edge.color);\n\t\tlet startControlX, startControlY, endControlX, endControlY: number;\n\t\tif (!item.controlPoints) {\n\t\t\t[startControlX, startControlY, endControlX, endControlY] = this.getControlPoints(\n\t\t\t\tstartX,\n\t\t\t\tstartY,\n\t\t\t\tendX,\n\t\t\t\tendY,\n\t\t\t\tedge.fromSide,\n\t\t\t\tedge.toSide,\n\t\t\t);\n\t\t\titem.controlPoints = [startControlX, startControlY, endControlX, endControlY];\n\t\t} else [startControlX, startControlY, endControlX, endControlY] = item.controlPoints;\n\t\tthis.drawCurvedPath(\n\t\t\tstartX,\n\t\t\tstartY,\n\t\t\tendX,\n\t\t\tendY,\n\t\t\tstartControlX,\n\t\t\tstartControlY,\n\t\t\tendControlX,\n\t\t\tendControlY,\n\t\t\tcolor.active,\n\t\t);\n\t\tthis.drawArrowhead(endX, endY, endControlX, endControlY, color.active);\n\t\tif (edge.label)\n\t\t\tthis.drawEdgeLabel(\n\t\t\t\tstartX,\n\t\t\t\tstartY,\n\t\t\t\tendX,\n\t\t\t\tendY,\n\t\t\t\tstartControlX,\n\t\t\t\tstartControlY,\n\t\t\t\tendControlX,\n\t\t\t\tendControlY,\n\t\t\t\tedge.label,\n\t\t\t\tcolor.active,\n\t\t\t\tcolor.text,\n\t\t\t);\n\t};\n\n\tprivate readonly drawEdgeLabel = (\n\t\tstartX: number,\n\t\tstartY: number,\n\t\tendX: number,\n\t\tendY: number,\n\t\tstartControlX: number,\n\t\tstartControlY: number,\n\t\tendControlX: number,\n\t\tendControlY: number,\n\t\tlabel: string,\n\t\tcolor: string,\n\t\ttextColor: string,\n\t) => {\n\t\tconst t = 0.5;\n\t\tconst x =\n\t\t\t(1 - t) ** 3 * startX +\n\t\t\t3 * (1 - t) ** 2 * t * startControlX +\n\t\t\t3 * (1 - t) * t * t * endControlX +\n\t\t\tt ** 3 * endX;\n\t\tconst y =\n\t\t\t(1 - t) ** 3 * startY +\n\t\t\t3 * (1 - t) ** 2 * t * startControlY +\n\t\t\t3 * (1 - t) * t * t * endControlY +\n\t\t\tt ** 3 * endY;\n\t\tthis.ctx.font = '18px sans-serif';\n\t\tconst lines = label.split('\\n');\n\t\tconst lineHeight = 17;\n\t\tlet maxWidth = 0;\n\t\tfor (const line of lines) {\n\t\t\tconst w = this.ctx.measureText(line).width;\n\t\t\tif (w > maxWidth) maxWidth = w;\n\t\t}\n\t\tconst paddingX = 8;\n\t\tconst paddingY = 3;\n\t\tconst labelWidth = maxWidth + paddingX * 2;\n\t\tconst labelHeight = lines.length * lineHeight + paddingY * 2; // Dynamic height\n\t\tthis.ctx.fillStyle = color;\n\t\tthis.ctx.beginPath();\n\t\tdrawRoundRect(\n\t\t\tthis.ctx,\n\t\t\tx - labelWidth / 2,\n\t\t\ty - labelHeight / 2 - 2,\n\t\t\tlabelWidth,\n\t\t\tlabelHeight,\n\t\t\t4,\n\t\t);\n\t\tthis.ctx.fill();\n\t\tthis.ctx.fillStyle = textColor;\n\t\tthis.ctx.textAlign = 'center';\n\t\tthis.ctx.textBaseline = 'middle';\n\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\tconst offsetY = (i - (lines.length - 1) / 2) * lineHeight;\n\t\t\tthis.ctx.fillText(lines[i], x, y - 2 + offsetY);\n\t\t}\n\t\tthis.ctx.textAlign = 'left';\n\t\tthis.ctx.textBaseline = 'alphabetic';\n\t};\n\n\tprivate readonly getControlPoints = (\n\t\tstartX: number,\n\t\tstartY: number,\n\t\tendX: number,\n\t\tendY: number,\n\t\tfromSide: string,\n\t\ttoSide: string,\n\t) => {\n\t\tconst distanceX = endX - startX;\n\t\tconst distanceY = endY - startY;\n\t\tconst realDistance =\n\t\t\tMath.min(Math.abs(distanceX), Math.abs(distanceY)) +\n\t\t\t0.3 * Math.max(Math.abs(distanceX), Math.abs(distanceY));\n\t\tconst clamp = (val: number, min: number, max: number) => Math.max(min, Math.min(max, val));\n\t\tconst PADDING = clamp(realDistance * 0.5, 60, 300);\n\t\tlet startControlX = startX;\n\t\tlet startControlY = startY;\n\t\tlet endControlX = endX;\n\t\tlet endControlY = endY;\n\t\tswitch (fromSide) {\n\t\t\tcase 'top': {\n\t\t\t\tstartControlY = startY - PADDING;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'bottom': {\n\t\t\t\tstartControlY = startY + PADDING;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'left': {\n\t\t\t\tstartControlX = startX - PADDING;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'right': {\n\t\t\t\tstartControlX = startX + PADDING;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tswitch (toSide) {\n\t\t\tcase 'top': {\n\t\t\t\tendControlY = endY - PADDING;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'bottom': {\n\t\t\t\tendControlY = endY + PADDING;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'left': {\n\t\t\t\tendControlX = endX - PADDING;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'right': {\n\t\t\t\tendControlX = endX + PADDING;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn [startControlX, startControlY, endControlX, endControlY];\n\t};\n\n\tprivate readonly drawGridDots = (scale: number, offsetX: number, offsetY: number) => {\n\t\tconst scaleLevel = -Math.floor(Math.log2(scale));\n\t\tconst actualGap = DOT_BASE_GAP * 2 ** scaleLevel * scale;\n\t\tconst width = this.canvas.width;\n\t\tconst height = this.canvas.height;\n\t\tconst startX = offsetX % actualGap;\n\t\tconst startY = offsetY % actualGap;\n\t\tthis.ctx.fillStyle = this.SM.getNamedColor('dots');\n\t\tfor (let x = startX; x <= width; x += actualGap)\n\t\t\tfor (let y = startY; y <= height; y += actualGap) {\n\t\t\t\tthis.ctx.beginPath();\n\t\t\t\tthis.ctx.arc(x, y, DOT_RADIUS, 0, 2 * Math.PI);\n\t\t\t\tthis.ctx.fill();\n\t\t\t}\n\t};\n\n\tprivate readonly drawCurvedPath = (\n\t\tstartX: number,\n\t\tstartY: number,\n\t\tendX: number,\n\t\tendY: number,\n\t\tc1x: number,\n\t\tc1y: number,\n\t\tc2x: number,\n\t\tc2y: number,\n\t\tcolor: string,\n\t) => {\n\t\tthis.ctx.beginPath();\n\t\tthis.ctx.moveTo(startX, startY);\n\t\tthis.ctx.bezierCurveTo(c1x, c1y, c2x, c2y, endX, endY);\n\t\tthis.ctx.strokeStyle = color;\n\t\tthis.ctx.lineWidth = 2;\n\t\tthis.ctx.stroke();\n\t};\n\n\tprivate readonly drawArrowhead = (\n\t\ttipX: number,\n\t\ttipY: number,\n\t\tfromX: number,\n\t\tfromY: number,\n\t\tcolor: string,\n\t) => {\n\t\tconst dx = tipX - fromX;\n\t\tconst dy = tipY - fromY;\n\t\tconst length = Math.sqrt(dx * dx + dy * dy);\n\t\tif (length === 0) return;\n\t\tconst unitX = dx / length;\n\t\tconst unitY = dy / length;\n\t\tconst leftX = tipX - unitX * ARROW_LENGTH - unitY * ARROW_WIDTH;\n\t\tconst leftY = tipY - unitY * ARROW_LENGTH + unitX * ARROW_WIDTH;\n\t\tconst rightX = tipX - unitX * ARROW_LENGTH + unitY * ARROW_WIDTH;\n\t\tconst rightY = tipY - unitY * ARROW_LENGTH - unitX * ARROW_WIDTH;\n\t\tthis.ctx.beginPath();\n\t\tthis.ctx.fillStyle = color;\n\t\tthis.ctx.moveTo(tipX, tipY);\n\t\tthis.ctx.lineTo(leftX, leftY);\n\t\tthis.ctx.lineTo(rightX, rightY);\n\t\tthis.ctx.closePath();\n\t\tthis.ctx.fill();\n\t};\n\n\tprivate readonly dispose = () => {\n\t\tif (this.zoomInOptimize.timeout) {\n\t\t\tclearTimeout(this.zoomInOptimize.timeout);\n\t\t\tthis.zoomInOptimize.timeout = undefined;\n\t\t}\n\t\tthis.canvas.remove();\n\t\tthis._canvas = undefined;\n\t};\n}\n"],"mappings":"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"}
@@ -3,129 +3,129 @@ import { BaseArgs, BaseModule } from "./BaseModule.js";
3
3
  import { BaseOptions } from "./index.js";
4
4
 
5
5
  //#region src/kernel/StyleManager.d.ts
6
- interface Color {
6
+ type Color = {
7
7
  border: string;
8
8
  background: string;
9
9
  active: string;
10
10
  text: string;
11
11
  card: string;
12
- }
13
- interface WithBorderWidth extends Color {
12
+ };
13
+ type WithBorderWidth = {
14
14
  'border-width': string;
15
- }
15
+ } & Color;
16
16
  type ColorOptions = { [K in keyof (StyleManager['definedColors']['light'] & StyleManager['namedColors']['light'])]?: string };
17
- interface Options extends BaseOptions {
17
+ type Options = {
18
18
  theme?: 'dark' | 'light';
19
19
  colors?: {
20
20
  light?: ColorOptions;
21
21
  dark?: ColorOptions;
22
22
  };
23
- }
24
- interface Augmentation {
23
+ } & BaseOptions;
24
+ type Augmentation = {
25
25
  changeTheme: StyleManager['changeTheme'];
26
26
  onChangeTheme: StyleManager['onChangeTheme'];
27
- }
27
+ };
28
28
  declare class StyleManager extends BaseModule<Options, Augmentation> {
29
29
  theme: 'dark' | 'light';
30
30
  onChangeTheme: Hook<["light" | "dark"], false>;
31
31
  definedColors: {
32
- light: {
32
+ dark: {
33
33
  '0': {
34
34
  hue: number;
35
- saturation: number;
36
35
  lightness: number;
36
+ saturation: number;
37
37
  };
38
38
  '1': {
39
39
  hue: number;
40
- saturation: number;
41
40
  lightness: number;
41
+ saturation: number;
42
42
  };
43
43
  '2': {
44
44
  hue: number;
45
- saturation: number;
46
45
  lightness: number;
46
+ saturation: number;
47
47
  };
48
48
  '3': {
49
49
  hue: number;
50
- saturation: number;
51
50
  lightness: number;
51
+ saturation: number;
52
52
  };
53
53
  '4': {
54
54
  hue: number;
55
- saturation: number;
56
55
  lightness: number;
56
+ saturation: number;
57
57
  };
58
58
  '5': {
59
59
  hue: number;
60
- saturation: number;
61
60
  lightness: number;
61
+ saturation: number;
62
62
  };
63
63
  '6': {
64
64
  hue: number;
65
- saturation: number;
66
65
  lightness: number;
66
+ saturation: number;
67
67
  };
68
68
  };
69
- dark: {
69
+ light: {
70
70
  '0': {
71
71
  hue: number;
72
- saturation: number;
73
72
  lightness: number;
73
+ saturation: number;
74
74
  };
75
75
  '1': {
76
76
  hue: number;
77
- saturation: number;
78
77
  lightness: number;
78
+ saturation: number;
79
79
  };
80
80
  '2': {
81
81
  hue: number;
82
- saturation: number;
83
82
  lightness: number;
83
+ saturation: number;
84
84
  };
85
85
  '3': {
86
86
  hue: number;
87
- saturation: number;
88
87
  lightness: number;
88
+ saturation: number;
89
89
  };
90
90
  '4': {
91
91
  hue: number;
92
- saturation: number;
93
92
  lightness: number;
93
+ saturation: number;
94
94
  };
95
95
  '5': {
96
96
  hue: number;
97
- saturation: number;
98
97
  lightness: number;
98
+ saturation: number;
99
99
  };
100
100
  '6': {
101
101
  hue: number;
102
- saturation: number;
103
102
  lightness: number;
103
+ saturation: number;
104
104
  };
105
105
  };
106
106
  };
107
107
  namedColors: {
108
- light: {
109
- dots: string;
110
- text: string;
108
+ dark: {
111
109
  background: string;
112
110
  'background-secondary': string;
113
- shadow: string;
114
111
  border: string;
115
- };
116
- dark: {
117
112
  dots: string;
113
+ shadow: string;
118
114
  text: string;
115
+ };
116
+ light: {
119
117
  background: string;
120
118
  'background-secondary': string;
121
- shadow: string;
122
119
  border: string;
120
+ dots: string;
121
+ shadow: string;
122
+ text: string;
123
123
  };
124
124
  };
125
- private colorCache;
125
+ private readonly colorCache;
126
126
  constructor(...args: BaseArgs);
127
- private hslProcessor;
128
- private parseColor;
127
+ private readonly hslProcessor;
128
+ private readonly parseColor;
129
129
  getColor: (colorIndex?: string) => WithBorderWidth;
130
130
  getNamedColor: (name: keyof typeof this.namedColors.light) => string;
131
131
  changeTheme: (theme?: "dark" | "light") => void;