react-beauti-graph 1.3.0 → 1.3.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 CHANGED
@@ -4,15 +4,16 @@
4
4
 
5
5
  A React component for drawing report dependency graphs with [Cytoscape](https://js.cytoscape.org/).
6
6
  Give it your reports, the groups they belong to and the connections between them; it draws the graph
7
- on a grid and adds search, tracing of parents and children, a details panel and clipboard export.
7
+ on a grid and adds search, tracing of parents and children, a details panel, clipboard export and SVG export.
8
8
 
9
- ![react-beauti-graph example: reports r001 and r002 in a Sales group joined by a two-way arrow, an arrow from r002 to r003 in a Finance group, and the Select a node list open with ALL, r001, r002 and r003](https://raw.githubusercontent.com/ramasco/react-beauti-graph/main/docs/example.jpg)
9
+ ![react-beauti-graph example: reports r001 and r002 in a Sales group joined by a two-way arrow, an arrow from r002 to r003 in a Finance group, and the Node to Display list open with ALL, r001, r002 and r003](https://raw.githubusercontent.com/ramasco/react-beauti-graph/main/docs/example.jpg)
10
10
 
11
11
  _The [quick start](#quick-start) example, with the_ Node to Display _list open._
12
12
 
13
13
  ## Contents
14
14
 
15
15
  - [Features](#features)
16
+ - [Release notes](#release-notes)
16
17
  - [Install](#install)
17
18
  - [Quick start](#quick-start)
18
19
  - [Frameworks](#frameworks)
@@ -39,15 +40,37 @@ _The [quick start](#quick-start) example, with the_ Node to Display _list open._
39
40
  - **Show Dependency 1 and 2**: highlight the whole chain of parents or children of a report in two colors, and dim the rest
40
41
  - **Details panel** (double click): the report, its group, its parents and children, one level or all levels; click a name to jump to it
41
42
  - **Save to clipboard** (right click): copies the same information as the details panel
43
+ - **Export SVG** button: downloads the whole graph as a vector `graph.svg` file (a static image, not interactive)
42
44
  - **Text size buttons** (− / +) for the top row, the details panel and the graph
43
45
  - **Configurable** colors, text sizes and grid spacing
44
46
 
47
+ ## Release notes
48
+
49
+ ### 1.3.1
50
+
51
+ - **Export SVG**: a blue button at the right end of the top row saves the whole graph (not only the visible part) as `graph.svg`, using [`cytoscape-svg`](https://github.com/kinimesi/cytoscape-svg), which is now a dependency. The graph is still drawn on canvas; the SVG is an export only.
52
+ - **Top row layout**: the text size dropdown with − / + and _Export SVG_ sit together at the right end of the row, after the _?_ help
53
+ - **`downloadSvg(cy)`**: the same export, available in code (takes a Cytoscape core instance)
54
+ - Typecheck, lint, format check and all 85 tests pass (`npm run check`)
55
+
56
+ ### 1.3.0
57
+
58
+ - **Report boxes fit their text**: each box is as big as its label plus a little padding (it was a fixed 200 × 60); the _Font Graph Panel_ − / + buttons resize the boxes with the text
59
+ - Built and type-checked with TypeScript 7; dependencies updated
60
+ - **Show Dependency 1 and 2**: two independent chains of parents or children, each with its own colors; reports and arrows on both use `commonColor`
61
+ - **Details panel**: _One level / All levels_ switch, also used by _Save to clipboard_
62
+ - **Text size**: dropdown with − / + buttons for the top row, the details panel and the graph
63
+ - **Renamed controls**: _Node to Display_, _Show Dependency_, _Show Nothing_
64
+ - **`node_groups`** is the name of the first `create_graph` argument (it was `folders`; the argument is positional, so existing calls keep working)
65
+ - **TypeScript**: written in strict TypeScript, with generated type definitions for ESM and CommonJS
66
+ - **Example app**: now a separate project in `examples/` (Vite); Next.js is no longer used
67
+
45
68
  ## Install
46
69
 
47
70
  From the [GitHub release](https://github.com/ramasco/react-beauti-graph/releases/latest):
48
71
 
49
72
  ```bash
50
- npm install https://github.com/ramasco/react-beauti-graph/releases/download/v1.3.0/react-beauti-graph-1.3.0.tgz
73
+ npm install https://github.com/ramasco/react-beauti-graph/releases/download/v1.3.1/react-beauti-graph-1.3.1.tgz
51
74
  ```
52
75
 
53
76
  Requires React 18 or newer. Cytoscape is installed automatically.
@@ -214,7 +237,7 @@ disappears too. Hidden reports stay in the list, greyed out.
214
237
  Clicking a checkbox does not select the report and keeps the list open, so you can hide several in a row.
215
238
  Picking a hidden report by name shows it again, and _ALL_ zooms to fit the reports that are shown.
216
239
 
217
- ![The Select a node list with r001 unchecked and greyed out: the graph shows only r002 with its arrow to r003; r001 and the two-way arrow are gone](https://raw.githubusercontent.com/ramasco/react-beauti-graph/main/docs/example_filter_out_node.jpg)
240
+ ![The Node to Display list with r001 unchecked and greyed out: the graph shows only r002 with its arrow to r003; r001 and the two-way arrow are gone](https://raw.githubusercontent.com/ramasco/react-beauti-graph/main/docs/example_filter_out_node.jpg)
218
241
 
219
242
  _`r001` unchecked, with_ Show Groups _and_ Add Group to Node Name _turned off: only `r002 → r003` is left._
220
243
 
@@ -267,6 +290,7 @@ at the graph. Pick what to resize in the dropdown, then click **−** or **+**:
267
290
  | _Parents / Children_ | Which chain the _Show Dependency_ next to it follows. Disabled while nothing is tracked. |
268
291
  | _Font Top Panel / Font Right Panel / Font Graph Panel_ | Dropdown that picks which text the next two buttons resize: the top row, the details panel, or the labels and boxes of the graph. |
269
292
  | _−_ and _+_ | Make the chosen text 2px smaller or larger (from 8px smaller to 16px larger than the configured size). Each area keeps its own size; they reset when the page is reloaded. |
293
+ | _Export SVG_ | Downloads the whole graph as `graph.svg` (all reports and groups, whatever the zoom). The file is a static image: no search, details or highlighting. |
270
294
  | _?_ | Short help. |
271
295
 
272
296
  In all search boxes, use the arrow keys and Enter to pick, Escape to close the list, and × to clear.
@@ -308,6 +332,7 @@ Building blocks used by the component, for building your own UI:
308
332
  | `NodeSearch` | The search box: `<NodeSearch options={[{ id, label }]} selectedId={id} onSelect={(id) => …} noneLabel="ALL" />`. `''` means no node. Add `onToggleVisible={(id) => …}` and `hiddenIds={new Set([...])}` to show a checkbox next to each node. |
309
333
  | `getNodeInfo(node, allLevels?)` | For a Cytoscape node: `{ id, name, group, parents, children }` (parents and children sorted by name). With `allLevels` set to `true`, the lists hold every ancestor and descendant instead of the direct ones. |
310
334
  | `formatNodeInfo(info)` | The clipboard text for the result of `getNodeInfo`. |
335
+ | `downloadSvg(cy)` | Downloads the whole graph of a Cytoscape core instance as `graph.svg`. |
311
336
 
312
337
  ## Development
313
338
 
@@ -331,6 +356,7 @@ npm run lint # ESLint, strict rules (eslint.config.mjs)
331
356
  npm run format # Prettier: formats the code (npm run format:check only checks)
332
357
  npm run check # typecheck + lint + format check + tests: run it before a commit
333
358
  npm run build:lib # build the npm package (code and .d.ts types) into dist/
359
+ npm run smoke # draws the example app in Chrome or Edge and checks the arrows are painted
334
360
  ```
335
361
 
336
362
  **Example app** (`examples/`):
@@ -346,19 +372,21 @@ On Windows, `examples/run.cmd` installs the example's dependencies the first tim
346
372
  `npm run dev` does the same as `cd examples && npm run dev`. While developing, the name `react-beauti-graph`
347
373
  points at the library source in `src/` (see `examples/vite.config.mjs`), so library changes show up at once.
348
374
 
349
- | Path | Contents |
350
- | ---------------------------------------------------------------- | -------------------------------------------------------------------------------- |
351
- | `src/graphFactory.tsx` | The library: `create_graph`, layout, styles, search box |
352
- | `src/default_setting.ts` | Default colors, text sizes and layout (the `DEFAULT_*` values) |
353
- | `src/react-beauti-graph.css` | The library styles (published as `style.css`) |
354
- | `src/index.ts` | Public entry point of the package (the `.d.ts` types are generated into `dist/`) |
355
- | `tests/` | `graphFactory.test.ts`, `NodeSearch.test.tsx` |
356
- | `tsconfig.json`, `tsconfig.build.json` | TypeScript settings (strict), and the settings that generate the types |
357
- | `vite.lib.config.mjs`, `vitest.config.mjs` | Build of the npm package, and the test setup |
358
- | `examples/DemoApp.tsx` | The example page, with the _Demo data_ dropdown |
359
- | `examples/main.tsx`, `examples/index.html`, `examples/index.css` | The Vite entry that mounts the example page, and its page styles |
360
- | `examples/samples/` | Example data: a small example and 100 reports in 5 groups |
361
- | `examples/package.json`, `examples/vite.config.mjs` | The example app's own dependencies and Vite setup |
375
+ | Path | Contents |
376
+ | ---------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
377
+ | `src/graphFactory.tsx` | The library: `create_graph`, layout, styles, search box |
378
+ | `src/default_setting.ts` | Default colors, text sizes and layout (the `DEFAULT_*` values) |
379
+ | `src/react-beauti-graph.css` | The library styles (published as `style.css`) |
380
+ | `src/index.ts` | Public entry point of the package (the `.d.ts` types are generated into `dist/`) |
381
+ | `tests/` | `graphFactory.test.ts`, `NodeSearch.test.tsx` |
382
+ | `tsconfig.json`, `tsconfig.build.json` | TypeScript settings (strict), and the settings that generate the types |
383
+ | `scripts/` | `smoke.mjs` (browser smoke test) and `make-cts.mjs` (finishes the type files) |
384
+ | `.github/workflows/ci.yml` | GitHub Actions: runs the check, the package build and the smoke test on every push |
385
+ | `vite.lib.config.mjs`, `vitest.config.mjs` | Build of the npm package, and the test setup |
386
+ | `examples/DemoApp.tsx` | The example page, with the _Demo data_ dropdown |
387
+ | `examples/main.tsx`, `examples/index.html`, `examples/index.css` | The Vite entry that mounts the example page, and its page styles |
388
+ | `examples/samples/` | Example data: a small example and 100 reports in 5 groups |
389
+ | `examples/package.json`, `examples/vite.config.mjs` | The example app's own dependencies and Vite setup |
362
390
 
363
391
  In the example app, switch between the two samples with the _Demo data_ dropdown at the top of the page.
364
392
 
@@ -2,6 +2,8 @@ import type { FC } from 'react';
2
2
  import cytoscape from 'cytoscape';
3
3
  import type { StylesheetJson } from 'cytoscape';
4
4
  export * from './default_setting.cjs';
5
+ /** Downloads the whole graph as a static SVG file named graph.svg. */
6
+ export declare function downloadSvg(cy: cytoscape.Core): void;
5
7
  export declare const REPORT_NODE = "node[class = \"macromolecule\"]";
6
8
  /** Group (folder box) names mapped to the names of the reports inside them */
7
9
  export type NodeGroups = Record<string, string[]>;
@@ -2,6 +2,8 @@ import type { FC } from 'react';
2
2
  import cytoscape from 'cytoscape';
3
3
  import type { StylesheetJson } from 'cytoscape';
4
4
  export * from './default_setting.js';
5
+ /** Downloads the whole graph as a static SVG file named graph.svg. */
6
+ export declare function downloadSvg(cy: cytoscape.Core): void;
5
7
  export declare const REPORT_NODE = "node[class = \"macromolecule\"]";
6
8
  /** Group (folder box) names mapped to the names of the reports inside them */
7
9
  export type NodeGroups = Record<string, string[]>;
package/dist/index.cjs CHANGED
@@ -1,3 +1,3 @@
1
- "use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,s)=>(s=n==null?{}:e(i(n)),o(r||!n||!n.__esModule||!a.call(n,`default`)?t(s,`default`,{value:n,enumerable:!0}):s,n));let c=require("react"),l=require("cytoscape");l=s(l,1);let u=require("react/jsx-runtime");var d=`#e91e63`,f=`#2e7d32`,p=`#7b1fa2`,m=`#efeb00`,h=`#8b4513`,g=`rgb(239, 108, 0)`,_=`22px`,v=`18px`,y=`#0066cc`,b=`#fff`,x=`#f0f8ff`,S=2,C=-8,w=16,T=16,E=14,D=[[`top`,`Font Top Panel`],[`right`,`Font Right Panel`],[`graph`,`Font Graph Panel`]],O=`Helvetica Neue, Helvetica, Arial, sans-serif`,k=1.2,A=.6,j=`macromolecule`,M=`compartment`,N=`node[class = "${j}"]`,P;function F(e,t){if(P===void 0)try{P=document.createElement(`canvas`).getContext(`2d`)}catch{P=null}return P?(P.font=`${t}px ${O}`,P.measureText(e).width):e.length*t*A}function ee(e,t=T){return{width:Math.ceil(F(e??``,t))+8,height:Math.ceil(t*k)+8}}function I(e,t){return e.localeCompare(t,void 0,{numeric:!0,sensitivity:`base`})}function te(e=[]){let t=new Map;return e.map(e=>e.map(e=>{let n=t.get(e)??0;if(t.set(e,n+1),n===0)return e;let r=`${e}(${n})`;return console.warn(`layout: duplicate id "${e}" — renamed to "${r}"`),r}))}function ne(e,t,n={}){let{startX:r=0,startY:i=0,offsetX:a=200,offsetY:o=200,base:s=1}=n,c=new Set;t.forEach((t,n)=>{t.forEach((t,l)=>{let u=t,d=e.getElementById(u);if(d.empty()){let n=/^(.+)\((\d+)\)$/.exec(t)?.[1];n!==void 0&&e.getElementById(n).nonempty()&&(u=n,d=e.getElementById(u),console.warn(`applyLayout: "${t}" not found — using "${u}" instead`))}d.empty()?console.warn(`applyLayout: node "${t}" not found`):c.has(u)?console.warn(`applyLayout: duplicate layout entry for node "${u}" (from "${t}") — keeping the first position`):(c.add(u),d.position({x:r+(l+s)*a,y:i+(n+s)*o}))})})}function L(e,t){let n=e,r=2;for(;t.has(n);)n=`${e}_${r++}`;return t.add(n),n}function R(e,t=10){let n=Math.max(1,Math.floor(t)||1),r=e.filter(e=>e.data.class===j),i=e.filter(e=>e.data.class===M).map(e=>r.filter(t=>t.data.parent===e.data.id));i.push(r.filter(e=>!e.data.parent));let a=[];for(let e of i)for(let t=0;t<e.length;t+=n)a.push(e.slice(t,t+n).map(e=>e.data.id));return a}function z(e={},t=[],n=[]){let r=[],i=new Set,a=new Set([...t.flat(),...n]);for(let t of Object.values(e))for(let e of t)i.add(e);for(let e of a)i.add(e);let o=e=>{let t=e.replace(/\s+/g,``);return t?t.charAt(0).toLowerCase()+t.slice(1):`folder`},s=new Map,c=new Map;for(let[t,n]of Object.entries(e)){let e=L(o(t),i);c.set(t,e),r.push({data:{id:e,class:M,label:t}});for(let e of n){let n=s.get(e)??[],r=e;if(n.length>0){let t=n.length;for(r=`${e}(${t})`;i.has(r);)r=`${e}(${++t})`;i.add(r)}n.push({actualId:r,folderLabel:t}),s.set(e,n)}}let l=[];for(let[e,t]of s)for(let{actualId:n,folderLabel:r}of t)l.push({actualId:n,originalId:e,folderLabel:r});for(let e of a)s.has(e)||l.push({actualId:e,originalId:e,folderLabel:null});for(let{actualId:e,originalId:t,folderLabel:n}of l){let i={id:e,class:j,rawLabel:t,displayLabel:n?`${t} (${n})`:t,group:n};n&&(i.parent=c.get(n)),r.push({data:i})}let u=e=>s.get(e)?.[0]?.actualId??e,d=(e,t)=>`${e}->${t}`,f=new Map;return t.forEach(([e,t],n)=>{let a=u(e),o=u(t);if(f.has(d(a,o)))return;let s=f.get(d(o,a));if(s){s.classes=`bidirectional`;return}let c={data:{id:L(`e${n+1}`,i),source:a,target:o}};f.set(d(a,o),c),r.push(c)}),r}function re(e,t,n){return e.filter(e=>t||e.data.class!==M).map(e=>{if(e.data.class!==j)return{...e,data:{...e.data}};let t=n?e.data.displayLabel:e.data.rawLabel;return{...e,data:{...e.data,graphLabel:t}}})}function B(e,t=!1){let n=e=>({id:e.id(),name:e.data(`rawLabel`)??e.id(),group:e.data(`group`)??null}),r=new Map,i=new Map;if(e.connectedEdges().forEach(t=>{let a=t.hasClass(`bidirectional`);t.target().same(e)&&(r.set(t.source().id(),n(t.source())),a&&i.set(t.source().id(),n(t.source()))),t.source().same(e)&&(i.set(t.target().id(),n(t.target())),a&&r.set(t.target().id(),n(t.target())))}),t){let t=[[r,`parents`],[i,`children`]];for(let[r,i]of t)r.clear(),V(e,i).nodes().forEach(t=>{t.same(e)||r.set(t.id(),n(t))})}let a=(e,t)=>I(e.name,t.name);return{...n(e),parents:[...r.values()].sort(a),children:[...i.values()].sort(a)}}function V(e,t){let n=t===`parents`,r=e.cy().collection(),i=new Set([e.id()]),a=[e];for(let e=a.shift();e!==void 0;e=a.shift()){let t=e;t.connectedEdges().forEach(e=>{let o=e.hasClass(`bidirectional`),s=null;e.target().same(t)&&(n||o)&&(s=e.source()),e.source().same(t)&&(!n||o)&&(s=e.target()),s&&(r=r.union(e),i.has(s.id())||(i.add(s.id()),a.push(s)))})}return r.union(e.cy().nodes().filter(e=>i.has(e.id())))}function H(e){return[[`Parent Nodes`,e.parents],[`Child Nodes`,e.children]].filter(([,e])=>e.length>0)}function ie(e,t){let n=e.nodes(N).filter(e=>t.has(e.id())),r=e.nodes(`:parent`).filter(e=>e.children().every(e=>n.has(e)));return n.union(r)}function U(e){let t=e=>e.group?`${e.name} (${e.group})`:e.name,n=[`Node: ${e.name}`];e.group&&n.push(`Group: ${e.group}`);for(let[r,i]of H(e))n.push(``,`${r} (${i.length}):`,...i.map(t));return n.join(`
2
- `)}function W(e){let t=/^#([0-9a-f]{6})$/i.exec(e)?.[1];if(t!==void 0)return parseInt(t,16);let n=/^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/i.exec(e);if(n===null)return null;let[r=0,i=0,a=0]=n.slice(1).map(e=>Math.min(Number(e),255));return r<<16|i<<8|a}function G(e,t=.88){let n=W(e);return n===null?`#ffffff`:`#${[16,8,0].map(e=>{let r=n>>e&255;return Math.round(r+(255-r)*t).toString(16).padStart(2,`0`)}).join(``)}`}function ae(e,t,n=g){let r=[`track`,`track2`],i=r.flatMap(e=>[`${e}-parents`,`${e}-children`,`${e}-root`]).concat(`faded`,`track-mixed`).join(` `);e.batch(()=>{e.elements().removeClass(i).removeData(`trackMixColor trackMixFill`);let a=t.map(({id:t,direction:n},i)=>{if(!t)return null;let a=e.getElementById(t);if(a.empty())return null;let o=V(a,n),s=r[i]??`track`;return o.addClass(`${s}-${n}`),a.addClass(`${s}-root`),o}),o=a.filter(e=>e!==null);if(o.length===0)return;let[s,c]=a;s&&c&&s.intersection(c).forEach(e=>{e.data({trackMixColor:n,trackMixFill:G(n)}),e.addClass(`track-mixed`)});let l=o.reduce((e,t)=>e.union(t));e.elements().not(l).not(`node:parent`).addClass(`faded`)})}function K({selectedColor:e=d,parentsColor:t=f,childrenColor:n=p,track2ParentsColor:r=m,track2ChildrenColor:i=h}={}){return[{selector:`node`,style:{"background-color":b,label:`data(graphLabel)`,shape:`rectangle`,"font-family":O,"font-size":T,color:y,"border-width":2,"border-color":y,"text-valign":`center`,"text-halign":`center`}},{selector:`node:parent`,style:{"background-color":x,"background-opacity":.5,"border-style":`dashed`,label:`data(label)`,"text-valign":`top`,"font-size":E,"font-weight":`bold`,padding:`18px`}},{selector:`.selected`,style:{"overlay-color":e,"overlay-opacity":.35,"overlay-padding":8}},{selector:`edge`,style:{"line-color":y,width:2,"curve-style":`bezier`,"target-arrow-shape":`vee`,"target-arrow-color":y,"target-arrow-fill":`filled`,"arrow-scale":2}},{selector:`edge:loop`,style:{"loop-direction":`0deg`,"loop-sweep":`-50deg`,"control-point-step-size":70}},{selector:`edge.bidirectional`,style:{"source-arrow-shape":`vee`,"source-arrow-color":y,"source-arrow-fill":`filled`}},{selector:`.faded`,style:{opacity:.15}},...[[`track-parents`,`track-root`,t],[`track-children`,`track-root`,n],[`track2-parents`,`track2-root`,r],[`track2-children`,`track2-root`,i]].flatMap(([e,t,n])=>[{selector:`edge.${e}`,style:{"line-color":n,"target-arrow-color":n,"source-arrow-color":n,width:4}},{selector:`node.${e}`,style:{"border-color":n,"border-width":3}},{selector:`node.${e}.${t}`,style:{"border-width":5,"background-color":G(n)}}]),{selector:`edge.track-mixed`,style:{"line-color":`data(trackMixColor)`,"target-arrow-color":`data(trackMixColor)`,"source-arrow-color":`data(trackMixColor)`,width:5}},{selector:`node.track-mixed`,style:{"border-color":`data(trackMixColor)`,"border-width":4}},{selector:`node.track-mixed.track-root, node.track-mixed.track2-root`,style:{"border-width":6,"background-color":`data(trackMixFill)`}},{selector:`.hidden`,style:{display:`none`}}]}var q=`ALL`;function J({id:e,options:t,selectedId:n,onSelect:r,noneLabel:i=q,hiddenIds:a,onToggleVisible:o}){let[s,l]=(0,c.useState)(``),[d,f]=(0,c.useState)(``),[p,m]=(0,c.useState)(!1),[h,g]=(0,c.useState)(0),_=(0,c.useRef)(null),v=(0,c.useRef)(null),y=t.find(e=>e.id===n)?.label??``,[b,x]=(0,c.useState)(null);b!==y&&(x(y),l(y));let S=d.trim().toLowerCase(),C=S?t.filter(e=>e.label.toLowerCase().includes(S)):t,w={id:``,label:i},T=!S||i.toLowerCase().includes(S)?[w,...C]:C,E=()=>{f(``),g(0),m(!0)},D=()=>{m(!1),f(``),l(y)},O=e=>{r(e.id),l(e.id?e.label:``),f(``),m(!1)};return(0,c.useEffect)(()=>{if(!p)return;let e=e=>{_.current?.contains(e.target)||D()};return document.addEventListener(`mousedown`,e),()=>document.removeEventListener(`mousedown`,e)}),(0,c.useEffect)(()=>{v.current?.children[h]?.scrollIntoView({block:`nearest`})},[h,p]),(0,u.jsxs)(`div`,{className:`node-search`,ref:_,children:[(0,u.jsx)(`input`,{id:e,type:`text`,value:s,placeholder:`-- type to search --`,autoComplete:`off`,onChange:e=>{l(e.target.value),f(e.target.value),g(0),m(!0)},onFocus:e=>{e.target.select(),E()},onClick:()=>{p||E()},onKeyDown:e=>{if(e.key===`ArrowDown`)e.preventDefault(),p||m(!0),g(e=>Math.min(e+1,T.length-1));else if(e.key===`ArrowUp`)e.preventDefault(),g(e=>Math.max(e-1,0));else if(e.key===`Enter`&&p){let t=T[h];t&&(e.preventDefault(),O(t))}else e.key===`Escape`&&D()}}),s&&(0,u.jsx)(`button`,{type:`button`,className:`node-search-clear`,"aria-label":`Clear`,onClick:()=>{r(``),l(``),f(``)},children:`×`}),p&&(0,u.jsx)(`ul`,{className:`node-search-list`,ref:v,role:`listbox`,children:T.length===0?(0,u.jsx)(`li`,{className:`node-search-empty`,role:`option`,"aria-selected":`false`,"aria-disabled":`true`,children:`no match`}):T.map((e,t)=>(0,u.jsxs)(`li`,{role:`option`,"aria-selected":t===h,className:[t===h&&`active`,a?.has(e.id)&&`off`].filter(Boolean).join(` `)||void 0,onMouseDown:t=>{t.preventDefault(),O(e)},onMouseEnter:()=>g(t),children:[o&&e.id&&(0,u.jsx)(`input`,{type:`checkbox`,checked:!a?.has(e.id),"aria-label":`Show ${e.label}`,onMouseDown:e=>{e.preventDefault(),e.stopPropagation()},onClick:e=>e.stopPropagation(),onChange:()=>o(e.id)}),e.label]},e.id||`__none__`))})]})}function Y(e={},t=[],n=null,r={}){let i=Array.isArray(n)?n:null,a=n!==null&&!Array.isArray(n)?n:r,o=i!==null&&i.length>0,{selectedColor:s=d,parentsColor:y=f,childrenColor:b=p,track2ParentsColor:x=m,track2ChildrenColor:O=h,commonColor:k=g,topControlsFontSize:A=_,rightDisplayFontSize:j=v,layoutColumns:M=10}=a,P=K({selectedColor:s,parentsColor:y,childrenColor:b,track2ParentsColor:x,track2ChildrenColor:O}),F={"--rbg-parents-color":y,"--rbg-children-color":b},L={"--rbg-parents-color":x,"--rbg-children-color":O},V=z(e,t,i!==null&&o?i.flat():[]),W=i!==null&&o?te(i):R(V,M);function G(){let e=(0,c.useRef)(null),t=(0,c.useRef)(null),n=(0,c.useId)(),[r,i]=(0,c.useState)([]),[o,s]=(0,c.useState)(``),[d,f]=(0,c.useState)(0),[p,m]=(0,c.useState)(``),[h,g]=(0,c.useState)(`parents`),[_,v]=(0,c.useState)(``),[y,b]=(0,c.useState)(`parents`),[x,O]=(0,c.useState)(!0),[M,te]=(0,c.useState)(!0),[R,z]=(0,c.useState)(null),[G,K]=(0,c.useState)(null),[q,Y]=(0,c.useState)(`top`),[X,oe]=(0,c.useState)({top:0,right:0,graph:0}),[Z,se]=(0,c.useState)(!1),Q=(0,c.useRef)(!1);(0,c.useEffect)(()=>{Q.current=Z},[Z]);let[$,ce]=(0,c.useState)(()=>new Set);(0,c.useEffect)(()=>{let n=e.current;if(!n)return;let r=(0,l.default)({container:n,elements:re(V,x,M),style:P,layout:{name:`preset`,fit:!1}});r.on(`cxttap`,N,e=>{let t=U(B(e.target,Q.current)),{clientX:n,clientY:r}=e.originalEvent;z({x:n,y:r,copyText:t})}),r.on(`dbltap`,N,e=>{K(B(e.target,Q.current))}),r.on(`tap cxttap`,e=>{e.target===r&&z(null)}),r.on(`tap`,`node`,()=>z(null)),r.on(`viewport`,()=>z(null));let o=e=>e.preventDefault();return n.addEventListener(`contextmenu`,o),ne(r,W,a),requestAnimationFrame(()=>r.resize()),i(r.nodes(N).map(e=>({id:e.id(),label:e.data(`displayLabel`)})).sort((e,t)=>I(e.label,t.label))),t.current=r,()=>{n.removeEventListener(`contextmenu`,o),z(null),r.destroy(),t.current=null}},[x,M]),(0,c.useEffect)(()=>{let e=t.current;if(!e)return;let n=X.graph;e.batch(()=>{e.nodes(N).forEach(e=>{let t=T+n,{width:r,height:i}=ee(e.data(`graphLabel`),t);e.style({"font-size":t,width:r,height:i})}),e.nodes(`:parent`).style(`font-size`,E+n)})},[X.graph,x,M]),(0,c.useEffect)(()=>{if(!R)return;let e=e=>{e.target.closest(`.node-context-menu`)||z(null)},t=e=>{e.key===`Escape`&&z(null)};return document.addEventListener(`mousedown`,e),document.addEventListener(`keydown`,t),()=>{document.removeEventListener(`mousedown`,e),document.removeEventListener(`keydown`,t)}},[R]);let le=()=>{if(R===null)return;let{copyText:e}=R;z(null),navigator.clipboard.writeText(e).catch(e=>{console.error(`Failed to copy:`,e)})},ue=e=>{ce(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},de=e=>{let n=t.current?.getElementById(e);n&&!n.empty()&&($.has(e)&&ue(e),s(e),K(B(n,Z)))},fe=()=>{s(``),K(null),f(e=>e+1)};(0,c.useEffect)(()=>{let e=t.current;e&&e.batch(()=>{e.elements().removeClass(`hidden`),ie(e,$).addClass(`hidden`)})},[$,x,M]),(0,c.useEffect)(()=>{let e=t.current;d&&e&&(e.stop(),e.resize(),e.animate({fit:{eles:e.elements().not(`.hidden`),padding:30}},{duration:400}))},[d]),(0,c.useEffect)(()=>{let e=t.current;if(!e||(e.nodes().removeClass(`selected`),!o))return;let n=e.getElementById(o);n.nonempty()&&(n.addClass(`selected`),e.animate({center:{eles:n},zoom:1.8},{duration:400}))},[o,x,M]),(0,c.useEffect)(()=>{let e=t.current;e&&ae(e,[{id:p,direction:h},{id:_,direction:y}],k)},[p,h,_,y,x,M]),(0,c.useEffect)(()=>{t.current?.resize()},[G!==null]),(0,c.useEffect)(()=>{let e=()=>t.current?.resize();return window.addEventListener(`resize`,e),()=>window.removeEventListener(`resize`,e)},[]);let pe=[{n:1,id:p,setId:m,direction:h,setDirection:g,style:void 0},{n:2,id:_,setId:v,direction:y,setDirection:b,style:L}],me=[{label:`Smaller text`,symbol:`−`,step:-2,atLimit:X[q]<=C},{label:`Larger text`,symbol:`+`,step:S,atLimit:X[q]>=w}];return(0,u.jsxs)(`div`,{className:`rbg-graph`,style:{...F,"--rbg-top-controls-font-size":`calc(${A} + ${X.top}px)`,"--rbg-right-display-font-size":`calc(${j} + ${X.right}px)`},children:[(0,u.jsxs)(`div`,{className:`controls`,children:[(0,u.jsxs)(`span`,{className:`control-group`,children:[(0,u.jsx)(`label`,{htmlFor:`${n}-search`,children:`Node to Display:`}),(0,u.jsx)(J,{id:`${n}-search`,options:r,selectedId:o,onSelect:e=>e?de(e):fe(),hiddenIds:$,onToggleVisible:ue})]}),(0,u.jsxs)(`label`,{children:[(0,u.jsx)(`input`,{type:`checkbox`,checked:x,onChange:e=>O(e.target.checked)}),`Show Groups`]}),(0,u.jsxs)(`label`,{children:[(0,u.jsx)(`input`,{type:`checkbox`,checked:M,onChange:e=>te(e.target.checked)}),`Add Group to Node Name`]}),pe.map(({n:e,id:t,setId:i,direction:a,setDirection:o,style:s})=>(0,u.jsxs)(`span`,{className:`control-group`,style:s,children:[(0,u.jsxs)(`label`,{htmlFor:`${n}-track${e}`,children:[`Show Dependency `,e,`:`]}),(0,u.jsx)(J,{id:`${n}-track${e}`,options:r,selectedId:t,onSelect:i,noneLabel:`Show Nothing`}),(0,u.jsxs)(`span`,{className:t?`track-switch`:`track-switch disabled`,children:[(0,u.jsx)(`span`,{className:a===`parents`?`parents on`:`parents`,children:`Parents`}),(0,u.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":a===`children`,"aria-label":`Show Dependency ${e}: track children instead of parents`,className:`switch`,disabled:!t,onClick:()=>o(e=>e===`parents`?`children`:`parents`),children:(0,u.jsx)(`span`,{className:`switch-knob`})}),(0,u.jsx)(`span`,{className:a===`children`?`children on`:`children`,children:`Children`})]})]},e)),(0,u.jsxs)(`span`,{className:`help`,children:[(0,u.jsx)(`button`,{type:`button`,className:`help-icon`,"aria-label":`Help`,"aria-describedby":`${n}-help`,children:`?`}),(0,u.jsxs)(`span`,{id:`${n}-help`,role:`tooltip`,className:`help-tooltip`,children:[(0,u.jsx)(`strong`,{children:`Double click`}),` on a node to see its information, parents and children.`,(0,u.jsx)(`br`,{}),(0,u.jsx)(`strong`,{children:`Right click`}),` on a node to save the same information to the clipboard.`]})]}),(0,u.jsxs)(`span`,{className:`font-size-buttons`,children:[(0,u.jsx)(`select`,{"aria-label":`Area whose text size the + and - buttons change`,value:q,onChange:e=>Y(e.target.value),children:D.map(([e,t])=>(0,u.jsx)(`option`,{value:e,children:t},e))}),me.map(({label:e,symbol:t,step:n,atLimit:r})=>(0,u.jsx)(`button`,{type:`button`,className:`help-icon`,"aria-label":e,disabled:r,onClick:()=>oe(e=>({...e,[q]:e[q]+n})),children:t},e))]})]}),(0,u.jsxs)(`div`,{className:`graph-area`,children:[(0,u.jsx)(`div`,{ref:e,className:`cy-container`}),G&&(0,u.jsxs)(`aside`,{className:`node-info-panel`,children:[(0,u.jsxs)(`div`,{className:`node-info-header`,children:[(0,u.jsxs)(`h2`,{children:[(0,u.jsx)(`strong`,{children:`Node:`}),` `,G.name]}),(0,u.jsx)(`button`,{type:`button`,onClick:()=>K(null),"aria-label":`Close`,children:`×`})]}),G.group&&(0,u.jsxs)(`p`,{children:[(0,u.jsx)(`strong`,{children:`Group:`}),` `,G.group]}),(0,u.jsxs)(`div`,{className:`track-switch level-switch`,children:[(0,u.jsx)(`span`,{className:Z?``:`parents on`,children:`One level`}),(0,u.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":Z,"aria-label":`Show all levels of parents and children`,className:`switch`,onClick:()=>{let e=!Z;se(e);let n=t.current?.getElementById(G.id);n&&!n.empty()&&K(B(n,e))},children:(0,u.jsx)(`span`,{className:`switch-knob`})}),(0,u.jsx)(`span`,{className:Z?`children on`:``,children:`All levels`})]}),H(G).map(([e,t])=>(0,u.jsxs)(`section`,{children:[(0,u.jsxs)(`h3`,{children:[e,` (`,t.length,`):`]}),(0,u.jsx)(`ul`,{children:t.map(e=>(0,u.jsx)(`li`,{children:(0,u.jsxs)(`button`,{type:`button`,onClick:()=>de(e.id),children:[e.name,e.group&&(0,u.jsxs)(`span`,{children:[` (`,e.group,`)`]})]})},e.id))})]},e))]})]}),R&&(0,u.jsx)(`div`,{className:`node-context-menu`,style:{left:R.x,top:R.y},onContextMenu:e=>e.preventDefault(),children:(0,u.jsx)(`button`,{type:`button`,onClick:le,children:`Save to clipboard`})})]})}return G.displayName=`CytoscapeGraph`,G}exports.NodeSearch=J,exports.create_graph=Y,exports.formatNodeInfo=U,exports.getNodeInfo=B;
1
+ "use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,s)=>(s=n==null?{}:e(i(n)),o(r||!n||!n.__esModule||!a.call(n,`default`)?t(s,`default`,{value:n,enumerable:!0}):s,n));let c=require("react"),l=require("cytoscape");l=s(l,1);let u=require("cytoscape-svg");u=s(u,1);let d=require("react/jsx-runtime");var f=`#e91e63`,p=`#2e7d32`,m=`#7b1fa2`,h=`#efeb00`,g=`#8b4513`,_=`rgb(239, 108, 0)`,v=`22px`,y=`18px`,b=`#0066cc`,x=`#fff`,S=`#f0f8ff`;l.default.use(u.default);function C(e){let t=e.svg({full:!0,scale:1}),n=URL.createObjectURL(new Blob([t],{type:`image/svg+xml`})),r=document.createElement(`a`);r.href=n,r.download=`graph.svg`,r.click(),URL.revokeObjectURL(n)}var w=2,T=-8,E=16,D=16,O=14,ee=[[`top`,`Font Top Panel`],[`right`,`Font Right Panel`],[`graph`,`Font Graph Panel`]],k=`Helvetica Neue, Helvetica, Arial, sans-serif`,A=1.2,j=.6,M=`macromolecule`,N=`compartment`,P=`node[class = "${M}"]`,F;function te(e,t){if(F===void 0)try{F=document.createElement(`canvas`).getContext(`2d`)}catch{F=null}return F?(F.font=`${t}px ${k}`,F.measureText(e).width):e.length*t*j}function ne(e,t=D){return{width:Math.ceil(te(e??``,t))+8,height:Math.ceil(t*A)+8}}function I(e,t){return e.localeCompare(t,void 0,{numeric:!0,sensitivity:`base`})}function L(e=[]){let t=new Map;return e.map(e=>e.map(e=>{let n=t.get(e)??0;if(t.set(e,n+1),n===0)return e;let r=`${e}(${n})`;return console.warn(`layout: duplicate id "${e}" — renamed to "${r}"`),r}))}function re(e,t,n={}){let{startX:r=0,startY:i=0,offsetX:a=200,offsetY:o=200,base:s=1}=n,c=new Set;t.forEach((t,n)=>{t.forEach((t,l)=>{let u=t,d=e.getElementById(u);if(d.empty()){let n=/^(.+)\((\d+)\)$/.exec(t)?.[1];n!==void 0&&e.getElementById(n).nonempty()&&(u=n,d=e.getElementById(u),console.warn(`applyLayout: "${t}" not found — using "${u}" instead`))}d.empty()?console.warn(`applyLayout: node "${t}" not found`):c.has(u)?console.warn(`applyLayout: duplicate layout entry for node "${u}" (from "${t}") — keeping the first position`):(c.add(u),d.position({x:r+(l+s)*a,y:i+(n+s)*o}))})})}function R(e,t){let n=e,r=2;for(;t.has(n);)n=`${e}_${r++}`;return t.add(n),n}function z(e,t=10){let n=Math.max(1,Math.floor(t)||1),r=e.filter(e=>e.data.class===M),i=e.filter(e=>e.data.class===N).map(e=>r.filter(t=>t.data.parent===e.data.id));i.push(r.filter(e=>!e.data.parent));let a=[];for(let e of i)for(let t=0;t<e.length;t+=n)a.push(e.slice(t,t+n).map(e=>e.data.id));return a}function B(e={},t=[],n=[]){let r=[],i=new Set,a=new Set([...t.flat(),...n]);for(let t of Object.values(e))for(let e of t)i.add(e);for(let e of a)i.add(e);let o=e=>{let t=e.replace(/\s+/g,``);return t?t.charAt(0).toLowerCase()+t.slice(1):`folder`},s=new Map,c=new Map;for(let[t,n]of Object.entries(e)){let e=R(o(t),i);c.set(t,e),r.push({data:{id:e,class:N,label:t}});for(let e of n){let n=s.get(e)??[],r=e;if(n.length>0){let t=n.length;for(r=`${e}(${t})`;i.has(r);)r=`${e}(${++t})`;i.add(r)}n.push({actualId:r,folderLabel:t}),s.set(e,n)}}let l=[];for(let[e,t]of s)for(let{actualId:n,folderLabel:r}of t)l.push({actualId:n,originalId:e,folderLabel:r});for(let e of a)s.has(e)||l.push({actualId:e,originalId:e,folderLabel:null});for(let{actualId:e,originalId:t,folderLabel:n}of l){let i={id:e,class:M,rawLabel:t,displayLabel:n?`${t} (${n})`:t,group:n};n&&(i.parent=c.get(n)),r.push({data:i})}let u=e=>s.get(e)?.[0]?.actualId??e,d=(e,t)=>`${e}->${t}`,f=new Map;return t.forEach(([e,t],n)=>{let a=u(e),o=u(t);if(f.has(d(a,o)))return;let s=f.get(d(o,a));if(s){s.classes=`bidirectional`;return}let c={data:{id:R(`e${n+1}`,i),source:a,target:o}};f.set(d(a,o),c),r.push(c)}),r}function ie(e,t,n){return e.filter(e=>t||e.data.class!==N).map(e=>{if(e.data.class!==M)return{...e,data:{...e.data}};let t=n?e.data.displayLabel:e.data.rawLabel;return{...e,data:{...e.data,graphLabel:t}}})}function V(e,t=!1){let n=e=>({id:e.id(),name:e.data(`rawLabel`)??e.id(),group:e.data(`group`)??null}),r=new Map,i=new Map;if(e.connectedEdges().forEach(t=>{let a=t.hasClass(`bidirectional`);t.target().same(e)&&(r.set(t.source().id(),n(t.source())),a&&i.set(t.source().id(),n(t.source()))),t.source().same(e)&&(i.set(t.target().id(),n(t.target())),a&&r.set(t.target().id(),n(t.target())))}),t){let t=[[r,`parents`],[i,`children`]];for(let[r,i]of t)r.clear(),H(e,i).nodes().forEach(t=>{t.same(e)||r.set(t.id(),n(t))})}let a=(e,t)=>I(e.name,t.name);return{...n(e),parents:[...r.values()].sort(a),children:[...i.values()].sort(a)}}function H(e,t){let n=t===`parents`,r=e.cy().collection(),i=new Set([e.id()]),a=[e];for(let e=a.shift();e!==void 0;e=a.shift()){let t=e;t.connectedEdges().forEach(e=>{let o=e.hasClass(`bidirectional`),s=null;e.target().same(t)&&(n||o)&&(s=e.source()),e.source().same(t)&&(!n||o)&&(s=e.target()),s&&(r=r.union(e),i.has(s.id())||(i.add(s.id()),a.push(s)))})}return r.union(e.cy().nodes().filter(e=>i.has(e.id())))}function U(e){return[[`Parent Nodes`,e.parents],[`Child Nodes`,e.children]].filter(([,e])=>e.length>0)}function ae(e,t){let n=e.nodes(P).filter(e=>t.has(e.id())),r=e.nodes(`:parent`).filter(e=>e.children().every(e=>n.has(e)));return n.union(r)}function W(e){let t=e=>e.group?`${e.name} (${e.group})`:e.name,n=[`Node: ${e.name}`];e.group&&n.push(`Group: ${e.group}`);for(let[r,i]of U(e))n.push(``,`${r} (${i.length}):`,...i.map(t));return n.join(`
2
+ `)}function G(e){let t=/^#([0-9a-f]{6})$/i.exec(e)?.[1];if(t!==void 0)return parseInt(t,16);let n=/^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/i.exec(e);if(n===null)return null;let[r=0,i=0,a=0]=n.slice(1).map(e=>Math.min(Number(e),255));return r<<16|i<<8|a}function K(e,t=.88){let n=G(e);return n===null?`#ffffff`:`#${[16,8,0].map(e=>{let r=n>>e&255;return Math.round(r+(255-r)*t).toString(16).padStart(2,`0`)}).join(``)}`}function oe(e,t,n=_){let r=[`track`,`track2`],i=r.flatMap(e=>[`${e}-parents`,`${e}-children`,`${e}-root`]).concat(`faded`,`track-mixed`).join(` `);e.batch(()=>{e.elements().removeClass(i).removeData(`trackMixColor trackMixFill`);let a=t.map(({id:t,direction:n},i)=>{if(!t)return null;let a=e.getElementById(t);if(a.empty())return null;let o=H(a,n),s=r[i]??`track`;return o.addClass(`${s}-${n}`),a.addClass(`${s}-root`),o}),o=a.filter(e=>e!==null);if(o.length===0)return;let[s,c]=a;s&&c&&s.intersection(c).forEach(e=>{e.data({trackMixColor:n,trackMixFill:K(n)}),e.addClass(`track-mixed`)});let l=o.reduce((e,t)=>e.union(t));e.elements().not(l).not(`node:parent`).addClass(`faded`)})}function q({selectedColor:e=f,parentsColor:t=p,childrenColor:n=m,track2ParentsColor:r=h,track2ChildrenColor:i=g}={}){return[{selector:`node`,style:{"background-color":x,label:`data(graphLabel)`,shape:`rectangle`,"font-family":k,"font-size":D,color:b,"border-width":2,"border-color":b,"text-valign":`center`,"text-halign":`center`}},{selector:`node:parent`,style:{"background-color":S,"background-opacity":.5,"border-style":`dashed`,label:`data(label)`,"text-valign":`top`,"font-size":O,"font-weight":`bold`,padding:`18px`}},{selector:`.selected`,style:{"overlay-color":e,"overlay-opacity":.35,"overlay-padding":8}},{selector:`edge`,style:{"line-color":b,width:2,"curve-style":`bezier`,"target-arrow-shape":`vee`,"target-arrow-color":b,"target-arrow-fill":`filled`,"arrow-scale":2}},{selector:`edge:loop`,style:{"loop-direction":`0deg`,"loop-sweep":`-50deg`,"control-point-step-size":70}},{selector:`edge.bidirectional`,style:{"source-arrow-shape":`vee`,"source-arrow-color":b,"source-arrow-fill":`filled`}},{selector:`.faded`,style:{opacity:.15}},...[[`track-parents`,`track-root`,t],[`track-children`,`track-root`,n],[`track2-parents`,`track2-root`,r],[`track2-children`,`track2-root`,i]].flatMap(([e,t,n])=>[{selector:`edge.${e}`,style:{"line-color":n,"target-arrow-color":n,"source-arrow-color":n,width:4}},{selector:`node.${e}`,style:{"border-color":n,"border-width":3}},{selector:`node.${e}.${t}`,style:{"border-width":5,"background-color":K(n)}}]),{selector:`edge.track-mixed`,style:{"line-color":`data(trackMixColor)`,"target-arrow-color":`data(trackMixColor)`,"source-arrow-color":`data(trackMixColor)`,width:5}},{selector:`node.track-mixed`,style:{"border-color":`data(trackMixColor)`,"border-width":4}},{selector:`node.track-mixed.track-root, node.track-mixed.track2-root`,style:{"border-width":6,"background-color":`data(trackMixFill)`}},{selector:`.hidden`,style:{display:`none`}}]}var J=`ALL`;function Y({id:e,options:t,selectedId:n,onSelect:r,noneLabel:i=J,hiddenIds:a,onToggleVisible:o}){let[s,l]=(0,c.useState)(``),[u,f]=(0,c.useState)(``),[p,m]=(0,c.useState)(!1),[h,g]=(0,c.useState)(0),_=(0,c.useRef)(null),v=(0,c.useRef)(null),y=t.find(e=>e.id===n)?.label??``,[b,x]=(0,c.useState)(null);b!==y&&(x(y),l(y));let S=u.trim().toLowerCase(),C=S?t.filter(e=>e.label.toLowerCase().includes(S)):t,w={id:``,label:i},T=!S||i.toLowerCase().includes(S)?[w,...C]:C,E=()=>{f(``),g(0),m(!0)},D=()=>{m(!1),f(``),l(y)},O=e=>{r(e.id),l(e.id?e.label:``),f(``),m(!1)};return(0,c.useEffect)(()=>{if(!p)return;let e=e=>{_.current?.contains(e.target)||D()};return document.addEventListener(`mousedown`,e),()=>document.removeEventListener(`mousedown`,e)}),(0,c.useEffect)(()=>{v.current?.children[h]?.scrollIntoView({block:`nearest`})},[h,p]),(0,d.jsxs)(`div`,{className:`node-search`,ref:_,children:[(0,d.jsx)(`input`,{id:e,type:`text`,value:s,placeholder:`-- type to search --`,autoComplete:`off`,onChange:e=>{l(e.target.value),f(e.target.value),g(0),m(!0)},onFocus:e=>{e.target.select(),E()},onClick:()=>{p||E()},onKeyDown:e=>{if(e.key===`ArrowDown`)e.preventDefault(),p||m(!0),g(e=>Math.min(e+1,T.length-1));else if(e.key===`ArrowUp`)e.preventDefault(),g(e=>Math.max(e-1,0));else if(e.key===`Enter`&&p){let t=T[h];t&&(e.preventDefault(),O(t))}else e.key===`Escape`&&D()}}),s&&(0,d.jsx)(`button`,{type:`button`,className:`node-search-clear`,"aria-label":`Clear`,onClick:()=>{r(``),l(``),f(``)},children:`×`}),p&&(0,d.jsx)(`ul`,{className:`node-search-list`,ref:v,role:`listbox`,children:T.length===0?(0,d.jsx)(`li`,{className:`node-search-empty`,role:`option`,"aria-selected":`false`,"aria-disabled":`true`,children:`no match`}):T.map((e,t)=>(0,d.jsxs)(`li`,{role:`option`,"aria-selected":t===h,className:[t===h&&`active`,a?.has(e.id)&&`off`].filter(Boolean).join(` `)||void 0,onMouseDown:t=>{t.preventDefault(),O(e)},onMouseEnter:()=>g(t),children:[o&&e.id&&(0,d.jsx)(`input`,{type:`checkbox`,checked:!a?.has(e.id),"aria-label":`Show ${e.label}`,onMouseDown:e=>{e.preventDefault(),e.stopPropagation()},onClick:e=>e.stopPropagation(),onChange:()=>o(e.id)}),e.label]},e.id||`__none__`))})]})}function X(e={},t=[],n=null,r={}){let i=Array.isArray(n)?n:null,a=n!==null&&!Array.isArray(n)?n:r,o=i!==null&&i.length>0,{selectedColor:s=f,parentsColor:u=p,childrenColor:b=m,track2ParentsColor:x=h,track2ChildrenColor:S=g,commonColor:k=_,topControlsFontSize:A=v,rightDisplayFontSize:j=y,layoutColumns:M=10}=a,N=q({selectedColor:s,parentsColor:u,childrenColor:b,track2ParentsColor:x,track2ChildrenColor:S}),F={"--rbg-parents-color":u,"--rbg-children-color":b},te={"--rbg-parents-color":x,"--rbg-children-color":S},R=B(e,t,i!==null&&o?i.flat():[]),H=i!==null&&o?L(i):z(R,M);function G(){let e=(0,c.useRef)(null),t=(0,c.useRef)(null),n=(0,c.useId)(),[r,i]=(0,c.useState)([]),[o,s]=(0,c.useState)(``),[u,f]=(0,c.useState)(0),[p,m]=(0,c.useState)(``),[h,g]=(0,c.useState)(`parents`),[_,v]=(0,c.useState)(``),[y,b]=(0,c.useState)(`parents`),[x,S]=(0,c.useState)(!0),[M,L]=(0,c.useState)(!0),[z,B]=(0,c.useState)(null),[G,K]=(0,c.useState)(null),[q,J]=(0,c.useState)(`top`),[X,se]=(0,c.useState)({top:0,right:0,graph:0}),[Z,ce]=(0,c.useState)(!1),Q=(0,c.useRef)(!1);(0,c.useEffect)(()=>{Q.current=Z},[Z]);let[$,le]=(0,c.useState)(()=>new Set);(0,c.useEffect)(()=>{let n=e.current;if(!n)return;let r=(0,l.default)({container:n,elements:ie(R,x,M),style:N,layout:{name:`preset`,fit:!1}});r.on(`cxttap`,P,e=>{let t=W(V(e.target,Q.current)),{clientX:n,clientY:r}=e.originalEvent;B({x:n,y:r,copyText:t})}),r.on(`dbltap`,P,e=>{K(V(e.target,Q.current))}),r.on(`tap cxttap`,e=>{e.target===r&&B(null)}),r.on(`tap`,`node`,()=>B(null)),r.on(`viewport`,()=>B(null));let o=e=>e.preventDefault();return n.addEventListener(`contextmenu`,o),re(r,H,a),requestAnimationFrame(()=>r.resize()),i(r.nodes(P).map(e=>({id:e.id(),label:e.data(`displayLabel`)})).sort((e,t)=>I(e.label,t.label))),t.current=r,()=>{n.removeEventListener(`contextmenu`,o),B(null),r.destroy(),t.current=null}},[x,M]),(0,c.useEffect)(()=>{let e=t.current;if(!e)return;let n=X.graph;e.batch(()=>{e.nodes(P).forEach(e=>{let t=D+n,{width:r,height:i}=ne(e.data(`graphLabel`),t);e.style({"font-size":t,width:r,height:i})}),e.nodes(`:parent`).style(`font-size`,O+n)})},[X.graph,x,M]),(0,c.useEffect)(()=>{if(!z)return;let e=e=>{e.target.closest(`.node-context-menu`)||B(null)},t=e=>{e.key===`Escape`&&B(null)};return document.addEventListener(`mousedown`,e),document.addEventListener(`keydown`,t),()=>{document.removeEventListener(`mousedown`,e),document.removeEventListener(`keydown`,t)}},[z]);let ue=()=>{if(z===null)return;let{copyText:e}=z;B(null),navigator.clipboard.writeText(e).catch(e=>{console.error(`Failed to copy:`,e)})},de=()=>{t.current&&C(t.current)},fe=e=>{le(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},pe=e=>{let n=t.current?.getElementById(e);n&&!n.empty()&&($.has(e)&&fe(e),s(e),K(V(n,Z)))},me=()=>{s(``),K(null),f(e=>e+1)};(0,c.useEffect)(()=>{let e=t.current;e&&e.batch(()=>{e.elements().removeClass(`hidden`),ae(e,$).addClass(`hidden`)})},[$,x,M]),(0,c.useEffect)(()=>{let e=t.current;u&&e&&(e.stop(),e.resize(),e.animate({fit:{eles:e.elements().not(`.hidden`),padding:30}},{duration:400}))},[u]),(0,c.useEffect)(()=>{let e=t.current;if(!e||(e.nodes().removeClass(`selected`),!o))return;let n=e.getElementById(o);n.nonempty()&&(n.addClass(`selected`),e.animate({center:{eles:n},zoom:1.8},{duration:400}))},[o,x,M]),(0,c.useEffect)(()=>{let e=t.current;e&&oe(e,[{id:p,direction:h},{id:_,direction:y}],k)},[p,h,_,y,x,M]),(0,c.useEffect)(()=>{t.current?.resize()},[G!==null]),(0,c.useEffect)(()=>{let e=()=>t.current?.resize();return window.addEventListener(`resize`,e),()=>window.removeEventListener(`resize`,e)},[]);let he=[{n:1,id:p,setId:m,direction:h,setDirection:g,style:void 0},{n:2,id:_,setId:v,direction:y,setDirection:b,style:te}],ge=[{label:`Smaller text`,symbol:`−`,step:-2,atLimit:X[q]<=T},{label:`Larger text`,symbol:`+`,step:w,atLimit:X[q]>=E}];return(0,d.jsxs)(`div`,{className:`rbg-graph`,style:{...F,"--rbg-top-controls-font-size":`calc(${A} + ${X.top}px)`,"--rbg-right-display-font-size":`calc(${j} + ${X.right}px)`},children:[(0,d.jsxs)(`div`,{className:`controls`,children:[(0,d.jsxs)(`span`,{className:`control-group`,children:[(0,d.jsx)(`label`,{htmlFor:`${n}-search`,children:`Node to Display:`}),(0,d.jsx)(Y,{id:`${n}-search`,options:r,selectedId:o,onSelect:e=>e?pe(e):me(),hiddenIds:$,onToggleVisible:fe})]}),(0,d.jsxs)(`label`,{children:[(0,d.jsx)(`input`,{type:`checkbox`,checked:x,onChange:e=>S(e.target.checked)}),`Show Groups`]}),(0,d.jsxs)(`label`,{children:[(0,d.jsx)(`input`,{type:`checkbox`,checked:M,onChange:e=>L(e.target.checked)}),`Add Group to Node Name`]}),he.map(({n:e,id:t,setId:i,direction:a,setDirection:o,style:s})=>(0,d.jsxs)(`span`,{className:`control-group`,style:s,children:[(0,d.jsxs)(`label`,{htmlFor:`${n}-track${e}`,children:[`Show Dependency `,e,`:`]}),(0,d.jsx)(Y,{id:`${n}-track${e}`,options:r,selectedId:t,onSelect:i,noneLabel:`Show Nothing`}),(0,d.jsxs)(`span`,{className:t?`track-switch`:`track-switch disabled`,children:[(0,d.jsx)(`span`,{className:a===`parents`?`parents on`:`parents`,children:`Parents`}),(0,d.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":a===`children`,"aria-label":`Show Dependency ${e}: track children instead of parents`,className:`switch`,disabled:!t,onClick:()=>o(e=>e===`parents`?`children`:`parents`),children:(0,d.jsx)(`span`,{className:`switch-knob`})}),(0,d.jsx)(`span`,{className:a===`children`?`children on`:`children`,children:`Children`})]})]},e)),(0,d.jsxs)(`span`,{className:`help`,children:[(0,d.jsx)(`button`,{type:`button`,className:`help-icon`,"aria-label":`Help`,"aria-describedby":`${n}-help`,children:`?`}),(0,d.jsxs)(`span`,{id:`${n}-help`,role:`tooltip`,className:`help-tooltip`,children:[(0,d.jsx)(`strong`,{children:`Double click`}),` on a node to see its information, parents and children.`,(0,d.jsx)(`br`,{}),(0,d.jsx)(`strong`,{children:`Right click`}),` on a node to save the same information to the clipboard.`]})]}),(0,d.jsxs)(`span`,{className:`font-size-buttons`,children:[(0,d.jsx)(`select`,{"aria-label":`Area whose text size the + and - buttons change`,value:q,onChange:e=>J(e.target.value),children:ee.map(([e,t])=>(0,d.jsx)(`option`,{value:e,children:t},e))}),ge.map(({label:e,symbol:t,step:n,atLimit:r})=>(0,d.jsx)(`button`,{type:`button`,className:`help-icon`,"aria-label":e,disabled:r,onClick:()=>se(e=>({...e,[q]:e[q]+n})),children:t},e))]}),(0,d.jsx)(`button`,{type:`button`,className:`export-svg`,onClick:de,children:`Export SVG`})]}),(0,d.jsxs)(`div`,{className:`graph-area`,children:[(0,d.jsx)(`div`,{ref:e,className:`cy-container`}),G&&(0,d.jsxs)(`aside`,{className:`node-info-panel`,children:[(0,d.jsxs)(`div`,{className:`node-info-header`,children:[(0,d.jsxs)(`h2`,{children:[(0,d.jsx)(`strong`,{children:`Node:`}),` `,G.name]}),(0,d.jsx)(`button`,{type:`button`,onClick:()=>K(null),"aria-label":`Close`,children:`×`})]}),G.group&&(0,d.jsxs)(`p`,{children:[(0,d.jsx)(`strong`,{children:`Group:`}),` `,G.group]}),(0,d.jsxs)(`div`,{className:`track-switch level-switch`,children:[(0,d.jsx)(`span`,{className:Z?``:`parents on`,children:`One level`}),(0,d.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":Z,"aria-label":`Show all levels of parents and children`,className:`switch`,onClick:()=>{let e=!Z;ce(e);let n=t.current?.getElementById(G.id);n&&!n.empty()&&K(V(n,e))},children:(0,d.jsx)(`span`,{className:`switch-knob`})}),(0,d.jsx)(`span`,{className:Z?`children on`:``,children:`All levels`})]}),U(G).map(([e,t])=>(0,d.jsxs)(`section`,{children:[(0,d.jsxs)(`h3`,{children:[e,` (`,t.length,`):`]}),(0,d.jsx)(`ul`,{children:t.map(e=>(0,d.jsx)(`li`,{children:(0,d.jsxs)(`button`,{type:`button`,onClick:()=>pe(e.id),children:[e.name,e.group&&(0,d.jsxs)(`span`,{children:[` (`,e.group,`)`]})]})},e.id))})]},e))]})]}),z&&(0,d.jsx)(`div`,{className:`node-context-menu`,style:{left:z.x,top:z.y},onContextMenu:e=>e.preventDefault(),children:(0,d.jsx)(`button`,{type:`button`,onClick:ue,children:`Save to clipboard`})})]})}return G.displayName=`CytoscapeGraph`,G}exports.NodeSearch=Y,exports.create_graph=X,exports.downloadSvg=C,exports.formatNodeInfo=W,exports.getNodeInfo=V;
3
3
  //# sourceMappingURL=index.cjs.map