@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.
- package/README.md +46 -0
- package/package copy.json +63 -0
- package/package.json +75 -0
- package/public/favicon.ico +0 -0
- package/public/index.html +43 -0
- package/public/logo192.png +0 -0
- package/public/logo512.png +0 -0
- package/public/manifest.json +25 -0
- package/public/robots.txt +3 -0
- package/public/worker_manager +1 -0
- package/src/App.css +38 -0
- package/src/App.test.tsx +9 -0
- package/src/App.tsx +22 -0
- package/src/frontend/datarenderer/images.tsx +28 -0
- package/src/frontend/datarenderer/index.tsx +53 -0
- package/src/frontend/datarenderer/plotly.tsx +82 -0
- package/src/frontend/dialog.scss +88 -0
- package/src/frontend/dialog.tsx +70 -0
- package/src/frontend/edge.scss +15 -0
- package/src/frontend/edge.tsx +31 -0
- package/src/frontend/funcnodesreactflow.scss +63 -0
- package/src/frontend/funcnodesreactflow.tsx +283 -0
- package/src/frontend/header/header.scss +48 -0
- package/src/frontend/header/index.tsx +268 -0
- package/src/frontend/index.tsx +4 -0
- package/src/frontend/layout/htmlelements.scss +63 -0
- package/src/frontend/lib.scss +157 -0
- package/src/frontend/lib.tsx +198 -0
- package/src/frontend/node/index.tsx +3 -0
- package/src/frontend/node/io/default_input_renderer.tsx +327 -0
- package/src/frontend/node/io/default_output_render.tsx +26 -0
- package/src/frontend/node/io/handle_renderer.tsx +89 -0
- package/src/frontend/node/io/index.tsx +4 -0
- package/src/frontend/node/io/io.scss +91 -0
- package/src/frontend/node/io/io.tsx +114 -0
- package/src/frontend/node/io/nodeinput.tsx +125 -0
- package/src/frontend/node/io/nodeoutput.tsx +37 -0
- package/src/frontend/node/node.scss +265 -0
- package/src/frontend/node/node.tsx +208 -0
- package/src/frontend/nodecontextmenu.scss +18 -0
- package/src/frontend/utils/colorpicker.scss +37 -0
- package/src/frontend/utils/colorpicker.tsx +342 -0
- package/src/frontend/utils/jsondata.tsx +19 -0
- package/src/frontend/utils/table.scss +22 -0
- package/src/frontend/utils/table.tsx +159 -0
- package/src/funcnodes/funcnodesworker.ts +455 -0
- package/src/funcnodes/index.ts +4 -0
- package/src/funcnodes/websocketworker.ts +153 -0
- package/src/funcnodes/workermanager.ts +229 -0
- package/src/index.css +13 -0
- package/src/index.tsx +19 -0
- package/src/logo.svg +1 -0
- package/src/react-app-env.d.ts +1 -0
- package/src/reportWebVitals.ts +15 -0
- package/src/setupTests.ts +5 -0
- package/src/state/edge.ts +35 -0
- package/src/state/fnrfzst.ts +440 -0
- package/src/state/index.ts +139 -0
- package/src/state/lib.ts +26 -0
- package/src/state/node.ts +118 -0
- package/src/state/nodespace.ts +151 -0
- package/src/state/reactflow.ts +65 -0
- package/src/types/lib.d.ts +16 -0
- package/src/types/node.d.ts +29 -0
- package/src/types/nodeio.d.ts +82 -0
- package/src/types/worker.d.ts +56 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
import { useContext, useEffect, useRef, useState } from "react";
|
|
2
|
+
import { FuncNodesReactFlowZustandInterface } from "../../../state";
|
|
3
|
+
|
|
4
|
+
import { FuncNodesContext } from "../../funcnodesreactflow";
|
|
5
|
+
import CustomColorPicker from "../../utils/colorpicker";
|
|
6
|
+
|
|
7
|
+
const BooleanInput = ({ io, inputconverter }: InputRendererProps) => {
|
|
8
|
+
const fnrf_zst: FuncNodesReactFlowZustandInterface =
|
|
9
|
+
useContext(FuncNodesContext);
|
|
10
|
+
|
|
11
|
+
const indeterminate = io.value === undefined;
|
|
12
|
+
const cRef = useRef<HTMLInputElement>(null);
|
|
13
|
+
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
if (!cRef.current) return;
|
|
16
|
+
cRef.current.indeterminate = indeterminate;
|
|
17
|
+
}, [cRef, indeterminate]);
|
|
18
|
+
|
|
19
|
+
const on_change = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
20
|
+
let new_value: boolean = e.target.checked;
|
|
21
|
+
try {
|
|
22
|
+
new_value = inputconverter(e.target.checked);
|
|
23
|
+
} catch (e) {}
|
|
24
|
+
fnrf_zst.worker?.set_io_value({
|
|
25
|
+
nid: io.node,
|
|
26
|
+
ioid: io.id,
|
|
27
|
+
value: new_value,
|
|
28
|
+
set_default: io.render_options?.set_default || false,
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
return (
|
|
32
|
+
<input
|
|
33
|
+
ref={cRef}
|
|
34
|
+
type="checkbox"
|
|
35
|
+
className="styledcheckbox"
|
|
36
|
+
checked={!!io.value}
|
|
37
|
+
onChange={on_change}
|
|
38
|
+
disabled={io.connected}
|
|
39
|
+
/>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
const NumberInput = ({
|
|
43
|
+
io,
|
|
44
|
+
inputconverter,
|
|
45
|
+
parser = (n: string) => parseFloat(n),
|
|
46
|
+
}: InputRendererProps & {
|
|
47
|
+
parser: (n: string) => number;
|
|
48
|
+
}) => {
|
|
49
|
+
const fnrf_zst: FuncNodesReactFlowZustandInterface =
|
|
50
|
+
useContext(FuncNodesContext);
|
|
51
|
+
|
|
52
|
+
const [tempvalue, setTempValue] = useState(io.value);
|
|
53
|
+
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
setTempValue(io.value);
|
|
56
|
+
}, [io.value]);
|
|
57
|
+
|
|
58
|
+
const set_new_value = (new_value: number | string) => {
|
|
59
|
+
new_value = parser(
|
|
60
|
+
parseFloat(new_value.toString()).toString() // parse float for e notation
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
if (isNaN(new_value)) {
|
|
64
|
+
new_value = "<NoValue>";
|
|
65
|
+
setTempValue("");
|
|
66
|
+
} else {
|
|
67
|
+
setTempValue(new_value.toString());
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
new_value = inputconverter(new_value);
|
|
71
|
+
} catch (e) {}
|
|
72
|
+
|
|
73
|
+
fnrf_zst.worker?.set_io_value({
|
|
74
|
+
nid: io.node,
|
|
75
|
+
ioid: io.id,
|
|
76
|
+
value: new_value,
|
|
77
|
+
set_default: io.render_options?.set_default || false,
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const on_change = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
82
|
+
set_new_value(e.target.value);
|
|
83
|
+
};
|
|
84
|
+
const v = io.connected ? io.value : tempvalue;
|
|
85
|
+
return (
|
|
86
|
+
<input
|
|
87
|
+
type="text"
|
|
88
|
+
className="nodedatainput styledinput"
|
|
89
|
+
value={v || ""}
|
|
90
|
+
onChange={(e) => setTempValue(e.target.value)}
|
|
91
|
+
onBlur={on_change}
|
|
92
|
+
onKeyDown={(e) => {
|
|
93
|
+
// on key up add step to value
|
|
94
|
+
|
|
95
|
+
if (e.key === "ArrowUp") {
|
|
96
|
+
let step = io.render_options?.step || 1;
|
|
97
|
+
if (e.shiftKey) step *= 10;
|
|
98
|
+
|
|
99
|
+
let new_value = (parseFloat(v) || 0) + step;
|
|
100
|
+
// setTempValue(new_value.toString());
|
|
101
|
+
set_new_value(new_value);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// on key down subtract step to value
|
|
106
|
+
if (e.key === "ArrowDown") {
|
|
107
|
+
let step = io.render_options?.step || 1;
|
|
108
|
+
if (e.shiftKey) step *= 10;
|
|
109
|
+
let new_value = (parseFloat(v) || 0) - step;
|
|
110
|
+
// setTempValue(new_value.toString());
|
|
111
|
+
set_new_value(new_value);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
//accept only numbers
|
|
116
|
+
if (
|
|
117
|
+
!/^[0-9.eE+-]$/.test(e.key) &&
|
|
118
|
+
!["Backspace", "ArrowLeft", "ArrowRight", "Delete", "Tab"].includes(
|
|
119
|
+
e.key
|
|
120
|
+
)
|
|
121
|
+
) {
|
|
122
|
+
e.preventDefault();
|
|
123
|
+
}
|
|
124
|
+
}}
|
|
125
|
+
disabled={io.connected}
|
|
126
|
+
step={io.render_options?.step}
|
|
127
|
+
min={io.value_options?.min}
|
|
128
|
+
/>
|
|
129
|
+
);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const FloatInput = ({ io, inputconverter }: InputRendererProps) => {
|
|
133
|
+
return NumberInput({ io, inputconverter, parser: parseFloat });
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const IntegerInput = ({ io, inputconverter }: InputRendererProps) => {
|
|
137
|
+
return NumberInput({ io, inputconverter, parser: parseInt });
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const StringInput = ({ io, inputconverter }: InputRendererProps) => {
|
|
141
|
+
const fnrf_zst: FuncNodesReactFlowZustandInterface =
|
|
142
|
+
useContext(FuncNodesContext);
|
|
143
|
+
|
|
144
|
+
const [tempvalue, setTempValue] = useState(io.value);
|
|
145
|
+
|
|
146
|
+
const on_change = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
147
|
+
let new_value: string = e.target.value;
|
|
148
|
+
try {
|
|
149
|
+
new_value = inputconverter(new_value);
|
|
150
|
+
} catch (e) {}
|
|
151
|
+
|
|
152
|
+
if (!new_value) new_value = "<NoValue>";
|
|
153
|
+
|
|
154
|
+
fnrf_zst.worker?.set_io_value({
|
|
155
|
+
nid: io.node,
|
|
156
|
+
ioid: io.id,
|
|
157
|
+
value: new_value,
|
|
158
|
+
set_default: io.render_options?.set_default || false,
|
|
159
|
+
});
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
return (
|
|
163
|
+
<input
|
|
164
|
+
className="nodedatainput styledinput"
|
|
165
|
+
value={io.connected ? io.value : tempvalue}
|
|
166
|
+
onChange={(e) => setTempValue(e.target.value)}
|
|
167
|
+
onBlur={on_change}
|
|
168
|
+
disabled={io.connected}
|
|
169
|
+
/>
|
|
170
|
+
);
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
const _parse_string = (s: string) => s;
|
|
174
|
+
const _parse_number = (s: string) => parseFloat(s);
|
|
175
|
+
const _parse_boolean = (s: string) => !!s;
|
|
176
|
+
const _parse_null = (s: string) => (s === "null" ? null : s);
|
|
177
|
+
|
|
178
|
+
const get_parser = (datatype: string | null) => {
|
|
179
|
+
if (datatype === "nuinputconvertermber") {
|
|
180
|
+
return _parse_number;
|
|
181
|
+
}
|
|
182
|
+
if (datatype === "boolean") {
|
|
183
|
+
return _parse_boolean;
|
|
184
|
+
}
|
|
185
|
+
if (datatype === "undefined") {
|
|
186
|
+
return _parse_null;
|
|
187
|
+
}
|
|
188
|
+
return _parse_string;
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const SelectionInput = ({
|
|
192
|
+
io,
|
|
193
|
+
inputconverter,
|
|
194
|
+
parser,
|
|
195
|
+
}: InputRendererProps & {
|
|
196
|
+
parser?(s: string): any;
|
|
197
|
+
}) => {
|
|
198
|
+
let options: (string | number)[] | EnumOf = io.value_options?.options || [];
|
|
199
|
+
if (Array.isArray(options)) {
|
|
200
|
+
options = {
|
|
201
|
+
type: "enum",
|
|
202
|
+
values: options,
|
|
203
|
+
keys: options.map((x) => x.toString()),
|
|
204
|
+
nullable: false,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
options = options as EnumOf;
|
|
208
|
+
if (
|
|
209
|
+
options.nullable &&
|
|
210
|
+
!options.values.includes(null) &&
|
|
211
|
+
!options.keys.includes("None")
|
|
212
|
+
) {
|
|
213
|
+
options.values.unshift(null);
|
|
214
|
+
options.keys.unshift("None");
|
|
215
|
+
}
|
|
216
|
+
//make key value pairs
|
|
217
|
+
const optionsmap: [string, string, string][] = [];
|
|
218
|
+
for (let i = 0; i < options.values.length; i++) {
|
|
219
|
+
// set const t to "string", "number","boolean" "null" depenting on the type of options.values[i]
|
|
220
|
+
const t =
|
|
221
|
+
options.values[i] === null || options.values[i] === undefined
|
|
222
|
+
? "undefined"
|
|
223
|
+
: typeof options.values[i];
|
|
224
|
+
let v = options.values[i];
|
|
225
|
+
|
|
226
|
+
if (v === null) {
|
|
227
|
+
v = "null";
|
|
228
|
+
}
|
|
229
|
+
if (v === undefined) {
|
|
230
|
+
v = "undefined";
|
|
231
|
+
}
|
|
232
|
+
optionsmap.push([options.keys[i], v.toString(), t]);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const fnrf_zst: FuncNodesReactFlowZustandInterface =
|
|
236
|
+
useContext(FuncNodesContext);
|
|
237
|
+
|
|
238
|
+
const on_change = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
|
239
|
+
// Find the selected option element
|
|
240
|
+
const selectedOption = e.target.options[e.target.selectedIndex];
|
|
241
|
+
// Retrieve the datatype attribute from the selected option
|
|
242
|
+
const datatype = selectedOption.getAttribute("datatype");
|
|
243
|
+
|
|
244
|
+
// Use the existing parser or get a new one based on the datatype
|
|
245
|
+
const p = parser || get_parser(datatype);
|
|
246
|
+
|
|
247
|
+
let new_value: string | number = p(e.target.value);
|
|
248
|
+
try {
|
|
249
|
+
new_value = inputconverter(e.target.value);
|
|
250
|
+
} catch (e) {}
|
|
251
|
+
|
|
252
|
+
fnrf_zst.worker?.set_io_value({
|
|
253
|
+
nid: io.node,
|
|
254
|
+
ioid: io.id,
|
|
255
|
+
value: p(e.target.value),
|
|
256
|
+
set_default: io.render_options?.set_default || false,
|
|
257
|
+
});
|
|
258
|
+
};
|
|
259
|
+
let v = io.value;
|
|
260
|
+
if (v === null) {
|
|
261
|
+
v = "null";
|
|
262
|
+
}
|
|
263
|
+
if (v === undefined) {
|
|
264
|
+
v = "undefined";
|
|
265
|
+
}
|
|
266
|
+
return (
|
|
267
|
+
<select
|
|
268
|
+
value={v}
|
|
269
|
+
onChange={on_change}
|
|
270
|
+
disabled={io.connected}
|
|
271
|
+
className="nodedatainput styleddropdown"
|
|
272
|
+
>
|
|
273
|
+
<option value="<NoValue>" disabled>
|
|
274
|
+
select
|
|
275
|
+
</option>
|
|
276
|
+
{optionsmap.map((option) => (
|
|
277
|
+
<option key={option[0]} value={option[1]} datatype={option[2]}>
|
|
278
|
+
{option[0]}
|
|
279
|
+
</option>
|
|
280
|
+
))}
|
|
281
|
+
</select>
|
|
282
|
+
);
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
const ColorInput = ({ io, inputconverter }: InputRendererProps) => {
|
|
286
|
+
const fnrf_zst: FuncNodesReactFlowZustandInterface =
|
|
287
|
+
useContext(FuncNodesContext);
|
|
288
|
+
|
|
289
|
+
const colorspace = io.value_options?.colorspace || "hex";
|
|
290
|
+
|
|
291
|
+
const on_change = (colorconverter?: {
|
|
292
|
+
[key: string]: () => number[] | string;
|
|
293
|
+
}) => {
|
|
294
|
+
let new_value: string | number[] = "<NoValue>";
|
|
295
|
+
if (colorconverter) {
|
|
296
|
+
if (colorconverter[colorspace]) new_value = colorconverter[colorspace]();
|
|
297
|
+
else new_value = colorconverter.hex();
|
|
298
|
+
}
|
|
299
|
+
try {
|
|
300
|
+
new_value = new_value;
|
|
301
|
+
} catch (e) {}
|
|
302
|
+
|
|
303
|
+
fnrf_zst.worker?.set_io_value({
|
|
304
|
+
nid: io.node,
|
|
305
|
+
ioid: io.id,
|
|
306
|
+
value: new_value,
|
|
307
|
+
set_default: io.render_options?.set_default || false,
|
|
308
|
+
});
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
return (
|
|
312
|
+
<CustomColorPicker
|
|
313
|
+
onChange={on_change}
|
|
314
|
+
inicolordata={io.value}
|
|
315
|
+
inicolorspace={colorspace}
|
|
316
|
+
/>
|
|
317
|
+
);
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
export {
|
|
321
|
+
FloatInput,
|
|
322
|
+
IntegerInput,
|
|
323
|
+
BooleanInput,
|
|
324
|
+
StringInput,
|
|
325
|
+
SelectionInput,
|
|
326
|
+
ColorInput,
|
|
327
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useContext } from "react";
|
|
2
|
+
import { FuncNodesReactFlowZustandInterface } from "../../../state";
|
|
3
|
+
import { FuncNodesContext } from "../../funcnodesreactflow";
|
|
4
|
+
import { SortableTable } from "../../utils/table";
|
|
5
|
+
import JSONDataDisplay from "../../utils/jsondata";
|
|
6
|
+
import { Base64ImageRenderer } from "../../datarenderer/images";
|
|
7
|
+
|
|
8
|
+
const InLineOutput = ({ io }: { io: IOType }) => {
|
|
9
|
+
const fnrf_zst: FuncNodesReactFlowZustandInterface =
|
|
10
|
+
useContext(FuncNodesContext);
|
|
11
|
+
let value = io.fullvalue;
|
|
12
|
+
if (value == undefined) value = io.value;
|
|
13
|
+
if (value === undefined) {
|
|
14
|
+
value = "";
|
|
15
|
+
} else {
|
|
16
|
+
value = JSON.stringify(io.value).replace(/\\n/g, "\n"); //respect "\n" in strings
|
|
17
|
+
}
|
|
18
|
+
//truncate the string if it is too long
|
|
19
|
+
if (value.length > 63) {
|
|
20
|
+
value = value.slice(0, 60) + "...";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return <div>{value}</div>;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export { InLineOutput };
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { useContext } from "react";
|
|
2
|
+
import { FuncNodesReactFlowZustandInterface } from "../../../state";
|
|
3
|
+
import { FuncNodesContext } from "../../funcnodesreactflow";
|
|
4
|
+
import { pick_best_io_type } from "./io";
|
|
5
|
+
import { SortableTable } from "../../utils/table";
|
|
6
|
+
import JSONDataDisplay from "../../utils/jsondata";
|
|
7
|
+
import { Base64ImageRenderer } from "../../datarenderer/images";
|
|
8
|
+
|
|
9
|
+
const TableOutput = ({ io }: { io: IOType }) => {
|
|
10
|
+
const fnrf_zst: FuncNodesReactFlowZustandInterface =
|
|
11
|
+
useContext(FuncNodesContext);
|
|
12
|
+
|
|
13
|
+
let value = io.fullvalue;
|
|
14
|
+
if (value == undefined) value = io.value;
|
|
15
|
+
if (value === undefined) {
|
|
16
|
+
value = [];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return <SortableTable tabledata={value} />;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const DictOutput = ({ io }: { io: IOType }) => {
|
|
23
|
+
let value = io.fullvalue;
|
|
24
|
+
|
|
25
|
+
if (value === undefined) value = io.value;
|
|
26
|
+
if (value === undefined) {
|
|
27
|
+
value = {};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return <JSONDataDisplay data={value} />;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const Base64ImageOutput = ({ io }: { io: IOType }) => {
|
|
34
|
+
const fnrf_zst: FuncNodesReactFlowZustandInterface =
|
|
35
|
+
useContext(FuncNodesContext);
|
|
36
|
+
|
|
37
|
+
let value = io.fullvalue;
|
|
38
|
+
if (value == undefined) value = io.value;
|
|
39
|
+
if (value === undefined) {
|
|
40
|
+
value = "";
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return <Base64ImageRenderer value={value} />;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const SingleValueOutput = ({ io }: { io: IOType }) => {
|
|
47
|
+
const fnrf_zst: FuncNodesReactFlowZustandInterface =
|
|
48
|
+
useContext(FuncNodesContext);
|
|
49
|
+
|
|
50
|
+
let value = io.fullvalue;
|
|
51
|
+
if (value == undefined) value = io.value;
|
|
52
|
+
if (value === undefined) {
|
|
53
|
+
value = "";
|
|
54
|
+
} else {
|
|
55
|
+
value = JSON.stringify(io.value).replace(/\\n/g, "\n"); //respect "\n" in strings
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<div>
|
|
60
|
+
<pre>{value}</pre>
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const HandlePreviouGenerators: {
|
|
66
|
+
[key: string]: ({ io }: { io: IOType }) => JSX.Element;
|
|
67
|
+
} = {
|
|
68
|
+
string: SingleValueOutput,
|
|
69
|
+
table: TableOutput,
|
|
70
|
+
image: Base64ImageOutput,
|
|
71
|
+
dict: DictOutput,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const PreviewHandleDataRendererForIo = (io: IOType) => {
|
|
75
|
+
const fnrf_zst: FuncNodesReactFlowZustandInterface =
|
|
76
|
+
useContext(FuncNodesContext);
|
|
77
|
+
const render: RenderOptions = fnrf_zst.render_options();
|
|
78
|
+
|
|
79
|
+
const [typestring, otypestring] = pick_best_io_type(
|
|
80
|
+
io.type,
|
|
81
|
+
render.typemap || {}
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
return typestring && HandlePreviouGenerators[typestring]
|
|
85
|
+
? HandlePreviouGenerators[typestring]
|
|
86
|
+
: DictOutput;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export { PreviewHandleDataRendererForIo };
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
s slideUpAndFade {
|
|
2
|
+
from {
|
|
3
|
+
opacity: 0;
|
|
4
|
+
transform: translateY(2px);
|
|
5
|
+
}
|
|
6
|
+
to {
|
|
7
|
+
opacity: 1;
|
|
8
|
+
transform: translateY(0);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@keyframes slideRightAndFade {
|
|
13
|
+
from {
|
|
14
|
+
opacity: 0;
|
|
15
|
+
transform: translateX(-2px);
|
|
16
|
+
}
|
|
17
|
+
to {
|
|
18
|
+
opacity: 1;
|
|
19
|
+
transform: translateX(0);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@keyframes slideDownAndFade {
|
|
24
|
+
from {
|
|
25
|
+
opacity: 0;
|
|
26
|
+
transform: translateY(-2px);
|
|
27
|
+
}
|
|
28
|
+
to {
|
|
29
|
+
opacity: 1;
|
|
30
|
+
transform: translateY(0);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@keyframes slideLeftAndFade {
|
|
35
|
+
from {
|
|
36
|
+
opacity: 0;
|
|
37
|
+
transform: translateX(2px);
|
|
38
|
+
}
|
|
39
|
+
to {
|
|
40
|
+
opacity: 1;
|
|
41
|
+
transform: translateX(0);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.iotooltipcontent {
|
|
46
|
+
background-color: #f9f9f9;
|
|
47
|
+
border: 1px solid #ffffff;
|
|
48
|
+
border-radius: 5px;
|
|
49
|
+
padding: 10px;
|
|
50
|
+
box-shadow: hsl(206 22% 7% / 35%) 0px 10px 38px -10px,
|
|
51
|
+
hsl(206 22% 7% / 20%) 0px 10px 20px -15px;
|
|
52
|
+
font-size: 10px;
|
|
53
|
+
color: #333;
|
|
54
|
+
max-width: 30vw;
|
|
55
|
+
max-height: 30vh;
|
|
56
|
+
cursor: default;
|
|
57
|
+
|
|
58
|
+
&.fullsize {
|
|
59
|
+
max-width: 100vw;
|
|
60
|
+
max-height: 100vh;
|
|
61
|
+
position: fixed;
|
|
62
|
+
top: 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
overflow: auto;
|
|
66
|
+
display: flex;
|
|
67
|
+
flex-direction: column;
|
|
68
|
+
&[data-state="delayed-open"][data-side="top"] {
|
|
69
|
+
animation-name: slideDownAndFade;
|
|
70
|
+
}
|
|
71
|
+
&[data-state="delayed-open"][data-side="right"] {
|
|
72
|
+
animation-name: slideLeftAndFade;
|
|
73
|
+
}
|
|
74
|
+
&[data-state="delayed-open"][data-side="bottom"] {
|
|
75
|
+
animation-name: slideUpAndFade;
|
|
76
|
+
}
|
|
77
|
+
&[data-state="delayed-open"][data-side="left"] {
|
|
78
|
+
animation-name: slideRightAndFade;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.iotooltip_container {
|
|
83
|
+
display: flex;
|
|
84
|
+
flex-direction: column;
|
|
85
|
+
max-width: inherit;
|
|
86
|
+
max-height: inherit;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.iotooltipcontentarrow {
|
|
90
|
+
fill: white;
|
|
91
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import * as Tooltip from "@radix-ui/react-tooltip";
|
|
2
|
+
import LockOpenIcon from "@mui/icons-material/LockOpen";
|
|
3
|
+
import LockIcon from "@mui/icons-material/Lock";
|
|
4
|
+
import FullscreenIcon from "@mui/icons-material/Fullscreen";
|
|
5
|
+
|
|
6
|
+
import "./io.scss";
|
|
7
|
+
import { Handle, HandleProps } from "reactflow";
|
|
8
|
+
import { useMemo, useState } from "react";
|
|
9
|
+
import CustomDialog from "../../dialog";
|
|
10
|
+
import { PreviewHandleDataRendererForIo } from "./handle_renderer";
|
|
11
|
+
const pick_best_io_type = (
|
|
12
|
+
iot: SerializedType,
|
|
13
|
+
typemap: { [key: string]: string }
|
|
14
|
+
): [string | undefined, string | undefined] => {
|
|
15
|
+
// check if iot is string
|
|
16
|
+
if (typeof iot === "string") {
|
|
17
|
+
if (iot in typemap) {
|
|
18
|
+
return [typemap[iot], iot];
|
|
19
|
+
}
|
|
20
|
+
return [iot, iot];
|
|
21
|
+
}
|
|
22
|
+
if ("allOf" in iot && iot.allOf !== undefined) {
|
|
23
|
+
return [undefined, undefined];
|
|
24
|
+
}
|
|
25
|
+
if ("anyOf" in iot && iot.anyOf !== undefined) {
|
|
26
|
+
const picks = iot.anyOf.map((x) => pick_best_io_type(x, typemap));
|
|
27
|
+
for (const pick of picks) {
|
|
28
|
+
switch (pick[0]) {
|
|
29
|
+
case "bool":
|
|
30
|
+
return ["bool", pick[1]];
|
|
31
|
+
case "enum":
|
|
32
|
+
return ["enum", pick[1]];
|
|
33
|
+
case "float":
|
|
34
|
+
return ["float", pick[1]];
|
|
35
|
+
case "int":
|
|
36
|
+
return ["int", pick[1]];
|
|
37
|
+
case "string":
|
|
38
|
+
return ["string", pick[1]];
|
|
39
|
+
case "str":
|
|
40
|
+
return ["string", pick[1]];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return [undefined, undefined];
|
|
45
|
+
}
|
|
46
|
+
if (!("type" in iot) || iot.type === undefined) {
|
|
47
|
+
return [undefined, undefined];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (iot.type === "enum") {
|
|
51
|
+
return ["enum", "enum"];
|
|
52
|
+
}
|
|
53
|
+
return [undefined, undefined];
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
type HandleWithPreviewProps = {
|
|
57
|
+
io: IOType;
|
|
58
|
+
typestring: string | undefined;
|
|
59
|
+
preview?: React.FC<{ io: IOType }>;
|
|
60
|
+
} & HandleProps;
|
|
61
|
+
|
|
62
|
+
const HandleWithPreview = ({
|
|
63
|
+
io,
|
|
64
|
+
typestring,
|
|
65
|
+
preview,
|
|
66
|
+
...props
|
|
67
|
+
}: HandleWithPreviewProps) => {
|
|
68
|
+
const [locked, setLocked] = useState(false);
|
|
69
|
+
const [opened, setOpened] = useState(false);
|
|
70
|
+
|
|
71
|
+
const pvhandle: React.FC<{ io: IOType }> =
|
|
72
|
+
preview || PreviewHandleDataRendererForIo(io);
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<Tooltip.Provider>
|
|
76
|
+
<Tooltip.Root open={locked || opened} onOpenChange={setOpened}>
|
|
77
|
+
<Tooltip.Trigger asChild>
|
|
78
|
+
<Handle id={io.id} {...props} />
|
|
79
|
+
</Tooltip.Trigger>
|
|
80
|
+
<Tooltip.Portal>
|
|
81
|
+
<Tooltip.Content className={"iotooltipcontent"} sideOffset={5}>
|
|
82
|
+
<div className="iotooltip_container">
|
|
83
|
+
<div className="iotooltip_header">
|
|
84
|
+
{locked ? (
|
|
85
|
+
<LockIcon onClick={() => setLocked(false)} />
|
|
86
|
+
) : (
|
|
87
|
+
<LockOpenIcon onClick={() => setLocked(true)} />
|
|
88
|
+
)}
|
|
89
|
+
{pvhandle && (
|
|
90
|
+
<CustomDialog
|
|
91
|
+
trigger={<FullscreenIcon />}
|
|
92
|
+
onOpenChange={(open: boolean) => {
|
|
93
|
+
if (open) {
|
|
94
|
+
io.try_get_full_value();
|
|
95
|
+
}
|
|
96
|
+
setLocked(open);
|
|
97
|
+
}}
|
|
98
|
+
>
|
|
99
|
+
{pvhandle({ io })}
|
|
100
|
+
</CustomDialog>
|
|
101
|
+
)}
|
|
102
|
+
</div>
|
|
103
|
+
{pvhandle
|
|
104
|
+
? pvhandle({ io })
|
|
105
|
+
: `no preview available for "${typestring}"`}
|
|
106
|
+
</div>
|
|
107
|
+
<Tooltip.Arrow className="iotooltipcontentarrow" />
|
|
108
|
+
</Tooltip.Content>
|
|
109
|
+
</Tooltip.Portal>
|
|
110
|
+
</Tooltip.Root>
|
|
111
|
+
</Tooltip.Provider>
|
|
112
|
+
);
|
|
113
|
+
};
|
|
114
|
+
export { pick_best_io_type, HandleWithPreview };
|