feat: Better unconstrained announcements (experimental) (#9529)

* feat: Improve annonucements for unconstrained.

* chore: Lint fixes.
This commit is contained in:
Ben Henning
2025-12-12 13:13:12 -08:00
committed by GitHub
parent 9a8293096b
commit 1216655cd5

View File

@@ -1901,33 +1901,37 @@ export class BlockSvg
/** Starts a drag on the block. */
startDrag(e?: PointerEvent): void {
const location = this.getRelativeToSurfaceXY();
this.dragStrategy.startDrag(e);
const dragStrategy = this.dragStrategy as BlockDragStrategy;
const candidate = dragStrategy.connectionCandidate?.neighbour ?? null;
this.currentConnectionCandidate = candidate;
this.announceDynamicAriaState(true, false);
this.announceDynamicAriaState(true, false, location);
}
/** Drags the block to the given location. */
drag(newLoc: Coordinate, e?: PointerEvent): void {
const prevLocation = this.getRelativeToSurfaceXY();
this.dragStrategy.drag(newLoc, e);
const dragStrategy = this.dragStrategy as BlockDragStrategy;
const candidate = dragStrategy.connectionCandidate?.neighbour ?? null;
this.currentConnectionCandidate = candidate;
this.announceDynamicAriaState(true, false, newLoc);
this.announceDynamicAriaState(true, false, prevLocation, newLoc);
}
/** Ends the drag on the block. */
endDrag(e?: PointerEvent): void {
const location = this.getRelativeToSurfaceXY();
this.dragStrategy.endDrag(e);
this.currentConnectionCandidate = null;
this.announceDynamicAriaState(false, false);
this.announceDynamicAriaState(false, false, location);
}
/** Moves the block back to where it was at the start of a drag. */
revertDrag(): void {
const location = this.getRelativeToSurfaceXY();
this.dragStrategy.revertDrag();
this.announceDynamicAriaState(false, true);
this.announceDynamicAriaState(false, true, location);
}
/**
@@ -2024,11 +2028,14 @@ export class BlockSvg
*
* @param isMoving Whether the specified block is currently being moved.
* @param isCanceled Whether the previous movement operation has been canceled.
* @param prevLoc Either the current location of the block, or its previous
* location if it's been moved (and a newLoc is provided).
* @param newLoc The new location the block is moving to (if unconstrained).
*/
private announceDynamicAriaState(
isMoving: boolean,
isCanceled: boolean,
prevLoc: Coordinate,
newLoc?: Coordinate,
) {
if (isCanceled) {
@@ -2057,11 +2064,99 @@ export class BlockSvg
aria.announceDynamicAriaState(announcementContext.join(' '));
} else if (newLoc) {
// The block is being freely dragged.
aria.announceDynamicAriaState(
`Moving unconstrained to coordinate x ${Math.round(newLoc.x)} and y ${Math.round(newLoc.y)}.`,
);
const direction = this.diff(prevLoc, newLoc);
if (direction === CoordinateShift.MOVE_NORTH) {
aria.announceDynamicAriaState('Moved block up.');
} else if (direction === CoordinateShift.MOVE_EAST) {
aria.announceDynamicAriaState('Moved block right.');
} else if (direction === CoordinateShift.MOVE_SOUTH) {
aria.announceDynamicAriaState('Moved block down.');
} else if (direction === CoordinateShift.MOVE_WEST) {
aria.announceDynamicAriaState('Moved block left.');
} else if (direction === CoordinateShift.MOVE_NORTHEAST) {
aria.announceDynamicAriaState('Moved block up and right.');
} else if (direction === CoordinateShift.MOVE_SOUTHEAST) {
aria.announceDynamicAriaState('Moved block down and right.');
} else if (direction === CoordinateShift.MOVE_SOUTHWEST) {
aria.announceDynamicAriaState('Moved block down and left.');
} else if (direction === CoordinateShift.MOVE_NORTHWEST) {
aria.announceDynamicAriaState('Moved block up and left.');
}
// Else don't announce anything because the block didn't move.
}
}
private diff(fromCoord: Coordinate, toCoord: Coordinate): CoordinateShift {
const xDiff = this.diffAxis(fromCoord.x, toCoord.x);
const yDiff = this.diffAxis(fromCoord.y, toCoord.y);
if (xDiff === AxisShift.SAME && yDiff == AxisShift.SAME) {
return CoordinateShift.STAY_STILL;
}
if (xDiff === AxisShift.SAME) {
// Move vertically.
if (yDiff === AxisShift.SMALLER) {
return CoordinateShift.MOVE_NORTH;
} else {
return CoordinateShift.MOVE_SOUTH;
}
} else if (yDiff === AxisShift.SAME) {
// Move horizontally.
if (xDiff === AxisShift.SMALLER) {
return CoordinateShift.MOVE_WEST;
} else {
return CoordinateShift.MOVE_EAST;
}
} else {
// Move diagonally.
if (xDiff === AxisShift.SMALLER) {
// Move left.
if (yDiff === AxisShift.SMALLER) {
return CoordinateShift.MOVE_NORTHWEST;
} else {
return CoordinateShift.MOVE_SOUTHWEST;
}
} else {
// Move right.
if (yDiff === AxisShift.SMALLER) {
return CoordinateShift.MOVE_NORTHEAST;
} else {
return CoordinateShift.MOVE_SOUTHEAST;
}
}
}
}
private diffAxis(fromX: number, toX: number): AxisShift {
if (this.isEqual(fromX, toX)) {
return AxisShift.SAME;
} else if (toX > fromX) {
return AxisShift.LARGER;
} else {
return AxisShift.SMALLER;
}
}
private isEqual(x: number, y: number): boolean {
return Math.abs(x - y) < 1e-10;
}
}
enum CoordinateShift {
MOVE_NORTH,
MOVE_EAST,
MOVE_SOUTH,
MOVE_WEST,
MOVE_NORTHEAST,
MOVE_SOUTHEAST,
MOVE_SOUTHWEST,
MOVE_NORTHWEST,
STAY_STILL,
}
enum AxisShift {
SMALLER,
SAME,
LARGER,
}
interface BlockSummary {