@ovalbee/flow-viewer 0.0.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.
package/README.md ADDED
@@ -0,0 +1,16 @@
1
+ # @ovalbee/flow-viewer
2
+
3
+ Read-only Vue components for displaying OvalBee workflow graphs.
4
+
5
+ ## Components
6
+
7
+ - `FlowPreview` renders a lightweight SVG preview suitable for cards.
8
+ - `FlowViewer` renders an interactive graph with pan, zoom, controls, and a minimap.
9
+
10
+ Import the package styles once through the package entrypoint:
11
+
12
+ ```ts
13
+ import { FlowPreview, FlowViewer } from '@ovalbee/flow-viewer';
14
+ ```
15
+
16
+ Vue and the `@vue-flow` packages are peer dependencies.
@@ -0,0 +1,12 @@
1
+ import { Component } from 'vue';
2
+ import { FlowPreviewDocument } from './types';
3
+ type __VLS_Props = {
4
+ preview: FlowPreviewDocument | null;
5
+ icons?: Record<string, Component>;
6
+ iconUrl?: (name: string) => string;
7
+ };
8
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
9
+ icons: Record<string, Component>;
10
+ iconUrl: (name: string) => string;
11
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
12
+ export default _default;
@@ -0,0 +1,21 @@
1
+ import { FlowViewerDocument } from './types';
2
+ type __VLS_Props = {
3
+ document: FlowViewerDocument;
4
+ fitViewOnInit?: boolean;
5
+ showControls?: boolean;
6
+ showMiniMap?: boolean;
7
+ minZoom?: number;
8
+ maxZoom?: number;
9
+ initialZoom?: number;
10
+ theme?: 'light' | 'dark';
11
+ };
12
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
13
+ fitViewOnInit: boolean;
14
+ showControls: boolean;
15
+ showMiniMap: boolean;
16
+ minZoom: number;
17
+ maxZoom: number;
18
+ initialZoom: number;
19
+ theme: "light" | "dark";
20
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
21
+ export default _default;
@@ -0,0 +1,8 @@
1
+ import { NodeProps } from '@vue-flow/core';
2
+ import { FlowViewerCatalogNode } from './types';
3
+ type FlowViewerNodeData = FlowViewerCatalogNode & {
4
+ connectedHandles: Set<string>;
5
+ };
6
+ type __VLS_Props = NodeProps<FlowViewerNodeData>;
7
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLElement>;
8
+ export default _default;
@@ -0,0 +1,5 @@
1
+ import { NodeProps } from '@vue-flow/core';
2
+ import { FlowViewerNote } from './types';
3
+ type __VLS_Props = NodeProps<FlowViewerNote>;
4
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLElement>;
5
+ export default _default;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("vue"),g=require("@vue-flow/core"),I=require("@vue-flow/controls"),L=require("@vue-flow/minimap"),z=Symbol("flow-viewer-details"),O=["aria-label"],A={class:"ob-flow-viewer-node__header"},R=["innerHTML"],X={key:1},Z={class:"ob-flow-viewer-node__title-wrap"},Y={class:"ob-flow-viewer-node__title"},W={class:"ob-flow-viewer-node__key"},U={class:"ob-flow-viewer-node__description ob-flow-viewer-node__description--clamped"},G={key:1,class:"ob-flow-viewer-node__widget-image","aria-hidden":"true"},q=e.defineComponent({__name:"FlowViewerNode",props:{id:{},type:{},selected:{type:Boolean},connectable:{type:[Boolean,Number,String,Function]},position:{},dimensions:{},label:{},isValidTargetPos:{type:Function},isValidSourcePos:{type:Function},parent:{},parentNodeId:{},dragging:{type:Boolean},resizing:{type:Boolean},zIndex:{},targetPosition:{},sourcePosition:{},dragHandle:{},data:{},events:{}},setup(n){const d=n,v=e.inject(z),x=d.data.available?d.data.description:"This node template is unavailable.";return(r,c)=>{var m,f;return e.openBlock(),e.createElementBlock("article",{class:e.normalizeClass(["ob-flow-viewer-node",{"ob-flow-viewer-node--unavailable":!n.data.available}]),tabindex:"0","aria-label":`${n.data.name} node`,onMouseenter:c[0]||(c[0]=o=>{var i;return(i=e.unref(v))==null?void 0:i.show(n.data,o)}),onMouseleave:c[1]||(c[1]=o=>{var i;return(i=e.unref(v))==null?void 0:i.hide()}),onClick:c[2]||(c[2]=o=>{var i;return(i=e.unref(v))==null?void 0:i.show(n.data,o)}),onFocus:c[3]||(c[3]=o=>{var i;return(i=e.unref(v))==null?void 0:i.show(n.data,o)}),onBlur:c[4]||(c[4]=o=>{var i;return(i=e.unref(v))==null?void 0:i.hide()})},[e.createElementVNode("header",A,[e.createElementVNode("span",{class:"ob-flow-viewer-node__icon",style:e.normalizeStyle({"--ob-node-icon-color":((m=n.data.icon)==null?void 0:m.color)??"#64748b"}),"aria-hidden":"true"},[(f=n.data.icon)!=null&&f.svg?(e.openBlock(),e.createElementBlock("span",{key:0,class:"ob-flow-viewer-node__icon-svg",innerHTML:n.data.icon.svg},null,8,R)):(e.openBlock(),e.createElementBlock("span",X,e.toDisplayString(n.data.available?n.data.name.slice(0,1).toUpperCase():"?"),1))],4),e.createElementVNode("span",Z,[e.createElementVNode("strong",Y,e.toDisplayString(n.data.name),1),e.createElementVNode("span",W,e.toDisplayString(n.data.key),1)])]),e.createElementVNode("p",U,e.toDisplayString(e.unref(x)),1),n.data.widgetPreview&&n.data.available?(e.openBlock(),e.createElementBlock("div",{key:0,class:e.normalizeClass(["ob-flow-viewer-node__widget",`ob-flow-viewer-node__widget--${n.data.widgetPreview}`]),"aria-label":"Widget preview"},[n.data.widgetPreview==="button"?(e.openBlock(),e.createElementBlock(e.Fragment,{key:0},[c[5]||(c[5]=e.createElementVNode("span",{class:"ob-flow-viewer-node__widget-icon"},"↗",-1)),c[6]||(c[6]=e.createElementVNode("span",{class:"ob-flow-viewer-node__widget-label"},null,-1))],64)):n.data.widgetPreview==="dataset"?(e.openBlock(),e.createElementBlock("span",G)):(e.openBlock(),e.createElementBlock(e.Fragment,{key:2},[c[7]||(c[7]=e.createElementVNode("span",null,null,-1)),c[8]||(c[8]=e.createElementVNode("span",null,null,-1))],64))],2)):e.createCommentVNode("",!0),n.data.connectedHandles.has("target")?(e.openBlock(),e.createBlock(e.unref(g.Handle),{key:1,type:"target",position:e.unref(g.Position).Top},null,8,["position"])):e.createCommentVNode("",!0),n.data.connectedHandles.has("left")?(e.openBlock(),e.createBlock(e.unref(g.Handle),{key:2,id:"left",type:"target",position:e.unref(g.Position).Left},null,8,["position"])):e.createCommentVNode("",!0),n.data.connectedHandles.has("right")?(e.openBlock(),e.createBlock(e.unref(g.Handle),{key:3,id:"right",type:"target",position:e.unref(g.Position).Right},null,8,["position"])):e.createCommentVNode("",!0),n.data.connectedHandles.has("source")?(e.openBlock(),e.createBlock(e.unref(g.Handle),{key:4,type:"source",position:e.unref(g.Position).Bottom},null,8,["position"])):e.createCommentVNode("",!0),n.data.connectedHandles.has("left-source")?(e.openBlock(),e.createBlock(e.unref(g.Handle),{key:5,id:"left-source",type:"source",position:e.unref(g.Position).Left},null,8,["position"])):e.createCommentVNode("",!0),n.data.connectedHandles.has("right-source")?(e.openBlock(),e.createBlock(e.unref(g.Handle),{key:6,id:"right-source",type:"source",position:e.unref(g.Position).Right},null,8,["position"])):e.createCommentVNode("",!0)],42,O)}}}),j=e.defineComponent({__name:"FlowViewerNote",props:{id:{},type:{},selected:{type:Boolean},connectable:{type:[Boolean,Number,String,Function]},position:{},dimensions:{},label:{},isValidTargetPos:{type:Function},isValidSourcePos:{type:Function},parent:{},parentNodeId:{},dragging:{type:Boolean},resizing:{type:Boolean},zIndex:{},targetPosition:{},sourcePosition:{},dragHandle:{},data:{},events:{}},setup(n){const d=n,v=e.computed(()=>({width:`${d.data.appearance.width}px`,minHeight:d.data.appearance.height?`${d.data.appearance.height}px`:void 0}));return(x,r)=>(e.openBlock(),e.createElementBlock("article",{class:e.normalizeClass(["ob-flow-viewer-note",`ob-flow-viewer-note--${n.data.appearance.color}`]),style:e.normalizeStyle(v.value)},e.toDisplayString(n.data.content),7))}}),K=["data-theme"],J=["data-theme"],Q={class:"ob-flow-viewer-tooltip__header"},ee=["innerHTML"],te={key:1},oe={class:"ob-flow-viewer-tooltip__title-wrap"},ne={class:"ob-flow-viewer-tooltip__body"},ie={key:0,class:"ob-flow-viewer-tooltip__unavailable"},ae={key:1,class:"ob-flow-viewer-tooltip__description"},le={key:2,class:"ob-flow-viewer-node__ports"},se={class:"ob-flow-viewer-node__port-group"},ce={key:0,class:"ob-flow-viewer-node__empty"},re={key:0},de={class:"ob-flow-viewer-node__port-group ob-flow-viewer-node__port-group--outputs"},ue={key:0,class:"ob-flow-viewer-node__empty"},me={key:0},S=72,P=64,pe=1.45,we=e.defineComponent({__name:"FlowViewer",props:{document:{},fitViewOnInit:{type:Boolean,default:!1},showControls:{type:Boolean,default:!0},showMiniMap:{type:Boolean,default:!0},minZoom:{default:.1},maxZoom:{default:2},initialZoom:{default:.8},theme:{default:"light"}},setup(n){const d=n,v={catalog:e.markRaw(q),note:e.markRaw(j)};function x(t){if(t.kind==="note")return t.appearance.height??130;const a=t.description?Math.min(2,Math.max(1,Math.ceil(t.description.length/34))):t.available?0:1,u=a>0?10+a*19.5:0,h=t.available&&t.widgetPreview?10+(t.widgetPreview==="dataset"?72:32):0;return 60+u+h}const r=e.ref(null);let c=null;function m(){c!==null&&(clearTimeout(c),c=null)}function f(){m(),c=setTimeout(()=>{r.value=null,c=null},140)}e.onBeforeUnmount(m);function o(t){const a=new Set;for(const u of d.document.edges)u.source===t&&a.add(u.sourceHandle??"source"),u.target===t&&a.add(u.targetHandle??"target");return a}function i(t,a){m();const u=a.currentTarget;if(!(u instanceof HTMLElement))return;const h=u.getBoundingClientRect(),l=12,s=Math.min(404,window.innerWidth-l*2),y=Math.min(520,window.innerHeight-l*2);let w=h.right+l+s/2;w+s/2>window.innerWidth-l&&(w=h.left-l-s/2),w=Math.max(s/2+l,Math.min(w,window.innerWidth-s/2-l)),r.value={node:t,x:w,y:Math.max(l,Math.min(h.top,window.innerHeight-y-l))}}function p(){f()}e.provide(z,{show:i,hide:p});const k=e.computed(()=>{const t=new Map(d.document.nodes.map(s=>[s.id,{...s.position}])),a=Math.min(...d.document.nodes.map(s=>s.position.x)),u=Math.max(...d.document.nodes.map(s=>s.position.x)),h=(a+u)/2;for(const s of t.values())s.x=h+(s.x-h)*pe;for(let s=0;s<d.document.nodes.length;s+=1)for(const y of d.document.edges){if(y.sourceHandle||y.targetHandle)continue;const w=t.get(y.source),B=t.get(y.target);if(!(!w||!B||Math.abs(w.x-B.x)>=40)&&(B.x=w.x,B.y>w.y)){const E=d.document.nodes.find($=>$.id===y.source);E&&(B.y=Math.max(B.y,w.y+x(E)+S))}}const l=[...d.document.nodes].sort((s,y)=>s.position.y-y.position.y||s.position.x-y.position.x);for(const[s,y]of l.entries()){const w=t.get(y.id);if(w)for(const B of l.slice(0,s)){const E=t.get(B.id);if(!E)continue;const $=y.kind==="note"?y.appearance.width:260,D=B.kind==="note"?B.appearance.width:260;w.x>=E.x+D+P||E.x>=w.x+$+P||(w.y=Math.max(w.y,E.y+x(B)+S))}}return t}),b=e.computed(()=>d.document.nodes.map(t=>{const a=k.value.get(t.id)??t.position;return t.kind==="note"?{id:t.id,type:"note",position:a,data:t,style:{width:`${t.appearance.width}px`,height:t.appearance.height?`${t.appearance.height}px`:void 0}}:{id:t.id,type:"catalog",position:a,data:{...t,connectedHandles:o(t.id)},selectable:!1}})),_=e.computed(()=>d.document.edges.map((t,a)=>({id:`viewer-edge-${a}-${t.source}-${t.target}`,source:t.source,target:t.target,sourceHandle:t.sourceHandle,targetHandle:t.targetHandle,type:g.ConnectionLineType.SmoothStep,data:t.data,style:t.isVisual?{strokeDasharray:"6 4"}:void 0,selectable:!1}))),F=e.computed(()=>{if(d.document.nodes.length===0)return{minX:0,minY:0,maxX:0,maxY:0};let t=1/0,a=1/0,u=-1/0,h=-1/0;for(const l of d.document.nodes){const s=k.value.get(l.id)??l.position,y=l.kind==="note"?l.appearance.width:260,w=x(l);t=Math.min(t,s.x),a=Math.min(a,s.y),u=Math.max(u,s.x+y),h=Math.max(h,s.y+w)}return{minX:t,minY:a,maxX:u,maxY:h}});function T(t){if(d.fitViewOnInit){t.fitView({padding:.15,maxZoom:1});return}const a=F.value,u=d.initialZoom;t.setViewport({x:t.dimensions.value.width/2-(a.minX+a.maxX)/2*u,y:24-a.minY*u,zoom:u})}return(t,a)=>{var u,h;return e.openBlock(),e.createElementBlock("div",{class:"ob-flow-viewer","data-theme":n.theme},[e.createVNode(e.unref(g.VueFlow),{nodes:b.value,edges:_.value,"node-types":v,"fit-view-on-init":!1,"min-zoom":n.minZoom,"max-zoom":n.maxZoom,"nodes-draggable":!1,"nodes-connectable":!1,"elements-selectable":!0,"select-nodes-on-drag":!1,"connect-on-click":!1,"zoom-on-double-click":!1,"delete-key-code":[],"multi-selection-key-code":[],"pan-on-drag":!0,"pan-on-scroll":!0,"zoom-on-scroll":!1,"zoom-on-pinch":!0,class:"ob-flow-viewer__canvas",onPaneReady:T},{default:e.withCtx(()=>[n.showControls?(e.openBlock(),e.createBlock(e.unref(I.Controls),{key:0,"show-interactive":!1})):e.createCommentVNode("",!0),n.showMiniMap?(e.openBlock(),e.createBlock(e.unref(L.MiniMap),{key:1,pannable:!0,zoomable:!0})):e.createCommentVNode("",!0)]),_:1},8,["nodes","edges","min-zoom","max-zoom"]),(e.openBlock(),e.createBlock(e.Teleport,{to:"body"},[r.value?(e.openBlock(),e.createElementBlock("section",{key:0,class:"ob-flow-viewer-tooltip","data-theme":n.theme,style:e.normalizeStyle({left:`${r.value.x}px`,top:`${r.value.y}px`}),role:"tooltip",tabindex:"0",onMouseenter:m,onMouseleave:p,onFocusin:m,onFocusout:p},[e.createElementVNode("header",Q,[e.createElementVNode("span",{class:"ob-flow-viewer-tooltip__icon",style:e.normalizeStyle({"--ob-node-icon-color":((u=r.value.node.icon)==null?void 0:u.color)??"#64748b"}),"aria-hidden":"true"},[(h=r.value.node.icon)!=null&&h.svg?(e.openBlock(),e.createElementBlock("span",{key:0,class:"ob-flow-viewer-node__icon-svg",innerHTML:r.value.node.icon.svg},null,8,ee)):(e.openBlock(),e.createElementBlock("span",te,e.toDisplayString(r.value.node.available?r.value.node.name.slice(0,1).toUpperCase():"?"),1))],4),e.createElementVNode("span",oe,[e.createElementVNode("strong",null,e.toDisplayString(r.value.node.name),1),e.createElementVNode("code",null,e.toDisplayString(r.value.node.key),1)])]),e.createElementVNode("div",ne,[r.value.node.available?r.value.node.description?(e.openBlock(),e.createElementBlock("p",ae,e.toDisplayString(r.value.node.description),1)):e.createCommentVNode("",!0):(e.openBlock(),e.createElementBlock("p",ie," This node template is unavailable. ")),r.value.node.available?(e.openBlock(),e.createElementBlock("div",le,[e.createElementVNode("div",se,[a[0]||(a[0]=e.createElementVNode("span",{class:"ob-flow-viewer-node__port-heading"},"Inputs",-1)),r.value.node.inputs.length===0?(e.openBlock(),e.createElementBlock("span",ce,"None")):e.createCommentVNode("",!0),(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(r.value.node.inputs,l=>(e.openBlock(),e.createElementBlock("span",{key:l.key,class:"ob-flow-viewer-node__port"},[e.createElementVNode("span",null,e.toDisplayString(l.name),1),l.description?(e.openBlock(),e.createElementBlock("small",re,e.toDisplayString(l.description),1)):e.createCommentVNode("",!0)]))),128))]),e.createElementVNode("div",de,[a[1]||(a[1]=e.createElementVNode("span",{class:"ob-flow-viewer-node__port-heading"},"Outputs",-1)),r.value.node.outputs.length===0?(e.openBlock(),e.createElementBlock("span",ue,"None")):e.createCommentVNode("",!0),(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(r.value.node.outputs,l=>(e.openBlock(),e.createElementBlock("span",{key:l.key,class:"ob-flow-viewer-node__port"},[e.createElementVNode("span",null,e.toDisplayString(l.name),1),l.description?(e.openBlock(),e.createElementBlock("small",me,e.toDisplayString(l.description),1)):e.createCommentVNode("",!0)]))),128))])])):e.createCommentVNode("",!0)])],44,J)):e.createCommentVNode("",!0)]))],8,K)}}}),fe={class:"ob-flow-preview"},ye=["viewBox"],he=["d"],ve=["x","y"],ge=["x","y"],ke=["href","x","y"],Be=["x","y"],xe=["x","y"],N=260,V=100,M=140,be=140,C=48,H=26,_e=e.defineComponent({__name:"FlowPreview",props:{preview:{},icons:{default:()=>({})},iconUrl:{type:Function,default:void 0}},setup(n){const d=n,v=e.computed(()=>{var o,i;const m=((o=d.preview)==null?void 0:o.n)??[],f=new Map(m.map(p=>[p.id,{x:p.x,y:p.y}]));for(let p=0;p<m.length;p+=1)for(const k of((i=d.preview)==null?void 0:i.e)??[]){const b=f.get(k.s),_=f.get(k.t);b&&_&&Math.abs(b.x-_.x)<be&&(_.x=b.x)}return m.map(p=>({...p,...f.get(p.id)??{x:p.x,y:p.y}}))}),x=e.computed(()=>{const m=v.value;if(m.length===0)return"0 0 1 1";let f=1/0,o=1/0,i=-1/0,p=-1/0;for(const k of m)f=Math.min(f,k.x),o=Math.min(o,k.y),i=Math.max(i,k.x+N),p=Math.max(p,k.y+V);return`${f-M} ${o-M} ${i-f+M*2} ${p-o+M*2}`}),r=e.computed(()=>new Map(v.value.map(m=>[m.id,m])));function c(m,f){const o=r.value.get(m),i=r.value.get(f);if(!o||!i)return"";const p=o.x+N/2,k=o.y+V/2,b=i.x+N/2,_=i.y+V/2;return`M ${p} ${k} L ${b} ${_}`}return(m,f)=>(e.openBlock(),e.createElementBlock("div",fe,[n.preview&&n.preview.n.length>0?(e.openBlock(),e.createElementBlock("svg",{key:0,class:"ob-flow-preview__svg",viewBox:x.value,preserveAspectRatio:"xMidYMid meet"},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(n.preview.e,(o,i)=>(e.openBlock(),e.createElementBlock("path",{key:i,d:c(o.s,o.t),class:"ob-flow-preview__edge","vector-effect":"non-scaling-stroke"},null,8,he))),128)),(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(v.value,o=>(e.openBlock(),e.createElementBlock("rect",{key:o.id,x:o.x,y:o.y,width:N,height:V,rx:"16",class:"ob-flow-preview__node","vector-effect":"non-scaling-stroke"},null,8,ve))),128)),(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(v.value,o=>(e.openBlock(),e.createElementBlock(e.Fragment,{key:`content-${o.id}`},[e.createElementVNode("rect",{x:o.x+18,y:o.y+18,width:"64",height:"64",rx:"16",class:"ob-flow-preview__icon-background",style:e.normalizeStyle(o.c?{fill:o.c}:void 0)},null,12,ge),o.i&&n.icons[o.i]?(e.openBlock(),e.createBlock(e.resolveDynamicComponent(n.icons[o.i]),{key:0,x:o.x+H,y:o.y+H,size:C,color:"white","stroke-width":2.5,"aria-hidden":"true"},null,8,["x","y"])):o.i&&n.iconUrl?(e.openBlock(),e.createElementBlock("image",{key:1,href:n.iconUrl(o.i),x:o.x+H,y:o.y+H,width:C,height:C},null,8,ke)):(e.openBlock(),e.createElementBlock("text",{key:2,x:o.x+50,y:o.y+68,fill:"white","font-size":"42","font-family":"sans-serif","text-anchor":"middle"}," * ",8,Be)),e.createElementVNode("rect",{x:o.x+100,y:o.y+45,width:"128",height:"10",rx:"5",class:"ob-flow-preview__line"},null,8,xe)],64))),128))],8,ye)):e.createCommentVNode("",!0)]))}});exports.FlowPreview=_e;exports.FlowViewer=we;
@@ -0,0 +1 @@
1
+ .vue-flow{position:relative;width:100%;height:100%;overflow:hidden;z-index:0;direction:ltr}.vue-flow__container{position:absolute;height:100%;width:100%;left:0;top:0}.vue-flow__pane{z-index:1}.vue-flow__pane.draggable{cursor:grab}.vue-flow__pane.selection{cursor:pointer}.vue-flow__pane.dragging{cursor:grabbing}.vue-flow__transformationpane{transform-origin:0 0;z-index:2;pointer-events:none}.vue-flow__viewport{z-index:4;overflow:clip}.vue-flow__selection{z-index:6}.vue-flow__edge-labels{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.vue-flow__nodesselection-rect:focus,.vue-flow__nodesselection-rect:focus-visible{outline:none}.vue-flow .vue-flow__edges{pointer-events:none;overflow:visible}.vue-flow__edge-path,.vue-flow__connection-path{stroke:#b1b1b7;stroke-width:1;fill:none}.vue-flow__edge{pointer-events:visibleStroke;cursor:pointer}.vue-flow__edge.animated path{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.vue-flow__edge.animated path.vue-flow__edge-interaction{stroke-dasharray:none;animation:none}.vue-flow__edge.inactive{pointer-events:none}.vue-flow__edge.selected,.vue-flow__edge:focus,.vue-flow__edge:focus-visible{outline:none}.vue-flow__edge.selected .vue-flow__edge-path,.vue-flow__edge:focus .vue-flow__edge-path,.vue-flow__edge:focus-visible .vue-flow__edge-path{stroke:#555}.vue-flow__edge-textwrapper{pointer-events:all}.vue-flow__edge-textbg{fill:#fff}.vue-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.vue-flow__connection{pointer-events:none}.vue-flow__connection .animated{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.vue-flow__connectionline{z-index:1001}.vue-flow__nodes{pointer-events:none;transform-origin:0 0}.vue-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:default}.vue-flow__node.draggable{cursor:grab;pointer-events:all}.vue-flow__node.draggable.dragging{cursor:grabbing}.vue-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.vue-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:grab}.vue-flow__nodesselection-rect.dragging{cursor:grabbing}.vue-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px}.vue-flow__handle.connectable{pointer-events:all;cursor:crosshair}.vue-flow__handle-bottom{left:50%;bottom:0;transform:translate(-50%,50%)}.vue-flow__handle-top{left:50%;top:0;transform:translate(-50%,-50%)}.vue-flow__handle-left{top:50%;left:0;transform:translate(-50%,-50%)}.vue-flow__handle-right{top:50%;right:0;transform:translate(50%,-50%)}.vue-flow__edgeupdater{cursor:move;pointer-events:all}.vue-flow__panel{position:absolute;z-index:5;margin:15px}.vue-flow__panel.top{top:0}.vue-flow__panel.bottom{bottom:0}.vue-flow__panel.left{left:0}.vue-flow__panel.right{right:0}.vue-flow__panel.center{left:50%;transform:translate(-50%)}@keyframes dashdraw{0%{stroke-dashoffset:10}}.vue-flow__controls{box-shadow:0 0 2px 1px #00000014}.vue-flow__controls-button{background:#fefefe;border:none;border-bottom:1px solid #eee;box-sizing:content-box;display:flex;justify-content:center;align-items:center;width:16px;height:16px;cursor:pointer;-webkit-user-select:none;user-select:none;padding:5px}.vue-flow__controls-button svg{width:100%;max-width:12px;max-height:12px}.vue-flow__controls-button:hover{background:#f4f4f4}.vue-flow__controls-button:disabled{pointer-events:none}.vue-flow__controls-button:disabled svg{fill-opacity:.4}.vue-flow__minimap{background-color:#fff}.vue-flow__minimap.pannable{cursor:grab}.vue-flow__minimap.dragging{cursor:grabbing}.vue-flow__minimap-mask.pannable{cursor:grab}.ob-flow-viewer{--ob-flow-viewer-background: #f8fafc;--ob-flow-viewer-surface: #ffffff;--ob-flow-viewer-surface-muted: #f1f5f9;--ob-flow-viewer-border: #dbe2ea;--ob-flow-viewer-text: #172033;--ob-flow-viewer-text-muted: #64748b;--ob-flow-viewer-edge: #94a3b8}.ob-flow-viewer{position:relative;width:100%;height:100%;min-height:320px;overflow:hidden;color:var(--ob-flow-viewer-text);font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;background:var(--ob-flow-viewer-background)}.ob-flow-viewer[data-theme=dark]{--ob-flow-viewer-background: #0f172a;--ob-flow-viewer-surface: #172033;--ob-flow-viewer-surface-muted: #263247;--ob-flow-viewer-border: #344258;--ob-flow-viewer-text: #e5e7eb;--ob-flow-viewer-text-muted: #9aa8bc;--ob-flow-viewer-edge: #64748b}.ob-flow-viewer__canvas{width:100%;height:100%;background-color:var(--ob-flow-viewer-background);background-image:radial-gradient(circle,#dce4ee 1px,transparent 1px);background-position:0 0;background-size:15px 15px}.ob-flow-viewer .vue-flow__edge-path{stroke:var(--ob-flow-viewer-edge);stroke-width:1.5}.ob-flow-viewer .vue-flow__node{cursor:default;pointer-events:auto!important}.ob-flow-viewer-node .vue-flow__handle{width:8px;height:8px;pointer-events:none;background:var(--ob-flow-viewer-surface);border:2px solid var(--ob-flow-viewer-edge);border-radius:50%}.ob-flow-viewer .vue-flow__controls,.ob-flow-viewer .vue-flow__minimap{overflow:hidden;border:1px solid var(--ob-flow-viewer-border);border-radius:6px;box-shadow:0 4px 12px #0f172a14}.ob-flow-viewer .vue-flow__controls-button{color:var(--ob-flow-viewer-text);background:var(--ob-flow-viewer-surface);border-color:var(--ob-flow-viewer-border)}.ob-flow-viewer .vue-flow__controls-button svg{max-width:10px;max-height:10px}.ob-flow-viewer .vue-flow__minimap{right:auto;bottom:10px;left:54px;width:160px;height:110px;background:color-mix(in srgb,var(--ob-flow-viewer-surface) 92%,transparent)}.ob-flow-viewer .vue-flow__minimap-node{fill:var(--ob-flow-viewer-edge)}.ob-flow-viewer-node{position:relative;box-sizing:border-box;width:260px;padding:14px;background:var(--ob-flow-viewer-surface);border:1px solid var(--ob-flow-viewer-border);border-radius:12px;box-shadow:0 2px 8px #0f172a14;outline:none;transition:border-color .16s ease,box-shadow .16s ease}.ob-flow-viewer-node:hover,.ob-flow-viewer-node:focus-visible{z-index:5;border-color:var(--ob-flow-viewer-edge);box-shadow:0 6px 16px #0f172a1c}.ob-flow-viewer-node--unavailable{border-style:dashed;opacity:.78}.ob-flow-viewer-node__header{display:flex;gap:9px;align-items:center;min-width:0}.ob-flow-viewer-node__icon{display:grid;flex:0 0 32px;width:32px;height:32px;place-items:center;overflow:hidden;color:#fff;font-size:14px;font-weight:700;background:var(--ob-node-icon-color);border-radius:8px}.ob-flow-viewer-node__icon-svg,.ob-flow-viewer-node__icon-svg svg{display:block;width:17px;height:17px}.ob-flow-viewer-node__icon-svg svg{color:#fff}.ob-flow-viewer-node__title-wrap{display:flex;min-width:0;flex-direction:column;gap:2px}.ob-flow-viewer-node__title,.ob-flow-viewer-node__key{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ob-flow-viewer-node__title{font-size:14px;font-weight:650;line-height:1.3}.ob-flow-viewer-node__key{color:var(--ob-flow-viewer-text-muted);font-size:10.5px;line-height:1.3}.ob-flow-viewer-node__description{margin:10px 0 0;color:var(--ob-flow-viewer-text-muted);font-size:13px;line-height:1.5;white-space:normal}.ob-flow-viewer-node__description--clamped{display:-webkit-box;overflow:hidden;-webkit-box-orient:vertical;-webkit-line-clamp:2}.ob-flow-viewer-node__widget{display:flex;align-items:center;height:32px;padding:7px;margin-top:10px;background:var(--ob-flow-viewer-surface-muted);border-radius:7px}.ob-flow-viewer-node__widget--button{gap:7px;width:112px}.ob-flow-viewer-node__widget-icon{display:grid;width:18px;height:18px;place-items:center;color:var(--ob-flow-viewer-text-muted);font-size:11px;background:color-mix(in srgb,var(--ob-flow-viewer-text-muted) 12%,transparent);border-radius:5px}.ob-flow-viewer-node__widget-label{width:62px;height:7px;background:color-mix(in srgb,var(--ob-flow-viewer-text-muted) 18%,transparent);border-radius:999px}.ob-flow-viewer-node__widget--dataset{justify-content:center;height:72px}.ob-flow-viewer-node__widget-image{position:relative;width:30px;height:23px;border:2px solid color-mix(in srgb,var(--ob-flow-viewer-text-muted) 40%,transparent);border-radius:5px}.ob-flow-viewer-node__widget-image:before{position:absolute;top:4px;left:5px;width:4px;height:4px;background:color-mix(in srgb,var(--ob-flow-viewer-text-muted) 42%,transparent);border-radius:50%;content:""}.ob-flow-viewer-node__widget-image:after{position:absolute;right:4px;bottom:4px;left:4px;height:8px;background:color-mix(in srgb,var(--ob-flow-viewer-text-muted) 24%,transparent);clip-path:polygon(0 100%,35% 28%,52% 64%,72% 8%,100% 100%);content:""}.ob-flow-viewer-node__widget--lines{flex-direction:column;align-items:flex-start;justify-content:center;gap:5px}.ob-flow-viewer-node__widget--lines span{width:82%;height:6px;background:color-mix(in srgb,var(--ob-flow-viewer-text-muted) 18%,transparent);border-radius:999px}.ob-flow-viewer-node__widget--lines span:last-child{width:58%}.ob-flow-viewer-tooltip{--ob-flow-viewer-surface: #ffffff;--ob-flow-viewer-border: #dbe2ea;--ob-flow-viewer-text: #172033;--ob-flow-viewer-text-muted: #64748b;--ob-flow-viewer-surface-muted: hsl(220 16% 98%);position:fixed;z-index:100;box-sizing:border-box;width:min(404px,calc(100% - 24px));max-height:min(520px,calc(100vh - 24px));padding:0;overflow:auto;pointer-events:auto;background:var(--ob-flow-viewer-surface);border:1px solid var(--ob-flow-viewer-border);border-radius:14px;box-shadow:0 14px 36px #0f172a29;transform:translate(-50%);scrollbar-color:color-mix(in srgb,var(--ob-flow-viewer-text-muted) 34%,transparent) transparent;scrollbar-width:thin}.ob-flow-viewer-tooltip::-webkit-scrollbar{width:9px}.ob-flow-viewer-tooltip::-webkit-scrollbar-track,.ob-flow-viewer-tooltip::-webkit-scrollbar-corner{background:transparent}.ob-flow-viewer-tooltip::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--ob-flow-viewer-text-muted) 34%,transparent);background-clip:padding-box;border:3px solid transparent;border-radius:999px}.ob-flow-preview{position:absolute;top:0;right:0;bottom:0;left:0;overflow:hidden;padding:6px 6px 0}.ob-flow-preview__svg{width:100%;height:100%}.ob-flow-preview__edge{fill:none;stroke:currentColor;stroke-width:1;stroke-linecap:round;stroke-opacity:.15}.ob-flow-preview__node{fill:#fff;stroke:var(--ob-flow-viewer-border, #dbe2ea);stroke-width:1}.ob-flow-preview__icon-background{fill:#eef1f5}.ob-flow-preview__line{fill:var(--ob-flow-viewer-border, #dbe2ea)}[data-theme=dark] .ob-flow-preview__node,.dark .ob-flow-preview__node{fill:#263247}.ob-flow-viewer-tooltip[data-theme=dark]{--ob-flow-viewer-surface: #172033;--ob-flow-viewer-border: #344258;--ob-flow-viewer-text: #e5e7eb;--ob-flow-viewer-text-muted: #9aa8bc;--ob-flow-viewer-surface-muted: #263247}.ob-flow-viewer-tooltip__header{display:flex;gap:10px;align-items:center;min-width:0;padding:14px 16px;border-bottom:1px solid var(--ob-flow-viewer-border)}.ob-flow-viewer-tooltip__body{background:var(--ob-flow-viewer-surface-muted)}.ob-flow-viewer-tooltip__icon{display:grid;flex:0 0 34px;width:34px;height:34px;place-items:center;overflow:hidden;color:#fff;font-size:14px;font-weight:700;background:var(--ob-node-icon-color);border-radius:9px}.ob-flow-viewer-tooltip__title-wrap{display:flex;min-width:0;flex-direction:column;gap:1px}.ob-flow-viewer-tooltip__title-wrap strong{overflow:hidden;font-size:13px;line-height:1.35;text-overflow:ellipsis;white-space:nowrap}.ob-flow-viewer-tooltip__title-wrap code{color:var(--ob-flow-viewer-text-muted);font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:10px;line-height:1.35}.ob-flow-viewer-tooltip__unavailable{margin:0;padding:14px 16px;color:var(--ob-flow-viewer-text-muted);font-size:11px;line-height:1.5}.ob-flow-viewer-tooltip__description{margin:0;padding:14px 16px 0;color:var(--ob-flow-viewer-text-muted);font-size:11px;line-height:1.55}.ob-flow-viewer-node__ports{display:flex;flex-direction:column;gap:14px;padding:14px 16px 16px}.ob-flow-viewer-node__port-group{display:flex;min-width:0;flex-direction:column;gap:9px}.ob-flow-viewer-node__port-group--outputs{padding-top:14px;border-top:1px solid var(--ob-flow-viewer-border)}.ob-flow-viewer-node__port-heading{color:var(--ob-flow-viewer-text);font-size:10px;font-weight:700;letter-spacing:.04em;text-transform:uppercase}.ob-flow-viewer-node__port{display:grid;grid-template-columns:minmax(116px,.8fr) minmax(0,1.2fr);column-gap:14px;min-width:0;color:var(--ob-flow-viewer-text-muted);font-size:11px}.ob-flow-viewer-node__port>span{grid-row:1;grid-column:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ob-flow-viewer-node__port small{display:-webkit-box;grid-row:1 / span 2;grid-column:2;margin:0;overflow:hidden;color:color-mix(in srgb,var(--ob-flow-viewer-text-muted) 82%,transparent);font-size:10px;line-height:1.45;white-space:normal;-webkit-box-orient:vertical;-webkit-line-clamp:3}.ob-flow-viewer-node__empty{color:var(--ob-flow-viewer-text-muted);font-size:10px;font-style:italic}.ob-flow-viewer-note{box-sizing:border-box;min-width:140px;padding:14px;color:#334155;font-size:12px;line-height:1.5;white-space:pre-wrap;border:1px solid #e2c56d;border-radius:4px 4px 12px;box-shadow:0 5px 16px #0f172a1a}.ob-flow-viewer-note--yellow{background:#fef3c7;border-color:#f5d56c}.ob-flow-viewer-note--blue{background:#dbeafe;border-color:#93c5fd}.ob-flow-viewer-note--green{background:#dcfce7;border-color:#86efac}.ob-flow-viewer-note--rose{background:#ffe4e6;border-color:#fda4af}.ob-flow-viewer-note--violet{background:#ede9fe;border-color:#c4b5fd}.ob-flow-viewer-note--slate{background:#e2e8f0;border-color:#94a3b8}@media (prefers-reduced-motion: reduce){.ob-flow-viewer-node{transition:none}}
@@ -0,0 +1,531 @@
1
+ import { defineComponent as A, inject as J, createElementBlock as i, openBlock as n, unref as f, normalizeClass as Z, createElementVNode as w, createCommentVNode as y, createBlock as H, normalizeStyle as S, toDisplayString as k, Fragment as P, computed as T, markRaw as Y, ref as Q, onBeforeUnmount as ee, provide as te, createVNode as oe, withCtx as ne, Teleport as ie, renderList as F, resolveDynamicComponent as ae } from "vue";
2
+ import { Handle as V, Position as C, ConnectionLineType as se, VueFlow as le } from "@vue-flow/core";
3
+ import { Controls as re } from "@vue-flow/controls";
4
+ import { MiniMap as de } from "@vue-flow/minimap";
5
+ const G = Symbol("flow-viewer-details"), ce = ["aria-label"], ue = { class: "ob-flow-viewer-node__header" }, we = ["innerHTML"], pe = { key: 1 }, he = { class: "ob-flow-viewer-node__title-wrap" }, me = { class: "ob-flow-viewer-node__title" }, fe = { class: "ob-flow-viewer-node__key" }, ve = { class: "ob-flow-viewer-node__description ob-flow-viewer-node__description--clamped" }, ye = {
6
+ key: 1,
7
+ class: "ob-flow-viewer-node__widget-image",
8
+ "aria-hidden": "true"
9
+ }, ge = /* @__PURE__ */ A({
10
+ __name: "FlowViewerNode",
11
+ props: {
12
+ id: {},
13
+ type: {},
14
+ selected: { type: Boolean },
15
+ connectable: { type: [Boolean, Number, String, Function] },
16
+ position: {},
17
+ dimensions: {},
18
+ label: {},
19
+ isValidTargetPos: { type: Function },
20
+ isValidSourcePos: { type: Function },
21
+ parent: {},
22
+ parentNodeId: {},
23
+ dragging: { type: Boolean },
24
+ resizing: { type: Boolean },
25
+ zIndex: {},
26
+ targetPosition: {},
27
+ sourcePosition: {},
28
+ dragHandle: {},
29
+ data: {},
30
+ events: {}
31
+ },
32
+ setup(o) {
33
+ const u = o, _ = J(G), N = u.data.available ? u.data.description : "This node template is unavailable.";
34
+ return (c, d) => {
35
+ var h, g;
36
+ return n(), i("article", {
37
+ class: Z(["ob-flow-viewer-node", { "ob-flow-viewer-node--unavailable": !o.data.available }]),
38
+ tabindex: "0",
39
+ "aria-label": `${o.data.name} node`,
40
+ onMouseenter: d[0] || (d[0] = (t) => {
41
+ var a;
42
+ return (a = f(_)) == null ? void 0 : a.show(o.data, t);
43
+ }),
44
+ onMouseleave: d[1] || (d[1] = (t) => {
45
+ var a;
46
+ return (a = f(_)) == null ? void 0 : a.hide();
47
+ }),
48
+ onClick: d[2] || (d[2] = (t) => {
49
+ var a;
50
+ return (a = f(_)) == null ? void 0 : a.show(o.data, t);
51
+ }),
52
+ onFocus: d[3] || (d[3] = (t) => {
53
+ var a;
54
+ return (a = f(_)) == null ? void 0 : a.show(o.data, t);
55
+ }),
56
+ onBlur: d[4] || (d[4] = (t) => {
57
+ var a;
58
+ return (a = f(_)) == null ? void 0 : a.hide();
59
+ })
60
+ }, [
61
+ w("header", ue, [
62
+ w("span", {
63
+ class: "ob-flow-viewer-node__icon",
64
+ style: S({ "--ob-node-icon-color": ((h = o.data.icon) == null ? void 0 : h.color) ?? "#64748b" }),
65
+ "aria-hidden": "true"
66
+ }, [
67
+ (g = o.data.icon) != null && g.svg ? (n(), i("span", {
68
+ key: 0,
69
+ class: "ob-flow-viewer-node__icon-svg",
70
+ innerHTML: o.data.icon.svg
71
+ }, null, 8, we)) : (n(), i("span", pe, k(o.data.available ? o.data.name.slice(0, 1).toUpperCase() : "?"), 1))
72
+ ], 4),
73
+ w("span", he, [
74
+ w("strong", me, k(o.data.name), 1),
75
+ w("span", fe, k(o.data.key), 1)
76
+ ])
77
+ ]),
78
+ w("p", ve, k(f(N)), 1),
79
+ o.data.widgetPreview && o.data.available ? (n(), i("div", {
80
+ key: 0,
81
+ class: Z(["ob-flow-viewer-node__widget", `ob-flow-viewer-node__widget--${o.data.widgetPreview}`]),
82
+ "aria-label": "Widget preview"
83
+ }, [
84
+ o.data.widgetPreview === "button" ? (n(), i(P, { key: 0 }, [
85
+ d[5] || (d[5] = w("span", { class: "ob-flow-viewer-node__widget-icon" }, "↗", -1)),
86
+ d[6] || (d[6] = w("span", { class: "ob-flow-viewer-node__widget-label" }, null, -1))
87
+ ], 64)) : o.data.widgetPreview === "dataset" ? (n(), i("span", ye)) : (n(), i(P, { key: 2 }, [
88
+ d[7] || (d[7] = w("span", null, null, -1)),
89
+ d[8] || (d[8] = w("span", null, null, -1))
90
+ ], 64))
91
+ ], 2)) : y("", !0),
92
+ o.data.connectedHandles.has("target") ? (n(), H(f(V), {
93
+ key: 1,
94
+ type: "target",
95
+ position: f(C).Top
96
+ }, null, 8, ["position"])) : y("", !0),
97
+ o.data.connectedHandles.has("left") ? (n(), H(f(V), {
98
+ key: 2,
99
+ id: "left",
100
+ type: "target",
101
+ position: f(C).Left
102
+ }, null, 8, ["position"])) : y("", !0),
103
+ o.data.connectedHandles.has("right") ? (n(), H(f(V), {
104
+ key: 3,
105
+ id: "right",
106
+ type: "target",
107
+ position: f(C).Right
108
+ }, null, 8, ["position"])) : y("", !0),
109
+ o.data.connectedHandles.has("source") ? (n(), H(f(V), {
110
+ key: 4,
111
+ type: "source",
112
+ position: f(C).Bottom
113
+ }, null, 8, ["position"])) : y("", !0),
114
+ o.data.connectedHandles.has("left-source") ? (n(), H(f(V), {
115
+ key: 5,
116
+ id: "left-source",
117
+ type: "source",
118
+ position: f(C).Left
119
+ }, null, 8, ["position"])) : y("", !0),
120
+ o.data.connectedHandles.has("right-source") ? (n(), H(f(V), {
121
+ key: 6,
122
+ id: "right-source",
123
+ type: "source",
124
+ position: f(C).Right
125
+ }, null, 8, ["position"])) : y("", !0)
126
+ ], 42, ce);
127
+ };
128
+ }
129
+ }), xe = /* @__PURE__ */ A({
130
+ __name: "FlowViewerNote",
131
+ props: {
132
+ id: {},
133
+ type: {},
134
+ selected: { type: Boolean },
135
+ connectable: { type: [Boolean, Number, String, Function] },
136
+ position: {},
137
+ dimensions: {},
138
+ label: {},
139
+ isValidTargetPos: { type: Function },
140
+ isValidSourcePos: { type: Function },
141
+ parent: {},
142
+ parentNodeId: {},
143
+ dragging: { type: Boolean },
144
+ resizing: { type: Boolean },
145
+ zIndex: {},
146
+ targetPosition: {},
147
+ sourcePosition: {},
148
+ dragHandle: {},
149
+ data: {},
150
+ events: {}
151
+ },
152
+ setup(o) {
153
+ const u = o, _ = T(() => ({
154
+ width: `${u.data.appearance.width}px`,
155
+ minHeight: u.data.appearance.height ? `${u.data.appearance.height}px` : void 0
156
+ }));
157
+ return (N, c) => (n(), i("article", {
158
+ class: Z(["ob-flow-viewer-note", `ob-flow-viewer-note--${o.data.appearance.color}`]),
159
+ style: S(_.value)
160
+ }, k(o.data.content), 7));
161
+ }
162
+ }), be = ["data-theme"], _e = ["data-theme"], ke = { class: "ob-flow-viewer-tooltip__header" }, Me = ["innerHTML"], $e = { key: 1 }, He = { class: "ob-flow-viewer-tooltip__title-wrap" }, Ne = { class: "ob-flow-viewer-tooltip__body" }, Pe = {
163
+ key: 0,
164
+ class: "ob-flow-viewer-tooltip__unavailable"
165
+ }, Te = {
166
+ key: 1,
167
+ class: "ob-flow-viewer-tooltip__description"
168
+ }, Ie = {
169
+ key: 2,
170
+ class: "ob-flow-viewer-node__ports"
171
+ }, Be = { class: "ob-flow-viewer-node__port-group" }, ze = {
172
+ key: 0,
173
+ class: "ob-flow-viewer-node__empty"
174
+ }, Ve = { key: 0 }, Ce = { class: "ob-flow-viewer-node__port-group ob-flow-viewer-node__port-group--outputs" }, Fe = {
175
+ key: 0,
176
+ class: "ob-flow-viewer-node__empty"
177
+ }, Se = { key: 0 }, W = 72, U = 64, Le = 1.45, Je = /* @__PURE__ */ A({
178
+ __name: "FlowViewer",
179
+ props: {
180
+ document: {},
181
+ fitViewOnInit: { type: Boolean, default: !1 },
182
+ showControls: { type: Boolean, default: !0 },
183
+ showMiniMap: { type: Boolean, default: !0 },
184
+ minZoom: { default: 0.1 },
185
+ maxZoom: { default: 2 },
186
+ initialZoom: { default: 0.8 },
187
+ theme: { default: "light" }
188
+ },
189
+ setup(o) {
190
+ const u = o, _ = {
191
+ catalog: Y(ge),
192
+ note: Y(xe)
193
+ };
194
+ function N(e) {
195
+ if (e.kind === "note") return e.appearance.height ?? 130;
196
+ const s = e.description ? Math.min(2, Math.max(1, Math.ceil(e.description.length / 34))) : e.available ? 0 : 1, p = s > 0 ? 10 + s * 19.5 : 0, b = e.available && e.widgetPreview ? 10 + (e.widgetPreview === "dataset" ? 72 : 32) : 0;
197
+ return 60 + p + b;
198
+ }
199
+ const c = Q(null);
200
+ let d = null;
201
+ function h() {
202
+ d !== null && (clearTimeout(d), d = null);
203
+ }
204
+ function g() {
205
+ h(), d = setTimeout(() => {
206
+ c.value = null, d = null;
207
+ }, 140);
208
+ }
209
+ ee(h);
210
+ function t(e) {
211
+ const s = /* @__PURE__ */ new Set();
212
+ for (const p of u.document.edges)
213
+ p.source === e && s.add(p.sourceHandle ?? "source"), p.target === e && s.add(p.targetHandle ?? "target");
214
+ return s;
215
+ }
216
+ function a(e, s) {
217
+ h();
218
+ const p = s.currentTarget;
219
+ if (!(p instanceof HTMLElement)) return;
220
+ const b = p.getBoundingClientRect(), l = 12, r = Math.min(404, window.innerWidth - l * 2), x = Math.min(520, window.innerHeight - l * 2);
221
+ let v = b.right + l + r / 2;
222
+ v + r / 2 > window.innerWidth - l && (v = b.left - l - r / 2), v = Math.max(r / 2 + l, Math.min(v, window.innerWidth - r / 2 - l)), c.value = {
223
+ node: e,
224
+ x: v,
225
+ y: Math.max(l, Math.min(b.top, window.innerHeight - x - l))
226
+ };
227
+ }
228
+ function m() {
229
+ g();
230
+ }
231
+ te(G, { show: a, hide: m });
232
+ const M = T(() => {
233
+ const e = new Map(u.document.nodes.map((r) => [r.id, { ...r.position }])), s = Math.min(...u.document.nodes.map((r) => r.position.x)), p = Math.max(...u.document.nodes.map((r) => r.position.x)), b = (s + p) / 2;
234
+ for (const r of e.values())
235
+ r.x = b + (r.x - b) * Le;
236
+ for (let r = 0; r < u.document.nodes.length; r += 1)
237
+ for (const x of u.document.edges) {
238
+ if (x.sourceHandle || x.targetHandle) continue;
239
+ const v = e.get(x.source), $ = e.get(x.target);
240
+ if (!(!v || !$ || Math.abs(v.x - $.x) >= 40) && ($.x = v.x, $.y > v.y)) {
241
+ const z = u.document.nodes.find((R) => R.id === x.source);
242
+ z && ($.y = Math.max(
243
+ $.y,
244
+ v.y + N(z) + W
245
+ ));
246
+ }
247
+ }
248
+ const l = [...u.document.nodes].sort(
249
+ (r, x) => r.position.y - x.position.y || r.position.x - x.position.x
250
+ );
251
+ for (const [r, x] of l.entries()) {
252
+ const v = e.get(x.id);
253
+ if (v)
254
+ for (const $ of l.slice(0, r)) {
255
+ const z = e.get($.id);
256
+ if (!z) continue;
257
+ const R = x.kind === "note" ? x.appearance.width : 260, q = $.kind === "note" ? $.appearance.width : 260;
258
+ v.x >= z.x + q + U || z.x >= v.x + R + U || (v.y = Math.max(
259
+ v.y,
260
+ z.y + N($) + W
261
+ ));
262
+ }
263
+ }
264
+ return e;
265
+ }), I = T(() => u.document.nodes.map((e) => {
266
+ const s = M.value.get(e.id) ?? e.position;
267
+ return e.kind === "note" ? {
268
+ id: e.id,
269
+ type: "note",
270
+ position: s,
271
+ data: e,
272
+ style: {
273
+ width: `${e.appearance.width}px`,
274
+ height: e.appearance.height ? `${e.appearance.height}px` : void 0
275
+ }
276
+ } : {
277
+ id: e.id,
278
+ type: "catalog",
279
+ position: s,
280
+ data: {
281
+ ...e,
282
+ connectedHandles: t(e.id)
283
+ },
284
+ selectable: !1
285
+ };
286
+ })), B = T(() => u.document.edges.map((e, s) => ({
287
+ id: `viewer-edge-${s}-${e.source}-${e.target}`,
288
+ source: e.source,
289
+ target: e.target,
290
+ sourceHandle: e.sourceHandle,
291
+ targetHandle: e.targetHandle,
292
+ type: se.SmoothStep,
293
+ data: e.data,
294
+ style: e.isVisual ? { strokeDasharray: "6 4" } : void 0,
295
+ selectable: !1
296
+ }))), j = T(() => {
297
+ if (u.document.nodes.length === 0) return { minX: 0, minY: 0, maxX: 0, maxY: 0 };
298
+ let e = 1 / 0, s = 1 / 0, p = -1 / 0, b = -1 / 0;
299
+ for (const l of u.document.nodes) {
300
+ const r = M.value.get(l.id) ?? l.position, x = l.kind === "note" ? l.appearance.width : 260, v = N(l);
301
+ e = Math.min(e, r.x), s = Math.min(s, r.y), p = Math.max(p, r.x + x), b = Math.max(b, r.y + v);
302
+ }
303
+ return { minX: e, minY: s, maxX: p, maxY: b };
304
+ });
305
+ function K(e) {
306
+ if (u.fitViewOnInit) {
307
+ e.fitView({ padding: 0.15, maxZoom: 1 });
308
+ return;
309
+ }
310
+ const s = j.value, p = u.initialZoom;
311
+ e.setViewport({
312
+ x: e.dimensions.value.width / 2 - (s.minX + s.maxX) / 2 * p,
313
+ y: 24 - s.minY * p,
314
+ zoom: p
315
+ });
316
+ }
317
+ return (e, s) => {
318
+ var p, b;
319
+ return n(), i("div", {
320
+ class: "ob-flow-viewer",
321
+ "data-theme": o.theme
322
+ }, [
323
+ oe(f(le), {
324
+ nodes: I.value,
325
+ edges: B.value,
326
+ "node-types": _,
327
+ "fit-view-on-init": !1,
328
+ "min-zoom": o.minZoom,
329
+ "max-zoom": o.maxZoom,
330
+ "nodes-draggable": !1,
331
+ "nodes-connectable": !1,
332
+ "elements-selectable": !0,
333
+ "select-nodes-on-drag": !1,
334
+ "connect-on-click": !1,
335
+ "zoom-on-double-click": !1,
336
+ "delete-key-code": [],
337
+ "multi-selection-key-code": [],
338
+ "pan-on-drag": !0,
339
+ "pan-on-scroll": !0,
340
+ "zoom-on-scroll": !1,
341
+ "zoom-on-pinch": !0,
342
+ class: "ob-flow-viewer__canvas",
343
+ onPaneReady: K
344
+ }, {
345
+ default: ne(() => [
346
+ o.showControls ? (n(), H(f(re), {
347
+ key: 0,
348
+ "show-interactive": !1
349
+ })) : y("", !0),
350
+ o.showMiniMap ? (n(), H(f(de), {
351
+ key: 1,
352
+ pannable: !0,
353
+ zoomable: !0
354
+ })) : y("", !0)
355
+ ]),
356
+ _: 1
357
+ }, 8, ["nodes", "edges", "min-zoom", "max-zoom"]),
358
+ (n(), H(ie, { to: "body" }, [
359
+ c.value ? (n(), i("section", {
360
+ key: 0,
361
+ class: "ob-flow-viewer-tooltip",
362
+ "data-theme": o.theme,
363
+ style: S({ left: `${c.value.x}px`, top: `${c.value.y}px` }),
364
+ role: "tooltip",
365
+ tabindex: "0",
366
+ onMouseenter: h,
367
+ onMouseleave: m,
368
+ onFocusin: h,
369
+ onFocusout: m
370
+ }, [
371
+ w("header", ke, [
372
+ w("span", {
373
+ class: "ob-flow-viewer-tooltip__icon",
374
+ style: S({ "--ob-node-icon-color": ((p = c.value.node.icon) == null ? void 0 : p.color) ?? "#64748b" }),
375
+ "aria-hidden": "true"
376
+ }, [
377
+ (b = c.value.node.icon) != null && b.svg ? (n(), i("span", {
378
+ key: 0,
379
+ class: "ob-flow-viewer-node__icon-svg",
380
+ innerHTML: c.value.node.icon.svg
381
+ }, null, 8, Me)) : (n(), i("span", $e, k(c.value.node.available ? c.value.node.name.slice(0, 1).toUpperCase() : "?"), 1))
382
+ ], 4),
383
+ w("span", He, [
384
+ w("strong", null, k(c.value.node.name), 1),
385
+ w("code", null, k(c.value.node.key), 1)
386
+ ])
387
+ ]),
388
+ w("div", Ne, [
389
+ c.value.node.available ? c.value.node.description ? (n(), i("p", Te, k(c.value.node.description), 1)) : y("", !0) : (n(), i("p", Pe, " This node template is unavailable. ")),
390
+ c.value.node.available ? (n(), i("div", Ie, [
391
+ w("div", Be, [
392
+ s[0] || (s[0] = w("span", { class: "ob-flow-viewer-node__port-heading" }, "Inputs", -1)),
393
+ c.value.node.inputs.length === 0 ? (n(), i("span", ze, "None")) : y("", !0),
394
+ (n(!0), i(P, null, F(c.value.node.inputs, (l) => (n(), i("span", {
395
+ key: l.key,
396
+ class: "ob-flow-viewer-node__port"
397
+ }, [
398
+ w("span", null, k(l.name), 1),
399
+ l.description ? (n(), i("small", Ve, k(l.description), 1)) : y("", !0)
400
+ ]))), 128))
401
+ ]),
402
+ w("div", Ce, [
403
+ s[1] || (s[1] = w("span", { class: "ob-flow-viewer-node__port-heading" }, "Outputs", -1)),
404
+ c.value.node.outputs.length === 0 ? (n(), i("span", Fe, "None")) : y("", !0),
405
+ (n(!0), i(P, null, F(c.value.node.outputs, (l) => (n(), i("span", {
406
+ key: l.key,
407
+ class: "ob-flow-viewer-node__port"
408
+ }, [
409
+ w("span", null, k(l.name), 1),
410
+ l.description ? (n(), i("small", Se, k(l.description), 1)) : y("", !0)
411
+ ]))), 128))
412
+ ])
413
+ ])) : y("", !0)
414
+ ])
415
+ ], 44, _e)) : y("", !0)
416
+ ]))
417
+ ], 8, be);
418
+ };
419
+ }
420
+ }), Oe = { class: "ob-flow-preview" }, De = ["viewBox"], Ee = ["d"], Ae = ["x", "y"], Re = ["x", "y"], Xe = ["href", "x", "y"], Ze = ["x", "y"], Ye = ["x", "y"], L = 260, O = 100, D = 140, We = 140, X = 48, E = 26, Qe = /* @__PURE__ */ A({
421
+ __name: "FlowPreview",
422
+ props: {
423
+ preview: {},
424
+ icons: { default: () => ({}) },
425
+ iconUrl: { type: Function, default: void 0 }
426
+ },
427
+ setup(o) {
428
+ const u = o, _ = T(() => {
429
+ var t, a;
430
+ const h = ((t = u.preview) == null ? void 0 : t.n) ?? [], g = new Map(h.map((m) => [m.id, { x: m.x, y: m.y }]));
431
+ for (let m = 0; m < h.length; m += 1)
432
+ for (const M of ((a = u.preview) == null ? void 0 : a.e) ?? []) {
433
+ const I = g.get(M.s), B = g.get(M.t);
434
+ I && B && Math.abs(I.x - B.x) < We && (B.x = I.x);
435
+ }
436
+ return h.map((m) => ({
437
+ ...m,
438
+ ...g.get(m.id) ?? { x: m.x, y: m.y }
439
+ }));
440
+ }), N = T(() => {
441
+ const h = _.value;
442
+ if (h.length === 0) return "0 0 1 1";
443
+ let g = 1 / 0, t = 1 / 0, a = -1 / 0, m = -1 / 0;
444
+ for (const M of h)
445
+ g = Math.min(g, M.x), t = Math.min(t, M.y), a = Math.max(a, M.x + L), m = Math.max(m, M.y + O);
446
+ return `${g - D} ${t - D} ${a - g + D * 2} ${m - t + D * 2}`;
447
+ }), c = T(
448
+ () => new Map(_.value.map((h) => [h.id, h]))
449
+ );
450
+ function d(h, g) {
451
+ const t = c.value.get(h), a = c.value.get(g);
452
+ if (!t || !a) return "";
453
+ const m = t.x + L / 2, M = t.y + O / 2, I = a.x + L / 2, B = a.y + O / 2;
454
+ return `M ${m} ${M} L ${I} ${B}`;
455
+ }
456
+ return (h, g) => (n(), i("div", Oe, [
457
+ o.preview && o.preview.n.length > 0 ? (n(), i("svg", {
458
+ key: 0,
459
+ class: "ob-flow-preview__svg",
460
+ viewBox: N.value,
461
+ preserveAspectRatio: "xMidYMid meet"
462
+ }, [
463
+ (n(!0), i(P, null, F(o.preview.e, (t, a) => (n(), i("path", {
464
+ key: a,
465
+ d: d(t.s, t.t),
466
+ class: "ob-flow-preview__edge",
467
+ "vector-effect": "non-scaling-stroke"
468
+ }, null, 8, Ee))), 128)),
469
+ (n(!0), i(P, null, F(_.value, (t) => (n(), i("rect", {
470
+ key: t.id,
471
+ x: t.x,
472
+ y: t.y,
473
+ width: L,
474
+ height: O,
475
+ rx: "16",
476
+ class: "ob-flow-preview__node",
477
+ "vector-effect": "non-scaling-stroke"
478
+ }, null, 8, Ae))), 128)),
479
+ (n(!0), i(P, null, F(_.value, (t) => (n(), i(P, {
480
+ key: `content-${t.id}`
481
+ }, [
482
+ w("rect", {
483
+ x: t.x + 18,
484
+ y: t.y + 18,
485
+ width: "64",
486
+ height: "64",
487
+ rx: "16",
488
+ class: "ob-flow-preview__icon-background",
489
+ style: S(t.c ? { fill: t.c } : void 0)
490
+ }, null, 12, Re),
491
+ t.i && o.icons[t.i] ? (n(), H(ae(o.icons[t.i]), {
492
+ key: 0,
493
+ x: t.x + E,
494
+ y: t.y + E,
495
+ size: X,
496
+ color: "white",
497
+ "stroke-width": 2.5,
498
+ "aria-hidden": "true"
499
+ }, null, 8, ["x", "y"])) : t.i && o.iconUrl ? (n(), i("image", {
500
+ key: 1,
501
+ href: o.iconUrl(t.i),
502
+ x: t.x + E,
503
+ y: t.y + E,
504
+ width: X,
505
+ height: X
506
+ }, null, 8, Xe)) : (n(), i("text", {
507
+ key: 2,
508
+ x: t.x + 50,
509
+ y: t.y + 68,
510
+ fill: "white",
511
+ "font-size": "42",
512
+ "font-family": "sans-serif",
513
+ "text-anchor": "middle"
514
+ }, " * ", 8, Ze)),
515
+ w("rect", {
516
+ x: t.x + 100,
517
+ y: t.y + 45,
518
+ width: "128",
519
+ height: "10",
520
+ rx: "5",
521
+ class: "ob-flow-preview__line"
522
+ }, null, 8, Ye)
523
+ ], 64))), 128))
524
+ ], 8, De)) : y("", !0)
525
+ ]));
526
+ }
527
+ });
528
+ export {
529
+ Qe as FlowPreview,
530
+ Je as FlowViewer
531
+ };
@@ -0,0 +1,3 @@
1
+ export { default as FlowViewer } from './FlowViewer.vue';
2
+ export { default as FlowPreview } from './FlowPreview.vue';
3
+ export type { FlowPreviewDocument, FlowViewerCatalogNode, FlowViewerDocument, FlowViewerEdge, FlowViewerField, FlowViewerIcon, FlowViewerNode, FlowViewerNote, FlowViewerNoteColor, FlowViewerPosition, } from './types';
@@ -0,0 +1,71 @@
1
+ export type FlowViewerPosition = {
2
+ x: number;
3
+ y: number;
4
+ };
5
+ export type FlowViewerIcon = {
6
+ color: string;
7
+ svg: string;
8
+ };
9
+ export type FlowViewerField = {
10
+ key: string;
11
+ name: string;
12
+ description?: string;
13
+ type: string;
14
+ };
15
+ export type FlowViewerCatalogNode = {
16
+ id: string;
17
+ kind: 'node';
18
+ position: FlowViewerPosition;
19
+ name: string;
20
+ key: string;
21
+ version: number;
22
+ description: string;
23
+ icon?: FlowViewerIcon;
24
+ widgetPreview: 'button' | 'dataset' | 'lines' | null;
25
+ inputs: FlowViewerField[];
26
+ outputs: FlowViewerField[];
27
+ setup?: {
28
+ requiredInputs: FlowViewerField[];
29
+ } | null;
30
+ available: boolean;
31
+ };
32
+ export type FlowPreviewDocument = {
33
+ n: Array<{
34
+ id: string;
35
+ x: number;
36
+ y: number;
37
+ w: boolean;
38
+ c?: string;
39
+ i?: string;
40
+ }>;
41
+ e: Array<{
42
+ s: string;
43
+ t: string;
44
+ }>;
45
+ };
46
+ export type FlowViewerNoteColor = 'yellow' | 'blue' | 'green' | 'rose' | 'violet' | 'slate';
47
+ export type FlowViewerNote = {
48
+ id: string;
49
+ kind: 'note';
50
+ position: FlowViewerPosition;
51
+ content: string;
52
+ appearance: {
53
+ width: number;
54
+ height?: number;
55
+ color: FlowViewerNoteColor;
56
+ };
57
+ };
58
+ export type FlowViewerNode = FlowViewerCatalogNode | FlowViewerNote;
59
+ export type FlowViewerEdge = {
60
+ source: string;
61
+ target: string;
62
+ sourceHandle?: string;
63
+ targetHandle?: string;
64
+ extraOffset?: number;
65
+ isVisual?: boolean;
66
+ data?: Record<string, unknown>;
67
+ };
68
+ export type FlowViewerDocument = {
69
+ nodes: FlowViewerNode[];
70
+ edges: FlowViewerEdge[];
71
+ };
@@ -0,0 +1,7 @@
1
+ import { InjectionKey } from 'vue';
2
+ import { FlowViewerCatalogNode } from './types';
3
+ export type FlowViewerDetailsContext = {
4
+ show: (node: FlowViewerCatalogNode, event: MouseEvent | FocusEvent) => void;
5
+ hide: () => void;
6
+ };
7
+ export declare const flowViewerDetailsKey: InjectionKey<FlowViewerDetailsContext>;
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@ovalbee/flow-viewer",
3
+ "version": "0.0.1",
4
+ "description": "Read-only Vue viewer for OvalBee flow graphs",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/oval-bee/ovalbee.git",
8
+ "directory": "packages/flow-viewer"
9
+ },
10
+ "homepage": "https://github.com/oval-bee/ovalbee/tree/main/packages/flow-viewer",
11
+ "bugs": {
12
+ "url": "https://github.com/oval-bee/ovalbee/issues"
13
+ },
14
+ "type": "module",
15
+ "main": "./dist/flow-viewer.cjs",
16
+ "module": "./dist/flow-viewer.js",
17
+ "types": "./dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/flow-viewer.js",
22
+ "require": "./dist/flow-viewer.cjs"
23
+ },
24
+ "./style.css": "./dist/flow-viewer.css"
25
+ },
26
+ "files": [
27
+ "dist"
28
+ ],
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "sideEffects": [
33
+ "**/*.css"
34
+ ],
35
+ "peerDependencies": {
36
+ "@vue-flow/core": "^1.47.0",
37
+ "@vue-flow/controls": "^1.1.3",
38
+ "@vue-flow/minimap": "^1.5.4",
39
+ "vue": "^3.3.0"
40
+ },
41
+ "devDependencies": {
42
+ "@vitejs/plugin-vue": "^5.2.1",
43
+ "@vue-flow/core": "^1.47.0",
44
+ "@vue-flow/controls": "^1.1.3",
45
+ "@vue-flow/minimap": "^1.5.4",
46
+ "typescript": "~5.6.3",
47
+ "vite": "^6.0.3",
48
+ "vite-plugin-dts": "^4.3.0",
49
+ "vue": "^3.5.13",
50
+ "vue-tsc": "^2.2.0"
51
+ },
52
+ "keywords": [
53
+ "ovalbee",
54
+ "vue",
55
+ "vue-flow",
56
+ "flow-viewer"
57
+ ],
58
+ "license": "MIT",
59
+ "scripts": {
60
+ "dev": "vite build --watch",
61
+ "typecheck": "vue-tsc --noEmit",
62
+ "build": "vue-tsc --noEmit && vite build"
63
+ }
64
+ }