@linkdlab/funcnodes_react_flow 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +46 -0
  2. package/package copy.json +63 -0
  3. package/package.json +75 -0
  4. package/public/favicon.ico +0 -0
  5. package/public/index.html +43 -0
  6. package/public/logo192.png +0 -0
  7. package/public/logo512.png +0 -0
  8. package/public/manifest.json +25 -0
  9. package/public/robots.txt +3 -0
  10. package/public/worker_manager +1 -0
  11. package/src/App.css +38 -0
  12. package/src/App.test.tsx +9 -0
  13. package/src/App.tsx +22 -0
  14. package/src/frontend/datarenderer/images.tsx +28 -0
  15. package/src/frontend/datarenderer/index.tsx +53 -0
  16. package/src/frontend/datarenderer/plotly.tsx +82 -0
  17. package/src/frontend/dialog.scss +88 -0
  18. package/src/frontend/dialog.tsx +70 -0
  19. package/src/frontend/edge.scss +15 -0
  20. package/src/frontend/edge.tsx +31 -0
  21. package/src/frontend/funcnodesreactflow.scss +63 -0
  22. package/src/frontend/funcnodesreactflow.tsx +283 -0
  23. package/src/frontend/header/header.scss +48 -0
  24. package/src/frontend/header/index.tsx +268 -0
  25. package/src/frontend/index.tsx +4 -0
  26. package/src/frontend/layout/htmlelements.scss +63 -0
  27. package/src/frontend/lib.scss +157 -0
  28. package/src/frontend/lib.tsx +198 -0
  29. package/src/frontend/node/index.tsx +3 -0
  30. package/src/frontend/node/io/default_input_renderer.tsx +327 -0
  31. package/src/frontend/node/io/default_output_render.tsx +26 -0
  32. package/src/frontend/node/io/handle_renderer.tsx +89 -0
  33. package/src/frontend/node/io/index.tsx +4 -0
  34. package/src/frontend/node/io/io.scss +91 -0
  35. package/src/frontend/node/io/io.tsx +114 -0
  36. package/src/frontend/node/io/nodeinput.tsx +125 -0
  37. package/src/frontend/node/io/nodeoutput.tsx +37 -0
  38. package/src/frontend/node/node.scss +265 -0
  39. package/src/frontend/node/node.tsx +208 -0
  40. package/src/frontend/nodecontextmenu.scss +18 -0
  41. package/src/frontend/utils/colorpicker.scss +37 -0
  42. package/src/frontend/utils/colorpicker.tsx +342 -0
  43. package/src/frontend/utils/jsondata.tsx +19 -0
  44. package/src/frontend/utils/table.scss +22 -0
  45. package/src/frontend/utils/table.tsx +159 -0
  46. package/src/funcnodes/funcnodesworker.ts +455 -0
  47. package/src/funcnodes/index.ts +4 -0
  48. package/src/funcnodes/websocketworker.ts +153 -0
  49. package/src/funcnodes/workermanager.ts +229 -0
  50. package/src/index.css +13 -0
  51. package/src/index.tsx +19 -0
  52. package/src/logo.svg +1 -0
  53. package/src/react-app-env.d.ts +1 -0
  54. package/src/reportWebVitals.ts +15 -0
  55. package/src/setupTests.ts +5 -0
  56. package/src/state/edge.ts +35 -0
  57. package/src/state/fnrfzst.ts +440 -0
  58. package/src/state/index.ts +139 -0
  59. package/src/state/lib.ts +26 -0
  60. package/src/state/node.ts +118 -0
  61. package/src/state/nodespace.ts +151 -0
  62. package/src/state/reactflow.ts +65 -0
  63. package/src/types/lib.d.ts +16 -0
  64. package/src/types/node.d.ts +29 -0
  65. package/src/types/nodeio.d.ts +82 -0
  66. package/src/types/worker.d.ts +56 -0
  67. package/tsconfig.json +20 -0
