scratch-blocks 2.0.0-spork.2 → 2.0.0-spork.4

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 (85) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/main.js +1 -1
  3. package/dist/main.js.LICENSE.txt +0 -12
  4. package/package.json +4 -4
  5. package/src/{block_reporting.js → block_reporting.ts} +7 -5
  6. package/src/blocks/{colour.js → colour.ts} +6 -6
  7. package/src/blocks/{control.js → control.ts} +21 -54
  8. package/src/blocks/{data.js → data.ts} +134 -142
  9. package/src/blocks/{event.js → event.ts} +12 -33
  10. package/src/blocks/{looks.js → looks.ts} +24 -73
  11. package/src/blocks/{math.js → math.ts} +6 -11
  12. package/src/blocks/{matrix.js → matrix.ts} +2 -3
  13. package/src/blocks/{motion.js → motion.ts} +23 -70
  14. package/src/blocks/{note.js → note.ts} +2 -3
  15. package/src/blocks/{operators.js → operators.ts} +18 -55
  16. package/src/blocks/{procedures.js → procedures.ts} +418 -269
  17. package/src/blocks/{sensing.js → sensing.ts} +21 -61
  18. package/src/blocks/{sound.js → sound.ts} +9 -28
  19. package/src/blocks/{text.js → text.ts} +1 -2
  20. package/src/blocks/{vertical_extensions.js → vertical_extensions.ts} +63 -100
  21. package/src/checkable_continuous_flyout.ts +112 -0
  22. package/src/{checkbox_bubble.js → checkbox_bubble.ts} +40 -58
  23. package/src/{colours.js → colours.ts} +11 -4
  24. package/src/{constants.js → constants.ts} +13 -0
  25. package/src/{context_menu_items.js → context_menu_items.ts} +18 -12
  26. package/src/{css.js → css.ts} +13 -7
  27. package/src/{data_category.js → data_category.ts} +216 -150
  28. package/src/events/{events_block_comment_base.js → events_block_comment_base.ts} +23 -4
  29. package/src/events/{events_block_comment_change.js → events_block_comment_change.ts} +29 -5
  30. package/src/events/{events_block_comment_collapse.js → events_block_comment_collapse.ts} +24 -6
  31. package/src/events/{events_block_comment_create.js → events_block_comment_create.ts} +36 -10
  32. package/src/events/{events_block_comment_delete.js → events_block_comment_delete.ts} +6 -2
  33. package/src/events/{events_block_comment_move.js → events_block_comment_move.ts} +36 -6
  34. package/src/events/events_block_comment_resize.ts +88 -0
  35. package/src/events/events_block_drag_end.ts +49 -0
  36. package/src/events/events_block_drag_outside.ts +44 -0
  37. package/src/events/{events_scratch_variable_create.js → events_scratch_variable_create.ts} +28 -15
  38. package/src/fields/{field_colour_slider.js → field_colour_slider.ts} +117 -106
  39. package/src/fields/{field_matrix.js → field_matrix.ts} +189 -215
  40. package/src/fields/{field_note.js → field_note.ts} +227 -286
  41. package/src/fields/{field_textinput_removable.js → field_textinput_removable.ts} +17 -20
  42. package/src/fields/{field_variable_getter.js → field_variable_getter.ts} +28 -17
  43. package/src/fields/{field_vertical_separator.js → field_vertical_separator.ts} +14 -30
  44. package/src/fields/{field_angle.js → scratch_field_angle.ts} +124 -80
  45. package/src/fields/{field_dropdown.js → scratch_field_dropdown.ts} +9 -7
  46. package/src/fields/{field_number.js → scratch_field_number.ts} +60 -55
  47. package/src/fields/{field_variable.js → scratch_field_variable.ts} +46 -27
  48. package/src/{flyout_checkbox_icon.js → flyout_checkbox_icon.ts} +15 -19
  49. package/src/{glows.js → glows.ts} +29 -18
  50. package/src/index.ts +62 -63
  51. package/src/procedures.ts +462 -0
  52. package/src/recyclable_block_flyout_inflater.ts +51 -0
  53. package/src/renderer/{bowler_hat.js → bowler_hat.ts} +1 -1
  54. package/src/renderer/{constants.js → constants.ts} +26 -12
  55. package/src/renderer/{drawer.js → drawer.ts} +8 -3
  56. package/src/renderer/{path_object.js → path_object.ts} +2 -2
  57. package/src/renderer/{render_info.js → render_info.ts} +19 -7
  58. package/src/renderer/renderer.ts +76 -0
  59. package/src/{scratch_block_paster.js → scratch_block_paster.ts} +9 -7
  60. package/src/scratch_blocks_utils.ts +39 -0
  61. package/src/{scratch_comment_icon.js → scratch_comment_icon.ts} +43 -26
  62. package/src/scratch_connection_checker.ts +44 -0
  63. package/src/{scratch_continuous_category.js → scratch_continuous_category.ts} +20 -13
  64. package/src/scratch_continuous_toolbox.ts +70 -0
  65. package/src/{scratch_dragger.js → scratch_dragger.ts} +97 -28
  66. package/src/{scratch_variable_map.js → scratch_variable_map.ts} +4 -1
  67. package/src/scratch_variable_model.ts +30 -0
  68. package/src/{shadows.js → shadows.ts} +8 -4
  69. package/src/{status_indicator_label.js → status_indicator_label.ts} +24 -36
  70. package/src/{status_indicator_label_flyout_inflater.js → status_indicator_label_flyout_inflater.ts} +13 -9
  71. package/src/{variables.js → variables.ts} +153 -123
  72. package/tsconfig.json +5 -0
  73. package/src/categories.js +0 -15
  74. package/src/checkable_continuous_flyout.js +0 -138
  75. package/src/events/events_block_comment_resize.js +0 -52
  76. package/src/events/events_block_drag_end.js +0 -33
  77. package/src/events/events_block_drag_outside.js +0 -30
  78. package/src/procedures.js +0 -425
  79. package/src/recyclable_block_flyout_inflater.js +0 -194
  80. package/src/renderer/renderer.js +0 -74
  81. package/src/scratch_blocks_utils.js +0 -148
  82. package/src/scratch_connection_checker.js +0 -29
  83. package/src/scratch_continuous_toolbox.js +0 -78
  84. package/src/scratch_variable_model.js +0 -24
  85. /package/{continuous-toolbox.d.ts → types/continuous-toolbox.d.ts} +0 -0
