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. */ /** Starts a drag on the block. */
startDrag(e?: PointerEvent): void { startDrag(e?: PointerEvent): void {
const location = this.getRelativeToSurfaceXY();
this.dragStrategy.startDrag(e); this.dragStrategy.startDrag(e);
const dragStrategy = this.dragStrategy as BlockDragStrategy; const dragStrategy = this.dragStrategy as BlockDragStrategy;
const candidate = dragStrategy.connectionCandidate?.neighbour ?? null; const candidate = dragStrategy.connectionCandidate?.neighbour ?? null;
this.currentConnectionCandidate = candidate; this.currentConnectionCandidate = candidate;
this.announceDynamicAriaState(true, false); this.announceDynamicAriaState(true, false, location);
} }
/** Drags the block to the given location. */ /** Drags the block to the given location. */
drag(newLoc: Coordinate, e?: PointerEvent): void { drag(newLoc: Coordinate, e?: PointerEvent): void {
const prevLocation = this.getRelativeToSurfaceXY();
this.dragStrategy.drag(newLoc, e); this.dragStrategy.drag(newLoc, e);
const dragStrategy = this.dragStrategy as BlockDragStrategy; const dragStrategy = this.dragStrategy as BlockDragStrategy;
const candidate = dragStrategy.connectionCandidate?.neighbour ?? null; const candidate = dragStrategy.connectionCandidate?.neighbour ?? null;
this.currentConnectionCandidate = candidate; this.currentConnectionCandidate = candidate;
this.announceDynamicAriaState(true, false, newLoc); this.announceDynamicAriaState(true, false, prevLocation, newLoc);
} }
/** Ends the drag on the block. */ /** Ends the drag on the block. */
endDrag(e?: PointerEvent): void { endDrag(e?: PointerEvent): void {
const location = this.getRelativeToSurfaceXY();
this.dragStrategy.endDrag(e); this.dragStrategy.endDrag(e);
this.currentConnectionCandidate = null; 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. */ /** Moves the block back to where it was at the start of a drag. */
revertDrag(): void { revertDrag(): void {
const location = this.getRelativeToSurfaceXY();
this.dragStrategy.revertDrag(); 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 isMoving Whether the specified block is currently being moved.
* @param isCanceled Whether the previous movement operation has been canceled. * @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). * @param newLoc The new location the block is moving to (if unconstrained).
*/ */
private announceDynamicAriaState( private announceDynamicAriaState(
isMoving: boolean, isMoving: boolean,
isCanceled: boolean, isCanceled: boolean,
prevLoc: Coordinate,
newLoc?: Coordinate, newLoc?: Coordinate,
) { ) {
if (isCanceled) { if (isCanceled) {
@@ -2057,11 +2064,99 @@ export class BlockSvg
aria.announceDynamicAriaState(announcementContext.join(' ')); aria.announceDynamicAriaState(announcementContext.join(' '));
} else if (newLoc) { } else if (newLoc) {
// The block is being freely dragged. // The block is being freely dragged.
aria.announceDynamicAriaState( const direction = this.diff(prevLoc, newLoc);
`Moving unconstrained to coordinate x ${Math.round(newLoc.x)} and y ${Math.round(newLoc.y)}.`, 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 { interface BlockSummary {