@@ -0,0 +1,342 @@
1
+ import React, { useEffect, useMemo, useRef, useState } from "react";
2
+ import * as Popover from "@radix-ui/react-popover";
3
+ import convert from "color-convert";
4
+ import "./colorpicker.scss";
5
+
6
+ const parse_colorstring = (colorstring: string): [string, any[]] => {
7
+ // This is a simplified parser and may need adjustments to handle all CSS color formats robustly
8
+ if (colorstring.startsWith("#")) {
9
+ return ["hex", [colorstring]];
10
+ }
11
+
12
+ let matches = colorstring.match(/^(\w+)\(([^)]+)\)$/);
13
+ if (!matches) return ["keyword", [colorstring]];
14
+
15
+ const colortype = matches[1];
16
+ const colordata = matches[2].split(",").map((n) => parseInt(n.trim()));
17
+
18
+ return [colortype, colordata];
19
+ };
20
+
21
+ const create_color_converter = (
22
+ type: string,
23
+ data: any[]
24
+ ): { [key: string]: () => number[] | string } => {
25
+ if (!Array.isArray(data)) data = [data];
26
+ if (data[0] === undefined || data[0] === null)
27
+ return create_color_converter("rgb", [0, 0, 0]);
28
+ // @ts-ignore
29
+ const source = convert[type];
30
+ if (!source) throw new Error("Unsupported color type: " + type);
31
+
32
+ source[type] = () => data;
33
+
34
+ const checkrgb = source.rgb(data);
35
+ if (!Array.isArray(checkrgb)) return create_color_converter("rgb", [0, 0, 0]);
36
+ if (checkrgb[0] === undefined || checkrgb[0] === null)
37
+ return create_color_converter("rgb", [0, 0, 0]);
38
+
39
+ const checkhsl = source.hsl(data);
40
+ if (!Array.isArray(checkhsl)) return create_color_converter("rgb", [0, 0, 0]);
41
+ if (checkhsl[0] === undefined || checkhsl[0] === null)
42
+ return create_color_converter("rgb", [0, 0, 0]);
43
+
44
+ const converter: { [key: string]: () => number[] | string } = {};
45
+
46
+ Object.keys(source).forEach((key) => {
47
+ const entry = source[key];
48
+ //check if entry is a function
49
+ if (typeof entry === "function") {
50
+ converter[key] = () => entry.apply(null, data);
51
+ }
52
+ });
53
+
54
+ return converter;
55
+ };
56
+ const create_color_converter_from_string = (
57
+ colorstring: string
58
+ ): { [key: string]: () => number[] | string } => {
59
+ const [colortype, colordata] = parse_colorstring(colorstring);
60
+ // @ts-ignore
61
+ if (!colortype || !convert[colortype]) {
62
+ console.error("Unsupported color type or invalid color string");
63
+ return {};
64
+ }
65
+
66
+ return create_color_converter(colortype, colordata);
67
+ };
68
+
69
+ const HSLColorPicker = ({
70
+ onChange,
71
+ colorconverter,
72
+ }: {
73
+ onChange: (colorconverter: {
74
+ [key: string]: () => number[] | string;
75
+ }) => void;
76
+ colorconverter: { [key: string]: () => number[] | string };
77
+ }) => {
78
+ const [converter, setConverter] = useState(colorconverter);
79
+ const hsl = converter.hsl() as number[];
80
+ const rgb = converter.rgb() as number[];
81
+ const hsv = converter.hsv() as number[];
82
+ const hex = converter.hex() as string;
83
+
84
+ const colorStyle = {
85
+ backgroundColor: `hsl(${hsl[0]}, ${hsl[1]}%, ${hsl[2]}%)`,
86
+ padding: "10px",
87
+ margin: "10px 0",
88
+ };
89
+
90
+ let g = "linear-gradient(to right";
91
+ for (let i = 0; i <= 360; i += 10) {
92
+ g += `, hsl(${i}, 100%, 50%)`;
93
+ }
94
+ g += ")";
95
+ const hueStyle = {
96
+ backgroundImage: "unset",
97
+ WebkitAppearance: "none" as any,
98
+ background: g,
99
+ height: 10,
100
+ borderRadius: 5,
101
+ };
102
+
103
+ return (
104
+ <div style={{ backgroundColor: "white" }}>
105
+ <div style={colorStyle}>Color Preview</div>
106
+ <div className="colorspace">
107
+ <div className="colorspace_title">RGB</div>
108
+ <div></div>
109
+
110
+ <label>Red</label>
111
+ <input
112
+ type="range"
113
+ min="0"
114
+ max="255"
115
+ value={rgb[0]}
116
+ onChange={(e) => {
117
+ const newrgb = [parseInt(e.target.value), rgb[1], rgb[2]];
118
+ const newconverter = create_color_converter("rgb", newrgb);
119
+ setConverter(newconverter);
120
+ onChange(newconverter);
121
+ }}
122
+ style={{ background: `linear-gradient(to right, #000, #f00)` }}
123
+ />
124
+
125
+ <label>Green</label>
126
+ <input
127
+ type="range"
128
+ min="0"
129
+ max="255"
130
+ value={rgb[1]}
131
+ onChange={(e) => {
132
+ const newrgb = [rgb[0], parseInt(e.target.value), rgb[2]];
133
+ const newconverter = create_color_converter("rgb", newrgb);
134
+ setConverter(newconverter);
135
+ onChange(newconverter);
136
+ }}
137
+ style={{ background: `linear-gradient(to right, #000, #0f0)` }}
138
+ />
139
+
140
+ <label>Blue</label>
141
+ <input
142
+ type="range"
143
+ min="0"
144
+ max="255"
145
+ value={rgb[2]}
146
+ onChange={(e) => {
147
+ const newrgb = [rgb[0], rgb[1], parseInt(e.target.value)];
148
+ const newconverter = create_color_converter("rgb", newrgb);
149
+ setConverter(newconverter);
150
+ onChange(newconverter);
151
+ }}
152
+ style={{ background: `linear-gradient(to right, #000, #00f)` }}
153
+ />
154
+ </div>
155
+ <div className="colorspace">
156
+ <div className="colorspace_title">HSL</div>
157
+ <div></div>
158
+
159
+ <label>Hue</label>
160
+ <input
161
+ type="range"
162
+ min="0"
163
+ max="360"
164
+ value={hsl[0]}
165
+ onChange={(e) => {
166
+ const newhsl = [parseInt(e.target.value), hsl[1], hsl[2]];
167
+ const newconverter = create_color_converter("hsl", newhsl);
168
+ setConverter(newconverter);
169
+ onChange(newconverter);
170
+ }}
171
+ style={{
172
+ background: `linear-gradient(to right, #f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00)`,
173
+ }}
174
+ />
175
+
176
+ <label>Saturation</label>
177
+ <input
178
+ type="range"
179
+ min="0"
180
+ max="100"
181
+ value={hsl[1]}
182
+ onChange={(e) => {
183
+ const newhsl = [hsl[0], parseInt(e.target.value), hsl[2]];
184
+ const newconverter = create_color_converter("hsl", newhsl);
185
+ setConverter(newconverter);
186
+ onChange(newconverter);
187
+ }}
188
+ style={{
189
+ background: `linear-gradient(to right, #fff, hsl(${hsl[0]}, 100%, 50%))`,
190
+ }}
191
+ />
192
+
193
+ <label>Lightness</label>
194
+
195
+ <input
196
+ type="range"
197
+ min="0"
198
+ max="100"
199
+ value={hsl[2]}
200
+ onChange={(e) => {
201
+ const newhsl = [hsl[0], hsl[1], parseInt(e.target.value)];
202
+ const newconverter = create_color_converter("hsl", newhsl);
203
+ setConverter(newconverter);
204
+ onChange(newconverter);
205
+ }}
206
+ style={{
207
+ background: `linear-gradient(to right, #000, hsl(${hsl[0]}, 100%, 50%), #fff)`,
208
+ }}
209
+ />
210
+ </div>
211
+
212
+ <div className="colorspace">
213
+ <div className="colorspace_title">HSV</div>
214
+ <div></div>
215
+
216
+ <label>Hue</label>
217
+ <input
218
+ type="range"
219
+ min="0"
220
+ max="360"
221
+ value={hsv[0]}
222
+ onChange={(e) => {
223
+ const newhsv = [parseInt(e.target.value), hsv[1], hsv[2]];
224
+ const newconverter = create_color_converter("hsv", newhsv);
225
+ setConverter(newconverter);
226
+ onChange(newconverter);
227
+ }}
228
+ style={{
229
+ background: `linear-gradient(to right, #f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00)`,
230
+ }}
231
+ />
232
+
233
+ <label>Saturation</label>
234
+ <input
235
+ type="range"
236
+ min="0"
237
+ max="100"
238
+ value={hsv[1]}
239
+ onChange={(e) => {
240
+ const newhsv = [hsv[0], parseInt(e.target.value), hsv[2]];
241
+ const newconverter = create_color_converter("hsv", newhsv);
242
+ setConverter(newconverter);
243
+ onChange(newconverter);
244
+ }}
245
+ style={{
246
+ background: `linear-gradient(to right, #fff, hsl(${hsl[0]}, 100%, 50%))`,
247
+ }}
248
+ />
249
+
250
+ <label>Value</label>
251
+ <input
252
+ type="range"
253
+ min="0"
254
+ max="100"
255
+ value={hsv[2]}
256
+ onChange={(e) => {
257
+ const newhsv = [hsv[0], hsv[1], parseInt(e.target.value)];
258
+ const newconverter = create_color_converter("hsv", newhsv);
259
+ setConverter(newconverter);
260
+ onChange(newconverter);
261
+ }}
262
+ style={{
263
+ background: `linear-gradient(to right, #000, hsl(${hsl[0]}, 100%, 50%))`,
264
+ }}
265
+ />
266
+ </div>
267
+
268
+ <div className="colorspace">
269
+ <div className="colorspace_title">HEX</div>
270
+ <div></div>
271
+
272
+ <input
273
+ type="text"
274
+ value={hex}
275
+ onChange={(e) => {
276
+ const newconverter = create_color_converter("hex", [
277
+ e.target.value,
278
+ ]);
279
+ setConverter(newconverter);
280
+ onChange(newconverter);
281
+ }}
282
+ />
283
+ </div>
284
+ </div>
285
+ );
286
+ };
287
+
288
+ const CustomColorPicker = ({
289
+ inicolordata,
290
+ inicolorspace = "hex",
291
+ onChange,
292
+ }: {
293
+ inicolordata?: number[] | string | string[];
294
+ inicolorspace?: string;
295
+ onChange?: (colorconverter: {
296
+ [key: string]: () => number[] | string;
297
+ }) => void;
298
+ }) => {
299
+ if (inicolordata === undefined) {
300
+ inicolordata = [0, 0, 0];
301
+ inicolorspace = "rgb";
302
+ }
303
+ if (!Array.isArray(inicolordata)) inicolordata = [inicolordata];
304
+
305
+ let iniconverter = create_color_converter(inicolorspace, inicolordata);
306
+
307
+ if (iniconverter.rgb() === undefined)
308
+ iniconverter = create_color_converter("rgb", [0, 0, 0]);
309
+ const [color, setColor] = useState(iniconverter);
310
+
311
+ const innerSetColor = (colorconverter: {
312
+ [key: string]: () => number[] | string;
313
+ }) => {
314
+ setColor(colorconverter);
315
+ if (onChange) onChange(colorconverter);
316
+ };
317
+
318
+ const style = {
319
+ background: "#" + color.hex(),
320
+ borderRadius: "0.3rem",
321
+ width: "2rem",
322
+ height: "1rem",
323
+ };
324
+ return (
325
+ <Popover.Root>
326
+ <Popover.Trigger asChild>
327
+ <button style={style}></button>
328
+ </Popover.Trigger>
329
+ <Popover.Portal>
330
+ <Popover.Content side="left">
331
+ <HSLColorPicker
332
+ onChange={innerSetColor}
333
+ colorconverter={color}
334
+ ></HSLColorPicker>
335
+ </Popover.Content>
336
+ </Popover.Portal>
337
+ </Popover.Root>
338
+ );
339
+ };
340
+
341
+ export default CustomColorPicker;
342
+ export { HSLColorPicker };
@@ -0,0 +1,19 @@
1
+ import {
2
+ JsonView,
3
+ allExpanded,
4
+ darkStyles,
5
+ defaultStyles,
6
+ collapseAllNested,
7
+ } from "react-json-view-lite";
8
+ import "react-json-view-lite/dist/index.css";
9
+ const JSONDataDisplay = ({ data }: { data: any }) => {
10
+ return (
11
+ <JsonView
12
+ data={data}
13
+ style={darkStyles}
14
+ shouldExpandNode={collapseAllNested}
15
+ />
16
+ );
17
+ };
18
+
19
+ export default JSONDataDisplay;
@@ -0,0 +1,22 @@
1
+ .tablecontainer {
2
+ overflow: auto;
3
+ background-color: white;
4
+ }
5
+ .tableHead {
6
+ color: var(--funheadercolor) !important;
7
+ background-color: var(--funcnodesbackground1);
8
+ font-weight: bold !important;
9
+ }
10
+
11
+ .tableheadercolor {
12
+ color: inherit !important;
13
+ font-family: inherit !important;
14
+ font-weight: inherit !important;
15
+ }
16
+
17
+ .indexcol {
18
+ background-color: var(--funcnodesbackground2);
19
+ color: var(--funheadercolor) !important;
20
+ font-family: inherit !important;
21
+ font-weight: inherit !important;
22
+ }
@@ -0,0 +1,159 @@
1
+ import Table from "@mui/material/Table";
2
+ import TableBody from "@mui/material/TableBody";
3
+ import TableCell, { SortDirection } from "@mui/material/TableCell";
4
+ import TableContainer from "@mui/material/TableContainer";
5
+ import TableHead from "@mui/material/TableHead";
6
+ import TableRow from "@mui/material/TableRow";
7
+ import TableSortLabel from "@mui/material/TableSortLabel";
8
+
9
+ import { useMemo, useState } from "react";
10
+
11
+ import "./table.scss";
12
+
13
+ interface TableData {
14
+ columns: string[];
15
+ index: string[];
16
+ data: any[][];
17
+ }
18
+
19
+ type comparertype = (a: any, b: any) => 1 | -1 | 0;
20
+ type _SD = "asc" | "desc";
21
+
22
+ interface TransFormedTableData {
23
+ header: string[];
24
+ rows: any[][];
25
+ }
26
+
27
+ const transform_table_data = (data: TableData): TransFormedTableData => {
28
+ const rows = [];
29
+ if (data === undefined) {
30
+ // return empty table if data is undefined
31
+ return {
32
+ header: [],
33
+ rows: [],
34
+ };
35
+ }
36
+ if (data.data === undefined) {
37
+ // if data.data is undefined, make it empty
38
+ data.data = [];
39
+ }
40
+
41
+ if (data.columns === undefined) {
42
+ // if np columns are defined, create columns based on the first row
43
+
44
+ // if data is empty, there are no columns
45
+ if (data.data.length === 0) {
46
+ data.columns = [];
47
+ } else {
48
+ // create columns based on the first row
49
+ data.columns = data.data[0].map((_, i) => `col${i}`);
50
+ }
51
+ }
52
+ if (data.index === undefined) {
53
+ // if no index is defined, create index based on the number of rows
54
+ data.index = data.data.map((_, i) => `row${i}`);
55
+ }
56
+
57
+ for (let i = 0; i < data.index.length; i++) {
58
+ const row = [data.index[i]];
59
+ for (let j = 0; j < data.columns.length; j++) {
60
+ row.push(data.data[i][j]);
61
+ }
62
+ rows.push(row);
63
+ }
64
+ return {
65
+ header: ["index", ...data.columns],
66
+ rows: rows,
67
+ };
68
+ };
69
+
70
+ function SortableTable({ tabledata }: { tabledata: TableData }) {
71
+ // State to manage the sorted column and direction
72
+ const transformed_table_data: TransFormedTableData = useMemo(
73
+ () => transform_table_data(tabledata),
74
+ [tabledata]
75
+ );
76
+ const [orderDirection, setOrderDirection] = useState<_SD>("asc");
77
+ const [orderBy, setOrderBy] = useState("index");
78
+
79
+ let order_by_index = transformed_table_data.header.indexOf(orderBy);
80
+ if (order_by_index === -1) {
81
+ order_by_index = 0;
82
+ }
83
+
84
+ // Function to handle sorting
85
+ const handleSort = (column: string) => {
86
+ const isAsc = orderBy === column && orderDirection === "asc";
87
+ setOrderDirection(isAsc ? "desc" : "asc");
88
+ setOrderBy(column);
89
+ };
90
+ // Function to sort data
91
+ const sortData = (data: any[][], comparator: comparertype) => {
92
+ const stabilizedThis: [any[], number][] = data.map((el, index) => [
93
+ el,
94
+ index,
95
+ ]);
96
+ stabilizedThis.sort((a, b) => {
97
+ const order = comparator(a[0], b[0]);
98
+ return order;
99
+ });
100
+ return stabilizedThis.map((el) => el[0]);
101
+ };
102
+
103
+ // Comparator function for sorting
104
+ const getComparator = (order: _SD, orderBy: string): comparertype => {
105
+ return order === "desc"
106
+ ? (a, b) => (b[order_by_index] < a[order_by_index] ? -1 : 1)
107
+ : (a, b) => (a[order_by_index] < b[order_by_index] ? -1 : 1);
108
+ };
109
+
110
+ // Sort the rows
111
+ const sortedRows = sortData(
112
+ transformed_table_data.rows,
113
+ getComparator(orderDirection, orderBy)
114
+ );
115
+ return (
116
+ <TableContainer className="tablecontainer">
117
+ <Table size="small">
118
+ <TableHead className="tableHead">
119
+ <TableRow className="tableheadercolor">
120
+ {transformed_table_data.header.map((column) => (
121
+ <TableCell
122
+ key={column}
123
+ sortDirection={orderBy === column ? orderDirection : false}
124
+ className="tableheadercolor"
125
+ >
126
+ <TableSortLabel
127
+ active={orderBy === column}
128
+ direction={orderBy === column ? orderDirection : "asc"}
129
+ onClick={() => handleSort(column)}
130
+ className="tableheadercolor"
131
+ sx={{
132
+ "& .MuiTableSortLabel-icon": {
133
+ color: "inherit !important",
134
+ },
135
+ }}
136
+ >
137
+ {column}
138
+ </TableSortLabel>
139
+ </TableCell>
140
+ ))}
141
+ </TableRow>
142
+ </TableHead>
143
+ <TableBody>
144
+ {sortedRows.map((row, index) => (
145
+ <TableRow key={tabledata.index[index]}>
146
+ {row.map((cell, i) => (
147
+ <TableCell key={i} className={i == 0 ? "indexcol" : "datacol"}>
148
+ {cell}
149
+ </TableCell>
150
+ ))}
151
+ </TableRow>
152
+ ))}
153
+ </TableBody>
154
+ </Table>
155
+ </TableContainer>
156
+ );
157
+ }
158
+
159
+ export { SortableTable };