json-canvas-viewer 4.0.0 → 4.1.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 (65) hide show
  1. package/dist/chimp.js +395 -1
  2. package/dist/index.d.ts +29 -608
  3. package/dist/index.js +2 -2
  4. package/dist/index.js.map +1 -1
  5. package/dist/kernel/BaseModule.d.ts +28 -0
  6. package/dist/kernel/BaseModule.js +2 -0
  7. package/dist/kernel/BaseModule.js.map +1 -0
  8. package/dist/kernel/Controller.d.ts +30 -0
  9. package/dist/kernel/Controller.js +2 -0
  10. package/dist/kernel/Controller.js.map +1 -0
  11. package/dist/kernel/DataManager.d.ts +67 -0
  12. package/dist/kernel/DataManager.js +2 -0
  13. package/dist/kernel/DataManager.js.map +1 -0
  14. package/dist/kernel/InteractionHandler.d.ts +51 -0
  15. package/dist/kernel/InteractionHandler.js +2 -0
  16. package/dist/kernel/InteractionHandler.js.map +1 -0
  17. package/dist/kernel/OverlayManager.d.ts +55 -0
  18. package/dist/kernel/OverlayManager.js +2 -0
  19. package/dist/kernel/OverlayManager.js.map +1 -0
  20. package/dist/kernel/Renderer.d.ts +36 -0
  21. package/dist/kernel/Renderer.js +2 -0
  22. package/dist/kernel/Renderer.js.map +1 -0
  23. package/dist/kernel/StyleManager.d.ts +135 -0
  24. package/dist/kernel/StyleManager.js +2 -0
  25. package/dist/kernel/StyleManager.js.map +1 -0
  26. package/dist/kernel/index.d.ts +46 -0
  27. package/dist/kernel/index.js +2 -0
  28. package/dist/kernel/index.js.map +1 -0
  29. package/dist/kernel/styles.js +285 -0
  30. package/dist/kernel/styles.js.map +1 -0
  31. package/dist/kernel/types.d.ts +33 -0
  32. package/dist/kernel/utilities.d.ts +39 -0
  33. package/dist/kernel/utilities.js +2 -0
  34. package/dist/kernel/utilities.js.map +1 -0
  35. package/dist/modules/Controls/index.d.ts +42 -0
  36. package/dist/modules/Controls/index.js +2 -0
  37. package/dist/modules/Controls/index.js.map +1 -0
  38. package/dist/modules/Controls/styles.js +29 -0
  39. package/dist/modules/Controls/styles.js.map +1 -0
  40. package/dist/modules/DebugPanel/index.d.ts +14 -0
  41. package/dist/modules/DebugPanel/index.js +2 -0
  42. package/dist/modules/DebugPanel/index.js.map +1 -0
  43. package/dist/modules/DebugPanel/styles.js +13 -0
  44. package/dist/modules/DebugPanel/styles.js.map +1 -0
  45. package/dist/modules/Minimap/index.d.ts +36 -0
  46. package/dist/modules/Minimap/index.js +2 -0
  47. package/dist/modules/Minimap/index.js.map +1 -0
  48. package/dist/modules/Minimap/styles.js +56 -0
  49. package/dist/modules/Minimap/styles.js.map +1 -0
  50. package/dist/modules/MistouchPreventer/index.d.ts +29 -0
  51. package/dist/modules/MistouchPreventer/index.js +2 -0
  52. package/dist/modules/MistouchPreventer/index.js.map +1 -0
  53. package/dist/modules/MistouchPreventer/styles.js +21 -0
  54. package/dist/modules/MistouchPreventer/styles.js.map +1 -0
  55. package/dist/shared/index.d.ts +50 -0
  56. package/dist/utilities/fetchCanvas.d.ts +7 -0
  57. package/dist/utilities/fetchCanvas.js +2 -0
  58. package/dist/utilities/fetchCanvas.js.map +1 -0
  59. package/dist/utilities/parser.d.ts +5 -0
  60. package/dist/utilities/parser.js +2 -0
  61. package/dist/utilities/parser.js.map +1 -0
  62. package/dist/utilities/renderToString.d.ts +12 -0
  63. package/dist/utilities/renderToString.js +2 -0
  64. package/dist/utilities/renderToString.js.map +1 -0
  65. package/package.json +12 -10
