diff --git a/ui/webui/resources/BUILD.gn b/ui/webui/resources/BUILD.gn index 3fc4c19b7d28ff..d81a788c868a6d 100644 --- a/ui/webui/resources/BUILD.gn +++ b/ui/webui/resources/BUILD.gn @@ -163,7 +163,6 @@ checked_in_dts_files = [ "cr_elements/cr_input/cr_input.m.d.ts", "cr_elements/cr_lazy_render/cr_lazy_render.m.d.ts", "cr_elements/cr_lottie/cr_lottie.m.d.ts", - "cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.d.ts", "cr_elements/cr_radio_button/cr_card_radio_button.m.d.ts", "cr_elements/cr_radio_button/cr_radio_button_behavior.m.d.ts", "cr_elements/cr_radio_button/cr_radio_button.m.d.ts", @@ -225,9 +224,7 @@ if (include_polymer) { "cr_elements/cr_actionable_row_style.m.js", "cr_elements/cr_icons_css.m.js", "cr_elements/cr_input/cr_input_style_css.m.js", - "cr_elements/cr_menu_selector/cr_menu_selector.js", "cr_elements/cr_page_host_style_css.js", - "cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector_grid.js", "cr_elements/cr_radio_button/cr_radio_button_style_css.m.js", "cr_elements/hidden_style_css.m.js", "cr_elements/icons.m.js", @@ -273,7 +270,10 @@ ts_library("library") { "cr_elements/cr_container_shadow_mixin.ts", "cr_elements/cr_drawer/cr_drawer.ts", "cr_elements/cr_link_row/cr_link_row.ts", + "cr_elements/cr_menu_selector/cr_menu_selector.ts", "cr_elements/cr_nav_menu_item_style.ts", + "cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector_grid.ts", + "cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.ts", "cr_elements/cr_slider/cr_slider.ts", "cr_elements/cr_splitter/cr_splitter.ts", "cr_elements/cr_tabs/cr_tabs.ts", diff --git a/ui/webui/resources/cr_elements/BUILD.gn b/ui/webui/resources/cr_elements/BUILD.gn index 5824affcf0fcfe..9ecf6dec81d9b9 100644 --- a/ui/webui/resources/cr_elements/BUILD.gn +++ b/ui/webui/resources/cr_elements/BUILD.gn @@ -161,10 +161,7 @@ preprocess_if_expr("preprocess_generated") { "cr_input/cr_input_style_css.m.js", "cr_lazy_render/cr_lazy_render.m.js", "cr_lottie/cr_lottie.m.js", - "cr_menu_selector/cr_menu_selector.js", "cr_page_host_style_css.js", - "cr_profile_avatar_selector/cr_profile_avatar_selector_grid.js", - "cr_profile_avatar_selector/cr_profile_avatar_selector.js", "cr_radio_button/cr_card_radio_button.m.js", "cr_radio_button/cr_radio_button_behavior.m.js", "cr_radio_button/cr_radio_button.m.js", @@ -211,7 +208,10 @@ preprocess_if_expr("preprocess_generated_ts") { "cr_drawer/cr_drawer.ts", "cr_grid/cr_grid.ts", "cr_link_row/cr_link_row.ts", + "cr_menu_selector/cr_menu_selector.ts", "cr_nav_menu_item_style.ts", + "cr_profile_avatar_selector/cr_profile_avatar_selector_grid.ts", + "cr_profile_avatar_selector/cr_profile_avatar_selector.ts", "cr_slider/cr_slider.ts", "cr_tabs/cr_tabs.ts", "cr_toast/cr_toast.ts", @@ -239,7 +239,6 @@ group("closure_compile") { "cr_icon_button:closure_compile", "cr_input:closure_compile", "cr_lottie:closure_compile", - "cr_menu_selector:closure_compile", "cr_radio_button:closure_compile", "cr_radio_group:closure_compile", "cr_toggle:closure_compile", @@ -256,7 +255,6 @@ group("closure_compile") { "cr_input:closure_compile_module", "cr_lazy_render:closure_compile_module", "cr_lottie:closure_compile_module", - "cr_profile_avatar_selector:closure_compile_module", "cr_radio_button:closure_compile_module", "cr_radio_group:closure_compile_module", "cr_search_field:closure_compile_module", diff --git a/ui/webui/resources/cr_elements/cr_menu_selector/BUILD.gn b/ui/webui/resources/cr_elements/cr_menu_selector/BUILD.gn index d1fc033f758774..bb16d2855786a7 100644 --- a/ui/webui/resources/cr_elements/cr_menu_selector/BUILD.gn +++ b/ui/webui/resources/cr_elements/cr_menu_selector/BUILD.gn @@ -2,21 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/html_to_js.gni") html_to_js("web_components") { - js_files = [ "cr_menu_selector.js" ] -} - -js_type_check("closure_compile") { - is_polymer3 = true - deps = [ ":cr_menu_selector" ] -} - -js_library("cr_menu_selector") { - deps = [ - "//ui/webui/resources/js:assert.m", - "//ui/webui/resources/js/cr/ui:focus_outline_manager.m", - ] + js_files = [ "cr_menu_selector.ts" ] } diff --git a/ui/webui/resources/cr_elements/cr_menu_selector/cr_menu_selector.js b/ui/webui/resources/cr_elements/cr_menu_selector/cr_menu_selector.ts similarity index 69% rename from ui/webui/resources/cr_elements/cr_menu_selector/cr_menu_selector.js rename to ui/webui/resources/cr_elements/cr_menu_selector/cr_menu_selector.ts index 2ae8e7ad320dcf..5a5fbadb5f55c9 100644 --- a/ui/webui/resources/cr_elements/cr_menu_selector/cr_menu_selector.js +++ b/ui/webui/resources/cr_elements/cr_menu_selector/cr_menu_selector.ts @@ -5,22 +5,18 @@ import {assert} from '../../js/assert.m.js'; import {FocusOutlineManager} from '../../js/cr/ui/focus_outline_manager.m.js'; -/** @extends {HTMLElement} */ export class CrMenuSelector extends HTMLElement { static get is() { return 'cr-menu-selector'; } + private focusOutlineManager_: FocusOutlineManager; + constructor() { super(); - /** @private {!FocusOutlineManager} */ - this.focusOutlineManager_; - - this.addEventListener( - 'focusin', e => this.onFocusin_(/** @type {!FocusEvent} */ (e))); - this.addEventListener( - 'keydown', e => this.onKeydown_(/** @type {!KeyboardEvent} */ (e))); + this.addEventListener('focusin', this.onFocusin_.bind(this)); + this.addEventListener('keydown', this.onKeydown_.bind(this)); } connectedCallback() { @@ -28,21 +24,12 @@ export class CrMenuSelector extends HTMLElement { this.setAttribute('role', 'menu'); } - /** - * @return {!Array} - * @private - */ - getItems_() { - return /** @type {!Array} */ ( - Array.from(this.querySelectorAll( - '[role=menuitem]:not([disabled]):not([hidden])'))); + private getItems_(): Array { + return Array.from( + this.querySelectorAll('[role=menuitem]:not([disabled]):not([hidden])')); } - /** - * @param {!FocusEvent} e - * @private - */ - onFocusin_(e) { + private onFocusin_(e: FocusEvent) { // If the focus was moved by keyboard and is coming in from a relatedTarget // that is not within this menu, move the focus to the first menu item. This // ensures that the first menu item is always the first focused item when @@ -50,21 +37,17 @@ export class CrMenuSelector extends HTMLElement { // from outside the WebContents. const focusMovedWithKeyboard = this.focusOutlineManager_.visible; const focusMovedFromOutside = e.relatedTarget === null || - !this.contains(/** @type {!HTMLElement} */ (e.relatedTarget)); + !this.contains(e.relatedTarget as HTMLElement); if (focusMovedWithKeyboard && focusMovedFromOutside) { - this.getItems_()[0].focus(); + this.getItems_()[0]!.focus(); } } - /** - * @param {!KeyboardEvent} event - * @private - */ - onKeydown_(event) { + private onKeydown_(event: KeyboardEvent) { const items = this.getItems_(); assert(items.length >= 1); - const currentFocusedIndex = items.indexOf( - /** @type {!HTMLElement} */ (this.querySelector(':focus'))); + const currentFocusedIndex = + items.indexOf(this.querySelector(':focus')!); let newFocusedIndex = currentFocusedIndex; switch (event.key) { @@ -73,12 +56,12 @@ export class CrMenuSelector extends HTMLElement { // If pressing Shift+Tab, immediately focus the first element so that // when the event is finished processing, the browser automatically // focuses the previous focusable element outside of the menu. - items[0].focus(); + items[0]!.focus(); } else { // If pressing Tab, immediately focus the last element so that when // the event is finished processing, the browser automatically focuses // the next focusable element outside of the menu. - items[items.length - 1].focus({preventScroll: true}); + items[items.length - 1]!.focus({preventScroll: true}); } return; case 'ArrowDown': @@ -101,7 +84,7 @@ export class CrMenuSelector extends HTMLElement { } event.preventDefault(); - items[newFocusedIndex].focus(); + items[newFocusedIndex]!.focus(); } } diff --git a/ui/webui/resources/cr_elements/cr_profile_avatar_selector/BUILD.gn b/ui/webui/resources/cr_elements/cr_profile_avatar_selector/BUILD.gn index 06230ed04cca66..9c398538705cd1 100644 --- a/ui/webui/resources/cr_elements/cr_profile_avatar_selector/BUILD.gn +++ b/ui/webui/resources/cr_elements/cr_profile_avatar_selector/BUILD.gn @@ -2,36 +2,11 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/html_to_js.gni") html_to_js("web_components") { js_files = [ - "cr_profile_avatar_selector_grid.js", - "cr_profile_avatar_selector.js", - ] -} - -js_type_check("closure_compile_module") { - is_polymer3 = true - deps = [ - ":cr_profile_avatar_selector", - ":cr_profile_avatar_selector_grid", - ] -} - -js_library("cr_profile_avatar_selector") { - deps = [ - ":cr_profile_avatar_selector_grid", - "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", - "//ui/webui/resources/js:icon", - ] -} - -js_library("cr_profile_avatar_selector_grid") { - deps = [ - "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", - "//ui/webui/resources/js:assert.m", - "//ui/webui/resources/js:util.m", + "cr_profile_avatar_selector_grid.ts", + "cr_profile_avatar_selector.ts", ] } diff --git a/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.d.ts b/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.d.ts deleted file mode 100644 index 232068de53c662..00000000000000 --- a/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.d.ts +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; - -export type AvatarIcon = { - url: string, - label: string, - index: number, - isGaiaAvatar: boolean, - selected: boolean, -}; - -interface CrProfileAvatarSelectorElement extends PolymerElement { - avatars: AvatarIcon[]; - selectedAvatar: AvatarIcon|null; - ignoreModifiedKeyEvents: boolean; -} - -export {CrProfileAvatarSelectorElement}; - -declare global { - interface HTMLElementTagNameMap { - 'cr-profile-avatar-selector': CrProfileAvatarSelectorElement; - } -} diff --git a/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.js b/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.ts similarity index 67% rename from ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.js rename to ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.ts index 2ccd460300636f..6c2715bee6415c 100644 --- a/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.js +++ b/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.ts @@ -14,20 +14,18 @@ import '//resources/polymer/v3_0/paper-styles/color.js'; import '//resources/polymer/v3_0/paper-tooltip/paper-tooltip.js'; import './cr_profile_avatar_selector_grid.js'; -import {html, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {DomRepeatEvent, html, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getImage} from '../../js/icon.js'; -/** - * @typedef {{url: string, - * label: string, - * index: (number), - * isGaiaAvatar: (boolean), - * selected: (boolean)}} - */ -export let AvatarIcon; +export type AvatarIcon = { + url: string, + label: string, + index: number, + isGaiaAvatar: boolean, + selected: boolean, +}; -/** @polymer */ export class CrProfileAvatarSelectorElement extends PolymerElement { static get is() { return 'cr-profile-avatar-selector'; @@ -41,7 +39,6 @@ export class CrProfileAvatarSelectorElement extends PolymerElement { return { /** * The list of profile avatar URLs and labels. - * @type {!Array} */ avatars: { type: Array, @@ -52,7 +49,6 @@ export class CrProfileAvatarSelectorElement extends PolymerElement { /** * The currently selected profile avatar icon, if any. - * @type {?AvatarIcon} */ selectedAvatar: { type: Object, @@ -67,7 +63,6 @@ export class CrProfileAvatarSelectorElement extends PolymerElement { /** * The currently selected profile avatar icon index, or '-1' if none is * selected. - * @type {number} */ tabFocusableAvatar_: { type: Number, @@ -76,22 +71,16 @@ export class CrProfileAvatarSelectorElement extends PolymerElement { }; } - /** - * @param {number} index - * @return {string} - * @private - */ - getAvatarId_(index) { + avatars: AvatarIcon[]; + selectedAvatar: AvatarIcon|null; + ignoreModifiedKeyEvents: boolean; + private tabFocusableAvatar_: number; + + private getAvatarId_(index: number): string { return 'avatarId' + index; } - /** - * @param {number} index - * @param {!AvatarIcon} item - * @return {string} - * @private - */ - getTabIndex_(index, item) { + private getTabIndex_(index: number, item: AvatarIcon): string { if (item.index === this.tabFocusableAvatar_) { return '0'; } @@ -103,38 +92,23 @@ export class CrProfileAvatarSelectorElement extends PolymerElement { return '-1'; } - /** - * @return {number} - * @private - */ - computeTabFocusableAvatar_() { + private computeTabFocusableAvatar_(): number { const selectedAvatar = this.avatars.find(avatar => this.isAvatarSelected(avatar)); return selectedAvatar ? selectedAvatar.index : -1; } - /** @private */ - getSelectedClass_(avatarItem) { + private getSelectedClass_(avatarItem: AvatarIcon): string { // TODO(dpapad): Rename 'iron-selected' to 'selected' now that this CSS // class is not assigned by any iron-* behavior. return this.isAvatarSelected(avatarItem) ? 'iron-selected' : ''; } - /** - * @param {AvatarIcon} avatarItem - * @return {string} - * @private - */ - getCheckedAttribute_(avatarItem) { + private getCheckedAttribute_(avatarItem: AvatarIcon): string { return this.isAvatarSelected(avatarItem) ? 'true' : 'false'; } - /** - * @param {AvatarIcon} avatarItem - * @return {boolean} - * @private - */ - isAvatarSelected(avatarItem) { + private isAvatarSelected(avatarItem: AvatarIcon): boolean { return !!avatarItem && (avatarItem.selected || (!!this.selectedAvatar && @@ -142,23 +116,22 @@ export class CrProfileAvatarSelectorElement extends PolymerElement { } /** - * @param {string} iconUrl - * @return {string} A CSS image-set for multiple scale factors. - * @private + * @return A CSS image-set for multiple scale factors. */ - getIconImageSet_(iconUrl) { + private getIconImageSet_(iconUrl: string): string { return getImage(iconUrl); } - /** - * @param {!Event} e - * @private - */ - onAvatarTap_(e) { + private onAvatarTap_(e: DomRepeatEvent) { // |selectedAvatar| is set to pass back selection to the owner of this // component. - this.selectedAvatar = - /** @type {!{model: {item: !AvatarIcon}}} */ (e).model.item; + this.selectedAvatar = e.model.item; + } +} + +declare global { + interface HTMLElementTagNameMap { + 'cr-profile-avatar-selector': CrProfileAvatarSelectorElement; } } diff --git a/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector_grid.js b/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector_grid.ts similarity index 81% rename from ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector_grid.js rename to ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector_grid.ts index a1f1eb7ef209ee..ed2afc674dcea2 100644 --- a/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector_grid.js +++ b/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector_grid.ts @@ -12,7 +12,6 @@ import {html, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bun import {assert} from '../../js/assert.m.js'; import {hasKeyModifiers} from '../../js/util.m.js'; -/** @polymer */ export class CrProfileAvatarSelectorGridElement extends PolymerElement { static get is() { return 'cr-profile-avatar-selector-grid'; @@ -31,19 +30,15 @@ export class CrProfileAvatarSelectorGridElement extends PolymerElement { }; } - /** @override */ - ready() { + ignoreModifiedKeyEvents: boolean; + + override ready() { super.ready(); - this.addEventListener( - 'keydown', e => this.onKeyDown_(/** @type {!KeyboardEvent} */ (e))); + this.addEventListener('keydown', this.onKeyDown_.bind(this)); } - /** - * @param {!KeyboardEvent} e - * @private - */ - onKeyDown_(e) { - const items = this.querySelectorAll('.avatar'); + private onKeyDown_(e: KeyboardEvent) { + const items = this.querySelectorAll('.avatar'); switch (e.key) { case 'ArrowDown': case 'ArrowUp': @@ -66,12 +61,10 @@ export class CrProfileAvatarSelectorGridElement extends PolymerElement { /** * Moves focus up/down/left/right according to the given direction. Wraps * around as necessary. - * @param {!NodeList} items - * @param {string} direction Must be on of 'ArrowLeft', 'ArrowRight', - * 'ArrowUp', 'ArrowDown'. - * @private */ - moveFocusRow_(items, direction) { + private moveFocusRow_( + items: NodeListOf, + direction: 'ArrowDown'|'ArrowRight'|'ArrowUp'|'ArrowLeft') { let offset = (direction === 'ArrowDown' || direction === 'ArrowRight') ? 1 : -1; const style = getComputedStyle(this); @@ -83,7 +76,7 @@ export class CrProfileAvatarSelectorGridElement extends PolymerElement { const gridSize = rows * rowSize; const focusIndex = Array.prototype.slice.call(items).findIndex(item => { - return this.parentNode.activeElement === item; + return (this.parentNode as ShadowRoot).activeElement === item; }); let nextItem = null; @@ -108,8 +101,14 @@ export class CrProfileAvatarSelectorGridElement extends PolymerElement { nextItem = items[nextIndex]; } - nextItem.focus(); - assert(this.parentNode.activeElement === nextItem); + nextItem!.focus(); + assert((this.parentNode as ShadowRoot).activeElement === nextItem); + } +} + +declare global { + interface HTMLElementTagNameMap { + 'cr-profile-avatar-selector-grid': CrProfileAvatarSelectorGridElement; } }