From ba018ccf050b94e2327defc3613852a7c2e59e29 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Wed, 6 Nov 2024 14:14:16 -0800 Subject: [PATCH 01/52] refactor: Update ContinuousFlyout for compatibility with new flyout API. --- .../src/ContinuousFlyout.js | 108 +++-------- .../src/recyclable_block_flyout_inflater.ts | 183 ++++++++++++++++++ plugins/continuous-toolbox/tsconfig.json | 16 ++ 3 files changed, 222 insertions(+), 85 deletions(-) create mode 100644 plugins/continuous-toolbox/src/recyclable_block_flyout_inflater.ts create mode 100644 plugins/continuous-toolbox/tsconfig.json diff --git a/plugins/continuous-toolbox/src/ContinuousFlyout.js b/plugins/continuous-toolbox/src/ContinuousFlyout.js index 32b063bb6a..2d7c28c9d4 100644 --- a/plugins/continuous-toolbox/src/ContinuousFlyout.js +++ b/plugins/continuous-toolbox/src/ContinuousFlyout.js @@ -11,6 +11,7 @@ import * as Blockly from 'blockly/core'; import {ContinuousToolbox} from './ContinuousToolbox'; import {ContinuousFlyoutMetrics} from './ContinuousMetricsFlyout'; +import {RecyclableBlockFlyoutInflater} from './recyclable_block_flyout_inflater'; /** * Class for continuous flyout. @@ -40,14 +41,6 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { */ this.scrollAnimationFraction = 0.3; - /** - * Whether to recycle blocks when refreshing the flyout. When false, do not - * allow anything to be recycled. The default is to recycle. - * @type {boolean} - * @private - */ - this.recyclingEnabled_ = true; - this.workspace_.setMetricsManager( new ContinuousFlyoutMetrics(this.workspace_, this), ); @@ -80,26 +73,25 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { */ recordScrollPositions() { this.scrollPositions = []; - const categoryLabels = this.buttons_.filter( - (button) => - button.isLabel() && - this.getParentToolbox_().getCategoryByName(button.getButtonText()), - ); - for (const [index, button] of categoryLabels.entries()) { - if (button.isLabel()) { - const position = button.getPosition(); - const adjustedPosition = new Blockly.utils.Coordinate( - position.x, - position.y - this.labelGaps[index], - ); - this.scrollPositions.push({ - name: button.getButtonText(), - position: adjustedPosition, - }); - } + const categoryLabels = this.getContents() + .filter(this.toolboxItemIsLabel.bind(this)) + .map((item) => item.element); + for (const [index, label] of categoryLabels.entries()) { + this.scrollPositions.push({ + name: label.getButtonText(), + position: label.getPosition(), + }); } } + toolboxItemIsLabel(item) { + return ( + item.type === 'label' && + item.element.isLabel() && + this.getParentToolbox_().getCategoryByName(item.element.getButtonText()) + ); + } + /** * Returns the scroll position for the given category name. * @param {string} name Category name. @@ -227,52 +219,10 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { if (!this.getParentToolbox_().getSelectedItem()) { this.selectCategoryByScrollPosition_(0); } - } - - /** - * Determine if this block can be recycled in the flyout. Blocks that have no - * variables and are not dynamic shadows can be recycled. - * @param {!Blockly.BlockSvg} block The block to attempt to recycle. - * @returns {boolean} True if the block can be recycled. - * @protected - */ - blockIsRecyclable_(block) { - if (!this.recyclingEnabled_) { - return false; + const inflater = this.getInflaterForType('block'); + if (inflater instanceof RecyclableBlockFlyoutInflater) { + inflater.emptyRecycledBlocks(); } - - // If the block needs to parse mutations, never recycle. - if (block.mutationToDom && block.domToMutation) { - return false; - } - - if (!block.isEnabled()) { - return false; - } - - for (const input of block.inputList) { - for (const field of input.fieldRow) { - // No variables. - if (field.referencesVariables()) { - return false; - } - if (field instanceof Blockly.FieldDropdown) { - if (field.isOptionListDynamic()) { - return false; - } - } - } - // Check children. - if (input.connection) { - const targetBlock = - /** @type {Blockly.BlockSvg} */ - (input.connection.targetBlock()); - if (targetBlock && !this.blockIsRecyclable_(targetBlock)) { - return false; - } - } - } - return true; } /** @@ -292,21 +242,9 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { * @public */ setRecyclingEnabled(isEnabled) { - this.recyclingEnabled_ = isEnabled; - } - - /** - * Lay out the blocks in the flyout. - * @param {Array} contents The blocks and buttons to lay out. - * @param {Array} gaps The visible gaps between blocks. - */ - layout_(contents, gaps) { - super.layout_(contents, gaps); - this.labelGaps = []; - for (const [index, item] of contents.entries()) { - if (item.type === 'button' && item.button.isLabel()) { - this.labelGaps.push(gaps[index - 1] ?? this.MARGIN); - } + const inflater = this.getInflaterForType('block'); + if (inflater instanceof RecyclableBlockFlyoutInflater) { + inflater.setRecyclingEnabled(isEnabled); } } } diff --git a/plugins/continuous-toolbox/src/recyclable_block_flyout_inflater.ts b/plugins/continuous-toolbox/src/recyclable_block_flyout_inflater.ts new file mode 100644 index 0000000000..662f4c2c0e --- /dev/null +++ b/plugins/continuous-toolbox/src/recyclable_block_flyout_inflater.ts @@ -0,0 +1,183 @@ +/** + * @license + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as Blockly from 'blockly/core'; + +/** + * A block inflater that caches and reuses blocks to improve performance. + */ +export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater { + /** + * Whether or not block recycling is enabled. + */ + recyclingEnabled = true; + + /** + * Map from block type to block instance. + */ + recycledBlocks = new Map(); + + /** + * Toggles whether or not recycling is enabled. + * + * @param enabled True if recycling should be enabled. + */ + setRecyclingEnabled(enabled: boolean) { + this.recyclingEnabled = enabled; + } + + /** + * Creates a new block from the given block definition. + * + * @param blockDefinition The definition to create a block from. + * @param workspace The workspace to create the block on. + * @returns The newly created block. + */ + override createBlock( + blockDefinition: Blockly.utils.toolbox.BlockInfo, + workspace: Blockly.WorkspaceSvg, + ): Blockly.BlockSvg { + const blockType = this.getTypeFromDefinition(blockDefinition); + return ( + this.getRecycledBlock(blockType) ?? + super.createBlock(blockDefinition, workspace) + ); + } + + /** + * Returns the type of a block from an XML or JSON block definition. + * + * @param blockDefinition The block definition to parse. + * @returns The block type. + */ + getTypeFromDefinition( + blockDefinition: Blockly.utils.toolbox.BlockInfo, + ): string { + let type: string | null | undefined; + if (blockDefinition['blockxml']) { + const xml = + typeof blockDefinition['blockxml'] === 'string' + ? Blockly.utils.xml.textToDom(blockDefinition['blockxml']) + : (blockDefinition['blockxml'] as Element); + type = xml.getAttribute('type'); + } else { + type = blockDefinition['type']; + } + + if (!type) { + throw new Error( + `Block type is not specified in block definition: ${JSON.stringify( + blockDefinition, + )}`, + ); + } + return type; + } + + /** + * Puts a previously created block into the recycle bin and moves it to the + * top of the workspace. Used during large workspace swaps to limit the number + * of new DOM elements we need to create. + * + * @param block The block to recycle. + */ + recycleBlock(block: Blockly.BlockSvg) { + const xy = block.getRelativeToSurfaceXY(); + block.moveBy(-xy.x, -xy.y); + this.recycledBlocks.set(block.type, block); + } + + /** + * Returns a block from the cache of recycled blocks with the given type, or + * undefined if one cannot be found. + * + * @param blockType The type of the block to try to recycle. + * @returns The recycled block, or undefined if one could not be recycled. + */ + getRecycledBlock(blockType: string): Blockly.BlockSvg | undefined { + const block = this.recycledBlocks.get(blockType); + this.recycledBlocks.delete(blockType); + return block; + } + + /** + * Returns whether the given block can be recycled or not. + * + * @param block The block to check for recyclability. + * @returns True if the block can be recycled. False otherwise. + */ + blockIsRecyclable(block: Blockly.Block): boolean { + if (!this.recyclingEnabled) { + return false; + } + + // If the block needs to parse mutations, never recycle. + if (block.mutationToDom && block.domToMutation) { + return false; + } + + if (!block.isEnabled()) { + return false; + } + + for (const input of block.inputList) { + for (const field of input.fieldRow) { + // No variables. + if (field.referencesVariables()) { + return false; + } + if (field instanceof Blockly.FieldDropdown) { + if (field.isOptionListDynamic()) { + return false; + } + } + } + // Check children. + if (input.connection) { + const targetBlock = input.connection.targetBlock(); + if (targetBlock && !this.blockIsRecyclable(targetBlock)) { + return false; + } + } + } + return true; + } + + /** + * Disposes of the provided block. + * + * @param element The block to dispose of. + */ + override disposeElement(element: Blockly.BlockSvg) { + if (this.blockIsRecyclable(element)) { + this.removeListeners(element.id); + this.recycleBlock(element); + } else { + super.disposeElement(element); + } + } + + /** + * Clears the cache of recycled blocks. + */ + emptyRecycledBlocks() { + this.recycledBlocks.forEach((block) => block.dispose(false, false)); + this.recycledBlocks.clear(); + } +} + +/** + * Registers the recyclable block flyout inflater, replacing the standard + * block flyout inflater. + */ +export function registerRecyclableBlockFlyoutInflater() { + Blockly.registry.unregister(Blockly.registry.Type.FLYOUT_INFLATER, 'block'); + Blockly.registry.register( + Blockly.registry.Type.FLYOUT_INFLATER, + 'block', + RecyclableBlockFlyoutInflater, + ); +} diff --git a/plugins/continuous-toolbox/tsconfig.json b/plugins/continuous-toolbox/tsconfig.json new file mode 100644 index 0000000000..b849232f2b --- /dev/null +++ b/plugins/continuous-toolbox/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "baseUrl": "./", + "outDir": "dist", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "module": "es2015", + "moduleResolution": "bundler", + "target": "es6", + "strict": true + }, + // NOTE: `test/**/*` is automatically included in `blockly-scripts start`. + // Only src matters for production builds. + "include": ["src"] +} From 1948c29fd05d48f96d07131ae6102303d5d4f34c Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Wed, 6 Nov 2024 14:15:06 -0800 Subject: [PATCH 02/52] chore: Rename ContinuousFlyout.js to ContinuousFlyout.ts. --- .../src/{ContinuousFlyout.js => ContinuousFlyout.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/continuous-toolbox/src/{ContinuousFlyout.js => ContinuousFlyout.ts} (100%) diff --git a/plugins/continuous-toolbox/src/ContinuousFlyout.js b/plugins/continuous-toolbox/src/ContinuousFlyout.ts similarity index 100% rename from plugins/continuous-toolbox/src/ContinuousFlyout.js rename to plugins/continuous-toolbox/src/ContinuousFlyout.ts From caebe497a67f9dc09cd7082adbbd70c315768c09 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Wed, 6 Nov 2024 15:29:01 -0800 Subject: [PATCH 03/52] chore: Rename ContinuousToolbox.js to ContinuousToolbox.ts. --- .../src/{ContinuousToolbox.js => ContinuousToolbox.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/continuous-toolbox/src/{ContinuousToolbox.js => ContinuousToolbox.ts} (100%) diff --git a/plugins/continuous-toolbox/src/ContinuousToolbox.js b/plugins/continuous-toolbox/src/ContinuousToolbox.ts similarity index 100% rename from plugins/continuous-toolbox/src/ContinuousToolbox.js rename to plugins/continuous-toolbox/src/ContinuousToolbox.ts From e1de24138c1ffda37ebea7367f78b4cef2006052 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Wed, 6 Nov 2024 15:49:58 -0800 Subject: [PATCH 04/52] chore: Rename ContinuousMetricsFlyout.js to ContinuousMetricsFlyout.ts. --- .../{ContinuousMetricsFlyout.js => ContinuousMetricsFlyout.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/continuous-toolbox/src/{ContinuousMetricsFlyout.js => ContinuousMetricsFlyout.ts} (100%) diff --git a/plugins/continuous-toolbox/src/ContinuousMetricsFlyout.js b/plugins/continuous-toolbox/src/ContinuousMetricsFlyout.ts similarity index 100% rename from plugins/continuous-toolbox/src/ContinuousMetricsFlyout.js rename to plugins/continuous-toolbox/src/ContinuousMetricsFlyout.ts From 5164c0c95f9664724c060e373a93e30b41fb6b8a Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 7 Nov 2024 08:56:09 -0800 Subject: [PATCH 05/52] chore: Rename ContinuousCategory.js to ContinuousCategory.ts. --- .../src/{ContinuousCategory.js => ContinuousCategory.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/continuous-toolbox/src/{ContinuousCategory.js => ContinuousCategory.ts} (100%) diff --git a/plugins/continuous-toolbox/src/ContinuousCategory.js b/plugins/continuous-toolbox/src/ContinuousCategory.ts similarity index 100% rename from plugins/continuous-toolbox/src/ContinuousCategory.js rename to plugins/continuous-toolbox/src/ContinuousCategory.ts From 9fcab31b92eecffb8fb84aa1927beb3cb97d0b5b Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 7 Nov 2024 09:03:46 -0800 Subject: [PATCH 06/52] chore: Rename ContinuousMetrics.js to ContinuousMetrics.ts. --- .../src/{ContinuousMetrics.js => ContinuousMetrics.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/continuous-toolbox/src/{ContinuousMetrics.js => ContinuousMetrics.ts} (100%) diff --git a/plugins/continuous-toolbox/src/ContinuousMetrics.js b/plugins/continuous-toolbox/src/ContinuousMetrics.ts similarity index 100% rename from plugins/continuous-toolbox/src/ContinuousMetrics.js rename to plugins/continuous-toolbox/src/ContinuousMetrics.ts From 5b73379bf1efae09860110ad924b989dc5ccb590 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 7 Nov 2024 09:17:40 -0800 Subject: [PATCH 07/52] chore: Rename index.js to index.ts. --- plugins/continuous-toolbox/src/{index.js => index.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/continuous-toolbox/src/{index.js => index.ts} (100%) diff --git a/plugins/continuous-toolbox/src/index.js b/plugins/continuous-toolbox/src/index.ts similarity index 100% rename from plugins/continuous-toolbox/src/index.js rename to plugins/continuous-toolbox/src/index.ts From 27f8d774138ad6bc971fcc3962ffad897f737d81 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 7 Nov 2024 09:36:18 -0800 Subject: [PATCH 08/52] refactor: Convert ContinuousToolbox to Typescript --- .../src/ContinuousCategory.ts | 35 ++- .../src/ContinuousFlyout.ts | 202 ++++++++---------- .../src/ContinuousMetrics.ts | 12 +- .../src/ContinuousMetricsFlyout.ts | 21 +- .../src/ContinuousToolbox.ts | 81 +++---- .../src/recyclable_block_flyout_inflater.ts | 16 +- 6 files changed, 164 insertions(+), 203 deletions(-) diff --git a/plugins/continuous-toolbox/src/ContinuousCategory.ts b/plugins/continuous-toolbox/src/ContinuousCategory.ts index f0c29fe6f5..6ee2b6ae69 100644 --- a/plugins/continuous-toolbox/src/ContinuousCategory.ts +++ b/plugins/continuous-toolbox/src/ContinuousCategory.ts @@ -12,47 +12,42 @@ import * as Blockly from 'blockly/core'; /** Toolbox category for continuous toolbox. */ export class ContinuousCategory extends Blockly.ToolboxCategory { - /** - * Constructor for ContinuousCategory which is used in ContinuousToolbox. - * @override - */ - constructor(categoryDef, toolbox) { - super(categoryDef, toolbox); - } - - /** @override */ - createLabelDom_(name) { + override createLabelDom_(name: string): Element { const label = document.createElement('div'); label.setAttribute('id', this.getId() + '.label'); label.textContent = name; - label.classList.add(this.cssConfig_['label']); + label.classList.add(this.cssConfig_['label'] ?? ''); return label; } - /** @override */ - createIconDom_() { + override createIconDom_(): Element { const icon = document.createElement('div'); icon.classList.add('categoryBubble'); icon.style.backgroundColor = this.colour_; return icon; } - /** @override */ - addColourBorder_() { + override addColourBorder_() { // No-op } - /** @override */ - setSelected(isSelected) { + override setSelected(isSelected: boolean) { + if (!this.rowDiv_ || !this.htmlDiv_) return; if (isSelected) { this.rowDiv_.style.backgroundColor = 'gray'; - Blockly.utils.dom.addClass(this.rowDiv_, this.cssConfig_['selected']); + Blockly.utils.dom.addClass( + this.rowDiv_, + this.cssConfig_['selected'] ?? '', + ); } else { this.rowDiv_.style.backgroundColor = ''; - Blockly.utils.dom.removeClass(this.rowDiv_, this.cssConfig_['selected']); + Blockly.utils.dom.removeClass( + this.rowDiv_, + this.cssConfig_['selected'] ?? '', + ); } Blockly.utils.aria.setState( - /** @type {!Element} */ (this.htmlDiv_), + this.htmlDiv_, Blockly.utils.aria.State.SELECTED, isSelected, ); diff --git a/plugins/continuous-toolbox/src/ContinuousFlyout.ts b/plugins/continuous-toolbox/src/ContinuousFlyout.ts index 2d7c28c9d4..2494dfd969 100644 --- a/plugins/continuous-toolbox/src/ContinuousFlyout.ts +++ b/plugins/continuous-toolbox/src/ContinuousFlyout.ts @@ -17,116 +17,92 @@ import {RecyclableBlockFlyoutInflater} from './recyclable_block_flyout_inflater' * Class for continuous flyout. */ export class ContinuousFlyout extends Blockly.VerticalFlyout { - /** @override */ - constructor(workspaceOptions) { + /** + * Target scroll position, used to smoothly scroll to a given category + * location when selected. + */ + private scrollTarget?: number; + + /** + * Map from category name to its position in the flyout. + */ + private scrollPositions = new Map(); + + /** + * The percentage of the distance to the scrollTarget that should be + * scrolled at a time. Lower values will produce a smoother, slower scroll. + */ + protected scrollAnimationFraction = 0.3; + + override autoClose = false; + + constructor(workspaceOptions: Blockly.Options) { super(workspaceOptions); - /** - * List of scroll positions for each category. - * @type {!Array<{name: string, position: !Object}>} - */ - this.scrollPositions = []; - - /** - * Target scroll position, used to smoothly scroll to a given category - * location when selected. - * @type {?number} - */ - this.scrollTarget = null; - - /** - * The percentage of the distance to the scrollTarget that should be - * scrolled at a time. Lower values will produce a smoother, slower scroll. - * @type {number} - */ - this.scrollAnimationFraction = 0.3; - - this.workspace_.setMetricsManager( - new ContinuousFlyoutMetrics(this.workspace_, this), + this.getWorkspace().setMetricsManager( + new ContinuousFlyoutMetrics(this.getWorkspace(), this), ); - this.workspace_.addChangeListener((e) => { + this.getWorkspace().addChangeListener((e: Blockly.Events.Abstract) => { if (e.type === Blockly.Events.VIEWPORT_CHANGE) { - this.selectCategoryByScrollPosition_(-this.workspace_.scrollY); + this.selectCategoryByScrollPosition(-this.getWorkspace().scrollY); } }); - - this.autoClose = false; } /** * Gets parent toolbox. * Since we registered the ContinuousToolbox, we know that's its type. - * @returns {!ContinuousToolbox} Toolbox that owns this flyout. - * @private + * @returns Toolbox that owns this flyout. */ - getParentToolbox_() { - const toolbox = this.targetWorkspace.getToolbox(); - return /** @type {!ContinuousToolbox} */ (toolbox); + private getParentToolbox(): ContinuousToolbox { + return this.targetWorkspace.getToolbox() as ContinuousToolbox; } /** * Records scroll position for each category in the toolbox. * The scroll position is determined by the coordinates of each category's * label after the entire flyout has been rendered. - * @package */ - recordScrollPositions() { - this.scrollPositions = []; + private recordScrollPositions() { + this.scrollPositions.clear(); const categoryLabels = this.getContents() .filter(this.toolboxItemIsLabel.bind(this)) .map((item) => item.element); for (const [index, label] of categoryLabels.entries()) { - this.scrollPositions.push({ - name: label.getButtonText(), - position: label.getPosition(), - }); + this.scrollPositions.set(label.getButtonText(), label.getPosition().y); } } - toolboxItemIsLabel(item) { - return ( + protected toolboxItemIsLabel( + item: Blockly.FlyoutItem, + ): item is {type: string; element: Blockly.FlyoutButton} { + return !!( item.type === 'label' && + item.element instanceof Blockly.FlyoutButton && item.element.isLabel() && - this.getParentToolbox_().getCategoryByName(item.element.getButtonText()) + this.getParentToolbox().getCategoryByName(item.element.getButtonText()) ); } - /** - * Returns the scroll position for the given category name. - * @param {string} name Category name. - * @returns {?Object} Scroll position for given category, or null if not - * found. - * @package - */ - getCategoryScrollPosition(name) { - for (const scrollInfo of this.scrollPositions) { - if (scrollInfo.name === name) { - return scrollInfo.position; - } - } - console.warn(`Scroll position not recorded for category ${name}`); - return null; - } - /** * Selects an item in the toolbox based on the scroll position of the flyout. - * @param {number} position Current scroll position of the workspace. - * @private + * @param position Current scroll position of the workspace. */ - selectCategoryByScrollPosition_(position) { + private selectCategoryByScrollPosition(position: number) { // If we are currently auto-scrolling, due to selecting a category by // clicking on it, do not update the category selection. - if (this.scrollTarget !== null) { + if (this.scrollTarget) { return; } - const scaledPosition = Math.round(position / this.workspace_.scale); + const scaledPosition = Math.round(position / this.getWorkspace().scale); // Traverse the array of scroll positions in reverse, so we can select the // furthest category that the scroll position is beyond. - for (let i = this.scrollPositions.length - 1; i >= 0; i--) { - const category = this.scrollPositions[i]; - if (scaledPosition >= category.position.y) { - this.getParentToolbox_().selectCategoryByName(category.name); + for (const [name, position] of [ + ...this.scrollPositions.entries(), + ].reverse()) { + if (scaledPosition >= position) { + this.getParentToolbox().selectCategoryByName(name); return; } } @@ -134,58 +110,65 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { /** * Scrolls flyout to given position. - * @param {number} position The Y coordinate to scroll to. + * @param position The Y coordinate to scroll to. */ - scrollTo(position) { + scrollTo(position: number) { // Set the scroll target to either the scaled position or the lowest // possible scroll point, whichever is smaller. - const metrics = this.workspace_.getMetrics(); + const metrics = this.getWorkspace().getMetrics(); this.scrollTarget = Math.min( - position * this.workspace_.scale, + position * this.getWorkspace().scale, metrics.scrollHeight - metrics.viewHeight, ); - this.stepScrollAnimation_(); + this.stepScrollAnimation(); + } + + scrollToCategory(category: Blockly.ISelectableToolboxItem) { + const position = this.scrollPositions.get(category.getName()); + if (!position) { + console.warn(`Scroll position not recorded for category ${name}`); + return; + } + this.scrollTo(position); } /** * Step the scrolling animation by scrolling a fraction of the way to * a scroll target, and request the next frame if necessary. - * @private */ - stepScrollAnimation_() { - if (this.scrollTarget === null) { - return; - } + private stepScrollAnimation() { + if (!this.scrollTarget) return; - const currentScrollPos = -this.workspace_.scrollY; + const currentScrollPos = -this.getWorkspace().scrollY; const diff = this.scrollTarget - currentScrollPos; if (Math.abs(diff) < 1) { - this.workspace_.scrollbar.setY(this.scrollTarget); - this.scrollTarget = null; + this.getWorkspace().scrollbar?.setY(this.scrollTarget); + this.scrollTarget = undefined; return; } - this.workspace_.scrollbar.setY( + this.getWorkspace().scrollbar?.setY( currentScrollPos + diff * this.scrollAnimationFraction, ); - requestAnimationFrame(this.stepScrollAnimation_.bind(this)); + requestAnimationFrame(this.stepScrollAnimation.bind(this)); } /** * Add additional padding to the bottom of the flyout if needed, * in order to make it possible to scroll to the top of the last category. - * @param {!Blockly.MetricsManager.ContainerRegion} contentMetrics Content - * metrics for the flyout. - * @param {!Blockly.MetricsManager.ContainerRegion} viewMetrics View metrics - * for the flyout. - * @returns {number} Additional bottom padding. + * @param contentMetrics Content metrics for the flyout. + * @param viewMetrics View metrics for the flyout. + * @returns Additional bottom padding. */ - calculateBottomPadding(contentMetrics, viewMetrics) { - if (this.scrollPositions.length > 0) { - const lastCategory = - this.scrollPositions[this.scrollPositions.length - 1]; - const lastPosition = lastCategory.position.y * this.workspace_.scale; + calculateBottomPadding( + contentMetrics: Blockly.MetricsManager.ContainerRegion, + viewMetrics: Blockly.MetricsManager.ContainerRegion, + ): number { + if (this.scrollPositions.size > 0) { + const lastPosition = + ([...this.scrollPositions.values()].pop() ?? 0) * + this.getWorkspace().scale; const lastCategoryHeight = contentMetrics.height - lastPosition; if (lastCategoryHeight < viewMetrics.height) { return viewMetrics.height - lastCategoryHeight; @@ -194,8 +177,7 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { return 0; } - /** @override */ - getX() { + override getX(): number { if ( this.isVisible() && this.targetWorkspace.toolboxPosition === this.toolboxPosition_ && @@ -209,15 +191,12 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { return super.getX(); } - /** - * @override - */ - show(flyoutDef) { + override show(flyoutDef: Blockly.utils.toolbox.FlyoutDefinition | string) { super.show(flyoutDef); this.recordScrollPositions(); - this.workspace_.resizeContents(); - if (!this.getParentToolbox_().getSelectedItem()) { - this.selectCategoryByScrollPosition_(0); + this.getWorkspace().resizeContents(); + if (!this.getParentToolbox().getSelectedItem()) { + this.selectCategoryByScrollPosition(0); } const inflater = this.getInflaterForType('block'); if (inflater instanceof RecyclableBlockFlyoutInflater) { @@ -227,21 +206,20 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { /** * Sets the function used to determine whether a block is recyclable. - * @param {function(!Blockly.BlockSvg):boolean} func The function used to - * determine if a block is recyclable. - * @public + * @param func The function used to determine if a block is recyclable. */ - setBlockIsRecyclable(func) { - this.blockIsRecyclable_ = func; + setBlockIsRecyclable(func: (block: Blockly.Block) => boolean) { + const inflater = this.getInflaterForType('block'); + if (inflater instanceof RecyclableBlockFlyoutInflater) { + inflater.setRecyclingEligibilityChecker(func); + } } /** * Set whether the flyout can recycle blocks. - * @param {boolean} isEnabled True to allow blocks to be recycled, false - * otherwise. - * @public + * @param isEnabled True to allow blocks to be recycled, false otherwise. */ - setRecyclingEnabled(isEnabled) { + setRecyclingEnabled(isEnabled: boolean) { const inflater = this.getInflaterForType('block'); if (inflater instanceof RecyclableBlockFlyoutInflater) { inflater.setRecyclingEnabled(isEnabled); diff --git a/plugins/continuous-toolbox/src/ContinuousMetrics.ts b/plugins/continuous-toolbox/src/ContinuousMetrics.ts index 97b9a72812..7c048e0ab2 100644 --- a/plugins/continuous-toolbox/src/ContinuousMetrics.ts +++ b/plugins/continuous-toolbox/src/ContinuousMetrics.ts @@ -12,16 +12,13 @@ import * as Blockly from 'blockly/core'; /** Computes metrics for a toolbox with an always open flyout. */ export class ContinuousMetrics extends Blockly.MetricsManager { - /** @override */ - constructor(workspace) { - super(workspace); - } /** * Computes the viewport size to not include the toolbox and the flyout. * The default viewport includes the flyout. - * @override */ - getViewMetrics(getWorkspaceCoordinates = undefined) { + override getViewMetrics( + getWorkspaceCoordinates?: boolean, + ): Blockly.MetricsManager.ContainerRegion { const scale = getWorkspaceCoordinates ? this.workspace_.scale : 1; const svgMetrics = this.getSvgMetrics(); const toolboxMetrics = this.getToolboxMetrics(); @@ -54,9 +51,8 @@ export class ContinuousMetrics extends Blockly.MetricsManager { /** * Moves the absoluteLeft and absoluteTop so they no longer include the * flyout. - * @override */ - getAbsoluteMetrics() { + override getAbsoluteMetrics(): Blockly.MetricsManager.AbsoluteMetrics { const toolboxMetrics = this.getToolboxMetrics(); const flyoutMetrics = this.getFlyoutMetrics(false); const toolboxPosition = toolboxMetrics.position; diff --git a/plugins/continuous-toolbox/src/ContinuousMetricsFlyout.ts b/plugins/continuous-toolbox/src/ContinuousMetricsFlyout.ts index 90b84a872e..69674c9735 100644 --- a/plugins/continuous-toolbox/src/ContinuousMetricsFlyout.ts +++ b/plugins/continuous-toolbox/src/ContinuousMetricsFlyout.ts @@ -5,22 +5,18 @@ */ import * as Blockly from 'blockly/core'; +import type {ContinuousFlyout} from './ContinuousFlyout'; /** Adds additional padding to the bottom of the flyout if needed. */ export class ContinuousFlyoutMetrics extends Blockly.FlyoutMetricsManager { - /** @override */ - constructor(workspace, flyout) { - super(workspace, flyout); - } /** * Adds additional padding to the bottom of the flyout if needed, * in order to make it possible to scroll to the top of the last category. - * @override */ - getScrollMetrics( - getWorkspaceCoordinates = undefined, - cachedViewMetrics = undefined, - cachedContentMetrics = undefined, + override getScrollMetrics( + getWorkspaceCoordinates?: boolean, + cachedViewMetrics?: Blockly.MetricsManager.ContainerRegion, + cachedContentMetrics?: Blockly.MetricsManager.ContainerRegion, ) { const scrollMetrics = super.getScrollMetrics( getWorkspaceCoordinates, @@ -33,10 +29,9 @@ export class ContinuousFlyoutMetrics extends Blockly.FlyoutMetricsManager { cachedViewMetrics || this.getViewMetrics(getWorkspaceCoordinates); if (scrollMetrics) { - scrollMetrics.height += this.flyout_.calculateBottomPadding( - contentMetrics, - viewMetrics, - ); + scrollMetrics.height += ( + this.flyout_ as ContinuousFlyout + ).calculateBottomPadding(contentMetrics, viewMetrics); } return scrollMetrics; } diff --git a/plugins/continuous-toolbox/src/ContinuousToolbox.ts b/plugins/continuous-toolbox/src/ContinuousToolbox.ts index 634f9a2033..f0454f655c 100644 --- a/plugins/continuous-toolbox/src/ContinuousToolbox.ts +++ b/plugins/continuous-toolbox/src/ContinuousToolbox.ts @@ -15,21 +15,14 @@ import {ContinuousFlyout} from './ContinuousFlyout'; * Class for continuous toolbox. */ export class ContinuousToolbox extends Blockly.Toolbox { - /** @override */ - constructor(workspace) { - super(workspace); - } - - /** @override */ - init() { + override init() { super.init(); // Populate the flyout with all blocks and show it immediately. const flyout = this.getFlyout(); flyout.show(this.getInitialFlyoutContents_()); - flyout.recordScrollPositions(); - this.workspace_.addChangeListener((e) => { + this.getWorkspace().addChangeListener((e: Blockly.Events.Abstract) => { if ( e.type === Blockly.Events.BLOCK_CREATE || e.type === Blockly.Events.BLOCK_DELETE @@ -39,37 +32,31 @@ export class ContinuousToolbox extends Blockly.Toolbox { }); } - /** @override */ - getFlyout() { - return /** @type {ContinuousFlyout} */ (super.getFlyout()); + override getFlyout(): ContinuousFlyout { + return super.getFlyout() as ContinuousFlyout; } /** * Gets the contents that should be shown in the flyout immediately. * This includes all blocks and labels for each category of block. - * @returns {!Blockly.utils.toolbox.FlyoutItemInfoArray} Flyout contents. - * @private + * @returns Flyout contents. */ - getInitialFlyoutContents_() { - /** @type {!Blockly.utils.toolbox.FlyoutItemInfoArray} */ - let contents = []; - for (const toolboxItem of this.contents_) { + private getInitialFlyoutContents_(): Blockly.utils.toolbox.FlyoutItemInfoArray { + let contents: Blockly.utils.toolbox.FlyoutItemInfoArray = []; + for (const toolboxItem of this.getToolboxItems()) { if (toolboxItem instanceof Blockly.ToolboxCategory) { // Create a label node to go at the top of the category contents.push({kind: 'LABEL', text: toolboxItem.getName()}); - /** - * @type {string|Blockly.utils.toolbox.FlyoutItemInfoArray| - * Blockly.utils.toolbox.FlyoutItemInfo} - */ let itemContents = toolboxItem.getContents(); // Handle custom categories (e.g. variables and functions) if (typeof itemContents === 'string') { - itemContents = - /** @type {!Blockly.utils.toolbox.DynamicCategoryInfo} */ ({ + itemContents = [ + { custom: itemContents, kind: 'CATEGORY', - }); + }, + ]; } contents = contents.concat(itemContents); } @@ -77,43 +64,42 @@ export class ContinuousToolbox extends Blockly.Toolbox { return contents; } - /** @override */ - refreshSelection() { + override refreshSelection() { this.getFlyout().show(this.getInitialFlyoutContents_()); } - /** @override */ - updateFlyout_(_oldItem, newItem) { + override updateFlyout_( + _oldItem: Blockly.ISelectableToolboxItem | null, + newItem: Blockly.ISelectableToolboxItem | null, + ) { if (newItem) { - const target = this.getFlyout().getCategoryScrollPosition( - newItem.name_, - ).y; - this.getFlyout().scrollTo(target); + this.getFlyout().scrollToCategory(newItem); } } - /** @override */ - shouldDeselectItem_(oldItem, newItem) { + override shouldDeselectItem_( + oldItem: Blockly.ISelectableToolboxItem | null, + newItem: Blockly.ISelectableToolboxItem | null, + ): boolean { // Should not deselect if the same category is clicked again. - return oldItem && oldItem !== newItem; + return !!(oldItem && oldItem !== newItem); } /** * Gets a category by name. - * @param {string} name Name of category to get. - * @returns {?Blockly.ToolboxCategory} Category, or null if not - * found. + * @param name Name of category to get. + * @returns Category, or null if not found. * @package */ - getCategoryByName(name) { - const category = this.contents_.find( + getCategoryByName(name: string): Blockly.ISelectableToolboxItem | null { + const category = this.getToolboxItems().find( (item) => item instanceof Blockly.ToolboxCategory && item.isSelectable() && name === item.getName(), ); if (category) { - return /** @type {!Blockly.ToolboxCategory} */ (category); + return category as Blockly.ISelectableToolboxItem; } return null; } @@ -122,17 +108,17 @@ export class ContinuousToolbox extends Blockly.Toolbox { * Selects the category with the given name. * Similar to setSelectedItem, but importantly, does not call updateFlyout * because this is called while the flyout is being scrolled. - * @param {string} name Name of category to select. + * @param name Name of category to select. * @package */ - selectCategoryByName(name) { + selectCategoryByName(name: string) { const newItem = this.getCategoryByName(name); if (!newItem) { return; } const oldItem = this.selectedItem_; - if (this.shouldDeselectItem_(oldItem, newItem)) { + if (oldItem && this.shouldDeselectItem_(oldItem, newItem)) { this.deselectItem_(oldItem); } @@ -141,8 +127,7 @@ export class ContinuousToolbox extends Blockly.Toolbox { } } - /** @override */ - getClientRect() { + override getClientRect(): Blockly.utils.Rect | null { // If the flyout never closes, it should be the deletable area. const flyout = this.getFlyout(); if (flyout && !flyout.autoClose) { @@ -160,7 +145,7 @@ Blockly.Css.register(` width: 1.25rem; height: 1.25rem; } -.blocklyTreeRow { +.blocklyToolboxCategory { height: initial; padding: 3px 0; } diff --git a/plugins/continuous-toolbox/src/recyclable_block_flyout_inflater.ts b/plugins/continuous-toolbox/src/recyclable_block_flyout_inflater.ts index 662f4c2c0e..da3d79f35b 100644 --- a/plugins/continuous-toolbox/src/recyclable_block_flyout_inflater.ts +++ b/plugins/continuous-toolbox/src/recyclable_block_flyout_inflater.ts @@ -13,12 +13,14 @@ export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater { /** * Whether or not block recycling is enabled. */ - recyclingEnabled = true; + private recyclingEnabled = true; /** * Map from block type to block instance. */ - recycledBlocks = new Map(); + private recycledBlocks = new Map(); + + private recycleEligibilityChecker?: (block: Blockly.Block) => boolean; /** * Toggles whether or not recycling is enabled. @@ -29,6 +31,16 @@ export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater { this.recyclingEnabled = enabled; } + /** + * Sets a function to use to determine a block's ability to be recycled. + * + * @param checker The eligibility check function to use, or undefined to + * revert to the built-in default. + */ + setRecyclingEligibilityChecker(checker?: (block: Blockly.Block) => boolean) { + this.recycleEligibilityChecker = checker; + } + /** * Creates a new block from the given block definition. * From b427748690a249e414dc66f95dfcdb895526f876 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 7 Nov 2024 09:37:18 -0800 Subject: [PATCH 09/52] chore: Name RecyclableBlockFlyoutInflater.ts consistently with other files. --- plugins/continuous-toolbox/src/ContinuousFlyout.ts | 2 +- ...lock_flyout_inflater.ts => RecyclableBlockFlyoutInflater.ts} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename plugins/continuous-toolbox/src/{recyclable_block_flyout_inflater.ts => RecyclableBlockFlyoutInflater.ts} (100%) diff --git a/plugins/continuous-toolbox/src/ContinuousFlyout.ts b/plugins/continuous-toolbox/src/ContinuousFlyout.ts index 2494dfd969..9d05e305ee 100644 --- a/plugins/continuous-toolbox/src/ContinuousFlyout.ts +++ b/plugins/continuous-toolbox/src/ContinuousFlyout.ts @@ -11,7 +11,7 @@ import * as Blockly from 'blockly/core'; import {ContinuousToolbox} from './ContinuousToolbox'; import {ContinuousFlyoutMetrics} from './ContinuousMetricsFlyout'; -import {RecyclableBlockFlyoutInflater} from './recyclable_block_flyout_inflater'; +import {RecyclableBlockFlyoutInflater} from './RecyclableBlockFlyoutInflater'; /** * Class for continuous flyout. diff --git a/plugins/continuous-toolbox/src/recyclable_block_flyout_inflater.ts b/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts similarity index 100% rename from plugins/continuous-toolbox/src/recyclable_block_flyout_inflater.ts rename to plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts From 7f711f1af016d5e11a2bd3324f4f6a6522d3aeb3 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 7 Nov 2024 10:34:07 -0800 Subject: [PATCH 10/52] refactor: Add and use a function for registering the continuous toolbox. --- plugins/continuous-toolbox/README.md | 19 ++--- plugins/continuous-toolbox/package.json | 2 +- .../src/ContinuousCategory.ts | 7 -- .../src/ContinuousMetrics.ts | 6 -- .../src/ContinuousToolbox.ts | 21 ----- .../src/RecyclableBlockFlyoutInflater.ts | 13 ---- plugins/continuous-toolbox/src/index.ts | 77 ++++++++++++++++++- plugins/continuous-toolbox/test/index.js | 12 +-- 8 files changed, 83 insertions(+), 74 deletions(-) diff --git a/plugins/continuous-toolbox/README.md b/plugins/continuous-toolbox/README.md index 81504bed6c..f00841cca2 100644 --- a/plugins/continuous-toolbox/README.md +++ b/plugins/continuous-toolbox/README.md @@ -21,25 +21,20 @@ npm install @blockly/continuous-toolbox --save ## Usage -Include the toolbox, flyout, and metrics manager classes from the plugin in the options struct used when injecting Blockly. This style of flyout works best with a toolbox definition that does not use collapsible categories. +Import and call the `registerContinuousToolbox()` function before injecting +Blockly. This style of flyout works best with a toolbox definition that does +not use collapsible categories. -Note that this plugin uses APIs introduced in the `3.20200924.3` release of Blockly, so you will need to use at least this version or higher. +Note that this plugin uses APIs introduced in the `v12` release of Blockly, so +you will need to use at least this version or higher. ```js import * as Blockly from 'blockly'; -import { - ContinuousToolbox, - ContinuousFlyout, - ContinuousMetrics, -} from '@blockly/continuous-toolbox'; +import {registerContinuousToolbox} from '@blockly/continuous-toolbox'; // Inject Blockly. +registerContinuousToolbox(); const workspace = Blockly.inject('blocklyDiv', { - plugins: { - toolbox: ContinuousToolbox, - flyoutsVerticalToolbox: ContinuousFlyout, - metricsManager: ContinuousMetrics, - }, toolbox: toolboxCategories, // ... your other options here ... }); diff --git a/plugins/continuous-toolbox/package.json b/plugins/continuous-toolbox/package.json index fea7df2717..c5877e3f65 100644 --- a/plugins/continuous-toolbox/package.json +++ b/plugins/continuous-toolbox/package.json @@ -43,7 +43,7 @@ "@blockly/dev-tools": "^8.0.10" }, "peerDependencies": { - "blockly": "^11.0.0" + "blockly": "^12.0.0" }, "publishConfig": { "access": "public", diff --git a/plugins/continuous-toolbox/src/ContinuousCategory.ts b/plugins/continuous-toolbox/src/ContinuousCategory.ts index 6ee2b6ae69..f365b1d32d 100644 --- a/plugins/continuous-toolbox/src/ContinuousCategory.ts +++ b/plugins/continuous-toolbox/src/ContinuousCategory.ts @@ -53,10 +53,3 @@ export class ContinuousCategory extends Blockly.ToolboxCategory { ); } } - -Blockly.registry.register( - Blockly.registry.Type.TOOLBOX_ITEM, - Blockly.ToolboxCategory.registrationName, - ContinuousCategory, - true, -); diff --git a/plugins/continuous-toolbox/src/ContinuousMetrics.ts b/plugins/continuous-toolbox/src/ContinuousMetrics.ts index 7c048e0ab2..6b08f2294f 100644 --- a/plugins/continuous-toolbox/src/ContinuousMetrics.ts +++ b/plugins/continuous-toolbox/src/ContinuousMetrics.ts @@ -77,9 +77,3 @@ export class ContinuousMetrics extends Blockly.MetricsManager { }; } } - -Blockly.registry.register( - Blockly.registry.Type.METRICS_MANAGER, - 'CustomMetricsManager', - ContinuousMetrics, -); diff --git a/plugins/continuous-toolbox/src/ContinuousToolbox.ts b/plugins/continuous-toolbox/src/ContinuousToolbox.ts index f0454f655c..e5c8a804a5 100644 --- a/plugins/continuous-toolbox/src/ContinuousToolbox.ts +++ b/plugins/continuous-toolbox/src/ContinuousToolbox.ts @@ -136,24 +136,3 @@ export class ContinuousToolbox extends Blockly.Toolbox { return super.getClientRect(); } } - -Blockly.Css.register(` -.categoryBubble { - margin: 0 auto 0.125rem; - border-radius: 100%; - border: 1px solid; - width: 1.25rem; - height: 1.25rem; -} -.blocklyToolboxCategory { - height: initial; - padding: 3px 0; -} -.blocklyTreeRowContentContainer { - display: flex; - flex-direction: column; -} -.blocklyTreeLabel { - margin: auto; -} -`); diff --git a/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts b/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts index da3d79f35b..3b2cce664a 100644 --- a/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts +++ b/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts @@ -180,16 +180,3 @@ export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater { this.recycledBlocks.clear(); } } - -/** - * Registers the recyclable block flyout inflater, replacing the standard - * block flyout inflater. - */ -export function registerRecyclableBlockFlyoutInflater() { - Blockly.registry.unregister(Blockly.registry.Type.FLYOUT_INFLATER, 'block'); - Blockly.registry.register( - Blockly.registry.Type.FLYOUT_INFLATER, - 'block', - RecyclableBlockFlyoutInflater, - ); -} diff --git a/plugins/continuous-toolbox/src/index.ts b/plugins/continuous-toolbox/src/index.ts index 6197eca06c..d0bf4bec83 100644 --- a/plugins/continuous-toolbox/src/index.ts +++ b/plugins/continuous-toolbox/src/index.ts @@ -8,7 +8,76 @@ * @fileoverview Continuous-scroll toolbox and flyout that is always open. */ -export * from './ContinuousCategory'; -export * from './ContinuousFlyout'; -export * from './ContinuousMetrics'; -export * from './ContinuousToolbox'; +import * as Blockly from 'blockly/core'; + +import {ContinuousCategory} from './ContinuousCategory'; +import {ContinuousFlyout} from './ContinuousFlyout'; +import {ContinuousMetrics} from './ContinuousMetrics'; +import {ContinuousToolbox} from './ContinuousToolbox'; +import {RecyclableBlockFlyoutInflater} from './RecyclableBlockFlyoutInflater'; + +export { + ContinuousCategory, + ContinuousFlyout, + ContinuousMetrics, + ContinuousToolbox, + RecyclableBlockFlyoutInflater, +}; + +export function registerContinuousToolbox() { + Blockly.registry.register( + Blockly.registry.Type.TOOLBOX_ITEM, + Blockly.ToolboxCategory.registrationName, + ContinuousCategory, + true, + ); + + Blockly.registry.register( + Blockly.registry.Type.METRICS_MANAGER, + 'CustomMetricsManager', + ContinuousMetrics, + true, + ); + + Blockly.registry.register( + Blockly.registry.Type.FLYOUTS_VERTICAL_TOOLBOX, + Blockly.registry.DEFAULT, + ContinuousFlyout, + true, + ); + + Blockly.registry.register( + Blockly.registry.Type.TOOLBOX, + Blockly.registry.DEFAULT, + ContinuousToolbox, + true, + ); + + Blockly.registry.register( + Blockly.registry.Type.FLYOUT_INFLATER, + 'block', + RecyclableBlockFlyoutInflater, + true, + ); + + Blockly.Css.register(` + .categoryBubble { + margin: 0 auto 0.125rem; + border-radius: 100%; + border: 1px solid; + width: 1.25rem; + height: 1.25rem; + } + .blocklyToolboxCategory { + height: initial; + padding: 3px 0; + } + .blocklyTreeRowContentContainer { + display: flex; + flex-direction: column; + } + .blocklyTreeLabel { + margin: auto; + } + `); +} diff --git a/plugins/continuous-toolbox/test/index.js b/plugins/continuous-toolbox/test/index.js index 57b17ef701..618b853960 100644 --- a/plugins/continuous-toolbox/test/index.js +++ b/plugins/continuous-toolbox/test/index.js @@ -10,11 +10,7 @@ import * as Blockly from 'blockly'; import {toolboxCategories, createPlayground} from '@blockly/dev-tools'; -import { - ContinuousToolbox, - ContinuousFlyout, - ContinuousMetrics, -} from '../src/index'; +import {registerContinuousToolbox} from '../src/index'; /** * Create a workspace. @@ -23,6 +19,7 @@ import { * @returns {!Blockly.WorkspaceSvg} The created workspace. */ function createWorkspace(blocklyDiv, options) { + registerContinuousToolbox(); const workspace = Blockly.inject(blocklyDiv, options); return workspace; @@ -31,11 +28,6 @@ function createWorkspace(blocklyDiv, options) { document.addEventListener('DOMContentLoaded', function () { const defaultOptions = { toolbox: toolboxCategories, - plugins: { - toolbox: ContinuousToolbox, - flyoutsVerticalToolbox: ContinuousFlyout, - metricsManager: ContinuousMetrics, - }, }; createPlayground( document.getElementById('root'), From ccfd99efb17e76fb90bd4b3b3363da578e9e1478 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 7 Nov 2024 15:14:27 -0800 Subject: [PATCH 11/52] chore: Improve docs. --- .../src/ContinuousCategory.ts | 20 +++++++++ .../src/ContinuousFlyout.ts | 41 +++++++++++++++++-- .../src/ContinuousMetrics.ts | 12 +++++- .../src/ContinuousMetricsFlyout.ts | 13 +++++- .../src/ContinuousToolbox.ts | 37 ++++++++++++++++- .../src/RecyclableBlockFlyoutInflater.ts | 3 ++ 6 files changed, 116 insertions(+), 10 deletions(-) diff --git a/plugins/continuous-toolbox/src/ContinuousCategory.ts b/plugins/continuous-toolbox/src/ContinuousCategory.ts index f365b1d32d..39175237dd 100644 --- a/plugins/continuous-toolbox/src/ContinuousCategory.ts +++ b/plugins/continuous-toolbox/src/ContinuousCategory.ts @@ -12,6 +12,12 @@ import * as Blockly from 'blockly/core'; /** Toolbox category for continuous toolbox. */ export class ContinuousCategory extends Blockly.ToolboxCategory { + /** + * Creates a DOM element to display the category's label. + * + * @param name The name of this category. + * @returns The newly created category label DOM element. + */ override createLabelDom_(name: string): Element { const label = document.createElement('div'); label.setAttribute('id', this.getId() + '.label'); @@ -20,6 +26,12 @@ export class ContinuousCategory extends Blockly.ToolboxCategory { return label; } + /** + * Creates a DOM element to display the category's icon. This category uses + * color swatches instead of graphical icons. + * + * @returns The newly created category icon DOM element. + */ override createIconDom_(): Element { const icon = document.createElement('div'); icon.classList.add('categoryBubble'); @@ -27,10 +39,18 @@ export class ContinuousCategory extends Blockly.ToolboxCategory { return icon; } + /** + * Adds a color indicator to the toolbox category. Intentionally a no-op. + */ override addColourBorder_() { // No-op } + /** + * Sets whether or not this category is selected in the toolbox. + * + * @param isSelected True if this category is selected, otherwise false. + */ override setSelected(isSelected: boolean) { if (!this.rowDiv_ || !this.htmlDiv_) return; if (isSelected) { diff --git a/plugins/continuous-toolbox/src/ContinuousFlyout.ts b/plugins/continuous-toolbox/src/ContinuousFlyout.ts index 9d05e305ee..2b011c7674 100644 --- a/plugins/continuous-toolbox/src/ContinuousFlyout.ts +++ b/plugins/continuous-toolbox/src/ContinuousFlyout.ts @@ -34,8 +34,16 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { */ protected scrollAnimationFraction = 0.3; + /** + * Prevents the flyout from closing automatically when a block is dragged out. + */ override autoClose = false; + /** + * Creates a new ContinuousFlyout. + * + * @param workspaceOptions The injection options for the flyout's workspace. + */ constructor(workspaceOptions: Blockly.Options) { super(workspaceOptions); @@ -53,6 +61,7 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { /** * Gets parent toolbox. * Since we registered the ContinuousToolbox, we know that's its type. + * * @returns Toolbox that owns this flyout. */ private getParentToolbox(): ContinuousToolbox { @@ -74,6 +83,13 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { } } + /** + * Validates and typechecks that the given toolbox item represents a label. + * + * @param item The toolbox item to check. + * @returns True if the item represents a label in the flyout, and is a + * Blockly.FlyoutButton. + */ protected toolboxItemIsLabel( item: Blockly.FlyoutItem, ): item is {type: string; element: Blockly.FlyoutButton} { @@ -87,6 +103,7 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { /** * Selects an item in the toolbox based on the scroll position of the flyout. + * * @param position Current scroll position of the workspace. */ private selectCategoryByScrollPosition(position: number) { @@ -109,7 +126,8 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { } /** - * Scrolls flyout to given position. + * Scrolls the flyout to given position. + * * @param position The Y coordinate to scroll to. */ scrollTo(position: number) { @@ -124,6 +142,11 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { this.stepScrollAnimation(); } + /** + * Scrolls the flyout to display the given category at the top. + * + * @param category The toolbox category to scroll to in the flyout. + */ scrollToCategory(category: Blockly.ISelectableToolboxItem) { const position = this.scrollPositions.get(category.getName()); if (!position) { @@ -155,11 +178,12 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { } /** - * Add additional padding to the bottom of the flyout if needed, - * in order to make it possible to scroll to the top of the last category. + * Calculates the additional padding needed at the bottom of the flyout in + * order to make it possible to scroll to the top of the last category. + * * @param contentMetrics Content metrics for the flyout. * @param viewMetrics View metrics for the flyout. - * @returns Additional bottom padding. + * @returns The additional bottom padding needed. */ calculateBottomPadding( contentMetrics: Blockly.MetricsManager.ContainerRegion, @@ -177,6 +201,9 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { return 0; } + /** + * Returns the X coordinate for the flyout's position. + */ override getX(): number { if ( this.isVisible() && @@ -191,7 +218,11 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { return super.getX(); } + /** + * Displays the given contents in the flyout. + */ override show(flyoutDef: Blockly.utils.toolbox.FlyoutDefinition | string) { + console.trace(); super.show(flyoutDef); this.recordScrollPositions(); this.getWorkspace().resizeContents(); @@ -206,6 +237,7 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { /** * Sets the function used to determine whether a block is recyclable. + * * @param func The function used to determine if a block is recyclable. */ setBlockIsRecyclable(func: (block: Blockly.Block) => boolean) { @@ -217,6 +249,7 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { /** * Set whether the flyout can recycle blocks. + * * @param isEnabled True to allow blocks to be recycled, false otherwise. */ setRecyclingEnabled(isEnabled: boolean) { diff --git a/plugins/continuous-toolbox/src/ContinuousMetrics.ts b/plugins/continuous-toolbox/src/ContinuousMetrics.ts index 6b08f2294f..d3d5b92efc 100644 --- a/plugins/continuous-toolbox/src/ContinuousMetrics.ts +++ b/plugins/continuous-toolbox/src/ContinuousMetrics.ts @@ -15,6 +15,11 @@ export class ContinuousMetrics extends Blockly.MetricsManager { /** * Computes the viewport size to not include the toolbox and the flyout. * The default viewport includes the flyout. + * + * @param getWorkspaceCoordinates True to get the view metrics in workspace + * coordinates, false to get them in pixel coordinates. + * @returns The width, height, top and left of the viewport in either + * workspace coordinates or pixel coordinates. */ override getViewMetrics( getWorkspaceCoordinates?: boolean, @@ -49,8 +54,11 @@ export class ContinuousMetrics extends Blockly.MetricsManager { } /** - * Moves the absoluteLeft and absoluteTop so they no longer include the - * flyout. + * Gets the absolute left and absolute top in pixel coordinates. + * This is where the visible workspace starts in relation to the SVG + * container, shifted to not include the area behind the flyout. + * + * @returns The absolute metrics for the workspace. */ override getAbsoluteMetrics(): Blockly.MetricsManager.AbsoluteMetrics { const toolboxMetrics = this.getToolboxMetrics(); diff --git a/plugins/continuous-toolbox/src/ContinuousMetricsFlyout.ts b/plugins/continuous-toolbox/src/ContinuousMetricsFlyout.ts index 69674c9735..b2dadfd256 100644 --- a/plugins/continuous-toolbox/src/ContinuousMetricsFlyout.ts +++ b/plugins/continuous-toolbox/src/ContinuousMetricsFlyout.ts @@ -10,8 +10,17 @@ import type {ContinuousFlyout} from './ContinuousFlyout'; /** Adds additional padding to the bottom of the flyout if needed. */ export class ContinuousFlyoutMetrics extends Blockly.FlyoutMetricsManager { /** - * Adds additional padding to the bottom of the flyout if needed, - * in order to make it possible to scroll to the top of the last category. + * Returns the metrics for the scroll area of the continuous flyout's + * workspace. Adds additional padding to the bottom of the flyout if needed in + * order to make it possible to scroll to the top of the last category. + * + * @param getWorkspaceCoordinates True to get the scroll metrics in + * workspace coordinates, false to get them in pixel coordinates. + * @param viewMetrics The view metrics if they have been previously + * computed. + * @param contentMetrics The content metrics if they have been previously + * computed. + * @returns The metrics for the scroll container. */ override getScrollMetrics( getWorkspaceCoordinates?: boolean, diff --git a/plugins/continuous-toolbox/src/ContinuousToolbox.ts b/plugins/continuous-toolbox/src/ContinuousToolbox.ts index e5c8a804a5..8444e0dcd4 100644 --- a/plugins/continuous-toolbox/src/ContinuousToolbox.ts +++ b/plugins/continuous-toolbox/src/ContinuousToolbox.ts @@ -15,6 +15,9 @@ import {ContinuousFlyout} from './ContinuousFlyout'; * Class for continuous toolbox. */ export class ContinuousToolbox extends Blockly.Toolbox { + /** + * Initializes the continuous toolbox. + */ override init() { super.init(); @@ -32,6 +35,11 @@ export class ContinuousToolbox extends Blockly.Toolbox { }); } + /** + * Returns the continuous toolbox's flyout. + * + * @returns The toolbox's flyout. + */ override getFlyout(): ContinuousFlyout { return super.getFlyout() as ContinuousFlyout; } @@ -39,6 +47,7 @@ export class ContinuousToolbox extends Blockly.Toolbox { /** * Gets the contents that should be shown in the flyout immediately. * This includes all blocks and labels for each category of block. + * * @returns Flyout contents. */ private getInitialFlyoutContents_(): Blockly.utils.toolbox.FlyoutItemInfoArray { @@ -64,10 +73,19 @@ export class ContinuousToolbox extends Blockly.Toolbox { return contents; } + /** + * Updates the flyout's contents if it is visible. + */ override refreshSelection() { this.getFlyout().show(this.getInitialFlyoutContents_()); } + /** + * Scrolls the flyout to display the newly selected category's contents. + * + * @param _oldItem The previously selected toolbox category. + * @param newItem The newly selected toolbox category. + */ override updateFlyout_( _oldItem: Blockly.ISelectableToolboxItem | null, newItem: Blockly.ISelectableToolboxItem | null, @@ -77,6 +95,12 @@ export class ContinuousToolbox extends Blockly.Toolbox { } } + /** + * Returns whether or not the toolbox should deselect the old category. + * + * @param oldItem The previously selected toolbox category. + * @param newItem The newly selected toolbox category. + */ override shouldDeselectItem_( oldItem: Blockly.ISelectableToolboxItem | null, newItem: Blockly.ISelectableToolboxItem | null, @@ -87,9 +111,10 @@ export class ContinuousToolbox extends Blockly.Toolbox { /** * Gets a category by name. + * * @param name Name of category to get. * @returns Category, or null if not found. - * @package + * @internal */ getCategoryByName(name: string): Blockly.ISelectableToolboxItem | null { const category = this.getToolboxItems().find( @@ -108,8 +133,9 @@ export class ContinuousToolbox extends Blockly.Toolbox { * Selects the category with the given name. * Similar to setSelectedItem, but importantly, does not call updateFlyout * because this is called while the flyout is being scrolled. + * * @param name Name of category to select. - * @package + * @internal */ selectCategoryByName(name: string) { const newItem = this.getCategoryByName(name); @@ -127,6 +153,13 @@ export class ContinuousToolbox extends Blockly.Toolbox { } } + /** + * Returns the bounding rectangle of the drag target/deletion area in pixels + * relative to the viewport. + * + * @returns The toolbox's bounding box. Null if drag target area should be + * ignored. + */ override getClientRect(): Blockly.utils.Rect | null { // If the flyout never closes, it should be the deletable area. const flyout = this.getFlyout(); diff --git a/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts b/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts index 3b2cce664a..e090f2a246 100644 --- a/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts +++ b/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts @@ -20,6 +20,9 @@ export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater { */ private recycledBlocks = new Map(); + /** + * Custom function to use for checking whether or not blocks can be recycled. + */ private recycleEligibilityChecker?: (block: Blockly.Block) => boolean; /** From c08fa48c04ee20be5a2fb488be2b1a3999b1891d Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 7 Nov 2024 15:26:08 -0800 Subject: [PATCH 12/52] feat: Add support for autoclosing continuous toolboxes. --- plugins/continuous-toolbox/src/ContinuousToolbox.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/plugins/continuous-toolbox/src/ContinuousToolbox.ts b/plugins/continuous-toolbox/src/ContinuousToolbox.ts index 8444e0dcd4..a2eed6cf7e 100644 --- a/plugins/continuous-toolbox/src/ContinuousToolbox.ts +++ b/plugins/continuous-toolbox/src/ContinuousToolbox.ts @@ -77,7 +77,9 @@ export class ContinuousToolbox extends Blockly.Toolbox { * Updates the flyout's contents if it is visible. */ override refreshSelection() { - this.getFlyout().show(this.getInitialFlyoutContents_()); + if (this.getFlyout().isVisible()) { + this.getFlyout().show(this.getInitialFlyoutContents_()); + } } /** @@ -92,6 +94,11 @@ export class ContinuousToolbox extends Blockly.Toolbox { ) { if (newItem) { this.getFlyout().scrollToCategory(newItem); + if (!this.getFlyout().isVisible()) { + this.getFlyout().show(this.getInitialFlyoutContents_()); + } + } else if (this.getFlyout().autoClose) { + this.getFlyout().hide(); } } From be89b8f47d0f03bceed52e68812f7533671d5ccc Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 8 Nov 2024 08:48:27 -0800 Subject: [PATCH 13/52] fix: Fix bug when making configuration changes in the playground. --- plugins/continuous-toolbox/test/index.js | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/plugins/continuous-toolbox/test/index.js b/plugins/continuous-toolbox/test/index.js index 618b853960..8cdf29f45f 100644 --- a/plugins/continuous-toolbox/test/index.js +++ b/plugins/continuous-toolbox/test/index.js @@ -19,19 +19,10 @@ import {registerContinuousToolbox} from '../src/index'; * @returns {!Blockly.WorkspaceSvg} The created workspace. */ function createWorkspace(blocklyDiv, options) { - registerContinuousToolbox(); - const workspace = Blockly.inject(blocklyDiv, options); - - return workspace; + return Blockly.inject(blocklyDiv, options); } document.addEventListener('DOMContentLoaded', function () { - const defaultOptions = { - toolbox: toolboxCategories, - }; - createPlayground( - document.getElementById('root'), - createWorkspace, - defaultOptions, - ); + registerContinuousToolbox(); + createPlayground(document.getElementById('root'), createWorkspace); }); From 285d89f94443d5676c3ee259578b4a2066c81ac5 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 8 Nov 2024 08:58:57 -0800 Subject: [PATCH 14/52] refactor: Update visibility on RecyclableBlockFlyoutInflater. --- .../src/RecyclableBlockFlyoutInflater.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts b/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts index e090f2a246..993463d190 100644 --- a/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts +++ b/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts @@ -68,7 +68,7 @@ export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater { * @param blockDefinition The block definition to parse. * @returns The block type. */ - getTypeFromDefinition( + private getTypeFromDefinition( blockDefinition: Blockly.utils.toolbox.BlockInfo, ): string { let type: string | null | undefined; @@ -99,7 +99,7 @@ export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater { * * @param block The block to recycle. */ - recycleBlock(block: Blockly.BlockSvg) { + private recycleBlock(block: Blockly.BlockSvg) { const xy = block.getRelativeToSurfaceXY(); block.moveBy(-xy.x, -xy.y); this.recycledBlocks.set(block.type, block); @@ -112,7 +112,7 @@ export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater { * @param blockType The type of the block to try to recycle. * @returns The recycled block, or undefined if one could not be recycled. */ - getRecycledBlock(blockType: string): Blockly.BlockSvg | undefined { + private getRecycledBlock(blockType: string): Blockly.BlockSvg | undefined { const block = this.recycledBlocks.get(blockType); this.recycledBlocks.delete(blockType); return block; @@ -124,7 +124,7 @@ export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater { * @param block The block to check for recyclability. * @returns True if the block can be recycled. False otherwise. */ - blockIsRecyclable(block: Blockly.Block): boolean { + protected blockIsRecyclable(block: Blockly.Block): boolean { if (!this.recyclingEnabled) { return false; } From a0fcb69075d58a278fcb0bfa14436b105968e887 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 8 Nov 2024 08:59:18 -0800 Subject: [PATCH 15/52] fix: Use the recycleEligibilityChecker callback if set. --- .../continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts b/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts index 993463d190..6cd2f95795 100644 --- a/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts +++ b/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts @@ -129,6 +129,10 @@ export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater { return false; } + if (this.recycleEligibilityChecker) { + return this.recycleEligibilityChecker(block); + } + // If the block needs to parse mutations, never recycle. if (block.mutationToDom && block.domToMutation) { return false; From 94fa6ab8a5f92e00423bdbe29095a53edfdcf245 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 8 Nov 2024 09:27:41 -0800 Subject: [PATCH 16/52] refactor: Make converting toolbox items to flyout items more extensible. --- .../src/ContinuousToolbox.ts | 43 ++++++++++++------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/plugins/continuous-toolbox/src/ContinuousToolbox.ts b/plugins/continuous-toolbox/src/ContinuousToolbox.ts index a2eed6cf7e..1e990da65f 100644 --- a/plugins/continuous-toolbox/src/ContinuousToolbox.ts +++ b/plugins/continuous-toolbox/src/ContinuousToolbox.ts @@ -51,24 +51,35 @@ export class ContinuousToolbox extends Blockly.Toolbox { * @returns Flyout contents. */ private getInitialFlyoutContents_(): Blockly.utils.toolbox.FlyoutItemInfoArray { + return this.getToolboxItems().flatMap(this.convertToolboxItemToFlyoutItems); + } + + /** + * Converts a given toolbox item to an array of flyout items, generally a + * label followed by the category's blocks. + * + * @param toolboxItem The toolbox item/category to convert. + * @returns An array of flyout items contained in the given toolbox item. + */ + protected convertToolboxItemToFlyoutItems( + toolboxItem: Blockly.IToolboxItem, + ): Blockly.utils.toolbox.FlyoutItemInfoArray { let contents: Blockly.utils.toolbox.FlyoutItemInfoArray = []; - for (const toolboxItem of this.getToolboxItems()) { - if (toolboxItem instanceof Blockly.ToolboxCategory) { - // Create a label node to go at the top of the category - contents.push({kind: 'LABEL', text: toolboxItem.getName()}); - let itemContents = toolboxItem.getContents(); - - // Handle custom categories (e.g. variables and functions) - if (typeof itemContents === 'string') { - itemContents = [ - { - custom: itemContents, - kind: 'CATEGORY', - }, - ]; - } - contents = contents.concat(itemContents); + if (toolboxItem instanceof Blockly.ToolboxCategory) { + // Create a label node to go at the top of the category + contents.push({kind: 'LABEL', text: toolboxItem.getName()}); + let itemContents = toolboxItem.getContents(); + + // Handle custom categories (e.g. variables and functions) + if (typeof itemContents === 'string') { + itemContents = [ + { + custom: itemContents, + kind: 'CATEGORY', + }, + ]; } + contents = contents.concat(itemContents); } return contents; } From 7a024d73a518f08a21bae88a21a15ca8d9e253ab Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 8 Nov 2024 10:21:34 -0800 Subject: [PATCH 17/52] chore: Remove debugging. --- plugins/continuous-toolbox/src/ContinuousFlyout.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/continuous-toolbox/src/ContinuousFlyout.ts b/plugins/continuous-toolbox/src/ContinuousFlyout.ts index 2b011c7674..fb9c7e74d4 100644 --- a/plugins/continuous-toolbox/src/ContinuousFlyout.ts +++ b/plugins/continuous-toolbox/src/ContinuousFlyout.ts @@ -222,7 +222,6 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { * Displays the given contents in the flyout. */ override show(flyoutDef: Blockly.utils.toolbox.FlyoutDefinition | string) { - console.trace(); super.show(flyoutDef); this.recordScrollPositions(); this.getWorkspace().resizeContents(); From 226c119827db03531bf3b79f7196522510a5e4f0 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 8 Nov 2024 10:23:38 -0800 Subject: [PATCH 18/52] fix: Debounce flyout refreshes. --- plugins/continuous-toolbox/src/ContinuousToolbox.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/plugins/continuous-toolbox/src/ContinuousToolbox.ts b/plugins/continuous-toolbox/src/ContinuousToolbox.ts index 1e990da65f..647542f758 100644 --- a/plugins/continuous-toolbox/src/ContinuousToolbox.ts +++ b/plugins/continuous-toolbox/src/ContinuousToolbox.ts @@ -15,6 +15,12 @@ import {ContinuousFlyout} from './ContinuousFlyout'; * Class for continuous toolbox. */ export class ContinuousToolbox extends Blockly.Toolbox { + /** + * Timeout ID used to prevent refreshing the flyout during extensive block + * changes. + */ + private refreshDebouncer?: ReturnType; + /** * Initializes the continuous toolbox. */ @@ -89,7 +95,12 @@ export class ContinuousToolbox extends Blockly.Toolbox { */ override refreshSelection() { if (this.getFlyout().isVisible()) { - this.getFlyout().show(this.getInitialFlyoutContents_()); + if (this.refreshDebouncer) { + clearTimeout(this.refreshDebouncer); + } + this.refreshDebouncer = setTimeout(() => { + this.getFlyout().show(this.getInitialFlyoutContents_()); + }, 100); } } From 7a7930d83dea6cebb1b69e3c8e8238c87329f2ea Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 8 Nov 2024 10:24:07 -0800 Subject: [PATCH 19/52] chore: Remove unused import. --- plugins/continuous-toolbox/test/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/continuous-toolbox/test/index.js b/plugins/continuous-toolbox/test/index.js index 8cdf29f45f..09a15b6d6b 100644 --- a/plugins/continuous-toolbox/test/index.js +++ b/plugins/continuous-toolbox/test/index.js @@ -9,7 +9,7 @@ */ import * as Blockly from 'blockly'; -import {toolboxCategories, createPlayground} from '@blockly/dev-tools'; +import {createPlayground} from '@blockly/dev-tools'; import {registerContinuousToolbox} from '../src/index'; /** From 0e23119c056788f5f5e1e5e35308af628e50ffb2 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 8 Nov 2024 10:25:30 -0800 Subject: [PATCH 20/52] chore: Fix TSDoc args. --- plugins/continuous-toolbox/src/ContinuousMetricsFlyout.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/continuous-toolbox/src/ContinuousMetricsFlyout.ts b/plugins/continuous-toolbox/src/ContinuousMetricsFlyout.ts index b2dadfd256..bd5fea5cdc 100644 --- a/plugins/continuous-toolbox/src/ContinuousMetricsFlyout.ts +++ b/plugins/continuous-toolbox/src/ContinuousMetricsFlyout.ts @@ -16,10 +16,10 @@ export class ContinuousFlyoutMetrics extends Blockly.FlyoutMetricsManager { * * @param getWorkspaceCoordinates True to get the scroll metrics in * workspace coordinates, false to get them in pixel coordinates. - * @param viewMetrics The view metrics if they have been previously - * computed. - * @param contentMetrics The content metrics if they have been previously + * @param cachedViewMetrics The view metrics if they have been previously * computed. + * @param cachedContentMetrics The content metrics if they have been + * previously computed. * @returns The metrics for the scroll container. */ override getScrollMetrics( From 5b61d3d73e14c366ccf02ba7afc0ba27279520b0 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 8 Nov 2024 10:25:41 -0800 Subject: [PATCH 21/52] chore: Add TSDoc for registration function. --- plugins/continuous-toolbox/src/index.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/continuous-toolbox/src/index.ts b/plugins/continuous-toolbox/src/index.ts index d0bf4bec83..518d78ef70 100644 --- a/plugins/continuous-toolbox/src/index.ts +++ b/plugins/continuous-toolbox/src/index.ts @@ -24,6 +24,10 @@ export { RecyclableBlockFlyoutInflater, }; +/** + * Registers the components of the continuous toolbox, replacing Blockly's + * built-in defaults. + */ export function registerContinuousToolbox() { Blockly.registry.register( Blockly.registry.Type.TOOLBOX_ITEM, From 308bf0ce5907aa830ca12fd46ae3d877df31798e Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 8 Nov 2024 10:28:22 -0800 Subject: [PATCH 22/52] refactor: Clean up implementation of recordScrollPositions. --- plugins/continuous-toolbox/src/ContinuousFlyout.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/continuous-toolbox/src/ContinuousFlyout.ts b/plugins/continuous-toolbox/src/ContinuousFlyout.ts index fb9c7e74d4..6b2e270c6c 100644 --- a/plugins/continuous-toolbox/src/ContinuousFlyout.ts +++ b/plugins/continuous-toolbox/src/ContinuousFlyout.ts @@ -75,12 +75,12 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { */ private recordScrollPositions() { this.scrollPositions.clear(); - const categoryLabels = this.getContents() + this.getContents() .filter(this.toolboxItemIsLabel.bind(this)) - .map((item) => item.element); - for (const [index, label] of categoryLabels.entries()) { - this.scrollPositions.set(label.getButtonText(), label.getPosition().y); - } + .map((item) => item.element) + .forEach((label) => { + this.scrollPositions.set(label.getButtonText(), label.getPosition().y); + }); } /** From 0075301d5801e74d46522730a3bcf2defffbe2f7 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 8 Nov 2024 10:50:29 -0800 Subject: [PATCH 23/52] chore: Fix TSDoc. --- plugins/continuous-toolbox/src/ContinuousFlyout.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/continuous-toolbox/src/ContinuousFlyout.ts b/plugins/continuous-toolbox/src/ContinuousFlyout.ts index 6b2e270c6c..aa1e8a0f07 100644 --- a/plugins/continuous-toolbox/src/ContinuousFlyout.ts +++ b/plugins/continuous-toolbox/src/ContinuousFlyout.ts @@ -220,6 +220,9 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { /** * Displays the given contents in the flyout. + * + * @param flyoutDef A string or JSON object specifying the contents of the + * flyout. */ override show(flyoutDef: Blockly.utils.toolbox.FlyoutDefinition | string) { super.show(flyoutDef); From 6543e460175f486b232a92cd0fbf1c154b9a152c Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 8 Nov 2024 10:51:45 -0800 Subject: [PATCH 24/52] chore: Remove unneeded underscores in symbol names. --- plugins/continuous-toolbox/src/ContinuousToolbox.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/continuous-toolbox/src/ContinuousToolbox.ts b/plugins/continuous-toolbox/src/ContinuousToolbox.ts index 647542f758..9e4b864fc6 100644 --- a/plugins/continuous-toolbox/src/ContinuousToolbox.ts +++ b/plugins/continuous-toolbox/src/ContinuousToolbox.ts @@ -29,7 +29,7 @@ export class ContinuousToolbox extends Blockly.Toolbox { // Populate the flyout with all blocks and show it immediately. const flyout = this.getFlyout(); - flyout.show(this.getInitialFlyoutContents_()); + flyout.show(this.getInitialFlyoutContents()); this.getWorkspace().addChangeListener((e: Blockly.Events.Abstract) => { if ( @@ -56,7 +56,7 @@ export class ContinuousToolbox extends Blockly.Toolbox { * * @returns Flyout contents. */ - private getInitialFlyoutContents_(): Blockly.utils.toolbox.FlyoutItemInfoArray { + private getInitialFlyoutContents(): Blockly.utils.toolbox.FlyoutItemInfoArray { return this.getToolboxItems().flatMap(this.convertToolboxItemToFlyoutItems); } @@ -99,7 +99,7 @@ export class ContinuousToolbox extends Blockly.Toolbox { clearTimeout(this.refreshDebouncer); } this.refreshDebouncer = setTimeout(() => { - this.getFlyout().show(this.getInitialFlyoutContents_()); + this.getFlyout().show(this.getInitialFlyoutContents()); }, 100); } } @@ -107,17 +107,17 @@ export class ContinuousToolbox extends Blockly.Toolbox { /** * Scrolls the flyout to display the newly selected category's contents. * - * @param _oldItem The previously selected toolbox category. + * @param oldItem The previously selected toolbox category. * @param newItem The newly selected toolbox category. */ override updateFlyout_( - _oldItem: Blockly.ISelectableToolboxItem | null, + oldItem: Blockly.ISelectableToolboxItem | null, newItem: Blockly.ISelectableToolboxItem | null, ) { if (newItem) { this.getFlyout().scrollToCategory(newItem); if (!this.getFlyout().isVisible()) { - this.getFlyout().show(this.getInitialFlyoutContents_()); + this.getFlyout().show(this.getInitialFlyoutContents()); } } else if (this.getFlyout().autoClose) { this.getFlyout().hide(); From 3e29643baf972b93ab395195e85530822048ed30 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 8 Nov 2024 10:54:14 -0800 Subject: [PATCH 25/52] chore: Suppress unavoidable lint errors. --- plugins/continuous-toolbox/src/ContinuousCategory.ts | 3 +++ plugins/continuous-toolbox/src/ContinuousToolbox.ts | 2 ++ 2 files changed, 5 insertions(+) diff --git a/plugins/continuous-toolbox/src/ContinuousCategory.ts b/plugins/continuous-toolbox/src/ContinuousCategory.ts index 39175237dd..6a5da76c9c 100644 --- a/plugins/continuous-toolbox/src/ContinuousCategory.ts +++ b/plugins/continuous-toolbox/src/ContinuousCategory.ts @@ -18,6 +18,7 @@ export class ContinuousCategory extends Blockly.ToolboxCategory { * @param name The name of this category. * @returns The newly created category label DOM element. */ + // eslint-disable-next-line @typescript-eslint/naming-convention override createLabelDom_(name: string): Element { const label = document.createElement('div'); label.setAttribute('id', this.getId() + '.label'); @@ -32,6 +33,7 @@ export class ContinuousCategory extends Blockly.ToolboxCategory { * * @returns The newly created category icon DOM element. */ + // eslint-disable-next-line @typescript-eslint/naming-convention override createIconDom_(): Element { const icon = document.createElement('div'); icon.classList.add('categoryBubble'); @@ -42,6 +44,7 @@ export class ContinuousCategory extends Blockly.ToolboxCategory { /** * Adds a color indicator to the toolbox category. Intentionally a no-op. */ + // eslint-disable-next-line @typescript-eslint/naming-convention override addColourBorder_() { // No-op } diff --git a/plugins/continuous-toolbox/src/ContinuousToolbox.ts b/plugins/continuous-toolbox/src/ContinuousToolbox.ts index 9e4b864fc6..d9e76d1e23 100644 --- a/plugins/continuous-toolbox/src/ContinuousToolbox.ts +++ b/plugins/continuous-toolbox/src/ContinuousToolbox.ts @@ -110,6 +110,7 @@ export class ContinuousToolbox extends Blockly.Toolbox { * @param oldItem The previously selected toolbox category. * @param newItem The newly selected toolbox category. */ + // eslint-disable-next-line @typescript-eslint/naming-convention override updateFlyout_( oldItem: Blockly.ISelectableToolboxItem | null, newItem: Blockly.ISelectableToolboxItem | null, @@ -130,6 +131,7 @@ export class ContinuousToolbox extends Blockly.Toolbox { * @param oldItem The previously selected toolbox category. * @param newItem The newly selected toolbox category. */ + // eslint-disable-next-line @typescript-eslint/naming-convention override shouldDeselectItem_( oldItem: Blockly.ISelectableToolboxItem | null, newItem: Blockly.ISelectableToolboxItem | null, From 6519373b992c2ffe35f50989f2143e0d21278b6f Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 8 Nov 2024 11:00:49 -0800 Subject: [PATCH 26/52] fix: Fix alignment when jumping to a category. --- plugins/continuous-toolbox/src/ContinuousFlyout.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/continuous-toolbox/src/ContinuousFlyout.ts b/plugins/continuous-toolbox/src/ContinuousFlyout.ts index aa1e8a0f07..b3e5cec7d3 100644 --- a/plugins/continuous-toolbox/src/ContinuousFlyout.ts +++ b/plugins/continuous-toolbox/src/ContinuousFlyout.ts @@ -79,7 +79,10 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { .filter(this.toolboxItemIsLabel.bind(this)) .map((item) => item.element) .forEach((label) => { - this.scrollPositions.set(label.getButtonText(), label.getPosition().y); + this.scrollPositions.set( + label.getButtonText(), + label.getPosition().y - label.height, + ); }); } From 933d9fafb11cccd7af7f8d0d34eb44c82fe3280a Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 8 Nov 2024 13:23:05 -0800 Subject: [PATCH 27/52] fix: Fix injection options and documentation. --- plugins/continuous-toolbox/README.md | 5 +++++ plugins/continuous-toolbox/src/index.ts | 6 +++--- plugins/continuous-toolbox/test/index.js | 8 +++++++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/plugins/continuous-toolbox/README.md b/plugins/continuous-toolbox/README.md index f00841cca2..dc8cfd3f2b 100644 --- a/plugins/continuous-toolbox/README.md +++ b/plugins/continuous-toolbox/README.md @@ -36,6 +36,11 @@ import {registerContinuousToolbox} from '@blockly/continuous-toolbox'; registerContinuousToolbox(); const workspace = Blockly.inject('blocklyDiv', { toolbox: toolboxCategories, + plugins: { + flyoutsVerticalToolbox: 'ContinuousFlyout', + metricsManager: 'ContinuousMetrics', + toolbox: 'ContinuousToolbox', + }, // ... your other options here ... }); ``` diff --git a/plugins/continuous-toolbox/src/index.ts b/plugins/continuous-toolbox/src/index.ts index 518d78ef70..098e78e139 100644 --- a/plugins/continuous-toolbox/src/index.ts +++ b/plugins/continuous-toolbox/src/index.ts @@ -38,21 +38,21 @@ export function registerContinuousToolbox() { Blockly.registry.register( Blockly.registry.Type.METRICS_MANAGER, - 'CustomMetricsManager', + 'ContinuousMetrics', ContinuousMetrics, true, ); Blockly.registry.register( Blockly.registry.Type.FLYOUTS_VERTICAL_TOOLBOX, - Blockly.registry.DEFAULT, + 'ContinuousFlyout', ContinuousFlyout, true, ); Blockly.registry.register( Blockly.registry.Type.TOOLBOX, - Blockly.registry.DEFAULT, + 'ContinuousToolbox', ContinuousToolbox, true, ); diff --git a/plugins/continuous-toolbox/test/index.js b/plugins/continuous-toolbox/test/index.js index 09a15b6d6b..f78f44a60c 100644 --- a/plugins/continuous-toolbox/test/index.js +++ b/plugins/continuous-toolbox/test/index.js @@ -24,5 +24,11 @@ function createWorkspace(blocklyDiv, options) { document.addEventListener('DOMContentLoaded', function () { registerContinuousToolbox(); - createPlayground(document.getElementById('root'), createWorkspace); + createPlayground(document.getElementById('root'), createWorkspace, { + plugins: { + flyoutsVerticalToolbox: 'ContinuousFlyout', + metricsManager: 'ContinuousMetrics', + toolbox: 'ContinuousToolbox', + }, + }); }); From 0c4148aaa8bac7323bbb94837df87292b8ebb6d0 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 8 Nov 2024 13:23:28 -0800 Subject: [PATCH 28/52] chore: Fix typo. --- plugins/continuous-toolbox/src/ContinuousMetrics.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/continuous-toolbox/src/ContinuousMetrics.ts b/plugins/continuous-toolbox/src/ContinuousMetrics.ts index d3d5b92efc..135e16f581 100644 --- a/plugins/continuous-toolbox/src/ContinuousMetrics.ts +++ b/plugins/continuous-toolbox/src/ContinuousMetrics.ts @@ -31,7 +31,7 @@ export class ContinuousMetrics extends Blockly.MetricsManager { const toolboxPosition = toolboxMetrics.position; if (this.workspace_.getToolbox()) { - // Note: Not actually supported at this time due to ContinunousToolbox + // Note: Not actually supported at this time due to ContinuousToolbox // only supporting a vertical flyout. But included for completeness. if ( toolboxPosition == Blockly.TOOLBOX_AT_TOP || From 66221173a6c78964881a02604f76a43d80157f52 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 8 Nov 2024 13:25:37 -0800 Subject: [PATCH 29/52] refactor: Make the ContinuousFlyoutMetrics class and file name consistent. --- plugins/continuous-toolbox/src/ContinuousFlyout.ts | 2 +- .../{ContinuousMetricsFlyout.ts => ContinuousFlyoutMetrics.ts} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename plugins/continuous-toolbox/src/{ContinuousMetricsFlyout.ts => ContinuousFlyoutMetrics.ts} (100%) diff --git a/plugins/continuous-toolbox/src/ContinuousFlyout.ts b/plugins/continuous-toolbox/src/ContinuousFlyout.ts index b3e5cec7d3..d65a0ba00a 100644 --- a/plugins/continuous-toolbox/src/ContinuousFlyout.ts +++ b/plugins/continuous-toolbox/src/ContinuousFlyout.ts @@ -10,7 +10,7 @@ import * as Blockly from 'blockly/core'; import {ContinuousToolbox} from './ContinuousToolbox'; -import {ContinuousFlyoutMetrics} from './ContinuousMetricsFlyout'; +import {ContinuousFlyoutMetrics} from './ContinuousFlyoutMetrics'; import {RecyclableBlockFlyoutInflater} from './RecyclableBlockFlyoutInflater'; /** diff --git a/plugins/continuous-toolbox/src/ContinuousMetricsFlyout.ts b/plugins/continuous-toolbox/src/ContinuousFlyoutMetrics.ts similarity index 100% rename from plugins/continuous-toolbox/src/ContinuousMetricsFlyout.ts rename to plugins/continuous-toolbox/src/ContinuousFlyoutMetrics.ts From 7c0a08cb873e94b554ad1e8d6153ddff5b0f8b32 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 8 Nov 2024 13:28:37 -0800 Subject: [PATCH 30/52] fix: Update flyout contents in response to procedure mutations. --- plugins/continuous-toolbox/src/ContinuousToolbox.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/continuous-toolbox/src/ContinuousToolbox.ts b/plugins/continuous-toolbox/src/ContinuousToolbox.ts index d9e76d1e23..5f77dd94c2 100644 --- a/plugins/continuous-toolbox/src/ContinuousToolbox.ts +++ b/plugins/continuous-toolbox/src/ContinuousToolbox.ts @@ -34,7 +34,8 @@ export class ContinuousToolbox extends Blockly.Toolbox { this.getWorkspace().addChangeListener((e: Blockly.Events.Abstract) => { if ( e.type === Blockly.Events.BLOCK_CREATE || - e.type === Blockly.Events.BLOCK_DELETE + e.type === Blockly.Events.BLOCK_DELETE || + e.type === Blockly.Events.BLOCK_CHANGE ) { this.refreshSelection(); } From a538e7e454ec56f631e3cc3310a7359838f0b56f Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 8 Nov 2024 13:34:47 -0800 Subject: [PATCH 31/52] refactor: Make the RecyclableBlockFlyoutInflater inert for non-continuous flyouts. --- .../src/ContinuousFlyout.ts | 27 ++++++++++++------- .../src/RecyclableBlockFlyoutInflater.ts | 2 +- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/plugins/continuous-toolbox/src/ContinuousFlyout.ts b/plugins/continuous-toolbox/src/ContinuousFlyout.ts index d65a0ba00a..76197d649d 100644 --- a/plugins/continuous-toolbox/src/ContinuousFlyout.ts +++ b/plugins/continuous-toolbox/src/ContinuousFlyout.ts @@ -56,6 +56,8 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { this.selectCategoryByScrollPosition(-this.getWorkspace().scrollY); } }); + + this.setRecyclingEnabled(true); } /** @@ -234,10 +236,7 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { if (!this.getParentToolbox().getSelectedItem()) { this.selectCategoryByScrollPosition(0); } - const inflater = this.getInflaterForType('block'); - if (inflater instanceof RecyclableBlockFlyoutInflater) { - inflater.emptyRecycledBlocks(); - } + this.getRecyclableInflater().emptyRecycledBlocks(); } /** @@ -246,10 +245,7 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { * @param func The function used to determine if a block is recyclable. */ setBlockIsRecyclable(func: (block: Blockly.Block) => boolean) { - const inflater = this.getInflaterForType('block'); - if (inflater instanceof RecyclableBlockFlyoutInflater) { - inflater.setRecyclingEligibilityChecker(func); - } + this.getRecyclableInflater().setRecyclingEligibilityChecker(func); } /** @@ -258,9 +254,20 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { * @param isEnabled True to allow blocks to be recycled, false otherwise. */ setRecyclingEnabled(isEnabled: boolean) { + this.getRecyclableInflater().setRecyclingEnabled(isEnabled); + } + + /** + * Returns the recyclable block flyout inflater. + * + * @returns The recyclable inflater. + */ + protected getRecyclableInflater(): RecyclableBlockFlyoutInflater { const inflater = this.getInflaterForType('block'); - if (inflater instanceof RecyclableBlockFlyoutInflater) { - inflater.setRecyclingEnabled(isEnabled); + if (!(inflater instanceof RecyclableBlockFlyoutInflater)) { + throw new Error('The RecyclableBlockFlyoutInflater is not registered.'); } + + return inflater; } } diff --git a/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts b/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts index 6cd2f95795..69dfeba37a 100644 --- a/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts +++ b/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts @@ -13,7 +13,7 @@ export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater { /** * Whether or not block recycling is enabled. */ - private recyclingEnabled = true; + private recyclingEnabled = false; /** * Map from block type to block instance. From c464bd145ccc1aa6a692e1943ca4ebf8547ba992 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Wed, 4 Dec 2024 14:21:04 -0800 Subject: [PATCH 32/52] fix: Fix alignment of toolbox labels. --- plugins/continuous-toolbox/src/index.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/continuous-toolbox/src/index.ts b/plugins/continuous-toolbox/src/index.ts index 098e78e139..6319793295 100644 --- a/plugins/continuous-toolbox/src/index.ts +++ b/plugins/continuous-toolbox/src/index.ts @@ -83,5 +83,8 @@ export function registerContinuousToolbox() { .blocklyTreeLabel { margin: auto; } + .blocklyToolboxCategoryLabel { + text-align: center; + } `); } From c97c8258702465d7cc4fd259cd3c228438132d9c Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Wed, 4 Dec 2024 14:21:26 -0800 Subject: [PATCH 33/52] chore: Update to use Blockly v12 beta. --- plugins/continuous-toolbox/package-lock.json | 1392 +++++++++++++----- plugins/continuous-toolbox/package.json | 2 +- 2 files changed, 1061 insertions(+), 333 deletions(-) diff --git a/plugins/continuous-toolbox/package-lock.json b/plugins/continuous-toolbox/package-lock.json index 8e5b604102..9ee1aa2009 100644 --- a/plugins/continuous-toolbox/package-lock.json +++ b/plugins/continuous-toolbox/package-lock.json @@ -16,7 +16,7 @@ "node": ">=8.17.0" }, "peerDependencies": { - "blockly": "^11.0.0" + "blockly": "^12.0.0-beta.0" } }, "node_modules/@babel/code-frame": { @@ -261,19 +261,6 @@ "node": ">=6.9.0" } }, - "node_modules/@blockly/block-test": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/@blockly/block-test/-/block-test-6.0.6.tgz", - "integrity": "sha512-qxX3nuMRP3pirq8Pwo6TInZWQZnwVNGuRiwIcfKHvpd80eBXEhNGVLvqTPMKu+GU64oTChqm+qSa8QJ0y8j9xg==", - "dev": true, - "license": "Apache 2.0", - "engines": { - "node": ">=8.17.0" - }, - "peerDependencies": { - "blockly": "^11.0.0" - } - }, "node_modules/@blockly/dev-scripts": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@blockly/dev-scripts/-/dev-scripts-4.0.5.tgz", @@ -311,17 +298,16 @@ } }, "node_modules/@blockly/dev-tools": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/@blockly/dev-tools/-/dev-tools-8.0.7.tgz", - "integrity": "sha512-/gtLu2tu4ZGaqVCfvivKJ5kWk8lUMQzJh8qtn6Z/U2SJng0nQXcXBEcFVlFAUPt1dE4lNMR7ZYScJw/V+38bgg==", + "version": "8.0.12", + "resolved": "https://registry.npmjs.org/@blockly/dev-tools/-/dev-tools-8.0.12.tgz", + "integrity": "sha512-jE0y/Z7ggmM2JS4l0Xf2ic3eecuM+ZDjUZNCcM2k6yy0VDJoxOPN63Cq2soswXQRuKHfzRMHY48rCvoKL3MqPA==", "dev": true, - "license": "Apache-2.0", "dependencies": { - "@blockly/block-test": "^6.0.6", - "@blockly/theme-dark": "^7.0.5", - "@blockly/theme-deuteranopia": "^6.0.5", - "@blockly/theme-highcontrast": "^6.0.5", - "@blockly/theme-tritanopia": "^6.0.5", + "@blockly/block-test": "^6.0.11", + "@blockly/theme-dark": "^7.0.10", + "@blockly/theme-deuteranopia": "^6.0.10", + "@blockly/theme-highcontrast": "^6.0.10", + "@blockly/theme-tritanopia": "^6.0.10", "chai": "^4.2.0", "dat.gui": "^0.7.7", "lodash.assign": "^4.2.0", @@ -336,31 +322,23 @@ "blockly": "^11.0.0" } }, - "node_modules/@blockly/eslint-config": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@blockly/eslint-config/-/eslint-config-4.0.1.tgz", - "integrity": "sha512-yY6aeX6gv0T/+lFwxP35yVbZT2Q6kOgeDfBXTmIsul+S6Qr0ZqMJIkwrCzl1z45YRrB1WBGUJw40rimFwspeyg==", + "node_modules/@blockly/dev-tools/node_modules/@blockly/block-test": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/@blockly/block-test/-/block-test-6.0.11.tgz", + "integrity": "sha512-aIgcxkof1gLJtJXKSvmnug9iSXbv5Qilnov4Sa/QNURiWJRxvMNqWiTZJVu/reuCQK4Qm4jadg9R9l+eu7ujvw==", "dev": true, - "dependencies": { - "@typescript-eslint/eslint-plugin": "^5.0.0", - "@typescript-eslint/parser": "^5.0.0", - "babel-eslint": "^10.1.0", - "eslint-config-google": "^0.14.0", - "eslint-plugin-jsdoc": "^46.8.0" - }, "engines": { - "node": ">=10.0.0" + "node": ">=8.17.0" }, "peerDependencies": { - "eslint": "7.x" + "blockly": "^11.0.0" } }, - "node_modules/@blockly/theme-dark": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/@blockly/theme-dark/-/theme-dark-7.0.5.tgz", - "integrity": "sha512-TUS7X+UM5AvTe4Z1mtb371psViAeZSSmTzWuFrdNolX2i9P6XbNA9iKFDF0MObO307pOrtXodmsXpvbtgLeCUw==", + "node_modules/@blockly/dev-tools/node_modules/@blockly/theme-dark": { + "version": "7.0.10", + "resolved": "https://registry.npmjs.org/@blockly/theme-dark/-/theme-dark-7.0.10.tgz", + "integrity": "sha512-Wc6n115vt9alxzPkEwYtvBBGoPUV3gaYE00dvSKhqXTNoy1Xioujj9kT9VkGmdMO2mhgnJNczSpvxG8tcd4zLQ==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=8.17.0" }, @@ -368,12 +346,11 @@ "blockly": "^11.0.0" } }, - "node_modules/@blockly/theme-deuteranopia": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/@blockly/theme-deuteranopia/-/theme-deuteranopia-6.0.5.tgz", - "integrity": "sha512-z2hcsmRd5yaKf96gNZ1qM7IDqPb2M492FZhomRz6PgFYw/2rFXmQk6WcI84mmcTLrwfOfLkq/HIaPd23Wc3Hcw==", + "node_modules/@blockly/dev-tools/node_modules/@blockly/theme-deuteranopia": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/@blockly/theme-deuteranopia/-/theme-deuteranopia-6.0.10.tgz", + "integrity": "sha512-im5nIvf/Z0f1vJ9DK5Euu6URfY8G44xeFsat2b7TySF0BfAUWkGsagK3C6D5NatigPxKZqz3exC9zeXEtprAcg==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=8.17.0" }, @@ -381,12 +358,11 @@ "blockly": "^11.0.0" } }, - "node_modules/@blockly/theme-highcontrast": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/@blockly/theme-highcontrast/-/theme-highcontrast-6.0.5.tgz", - "integrity": "sha512-rLhFM1+M6okikeSGHbZfxqJB7quWFm+RBXCi8ht8bjSkspdh5PCUOs10U4/GbI+YXSuAd2uFdg20xINL+X3KfQ==", + "node_modules/@blockly/dev-tools/node_modules/@blockly/theme-highcontrast": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/@blockly/theme-highcontrast/-/theme-highcontrast-6.0.10.tgz", + "integrity": "sha512-s1hehl/b50IhebCs20hm2hFWbUTqJ2YSGdR0gnp2NLfNNRWwyZHZk+q4aG3k4L0YBWjNfE3XiRCkDISy83dBIA==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=8.17.0" }, @@ -394,12 +370,11 @@ "blockly": "^11.0.0" } }, - "node_modules/@blockly/theme-tritanopia": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/@blockly/theme-tritanopia/-/theme-tritanopia-6.0.5.tgz", - "integrity": "sha512-FVZmKfTQt1OQGsoZP78ET6V9xw83dd2vlJbTdjL1V6xlh0hixFGnqsze+Pw/FXiSWWLgeNKxTqQ6ImwhTHf5wA==", + "node_modules/@blockly/dev-tools/node_modules/@blockly/theme-tritanopia": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/@blockly/theme-tritanopia/-/theme-tritanopia-6.0.10.tgz", + "integrity": "sha512-QNIvUHokGMLnCWUzERRZa6sSkD5RIUynWDI+KNurBH21NeWnSNScQiNu0dS/w5MSkZ/Iqqbi79UZoF49SzEayg==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=8.17.0" }, @@ -407,6 +382,25 @@ "blockly": "^11.0.0" } }, + "node_modules/@blockly/eslint-config": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@blockly/eslint-config/-/eslint-config-4.0.1.tgz", + "integrity": "sha512-yY6aeX6gv0T/+lFwxP35yVbZT2Q6kOgeDfBXTmIsul+S6Qr0ZqMJIkwrCzl1z45YRrB1WBGUJw40rimFwspeyg==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "^5.0.0", + "@typescript-eslint/parser": "^5.0.0", + "babel-eslint": "^10.1.0", + "eslint-config-google": "^0.14.0", + "eslint-plugin-jsdoc": "^46.8.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "eslint": "7.x" + } + }, "node_modules/@discoveryjs/json-ext": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", @@ -475,6 +469,22 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/@eslint/eslintrc/node_modules/globals": { "version": "13.24.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", @@ -499,6 +509,12 @@ "node": ">= 4" } }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/@humanwhocodes/config-array": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", @@ -1480,9 +1496,9 @@ } }, "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1509,16 +1525,28 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "peer": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -1542,28 +1570,6 @@ } } }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/ajv-keywords": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", @@ -1687,6 +1693,12 @@ "node": ">=8" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "peer": true + }, "node_modules/babel-eslint": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", @@ -1751,6 +1763,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/blockly": { + "version": "12.0.0-beta.0", + "resolved": "https://registry.npmjs.org/blockly/-/blockly-12.0.0-beta.0.tgz", + "integrity": "sha512-Z9cULe95wgQGj87DQZ9RBJRu5oMLQEUTz0beZVcZL/ddVuga6qtZZ9DbaDfCvt4ffVz1O/kyNzPJ+cqvovSjGg==", + "peer": true, + "dependencies": { + "jsdom": "25.0.1" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/body-parser": { "version": "1.20.2", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", @@ -2125,6 +2149,18 @@ "dev": true, "license": "MIT" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "peer": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -2289,17 +2325,41 @@ "node": ">= 8" } }, + "node_modules/cssstyle": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz", + "integrity": "sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==", + "peer": true, + "dependencies": { + "rrweb-cssom": "^0.7.1" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/dat.gui": { "version": "0.7.9", "resolved": "https://registry.npmjs.org/dat.gui/-/dat.gui-0.7.9.tgz", "integrity": "sha512-sCNc1OHobc+Erc1HqiswYgHdVNpSJUlk/Hz8vzOCsER7rl+oF/4+v8GXFUyCgtXpoCX6+bnmg07DedLvBLwYKQ==", "dev": true }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "peer": true, + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/debug": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", - "dev": true, "license": "MIT", "dependencies": { "ms": "2.1.2" @@ -2326,6 +2386,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "peer": true + }, "node_modules/deep-eql": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", @@ -2427,6 +2493,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "peer": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -2573,6 +2648,18 @@ "node": ">=8.6" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "peer": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/envinfo": { "version": "7.13.0", "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", @@ -2826,6 +2913,22 @@ "@babel/highlight": "^7.10.4" } }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/eslint/node_modules/eslint-visitor-keys": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", @@ -2859,6 +2962,12 @@ "node": ">= 4" } }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/espree": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", @@ -2873,6 +2982,18 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/espree/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/espree/node_modules/eslint-visitor-keys": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", @@ -3330,6 +3451,22 @@ "webpack": "^5.11.0" } }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/fork-ts-checker-webpack-plugin/node_modules/ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", @@ -3339,6 +3476,12 @@ "ajv": "^6.9.1" } }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", @@ -3357,6 +3500,20 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "peer": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -3707,6 +3864,18 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "peer": true, + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/html-entities": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", @@ -3770,6 +3939,19 @@ "node": ">=8.0.0" } }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "peer": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/http-proxy-middleware": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", @@ -3795,6 +3977,19 @@ } } }, + "node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "peer": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -3819,7 +4014,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -4079,6 +4273,12 @@ "node": ">=0.10.0" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "peer": true + }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -4216,6 +4416,46 @@ "node": ">=12.0.0" } }, + "node_modules/jsdom": { + "version": "25.0.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz", + "integrity": "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==", + "peer": true, + "dependencies": { + "cssstyle": "^4.1.0", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.12", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.7.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.0.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^2.11.2" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -4241,9 +4481,9 @@ "dev": true }, "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true }, "node_modules/json-stable-stringify-without-jsonify": { @@ -4511,7 +4751,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -4520,7 +4759,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "dependencies": { "mime-db": "1.52.0" }, @@ -4699,8 +4937,7 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/multicast-dns": { "version": "7.2.5", @@ -4801,6 +5038,12 @@ "node": ">=8" } }, + "node_modules/nwsapi": { + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.16.tgz", + "integrity": "sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==", + "peer": true + }, "node_modules/object-inspect": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", @@ -5002,6 +5245,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse5": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", + "peer": true, + "dependencies": { + "entities": "^4.5.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -5230,7 +5485,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, "engines": { "node": ">=6" } @@ -5492,6 +5746,12 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rrweb-cssom": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", + "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", + "peer": true + }, "node_modules/run-applescript": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", @@ -5551,8 +5811,19 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "peer": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } }, "node_modules/schema-utils": { "version": "4.2.0", @@ -5573,28 +5844,6 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/schema-utils/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/schema-utils/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -5983,6 +6232,22 @@ "webpack": "^4.0.0 || ^5.0.0" } }, + "node_modules/source-map-loader/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/source-map-loader/node_modules/ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", @@ -5992,6 +6257,12 @@ "ajv": "^6.9.1" } }, + "node_modules/source-map-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/source-map-loader/node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", @@ -6208,6 +6479,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "peer": true + }, "node_modules/table": { "version": "6.8.2", "resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz", @@ -6224,28 +6501,6 @@ "node": ">=10.0.0" } }, - "node_modules/table/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -6307,6 +6562,22 @@ } } }, + "node_modules/terser-webpack-plugin/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", @@ -6330,6 +6601,12 @@ "node": ">= 10.13.0" } }, + "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/terser-webpack-plugin/node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", @@ -6363,18 +6640,6 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/terser/node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -6401,6 +6666,24 @@ "dev": true, "license": "MIT" }, + "node_modules/tldts": { + "version": "6.1.65", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.65.tgz", + "integrity": "sha512-xU9gLTfAGsADQ2PcWee6Hg8RFAv0DnjMGVJmDnUmI8a9+nYmapMQix4afwrdaCtT+AqP4MaxEzu7cCrYmBPbzQ==", + "peer": true, + "dependencies": { + "tldts-core": "^6.1.65" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "6.1.65", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.65.tgz", + "integrity": "sha512-Uq5t0N0Oj4nQSbU8wFN1YYENvMthvwU13MQrMJRspYCGLSAZjAfoBOJki5IQpnBM/WFskxxC/gIOTwaedmHaSg==", + "peer": true + }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -6432,6 +6715,30 @@ "node": ">=0.6" } }, + "node_modules/tough-cookie": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.0.0.tgz", + "integrity": "sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q==", + "peer": true, + "dependencies": { + "tldts": "^6.1.32" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "peer": true, + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/tree-dump": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz", @@ -6479,9 +6786,9 @@ } }, "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true }, "node_modules/tsutils": { @@ -6499,6 +6806,12 @@ "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" } }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -6546,6 +6859,20 @@ "node": ">= 0.6" } }, + "node_modules/typescript": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", @@ -6653,6 +6980,18 @@ "node": ">= 0.8" } }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "peer": true, + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/watchpack": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", @@ -6676,6 +7015,15 @@ "minimalistic-assert": "^1.0.0" } }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "peer": true, + "engines": { + "node": ">=12" + } + }, "node_modules/webpack": { "version": "5.93.0", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.93.0.tgz", @@ -6829,13 +7177,6 @@ "url": "https://github.com/sponsors/streamich" } }, - "node_modules/webpack-dev-middleware/node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", - "dev": true, - "license": "0BSD" - }, "node_modules/webpack-dev-server": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.0.4.tgz", @@ -6983,16 +7324,20 @@ "node": ">=10.13.0" } }, - "node_modules/webpack/node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "node_modules/webpack/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, - "bin": { - "acorn": "bin/acorn" + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, - "engines": { - "node": ">=0.4.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, "node_modules/webpack/node_modules/ajv-keywords": { @@ -7004,6 +7349,12 @@ "ajv": "^6.9.1" } }, + "node_modules/webpack/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/webpack/node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", @@ -7047,6 +7398,40 @@ "node": ">=0.8.0" } }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "peer": true, + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.0.tgz", + "integrity": "sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==", + "peer": true, + "dependencies": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -7132,7 +7517,6 @@ "version": "8.18.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "dev": true, "license": "MIT", "engines": { "node": ">=10.0.0" @@ -7150,6 +7534,21 @@ } } }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "peer": true + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -7426,12 +7825,6 @@ "to-fast-properties": "^2.0.0" } }, - "@blockly/block-test": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/@blockly/block-test/-/block-test-6.0.6.tgz", - "integrity": "sha512-qxX3nuMRP3pirq8Pwo6TInZWQZnwVNGuRiwIcfKHvpd80eBXEhNGVLvqTPMKu+GU64oTChqm+qSa8QJ0y8j9xg==", - "dev": true - }, "@blockly/dev-scripts": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@blockly/dev-scripts/-/dev-scripts-4.0.5.tgz", @@ -7454,22 +7847,59 @@ } }, "@blockly/dev-tools": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/@blockly/dev-tools/-/dev-tools-8.0.7.tgz", - "integrity": "sha512-/gtLu2tu4ZGaqVCfvivKJ5kWk8lUMQzJh8qtn6Z/U2SJng0nQXcXBEcFVlFAUPt1dE4lNMR7ZYScJw/V+38bgg==", + "version": "8.0.12", + "resolved": "https://registry.npmjs.org/@blockly/dev-tools/-/dev-tools-8.0.12.tgz", + "integrity": "sha512-jE0y/Z7ggmM2JS4l0Xf2ic3eecuM+ZDjUZNCcM2k6yy0VDJoxOPN63Cq2soswXQRuKHfzRMHY48rCvoKL3MqPA==", "dev": true, "requires": { - "@blockly/block-test": "^6.0.6", - "@blockly/theme-dark": "^7.0.5", - "@blockly/theme-deuteranopia": "^6.0.5", - "@blockly/theme-highcontrast": "^6.0.5", - "@blockly/theme-tritanopia": "^6.0.5", + "@blockly/block-test": "^6.0.11", + "@blockly/theme-dark": "^7.0.10", + "@blockly/theme-deuteranopia": "^6.0.10", + "@blockly/theme-highcontrast": "^6.0.10", + "@blockly/theme-tritanopia": "^6.0.10", "chai": "^4.2.0", "dat.gui": "^0.7.7", "lodash.assign": "^4.2.0", "lodash.merge": "^4.6.2", "monaco-editor": "^0.20.0", "sinon": "^9.0.2" + }, + "dependencies": { + "@blockly/block-test": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/@blockly/block-test/-/block-test-6.0.11.tgz", + "integrity": "sha512-aIgcxkof1gLJtJXKSvmnug9iSXbv5Qilnov4Sa/QNURiWJRxvMNqWiTZJVu/reuCQK4Qm4jadg9R9l+eu7ujvw==", + "dev": true, + "requires": {} + }, + "@blockly/theme-dark": { + "version": "7.0.10", + "resolved": "https://registry.npmjs.org/@blockly/theme-dark/-/theme-dark-7.0.10.tgz", + "integrity": "sha512-Wc6n115vt9alxzPkEwYtvBBGoPUV3gaYE00dvSKhqXTNoy1Xioujj9kT9VkGmdMO2mhgnJNczSpvxG8tcd4zLQ==", + "dev": true, + "requires": {} + }, + "@blockly/theme-deuteranopia": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/@blockly/theme-deuteranopia/-/theme-deuteranopia-6.0.10.tgz", + "integrity": "sha512-im5nIvf/Z0f1vJ9DK5Euu6URfY8G44xeFsat2b7TySF0BfAUWkGsagK3C6D5NatigPxKZqz3exC9zeXEtprAcg==", + "dev": true, + "requires": {} + }, + "@blockly/theme-highcontrast": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/@blockly/theme-highcontrast/-/theme-highcontrast-6.0.10.tgz", + "integrity": "sha512-s1hehl/b50IhebCs20hm2hFWbUTqJ2YSGdR0gnp2NLfNNRWwyZHZk+q4aG3k4L0YBWjNfE3XiRCkDISy83dBIA==", + "dev": true, + "requires": {} + }, + "@blockly/theme-tritanopia": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/@blockly/theme-tritanopia/-/theme-tritanopia-6.0.10.tgz", + "integrity": "sha512-QNIvUHokGMLnCWUzERRZa6sSkD5RIUynWDI+KNurBH21NeWnSNScQiNu0dS/w5MSkZ/Iqqbi79UZoF49SzEayg==", + "dev": true, + "requires": {} + } } }, "@blockly/eslint-config": { @@ -7485,30 +7915,6 @@ "eslint-plugin-jsdoc": "^46.8.0" } }, - "@blockly/theme-dark": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/@blockly/theme-dark/-/theme-dark-7.0.5.tgz", - "integrity": "sha512-TUS7X+UM5AvTe4Z1mtb371psViAeZSSmTzWuFrdNolX2i9P6XbNA9iKFDF0MObO307pOrtXodmsXpvbtgLeCUw==", - "dev": true - }, - "@blockly/theme-deuteranopia": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/@blockly/theme-deuteranopia/-/theme-deuteranopia-6.0.5.tgz", - "integrity": "sha512-z2hcsmRd5yaKf96gNZ1qM7IDqPb2M492FZhomRz6PgFYw/2rFXmQk6WcI84mmcTLrwfOfLkq/HIaPd23Wc3Hcw==", - "dev": true - }, - "@blockly/theme-highcontrast": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/@blockly/theme-highcontrast/-/theme-highcontrast-6.0.5.tgz", - "integrity": "sha512-rLhFM1+M6okikeSGHbZfxqJB7quWFm+RBXCi8ht8bjSkspdh5PCUOs10U4/GbI+YXSuAd2uFdg20xINL+X3KfQ==", - "dev": true - }, - "@blockly/theme-tritanopia": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/@blockly/theme-tritanopia/-/theme-tritanopia-6.0.5.tgz", - "integrity": "sha512-FVZmKfTQt1OQGsoZP78ET6V9xw83dd2vlJbTdjL1V6xlh0hixFGnqsze+Pw/FXiSWWLgeNKxTqQ6ImwhTHf5wA==", - "dev": true - }, "@discoveryjs/json-ext": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", @@ -7558,6 +7964,18 @@ "strip-json-comments": "^3.1.1" }, "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, "globals": { "version": "13.24.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", @@ -7572,6 +7990,12 @@ "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true } } }, @@ -7710,7 +8134,8 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", - "dev": true + "dev": true, + "requires": {} }, "@jsonjoy.com/json-pack": { "version": "1.1.0", @@ -7728,7 +8153,8 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.3.0.tgz", "integrity": "sha512-Cebt4Vk7k1xHy87kHY7KSPLT77A7Ev7IfOblyLZhtYEhrdQ6fX4EoLq3xOQ3O/DRMEh2ok5nyC180E+ABS8Wmw==", - "dev": true + "dev": true, + "requires": {} }, "@leichtgewicht/ip-codec": { "version": "2.0.5", @@ -8272,19 +8698,22 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", - "dev": true + "dev": true, + "requires": {} }, "@webpack-cli/info": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", - "dev": true + "dev": true, + "requires": {} }, "@webpack-cli/serve": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", - "dev": true + "dev": true, + "requires": {} }, "@xtuc/ieee754": { "version": "1.2.0", @@ -8315,33 +8744,44 @@ } }, "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true }, "acorn-import-attributes": { "version": "1.9.5", "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", - "dev": true + "dev": true, + "requires": {} }, "acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true + "dev": true, + "requires": {} + }, + "agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "peer": true, + "requires": { + "debug": "^4.3.4" + } }, "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" } }, "ajv-formats": { @@ -8351,26 +8791,6 @@ "dev": true, "requires": { "ajv": "^8.0.0" - }, - "dependencies": { - "ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } } }, "ajv-keywords": { @@ -8458,6 +8878,12 @@ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "peer": true + }, "babel-eslint": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", @@ -8504,6 +8930,15 @@ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true }, + "blockly": { + "version": "12.0.0-beta.0", + "resolved": "https://registry.npmjs.org/blockly/-/blockly-12.0.0-beta.0.tgz", + "integrity": "sha512-Z9cULe95wgQGj87DQZ9RBJRu5oMLQEUTz0beZVcZL/ddVuga6qtZZ9DbaDfCvt4ffVz1O/kyNzPJ+cqvovSjGg==", + "peer": true, + "requires": { + "jsdom": "25.0.1" + } + }, "body-parser": { "version": "1.20.2", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", @@ -8760,6 +9195,15 @@ "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "dev": true }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "peer": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -8888,17 +9332,35 @@ "which": "^2.0.1" } }, + "cssstyle": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz", + "integrity": "sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==", + "peer": true, + "requires": { + "rrweb-cssom": "^0.7.1" + } + }, "dat.gui": { "version": "0.7.9", "resolved": "https://registry.npmjs.org/dat.gui/-/dat.gui-0.7.9.tgz", "integrity": "sha512-sCNc1OHobc+Erc1HqiswYgHdVNpSJUlk/Hz8vzOCsER7rl+oF/4+v8GXFUyCgtXpoCX6+bnmg07DedLvBLwYKQ==", "dev": true }, + "data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "peer": true, + "requires": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + } + }, "debug": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", - "dev": true, "requires": { "ms": "2.1.2" } @@ -8909,6 +9371,12 @@ "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", "dev": true }, + "decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "peer": true + }, "deep-eql": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", @@ -8972,6 +9440,12 @@ "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", "dev": true }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "peer": true + }, "depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -9079,6 +9553,12 @@ "strip-ansi": "^6.0.1" } }, + "entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "peer": true + }, "envinfo": { "version": "7.13.0", "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", @@ -9190,6 +9670,18 @@ "@babel/highlight": "^7.10.4" } }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, "eslint-visitor-keys": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", @@ -9210,6 +9702,12 @@ "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true } } }, @@ -9217,7 +9715,8 @@ "version": "0.14.0", "resolved": "https://registry.npmjs.org/eslint-config-google/-/eslint-config-google-0.14.0.tgz", "integrity": "sha512-WsbX4WbjuMvTdeVL6+J3rK1RGhCTqjsFjX7UMSMgZiyxxaNLkoJENbrGExzERFeoTpGw3F3FypTiWAP9ZXzkEw==", - "dev": true + "dev": true, + "requires": {} }, "eslint-plugin-jsdoc": { "version": "46.10.1", @@ -9293,6 +9792,12 @@ "eslint-visitor-keys": "^1.3.0" }, "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, "eslint-visitor-keys": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", @@ -9638,10 +10143,29 @@ "tapable": "^2.2.1" }, "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, "ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, "schema-utils": { @@ -9657,6 +10181,17 @@ } } }, + "form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "peer": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -9910,6 +10445,15 @@ } } }, + "html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "peer": true, + "requires": { + "whatwg-encoding": "^3.1.1" + } + }, "html-entities": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", @@ -9952,6 +10496,16 @@ "requires-port": "^1.0.0" } }, + "http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "peer": true, + "requires": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + } + }, "http-proxy-middleware": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", @@ -9965,6 +10519,16 @@ "micromatch": "^4.0.2" } }, + "https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "peer": true, + "requires": { + "agent-base": "^7.0.2", + "debug": "4" + } + }, "human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -9981,7 +10545,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3.0.0" } @@ -10142,6 +10705,12 @@ "isobject": "^3.0.1" } }, + "is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "peer": true + }, "is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -10235,6 +10804,35 @@ "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", "dev": true }, + "jsdom": { + "version": "25.0.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz", + "integrity": "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==", + "peer": true, + "requires": { + "cssstyle": "^4.1.0", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.12", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.7.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.0.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + } + }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -10254,9 +10852,9 @@ "dev": true }, "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true }, "json-stable-stringify-without-jsonify": { @@ -10461,14 +11059,12 @@ "mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" }, "mime-types": { "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "requires": { "mime-db": "1.52.0" } @@ -10600,8 +11196,7 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "multicast-dns": { "version": "7.2.5", @@ -10683,6 +11278,12 @@ "path-key": "^3.0.0" } }, + "nwsapi": { + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.16.tgz", + "integrity": "sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==", + "peer": true + }, "object-inspect": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", @@ -10816,6 +11417,15 @@ "lines-and-columns": "^1.1.6" } }, + "parse5": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", + "peer": true, + "requires": { + "entities": "^4.5.0" + } + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -10976,8 +11586,7 @@ "punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==" }, "qs": { "version": "6.11.0", @@ -11146,6 +11755,12 @@ "glob": "^7.1.3" } }, + "rrweb-cssom": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", + "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", + "peer": true + }, "run-applescript": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", @@ -11170,8 +11785,16 @@ "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "peer": true, + "requires": { + "xmlchars": "^2.2.0" + } }, "schema-utils": { "version": "4.2.0", @@ -11183,26 +11806,6 @@ "ajv": "^8.9.0", "ajv-formats": "^2.1.1", "ajv-keywords": "^5.1.0" - }, - "dependencies": { - "ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } } }, "select-hose": { @@ -11500,10 +12103,29 @@ "whatwg-mimetype": "^2.3.0" }, "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, "ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, "schema-utils": { @@ -11672,6 +12294,12 @@ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "peer": true + }, "table": { "version": "6.8.2", "resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz", @@ -11683,26 +12311,6 @@ "slice-ansi": "^4.0.0", "string-width": "^4.2.3", "strip-ansi": "^6.0.1" - }, - "dependencies": { - "ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } } }, "tapable": { @@ -11721,14 +12329,6 @@ "acorn": "^8.8.2", "commander": "^2.20.0", "source-map-support": "~0.5.20" - }, - "dependencies": { - "acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", - "dev": true - } } }, "terser-webpack-plugin": { @@ -11744,11 +12344,24 @@ "terser": "^5.26.0" }, "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, "ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true + "dev": true, + "requires": {} }, "jest-worker": { "version": "27.5.1", @@ -11761,6 +12374,12 @@ "supports-color": "^8.0.0" } }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", @@ -11793,7 +12412,8 @@ "version": "1.21.0", "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==", - "dev": true + "dev": true, + "requires": {} }, "thunky": { "version": "1.1.0", @@ -11801,6 +12421,21 @@ "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", "dev": true }, + "tldts": { + "version": "6.1.65", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.65.tgz", + "integrity": "sha512-xU9gLTfAGsADQ2PcWee6Hg8RFAv0DnjMGVJmDnUmI8a9+nYmapMQix4afwrdaCtT+AqP4MaxEzu7cCrYmBPbzQ==", + "peer": true, + "requires": { + "tldts-core": "^6.1.65" + } + }, + "tldts-core": { + "version": "6.1.65", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.65.tgz", + "integrity": "sha512-Uq5t0N0Oj4nQSbU8wFN1YYENvMthvwU13MQrMJRspYCGLSAZjAfoBOJki5IQpnBM/WFskxxC/gIOTwaedmHaSg==", + "peer": true + }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -11822,11 +12457,30 @@ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true }, + "tough-cookie": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.0.0.tgz", + "integrity": "sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q==", + "peer": true, + "requires": { + "tldts": "^6.1.32" + } + }, + "tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "peer": true, + "requires": { + "punycode": "^2.3.1" + } + }, "tree-dump": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz", "integrity": "sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==", - "dev": true + "dev": true, + "requires": {} }, "ts-loader": { "version": "9.5.1", @@ -11850,9 +12504,9 @@ } }, "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true }, "tsutils": { @@ -11862,6 +12516,14 @@ "dev": true, "requires": { "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } } }, "type-check": { @@ -11895,6 +12557,13 @@ "mime-types": "~2.1.24" } }, + "typescript": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", + "dev": true, + "peer": true + }, "undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", @@ -11962,6 +12631,15 @@ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "dev": true }, + "w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "peer": true, + "requires": { + "xml-name-validator": "^5.0.0" + } + }, "watchpack": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", @@ -11981,6 +12659,12 @@ "minimalistic-assert": "^1.0.0" } }, + "webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "peer": true + }, "webpack": { "version": "5.93.0", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.93.0.tgz", @@ -12013,16 +12697,29 @@ "webpack-sources": "^3.2.3" }, "dependencies": { - "acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", - "dev": true + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } }, "ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, "schema-utils": { @@ -12092,12 +12789,6 @@ "tree-dump": "^1.0.1", "tslib": "^2.0.0" } - }, - "tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", - "dev": true } } }, @@ -12216,6 +12907,31 @@ "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true }, + "whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "peer": true, + "requires": { + "iconv-lite": "0.6.3" + } + }, + "whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "peer": true + }, + "whatwg-url": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.0.tgz", + "integrity": "sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==", + "peer": true, + "requires": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + } + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -12275,7 +12991,19 @@ "version": "8.18.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "dev": true + "requires": {} + }, + "xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "peer": true + }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "peer": true }, "y18n": { "version": "5.0.8", @@ -12337,4 +13065,4 @@ "dev": true } } -} \ No newline at end of file +} diff --git a/plugins/continuous-toolbox/package.json b/plugins/continuous-toolbox/package.json index c5877e3f65..cc21c6fe07 100644 --- a/plugins/continuous-toolbox/package.json +++ b/plugins/continuous-toolbox/package.json @@ -43,7 +43,7 @@ "@blockly/dev-tools": "^8.0.10" }, "peerDependencies": { - "blockly": "^12.0.0" + "blockly": "^12.0.0-beta.0" }, "publishConfig": { "access": "public", From 6e4fd66c39c8d99437efaf28beb83e2185d40dda Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Wed, 4 Dec 2024 15:15:50 -0800 Subject: [PATCH 34/52] chore: Update plugins for compatibility with Blockly v12. --- package-lock.json | 360 +++++++----------- package.json | 2 +- .../src/observable_parameter_model.ts | 12 +- plugins/content-highlight/src/index.ts | 2 +- plugins/field-bitmap/src/field-bitmap.ts | 1 - plugins/field-colour/src/field_colour.ts | 3 - plugins/field-date/src/field_date.ts | 5 - plugins/workspace-minimap/src/focus_region.ts | 2 +- plugins/workspace-minimap/src/minimap.ts | 2 +- 9 files changed, 150 insertions(+), 239 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9b1cc3ac5e..1212949849 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "@eslint/js": "^8.49.0", "@typescript-eslint/eslint-plugin": "^6.7.2", "@typescript-eslint/parser": "^6.7.2", - "blockly": "^11.0.0", + "blockly": "^12.0.0-beta.0", "conventional-changelog-conventionalcommits": "^5.0.0", "eslint": "^8.49.0", "eslint-config-google": "^0.14.0", @@ -911,12 +911,12 @@ } }, "node_modules/blockly": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/blockly/-/blockly-11.0.0.tgz", - "integrity": "sha512-6Ie7HuZWZLaETIVKFEP4FPDz267Pubn6+weQNZvXzqnkOYp9sKPSsPue8QIMCV9Qb5F4wYhqivgiDcZJcE1UlQ==", + "version": "12.0.0-beta.0", + "resolved": "https://registry.npmjs.org/blockly/-/blockly-12.0.0-beta.0.tgz", + "integrity": "sha512-Z9cULe95wgQGj87DQZ9RBJRu5oMLQEUTz0beZVcZL/ddVuga6qtZZ9DbaDfCvt4ffVz1O/kyNzPJ+cqvovSjGg==", "dev": true, "dependencies": { - "jsdom": "23.0.0" + "jsdom": "25.0.1" }, "engines": { "node": ">=18" @@ -1288,15 +1288,15 @@ } }, "node_modules/cssstyle": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", - "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz", + "integrity": "sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==", "dev": true, "dependencies": { - "rrweb-cssom": "^0.6.0" + "rrweb-cssom": "^0.7.1" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "node_modules/data-urls": { @@ -2227,9 +2227,9 @@ } }, "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", "dev": true, "dependencies": { "asynckit": "^0.4.0", @@ -3057,6 +3057,18 @@ "node": ">= 6" } }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -3539,38 +3551,38 @@ } }, "node_modules/jsdom": { - "version": "23.0.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-23.0.0.tgz", - "integrity": "sha512-cbL/UCtohJguhFC7c2/hgW6BeZCNvP7URQGnx9tSJRYKCdnfbfWOrtuLTMfiB2VxKsx5wPHVsh/J0aBy9lIIhQ==", + "version": "25.0.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz", + "integrity": "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==", "dev": true, "dependencies": { - "cssstyle": "^3.0.0", + "cssstyle": "^4.1.0", "data-urls": "^5.0.0", "decimal.js": "^10.4.3", "form-data": "^4.0.0", "html-encoding-sniffer": "^4.0.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.2", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.7", + "nwsapi": "^2.2.12", "parse5": "^7.1.2", - "rrweb-cssom": "^0.6.0", + "rrweb-cssom": "^0.7.1", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", - "tough-cookie": "^4.1.3", + "tough-cookie": "^5.0.0", "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^7.0.0", "whatwg-encoding": "^3.1.1", "whatwg-mimetype": "^4.0.0", "whatwg-url": "^14.0.0", - "ws": "^8.14.2", + "ws": "^8.18.0", "xml-name-validator": "^5.0.0" }, "engines": { "node": ">=18" }, "peerDependencies": { - "canvas": "^3.0.0" + "canvas": "^2.11.2" }, "peerDependenciesMeta": { "canvas": { @@ -3603,9 +3615,9 @@ } }, "node_modules/jsdom/node_modules/https-proxy-agent": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", - "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", "dev": true, "dependencies": { "agent-base": "^7.0.2", @@ -3615,18 +3627,6 @@ "node": ">= 14" } }, - "node_modules/jsdom/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/jsdom/node_modules/whatwg-encoding": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", @@ -4055,9 +4055,9 @@ } }, "node_modules/nwsapi": { - "version": "2.2.10", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.10.tgz", - "integrity": "sha512-QK0sRs7MKv0tKe1+5uZIQk/C8XGza4DAnztJG8iD+TpJIORARrCxczA738awHrZoHeTjSSoHqao2teO0dC/gFQ==", + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.16.tgz", + "integrity": "sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==", "dev": true }, "node_modules/object-assign": { @@ -4263,12 +4263,12 @@ } }, "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", "dev": true, "dependencies": { - "entities": "^4.4.0" + "entities": "^4.5.0" }, "funding": { "url": "https://github.com/inikulin/parse5?sponsor=1" @@ -4447,12 +4447,6 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true - }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -4497,12 +4491,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -4772,9 +4760,9 @@ } }, "node_modules/rrweb-cssom": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", - "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", + "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", "dev": true }, "node_modules/run-parallel": { @@ -5178,6 +5166,24 @@ "xtend": "~4.0.1" } }, + "node_modules/tldts": { + "version": "6.1.65", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.65.tgz", + "integrity": "sha512-xU9gLTfAGsADQ2PcWee6Hg8RFAv0DnjMGVJmDnUmI8a9+nYmapMQix4afwrdaCtT+AqP4MaxEzu7cCrYmBPbzQ==", + "dev": true, + "dependencies": { + "tldts-core": "^6.1.65" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "6.1.65", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.65.tgz", + "integrity": "sha512-Uq5t0N0Oj4nQSbU8wFN1YYENvMthvwU13MQrMJRspYCGLSAZjAfoBOJki5IQpnBM/WFskxxC/gIOTwaedmHaSg==", + "dev": true + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -5203,27 +5209,15 @@ } }, "node_modules/tough-cookie": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", - "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.0.0.tgz", + "integrity": "sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q==", "dev": true, "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" + "tldts": "^6.1.32" }, "engines": { - "node": ">=6" - } - }, - "node_modules/tough-cookie/node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" + "node": ">=16" } }, "node_modules/tr46": { @@ -5369,16 +5363,6 @@ "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", "dev": true }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -5525,18 +5509,6 @@ "node": ">=10.13.0" } }, - "node_modules/vinyl-fs/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/vinyl-sourcemap": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-2.0.0.tgz", @@ -5587,18 +5559,6 @@ "node": ">=12" } }, - "node_modules/whatwg-encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/whatwg-mimetype": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", @@ -5609,9 +5569,9 @@ } }, "node_modules/whatwg-url": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", - "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.0.tgz", + "integrity": "sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==", "dev": true, "dependencies": { "tr46": "^5.0.0", @@ -6407,12 +6367,12 @@ "dev": true }, "blockly": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/blockly/-/blockly-11.0.0.tgz", - "integrity": "sha512-6Ie7HuZWZLaETIVKFEP4FPDz267Pubn6+weQNZvXzqnkOYp9sKPSsPue8QIMCV9Qb5F4wYhqivgiDcZJcE1UlQ==", + "version": "12.0.0-beta.0", + "resolved": "https://registry.npmjs.org/blockly/-/blockly-12.0.0-beta.0.tgz", + "integrity": "sha512-Z9cULe95wgQGj87DQZ9RBJRu5oMLQEUTz0beZVcZL/ddVuga6qtZZ9DbaDfCvt4ffVz1O/kyNzPJ+cqvovSjGg==", "dev": true, "requires": { - "jsdom": "23.0.0" + "jsdom": "25.0.1" } }, "brace-expansion": { @@ -6707,12 +6667,12 @@ } }, "cssstyle": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", - "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz", + "integrity": "sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==", "dev": true, "requires": { - "rrweb-cssom": "^0.6.0" + "rrweb-cssom": "^0.7.1" } }, "data-urls": { @@ -7383,9 +7343,9 @@ } }, "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", "dev": true, "requires": { "asynckit": "^0.4.0", @@ -8014,6 +7974,15 @@ "debug": "4" } }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, "ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -8365,31 +8334,31 @@ "dev": true }, "jsdom": { - "version": "23.0.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-23.0.0.tgz", - "integrity": "sha512-cbL/UCtohJguhFC7c2/hgW6BeZCNvP7URQGnx9tSJRYKCdnfbfWOrtuLTMfiB2VxKsx5wPHVsh/J0aBy9lIIhQ==", + "version": "25.0.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz", + "integrity": "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==", "dev": true, "requires": { - "cssstyle": "^3.0.0", + "cssstyle": "^4.1.0", "data-urls": "^5.0.0", "decimal.js": "^10.4.3", "form-data": "^4.0.0", "html-encoding-sniffer": "^4.0.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.2", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.7", + "nwsapi": "^2.2.12", "parse5": "^7.1.2", - "rrweb-cssom": "^0.6.0", + "rrweb-cssom": "^0.7.1", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", - "tough-cookie": "^4.1.3", + "tough-cookie": "^5.0.0", "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^7.0.0", "whatwg-encoding": "^3.1.1", "whatwg-mimetype": "^4.0.0", "whatwg-url": "^14.0.0", - "ws": "^8.14.2", + "ws": "^8.18.0", "xml-name-validator": "^5.0.0" }, "dependencies": { @@ -8412,24 +8381,15 @@ } }, "https-proxy-agent": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", - "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", "dev": true, "requires": { "agent-base": "^7.0.2", "debug": "4" } }, - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - }, "whatwg-encoding": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", @@ -8763,9 +8723,9 @@ } }, "nwsapi": { - "version": "2.2.10", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.10.tgz", - "integrity": "sha512-QK0sRs7MKv0tKe1+5uZIQk/C8XGza4DAnztJG8iD+TpJIORARrCxczA738awHrZoHeTjSSoHqao2teO0dC/gFQ==", + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.16.tgz", + "integrity": "sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==", "dev": true }, "object-assign": { @@ -8919,12 +8879,12 @@ "dev": true }, "parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", "dev": true, "requires": { - "entities": "^4.4.0" + "entities": "^4.5.0" } }, "path-exists": { @@ -9051,12 +9011,6 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, - "psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true - }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -9088,12 +9042,6 @@ "side-channel": "^1.0.4" } }, - "querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true - }, "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -9290,9 +9238,9 @@ } }, "rrweb-cssom": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", - "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", + "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", "dev": true }, "run-parallel": { @@ -9617,6 +9565,21 @@ "xtend": "~4.0.1" } }, + "tldts": { + "version": "6.1.65", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.65.tgz", + "integrity": "sha512-xU9gLTfAGsADQ2PcWee6Hg8RFAv0DnjMGVJmDnUmI8a9+nYmapMQix4afwrdaCtT+AqP4MaxEzu7cCrYmBPbzQ==", + "dev": true, + "requires": { + "tldts-core": "^6.1.65" + } + }, + "tldts-core": { + "version": "6.1.65", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.65.tgz", + "integrity": "sha512-Uq5t0N0Oj4nQSbU8wFN1YYENvMthvwU13MQrMJRspYCGLSAZjAfoBOJki5IQpnBM/WFskxxC/gIOTwaedmHaSg==", + "dev": true + }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -9636,23 +9599,12 @@ } }, "tough-cookie": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", - "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.0.0.tgz", + "integrity": "sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q==", "dev": true, "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "dependencies": { - "universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true - } + "tldts": "^6.1.32" } }, "tr46": { @@ -9765,16 +9717,6 @@ "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", "dev": true }, - "url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, - "requires": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -9889,17 +9831,6 @@ "value-or-function": "^4.0.0", "vinyl": "^3.0.0", "vinyl-sourcemap": "^2.0.0" - }, - "dependencies": { - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - } } }, "vinyl-sourcemap": { @@ -9938,17 +9869,6 @@ "dev": true, "requires": { "iconv-lite": "0.6.3" - }, - "dependencies": { - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - } } }, "whatwg-mimetype": { @@ -9958,9 +9878,9 @@ "dev": true }, "whatwg-url": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", - "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.0.tgz", + "integrity": "sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==", "dev": true, "requires": { "tr46": "^5.0.0", diff --git a/package.json b/package.json index 177396cc5d..ce6d47fafc 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@eslint/js": "^8.49.0", "@typescript-eslint/eslint-plugin": "^6.7.2", "@typescript-eslint/parser": "^6.7.2", - "blockly": "^11.0.0", + "blockly": "^12.0.0-beta.0", "conventional-changelog-conventionalcommits": "^5.0.0", "eslint": "^8.49.0", "eslint-config-google": "^0.14.0", diff --git a/plugins/block-shareable-procedures/src/observable_parameter_model.ts b/plugins/block-shareable-procedures/src/observable_parameter_model.ts index 4e14647c55..b253874af9 100644 --- a/plugins/block-shareable-procedures/src/observable_parameter_model.ts +++ b/plugins/block-shareable-procedures/src/observable_parameter_model.ts @@ -13,7 +13,7 @@ export class ObservableParameterModel implements Blockly.procedures.IParameterModel { private id: string; - private variable: Blockly.VariableModel; + private variable: Blockly.IVariableModel; private shouldFireEvents = false; private procedureModel: Blockly.procedures.IProcedureModel | null = null; @@ -44,8 +44,8 @@ export class ObservableParameterModel * @returns This parameter model. */ setName(name: string, id?: string): this { - if (name === this.variable.name) return this; - const oldName = this.variable.name; + if (name === this.variable.getName()) return this; + const oldName = this.variable.getName(); this.variable = this.workspace.getVariable(name) ?? this.workspace.createVariable(name, '', id); @@ -73,7 +73,7 @@ export class ObservableParameterModel protected createBackingVariable( name: string, varId?: string, - ): Blockly.VariableModel { + ): Blockly.IVariableModel { this.variable = this.workspace.getVariable(name) ?? this.workspace.createVariable(name, '', varId); @@ -100,7 +100,7 @@ export class ObservableParameterModel * @returns the name of this parameter. */ getName(): string { - return this.variable.name; + return this.variable.getName(); } /** @@ -123,7 +123,7 @@ export class ObservableParameterModel /** * @returns the variable model associated with the parameter model. */ - getVariableModel(): Blockly.VariableModel { + getVariableModel(): Blockly.IVariableModel { return this.variable; } diff --git a/plugins/content-highlight/src/index.ts b/plugins/content-highlight/src/index.ts index 4ec5a2d23f..f8a072b908 100644 --- a/plugins/content-highlight/src/index.ts +++ b/plugins/content-highlight/src/index.ts @@ -13,7 +13,7 @@ import * as Blockly from 'blockly/core'; /** * List of events that cause a change in content area size. */ -const contentChangeEvents = [ +const contentChangeEvents: string[] = [ Blockly.Events.VIEWPORT_CHANGE, Blockly.Events.BLOCK_MOVE, Blockly.Events.BLOCK_DELETE, diff --git a/plugins/field-bitmap/src/field-bitmap.ts b/plugins/field-bitmap/src/field-bitmap.ts index 70b4fea421..8cf361160f 100644 --- a/plugins/field-bitmap/src/field-bitmap.ts +++ b/plugins/field-bitmap/src/field-bitmap.ts @@ -59,7 +59,6 @@ export class FieldBitmap extends Blockly.Field { super(value, validator, config); this.SERIALIZABLE = true; - this.CURSOR = 'default'; this.buttonOptions = {...DEFAULT_BUTTONS, ...config?.buttons}; this.pixelColours = {...DEFAULT_PIXEL_COLOURS, ...config?.colours}; diff --git a/plugins/field-colour/src/field_colour.ts b/plugins/field-colour/src/field_colour.ts index dc5c88dfe4..4d125853d2 100644 --- a/plugins/field-colour/src/field_colour.ts +++ b/plugins/field-colour/src/field_colour.ts @@ -33,9 +33,6 @@ export class FieldColour extends Blockly.Field { */ override SERIALIZABLE = true; - /** Mouse cursor style when over the hotspot that initiates the editor. */ - override CURSOR = 'default'; - /** * Used to tell if the field needs to be rendered the next time the block is * rendered. Colour fields are statically sized, and only need to be diff --git a/plugins/field-date/src/field_date.ts b/plugins/field-date/src/field_date.ts index 9b2a9ff8b8..0ec7c4846a 100644 --- a/plugins/field-date/src/field_date.ts +++ b/plugins/field-date/src/field_date.ts @@ -20,11 +20,6 @@ export class FieldDate extends Blockly.FieldTextInput { */ SERIALIZABLE = true; - /** - * Mouse cursor style when over the hotspot that initiates the editor. - */ - CURSOR = 'text'; - /** * Class for a date input field. Derived from the Closure library date * picker. diff --git a/plugins/workspace-minimap/src/focus_region.ts b/plugins/workspace-minimap/src/focus_region.ts index bb71f07918..70b5b6fba7 100644 --- a/plugins/workspace-minimap/src/focus_region.ts +++ b/plugins/workspace-minimap/src/focus_region.ts @@ -12,7 +12,7 @@ import * as Blockly from 'blockly/core'; -const blockEvents = new Set([ +const blockEvents = new Set([ Blockly.Events.VIEWPORT_CHANGE, Blockly.Events.BLOCK_CHANGE, Blockly.Events.BLOCK_CREATE, diff --git a/plugins/workspace-minimap/src/minimap.ts b/plugins/workspace-minimap/src/minimap.ts index f61b7a4d8f..041701d418 100644 --- a/plugins/workspace-minimap/src/minimap.ts +++ b/plugins/workspace-minimap/src/minimap.ts @@ -15,7 +15,7 @@ import * as Blockly from 'blockly/core'; import {FocusRegion} from './focus_region'; // Events that should be send over to the minimap from the primary workspace -const blockEvents = new Set([ +const blockEvents = new Set([ Blockly.Events.BLOCK_CHANGE, Blockly.Events.BLOCK_CREATE, Blockly.Events.BLOCK_DELETE, From 52172b62fd22d7ae6f3fb2b5d2074a2f62dc2b9c Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 5 Dec 2024 12:49:48 -0800 Subject: [PATCH 35/52] fix: Fix tests for v12 compatibility. --- .../block-plus-minus/test/list_create.mocha.js | 2 +- .../test/procedure_blocks.mocha.js | 1 + plugins/keyboard-navigation/src/navigation.js | 10 ++++++---- .../src/navigation_controller.js | 8 ++++---- .../test/navigation_test.mocha.js | 15 +++++++++------ 5 files changed, 21 insertions(+), 15 deletions(-) diff --git a/plugins/block-plus-minus/test/list_create.mocha.js b/plugins/block-plus-minus/test/list_create.mocha.js index e99a756eab..f5f14db936 100644 --- a/plugins/block-plus-minus/test/list_create.mocha.js +++ b/plugins/block-plus-minus/test/list_create.mocha.js @@ -103,7 +103,7 @@ suite('List create block', function () { testCases: [ { title: 'Trivial', - expectedCode: '{nil, nil, nil}', + expectedCode: '{None, None, None}', createBlock: trivialCreateBlock, }, ], diff --git a/plugins/block-shareable-procedures/test/procedure_blocks.mocha.js b/plugins/block-shareable-procedures/test/procedure_blocks.mocha.js index 8733ff18c9..8b0694a6eb 100644 --- a/plugins/block-shareable-procedures/test/procedure_blocks.mocha.js +++ b/plugins/block-shareable-procedures/test/procedure_blocks.mocha.js @@ -1237,6 +1237,7 @@ suite('Procedures', function () { 'if a procedure caller block was already disabled before ' + 'its definition was disabled, it is not reenabled', function () { + this.workspace.options.disable = true; const defBlock = createProcDefBlock(this.workspace); const callBlock = createProcCallBlock(this.workspace); globalThis.clock.runAll(); diff --git a/plugins/keyboard-navigation/src/navigation.js b/plugins/keyboard-navigation/src/navigation.js index 9fc285ba8d..e78edb897f 100644 --- a/plugins/keyboard-navigation/src/navigation.js +++ b/plugins/keyboard-navigation/src/navigation.js @@ -503,13 +503,15 @@ export class Navigation { const flyoutContents = flyout.getContents(); const firstFlyoutItem = flyoutContents[0]; if (!firstFlyoutItem) return; - if (firstFlyoutItem.button) { + if (firstFlyoutItem.element instanceof Blockly.FlyoutButton) { const astNode = Blockly.ASTNode.createButtonNode( - firstFlyoutItem.button, + firstFlyoutItem.element, ); this.getFlyoutCursor(workspace).setCurNode(astNode); - } else if (firstFlyoutItem.block) { - const astNode = Blockly.ASTNode.createStackNode(firstFlyoutItem.block); + } else if (firstFlyoutItem.element instanceof Blockly.BlockSvg) { + const astNode = Blockly.ASTNode.createStackNode( + firstFlyoutItem.element, + ); this.getFlyoutCursor(workspace).setCurNode(astNode); } } diff --git a/plugins/keyboard-navigation/src/navigation_controller.js b/plugins/keyboard-navigation/src/navigation_controller.js index 8f3820a906..d3eaa4c1c1 100644 --- a/plugins/keyboard-navigation/src/navigation_controller.js +++ b/plugins/keyboard-navigation/src/navigation_controller.js @@ -126,13 +126,13 @@ export class NavigationController { } switch (shortcut.name) { case Constants.SHORTCUT_NAMES.PREVIOUS: - return this.selectPrevious_(); + return this.selectPrevious(); case Constants.SHORTCUT_NAMES.OUT: - return this.selectParent_(); + return this.selectParent(); case Constants.SHORTCUT_NAMES.NEXT: - return this.selectNext_(); + return this.selectNext(); case Constants.SHORTCUT_NAMES.IN: - return this.selectChild_(); + return this.selectChild(); default: return false; } diff --git a/plugins/keyboard-navigation/test/navigation_test.mocha.js b/plugins/keyboard-navigation/test/navigation_test.mocha.js index ed5c67e989..81705b850d 100644 --- a/plugins/keyboard-navigation/test/navigation_test.mocha.js +++ b/plugins/keyboard-navigation/test/navigation_test.mocha.js @@ -83,22 +83,22 @@ suite('Navigation', function () { [ 'Calls toolbox selectNext', createKeyDownEvent(Blockly.utils.KeyCodes.S, 'NotAField'), - 'selectNext_', + 'selectNext', ], [ 'Calls toolbox selectPrevious', createKeyDownEvent(Blockly.utils.KeyCodes.W, 'NotAField'), - 'selectPrevious_', + 'selectPrevious', ], [ 'Calls toolbox selectParent', createKeyDownEvent(Blockly.utils.KeyCodes.D, 'NotAField'), - 'selectChild_', + 'selectChild', ], [ 'Calls toolbox selectChild', createKeyDownEvent(Blockly.utils.KeyCodes.A, 'NotAField'), - 'selectParent_', + 'selectParent', ], ]; @@ -109,7 +109,7 @@ suite('Navigation', function () { test(testCaseName, function () { const toolbox = this.workspace.getToolbox(); const selectStub = sinon.stub(toolbox, stubName); - toolbox.selectedItem_ = toolbox.contents_[0]; + toolbox.selectedItem_ = toolbox.contents.values().next().value; Blockly.ShortcutRegistry.registry.onKeyDown(this.workspace, mockEvent); sinon.assert.called(selectStub); }); @@ -554,7 +554,10 @@ suite('Navigation', function () { Blockly.ShortcutRegistry.registry.onKeyDown(this.workspace, tEvent); - const firstCategory = this.workspace.getToolbox().contents_[0]; + const firstCategory = this.workspace + .getToolbox() + .contents.values() + .next().value; chai.assert.isTrue(keyDownSpy.returned(true)); chai.assert.equal( this.workspace.getToolbox().getSelectedItem(), From 2b5c09c9fffe00b7214deae34c126aa7afa9d781 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 5 Dec 2024 14:50:34 -0800 Subject: [PATCH 36/52] fix: Fix bug that could cause scroll jank when interrupting an animated scroll. --- plugins/continuous-toolbox/src/ContinuousFlyout.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/plugins/continuous-toolbox/src/ContinuousFlyout.ts b/plugins/continuous-toolbox/src/ContinuousFlyout.ts index 76197d649d..be887e06f3 100644 --- a/plugins/continuous-toolbox/src/ContinuousFlyout.ts +++ b/plugins/continuous-toolbox/src/ContinuousFlyout.ts @@ -182,6 +182,19 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { requestAnimationFrame(this.stepScrollAnimation.bind(this)); } + /** + * Handles mouse wheel events. + * + * @param e The mouse wheel event to handle. + */ + protected override wheel_(e: WheelEvent) { + // Don't scroll in response to mouse wheel events if we're currently + // animating scrolling to a category. + if (!this.scrollTarget) { + super.wheel_(e); + } + } + /** * Calculates the additional padding needed at the bottom of the flyout in * order to make it possible to scroll to the top of the last category. From c9b38b0f8c3509e7f44ac0f1c047a048d6b66b3b Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 9 Jan 2025 15:47:25 -0800 Subject: [PATCH 37/52] chore: Revert errant test change. --- plugins/block-plus-minus/test/list_create.mocha.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/block-plus-minus/test/list_create.mocha.js b/plugins/block-plus-minus/test/list_create.mocha.js index f5f14db936..e99a756eab 100644 --- a/plugins/block-plus-minus/test/list_create.mocha.js +++ b/plugins/block-plus-minus/test/list_create.mocha.js @@ -103,7 +103,7 @@ suite('List create block', function () { testCases: [ { title: 'Trivial', - expectedCode: '{None, None, None}', + expectedCode: '{nil, nil, nil}', createBlock: trivialCreateBlock, }, ], From 769aaca1e34ac5238677fda9e7c6f5f7cc545d3e Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 9 Jan 2025 15:47:51 -0800 Subject: [PATCH 38/52] refactor: Update continuous-toolbox for latest flyout API changes. --- .../continuous-toolbox/src/ContinuousFlyout.ts | 18 ++++++++++++------ .../src/RecyclableBlockFlyoutInflater.ts | 12 ++++++++---- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/plugins/continuous-toolbox/src/ContinuousFlyout.ts b/plugins/continuous-toolbox/src/ContinuousFlyout.ts index be887e06f3..9dc3f7d87c 100644 --- a/plugins/continuous-toolbox/src/ContinuousFlyout.ts +++ b/plugins/continuous-toolbox/src/ContinuousFlyout.ts @@ -13,6 +13,10 @@ import {ContinuousToolbox} from './ContinuousToolbox'; import {ContinuousFlyoutMetrics} from './ContinuousFlyoutMetrics'; import {RecyclableBlockFlyoutInflater} from './RecyclableBlockFlyoutInflater'; +interface LabelFlyoutItem extends Blockly.FlyoutItem { + getElement(): Blockly.FlyoutButton; +} + /** * Class for continuous flyout. */ @@ -79,7 +83,7 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { this.scrollPositions.clear(); this.getContents() .filter(this.toolboxItemIsLabel.bind(this)) - .map((item) => item.element) + .map((item) => item.getElement()) .forEach((label) => { this.scrollPositions.set( label.getButtonText(), @@ -97,12 +101,13 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { */ protected toolboxItemIsLabel( item: Blockly.FlyoutItem, - ): item is {type: string; element: Blockly.FlyoutButton} { + ): item is LabelFlyoutItem { + const element = item.getElement(); return !!( - item.type === 'label' && - item.element instanceof Blockly.FlyoutButton && - item.element.isLabel() && - this.getParentToolbox().getCategoryByName(item.element.getButtonText()) + item.getType() === 'label' && + element instanceof Blockly.FlyoutButton && + element.isLabel() && + this.getParentToolbox().getCategoryByName(element.getButtonText()) ); } @@ -187,6 +192,7 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { * * @param e The mouse wheel event to handle. */ + // eslint-disable-next-line @typescript-eslint/naming-convention protected override wheel_(e: WheelEvent) { // Don't scroll in response to mouse wheel events if we're currently // animating scrolling to a category. diff --git a/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts b/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts index 69dfeba37a..6a6feb7d43 100644 --- a/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts +++ b/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts @@ -168,14 +168,18 @@ export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater { /** * Disposes of the provided block. * - * @param element The block to dispose of. + * @param item The block to dispose of. */ - override disposeElement(element: Blockly.BlockSvg) { - if (this.blockIsRecyclable(element)) { + override disposeItem(item: Blockly.FlyoutItem) { + const element = item.getElement(); + if ( + element instanceof Blockly.BlockSvg && + this.blockIsRecyclable(element) + ) { this.removeListeners(element.id); this.recycleBlock(element); } else { - super.disposeElement(element); + super.disposeItem(item); } } From b5a678066ac51e72e5086cda8bdc9180a57cf977 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 10 Jan 2025 14:16:47 -0800 Subject: [PATCH 39/52] chore: Update Blockly dependency to 12.0.0-beta.1. --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1212949849..e850941a98 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "@eslint/js": "^8.49.0", "@typescript-eslint/eslint-plugin": "^6.7.2", "@typescript-eslint/parser": "^6.7.2", - "blockly": "^12.0.0-beta.0", + "blockly": "^12.0.0-beta.1", "conventional-changelog-conventionalcommits": "^5.0.0", "eslint": "^8.49.0", "eslint-config-google": "^0.14.0", @@ -911,9 +911,9 @@ } }, "node_modules/blockly": { - "version": "12.0.0-beta.0", - "resolved": "https://registry.npmjs.org/blockly/-/blockly-12.0.0-beta.0.tgz", - "integrity": "sha512-Z9cULe95wgQGj87DQZ9RBJRu5oMLQEUTz0beZVcZL/ddVuga6qtZZ9DbaDfCvt4ffVz1O/kyNzPJ+cqvovSjGg==", + "version": "12.0.0-beta.1", + "resolved": "https://registry.npmjs.org/blockly/-/blockly-12.0.0-beta.1.tgz", + "integrity": "sha512-lECwZ4K+YuLXMM0yxWTz1lwkmDl424sst7h/dhtSefuCki8afjI/F87byYK/ZIZsMKBEz2+8wEJ1Wlx5cYWIAg==", "dev": true, "dependencies": { "jsdom": "25.0.1" @@ -6367,9 +6367,9 @@ "dev": true }, "blockly": { - "version": "12.0.0-beta.0", - "resolved": "https://registry.npmjs.org/blockly/-/blockly-12.0.0-beta.0.tgz", - "integrity": "sha512-Z9cULe95wgQGj87DQZ9RBJRu5oMLQEUTz0beZVcZL/ddVuga6qtZZ9DbaDfCvt4ffVz1O/kyNzPJ+cqvovSjGg==", + "version": "12.0.0-beta.1", + "resolved": "https://registry.npmjs.org/blockly/-/blockly-12.0.0-beta.1.tgz", + "integrity": "sha512-lECwZ4K+YuLXMM0yxWTz1lwkmDl424sst7h/dhtSefuCki8afjI/F87byYK/ZIZsMKBEz2+8wEJ1Wlx5cYWIAg==", "dev": true, "requires": { "jsdom": "25.0.1" diff --git a/package.json b/package.json index ce6d47fafc..be5e65263e 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@eslint/js": "^8.49.0", "@typescript-eslint/eslint-plugin": "^6.7.2", "@typescript-eslint/parser": "^6.7.2", - "blockly": "^12.0.0-beta.0", + "blockly": "^12.0.0-beta.1", "conventional-changelog-conventionalcommits": "^5.0.0", "eslint": "^8.49.0", "eslint-config-google": "^0.14.0", From 1f62a1cdae7113ef2c67bf24d5d8ef9032be8e64 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 17 Jan 2025 10:39:06 -0800 Subject: [PATCH 40/52] chore: Clarify comments. --- plugins/continuous-toolbox/src/ContinuousFlyout.ts | 2 ++ plugins/continuous-toolbox/src/ContinuousMetrics.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/continuous-toolbox/src/ContinuousFlyout.ts b/plugins/continuous-toolbox/src/ContinuousFlyout.ts index 9dc3f7d87c..28f7fde8e0 100644 --- a/plugins/continuous-toolbox/src/ContinuousFlyout.ts +++ b/plugins/continuous-toolbox/src/ContinuousFlyout.ts @@ -14,6 +14,8 @@ import {ContinuousFlyoutMetrics} from './ContinuousFlyoutMetrics'; import {RecyclableBlockFlyoutInflater} from './RecyclableBlockFlyoutInflater'; interface LabelFlyoutItem extends Blockly.FlyoutItem { + // Blockly.FlyoutButton represents both buttons and labels; a label is just + // a borderless, non-clickable button. getElement(): Blockly.FlyoutButton; } diff --git a/plugins/continuous-toolbox/src/ContinuousMetrics.ts b/plugins/continuous-toolbox/src/ContinuousMetrics.ts index 135e16f581..48c0663c3b 100644 --- a/plugins/continuous-toolbox/src/ContinuousMetrics.ts +++ b/plugins/continuous-toolbox/src/ContinuousMetrics.ts @@ -56,7 +56,7 @@ export class ContinuousMetrics extends Blockly.MetricsManager { /** * Gets the absolute left and absolute top in pixel coordinates. * This is where the visible workspace starts in relation to the SVG - * container, shifted to not include the area behind the flyout. + * container, adjusted to not include the area behind the flyout. * * @returns The absolute metrics for the workspace. */ From a964e0118385e809186e29c2fcaf2c6a05d9405f Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 17 Jan 2025 10:59:25 -0800 Subject: [PATCH 41/52] chore: Make guard clauses single-line. --- .../src/ContinuousFlyout.ts | 28 +++++++++---------- .../src/ContinuousToolbox.ts | 11 +++----- .../src/RecyclableBlockFlyoutInflater.ts | 21 ++++---------- 3 files changed, 23 insertions(+), 37 deletions(-) diff --git a/plugins/continuous-toolbox/src/ContinuousFlyout.ts b/plugins/continuous-toolbox/src/ContinuousFlyout.ts index 28f7fde8e0..90cbfdfebe 100644 --- a/plugins/continuous-toolbox/src/ContinuousFlyout.ts +++ b/plugins/continuous-toolbox/src/ContinuousFlyout.ts @@ -121,9 +121,8 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { private selectCategoryByScrollPosition(position: number) { // If we are currently auto-scrolling, due to selecting a category by // clicking on it, do not update the category selection. - if (this.scrollTarget) { - return; - } + if (this.scrollTarget) return; + const scaledPosition = Math.round(position / this.getWorkspace().scale); // Traverse the array of scroll positions in reverse, so we can select the // furthest category that the scroll position is beyond. @@ -198,9 +197,9 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { protected override wheel_(e: WheelEvent) { // Don't scroll in response to mouse wheel events if we're currently // animating scrolling to a category. - if (!this.scrollTarget) { - super.wheel_(e); - } + if (this.scrollTarget) return; + + super.wheel_(e); } /** @@ -215,16 +214,15 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { contentMetrics: Blockly.MetricsManager.ContainerRegion, viewMetrics: Blockly.MetricsManager.ContainerRegion, ): number { - if (this.scrollPositions.size > 0) { - const lastPosition = - ([...this.scrollPositions.values()].pop() ?? 0) * - this.getWorkspace().scale; - const lastCategoryHeight = contentMetrics.height - lastPosition; - if (lastCategoryHeight < viewMetrics.height) { - return viewMetrics.height - lastCategoryHeight; - } + if (this.scrollPositions.size === 0) return 0; + + const lastPosition = + ([...this.scrollPositions.values()].pop() ?? 0) * + this.getWorkspace().scale; + const lastCategoryHeight = contentMetrics.height - lastPosition; + if (lastCategoryHeight < viewMetrics.height) { + return viewMetrics.height - lastCategoryHeight; } - return 0; } /** diff --git a/plugins/continuous-toolbox/src/ContinuousToolbox.ts b/plugins/continuous-toolbox/src/ContinuousToolbox.ts index 5f77dd94c2..5fe2948439 100644 --- a/plugins/continuous-toolbox/src/ContinuousToolbox.ts +++ b/plugins/continuous-toolbox/src/ContinuousToolbox.ts @@ -155,10 +155,8 @@ export class ContinuousToolbox extends Blockly.Toolbox { item.isSelectable() && name === item.getName(), ); - if (category) { - return category as Blockly.ISelectableToolboxItem; - } - return null; + if (!category) return null; + return category as Blockly.ISelectableToolboxItem; } /** @@ -171,9 +169,8 @@ export class ContinuousToolbox extends Blockly.Toolbox { */ selectCategoryByName(name: string) { const newItem = this.getCategoryByName(name); - if (!newItem) { - return; - } + if (!newItem) return; + const oldItem = this.selectedItem_; if (oldItem && this.shouldDeselectItem_(oldItem, newItem)) { diff --git a/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts b/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts index 6a6feb7d43..b09f3dcb0f 100644 --- a/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts +++ b/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts @@ -125,33 +125,24 @@ export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater { * @returns True if the block can be recycled. False otherwise. */ protected blockIsRecyclable(block: Blockly.Block): boolean { - if (!this.recyclingEnabled) { - return false; - } + if (!this.recyclingEnabled) return false; if (this.recycleEligibilityChecker) { return this.recycleEligibilityChecker(block); } // If the block needs to parse mutations, never recycle. - if (block.mutationToDom && block.domToMutation) { - return false; - } + if (block.mutationToDom && block.domToMutation) return false; - if (!block.isEnabled()) { - return false; - } + if (!block.isEnabled()) return false; for (const input of block.inputList) { for (const field of input.fieldRow) { // No variables. - if (field.referencesVariables()) { - return false; - } + if (field.referencesVariables()) return false; + if (field instanceof Blockly.FieldDropdown) { - if (field.isOptionListDynamic()) { - return false; - } + if (field.isOptionListDynamic()) return false; } } // Check children. From de04cdb8fbad27daf9b8f647bf12e3c572924f8d Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 17 Jan 2025 11:02:04 -0800 Subject: [PATCH 42/52] refactor: Improve typings for getViewMetrics(). --- plugins/continuous-toolbox/src/ContinuousMetrics.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/continuous-toolbox/src/ContinuousMetrics.ts b/plugins/continuous-toolbox/src/ContinuousMetrics.ts index 48c0663c3b..3355f40d0d 100644 --- a/plugins/continuous-toolbox/src/ContinuousMetrics.ts +++ b/plugins/continuous-toolbox/src/ContinuousMetrics.ts @@ -22,7 +22,7 @@ export class ContinuousMetrics extends Blockly.MetricsManager { * workspace coordinates or pixel coordinates. */ override getViewMetrics( - getWorkspaceCoordinates?: boolean, + getWorkspaceCoordinates = false, ): Blockly.MetricsManager.ContainerRegion { const scale = getWorkspaceCoordinates ? this.workspace_.scale : 1; const svgMetrics = this.getSvgMetrics(); From f49e087dc3eaf7007ae5e82cc5775a4ae56390a3 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 17 Jan 2025 11:07:14 -0800 Subject: [PATCH 43/52] fix: Fix missing return. --- plugins/continuous-toolbox/src/ContinuousFlyout.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/continuous-toolbox/src/ContinuousFlyout.ts b/plugins/continuous-toolbox/src/ContinuousFlyout.ts index 90cbfdfebe..563519f5e2 100644 --- a/plugins/continuous-toolbox/src/ContinuousFlyout.ts +++ b/plugins/continuous-toolbox/src/ContinuousFlyout.ts @@ -223,6 +223,8 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { if (lastCategoryHeight < viewMetrics.height) { return viewMetrics.height - lastCategoryHeight; } + + return 0; } /** From 921f7a9ede1c5f79e1dfb267ecfd75f81d217515 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 17 Jan 2025 11:09:03 -0800 Subject: [PATCH 44/52] chore: Add comment clarifying FlyoutButton weirdness. --- plugins/continuous-toolbox/src/ContinuousFlyout.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/continuous-toolbox/src/ContinuousFlyout.ts b/plugins/continuous-toolbox/src/ContinuousFlyout.ts index 563519f5e2..b188092f00 100644 --- a/plugins/continuous-toolbox/src/ContinuousFlyout.ts +++ b/plugins/continuous-toolbox/src/ContinuousFlyout.ts @@ -107,6 +107,7 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { const element = item.getElement(); return !!( item.getType() === 'label' && + // Note that `FlyoutButton` represents both buttons and labels. element instanceof Blockly.FlyoutButton && element.isLabel() && this.getParentToolbox().getCategoryByName(element.getButtonText()) From 8aa65d0e3455c8832ec5c51a7bfc81236413b9fc Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 17 Jan 2025 13:30:13 -0800 Subject: [PATCH 45/52] chore: Improve formatting. --- plugins/continuous-toolbox/src/ContinuousToolbox.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/plugins/continuous-toolbox/src/ContinuousToolbox.ts b/plugins/continuous-toolbox/src/ContinuousToolbox.ts index 5fe2948439..67267b8dde 100644 --- a/plugins/continuous-toolbox/src/ContinuousToolbox.ts +++ b/plugins/continuous-toolbox/src/ContinuousToolbox.ts @@ -79,12 +79,7 @@ export class ContinuousToolbox extends Blockly.Toolbox { // Handle custom categories (e.g. variables and functions) if (typeof itemContents === 'string') { - itemContents = [ - { - custom: itemContents, - kind: 'CATEGORY', - }, - ]; + itemContents = [{custom: itemContents, kind: 'CATEGORY'}]; } contents = contents.concat(itemContents); } From 12378ea351a126fd5731c8b3316d87137dcf9613 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 17 Jan 2025 13:43:18 -0800 Subject: [PATCH 46/52] refactor: Use direct field access instead of pass-through setters. --- .../src/ContinuousFlyout.ts | 4 ++-- .../src/RecyclableBlockFlyoutInflater.ts | 23 ++----------------- 2 files changed, 4 insertions(+), 23 deletions(-) diff --git a/plugins/continuous-toolbox/src/ContinuousFlyout.ts b/plugins/continuous-toolbox/src/ContinuousFlyout.ts index b188092f00..40326b5adb 100644 --- a/plugins/continuous-toolbox/src/ContinuousFlyout.ts +++ b/plugins/continuous-toolbox/src/ContinuousFlyout.ts @@ -267,7 +267,7 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { * @param func The function used to determine if a block is recyclable. */ setBlockIsRecyclable(func: (block: Blockly.Block) => boolean) { - this.getRecyclableInflater().setRecyclingEligibilityChecker(func); + this.getRecyclableInflater().recycleEligibilityChecker = func; } /** @@ -276,7 +276,7 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { * @param isEnabled True to allow blocks to be recycled, false otherwise. */ setRecyclingEnabled(isEnabled: boolean) { - this.getRecyclableInflater().setRecyclingEnabled(isEnabled); + this.getRecyclableInflater().recyclingEnabled = isEnabled; } /** diff --git a/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts b/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts index b09f3dcb0f..14cdeafe89 100644 --- a/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts +++ b/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts @@ -13,7 +13,7 @@ export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater { /** * Whether or not block recycling is enabled. */ - private recyclingEnabled = false; + public recyclingEnabled = false; /** * Map from block type to block instance. @@ -23,26 +23,7 @@ export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater { /** * Custom function to use for checking whether or not blocks can be recycled. */ - private recycleEligibilityChecker?: (block: Blockly.Block) => boolean; - - /** - * Toggles whether or not recycling is enabled. - * - * @param enabled True if recycling should be enabled. - */ - setRecyclingEnabled(enabled: boolean) { - this.recyclingEnabled = enabled; - } - - /** - * Sets a function to use to determine a block's ability to be recycled. - * - * @param checker The eligibility check function to use, or undefined to - * revert to the built-in default. - */ - setRecyclingEligibilityChecker(checker?: (block: Blockly.Block) => boolean) { - this.recycleEligibilityChecker = checker; - } + public recycleEligibilityChecker?: (block: Blockly.Block) => boolean; /** * Creates a new block from the given block definition. From cdecc3211ae43512c9e1d82a9b86167a32406d56 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 17 Jan 2025 14:46:17 -0800 Subject: [PATCH 47/52] fix: Check for modern mutations when determining block recyclability. --- .../src/RecyclableBlockFlyoutInflater.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts b/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts index 14cdeafe89..66bd36f85f 100644 --- a/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts +++ b/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts @@ -113,7 +113,12 @@ export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater { } // If the block needs to parse mutations, never recycle. - if (block.mutationToDom && block.domToMutation) return false; + if ( + (block.mutationToDom && block.domToMutation) || + (block.saveExtraState && block.loadExtraState) + ) { + return false; + } if (!block.isEnabled()) return false; From 702e5b19a6a69040365d707d28442f51773a8720 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 17 Jan 2025 15:22:03 -0800 Subject: [PATCH 48/52] chore: Add comment clarifying flyout positioning checks. --- plugins/continuous-toolbox/src/ContinuousFlyout.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/continuous-toolbox/src/ContinuousFlyout.ts b/plugins/continuous-toolbox/src/ContinuousFlyout.ts index 40326b5adb..94ca0a7828 100644 --- a/plugins/continuous-toolbox/src/ContinuousFlyout.ts +++ b/plugins/continuous-toolbox/src/ContinuousFlyout.ts @@ -234,6 +234,8 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout { override getX(): number { if ( this.isVisible() && + // Make sure that this flyout is associated with a toolbox and not e.g. + // a simple flyout or the trashcan flyout. this.targetWorkspace.toolboxPosition === this.toolboxPosition_ && this.targetWorkspace.getToolbox() && this.toolboxPosition_ !== Blockly.utils.toolbox.Position.LEFT From 96d85a0ff7dc680726d064c5976b9cf1d82574db Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 17 Jan 2025 15:44:13 -0800 Subject: [PATCH 49/52] fix: Remove explicit public visibility annotations. --- .../continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts b/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts index 66bd36f85f..58278bc40f 100644 --- a/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts +++ b/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts @@ -13,7 +13,7 @@ export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater { /** * Whether or not block recycling is enabled. */ - public recyclingEnabled = false; + recyclingEnabled = false; /** * Map from block type to block instance. @@ -23,7 +23,7 @@ export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater { /** * Custom function to use for checking whether or not blocks can be recycled. */ - public recycleEligibilityChecker?: (block: Blockly.Block) => boolean; + recycleEligibilityChecker?: (block: Blockly.Block) => boolean; /** * Creates a new block from the given block definition. From 09ed44f691623b2c70ff2e7fd68cee5501f28145 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 27 Jan 2025 12:14:03 -0800 Subject: [PATCH 50/52] fix: Don't recycle blocks with any mutation-related methods. --- .../continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts b/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts index 58278bc40f..96b62bbf94 100644 --- a/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts +++ b/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts @@ -114,8 +114,10 @@ export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater { // If the block needs to parse mutations, never recycle. if ( - (block.mutationToDom && block.domToMutation) || - (block.saveExtraState && block.loadExtraState) + block.mutationToDom || + block.domToMutation || + block.saveExtraState || + block.loadExtraState ) { return false; } From 5bdd70ecbe1cea95061ffabd3e22bc6878f9677c Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 27 Jan 2025 12:54:19 -0800 Subject: [PATCH 51/52] chore: Add some information about block recycling to the README. --- plugins/continuous-toolbox/README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/plugins/continuous-toolbox/README.md b/plugins/continuous-toolbox/README.md index dc8cfd3f2b..6d74dc8c5c 100644 --- a/plugins/continuous-toolbox/README.md +++ b/plugins/continuous-toolbox/README.md @@ -45,6 +45,21 @@ const workspace = Blockly.inject('blocklyDiv', { }); ``` +## Block Recycling + +As a performance optimization, by default the continuous toolbox "recycles" +blocks to avoid having to create DOM elements for potentially hundreds of blocks +every time the flyout is shown. This entails moving the blocks offscreen when +the flyout is hidden, and then simply repositioning them when the flyout is +shown. Not all block types are amenable to this; in particular, blocks with +dynamic behavior (e.g. those that reference variables, support mutations, or +have dynamic dropdown fields) are excluded by default. + +This feature can be toggled by calling `setRecyclingEnabled()` on an instance of +`ContinuousFlyout`, and the default ruleset for determing which blocks are safe +for recycling can be replaced with a custom callback by passing that function to +`setBlockIsRecyclable()`. + ## License Apache 2.0 From f51d56b242e17d58d0f31f3c86d37d240a393212 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Tue, 28 Jan 2025 09:03:27 -0800 Subject: [PATCH 52/52] chore: Improve continuous toolbox README. --- plugins/continuous-toolbox/README.md | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/plugins/continuous-toolbox/README.md b/plugins/continuous-toolbox/README.md index 6d74dc8c5c..34fecd2113 100644 --- a/plugins/continuous-toolbox/README.md +++ b/plugins/continuous-toolbox/README.md @@ -49,16 +49,21 @@ const workspace = Blockly.inject('blocklyDiv', { As a performance optimization, by default the continuous toolbox "recycles" blocks to avoid having to create DOM elements for potentially hundreds of blocks -every time the flyout is shown. This entails moving the blocks offscreen when -the flyout is hidden, and then simply repositioning them when the flyout is -shown. Not all block types are amenable to this; in particular, blocks with -dynamic behavior (e.g. those that reference variables, support mutations, or -have dynamic dropdown fields) are excluded by default. +every time the flyout is shown. With the default set of blocks, this drops the +time to show the flyout from roughly 35ms to 25ms; the effect is naturally +larger with larger block sets. + +Recycling is unrelated to Blockly's Trash feature; instead, it entails moving +the blocks offscreen when the flyout is hidden, and then simply repositioning +them when the flyout is shown again. Not all block types are amenable to this; +in particular, blocks with dynamic behavior (e.g. those that reference +variables, support mutations, or have dynamic dropdown fields) are excluded by +default. This feature can be toggled by calling `setRecyclingEnabled()` on an instance of -`ContinuousFlyout`, and the default ruleset for determing which blocks are safe -for recycling can be replaced with a custom callback by passing that function to -`setBlockIsRecyclable()`. +`ContinuousFlyout`, and the default ruleset for determining which blocks are +safe for recycling can be replaced with a custom callback by passing that +function to `setBlockIsRecyclable()`. ## License