Skip to content

Commit 53ad6ad

Browse files
committed
Asked Copilot to change to follow Google coding guidelines
1 parent 260a6f7 commit 53ad6ad

File tree

11 files changed

+2666
-1901
lines changed

11 files changed

+2666
-1901
lines changed

src/App.tsx

Lines changed: 297 additions & 224 deletions
Large diffs are not rendered by default.

src/reactComponents/AddTabDialog.tsx

Lines changed: 388 additions & 340 deletions
Large diffs are not rendered by default.
Lines changed: 176 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,119 +1,195 @@
1-
import React from 'react';
1+
/**
2+
* @license
3+
* Copyright 2025 Porpoiseful LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* https://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
217

18+
/**
19+
* @author [email protected] (Alan Smith)
20+
*/
21+
import * as React from 'react';
322
import * as Blockly from 'blockly/core';
423
import * as locale from 'blockly/msg/en';
5-
import * as MrcTheme from '../themes/mrc_theme_dark'
24+
import * as MrcTheme from '../themes/mrc_theme_dark';
625
import {pluginInfo as HardwareConnectionsPluginInfo} from '../blocks/utils/connection_checker';
726

8-
927
import 'blockly/blocks'; // Includes standard blocks like controls_if, logic_compare, etc.
1028

11-
export type BlocklyComponentType = {
12-
getBlocklyWorkspace: () => Blockly.WorkspaceSvg,
29+
/** Interface for methods exposed by the BlocklyComponent. */
30+
export interface BlocklyComponentType {
31+
getBlocklyWorkspace: () => Blockly.WorkspaceSvg;
32+
}
33+
34+
/** Grid spacing for the Blockly workspace. */
35+
const GRID_SPACING = 20;
36+
37+
/** Grid line length for the Blockly workspace. */
38+
const GRID_LENGTH = 3;
39+
40+
/** Grid color for the Blockly workspace. */
41+
const GRID_COLOR = '#ccc';
42+
43+
/** Default zoom start scale. */
44+
const DEFAULT_ZOOM_START_SCALE = 1.0;
45+
46+
/** Maximum zoom scale. */
47+
const MAX_ZOOM_SCALE = 3;
48+
49+
/** Minimum zoom scale. */
50+
const MIN_ZOOM_SCALE = 0.3;
51+
52+
/** Zoom scale speed multiplier. */
53+
const ZOOM_SCALE_SPEED = 1.2;
54+
55+
/** Container and workspace styling. */
56+
const FULL_SIZE_STYLE: React.CSSProperties = {
57+
width: '100%',
58+
height: '100%',
1359
};
1460

15-
const BlocklyComponent = React.forwardRef<BlocklyComponentType | null>((_, ref) => {
16-
const blocklyDiv = React.useRef<HTMLDivElement | null>(null);
17-
const workspaceRef = React.useRef<Blockly.WorkspaceSvg>(null);
18-
19-
// Initialize Blockly
20-
React.useEffect(() => {
21-
// Configure Blockly workspace
22-
const workspaceConfig = {
23-
theme: MrcTheme.theme,
24-
horizontalLayout: false, // Forces vertical layout for the workspace
25-
26-
// Start with an empty (but not null) toolbox. It will be replaced later.
27-
toolbox: {
28-
kind: 'categoryToolbox',
29-
contents: [],
30-
},
31-
grid: {
32-
spacing: 20,
33-
length: 3,
34-
colour: '#ccc',
35-
snap: true
36-
},
37-
zoom: {
38-
controls: true,
39-
wheel: true,
40-
startScale: 1.0,
41-
maxScale: 3,
42-
minScale: 0.3,
43-
scaleSpeed: 1.2
44-
},
45-
scrollbars: true,
46-
trashcan: false,
47-
move: {
61+
/** Workspace positioning style. */
62+
const WORKSPACE_STYLE: React.CSSProperties = {
63+
...FULL_SIZE_STYLE,
64+
position: 'relative',
65+
};
66+
67+
/**
68+
* React component that renders a Blockly workspace with proper initialization,
69+
* cleanup, and resize handling.
70+
*/
71+
const BlocklyComponent = React.forwardRef<BlocklyComponentType | null>(
72+
(_, ref): React.JSX.Element => {
73+
const blocklyDiv = React.useRef<HTMLDivElement | null>(null);
74+
const workspaceRef = React.useRef<Blockly.WorkspaceSvg | null>(null);
75+
76+
/** Creates the Blockly workspace configuration object. */
77+
const createWorkspaceConfig = (): Blockly.BlocklyOptions => ({
78+
theme: MrcTheme.theme,
79+
horizontalLayout: false, // Forces vertical layout for the workspace
80+
// Start with an empty (but not null) toolbox. It will be replaced later.
81+
toolbox: {
82+
kind: 'categoryToolbox',
83+
contents: [],
84+
},
85+
grid: {
86+
spacing: GRID_SPACING,
87+
length: GRID_LENGTH,
88+
colour: GRID_COLOR,
89+
snap: true,
90+
},
91+
zoom: {
92+
controls: true,
93+
wheel: true,
94+
startScale: DEFAULT_ZOOM_START_SCALE,
95+
maxScale: MAX_ZOOM_SCALE,
96+
minScale: MIN_ZOOM_SCALE,
97+
scaleSpeed: ZOOM_SCALE_SPEED,
98+
},
4899
scrollbars: true,
49-
drag: true,
50-
wheel: true
51-
},
52-
oneBasedIndex: false,
53-
plugins: {
54-
...HardwareConnectionsPluginInfo,
55-
}
56-
};
57-
58-
// Set Blockly locale
59-
Blockly.setLocale(locale as any);
60-
61-
// Create workspace
62-
if (blocklyDiv.current) {
63-
const workspace = Blockly.inject(blocklyDiv.current, workspaceConfig);
64-
workspaceRef.current = workspace;
65-
}
100+
trashcan: false,
101+
move: {
102+
scrollbars: true,
103+
drag: true,
104+
wheel: true,
105+
},
106+
oneBasedIndex: false,
107+
plugins: {
108+
...HardwareConnectionsPluginInfo,
109+
},
110+
});
111+
112+
/** Initializes the Blockly workspace. */
113+
const initializeWorkspace = (): void => {
114+
if (!blocklyDiv.current) {
115+
return;
116+
}
117+
118+
// Set Blockly locale
119+
Blockly.setLocale(locale as any);
120+
121+
// Create workspace
122+
const workspaceConfig = createWorkspaceConfig();
123+
const workspace = Blockly.inject(blocklyDiv.current, workspaceConfig);
124+
workspaceRef.current = workspace;
125+
};
126+
127+
/** Cleans up the Blockly workspace on unmount. */
128+
const cleanupWorkspace = (): void => {
129+
if (workspaceRef.current) {
130+
workspaceRef.current.dispose();
131+
workspaceRef.current = null;
132+
}
133+
};
66134

67-
// Cleanup on unmount
68-
return () => {
69-
if (workspaceRef.current) {
70-
workspaceRef.current.dispose();
71-
}
72-
};
73-
}, []);
74-
75-
// Handle workspace resize
76-
React.useEffect(() => {
77-
const div = blocklyDiv.current;
78-
if (div) {
79-
const resizeObserver = new ResizeObserver(() => {
135+
/** Handles workspace resize events. */
136+
const handleWorkspaceResize = (): void => {
80137
if (workspaceRef.current) {
81138
Blockly.svgResize(workspaceRef.current);
82139
}
83-
});
84-
resizeObserver.observe(div);
140+
};
141+
142+
/** Sets up resize observer for the workspace container. */
143+
const setupResizeObserver = (): (() => void) | undefined => {
144+
const div = blocklyDiv.current;
145+
if (!div) {
146+
return undefined;
147+
}
85148

86-
return () => {
87-
resizeObserver.unobserve(div);
149+
const resizeObserver = new ResizeObserver(handleWorkspaceResize);
150+
resizeObserver.observe(div);
151+
152+
return () => {
153+
resizeObserver.unobserve(div);
154+
};
88155
};
156+
157+
/** Gets the current Blockly workspace instance. */
158+
const getBlocklyWorkspace = (): Blockly.WorkspaceSvg => {
159+
if (!workspaceRef.current) {
160+
throw new Error('Blockly workspace not initialized');
161+
}
162+
return workspaceRef.current;
163+
};
164+
165+
// Initialize Blockly workspace
166+
React.useEffect(() => {
167+
initializeWorkspace();
168+
return cleanupWorkspace;
169+
}, []);
170+
171+
// Handle workspace resize
172+
React.useEffect(() => {
173+
return setupResizeObserver();
174+
}, []);
175+
176+
// Expose methods through ref
177+
React.useImperativeHandle(
178+
ref,
179+
(): BlocklyComponentType => ({
180+
getBlocklyWorkspace,
181+
}),
182+
[]
183+
);
184+
185+
return (
186+
<div className="blockly-workspace-container" style={FULL_SIZE_STYLE}>
187+
<div ref={blocklyDiv} style={WORKSPACE_STYLE} />
188+
</div>
189+
);
89190
}
90-
}, [blocklyDiv]);
91-
92-
// Public methods exposed through ref
93-
const getBlocklyWorkspace = () => workspaceRef.current;
94-
95-
// Expose methods through ref
96-
// TODO(Alan) - figure out the real way to do this instead of any
97-
React.useImperativeHandle(ref as any, () => ({getBlocklyWorkspace}));
98-
99-
return (
100-
<div
101-
className="blockly-workspace-container"
102-
style={{
103-
width: '100%',
104-
height: '100%',
105-
}}
106-
>
107-
<div
108-
ref={blocklyDiv}
109-
style={{
110-
width: '100%',
111-
height: '100%',
112-
position: 'relative',
113-
}}
114-
/>
115-
</div>
116-
);
117-
});
191+
);
192+
193+
BlocklyComponent.displayName = 'BlocklyComponent';
118194

119195
export default BlocklyComponent;

0 commit comments

Comments
 (0)