Skip to content

Commit 5fa493b

Browse files
committed
Merge branch 'main' into v13
2 parents 1cbf1b3 + 10079df commit 5fa493b

17 files changed

Lines changed: 1372 additions & 12298 deletions

package-lock.json

Lines changed: 1204 additions & 1231 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
"workspaces": [
2020
"packages/*"
2121
],
22+
"devDependencies": {
23+
"@commitlint/cli": "^20.1.0",
24+
"@commitlint/config-conventional": "^20.0.0"
25+
},
2226
"scripts": {
2327
"test": "npm run test --ws --if-present",
2428
"lint": "npm run lint --ws --if-present",

packages/blockly/core/block_svg.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -354,8 +354,8 @@ export class BlockSvg
354354
* @returns Object with .x and .y properties in workspace coordinates.
355355
*/
356356
override getRelativeToSurfaceXY(): Coordinate {
357-
const layerManger = this.workspace.getLayerManager();
358-
if (!layerManger) {
357+
const layerManager = this.workspace.getLayerManager();
358+
if (!layerManager) {
359359
throw new Error(
360360
'Cannot calculate position because the workspace has not been appended',
361361
);
@@ -371,7 +371,7 @@ export class BlockSvg
371371
x += xy.x;
372372
y += xy.y;
373373
element = element.parentNode as SVGElement;
374-
} while (element && !layerManger.hasLayer(element));
374+
} while (element && !layerManager.hasLayer(element));
375375
}
376376
return new Coordinate(x, y);
377377
}
@@ -1126,7 +1126,9 @@ export class BlockSvg
11261126
if (this.isDeadOrDying()) return;
11271127
const gesture = this.workspace.getGesture(e);
11281128
if (gesture) {
1129+
this.bringToFront();
11291130
gesture.setStartIcon(icon);
1131+
getFocusManager().focusNode(icon);
11301132
}
11311133
};
11321134
}

