component FlowCanvas { outputs { select(payload: object) connect(payload: object) move(payload: object) add(payload: object) } props { nodes=[] palette=[] activeNode="" label="Workflow" arrangeLabel="Arrange nodes" connectLabel="Connect" color="primary" size="default" class="" } state currentNodes = nodes state selected = "" state pending = null state drag = null functions { shared function findNode(list,id) {for(var i=0;i
{#each palette as item}{/each}
{#each rows(currentNodes,nodes) as node}
{#each node.ports as port}{/each}
{/each}
} style { .wrn-flow{border:1px solid var(--wrn-color-border);border-radius:var(--wrn-radius-lg,12px);background:var(--wrn-color-surface);overflow:hidden} .wrn-flow-toolbar{display:flex;gap:8px;flex-wrap:wrap;padding:12px;border-bottom:1px solid var(--wrn-color-border)} .wrn-flow-toolbar button{padding:8px 12px;border:1px solid var(--wrn-color-border);border-radius:8px;color:var(--wrn-color-text);background:var(--wrn-color-surface-muted);cursor:pointer} .wrn-flow-toolbar button:last-child{margin-inline-start:auto} .wrn-flow-viewport{overflow:auto;max-height:65vh;background-image:radial-gradient(var(--wrn-color-border) 1px,transparent 1px);background-size:20px 20px} .wrn-flow-stage{position:relative;isolation:isolate} .wrn-flow-links{position:absolute;inset:0;width:100%;height:100%;overflow:visible;pointer-events:none} .wrn-flow-links path{fill:none;stroke:var(--wrn-color-primary,#0e9db6);stroke-width:2} .wrn-flow-node{position:absolute;width:230px;border:1px solid var(--wrn-color-border);border-radius:12px;background:var(--wrn-color-surface);box-shadow:0 2px 8px #0002;overflow:hidden} .wrn-flow-node[data-selected=true]{border-color:var(--wrn-color-primary);box-shadow:0 0 0 2px color-mix(in srgb,var(--wrn-color-primary) 20%,transparent)} .wrn-flow-node-title{display:flex;align-items:center;justify-content:space-between;gap:8px;width:100%;padding:14px;border:0;color:var(--wrn-color-text);background:transparent;touch-action:none;cursor:grab;text-align:start} .wrn-flow-node-title small{font-size:11px;color:var(--wrn-color-text-muted)} .wrn-flow-port{display:flex;align-items:center;justify-content:space-between;width:100%;padding:6px 14px;border:0;border-top:1px solid var(--wrn-color-border);background:transparent;color:var(--wrn-color-text-muted);cursor:crosshair} .wrn-flow-port span{width:9px;height:9px;border-radius:50%;background:var(--wrn-color-primary)} .wrn-flow-port[data-pending=true]{color:var(--wrn-color-primary);background:var(--wrn-color-surface-muted)} .wrn-flow button:focus-visible{outline:2px solid var(--wrn-color-primary);outline-offset:-3px} } }