Skip to content

Commit d474c76

Browse files
committed
iterating further on base-rect-node used as base node for rect-node and oval-node
1 parent 2797202 commit d474c76

File tree

8 files changed

+180
-168
lines changed

8 files changed

+180
-168
lines changed
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import {
2+
createJSXElement,
3+
FlowNode,
4+
IComputeResult,
5+
IDOMElement,
6+
IRectNodeComponent,
7+
Rect,
8+
IFlowCanvasBase,
9+
} from '@devhelpr/visual-programming-system';
10+
import { NodeInfo, RunCounter } from '@devhelpr/web-flow-executor';
11+
12+
export type CreateRunCounterContext = (
13+
isRunViaRunButton: boolean,
14+
shouldResetConnectionSlider: boolean,
15+
onFlowFinished?: () => void
16+
) => RunCounter;
17+
18+
export class BaseRectNode {
19+
nodeRenderElement: HTMLElement | undefined = undefined;
20+
rectElement: HTMLElement | undefined = undefined;
21+
canvasAppInstance: IFlowCanvasBase<NodeInfo> | undefined = undefined;
22+
id: string;
23+
node: IRectNodeComponent<NodeInfo> | undefined = undefined;
24+
updated: () => void;
25+
getSettingsPopup:
26+
| ((popupContainer: HTMLElement) => IDOMElement | undefined)
27+
| undefined = undefined;
28+
29+
rectInstance: Rect<NodeInfo> | undefined;
30+
31+
createRunCounterContext: CreateRunCounterContext | undefined = undefined;
32+
33+
static readonly nodeTypeName: string = 'rect-node';
34+
static readonly nodeTitle: string = 'Rect node';
35+
static readonly category: string = 'Default';
36+
37+
static readonly text: string = 'rect';
38+
39+
static readonly disableManualResize: boolean = true;
40+
41+
constructor(
42+
id: string,
43+
updated: () => void,
44+
node: IRectNodeComponent<NodeInfo>
45+
) {
46+
this.id = id;
47+
this.updated = updated;
48+
this.node = node;
49+
}
50+
compute = (
51+
input: string,
52+
_loopIndex?: number,
53+
_payload?: any
54+
): Promise<IComputeResult> => {
55+
return new Promise<IComputeResult>((resolve) => {
56+
resolve({
57+
result: input,
58+
output: input,
59+
followPath: undefined,
60+
});
61+
});
62+
};
63+
64+
childElementSelector = '.child-node-wrapper > textarea'; // '.child-node-wrapper > *:first-child'
65+
render(node: FlowNode<NodeInfo>) {
66+
const nodeInfo = node.nodeInfo as any;
67+
console.log(
68+
'render rect-node',
69+
node.width,
70+
node.height,
71+
(node?.nodeInfo as any)?.text
72+
);
73+
return (
74+
<textarea
75+
class="w-full h-full bg-transparent text-center appearance-none focus-visible:outline-none resize-none"
76+
resize="none"
77+
rows="1"
78+
renderElement={(element: HTMLTextAreaElement) => {
79+
element.value = nodeInfo?.text ?? '';
80+
setTimeout(() => {
81+
element.style.height = 'auto';
82+
console.log('renderElement textarea', element.scrollHeight);
83+
element.style.height = element.scrollHeight + 'px';
84+
}, 0);
85+
}}
86+
input={(event: InputEvent) => {
87+
if (this.canvasAppInstance?.getCanvasAttribute('create-connection')) {
88+
event.preventDefault();
89+
return false;
90+
}
91+
if (
92+
this.node?.nodeInfo &&
93+
this.rectElement &&
94+
(event?.target as HTMLTextAreaElement)?.value
95+
) {
96+
console.log(
97+
'textarea input',
98+
(event?.target as HTMLTextAreaElement)?.value
99+
);
100+
const value = (event?.target as HTMLTextAreaElement)?.value;
101+
102+
(this.node.nodeInfo as any).text = value;
103+
const textarea = event.target as HTMLTextAreaElement;
104+
textarea.style.height = 'auto';
105+
textarea.style.height = textarea.scrollHeight + 'px';
106+
if (this.onResize) {
107+
this.onResize(this.node.width ?? 10, textarea.scrollHeight);
108+
}
109+
}
110+
this.updated();
111+
return true;
112+
}}
113+
></textarea>
114+
);
115+
}
116+
onResize: ((width: number, height: number) => void) | undefined = undefined;
117+
setSize = (width: number, height: number) => {
118+
if (this.rectElement) {
119+
this.rectElement.style.width = `${width}px`;
120+
this.rectElement.style.height = `${height}px`;
121+
}
122+
};
123+
}

