[cr147] Fixing eslint warnings on local variables in templates

Chromium changes:
https://chromium.googlesource.com/chromium/src/+/d3321f2d58bca7a6c085abb9103c14a9e66c9806

commit d3321f2d58bca7a6c085abb9103c14a9e66c9806
Author: rbpotter <rbpotter@chromium.org>
Date:   Fri Feb 13 13:46:50 2026 -0800

    WebUI: Add eslint rule to detect local variables in templates

    Per the WebUI Lit styleguide, local variables like const/let should not
    be used in Lit HTML template files.

    Adding eslint-disable for a few locations that are still in the
    process of being fixed, to facilitate landing this change sooner
    to prevent new violations being added.

    Bug: 481519338
    Change-Id: Ibff5abd171e864943f99a8d5598386e57c21fd29
    Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7564854
    Reviewed-by: Demetrios Papadopoulos <dpapad@chromium.org>
    Commit-Queue: Rebekah Potter <rbpotter@chromium.org>
    Cr-Commit-Position: refs/heads/main@{#1584889}
This commit is contained in:
Claudio DeSouza
2026-03-26 19:25:00 -04:00
committed by Max Karolinskiy
parent bdc2826eaf
commit 5eef3db3ed
10 changed files with 222 additions and 206 deletions
@@ -3,107 +3,13 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
import '//resources/cr_components/localized_link/localized_link.js'
import { html } from '//resources/lit/v3_0/lit.rollup.js'
import { html, nothing } from '//resources/lit/v3_0/lit.rollup.js'
import { AccountStateFieldTags, whichAccountState } from '../brave_account_row.mojom-webui.js'
import { BraveAccountSettingsStrings } from '../brave_components_webui_strings.js'
import { SettingsBraveAccountRow } from './brave_account_row.js'
const createFirstRow = (
title: string,
descriptions: (string | ReturnType<typeof html>)[],
button?: ReturnType<typeof html>
) => {
return html`
<div class="first-row">
<div class="circle">
<leo-icon name="social-brave-release-favicon-fullheight-color">
</leo-icon>
</div>
<div class="title-and-description">
<div class="title">${title}</div>
${descriptions.map(
desc => html`<div class="description">${desc}</div>`)}
</div>
${button || nothing}
</div>
`
}
export function getHtml(this: SettingsBraveAccountRow) {
const stateHtml: Record<
AccountStateFieldTags,
() => ReturnType<typeof html>
> = {
[AccountStateFieldTags.LOGGED_IN]: () => createFirstRow(
this.i18n(
BraveAccountSettingsStrings
.BRAVE_ACCOUNT_TITLE),
[html`<div id="email">${this.state!.loggedIn!.email}</div>`],
html`
<leo-button kind="outline"
size="small"
@click=${this.onLogOutButtonClicked}>
${this.i18n(
BraveAccountSettingsStrings
.SETTINGS_BRAVE_ACCOUNT_LOG_OUT_BUTTON_LABEL)}
</leo-button>
`
),
[AccountStateFieldTags.VERIFICATION]: () => html`
${createFirstRow(
this.i18n(
BraveAccountSettingsStrings
.SETTINGS_BRAVE_ACCOUNT_VERIFICATION_ROW_TITLE),
[
this.i18n(
BraveAccountSettingsStrings
.SETTINGS_BRAVE_ACCOUNT_VERIFICATION_ROW_DESCRIPTION_1),
html`<localized-link
.localizedString=${this.i18nAdvanced(
BraveAccountSettingsStrings
.SETTINGS_BRAVE_ACCOUNT_VERIFICATION_ROW_DESCRIPTION_2,
{tags: ['a'], attrs: ['href']})}
@link-clicked=${this.onResendConfirmationEmailLinkClicked}>
</localized-link>`
]
)}
<div class="second-row">
<leo-button kind="plain-faint"
size="small"
class="cancel-registration-button"
@click=${this.onCancelRegistrationButtonClicked}>
${this.i18n(
BraveAccountSettingsStrings
.SETTINGS_BRAVE_ACCOUNT_CANCEL_REGISTRATION_BUTTON_LABEL)}
</leo-button>
</div>
`,
[AccountStateFieldTags.LOGGED_OUT]: () => createFirstRow(
this.i18n(
BraveAccountSettingsStrings
.SETTINGS_BRAVE_ACCOUNT_LOGGED_OUT_ROW_TITLE),
[this.i18n(
BraveAccountSettingsStrings
.BRAVE_ACCOUNT_DESCRIPTION)],
html`
<leo-button kind="filled"
size="small"
@click=${this.onGetStartedButtonClicked}>
${this.i18n(
BraveAccountSettingsStrings
.SETTINGS_BRAVE_ACCOUNT_GET_STARTED_BUTTON_LABEL)}
</leo-button>
`
),
}
return html`
<div class="row-container">
${this.state === undefined
? nothing
: stateHtml[whichAccountState(this.state)]()}
${this.getStateHtml()}
</div>`
}
@@ -3,7 +3,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
import '//resources/cr_components/localized_link/localized_link.js'
import { CrLitElement, PropertyValues } from '//resources/lit/v3_0/lit.rollup.js'
import { html, nothing } from '//resources/lit/v3_0/lit.rollup.js'
import { I18nMixinLit } from '//resources/cr_elements/i18n_mixin_lit.js'
// @ts-expect-error
import { leoShowAlert } from '//resources/brave/leo.bundle.js'
@@ -120,6 +122,100 @@ export class SettingsBraveAccountRow extends I18nMixinLit(CrLitElement) {
this.browserProxy.rowHandler.openDialog(this.initiatingServiceName)
}
protected createFirstRow(
title: string,
descriptions: (string | ReturnType<typeof html>)[],
button?: ReturnType<typeof html>
) {
return html`
<div class="first-row">
<div class="circle">
<leo-icon name="social-brave-release-favicon-fullheight-color">
</leo-icon>
</div>
<div class="title-and-description">
<div class="title">${title}</div>
${descriptions.map(
desc => html`<div class="description">${desc}</div>`)}
</div>
${button || nothing}
</div>
`
}
protected getStateHtml() {
const stateHtml: Record<
AccountStateFieldTags,
() => ReturnType<typeof html>
> = {
[AccountStateFieldTags.LOGGED_IN]: () => this.createFirstRow(
this.i18n(
BraveAccountSettingsStrings
.BRAVE_ACCOUNT_TITLE),
[html`<div id="email">${this.state!.loggedIn!.email}</div>`],
html`
<leo-button kind="outline"
size="small"
@click=${this.onLogOutButtonClicked}>
${this.i18n(
BraveAccountSettingsStrings
.SETTINGS_BRAVE_ACCOUNT_LOG_OUT_BUTTON_LABEL)}
</leo-button>
`
),
[AccountStateFieldTags.VERIFICATION]: () => html`
${this.createFirstRow(
this.i18n(
BraveAccountSettingsStrings
.SETTINGS_BRAVE_ACCOUNT_VERIFICATION_ROW_TITLE),
[
this.i18n(
BraveAccountSettingsStrings
.SETTINGS_BRAVE_ACCOUNT_VERIFICATION_ROW_DESCRIPTION_1),
html`<localized-link
.localizedString=${this.i18nAdvanced(
BraveAccountSettingsStrings
.SETTINGS_BRAVE_ACCOUNT_VERIFICATION_ROW_DESCRIPTION_2,
{tags: ['a'], attrs: ['href']})}
@link-clicked=${this.onResendConfirmationEmailLinkClicked}>
</localized-link>`
]
)}
<div class="second-row">
<leo-button kind="plain-faint"
size="small"
class="cancel-registration-button"
@click=${this.onCancelRegistrationButtonClicked}>
${this.i18n(
BraveAccountSettingsStrings
.SETTINGS_BRAVE_ACCOUNT_CANCEL_REGISTRATION_BUTTON_LABEL)}
</leo-button>
</div>
`,
[AccountStateFieldTags.LOGGED_OUT]: () => this.createFirstRow(
this.i18n(
BraveAccountSettingsStrings
.SETTINGS_BRAVE_ACCOUNT_LOGGED_OUT_ROW_TITLE),
[this.i18n(
BraveAccountSettingsStrings
.BRAVE_ACCOUNT_DESCRIPTION)],
html`
<leo-button kind="filled"
size="small"
@click=${this.onGetStartedButtonClicked}>
${this.i18n(
BraveAccountSettingsStrings
.SETTINGS_BRAVE_ACCOUNT_GET_STARTED_BUTTON_LABEL)}
</leo-button>
`
),
}
return this.state === undefined
? nothing
: stateHtml[whichAccountState(this.state)]()
}
private async loadInitialState() {
const { state } = await this.browserProxy.rowHandler.getAccountState()
this.state = state
@@ -3,7 +3,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
import { html, TemplateResult } from '//resources/lit/v3_0/lit.rollup.js'
import { html } from '//resources/lit/v3_0/lit.rollup.js'
import './brave_account_create_dialog.js'
import './brave_account_entry_dialog.js'
@@ -11,71 +11,12 @@ import './brave_account_error_dialog.js'
import './brave_account_forgot_password_dialog.js'
import './brave_account_otp_dialog.js'
import './brave_account_sign_in_dialog.js'
import { BraveAccountDialogs, Dialog } from './brave_account_dialogs.js'
import { Error } from './brave_account_common.js'
import { BraveAccountDialogsElement } from './brave_account_dialogs.js'
export function getHtml(this: BraveAccountDialogs) {
const dialogHtml: Record<Dialog['type'], () => TemplateResult> = {
ENTRY: () => html`
<brave-account-entry-dialog
@close-dialog=${this.onCloseDialog}
@create-button-clicked=${() => (this.dialog = { type: 'CREATE' })}
@logo-double-clicked=${() => (this.dialog = { type: 'OTP' })}
@sign-in-button-clicked=${() => (this.dialog = { type: 'SIGN_IN' })}
>
</brave-account-entry-dialog>
`,
CREATE: () => html`
<brave-account-create-dialog
.isCapsLockOn=${this.isCapsLockOn}
@back-button-clicked=${this.onBackButtonClicked}
@close-dialog=${this.onCloseDialog}
@error-occurred=${(e: CustomEvent<Error>) =>
(this.dialog = {
type: 'ERROR',
error: e.detail,
})}
>
</brave-account-create-dialog>
`,
SIGN_IN: () => html`
<brave-account-sign-in-dialog
.isCapsLockOn=${this.isCapsLockOn}
@back-button-clicked=${this.onBackButtonClicked}
@close-dialog=${this.onCloseDialog}
@error-occurred=${(e: CustomEvent<Error>) =>
(this.dialog = {
type: 'ERROR',
error: e.detail,
})}
@forgot-password-button-clicked=${() =>
(this.dialog = { type: 'FORGOT_PASSWORD' })}
>
</brave-account-sign-in-dialog>
`,
FORGOT_PASSWORD: () => html`
<brave-account-forgot-password-dialog
@back-button-clicked=${this.onBackButtonClicked}
@close-dialog=${this.onCloseDialog}
>
</brave-account-forgot-password-dialog>
`,
OTP: () => html`
<brave-account-otp-dialog
@back-button-clicked=${this.onBackButtonClicked}
@close-dialog=${this.onCloseDialog}
>
</brave-account-otp-dialog>
`,
ERROR: () => html`
<brave-account-error-dialog
@back-button-clicked=${this.onBackButtonClicked}
@close-dialog=${this.onCloseDialog}
.error=${(this.dialog as Extract<Dialog, { type: 'ERROR' }>).error}
>
</brave-account-error-dialog>
`,
}
return dialogHtml[this.dialog.type]()
export function getHtml(this: BraveAccountDialogsElement) {
// clang-format off
return html`
${this.getDialogHtml()}
`
// clang-format on
}
@@ -3,7 +3,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
import { CrLitElement } from '//resources/lit/v3_0/lit.rollup.js'
import { CrLitElement, html, TemplateResult } from '//resources/lit/v3_0/lit.rollup.js'
// <if expr="not is_android and not is_ios">
import { EventTracker } from '//resources/js/event_tracker.js'
import { hasKeyModifiers } from '//resources/js/util.js'
@@ -47,6 +47,76 @@ export class BraveAccountDialogs extends CrLitElement {
this.browserProxy.closeDialog()
}
protected getDialogHtml(): TemplateResult {
switch (this.dialog.type) {
case 'ENTRY':
return html`
<brave-account-entry-dialog
@close-dialog=${this.onCloseDialog}
@create-button-clicked=${() => (this.dialog = { type: 'CREATE' })}
@logo-double-clicked=${() => (this.dialog = { type: 'OTP' })}
@sign-in-button-clicked=${() => (this.dialog = { type: 'SIGN_IN' })}
>
</brave-account-entry-dialog>
`
case 'CREATE':
return html`
<brave-account-create-dialog
.isCapsLockOn=${this.isCapsLockOn}
@back-button-clicked=${this.onBackButtonClicked}
@close-dialog=${this.onCloseDialog}
@error-occurred=${(e: CustomEvent<Error>) =>
(this.dialog = {
type: 'ERROR',
error: e.detail,
})}
>
</brave-account-create-dialog>
`
case 'SIGN_IN':
return html`
<brave-account-sign-in-dialog
.isCapsLockOn=${this.isCapsLockOn}
@back-button-clicked=${this.onBackButtonClicked}
@close-dialog=${this.onCloseDialog}
@error-occurred=${(e: CustomEvent<Error>) =>
(this.dialog = {
type: 'ERROR',
error: e.detail,
})}
@forgot-password-button-clicked=${() =>
(this.dialog = { type: 'FORGOT_PASSWORD' })}
>
</brave-account-sign-in-dialog>
`
case 'FORGOT_PASSWORD':
return html`
<brave-account-forgot-password-dialog
@back-button-clicked=${this.onBackButtonClicked}
@close-dialog=${this.onCloseDialog}
>
</brave-account-forgot-password-dialog>
`
case 'OTP':
return html`
<brave-account-otp-dialog
@back-button-clicked=${this.onBackButtonClicked}
@close-dialog=${this.onCloseDialog}
>
</brave-account-otp-dialog>
`
case 'ERROR':
return html`
<brave-account-error-dialog
@back-button-clicked=${this.onBackButtonClicked}
@close-dialog=${this.onCloseDialog}
.error=${this.dialog.error}
>
</brave-account-error-dialog>
`
}
}
private browserProxy: BraveAccountBrowserProxy =
BraveAccountBrowserProxyImpl.getInstance()
@@ -5,16 +5,7 @@
import { html } from '//resources/lit/v3_0/lit.rollup.js'
import { BraveAccountEmailInputElement } from './brave_account_email_input.js'
// Maximum email address length according to this RFC3696 errata:
// https://www.rfc-editor.org/errata/eid1690.
// While maxlength is based on UTF-16 code units (where surrogate pairs count as
// 2 code units), type="email"'s built-in validation filters out non-ASCII
// characters, so maxlength="254" effectively means 254 ASCII characters/254
// bytes. Platform behaviors: desktop and iOS invalidate the value if non-ASCII
// is typed, while Android prevents typing non-ASCII entirely.
const MAX_EMAIL_LENGTH = 254
import { BraveAccountEmailInputElement, MAX_EMAIL_LENGTH } from './brave_account_email_input.js'
export function getHtml(this: BraveAccountEmailInputElement) {
return html`<!--_html_template_start_-->
@@ -8,6 +8,15 @@ import { CrLitElement } from '//resources/lit/v3_0/lit.rollup.js'
import { getCss } from './brave_account_email_input.css.js'
import { getHtml } from './brave_account_email_input.html.js'
// Maximum email address length according to this RFC3696 errata:
// https://www.rfc-editor.org/errata/eid1690.
// While maxlength is based on UTF-16 code units (where surrogate pairs count as
// 2 code units), type="email"'s built-in validation filters out non-ASCII
// characters, so maxlength="254" effectively means 254 ASCII characters/254
// bytes. Platform behaviors: desktop and iOS invalidate the value if non-ASCII
// is typed, while Android prevents typing non-ASCII entirely.
export const MAX_EMAIL_LENGTH = 254
export type EmailInputEventDetail = { email: string; isValid: boolean }
export class BraveAccountEmailInputElement extends CrLitElement {
@@ -16,31 +16,5 @@ import { BraveAccountOtpInputElement } from './brave_account_otp_input.js'
// beforeinput: deleteContentBackward
// beforeinput: insertText "…"
export function getHtml(this: BraveAccountOtpInputElement) {
const indices = [...Array(this.length).keys()]
return html`<!--_html_template_start_-->
<div class="label">$i18n{BRAVE_ACCOUNT_OTP_INPUT_LABEL}</div>
<div
class="otp-inputs"
@paste=${this.onPaste}
>
${indices.map(
(index) => html`
<leo-input
autofocus=${index === 0}
<if expr="is_ios">
spellcheck="false"
</if>
type="text"
@beforeinput=${(e: InputEvent) => this.onBeforeInput(e, index)}
@focus=${this.onFocus}
@input=${(detail: { value: string }) => this.onInput(detail, index)}
@keydown=${(detail: { innerEvent: KeyboardEvent }) =>
this.onKeyDown(detail, index)}
>
</leo-input>
`,
)}
</div>
<!--_html_template_end_-->`
return html` ${this.getElementHtml()} `
}
@@ -3,7 +3,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
import { CrLitElement } from '//resources/lit/v3_0/lit.rollup.js'
import { CrLitElement, html } from '//resources/lit/v3_0/lit.rollup.js'
import { getDeepActiveElement, hasKeyModifiers } from '//resources/js/util.js'
import { getCss } from './brave_account_otp_input.css.js'
@@ -137,6 +137,34 @@ export class BraveAccountOtpInputElement extends CrLitElement {
}
}
protected getElementHtml() {
const indices = [...Array(this.length).keys()]
return html` <div class="label">$i18n{BRAVE_ACCOUNT_OTP_INPUT_LABEL}</div>
<div
class="otp-inputs"
@paste=${this.onPaste}
>
${indices.map(
(index) => html`
<leo-input
autofocus=${index === 0}
// <if expr="is_ios">
spellcheck="false"
// </if>
type="text"
@beforeinput=${(e: InputEvent) => this.onBeforeInput(e, index)}
@focus=${this.onFocus}
@input=${(detail: { value: string }) => this.onInput(detail, index)}
@keydown=${(detail: { innerEvent: KeyboardEvent }) =>
this.onKeyDown(detail, index)}
>
</leo-input>
`,
)}
</div>`
}
private handleArrowKey(e: KeyboardEvent, index: number) {
const nextIndex =
e.key === 'ArrowLeft'
@@ -8,11 +8,8 @@ import { html, nothing } from '//resources/lit/v3_0/lit.rollup.js'
import { BraveAccountPasswordIconsElement } from './brave_account_password_icons.js'
export function getHtml(this: BraveAccountPasswordIconsElement) {
const showCapsLock =
this.isCapsLockOn && this.isInputFocused && !this.isPasswordVisible
return html`<!--_html_template_start_-->
${showCapsLock
${this.showCapsLock
? html`<leo-tooltip>
<div slot="content">$i18n{BRAVE_ACCOUNT_CAPS_LOCK_ON}</div>
<leo-icon name="caps-lock"></leo-icon>
@@ -40,6 +40,10 @@ export class BraveAccountPasswordIconsElement extends CrLitElement {
}
}
protected get showCapsLock(): boolean {
return this.isCapsLockOn && this.isInputFocused && !this.isPasswordVisible
}
protected onEyeIconClicked(event: Event) {
event.preventDefault()
const target = event.target as Element