@@ -0,0 +1,67 @@
1
+ import { Box, NodeBounds } from "./types.js";
2
+ import { JSONCanvas, JSONCanvasEdge, JSONCanvasNode } from "../shared/index.js";
3
+ import { Hook } from "./utilities.js";
4
+ import { BaseArgs, BaseModule } from "./BaseModule.js";
5
+ import { BaseOptions } from "./index.js";
6
+
7
+ //#region src/kernel/DataManager.d.ts
8
+ interface Options extends BaseOptions {
9
+ shadowed?: boolean;
10
+ canvas?: JSONCanvas;
11
+ attachmentDir?: string;
12
+ extraCSS?: string;
13
+ attachments?: Record<string, string>;
14
+ noAttachmentRelocation?: boolean;
15
+ }
16
+ interface Augmentation {
17
+ resetView: DataManager['resetView'];
18
+ toggleFullscreen: DataManager['toggleFullscreen'];
19
+ onToggleFullscreen: DataManager['onToggleFullscreen'];
20
+ }
21
+ interface NodeItem {
22
+ ref: JSONCanvasNode;
23
+ box: Box;
24
+ fileName?: string;
25
+ onBeforeUnmount?: Hook;
26
+ onActive?: Hook;
27
+ onLoseActive?: Hook;
28
+ }
29
+ interface EdgeItem {
30
+ ref: JSONCanvasEdge;
31
+ box: Box;
32
+ controlPoints?: Array<number>;
33
+ }
34
+ type NodeMap = Record<string, NodeItem>;
35
+ type EdgeMap = Record<string, EdgeItem>;
36
+ declare class DataManager extends BaseModule<Options, Augmentation> {
37
+ onToggleFullscreen: Hook<["enter" | "exit"], false>;
38
+ data: {
39
+ canvasData: Required<JSONCanvas>;
40
+ nodeMap: NodeMap;
41
+ edgeMap: EdgeMap;
42
+ canvasBaseDir: string;
43
+ nodeBounds: NodeBounds;
44
+ offsetX: number;
45
+ offsetY: number;
46
+ scale: number;
47
+ container: HTMLDivElement;
48
+ };
49
+ constructor(...args: BaseArgs);
50
+ private start;
51
+ private processBaseDir;
52
+ private getNodeBox;
53
+ private getEdgeBox;
54
+ private calculateNodeBounds;
55
+ toggleFullscreen: (option?: "enter" | "exit") => Promise<void>;
56
+ resetView: () => void;
57
+ middleViewer: () => {
58
+ x: number;
59
+ y: number;
60
+ width: number;
61
+ height: number;
62
+ };
63
+ private dispose;
64
+ }
65
+ //#endregion
66
+ export { DataManager };
67
+ //# sourceMappingURL=DataManager.d.ts.map
@@ -0,0 +1,2 @@
1
+ import{BaseModule as e}from"./BaseModule.js";import t from"./styles.js";import n from"./utilities.js";var r=class extends e{onToggleFullscreen=n.makeHook();data={canvasData:{nodes:[],edges:[]},nodeMap:{},edgeMap:{},canvasBaseDir:`./`,nodeBounds:{maxX:0,maxY:0,minX:0,minY:0,width:0,height:0,centerX:0,centerY:0},offsetX:0,offsetY:0,scale:1,container:document.createElement(`div`)};constructor(...e){super(...e);let r=this.options.container;for(;r.firstElementChild;)r.firstElementChild.remove();r.innerHTML=``;let i=this.options.shadowed?r.attachShadow({mode:`open`}):r;n.applyStyles(i,t+this.options.extraCSS),this.data.container.classList.add(`JSON-Canvas-Viewer`),i.appendChild(this.data.container),this.augment({resetView:this.resetView,toggleFullscreen:this.toggleFullscreen,onToggleFullscreen:this.onToggleFullscreen}),this.onStart(this.start),this.onRestart(this.start),this.onDispose(this.dispose)}start=()=>{let e=Object.assign({nodes:[],edges:[]},this.options.canvas);Object.assign(this.data,{canvasData:e,nodeMap:{},edgeMap:{},canvasBaseDir:this.processBaseDir(this.options.attachmentDir),nodeBounds:this.calculateNodeBounds(e),offsetX:0,offsetY:0,scale:1}),this.data.canvasData.nodes.forEach(e=>{let t={ref:e,box:this.getNodeBox(e)};if(this.data.nodeMap[e.id]=t,e.type===`file`){let n=e.file.split(`/`).pop()??``;if(t.fileName=n,!e.file.startsWith(`http://`)&&!e.file.startsWith(`https://`)){let t=this.options.attachments?.[n];t?e.file=t:this.options.noAttachmentRelocation||(e.file=this.data.canvasBaseDir+n)}}}),this.data.canvasData.edges.forEach(e=>{this.data.edgeMap[e.id]={ref:e,box:this.getEdgeBox(e)}}),this.resetView()};processBaseDir=e=>e?e?.slice(-1)===`/`?e:`${e}/`:`./`;getNodeBox=e=>({left:e.x,top:e.type===`file`||e.type===`group`?e.y-40:e.y,right:e.width+e.x,bottom:e.y+e.height});getEdgeBox=e=>{let t=this.data.nodeMap,r=t[e.fromNode].ref,i=t[e.toNode].ref,a=n.getAnchorCoord(r,e.fromSide),o=n.getAnchorCoord(i,e.toSide),s={left:Math.min(a.x,o.x),top:Math.min(a.y,o.y),right:Math.max(a.x,o.x),bottom:Math.max(a.y,o.y)},c=s.right-s.left,l=s.bottom-s.top,u=Math.min(c,l),d=Math.log2(Math.max(c,l)/(u===0?1:u))*10;return{left:s.left-d,top:s.top-d,right:s.right+d,bottom:s.bottom+d}};calculateNodeBounds(e){let t=1/0,n=1/0,r=-1/0,i=-1/0;e.nodes.forEach(e=>{t=Math.min(t,e.x),n=Math.min(n,e.y),r=Math.max(r,e.x+e.width),i=Math.max(i,e.y+e.height)});let a=r-t,o=i-n,s=t+a/2,c=n+o/2;return{minX:t,minY:n,maxX:r,maxY:i,width:a,height:o,centerX:s,centerY:c}}toggleFullscreen=async e=>{!document.fullscreenElement&&(!e||e===`enter`)?(await this.data.container.requestFullscreen(),this.onToggleFullscreen(`enter`)):document.fullscreenElement&&(!e||e===`exit`)&&(await document.exitFullscreen(),this.onToggleFullscreen(`exit`))};resetView=()=>{let e=this.data.nodeBounds,t=this.data.container;if(!e||!t)return;let n=e.width+200,r=e.height+200,i=t.clientWidth,a=t.clientHeight,o=i/n,s=a/r,c=Math.round(Math.min(o,s)*1e3)/1e3,l=e.centerX,u=e.centerY,d={scale:c,offsetX:i/2-l*c,offsetY:a/2-u*c};this.data.offsetX=d.offsetX,this.data.offsetY=d.offsetY,this.data.scale=d.scale};middleViewer=()=>{let e=this.data.container;return{x:e.clientWidth/2,y:e.clientHeight/2,width:e.clientWidth,height:e.clientHeight}};dispose=()=>{this.data.container.remove()}};export{r as default};
2
+ //# sourceMappingURL=DataManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DataManager.js","names":["utilities","style"],"sources":["../../src/kernel/DataManager.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { Box, NodeBounds } from '$/types';\nimport type { JSONCanvas, JSONCanvasEdge, JSONCanvasNode } from '@repo/shared';\nimport { type BaseArgs, BaseModule } from '$/BaseModule';\nimport style from '$/styles.scss?inline';\nimport utilities, { type Hook } from '$/utilities';\n\nconst INITIAL_VIEWPORT_PADDING = 100;\nconst NODE_LABEL_MARGIN = 40;\nconst EDGE_BOX_HEURISTICS_BASE_MARGIN = 10;\n\ninterface Options extends BaseOptions {\n\tshadowed?: boolean;\n\tcanvas?: JSONCanvas;\n\tattachmentDir?: string;\n\textraCSS?: string;\n\tattachments?: Record<string, string>;\n\tnoAttachmentRelocation?: boolean;\n}\n\ninterface Augmentation {\n\tresetView: DataManager['resetView'];\n\ttoggleFullscreen: DataManager['toggleFullscreen'];\n\tonToggleFullscreen: DataManager['onToggleFullscreen'];\n}\n\nexport interface NodeItem {\n\tref: JSONCanvasNode;\n\tbox: Box;\n\tfileName?: string;\n\tonBeforeUnmount?: Hook;\n\tonActive?: Hook;\n\tonLoseActive?: Hook;\n}\n\nexport interface EdgeItem {\n\tref: JSONCanvasEdge;\n\tbox: Box;\n\tcontrolPoints?: Array<number>;\n}\n\ntype NodeMap = Record<string, NodeItem>;\ntype EdgeMap = Record<string, EdgeItem>;\n\nexport default class DataManager extends BaseModule<Options, Augmentation> {\n\tonToggleFullscreen = utilities.makeHook<['enter' | 'exit']>();\n\n\tdata: {\n\t\tcanvasData: Required<JSONCanvas>;\n\t\tnodeMap: NodeMap;\n\t\tedgeMap: EdgeMap;\n\t\tcanvasBaseDir: string;\n\t\tnodeBounds: NodeBounds;\n\t\toffsetX: number;\n\t\toffsetY: number;\n\t\tscale: number;\n\t\tcontainer: HTMLDivElement;\n\t} = {\n\t\tcanvasData: {\n\t\t\tnodes: [],\n\t\t\tedges: [],\n\t\t},\n\t\tnodeMap: {},\n\t\tedgeMap: {},\n\t\tcanvasBaseDir: './',\n\t\tnodeBounds: {\n\t\t\tmaxX: 0,\n\t\t\tmaxY: 0,\n\t\t\tminX: 0,\n\t\t\tminY: 0,\n\t\t\twidth: 0,\n\t\t\theight: 0,\n\t\t\tcenterX: 0,\n\t\t\tcenterY: 0,\n\t\t},\n\t\toffsetX: 0,\n\t\toffsetY: 0,\n\t\tscale: 1,\n\t\tcontainer: document.createElement('div'),\n\t};\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tconst viewerContainer = this.options.container;\n\t\twhile (viewerContainer.firstElementChild) viewerContainer.firstElementChild.remove();\n\t\tviewerContainer.innerHTML = '';\n\n\t\tconst realContainer = this.options.shadowed\n\t\t\t? viewerContainer.attachShadow({ mode: 'open' })\n\t\t\t: viewerContainer;\n\n\t\tutilities.applyStyles(realContainer, style + this.options.extraCSS);\n\n\t\tthis.data.container.classList.add('JSON-Canvas-Viewer');\n\t\trealContainer.appendChild(this.data.container);\n\n\t\tthis.augment({\n\t\t\tresetView: this.resetView,\n\t\t\ttoggleFullscreen: this.toggleFullscreen,\n\t\t\tonToggleFullscreen: this.onToggleFullscreen,\n\t\t});\n\t\tthis.onStart(this.start);\n\t\tthis.onRestart(this.start);\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\tprivate start = () => {\n\t\tconst canvasData = Object.assign(\n\t\t\t{\n\t\t\t\tnodes: [],\n\t\t\t\tedges: [],\n\t\t\t},\n\t\t\tthis.options.canvas,\n\t\t);\n\n\t\tObject.assign(this.data, {\n\t\t\tcanvasData: canvasData,\n\t\t\tnodeMap: {},\n\t\t\tedgeMap: {},\n\t\t\tcanvasBaseDir: this.processBaseDir(this.options.attachmentDir),\n\t\t\tnodeBounds: this.calculateNodeBounds(canvasData),\n\t\t\toffsetX: 0,\n\t\t\toffsetY: 0,\n\t\t\tscale: 1,\n\t\t});\n\n\t\tthis.data.canvasData.nodes.forEach((node) => {\n\t\t\tconst item: NodeItem = {\n\t\t\t\tref: node,\n\t\t\t\tbox: this.getNodeBox(node),\n\t\t\t};\n\t\t\tthis.data.nodeMap[node.id] = item;\n\n\t\t\t// re-process attachments\n\t\t\tif (node.type === 'file') {\n\t\t\t\tconst path = node.file.split('/');\n\t\t\t\tconst fileName = path.pop() ?? '';\n\t\t\t\titem.fileName = fileName;\n\t\t\t\tif (!node.file.startsWith('http://') && !node.file.startsWith('https://')) {\n\t\t\t\t\tconst userDefinedAttachment = this.options.attachments?.[fileName];\n\t\t\t\t\tif (userDefinedAttachment) node.file = userDefinedAttachment;\n\t\t\t\t\telse if (!this.options.noAttachmentRelocation)\n\t\t\t\t\t\tnode.file = this.data.canvasBaseDir + fileName;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tthis.data.canvasData.edges.forEach((edge) => {\n\t\t\tthis.data.edgeMap[edge.id] = {\n\t\t\t\tref: edge,\n\t\t\t\tbox: this.getEdgeBox(edge),\n\t\t\t};\n\t\t});\n\t\tthis.resetView();\n\t};\n\n\tprivate processBaseDir = (baseDir: string | undefined) => {\n\t\tif (!baseDir) return './';\n\t\tconst lastChar = baseDir?.slice(-1);\n\t\tif (lastChar === '/') return baseDir;\n\t\treturn `${baseDir}/`;\n\t};\n\n\tprivate getNodeBox = (node: JSONCanvasNode) => {\n\t\treturn {\n\t\t\tleft: node.x,\n\t\t\ttop:\n\t\t\t\tnode.type === 'file' || node.type === 'group' ? node.y - NODE_LABEL_MARGIN : node.y,\n\t\t\tright: node.width + node.x,\n\t\t\tbottom: node.y + node.height,\n\t\t};\n\t};\n\n\tprivate getEdgeBox = (edge: JSONCanvasEdge) => {\n\t\tconst nodes = this.data.nodeMap;\n\t\tconst from = nodes[edge.fromNode].ref;\n\t\tconst to = nodes[edge.toNode].ref;\n\t\tconst fromAnchor = utilities.getAnchorCoord(from, edge.fromSide);\n\t\tconst toAnchor = utilities.getAnchorCoord(to, edge.toSide);\n\t\tconst strictBox = {\n\t\t\tleft: Math.min(fromAnchor.x, toAnchor.x),\n\t\t\ttop: Math.min(fromAnchor.y, toAnchor.y),\n\t\t\tright: Math.max(fromAnchor.x, toAnchor.x),\n\t\t\tbottom: Math.max(fromAnchor.y, toAnchor.y),\n\t\t};\n\t\t// edge size heuristics\n\t\tconst width = strictBox.right - strictBox.left;\n\t\tconst height = strictBox.bottom - strictBox.top;\n\t\tconst _min = Math.min(width, height);\n\t\tconst min = _min === 0 ? 1 : _min;\n\t\tconst max = Math.max(width, height);\n\t\tconst edgeFactor = Math.log2(max / min);\n\t\tconst margin = edgeFactor * EDGE_BOX_HEURISTICS_BASE_MARGIN;\n\t\treturn {\n\t\t\tleft: strictBox.left - margin,\n\t\t\ttop: strictBox.top - margin,\n\t\t\tright: strictBox.right + margin,\n\t\t\tbottom: strictBox.bottom + margin,\n\t\t};\n\t};\n\n\tprivate calculateNodeBounds(canvasData: Required<JSONCanvas>) {\n\t\tlet minX = Infinity,\n\t\t\tminY = Infinity,\n\t\t\tmaxX = -Infinity,\n\t\t\tmaxY = -Infinity;\n\t\tcanvasData.nodes.forEach((node) => {\n\t\t\tminX = Math.min(minX, node.x);\n\t\t\tminY = Math.min(minY, node.y);\n\t\t\tmaxX = Math.max(maxX, node.x + node.width);\n\t\t\tmaxY = Math.max(maxY, node.y + node.height);\n\t\t});\n\t\tconst width = maxX - minX;\n\t\tconst height = maxY - minY;\n\t\tconst centerX = minX + width / 2;\n\t\tconst centerY = minY + height / 2;\n\t\treturn { minX, minY, maxX, maxY, width, height, centerX, centerY };\n\t}\n\ttoggleFullscreen = async (option?: 'enter' | 'exit') => {\n\t\tif (!document.fullscreenElement && (!option || option === 'enter')) {\n\t\t\tawait this.data.container.requestFullscreen();\n\t\t\tthis.onToggleFullscreen('enter');\n\t\t} else if (document.fullscreenElement && (!option || option === 'exit')) {\n\t\t\tawait document.exitFullscreen();\n\t\t\tthis.onToggleFullscreen('exit');\n\t\t}\n\t};\n\tresetView = () => {\n\t\tconst bounds = this.data.nodeBounds;\n\t\tconst container = this.data.container;\n\t\tif (!bounds || !container) return;\n\t\tconst contentWidth = bounds.width + INITIAL_VIEWPORT_PADDING * 2;\n\t\tconst contentHeight = bounds.height + INITIAL_VIEWPORT_PADDING * 2;\n\t\t// Use logical dimensions for scaling calculations\n\t\tconst viewWidth = container.clientWidth;\n\t\tconst viewHeight = container.clientHeight;\n\t\tconst scaleX = viewWidth / contentWidth;\n\t\tconst scaleY = viewHeight / contentHeight;\n\t\tconst newScale = Math.round(Math.min(scaleX, scaleY) * 1000) / 1000;\n\t\tconst contentCenterX = bounds.centerX;\n\t\tconst contentCenterY = bounds.centerY;\n\t\tconst initialView = {\n\t\t\tscale: newScale,\n\t\t\toffsetX: viewWidth / 2 - contentCenterX * newScale,\n\t\t\toffsetY: viewHeight / 2 - contentCenterY * newScale,\n\t\t};\n\t\tthis.data.offsetX = initialView.offsetX;\n\t\tthis.data.offsetY = initialView.offsetY;\n\t\tthis.data.scale = initialView.scale;\n\t};\n\n\tmiddleViewer = () => {\n\t\tconst container = this.data.container;\n\t\treturn {\n\t\t\tx: container.clientWidth / 2,\n\t\t\ty: container.clientHeight / 2,\n\t\t\twidth: container.clientWidth,\n\t\t\theight: container.clientHeight,\n\t\t};\n\t};\n\n\tprivate dispose = () => {\n\t\tthis.data.container.remove();\n\t};\n}\n"],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ import { Coordinates } from "./types.js";
2
+ import { Hook } from "./utilities.js";
3
+ import { BaseArgs, BaseModule } from "./BaseModule.js";
4
+ import { BaseOptions } from "./index.js";
5
+ import { Click, Drag, Lubricator, MultitouchPanZoom, Options, PointeractInterface, PreventDefault, WheelPanZoom } from "pointeract";
6
+
7
+ //#region src/kernel/InteractionHandler.d.ts
8
+ type LoadedModules = [Click, Drag, WheelPanZoom, PreventDefault, MultitouchPanZoom, Lubricator];
9
+ interface Options$1 extends BaseOptions {
10
+ pointeract?: Options<LoadedModules>;
11
+ }
12
+ interface Augmentation {
13
+ pan: InteractionHandler['pan'];
14
+ panToCoords: InteractionHandler['panToCoords'];
15
+ zoom: InteractionHandler['zoom'];
16
+ zoomToScale: InteractionHandler['zoomToScale'];
17
+ }
18
+ declare class InteractionHandler extends BaseModule<Options$1, Augmentation> {
19
+ pointeract: PointeractInterface<LoadedModules>;
20
+ private DM;
21
+ onClick: Hook<[string | null], false>;
22
+ constructor(...args: BaseArgs);
23
+ private start;
24
+ private startInteract;
25
+ private stopInteract;
26
+ private onPan;
27
+ private onZoom;
28
+ trueZoom: (_factor: number, origin: Coordinates) => void;
29
+ truePan: ({
30
+ x,
31
+ y
32
+ }: Coordinates) => void;
33
+ zoom: (_factor: number, origin: Coordinates) => void;
34
+ pan: ({
35
+ x,
36
+ y
37
+ }: Coordinates) => void;
38
+ zoomToScale: (newScale: number, origin: Coordinates) => void;
39
+ panToCoords: ({
40
+ x,
41
+ y
42
+ }: Coordinates) => void;
43
+ private C2C;
44
+ private onTrueClick;
45
+ private isUIControl;
46
+ private findNodeId;
47
+ private dispose;
48
+ }
49
+ //#endregion
50
+ export { InteractionHandler };
51
+ //# sourceMappingURL=InteractionHandler.d.ts.map
@@ -0,0 +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};
2
+ //# sourceMappingURL=InteractionHandler.js.map
@@ -0,0 +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":"qWAqCA,IAAqB,EAArB,cAAgD,CAAkC,CACjF,WACA,GACA,QAAUA,EAAU,UAA2B,CAE/C,YAAY,GAAG,EAAgB,CAC9B,MAAM,GAAG,EAAK,CACd,KAAK,GAAK,KAAK,UAAU,IAAI,EAAY,CACzC,IAAM,EAAU,OAAO,OAAO,KAAK,QAAQ,YAAc,EAAE,CAAE,CAC5D,iBAAkB,WAClB,QAAS,KAAK,GAAG,KAAK,UACtB,WAAY,CAAE,IAAA,EAAK,KAAA,EAAM,KAAA,EAAM,CAC/B,CAA4C,CAC7C,KAAK,WAAa,IAAI,EAAW,EAAS,CACzC,EACA,EACA,EACA,EACA,EACA,EACA,CAAC,CACF,IAAM,EAAK,KAAK,UAAU,IAAI,EAAe,CAC7C,EAAG,mBAAmB,UAAU,KAAK,aAAa,CAClD,EAAG,iBAAiB,UAAU,KAAK,cAAc,CAEjD,KAAK,QAAQ,CACZ,IAAK,KAAK,IACV,YAAa,KAAK,YAClB,KAAM,KAAK,KACX,YAAa,KAAK,YAClB,CAAC,CACF,KAAK,QAAQ,KAAK,MAAM,CACxB,KAAK,UAAU,KAAK,QAAQ,CAG7B,UAAsB,CACrB,KAAK,WACH,GAAG,MAAO,KAAK,MAAM,CACrB,GAAG,OAAQ,KAAK,MAAM,CACtB,GAAG,OAAQ,KAAK,OAAO,CACvB,GAAG,YAAa,KAAK,YAAY,CACjC,OAAO,EAGV,kBAA8B,CAC7B,KAAK,WAAW,OAAO,EAExB,iBAA6B,CAC5B,KAAK,WAAW,MAAM,EAGvB,MAAiB,GAA+B,CAC/C,KAAK,QAAQ,CACZ,EAAG,EAAM,OACT,EAAG,EAAM,OACT,CAAC,EAEH,OAAkB,GAAgC,CACjD,KAAK,SAAS,EAAM,OAAQ,EAAM,EAGnC,UAAY,EAAiB,IAAwB,CACpD,IAAM,EAAW,KAAK,IAAI,KAAK,IAAI,KAAK,GAAG,KAAK,MAAQ,EAAS,GAAG,CAAE,IAAK,CAE3E,GAAI,IADU,KAAK,GAAG,KAAK,MACH,OACxB,IAAM,EAAS,EAAW,KAAK,GAAG,KAAK,MACjC,EAAe,KAAK,IAAI,EAAO,CACrC,KAAK,GAAG,KAAK,QAAU,EAAO,EAAI,EAAa,EAAI,EACnD,KAAK,GAAG,KAAK,QAAU,EAAO,EAAI,EAAa,EAAI,EACnD,KAAK,GAAG,KAAK,MAAQ,GAEtB,SAAW,CAAE,IAAG,OAAqB,CACpC,KAAK,GAAG,KAAK,QAAU,KAAK,GAAG,KAAK,QAAU,EAC9C,KAAK,GAAG,KAAK,QAAU,KAAK,GAAG,KAAK,QAAU,GAG/C,MAAQ,EAAiB,IAAwB,CAChD,KAAK,WAAW,SAAS,OAAQ,CAAE,OAAQ,EAAS,GAAG,EAAQ,CAAC,EAEjE,KAAO,CAAE,IAAG,OAAqB,CAChC,KAAK,WAAW,SAAS,MAAO,CAAE,OAAQ,EAAG,OAAQ,EAAG,CAAC,EAE1D,aAAe,EAAkB,IAAwB,CACxD,IAAM,EAAS,EAAW,KAAK,GAAG,KAAK,MACvC,KAAK,WAAW,SAAS,OAAQ,CAAE,SAAQ,GAAG,EAAQ,CAAC,EAExD,aAAe,CAAE,IAAG,OAAqB,CACxC,KAAK,WAAW,SAAS,MAAO,CAC/B,OAAQ,EAAI,KAAK,GAAG,KAAK,QACzB,OAAQ,EAAI,KAAK,GAAG,KAAK,QACzB,CAAC,EAIH,KAAe,CAAE,EAAG,EAAY,EAAG,MAA+B,CACjE,EAAG,EAAa,KAAK,GAAG,KAAK,QAC7B,EAAG,EAAa,KAAK,GAAG,KAAK,QAC7B,EAED,YAAuB,GAAiC,CACvD,IAAM,EAAU,EAAE,OAClB,GAAI,KAAK,YAAY,EAAQ,CAAE,OAC/B,IAAM,EAAO,KAAK,WAAW,EAAQ,CACrC,KAAK,QAAQ,EAAK,EAGnB,YAAuB,GACjB,EACE,EAAO,QAAQ,YAAY,EAAI,EAAO,QAAQ,SAAS,EAAI,EAAO,QAAQ,QAAQ,CADrE,GAIrB,WAAsB,GAAgC,CACrD,GAAI,CAAC,EAAS,OAAO,KACrB,IAAI,EAAM,EACV,MAAO,CAAC,EAAI,IAAM,EAAI,KAAO,KACvB,EAAI,eACT,EAAM,EAAI,cAGX,OADI,EAAI,KAAO,YAAc,CAAC,EAAI,IAAM,EAAI,KAAO,GAAW,KACvD,EAAI,IAGZ,YAAwB,KAAK,WAAW,SAAS"}
@@ -0,0 +1,55 @@
1
+ import { JSONCanvasFileNode, JSONCanvasLinkNode, JSONCanvasNode, JSONCanvasTextNode, Parser } from "../shared/index.js";
2
+ import { Hook } from "./utilities.js";
3
+ import { BaseArgs, BaseModule } from "./BaseModule.js";
4
+ import { BaseOptions } from "./index.js";
5
+
6
+ //#region src/kernel/OverlayManager.d.ts
7
+ interface Options extends BaseOptions {
8
+ parser?: Parser;
9
+ nodeComponents?: Partial<ComponentDict>;
10
+ }
11
+ interface Augmentation {
12
+ onNodeActive: OverlayManager['onNodeActive'];
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>;
16
+ type ComponentNodeMap = {
17
+ text: JSONCanvasTextNode;
18
+ markdown: JSONCanvasFileNode;
19
+ image: JSONCanvasFileNode;
20
+ audio: JSONCanvasFileNode;
21
+ video: JSONCanvasFileNode;
22
+ link: JSONCanvasLinkNode;
23
+ };
24
+ type ComponentDict = { [K in keyof ComponentNodeMap]: NodeComponentHook<ComponentNodeMap[K]> };
25
+ declare class OverlayManager extends BaseModule<Options, Augmentation> {
26
+ private _overlaysLayer;
27
+ private overlays;
28
+ private selectedId;
29
+ private aborted;
30
+ private eventListeners;
31
+ private DM;
32
+ private SM;
33
+ private parse;
34
+ private componentDict;
35
+ private get overlaysLayer();
36
+ onInteractionStart: Hook<[], false>;
37
+ onInteractionEnd: Hook<[], false>;
38
+ onNodeActive: Hook<[JSONCanvasNode], false>;
39
+ onNodeLosesActive: Hook<[JSONCanvasNode], false>;
40
+ 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;
52
+ }
53
+ //#endregion
54
+ export { OverlayManager };
55
+ //# sourceMappingURL=OverlayManager.d.ts.map
@@ -0,0 +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};
2
+ //# sourceMappingURL=OverlayManager.js.map
@@ -0,0 +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":"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"}
@@ -0,0 +1,36 @@
1
+ import { BaseArgs, BaseModule } from "./BaseModule.js";
2
+ import { BaseOptions } from "./index.js";
3
+
4
+ //#region src/kernel/Renderer.d.ts
5
+ interface Options extends BaseOptions {
6
+ zoomInOptimization?: boolean;
7
+ }
8
+ declare class Renderer extends BaseModule<Options> {
9
+ private _canvas;
10
+ private ctx;
11
+ private DM;
12
+ private SM;
13
+ private zoomInOptimize;
14
+ private get canvas();
15
+ constructor(...args: BaseArgs);
16
+ private optimizeDPR;
17
+ private redraw;
18
+ private trueRedraw;
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;
33
+ }
34
+ //#endregion
35
+ export { Renderer };
36
+ //# sourceMappingURL=Renderer.d.ts.map
@@ -0,0 +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";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};
2
+ //# sourceMappingURL=Renderer.js.map
@@ -0,0 +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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"}
@@ -0,0 +1,135 @@
1
+ import { Hook } from "./utilities.js";
2
+ import { BaseArgs, BaseModule } from "./BaseModule.js";
3
+ import { BaseOptions } from "./index.js";
4
+
5
+ //#region src/kernel/StyleManager.d.ts
6
+ interface Color {
7
+ border: string;
8
+ background: string;
9
+ active: string;
10
+ text: string;
11
+ card: string;
12
+ }
13
+ interface WithBorderWidth extends Color {
14
+ 'border-width': string;
15
+ }
16
+ type ColorOptions = { [K in keyof (StyleManager['definedColors']['light'] & StyleManager['namedColors']['light'])]?: string };
17
+ interface Options extends BaseOptions {
18
+ theme?: 'dark' | 'light';
19
+ colors?: {
20
+ light?: ColorOptions;
21
+ dark?: ColorOptions;
22
+ };
23
+ }
24
+ interface Augmentation {
25
+ changeTheme: StyleManager['changeTheme'];
26
+ onChangeTheme: StyleManager['onChangeTheme'];
27
+ }
28
+ declare class StyleManager extends BaseModule<Options, Augmentation> {
29
+ theme: 'dark' | 'light';
30
+ onChangeTheme: Hook<["light" | "dark"], false>;
31
+ definedColors: {
32
+ light: {
33
+ '0': {
34
+ hue: number;
35
+ saturation: number;
36
+ lightness: number;
37
+ };
38
+ '1': {
39
+ hue: number;
40
+ saturation: number;
41
+ lightness: number;
42
+ };
43
+ '2': {
44
+ hue: number;
45
+ saturation: number;
46
+ lightness: number;
47
+ };
48
+ '3': {
49
+ hue: number;
50
+ saturation: number;
51
+ lightness: number;
52
+ };
53
+ '4': {
54
+ hue: number;
55
+ saturation: number;
56
+ lightness: number;
57
+ };
58
+ '5': {
59
+ hue: number;
60
+ saturation: number;
61
+ lightness: number;
62
+ };
63
+ '6': {
64
+ hue: number;
65
+ saturation: number;
66
+ lightness: number;
67
+ };
68
+ };
69
+ dark: {
70
+ '0': {
71
+ hue: number;
72
+ saturation: number;
73
+ lightness: number;
74
+ };
75
+ '1': {
76
+ hue: number;
77
+ saturation: number;
78
+ lightness: number;
79
+ };
80
+ '2': {
81
+ hue: number;
82
+ saturation: number;
83
+ lightness: number;
84
+ };
85
+ '3': {
86
+ hue: number;
87
+ saturation: number;
88
+ lightness: number;
89
+ };
90
+ '4': {
91
+ hue: number;
92
+ saturation: number;
93
+ lightness: number;
94
+ };
95
+ '5': {
96
+ hue: number;
97
+ saturation: number;
98
+ lightness: number;
99
+ };
100
+ '6': {
101
+ hue: number;
102
+ saturation: number;
103
+ lightness: number;
104
+ };
105
+ };
106
+ };
107
+ namedColors: {
108
+ light: {
109
+ dots: string;
110
+ text: string;
111
+ background: string;
112
+ 'background-secondary': string;
113
+ shadow: string;
114
+ border: string;
115
+ };
116
+ dark: {
117
+ dots: string;
118
+ text: string;
119
+ background: string;
120
+ 'background-secondary': string;
121
+ shadow: string;
122
+ border: string;
123
+ };
124
+ };
125
+ private colorCache;
126
+ constructor(...args: BaseArgs);
127
+ private hslProcessor;
128
+ private parseColor;
129
+ getColor: (colorIndex?: string) => WithBorderWidth;
130
+ getNamedColor: (name: keyof typeof this.namedColors.light) => string;
131
+ changeTheme: (theme?: "dark" | "light") => void;
132
+ }
133
+ //#endregion
134
+ export { StyleManager };
135
+ //# sourceMappingURL=StyleManager.d.ts.map
@@ -0,0 +1,2 @@
1
+ import{BaseModule as e}from"./BaseModule.js";import t from"./utilities.js";import n from"./DataManager.js";import{parseHex as r,parseHsl as i,parseRgb as a,rgbToHsl as o,toHslString as s}from"@ahmedsemih/color-fns";var c=class extends e{theme=`light`;onChangeTheme=t.makeHook();definedColors={light:{0:{hue:0,saturation:0,lightness:72},1:{hue:358,saturation:81,lightness:55},2:{hue:19,saturation:87,lightness:58},3:{hue:41,saturation:79,lightness:52},4:{hue:150,saturation:100,lightness:37},5:{hue:221,saturation:100,lightness:59},6:{hue:257,saturation:81,lightness:62}},dark:{0:{hue:0,saturation:0,lightness:40},1:{hue:358,saturation:100,lightness:65},2:{hue:23,saturation:86,lightness:63},3:{hue:39,saturation:91,lightness:70},4:{hue:153,saturation:80,lightness:45},5:{hue:217,saturation:100,lightness:62},6:{hue:259,saturation:100,lightness:75}}};namedColors={light:{dots:`hsla(0, 0%, 72%, 0.4)`,text:`rgb(30, 30, 30)`,background:`rgb(250, 250, 250)`,"background-secondary":`rgb(255, 255, 255)`,shadow:`0px 0px 8px rgb(0, 0, 0, 0.1)`,border:`hsla(0, 0%, 82%, 0.7)`},dark:{dots:`hsla(0, 0%, 40%, 0.3)`,text:`rgb(242, 242, 242)`,background:`rgb(30, 30, 30)`,"background-secondary":`rgb(37, 37, 40)`,shadow:`0px 0px 8px rgb(0, 0, 0, 0.2)`,border:`hsla(0, 0%, 30%, 0.7)`}};colorCache={dark:{},light:{}};constructor(...e){super(...e);let t=this.options.colors;t&&[`light`,`dark`].forEach(e=>{if(!(e in t))return;let n=t[e];n&&Object.entries(n).forEach(([t,n])=>{if(!n)return;let r=this.namedColors[e],i=this.definedColors[e];if(t in r)r[t]=n;else if(t in i){let e=this.parseColor(n);if(!e){console.warn(`[JSON Canvas Viewer] Color ${n} unsupported.`);return}i[t]=e}})}),this.changeTheme(this.options.theme??`light`),this.augment({changeTheme:this.changeTheme,onChangeTheme:this.onChangeTheme})}hslProcessor=e=>{let{hue:t,saturation:n,lightness:r}=e,i;return i=this.theme===`dark`?{active:e,card:{hue:t,saturation:n/3,lightness:r/3},border:{...e,alpha:.7},background:{...e,alpha:.1},text:e.lightness>=70?`rgb(30, 30, 30)`:`rgb(242, 242, 242)`}:{active:e,card:t===0?{hue:t,saturation:n,lightness:100}:{hue:t,saturation:n*.4,lightness:90},border:{...e,alpha:.7},background:{...e,alpha:.1},text:e.lightness>=70?`rgb(30, 30, 30)`:`rgb(242, 242, 242)`},{active:s(i.active),card:s(i.card),border:s(i.border),background:s(i.background),text:i.text}};parseColor=e=>{if(e.startsWith(`rgb`))return o(a(e));if(e.startsWith(`#`))return o(r(e));if(e.startsWith(`hsl`))return i(e)};getColor=(e=`0`)=>{let t=this.theme,n;if(this.colorCache[t][e])return this.colorCache[t][e];n=e in this.definedColors[t]?this.hslProcessor(this.definedColors[t][e]):this.hslProcessor(o(r(e)));let i={...n,"border-width":e===`0`?`1px`:`2px`};return this.colorCache[t][e]=i,i};getNamedColor=e=>this.namedColors[this.theme][e];changeTheme=e=>{this.theme=e||(this.theme===`dark`?`light`:`dark`);let t=this.container.get(n).data.container;Object.entries(this.namedColors[this.theme]).forEach(([e,n])=>{t.style.setProperty(`--${e}`,n)}),this.onChangeTheme(this.theme)}};export{c as default};
2
+ //# sourceMappingURL=StyleManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StyleManager.js","names":["utilities"],"sources":["../../src/kernel/StyleManager.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport { BaseModule, type BaseArgs } from '$/BaseModule';\nimport DataManager from '$/DataManager';\nimport utilities from '$/utilities';\nimport {\n\tparseHex,\n\ttoHslString,\n\ttype HslColor,\n\trgbToHsl,\n\tparseHsl,\n\tparseRgb,\n} from '@ahmedsemih/color-fns';\n\ninterface Color {\n\tborder: string;\n\tbackground: string;\n\tactive: string;\n\ttext: string;\n\tcard: string;\n}\n\nexport interface WithBorderWidth extends Color {\n\t'border-width': string;\n}\n\ntype ColorOptions = {\n\t[K in keyof (StyleManager['definedColors']['light'] &\n\t\tStyleManager['namedColors']['light'])]?: string;\n};\n\ninterface Options extends BaseOptions {\n\ttheme?: 'dark' | 'light';\n\tcolors?: {\n\t\tlight?: ColorOptions;\n\t\tdark?: ColorOptions;\n\t};\n}\n\ninterface Augmentation {\n\tchangeTheme: StyleManager['changeTheme'];\n\tonChangeTheme: StyleManager['onChangeTheme'];\n}\n\nexport default class StyleManager extends BaseModule<Options, Augmentation> {\n\ttheme: 'dark' | 'light' = 'light';\n\tonChangeTheme = utilities.makeHook<['light' | 'dark']>();\n\tdefinedColors = {\n\t\tlight: {\n\t\t\t'0': { hue: 0, saturation: 0, lightness: 72 },\n\t\t\t'1': { hue: 358, saturation: 81, lightness: 55 },\n\t\t\t'2': { hue: 19, saturation: 87, lightness: 58 },\n\t\t\t'3': { hue: 41, saturation: 79, lightness: 52 },\n\t\t\t'4': { hue: 150, saturation: 100, lightness: 37 },\n\t\t\t'5': { hue: 221, saturation: 100, lightness: 59 },\n\t\t\t'6': { hue: 257, saturation: 81, lightness: 62 },\n\t\t},\n\t\tdark: {\n\t\t\t'0': { hue: 0, saturation: 0, lightness: 40 },\n\t\t\t'1': { hue: 358, saturation: 100, lightness: 65 },\n\t\t\t'2': { hue: 23, saturation: 86, lightness: 63 },\n\t\t\t'3': { hue: 39, saturation: 91, lightness: 70 },\n\t\t\t'4': { hue: 153, saturation: 80, lightness: 45 },\n\t\t\t'5': { hue: 217, saturation: 100, lightness: 62 },\n\t\t\t'6': { hue: 259, saturation: 100, lightness: 75 },\n\t\t},\n\t};\n\n\tnamedColors = {\n\t\tlight: {\n\t\t\tdots: 'hsla(0, 0%, 72%, 0.4)',\n\t\t\ttext: 'rgb(30, 30, 30)',\n\t\t\tbackground: 'rgb(250, 250, 250)',\n\t\t\t'background-secondary': 'rgb(255, 255, 255)',\n\t\t\tshadow: '0px 0px 8px rgb(0, 0, 0, 0.1)',\n\t\t\tborder: 'hsla(0, 0%, 82%, 0.7)',\n\t\t},\n\t\tdark: {\n\t\t\tdots: 'hsla(0, 0%, 40%, 0.3)',\n\t\t\ttext: 'rgb(242, 242, 242)',\n\t\t\tbackground: 'rgb(30, 30, 30)',\n\t\t\t'background-secondary': 'rgb(37, 37, 40)',\n\t\t\tshadow: '0px 0px 8px rgb(0, 0, 0, 0.2)',\n\t\t\tborder: 'hsla(0, 0%, 30%, 0.7)',\n\t\t},\n\t};\n\n\tprivate colorCache: {\n\t\tdark: {\n\t\t\t[key: string]: WithBorderWidth;\n\t\t};\n\t\tlight: {\n\t\t\t[key: string]: WithBorderWidth;\n\t\t};\n\t} = {\n\t\tdark: {},\n\t\tlight: {},\n\t};\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\n\t\t// user-defined color merging\n\t\tconst colors = this.options.colors;\n\t\tif (colors) {\n\t\t\tconst themes = ['light', 'dark'] as const;\n\t\t\tthemes.forEach((theme) => {\n\t\t\t\tif (!(theme in colors)) return;\n\t\t\t\tconst colorObject = colors[theme];\n\t\t\t\tif (!colorObject) return;\n\t\t\t\tObject.entries(colorObject).forEach(([key, value]) => {\n\t\t\t\t\tif (!value) return;\n\t\t\t\t\tconst namedColorsDict = this.namedColors[theme];\n\t\t\t\t\tconst definedColorsDict = this.definedColors[theme];\n\t\t\t\t\tif (key in namedColorsDict)\n\t\t\t\t\t\tnamedColorsDict[key as keyof typeof namedColorsDict] = value;\n\t\t\t\t\telse if (key in definedColorsDict) {\n\t\t\t\t\t\tconst color = this.parseColor(value);\n\t\t\t\t\t\tif (!color) {\n\t\t\t\t\t\t\tconsole.warn(`[JSON Canvas Viewer] Color ${value} unsupported.`);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdefinedColorsDict[key as keyof typeof definedColorsDict] = color;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\tthis.changeTheme(this.options.theme ?? 'light');\n\t\tthis.augment({\n\t\t\tchangeTheme: this.changeTheme,\n\t\t\tonChangeTheme: this.onChangeTheme,\n\t\t});\n\t}\n\n\tprivate hslProcessor = (color: HslColor) => {\n\t\tconst { hue, saturation, lightness } = color;\n\t\tlet result;\n\t\tif (this.theme === 'dark') {\n\t\t\tresult = {\n\t\t\t\tactive: color,\n\t\t\t\tcard: { hue, saturation: saturation / 3, lightness: lightness / 3 },\n\t\t\t\tborder: { ...color, alpha: 0.7 },\n\t\t\t\tbackground: { ...color, alpha: 0.1 },\n\t\t\t\ttext: color.lightness >= 70 ? 'rgb(30, 30, 30)' : 'rgb(242, 242, 242)',\n\t\t\t};\n\t\t} else {\n\t\t\tresult = {\n\t\t\t\tactive: color,\n\t\t\t\tcard:\n\t\t\t\t\thue === 0\n\t\t\t\t\t\t? { hue, saturation, lightness: 100 }\n\t\t\t\t\t\t: { hue, saturation: saturation * 0.4, lightness: 90 },\n\t\t\t\tborder: { ...color, alpha: 0.7 },\n\t\t\t\tbackground: { ...color, alpha: 0.1 },\n\t\t\t\ttext: color.lightness >= 70 ? 'rgb(30, 30, 30)' : 'rgb(242, 242, 242)',\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tactive: toHslString(result.active),\n\t\t\tcard: toHslString(result.card),\n\t\t\tborder: toHslString(result.border),\n\t\t\tbackground: toHslString(result.background),\n\t\t\ttext: result.text,\n\t\t};\n\t};\n\n\tprivate parseColor = (color: string) => {\n\t\tif (color.startsWith('rgb')) return rgbToHsl(parseRgb(color));\n\t\tif (color.startsWith('#')) return rgbToHsl(parseHex(color));\n\t\tif (color.startsWith('hsl')) return parseHsl(color);\n\t};\n\n\tgetColor = (colorIndex: string = '0') => {\n\t\tconst theme = this.theme;\n\t\tlet color: Color;\n\t\tif (this.colorCache[theme][colorIndex]) return this.colorCache[theme][colorIndex];\n\t\telse if (colorIndex in this.definedColors[theme])\n\t\t\tcolor = this.hslProcessor(\n\t\t\t\tthis.definedColors[theme][colorIndex as keyof typeof this.definedColors.dark],\n\t\t\t);\n\t\telse color = this.hslProcessor(rgbToHsl(parseHex(colorIndex)));\n\t\tconst withBorderWidth: WithBorderWidth = {\n\t\t\t...color,\n\t\t\t'border-width': colorIndex === '0' ? '1px' : '2px',\n\t\t};\n\t\tthis.colorCache[theme][colorIndex] = withBorderWidth;\n\t\treturn withBorderWidth;\n\t};\n\n\tgetNamedColor = (name: keyof typeof this.namedColors.light) =>\n\t\tthis.namedColors[this.theme][name];\n\n\tchangeTheme = (theme?: 'dark' | 'light') => {\n\t\tthis.theme = theme ? theme : this.theme === 'dark' ? 'light' : 'dark';\n\t\tconst container = this.container.get(DataManager).data.container;\n\t\tObject.entries(this.namedColors[this.theme]).forEach(([key, value]) => {\n\t\t\tcontainer.style.setProperty(`--${key}`, value);\n\t\t});\n\t\tthis.onChangeTheme(this.theme);\n\t};\n}\n"],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import { JSONCanvas } from "../shared/index.js";
2
+ import { Hook } from "./utilities.js";
3
+ import { Augmentation, ModuleInput, ModuleInputCtor, Options } from "./BaseModule.js";
4
+ import { Controller } from "./Controller.js";
5
+ import { DataManager } from "./DataManager.js";
6
+ import { InteractionHandler } from "./InteractionHandler.js";
7
+ import { OverlayManager } from "./OverlayManager.js";
8
+ import { Renderer } from "./Renderer.js";
9
+ import { StyleManager } from "./StyleManager.js";
10
+ import { Container } from "@needle-di/core";
11
+
12
+ //#region src/kernel/index.d.ts
13
+ interface BaseOptions {
14
+ container: HTMLElement;
15
+ loading?: 'normal' | 'lazy' | 'none';
16
+ }
17
+ declare const internalModules: (typeof Controller | typeof DataManager | typeof InteractionHandler | typeof OverlayManager | typeof Renderer | typeof StyleManager)[];
18
+ type InternalModules = typeof internalModules;
19
+ type AllOptions<M extends ModuleInput = []> = Options<M> & Options<InternalModules>;
20
+ type AllAugmentation<M extends ModuleInput = []> = Augmentation<M> & Augmentation<InternalModules>;
21
+ declare class JSONCanvasViewer<M extends ModuleInputCtor> {
22
+ private allModules;
23
+ private IO;
24
+ private started;
25
+ private disposed;
26
+ options: AllOptions<M>;
27
+ container: Container;
28
+ onDispose: Hook<[], false>;
29
+ onStart: Hook<[], false>;
30
+ onRestart: Hook<[], false>;
31
+ constructor(options: AllOptions<M>, modules?: M);
32
+ private onVisibilityCheck;
33
+ private augment;
34
+ load: (options?: {
35
+ canvas?: JSONCanvas;
36
+ attachmentDir?: string;
37
+ attachments?: Record<string, string>;
38
+ }) => void;
39
+ dispose: () => void;
40
+ }
41
+ type JSONCanvasViewerType = new <M extends ModuleInputCtor = []>(...args: ConstructorParameters<typeof JSONCanvasViewer<M>>) => JSONCanvasViewer<M> & AllAugmentation<M>;
42
+ type JSONCanvasViewerInterface<M extends ModuleInput = []> = JSONCanvasViewer<never> & AllAugmentation<M>;
43
+ declare const _default: JSONCanvasViewerType;
44
+ //#endregion
45
+ export { AllOptions, BaseOptions, JSONCanvasViewerInterface, _default };
46
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,2 @@
1
+ import e from"./utilities.js";import t from"./DataManager.js";import n from"./StyleManager.js";import r from"./Controller.js";import i from"./OverlayManager.js";import a from"./InteractionHandler.js";import o from"./Renderer.js";import{Container as s}from"@needle-di/core";const c=[t,n,r,i,a,o];var l=class{allModules;IO=null;started=!1;disposed=!1;options;container;onDispose=e.makeHook(!0);onStart=e.makeHook();onRestart=e.makeHook();constructor(e,t){this.container=new s,this.options=e;let n=e=>{this.container.bind({provide:e,useFactory:()=>new e(this.container,this.options,this.onStart,this.onDispose,this.onRestart,this.augment)})};this.allModules=[...c,...t??[]],this.allModules.forEach(n),this.allModules.forEach(e=>{this.container.get(e)});let r=this.options.loading??`normal`;r===`normal`?this.load():r===`lazy`&&(this.IO=new IntersectionObserver(this.onVisibilityCheck,{root:null,rootMargin:`50px`,threshold:0}),this.IO.observe(this.options.container))}onVisibilityCheck=e=>{e.forEach(e=>{if(e.isIntersecting){this.load(),this.IO?.disconnect(),this.IO=null;return}})};augment=e=>{let t=Object.getOwnPropertyDescriptors(e);Object.defineProperties(this,t)};load=e=>{this.disposed||(e&&Object.assign(this.options,e),this.started?this.onRestart():(this.onStart(),this.started=!0))};dispose=()=>{if(!this.started||this.disposed)return;this.IO?.disconnect(),this.IO=null;let e=this.options.container;for(;e.firstChild;)e.firstChild.remove();this.onDispose(),this.container.unbindAll(),this.disposed=!0}};export{l as default};
2
+ //# sourceMappingURL=index.js.map