@@ -26,24 +26,22 @@
26
26
  * @author fenichel@google.com (Rachel Fenichel)
27
27
  */
28
28
  import * as Blockly from "blockly/core";
29
- import { ScratchProcedures } from "../procedures.js";
30
- import * as Constants from "../constants.js";
31
- import { FlyoutCheckboxIcon } from "../flyout_checkbox_icon.js";
29
+ import { ScratchProcedures } from "../procedures";
30
+ import * as Constants from "../constants";
31
+ import { FlyoutCheckboxIcon } from "../flyout_checkbox_icon";
32
32
 
33
- const VerticalExtensions = {};
34
33
  /**
35
34
  * Helper function that generates an extension based on a category name.
36
35
  * The generated function will set the block's style based on the category name.
37
- * @param {String} category The name of the category to set colours for.
38
- * @return {function} An extension function that sets colours based on the given
39
- * category.
36
+ *
37
+ * @param category The name of the category to set colours for.
38
+ * @return An extension function that sets colours based on the given category.
40
39
  */
41
- VerticalExtensions.colourHelper = function (category) {
40
+ const colourHelper = function (category: string): () => void {
42
41
  /**
43
42
  * Set the block style on this block for the given category.
44
- * @this {Blockly.Block}
45
43
  */
46
- return function () {
44
+ return function (this: Blockly.Block) {
47
45
  this.setStyle(category);
48
46
  };
49
47
  };
@@ -51,18 +49,16 @@ VerticalExtensions.colourHelper = function (category) {
51
49
  /**
52
50
  * Extension to set the colours of a text field, which are all the same.
53
51
  */
54
- VerticalExtensions.COLOUR_TEXTFIELD = function () {
55
- VerticalExtensions.colourHelper("textField").apply(this);
52
+ const COLOUR_TEXTFIELD = function (this: Blockly.Block) {
53
+ colourHelper("textField").apply(this);
56
54
  };
57
55
 
58
56
  /**
59
57
  * Extension to make a block fit into a stack of statements, regardless of its
60
58
  * inputs. That means the block should have a previous connection and a next
61
59
  * connection and have inline inputs.
62
- * @this {Blockly.Block}
63
- * @readonly
64
60
  */
65
- VerticalExtensions.SHAPE_STATEMENT = function () {
61
+ const SHAPE_STATEMENT = function (this: Blockly.Block) {
66
62
  this.setInputsInline(true);
67
63
  this.setPreviousStatement(true, null);
68
64
  this.setNextStatement(true, null);
@@ -72,10 +68,8 @@ VerticalExtensions.SHAPE_STATEMENT = function () {
72
68
  * Extension to make a block be shaped as a hat block, regardless of its
73
69
  * inputs. That means the block should have a next connection and have inline
74
70
  * inputs, but have no previous connection.
75
- * @this {Blockly.Block}
76
- * @readonly
77
71
  */
78
- VerticalExtensions.SHAPE_HAT = function () {
72
+ const SHAPE_HAT = function (this: Blockly.Block) {
79
73
  this.setInputsInline(true);
80
74
  this.setNextStatement(true, null);
81
75
  this.hat = "cap";
@@ -84,10 +78,8 @@ VerticalExtensions.SHAPE_HAT = function () {
84
78
  /**
85
79
  * Extension to make a block be shaped as a bowler hat block, with rounded
86
80
  * corners on both sides and no indentation for statement blocks.
87
- * @this {Blockly.Block}
88
- * @readonly
89
81
  */
90
- VerticalExtensions.SHAPE_BOWLER_HAT = function () {
82
+ const SHAPE_BOWLER_HAT = function (this: Blockly.Block) {
91
83
  this.setInputsInline(true);
92
84
  this.setNextStatement(true, null);
93
85
  this.hat = "bowler";
@@ -97,10 +89,8 @@ VerticalExtensions.SHAPE_BOWLER_HAT = function () {
97
89
  * Extension to make a block be shaped as an end block, regardless of its
98
90
  * inputs. That means the block should have a previous connection and have
99
91
  * inline inputs, but have no next connection.
100
- * @this {Blockly.Block}
101
- * @readonly
102
92
  */
103
- VerticalExtensions.SHAPE_END = function () {
93
+ const SHAPE_END = function (this: Blockly.Block) {
104
94
  this.setInputsInline(true);
105
95
  this.setPreviousStatement(true, null);
106
96
  };
@@ -109,10 +99,8 @@ VerticalExtensions.SHAPE_END = function () {
109
99
  * Extension to make represent a number reporter in Scratch-Blocks.
110
100
  * That means the block has inline inputs, a round output shape, and a 'Number'
111
101
  * output type.
112
- * @this {Blockly.Block}
113
- * @readonly
114
102
  */
115
- VerticalExtensions.OUTPUT_NUMBER = function () {
103
+ const OUTPUT_NUMBER = function (this: Blockly.Block) {
116
104
  this.setInputsInline(true);
117
105
  this.setOutputShape(Constants.OUTPUT_SHAPE_ROUND);
118
106
  this.setOutput(true, "Number");
@@ -122,10 +110,8 @@ VerticalExtensions.OUTPUT_NUMBER = function () {
122
110
  * Extension to make represent a string reporter in Scratch-Blocks.
123
111
  * That means the block has inline inputs, a round output shape, and a 'String'
124
112
  * output type.
125
- * @this {Blockly.Block}
126
- * @readonly
127
113
  */
128
- VerticalExtensions.OUTPUT_STRING = function () {
114
+ const OUTPUT_STRING = function (this: Blockly.Block) {
129
115
  this.setInputsInline(true);
130
116
  this.setOutputShape(Constants.OUTPUT_SHAPE_ROUND);
131
117
  this.setOutput(true, "String");
@@ -135,10 +121,8 @@ VerticalExtensions.OUTPUT_STRING = function () {
135
121
  * Extension to make represent a boolean reporter in Scratch-Blocks.
136
122
  * That means the block has inline inputs, a round output shape, and a 'Boolean'
137
123
  * output type.
138
- * @this {Blockly.Block}
139
- * @readonly
140
124
  */
141
- VerticalExtensions.OUTPUT_BOOLEAN = function () {
125
+ const OUTPUT_BOOLEAN = function (this: Blockly.Block) {
142
126
  this.setInputsInline(true);
143
127
  this.setOutputShape(Constants.OUTPUT_SHAPE_HEXAGONAL);
144
128
  this.setOutput(true, "Boolean");
@@ -149,34 +133,35 @@ VerticalExtensions.OUTPUT_BOOLEAN = function () {
149
133
  * value in a dropdown. These blocks also have an accompanying checkbox in the
150
134
  * flyout to toggle display of their current value in a chip on the stage.
151
135
  */
152
- VerticalExtensions.MONITOR_BLOCK = function () {
136
+ const MONITOR_BLOCK = function (this: Blockly.BlockSvg) {
153
137
  this.addIcon(new FlyoutCheckboxIcon(this));
154
- this.checkboxInFlyout = true;
138
+ (this as any).checkboxInFlyout = true;
155
139
  };
156
140
 
157
141
  /**
158
142
  * Mixin to add a context menu for a procedure definition block.
159
143
  * It adds the "edit" option and removes the "duplicate" option.
160
- * @mixin
161
- * @augments Blockly.Block
162
- * @package
163
- * @readonly
164
144
  */
165
- VerticalExtensions.PROCEDURE_DEF_CONTEXTMENU = function () {
145
+ const PROCEDURE_DEF_CONTEXTMENU = function (this: Blockly.Block) {
166
146
  /**
167
147
  * Add the "edit" option and removes the "duplicate" option from the context
168
148
  * menu.
169
- * @param {!Array.<!Object>} menuOptions List of menu options to edit.
170
- * @this Blockly.Block
149
+ *
150
+ * @param menuOptions List of menu options to edit.
171
151
  */
172
152
  this.mixin(
173
153
  {
174
- customContextMenu: function (menuOptions) {
154
+ customContextMenu: function (
155
+ menuOptions: Array<
156
+ | Blockly.ContextMenuRegistry.ContextMenuOption
157
+ | Blockly.ContextMenuRegistry.LegacyContextMenuOption
158
+ >
159
+ ) {
175
160
  // Add the edit option at the end.
176
161
  menuOptions.push(ScratchProcedures.makeEditOption(this));
177
162
 
178
163
  // Find and remove the duplicate option
179
- for (var i = 0, option; (option = menuOptions[i]); i++) {
164
+ for (let i = 0, option; (option = menuOptions[i]); i++) {
180
165
  if (option.text == Blockly.Msg.DUPLICATE) {
181
166
  menuOptions.splice(i, 1);
182
167
  break;
@@ -184,11 +169,11 @@ VerticalExtensions.PROCEDURE_DEF_CONTEXTMENU = function () {
184
169
  }
185
170
  },
186
171
  checkAndDelete: function () {
187
- var input = this.getInput("custom_block");
172
+ const input = this.getInput("custom_block");
188
173
  // this is the root block, not the shadow block.
189
174
  if (input && input.connection && input.connection.targetBlock()) {
190
- var procCode = input.connection.targetBlock().getProcCode();
191
- var didDelete = ScratchProcedures.deleteProcedureDefCallback(
175
+ const procCode = input.connection.targetBlock().getProcCode();
176
+ const didDelete = ScratchProcedures.deleteProcedureDefCallback(
192
177
  procCode,
193
178
  this
194
179
  );
@@ -208,29 +193,35 @@ VerticalExtensions.PROCEDURE_DEF_CONTEXTMENU = function () {
208
193
  * @mixin
209
194
  * @augments Blockly.Block
210
195
  * @package
211
- * @readonly
212
196
  */
213
- VerticalExtensions.PROCEDURE_CALL_CONTEXTMENU = {
197
+ const PROCEDURE_CALL_CONTEXTMENU = {
214
198
  /**
215
199
  * Add the "edit" option to the context menu.
200
+ *
216
201
  * @todo Add "go to definition" option once implemented.
217
- * @param {!Array.<!Object>} menuOptions List of menu options to edit.
218
- * @this Blockly.Block
202
+ * @param menuOptions List of menu options to edit.
219
203
  */
220
- customContextMenu: function (menuOptions) {
204
+ customContextMenu: function (
205
+ this: Blockly.BlockSvg,
206
+ menuOptions: Array<
207
+ | Blockly.ContextMenuRegistry.ContextMenuOption
208
+ | Blockly.ContextMenuRegistry.LegacyContextMenuOption
209
+ >
210
+ ) {
221
211
  menuOptions.push(ScratchProcedures.makeEditOption(this));
222
212
  },
223
213
  };
224
214
 
225
- VerticalExtensions.SCRATCH_EXTENSION = function () {
226
- this.isScratchExtension = true;
215
+ const SCRATCH_EXTENSION = function (this: Blockly.Block) {
216
+ (this as any).isScratchExtension = true;
227
217
  };
218
+
228
219
  /**
229
220
  * Register all extensions for scratch-blocks.
230
221
  * @package
231
222
  */
232
- VerticalExtensions.registerAll = function () {
233
- var categoryNames = [
223
+ function registerAll() {
224
+ const categoryNames = [
234
225
  "control",
235
226
  "data",
236
227
  "data_lists",
@@ -244,66 +235,38 @@ VerticalExtensions.registerAll = function () {
244
235
  "more",
245
236
  ];
246
237
  // Register functions for all category colours.
247
- for (var i = 0; i < categoryNames.length; i++) {
248
- var name = categoryNames[i];
249
- Blockly.Extensions.register(
250
- "colours_" + name,
251
- VerticalExtensions.colourHelper(name)
252
- );
238
+ for (const name of categoryNames) {
239
+ Blockly.Extensions.register("colours_" + name, colourHelper(name));
253
240
  }
254
241
 
255
242
  // Text fields transcend categories.
256
- Blockly.Extensions.register(
257
- "colours_textfield",
258
- VerticalExtensions.COLOUR_TEXTFIELD
259
- );
243
+ Blockly.Extensions.register("colours_textfield", COLOUR_TEXTFIELD);
260
244
 
261
245
  // Register extensions for common block shapes.
262
- Blockly.Extensions.register(
263
- "shape_statement",
264
- VerticalExtensions.SHAPE_STATEMENT
265
- );
266
- Blockly.Extensions.register("shape_hat", VerticalExtensions.SHAPE_HAT);
267
- Blockly.Extensions.register(
268
- "shape_bowler_hat",
269
- VerticalExtensions.SHAPE_BOWLER_HAT
270
- );
271
- Blockly.Extensions.register("shape_end", VerticalExtensions.SHAPE_END);
246
+ Blockly.Extensions.register("shape_statement", SHAPE_STATEMENT);
247
+ Blockly.Extensions.register("shape_hat", SHAPE_HAT);
248
+ Blockly.Extensions.register("shape_bowler_hat", SHAPE_BOWLER_HAT);
249
+ Blockly.Extensions.register("shape_end", SHAPE_END);
272
250
 
273
251
  // Output shapes and types are related.
274
- Blockly.Extensions.register(
275
- "output_number",
276
- VerticalExtensions.OUTPUT_NUMBER
277
- );
278
- Blockly.Extensions.register(
279
- "output_string",
280
- VerticalExtensions.OUTPUT_STRING
281
- );
282
- Blockly.Extensions.register(
283
- "output_boolean",
284
- VerticalExtensions.OUTPUT_BOOLEAN
285
- );
252
+ Blockly.Extensions.register("output_number", OUTPUT_NUMBER);
253
+ Blockly.Extensions.register("output_string", OUTPUT_STRING);
254
+ Blockly.Extensions.register("output_boolean", OUTPUT_BOOLEAN);
286
255
 
287
256
  // Custom procedures have interesting context menus.
288
257
  Blockly.Extensions.register(
289
258
  "procedure_def_contextmenu",
290
- VerticalExtensions.PROCEDURE_DEF_CONTEXTMENU
259
+ PROCEDURE_DEF_CONTEXTMENU
291
260
  );
292
261
  Blockly.Extensions.registerMixin(
293
262
  "procedure_call_contextmenu",
294
- VerticalExtensions.PROCEDURE_CALL_CONTEXTMENU
263
+ PROCEDURE_CALL_CONTEXTMENU
295
264
  );
296
265
 
297
266
  // Extension blocks have slightly different block rendering.
298
- Blockly.Extensions.register(
299
- "scratch_extension",
300
- VerticalExtensions.SCRATCH_EXTENSION
301
- );
267
+ Blockly.Extensions.register("scratch_extension", SCRATCH_EXTENSION);
302
268
 
303
- Blockly.Extensions.register(
304
- "monitor_block",
305
- VerticalExtensions.MONITOR_BLOCK
306
- );
307
- };
269
+ Blockly.Extensions.register("monitor_block", MONITOR_BLOCK);
270
+ }
308
271
 
309
- VerticalExtensions.registerAll();
272
+ registerAll();
@@ -0,0 +1,112 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2024 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import * as Blockly from "blockly/core";
8
+ import { ContinuousFlyout } from "@blockly/continuous-toolbox";
9
+ import { CheckboxBubble } from "./checkbox_bubble";
10
+ import { StatusIndicatorLabel } from "./status_indicator_label";
11
+ import { STATUS_INDICATOR_LABEL_TYPE } from "./status_indicator_label_flyout_inflater";
12
+
13
+ export class CheckableContinuousFlyout extends ContinuousFlyout {
14
+ /**
15
+ * Creates a new CheckableContinuousFlyout.
16
+ *
17
+ * @param workspaceOptions Configuration options for the flyout workspace.
18
+ */
19
+ constructor(workspaceOptions: Blockly.Options) {
20
+ workspaceOptions.modalInputs = false;
21
+ super(workspaceOptions);
22
+ this.tabWidth_ = 0;
23
+ this.MARGIN = 12;
24
+ this.GAP_Y = 12;
25
+ }
26
+
27
+ /**
28
+ * Serializes a block to JSON in order to copy it to the main workspace.
29
+ *
30
+ * @param block The block to serialize.
31
+ * @returns A JSON representation of the block.
32
+ */
33
+ protected serializeBlock(block: Blockly.BlockSvg) {
34
+ const json = super.serializeBlock(block);
35
+ // Delete the serialized block's ID so that a new one is generated when it is
36
+ // placed on the workspace. Otherwise, the block on the workspace may be
37
+ // indistinguishable from the one in the flyout, which can cause reporter blocks
38
+ // to have their value dropdown shown in the wrong place.
39
+ delete json.id;
40
+ return json;
41
+ }
42
+
43
+ /**
44
+ * Set the state of a checkbox by block ID.
45
+ *
46
+ * @param blockId ID of the block whose checkbox should be set
47
+ * @param value Value to set the checkbox to.
48
+ */
49
+ setCheckboxState(blockId: string, value: boolean) {
50
+ this.getWorkspace()
51
+ .getBlockById(blockId)
52
+ ?.getIcon("checkbox")
53
+ ?.setChecked(value);
54
+ }
55
+
56
+ getFlyoutScale() {
57
+ return 0.675;
58
+ }
59
+
60
+ getWidth() {
61
+ return 250;
62
+ }
63
+
64
+ protected reflowInternal_() {
65
+ super.reflowInternal_();
66
+
67
+ if (this.RTL) {
68
+ // The parent implementation assumes that the flyout grows to fit its
69
+ // contents, and adjusts blocks in RTL mode accordingly. In Scratch, the
70
+ // flyout width is fixed (and blocks may exceed it), so re-adjust blocks
71
+ // accordingly based on the actual fixed width.
72
+ for (const item of this.getContents()) {
73
+ const oldX = item.getElement().getBoundingRectangle().left;
74
+ let newX =
75
+ this.getWidth() / this.workspace_.scale -
76
+ item.getElement().getBoundingRectangle().getWidth() -
77
+ this.MARGIN;
78
+ if (
79
+ "checkboxInFlyout" in item.getElement() &&
80
+ item.getElement().checkboxInFlyout
81
+ ) {
82
+ newX -= CheckboxBubble.CHECKBOX_SIZE + CheckboxBubble.CHECKBOX_MARGIN;
83
+ }
84
+ item.getElement().moveBy(newX - oldX, 0);
85
+ }
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Validates that the given toolbox item represents a label.
91
+ *
92
+ * @param item The toolbox item to check.
93
+ * @returns True if the item represents a label in the flyout.
94
+ */
95
+ protected toolboxItemIsLabel(item: Blockly.FlyoutItem) {
96
+ return (
97
+ item.getType() === STATUS_INDICATOR_LABEL_TYPE ||
98
+ super.toolboxItemIsLabel(item)
99
+ );
100
+ }
101
+
102
+ /**
103
+ * Updates the state of status indicators for hardware-based extensions.
104
+ */
105
+ refreshStatusButtons() {
106
+ for (const item of this.contents) {
107
+ if (item.element instanceof StatusIndicatorLabel) {
108
+ item.element.refreshStatus();
109
+ }
110
+ }
111
+ }
112
+ }
@@ -8,30 +8,24 @@ import * as Blockly from "blockly/core";
8
8
 
9
9
  /**
10
10
  * A checkbox shown next to reporter blocks in the flyout.
11
- * @implements {Blockly.IBubble}
12
- * @implements {Blockly.IRenderedElement}
13
11
  */
14
- export class CheckboxBubble {
12
+ export class CheckboxBubble
13
+ implements Blockly.IBubble, Blockly.IRenderedElement
14
+ {
15
15
  /**
16
16
  * Size of a checkbox next to a variable reporter.
17
- * @type {number}
18
- * @const
19
17
  */
20
- static CHECKBOX_SIZE = 25;
18
+ static readonly CHECKBOX_SIZE = 25;
21
19
 
22
20
  /**
23
21
  * Amount of touchable padding around reporter checkboxes.
24
- * @type {number}
25
- * @const
26
22
  */
27
- static CHECKBOX_TOUCH_PADDING = 12;
23
+ static readonly CHECKBOX_TOUCH_PADDING = 12;
28
24
 
29
25
  /**
30
26
  * SVG path data for checkmark in checkbox.
31
- * @type {string}
32
- * @const
33
27
  */
34
- static CHECKMARK_PATH =
28
+ static readonly CHECKMARK_PATH =
35
29
  "M" +
36
30
  CheckboxBubble.CHECKBOX_SIZE / 4 +
37
31
  " " +
@@ -46,59 +40,48 @@ export class CheckboxBubble {
46
40
  CheckboxBubble.CHECKBOX_SIZE / 3;
47
41
 
48
42
  /**
49
- * Size of the checkbox corner radius
50
- * @type {number}
51
- * @const
43
+ * Size of the checkbox corner radius.
52
44
  */
53
- static CHECKBOX_CORNER_RADIUS = 5;
45
+ static readonly CHECKBOX_CORNER_RADIUS = 5;
54
46
 
55
47
  /**
56
- * @type {number}
57
- * @const
48
+ * The margin around a checkbox.
58
49
  */
59
- static CHECKBOX_MARGIN = 12;
50
+ static readonly CHECKBOX_MARGIN = 12;
60
51
 
61
52
  /**
62
53
  * Total additional width of a row that contains a checkbox.
63
- * @type {number}
64
- * @const
65
54
  */
66
- static CHECKBOX_SPACE_X =
55
+ static readonly CHECKBOX_SPACE_X =
67
56
  CheckboxBubble.CHECKBOX_SIZE + 2 * CheckboxBubble.CHECKBOX_MARGIN;
68
57
 
69
58
  /**
70
59
  * Root SVG element for this bubble.
71
- * @type {!SVGGElement}
72
60
  */
73
- svgRoot;
61
+ svgRoot: SVGGElement;
74
62
 
75
63
  /**
76
64
  * Identifier for click handler, to allow unregistering during disposal.
77
- * @type {!Blockly.browserEvents.Data}
78
65
  */
79
- clickListener;
66
+ clickListener: Blockly.browserEvents.Data;
80
67
 
81
68
  /**
82
69
  * Whether or not this bubble is displayed as checked. Note that the source of
83
70
  * truth is the Scratch VM.
84
- * @type {boolean}
85
71
  */
86
72
  checked = false;
87
73
 
88
74
  /**
89
75
  * The location of this bubble in workspace coordinates.
90
- * @type {!Blockly.utils.Coordinate}
91
76
  */
92
77
  location = new Blockly.utils.Coordinate(0, 0);
93
78
 
94
79
  /**
95
80
  * Creates a new flyout checkbox bubble.
96
81
  *
97
- * @param {!Blockly.BlockSvg} sourceBlock The block this bubble should be
98
- * associated with.
82
+ * @param sourceBlock The block this bubble should be associated with.
99
83
  */
100
- constructor(sourceBlock) {
101
- this.sourceBlock = sourceBlock;
84
+ constructor(private sourceBlock: Blockly.BlockSvg) {
102
85
  this.svgRoot = Blockly.utils.dom.createSvgElement(
103
86
  Blockly.utils.Svg.G,
104
87
  {},
@@ -149,9 +132,9 @@ export class CheckboxBubble {
149
132
 
150
133
  this.clickListener = Blockly.browserEvents.bind(
151
134
  this.svgRoot,
152
- "mousedown",
135
+ "pointerdown",
153
136
  null,
154
- (event) => {
137
+ (event: PointerEvent) => {
155
138
  this.setChecked(!this.checked);
156
139
  event.stopPropagation();
157
140
  event.preventDefault();
@@ -163,9 +146,9 @@ export class CheckboxBubble {
163
146
  /**
164
147
  * Sets whether or not this bubble should be displayed in the checked state.
165
148
  *
166
- * @param {boolean} checked True if this bubble should be checked.
149
+ * @param checked True if this bubble should be checked.
167
150
  */
168
- setChecked(checked) {
151
+ setChecked(checked: boolean) {
169
152
  if (checked === this.checked) return;
170
153
 
171
154
  this.checked = checked;
@@ -191,28 +174,28 @@ export class CheckboxBubble {
191
174
  *
192
175
  * This method is patched by scratch-gui to query the VM state.
193
176
  *
194
- * @param {string} blockId The ID of the block in question.
195
- * @returns {boolean} True if the block's checkbox should be checked.
177
+ * @param blockId The ID of the block in question.
178
+ * @returns True if the block's checkbox should be checked.
196
179
  */
197
- isChecked(blockId) {
180
+ isChecked(blockId: string): boolean {
198
181
  return false;
199
182
  }
200
183
 
201
184
  /**
202
185
  * Returns whether this bubble is movable by the user.
203
186
  *
204
- * @returns {boolean} Always returns false.
187
+ * @returns Always returns false.
205
188
  */
206
- isMovable() {
189
+ isMovable(): boolean {
207
190
  return false;
208
191
  }
209
192
 
210
193
  /**
211
194
  * Returns the root SVG element for this bubble.
212
195
  *
213
- * @returns {!SVGGElement} The root SVG element.
196
+ * @returns The root SVG element.
214
197
  */
215
- getSvgRoot() {
198
+ getSvgRoot(): SVGGElement {
216
199
  return this.svgRoot;
217
200
  }
218
201
 
@@ -220,25 +203,24 @@ export class CheckboxBubble {
220
203
  * Recalculates this bubble's location, keeping it adjacent to its block.
221
204
  */
222
205
  updateLocation() {
223
- const blockLocation = this.sourceBlock.getRelativeToSurfaceXY();
224
- const blockBounds = this.sourceBlock.getHeightWidth();
206
+ const bounds = this.sourceBlock.getBoundingRectangle();
225
207
  const x = this.sourceBlock.workspace.RTL
226
- ? blockLocation.x + blockBounds.width + CheckboxBubble.CHECKBOX_MARGIN
227
- : blockLocation.x -
208
+ ? bounds.right + CheckboxBubble.CHECKBOX_MARGIN
209
+ : bounds.left -
228
210
  CheckboxBubble.CHECKBOX_MARGIN -
229
211
  CheckboxBubble.CHECKBOX_SIZE;
230
212
  const y =
231
- blockLocation.y + (blockBounds.height - CheckboxBubble.CHECKBOX_SIZE) / 2;
213
+ bounds.top + (bounds.getHeight() - CheckboxBubble.CHECKBOX_SIZE) / 2;
232
214
  this.moveTo(x, y);
233
215
  }
234
216
 
235
217
  /**
236
218
  * Moves this bubble to the specified location.
237
219
  *
238
- * @param {number} x The location on the X axis to move to.
239
- * @param {number} y The location on the Y axis to move to.
220
+ * @param x The location on the X axis to move to.
221
+ * @param y The location on the Y axis to move to.
240
222
  */
241
- moveTo(x, y) {
223
+ moveTo(x: number, y: number) {
242
224
  this.location.x = x;
243
225
  this.location.y = y;
244
226
  this.svgRoot.setAttribute("transform", `translate(${x}, ${y})`);
@@ -247,9 +229,9 @@ export class CheckboxBubble {
247
229
  /**
248
230
  * Returns this bubble's location in workspace coordinates.
249
231
  *
250
- * @returns {!Blockly.utils.Coordinate} The bubble's location.
232
+ * @returns The bubble's location.
251
233
  */
252
- getRelativeToSurfaceXY() {
234
+ getRelativeToSurfaceXY(): Blockly.utils.Coordinate {
253
235
  return this.location;
254
236
  }
255
237
 
@@ -266,17 +248,17 @@ export class CheckboxBubble {
266
248
  // to its block and is not draggable by the user.
267
249
  showContextMenu() {}
268
250
 
269
- setDragging(dragging) {}
251
+ setDragging(dragging: boolean) {}
270
252
 
271
- startDrag(event) {}
253
+ startDrag(event: PointerEvent) {}
272
254
 
273
- drag(newLocation, event) {}
255
+ drag(newLocation: Blockly.utils.Coordinate, event: PointerEvent) {}
274
256
 
275
- moveDuringDrag(newLocation) {}
257
+ moveDuringDrag(newLocation: Blockly.utils.Coordinate) {}
276
258
 
277
259
  endDrag() {}
278
260
 
279
261
  revertDrag() {}
280
262
 
281
- setDeleteStyle(enable) {}
263
+ setDeleteStyle(enable: boolean) {}
282
264
  }
@@ -55,10 +55,17 @@ const Colours = {
55
55
  contextualMenuHover: "rgba(77, 151, 255, .25)",
56
56
  };
57
57
 
58
- function varify(coloursObj, prefix = "--colour") {
59
- return Object.keys(coloursObj)
60
- .map((key) => {
61
- const colour = coloursObj[key];
58
+ /**
59
+ * Converts the given colours to CSS variables.
60
+ *
61
+ * @param coloursObj A (potentially nested) object whose keys are colour names
62
+ * and values are CSS colours.
63
+ * @param prefix A prefix to prepend to the CSS variables.
64
+ * @returns A string containing CSS variable definitions for the colours.
65
+ */
66
+ function varify(coloursObj: Object, prefix = "--colour"): string {
67
+ return Object.entries(coloursObj)
68
+ .map(([key, colour]) => {
62
69
  if (typeof colour === "string") {
63
70
  return `${prefix}-${key}: ${colour};`;
64
71
  } else {