Skip to content

feat: Add more ephemeral overrides for drop-downs. #9086

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 26 additions & 8 deletions core/dropdowndiv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ export function createDom() {
}
div = document.createElement('div');
div.className = 'blocklyDropDownDiv';
div.tabIndex = -1;
const parentDiv = common.getParentContainer() || document.body;
parentDiv.appendChild(div);

Expand Down Expand Up @@ -192,17 +193,24 @@ export function setColour(backgroundColour: string, borderColour: string) {
* @param block Block to position the drop-down around.
* @param opt_onHide Optional callback for when the drop-down is hidden.
* @param opt_secondaryYOffset Optional Y offset for above-block positioning.
* @param manageEphemeralFocus Whether ephemeral focus should be managed
* according to the drop-down div's lifetime. Note that if a false value is
* passed in here then callers should manage ephemeral focus directly
* otherwise focus may not properly restore when the widget closes. Defaults
* to true.
* @returns True if the menu rendered below block; false if above.
*/
export function showPositionedByBlock<T>(
field: Field<T>,
block: BlockSvg,
opt_onHide?: () => void,
opt_secondaryYOffset?: number,
manageEphemeralFocus: boolean = true,
): boolean {
return showPositionedByRect(
getScaledBboxOfBlock(block),
field as Field,
manageEphemeralFocus,
opt_onHide,
opt_secondaryYOffset,
);
Expand All @@ -217,17 +225,24 @@ export function showPositionedByBlock<T>(
* @param field The field to position the dropdown against.
* @param opt_onHide Optional callback for when the drop-down is hidden.
* @param opt_secondaryYOffset Optional Y offset for above-block positioning.
* @param manageEphemeralFocus Whether ephemeral focus should be managed
* according to the drop-down div's lifetime. Note that if a false value is
* passed in here then callers should manage ephemeral focus directly
* otherwise focus may not properly restore when the widget closes. Defaults
* to true.
* @returns True if the menu rendered below block; false if above.
*/
export function showPositionedByField<T>(
field: Field<T>,
opt_onHide?: () => void,
opt_secondaryYOffset?: number,
manageEphemeralFocus: boolean = true,
): boolean {
positionToField = true;
return showPositionedByRect(
getScaledBboxOfField(field as Field),
field as Field,
manageEphemeralFocus,
opt_onHide,
opt_secondaryYOffset,
);
Expand Down Expand Up @@ -271,16 +286,15 @@ function getScaledBboxOfField(field: Field): Rect {
* @param manageEphemeralFocus Whether ephemeral focus should be managed
* according to the drop-down div's lifetime. Note that if a false value is
* passed in here then callers should manage ephemeral focus directly
* otherwise focus may not properly restore when the widget closes. Defaults
* to true.
* otherwise focus may not properly restore when the widget closes.
* @returns True if the menu rendered below block; false if above.
*/
function showPositionedByRect(
bBox: Rect,
field: Field,
manageEphemeralFocus: boolean,
opt_onHide?: () => void,
opt_secondaryYOffset?: number,
manageEphemeralFocus: boolean = true,
): boolean {
// If we can fit it, render below the block.
const primaryX = bBox.left + (bBox.right - bBox.left) / 2;
Expand Down Expand Up @@ -352,10 +366,6 @@ export function show<T>(
dom.addClass(div, renderedClassName);
dom.addClass(div, themeClassName);

if (manageEphemeralFocus) {
returnEphemeralFocus = getFocusManager().takeEphemeralFocus(div);
}

// When we change `translate` multiple times in close succession,
// Chrome may choose to wait and apply them all at once.
// Since we want the translation to initial X, Y to be immediate,
Expand All @@ -364,7 +374,15 @@ export function show<T>(
// making the dropdown appear to fly in from (0, 0).
// Using both `left`, `top` for the initial translation and then `translate`
// for the animated transition to final X, Y is a workaround.
return positionInternal(primaryX, primaryY, secondaryX, secondaryY);
const atOrigin = positionInternal(primaryX, primaryY, secondaryX, secondaryY);

// Ephemeral focus must happen after the div is fully visible in order to
// ensure that it properly receives focus.
if (manageEphemeralFocus) {
returnEphemeralFocus = getFocusManager().takeEphemeralFocus(div);
}

return atOrigin;
}

const internal = {
Expand Down
1 change: 1 addition & 0 deletions core/widgetdiv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export function createDom() {
} else {
containerDiv = document.createElement('div') as HTMLDivElement;
containerDiv.className = containerClassName;
containerDiv.tabIndex = -1;
}

container.appendChild(containerDiv!);
Expand Down
Loading