apps/vps-web/src/app/custom-nodes/classes/draw-grid-node.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import {
55
IComputeResult,
66
} from '@devhelpr/visual-programming-system';
77
import { getRunIndex, NodeInfo, runNode } from '@devhelpr/web-flow-executor';
8-
import { BaseRectNode } from './rect-node-class';
98

109
import './style.css';
10+
import { BaseRectNode } from './base-rect-node-class';
1111

1212
class Label extends HTMLElement {
1313
constructor() {

apps/vps-web/src/app/custom-nodes/classes/oval-node-class.tsx

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import {
44
IComputeResult,
55
} from '@devhelpr/visual-programming-system';
66
import { NodeInfo } from '@devhelpr/web-flow-executor';
7-
import { BaseRectNode } from './rect-node-class';
87

98
import TestWorker from './workers/test-worker?worker';
9+
import { BaseRectNode } from './base-rect-node-class';
1010

1111
const testWorker = new TestWorker();
1212

@@ -47,41 +47,16 @@ export class OvalNode extends BaseRectNode {
4747
getElement={(element: HTMLElement) => {
4848
this.rectElement = element;
4949
}}
50-
class={`rounded-full justify-center items-center text-center whitespace-pre inline-flex`}
50+
class={`rounded-full overflow-clip justify-center items-center text-center whitespace-pre inline-flex`}
5151
style={`min-width:${node.width ?? 50}px;min-height:${
5252
node.height ?? 50
5353
}px;background:${nodeInfo?.fillColor ?? 'black'};border: ${
5454
nodeInfo?.strokeWidth ?? '2'
5555
}px ${nodeInfo?.strokeColor ?? 'white'} solid;color:${
5656
nodeInfo?.strokeColor ?? 'white'
5757
}`}
58-
spellcheck="false"
59-
blur={() => {
60-
if (this.rectElement) {
61-
if (this.rectElement.innerHTML.toString().length == 0) {
62-
// hacky solution to prevent caret being aligned to top
63-
this.rectElement.innerHTML = '&nbsp;';
64-
}
65-
}
66-
console.log('blur', this.rectElement?.textContent);
67-
if (this.node?.nodeInfo) {
68-
(this.node.nodeInfo as any).text = this.rectElement?.textContent;
69-
}
70-
this.updated();
71-
}}
72-
contentEditable={true}
73-
pointerdown={(e: PointerEvent) => {
74-
if (e.shiftKey && this.rectElement) {
75-
this.rectElement.contentEditable = 'false';
76-
}
77-
}}
78-
pointerup={() => {
79-
if (this.rectElement) {
80-
this.rectElement.contentEditable = 'true';
81-
}
82-
}}
8358
>
84-
{nodeInfo?.text ?? ''}
59+
{super.render(node)}
8560
</div>
8661
</div>
8762
);

apps/vps-web/src/app/custom-nodes/classes/rect-node-class.tsx

Lines changed: 8 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,12 @@ import {
22
createJSXElement,
33
FlowNode,
44
IComputeResult,
5-
IDOMElement,
65
IRectNodeComponent,
7-
Rect,
8-
IFlowCanvasBase,
96
} from '@devhelpr/visual-programming-system';
10-
import { NodeInfo, RunCounter } from '@devhelpr/web-flow-executor';
11-
12-
export type CreateRunCounterContext = (
13-
isRunViaRunButton: boolean,
14-
shouldResetConnectionSlider: boolean,
15-
onFlowFinished?: () => void
16-
) => RunCounter;
17-
18-
export class BaseRectNode {
19-
nodeRenderElement: HTMLElement | undefined = undefined;
20-
rectElement: HTMLElement | undefined = undefined;
21-
canvasAppInstance: IFlowCanvasBase<NodeInfo> | undefined = undefined;
22-
id: string;
23-
node: IRectNodeComponent<NodeInfo> | undefined = undefined;
24-
updated: () => void;
25-
getSettingsPopup:
26-
| ((popupContainer: HTMLElement) => IDOMElement | undefined)
27-
| undefined = undefined;
28-
29-
rectInstance: Rect<NodeInfo> | undefined;
30-
31-
createRunCounterContext: CreateRunCounterContext | undefined = undefined;
7+
import { NodeInfo } from '@devhelpr/web-flow-executor';
8+
import { BaseRectNode } from './base-rect-node-class';
329

10+
export class RectNode extends BaseRectNode {
3311
static readonly nodeTypeName: string = 'rect-node';
3412
static readonly nodeTitle: string = 'Rect node';
3513
static readonly category: string = 'Default';
@@ -43,9 +21,7 @@ export class BaseRectNode {
4321
updated: () => void,
4422
node: IRectNodeComponent<NodeInfo>
4523
) {
46-
this.id = id;
47-
this.updated = updated;
48-
this.node = node;
24+
super(id, updated, node);
4925
}
5026
compute = (
5127
input: string,
@@ -68,7 +44,7 @@ w-min h-min
6844
*/
6945

7046
childElementSelector = '.child-node-wrapper > textarea'; // '.child-node-wrapper > *:first-child'
71-
render = (node: FlowNode<NodeInfo>) => {
47+
render(node: FlowNode<NodeInfo>) {
7248
const nodeInfo = node.nodeInfo as any;
7349
console.log(
7450
'render rect-node',
@@ -82,81 +58,20 @@ w-min h-min
8258
getElement={(element: HTMLElement) => {
8359
this.rectElement = element;
8460
}}
85-
class={`rounded justify-center items-center text-center whitespace-pre inline-flex grow-textarea`}
61+
class={`rounded overflow-clip justify-center items-center text-center whitespace-pre inline-flex grow-textarea`}
8662
style={`min-width:${node.width ?? 50}px;min-height:${
8763
node.height ?? 50
8864
}px;background:${nodeInfo?.fillColor ?? 'black'};border: ${
8965
nodeInfo?.strokeWidth ?? '2'
9066
}px ${nodeInfo?.strokeColor ?? 'white'} solid;color:${
9167
nodeInfo?.strokeColor ?? 'white'
9268
}`}
93-
spellcheck="false"
94-
contentEditable={false}
95-
pointerdown={(e: PointerEvent) => {
96-
if (e.shiftKey && this.rectElement) {
97-
this.rectElement.contentEditable = 'false';
98-
}
99-
}}
100-
pointerup={() => {
101-
if (this.rectElement) {
102-
this.rectElement.contentEditable = 'true';
103-
}
104-
}}
10569
>
106-
<textarea
107-
class="w-full h-full bg-transparent text-center appearance-none focus-visible:outline-none resize-none"
108-
resize="none"
109-
rows="1"
110-
renderElement={(element: HTMLTextAreaElement) => {
111-
element.value = nodeInfo?.text ?? '';
112-
setTimeout(() => {
113-
element.style.height = 'auto';
114-
console.log('renderElement textarea', element.scrollHeight);
115-
element.style.height = element.scrollHeight + 'px';
116-
}, 0);
117-
}}
118-
input={(event: InputEvent) => {
119-
//w-full h-full
120-
// if (this.rectElement) {
121-
// if (this.rectElement.innerHTML.toString().length == 0) {
122-
// // hacky solution to prevent caret being aligned to top
123-
// this.rectElement.innerHTML = '&nbsp;';
124-
// }
125-
// }
126-
// console.log('blur', this.rectElement?.textContent);
127-
if (
128-
this.canvasAppInstance?.getCanvasAttribute('create-connection')
129-
) {
130-
event.preventDefault();
131-
return false;
132-
}
133-
if (
134-
this.node?.nodeInfo &&
135-
this.rectElement &&
136-
(event?.target as HTMLTextAreaElement)?.value
137-
) {
138-
console.log(
139-
'textarea input',
140-
(event?.target as HTMLTextAreaElement)?.value
141-
);
142-
const value = (event?.target as HTMLTextAreaElement)?.value;
143-
144-
(this.node.nodeInfo as any).text = value;
145-
const textarea = event.target as HTMLTextAreaElement;
146-
textarea.style.height = 'auto';
147-
textarea.style.height = textarea.scrollHeight + 'px';
148-
if (this.onResize) {
149-
this.onResize(this.node.width ?? 10, textarea.scrollHeight);
150-
}
151-
}
152-
this.updated();
153-
return true;
154-
}}
155-
></textarea>
70+
{super.render(node)}
15671
</div>
15772
</div>
15873
);
159-
};
74+
}
16075
onResize: ((width: number, height: number) => void) | undefined = undefined;
16176
setSize = (width: number, height: number) => {
16277
if (this.rectElement) {

0 commit comments

Comments
 (0)