diff --git a/extensions/schema-compare/src/dialogs/schemaCompareDialog.ts b/extensions/schema-compare/src/dialogs/schemaCompareDialog.ts index 1eb53cbeac..ee6284f8f1 100644 --- a/extensions/schema-compare/src/dialogs/schemaCompareDialog.ts +++ b/extensions/schema-compare/src/dialogs/schemaCompareDialog.ts @@ -376,9 +376,11 @@ export class SchemaCompareDialog { // if source is currently a db, show it in the server and db dropdowns if (this.schemaCompareResult.sourceEndpointInfo && this.schemaCompareResult.sourceEndpointInfo.endpointType === mssql.SchemaCompareEndpointType.Database) { databaseRadioButton.checked = true; + databaseRadioButton.focused = true; this.sourceIsDacpac = false; } else { dacpacRadioButton.checked = true; + dacpacRadioButton.focused = true; this.sourceIsDacpac = true; } let flexRadioButtonsModel = view.modelBuilder.flexContainer() diff --git a/src/sql/azdata.d.ts b/src/sql/azdata.d.ts index 70e587507f..4125524979 100644 --- a/src/sql/azdata.d.ts +++ b/src/sql/azdata.d.ts @@ -2970,6 +2970,7 @@ declare module 'azdata' { label?: string; value?: string; checked?: boolean; + focused?: boolean; } export interface TextComponentProperties { diff --git a/src/sql/base/browser/ui/radioButton/radioButton.ts b/src/sql/base/browser/ui/radioButton/radioButton.ts index 818649cb28..7c4ef75980 100644 --- a/src/sql/base/browser/ui/radioButton/radioButton.ts +++ b/src/sql/base/browser/ui/radioButton/radioButton.ts @@ -84,4 +84,11 @@ export class RadioButton extends Widget { this.inputElement.setAttribute('aria-label', val); } + public focus(): void { + this.inputElement.focus(); + } + + public blur(): void { + this.inputElement.blur(); + } } diff --git a/src/sql/platform/dialog/browser/dialogPane.ts b/src/sql/platform/dialog/browser/dialogPane.ts index 2e8c28a1c3..f0cbee8cee 100644 --- a/src/sql/platform/dialog/browser/dialogPane.ts +++ b/src/sql/platform/dialog/browser/dialogPane.ts @@ -130,14 +130,22 @@ export class DialogPane extends Disposable implements IThemable { }); } - public show(): void { + public show(focus: boolean = false): void { this._body.classList.remove('dialogModal-hidden'); + if (focus) { + this.focus(); + } } public hide(): void { this._body.classList.add('dialogModal-hidden'); } + private focus(): void { + let focusedElement = this._body.querySelector('a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled])'); + focusedElement ? focusedElement.focus() : this._body.focus(); + } + /** * Called by the theme registry on theme change to style the component */ diff --git a/src/sql/platform/dialog/browser/wizardModal.ts b/src/sql/platform/dialog/browser/wizardModal.ts index dd47cd7695..e0476341e0 100644 --- a/src/sql/platform/dialog/browser/wizardModal.ts +++ b/src/sql/platform/dialog/browser/wizardModal.ts @@ -82,7 +82,7 @@ export class WizardModal extends Modal { } this._previousButton = this.addDialogButton(this._wizard.backButton, () => this.showPage(this._wizard.currentPage - 1)); - this._nextButton = this.addDialogButton(this._wizard.nextButton, () => this.showPage(this._wizard.currentPage + 1), true, true); + this._nextButton = this.addDialogButton(this._wizard.nextButton, () => this.showPage(this._wizard.currentPage + 1, true, true), true, true); this._generateScriptButton = this.addDialogButton(this._wizard.generateScriptButton, () => undefined); this._doneButton = this.addDialogButton(this._wizard.doneButton, () => this.done(), false, true); this._wizard.doneButton.registerClickEvent(this._onDone.event); @@ -164,7 +164,7 @@ export class WizardModal extends Modal { page.onUpdate(() => this.setButtonsForPage(this._wizard.currentPage)); } - private async showPage(index: number, validate: boolean = true): Promise { + private async showPage(index: number, validate: boolean = true, focus: boolean = false): Promise { let pageToShow = this._wizard.pages[index]; if (!pageToShow) { this.done(validate); @@ -175,7 +175,7 @@ export class WizardModal extends Modal { } this._dialogPanes.forEach((dialogPane, page) => { if (page === pageToShow) { - dialogPane.show(); + dialogPane.show(focus); } else { dialogPane.hide(); } @@ -227,14 +227,14 @@ export class WizardModal extends Modal { 'wizard-navigation', { wizard: this._wizard, - navigationHandler: (index: number) => this.showPage(index, index > this._wizard.currentPage) + navigationHandler: (index: number) => this.showPage(index, index > this._wizard.currentPage, true) }, undefined, () => undefined); } public open(): void { - this.showPage(0, false); + this.showPage(0, false, true); this.show(); } @@ -292,7 +292,7 @@ export class WizardModal extends Modal { this.done(); } else { if (this._nextButton.enabled) { - this.showPage(this._wizard.currentPage + 1); + this.showPage(this._wizard.currentPage + 1, true, true); } } } diff --git a/src/sql/workbench/api/common/extHostModelView.ts b/src/sql/workbench/api/common/extHostModelView.ts index b150632db4..a49ff4a3a3 100644 --- a/src/sql/workbench/api/common/extHostModelView.ts +++ b/src/sql/workbench/api/common/extHostModelView.ts @@ -1066,6 +1066,12 @@ class RadioButtonWrapper extends ComponentWrapper implements azdata.RadioButtonC public set checked(v: boolean) { this.setProperty('checked', v); } + public get focused(): boolean { + return this.properties['focused']; + } + public set focused(v: boolean) { + this.setProperty('focused', v); + } public get onDidClick(): vscode.Event { let emitter = this._emitterMap.get(ComponentEventType.onDidClick); diff --git a/src/sql/workbench/browser/modelComponents/radioButton.component.ts b/src/sql/workbench/browser/modelComponents/radioButton.component.ts index 4ba35e49a0..a70b42fa93 100644 --- a/src/sql/workbench/browser/modelComponents/radioButton.component.ts +++ b/src/sql/workbench/browser/modelComponents/radioButton.component.ts @@ -74,8 +74,8 @@ export default class RadioButtonComponent extends ComponentBase implements IComp this._input.value = this.value; this._input.label = this.label; this._input.enabled = this.enabled; - this._input.checked = this.checked; + this.focused ? this._input.focus() : this._input.blur(); } // CSS-bound properties @@ -115,4 +115,12 @@ export default class RadioButtonComponent extends ComponentBase implements IComp public set name(newValue: string) { this.setPropertyFromUI((properties, label) => { properties.name = label; }, newValue); } + + public get focused(): boolean { + return this.getPropertyOrDefault((props) => props.focused, false); + } + + public set focused(newValue: boolean) { + this.setPropertyFromUI((properties, value) => { properties.focused = value; }, newValue); + } }