packages/blockly/core/css.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,14 @@ let content = `
9393
9494
.blocklyBlockCanvas.blocklyCanvasTransitioning,
9595
.blocklyBubbleCanvas.blocklyCanvasTransitioning {
96-
transition: transform .5s;
96+
transition: transform .15s;
97+
}
98+
99+
@media (prefers-reduced-motion) {
100+
.blocklyBlockCanvas.blocklyCanvasTransitioning,
101+
.blocklyBubbleCanvas.blocklyCanvasTransitioning {
102+
transition: none;
103+
}
97104
}
98105
99106
.blocklyEmboss {

packages/blockly/core/flyout_base.ts

Lines changed: 14 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ import * as dom from './utils/dom.js';
3838
import * as idGenerator from './utils/idgenerator.js';
3939
import {Svg} from './utils/svg.js';
4040
import * as toolbox from './utils/toolbox.js';
41-
import * as Variables from './variables.js';
4241
import {WorkspaceSvg} from './workspace_svg.js';
4342

4443
/**
@@ -813,44 +812,23 @@ export abstract class Flyout
813812
* @internal
814813
*/
815814
createBlock(originalBlock: BlockSvg): BlockSvg {
816-
let newBlock = null;
817-
eventUtils.disable();
818-
const variablesBeforeCreation = this.targetWorkspace
819-
.getVariableMap()
820-
.getAllVariables();
821-
this.targetWorkspace.setResizesEnabled(false);
822-
try {
823-
newBlock = this.placeNewBlock(originalBlock);
824-
} finally {
825-
eventUtils.enable();
815+
const targetWorkspace = this.targetWorkspace;
816+
const svgRootOld = originalBlock.getSvgRoot();
817+
if (!svgRootOld) {
818+
throw Error('oldBlock is not rendered');
826819
}
827820

828-
// Close the flyout.
829-
this.targetWorkspace.hideChaff();
830-
831-
const newVariables = Variables.getAddedVariables(
832-
this.targetWorkspace,
833-
variablesBeforeCreation,
834-
);
835-
836-
if (eventUtils.isEnabled()) {
837-
eventUtils.setGroup(true);
838-
// Fire a VarCreate event for each (if any) new variable created.
839-
for (let i = 0; i < newVariables.length; i++) {
840-
const thisVariable = newVariables[i];
841-
eventUtils.fire(
842-
new (eventUtils.get(EventType.VAR_CREATE))(thisVariable),
843-
);
844-
}
821+
// Clone the block.
822+
const json = this.serializeBlock(originalBlock);
823+
// Normally this resizes leading to weird jumps. Save it for terminateDrag.
824+
targetWorkspace.setResizesEnabled(false);
825+
const block = blocks.appendInternal(json, targetWorkspace, {
826+
recordUndo: true,
827+
}) as BlockSvg;
845828

846-
// Block events come after var events, in case they refer to newly created
847-
// variables.
848-
eventUtils.fire(new (eventUtils.get(EventType.BLOCK_CREATE))(newBlock));
849-
}
850-
if (this.autoClose) {
851-
this.hide();
852-
}
853-
return newBlock;
829+
this.positionNewBlock(originalBlock, block);
830+
targetWorkspace.hideChaff();
831+
return block;
854832
}
855833

856834
/**
@@ -873,30 +851,6 @@ export abstract class Flyout
873851
: false;
874852
}
875853

876-
/**
877-
* Copy a block from the flyout to the workspace and position it correctly.
878-
*
879-
* @param oldBlock The flyout block to copy.
880-
* @returns The new block in the main workspace.
881-
*/
882-
private placeNewBlock(oldBlock: BlockSvg): BlockSvg {
883-
const targetWorkspace = this.targetWorkspace;
884-
const svgRootOld = oldBlock.getSvgRoot();
885-
if (!svgRootOld) {
886-
throw Error('oldBlock is not rendered');
887-
}
888-
889-
// Clone the block.
890-
const json = this.serializeBlock(oldBlock);
891-
// Normally this resizes leading to weird jumps. Save it for terminateDrag.
892-
targetWorkspace.setResizesEnabled(false);
893-
const block = blocks.append(json, targetWorkspace) as BlockSvg;
894-
895-
this.positionNewBlock(oldBlock, block);
896-
897-
return block;
898-
}
899-
900854
/**
901855
* Serialize a block to JSON.
902856
*

packages/blockly/core/flyout_button.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,13 @@ Css.register(`
427427
fill: #666;
428428
}
429429
430-
.blocklyFlyoutButton:hover {
430+
@media (hover: hover) {
431+
.blocklyFlyoutButton:hover {
432+
fill: #aaa;
433+
}
434+
}
435+
436+
.blocklyFlyoutButton:active {
431437
fill: #aaa;
432438
}
433439

packages/blockly/core/gesture.ts

Lines changed: 28 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import * as eventUtils from './events/utils.js';
2727
import type {Field} from './field.js';
2828
import {getFocusManager} from './focus_manager.js';
2929
import type {IBubble} from './interfaces/i_bubble.js';
30+
import {hasContextMenu} from './interfaces/i_contextmenu.js';
3031
import {IDraggable, isDraggable} from './interfaces/i_draggable.js';
3132
import {IDragger} from './interfaces/i_dragger.js';
3233
import type {IFlyout} from './interfaces/i_flyout.js';
@@ -273,24 +274,19 @@ export class Gesture {
273274
throw new Error(`Cannot update dragging from the flyout because the ' +
274275
'flyout's target workspace is undefined`);
275276
}
276-
if (
277-
!this.flyout.isScrollable() ||
278-
this.flyout.isDragTowardWorkspace(this.currentDragDeltaXY)
279-
) {
280-
this.startWorkspace_ = this.flyout.targetWorkspace;
281-
this.startWorkspace_.updateScreenCalculationsIfScrolled();
282-
// Start the event group now, so that the same event group is used for
283-
// block creation and block dragging.
284-
if (!eventUtils.getGroup()) {
285-
eventUtils.setGroup(true);
286-
}
287-
// The start block is no longer relevant, because this is a drag.
288-
this.startBlock = null;
289-
this.targetBlock = this.flyout.createBlock(this.targetBlock);
290-
getFocusManager().focusNode(this.targetBlock);
291-
return true;
277+
278+
this.startWorkspace_ = this.flyout.targetWorkspace;
279+
this.startWorkspace_.updateScreenCalculationsIfScrolled();
280+
// Start the event group now, so that the same event group is used for
281+
// block creation and block dragging.
282+
if (!eventUtils.getGroup()) {
283+
eventUtils.setGroup(true);
292284
}
293-
return false;
285+
// The start block is no longer relevant, because this is a drag.
286+
this.startBlock = null;
287+
this.targetBlock = this.flyout.createBlock(this.targetBlock);
288+
getFocusManager().focusNode(this.targetBlock);
289+
return true;
294290
}
295291

296292
/**
@@ -732,22 +728,12 @@ export class Gesture {
732728
* @internal
733729
*/
734730
handleRightClick(e: PointerEvent) {
735-
if (this.targetBlock) {
736-
this.bringBlockToFront();
737-
this.targetBlock.workspace.hideChaff(!!this.flyout);
738-
this.targetBlock.showContextMenu(e);
739-
} else if (this.startBubble) {
740-
this.startBubble.showContextMenu(e);
741-
} else if (this.startComment) {
742-
this.startComment.workspace.hideChaff();
743-
this.startComment.showContextMenu(e);
744-
} else if (this.startWorkspace_ && !this.flyout) {
745-
this.startWorkspace_.hideChaff();
746-
getFocusManager().focusNode(this.startWorkspace_);
747-
this.startWorkspace_.showContextMenu(e);
731+
const selection = getFocusManager().getFocusedNode();
732+
if (hasContextMenu(selection)) {
733+
this.startWorkspace_?.hideChaff(!!this.flyout);
734+
selection.showContextMenu(e);
748735
}
749736

750-
// TODO: Handle right-click on a bubble.
751737
e.preventDefault();
752738
e.stopPropagation();
753739

@@ -773,7 +759,12 @@ export class Gesture {
773759
this.setStartWorkspace(ws);
774760
this.mostRecentEvent = e;
775761

776-
if (!this.targetBlock && !this.startBubble && !this.startComment) {
762+
if (
763+
!this.targetBlock &&
764+
!this.startBubble &&
765+
!this.startComment &&
766+
!this.startIcon
767+
) {
777768
// Ensure the workspace is selected if nothing else should be. Note that
778769
// this is focusNode() instead of focusTree() because if any active node
779770
// is focused in the workspace it should be defocused.
@@ -878,12 +869,6 @@ export class Gesture {
878869
);
879870
}
880871

881-
// Note that the order is important here: bringing a block to the front will
882-
// cause it to become focused and showing the field editor will capture
883-
// focus ephemerally. It's important to ensure that focus is properly
884-
// restored back to the block after field editing has completed.
885-
this.bringBlockToFront();
886-
887872
// Only show the editor if the field's editor wasn't already open
888873
// right before this gesture started.
889874
const dropdownAlreadyOpen = this.currentDropdownOwner === this.startField;
@@ -899,7 +884,6 @@ export class Gesture {
899884
'Cannot do an icon click because the start icon is undefined',
900885
);
901886
}
902-
this.bringBlockToFront();
903887
this.startIcon.onClick();
904888
}
905889

@@ -938,7 +922,6 @@ export class Gesture {
938922
);
939923
eventUtils.fire(event);
940924
}
941-
this.bringBlockToFront();
942925
eventUtils.setGroup(false);
943926
}
944927

@@ -957,19 +940,6 @@ export class Gesture {
957940

958941
// TODO (fenichel): Move bubbles to the front.
959942

960-
/**
961-
* Move the dragged/clicked block to the front of the workspace so that it is
962-
* not occluded by other blocks.
963-
*/
964-
private bringBlockToFront() {
965-
// Blocks in the flyout don't overlap, so skip the work.
966-
if (this.targetBlock && !this.flyout) {
967-
// Always ensure the block being dragged/clicked has focus.
968-
getFocusManager().focusNode(this.targetBlock);
969-
this.targetBlock.bringToFront();
970-
}
971-
}
972-
973943
/* Begin functions for populating a gesture at pointerdown. */
974944

975945
/**
@@ -1039,8 +1009,9 @@ export class Gesture {
10391009
* @internal
10401010
*/
10411011
setStartBlock(block: BlockSvg) {
1042-
// If the gesture already went through a bubble, don't set the start block.
1043-
if (!this.startBlock && !this.startBubble) {
1012+
// If the gesture already went through a block child, don't set the start
1013+
// block.
1014+
if (!this.startBlock && !this.startBubble && !this.startIcon) {
10441015
this.startBlock = block;
10451016
if (block.isInFlyout && block !== block.getRootBlock()) {
10461017
this.setTargetBlock(block.getRootBlock());
@@ -1064,7 +1035,8 @@ export class Gesture {
10641035
this.setTargetBlock(block.getParent()!);
10651036
} else {
10661037
this.targetBlock = block;
1067-
getFocusManager().focusNode(block);
1038+
getFocusManager().focusNode(this.targetBlock);
1039+
this.targetBlock.bringToFront();
10681040
}
10691041
}
10701042

packages/blockly/core/icons/icon.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import type {Block} from '../block.js';
88
import type {BlockSvg} from '../block_svg.js';
99
import * as browserEvents from '../browser_events.js';
10+
import type {IContextMenu} from '../interfaces/i_contextmenu.js';
1011
import type {IFocusableTree} from '../interfaces/i_focusable_tree.js';
1112
import {hasBubble} from '../interfaces/i_has_bubble.js';
1213
import type {IIcon} from '../interfaces/i_icon.js';
@@ -26,7 +27,7 @@ import type {IconType} from './icon_types.js';
2627
* block (such as warnings or comments) as opposed to fields, which provide
2728
* "actual" information, related to how a block functions.
2829
*/
29-
export abstract class Icon implements IIcon {
30+
export abstract class Icon implements IIcon, IContextMenu {
3031
/**
3132
* The position of this icon relative to its blocks top-start,
3233
* in workspace units.
@@ -196,4 +197,8 @@ export abstract class Icon implements IIcon {
196197
getSourceBlock(): Block {
197198
return this.sourceBlock;
198199
}
200+
201+
showContextMenu(e: PointerEvent) {
202+
(this.getSourceBlock() as BlockSvg).showContextMenu(e);
203+
}
199204
}

packages/blockly/core/interfaces/i_contextmenu.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,8 @@ export interface IContextMenu {
1414
*/
1515
showContextMenu(e: Event): void;
1616
}
17+
18+
/** @returns true if the given object implements IContextMenu. */
19+
export function hasContextMenu(obj: any): obj is IContextMenu {
20+
return obj && typeof obj.showContextMenu === 'function';
21+
}

packages/blockly/core/layer_manager.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,11 @@ export class LayerManager {
7373
* @internal
7474
*/
7575
appendToAnimationLayer(elem: IRenderedElement) {
76-
const currentTransform = this.dragLayer?.getAttribute('transform');
76+
const currentTransform = this.dragLayer?.style.transform;
7777
// Only update the current transform when appending, so animations don't
7878
// move if the workspace moves.
79-
if (currentTransform) {
80-
this.animationLayer?.setAttribute('transform', currentTransform);
79+
if (currentTransform && this.animationLayer) {
80+
this.animationLayer.style.transform = currentTransform;
8181
}
8282
this.animationLayer?.appendChild(elem.getSvgRoot());
8383
}
@@ -88,10 +88,12 @@ export class LayerManager {
8888
* @internal
8989
*/
9090
translateLayers(newCoord: Coordinate, newScale: number) {
91-
const translation = `translate(${newCoord.x}, ${newCoord.y}) scale(${newScale})`;
92-
this.dragLayer?.setAttribute('transform', translation);
91+
const translation = `translate(${newCoord.x}px, ${newCoord.y}px) scale(${newScale})`;
92+
if (this.dragLayer) {
93+
this.dragLayer.style.transform = translation;
94+
}
9395
for (const [_, layer] of this.layers) {
94-
layer.setAttribute('transform', translation);
96+
layer.style.transform = translation;
9597
}
9698
}
9799

0 commit comments

Comments
 (0)