Skip to content

Commit 32ee0f8

Browse files
Sho MizoeChromium LUCI CQ
authored andcommitted
[realbox][ntp] Apply the scrim when the input box is focused
This CL updates the logic so that the scrim is applied when the input box of Realbox or Composebox is focused. Screencast: Realbox Next Enabled: https://screencast.googleplex.com/cast/NDk1MDA2NjYwMjE4MDYwOHxhOTdiZTBlMS05NQ Realbox Next Disabled: https://screencast.googleplex.com/cast/NTY0NTA0NTcyOTMyOTE1Mnw3ODJkY2IyNi1hMw Fixed: b:452691308 Change-Id: I8e0818a900953372869c678ef92db39f62afc7bf Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7049856 Reviewed-by: Hannah Collins <[email protected]> Commit-Queue: Sho Mizoe <[email protected]> Reviewed-by: Roman Arora <[email protected]> Cr-Commit-Position: refs/heads/main@{#1532370}
1 parent 0215844 commit 32ee0f8

File tree

7 files changed

+108
-145
lines changed

7 files changed

+108
-145
lines changed

chrome/browser/resources/new_tab_page/app.css

Lines changed: 3 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ cr-most-visited {
105105
z-index: 1000;
106106
}
107107

108-
/* When a dropdown menu is opened, scrim is applied and OGB is behind it. */
109-
:host([dropdown-is-visible_]) #oneGoogleBarStackingContext {
108+
/* When scrim is applied, OGB must be behind it. */
109+
:host([show-scrim_]) #oneGoogleBarStackingContext {
110110
z-index: 0;
111111
}
112112

@@ -154,7 +154,7 @@ cr-most-visited {
154154
}
155155

156156
:host([show-composebox_]) #logo,
157-
:host([ntp-realbox-next-enabled_][dropdown-is-visible_]) #logo{
157+
:host([ntp-realbox-next-enabled_][show-scrim_]) #logo {
158158
z-index: 2;
159159
}
160160

@@ -318,32 +318,6 @@ ntp-lens-upload-dialog {
318318
z-index: 1;
319319
}
320320

321-
/**
322-
* When NTP Realbox Next is enabled, we want to ensure the following behavior
323-
* way for Composebox:
324-
* - when the dropdown is shown, clicking on any part of the half-opaque scrim
325-
* covering the whole viewport exits Composebox.
326-
* - when the dropdown is not shown, clicking on (virtually) anywhere exits
327-
* Composebox.
328-
*
329-
* An additional (natural) constraint in the latter is that when a click is on
330-
* an element triggering an action (e.g., MV tiles), its on-click behavior
331-
* should be triggered.
332-
* To achieve the latter behavior, the elements are placed at the following
333-
* z-index:
334-
* - transparent scrim: 0
335-
* - OGB: -1
336-
* - everything else: 1+
337-
*
338-
* With this, clicking on any interactive element, except OGB, shows the
339-
* element's on-click behavior, while clicking on the other parts removes the
340-
* scrim layer.
341-
*/
342-
:host([ntp-realbox-next-enabled_][show-composebox_]:not([dropdown-is-visible_])) #scrim {
343-
z-index: 0;
344-
opacity: 0;
345-
}
346-
347321
#webstoreToast {
348322
padding: 16px;
349323
}

chrome/browser/resources/new_tab_page/app.html

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,10 @@
3434
<ntp-logo id="logo" ?single-colored="${this.singleColoredLogo_}"
3535
.theme="${this.theme_}" ?hidden="${!this.logoEnabled_}">
3636
</ntp-logo>
37-
${this.ntpRealboxNextEnabled_ && (this.dropdownIsVisible_ || this.showComposebox_) ? html`
37+
${this.ntpRealboxNextEnabled_ ? html`
3838
<div id="scrim"
39-
@click="${this.showComposebox_ && this.composeboxCloseByClickOutside_ ? this.onComposeboxClickOutside_ : nothing}"></div>
39+
@click="${this.showComposebox_ && this.composeboxCloseByClickOutside_ ? this.onComposeboxClickOutside_ : nothing}"
40+
?hidden="${!this.showScrim_}"></div>
4041
` : ''}
4142
<div id="searchboxContainer">
4243
<cr-searchbox id="searchbox" ?is-dark="${this.isThemeDark_()}"
@@ -53,14 +54,16 @@
5354
realbox-layout-mode="${this.realboxLayoutMode_}"
5455
?ntp-realbox-next-enabled="${this.ntpRealboxNextEnabled_}"
5556
?cycling-placeholders="${this.searchboxCyclingPlaceholders_}"
56-
@dropdown-visible-changed="${this.onDropdownVisibleChanged_}">
57+
@dropdown-visible-changed="${this.onDropdownVisibleChanged_}"
58+
@searchbox-input-focus-changed="${this.onInputFocusChanged_}">
5759
</cr-searchbox>
5860
${this.showComposebox_ ? html`
5961
<ntp-composebox id="composebox" ?is_collapsible="false"
6062
?ntp-realbox-next-enabled="${this.ntpRealboxNextEnabled_}"
6163
@composebox-initialized="${this.onComposeboxInitialized_}"
6264
@close-composebox="${this.closeComposebox_}"
6365
@composebox-dropdown-visible-changed="${this.onDropdownVisibleChanged_}"
66+
@composebox-input-focus-changed="${this.onInputFocusChanged_}"
6467
realbox-layout-mode="${this.realboxLayoutMode_}">
6568
</ntp-composebox>
6669
` : ''}

chrome/browser/resources/new_tab_page/app.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,13 @@ export class AppElement extends AppElementBase {
303303
ntpNextFeaturesEnabled_: {type: Boolean},
304304

305305
dropdownIsVisible_: {type: Boolean, reflect: true},
306+
307+
searchboxInputFocused_: {type: Boolean},
308+
composeboxInputFocused_: {type: Boolean},
309+
/**
310+
* Whether the scrim is shown in Realbox Next.
311+
*/
312+
showScrim_: {type: Boolean, reflect: true},
306313
};
307314
}
308315

@@ -377,6 +384,9 @@ export class AppElement extends AppElementBase {
377384
protected accessor ntpNextFeaturesEnabled_: boolean =
378385
loadTimeData.getBoolean('ntpNextFeaturesEnabled');
379386
protected accessor dropdownIsVisible_: boolean = false;
387+
protected accessor searchboxInputFocused_: boolean = false;
388+
protected accessor composeboxInputFocused_: boolean = false;
389+
protected accessor showScrim_: boolean = false;
380390

381391
private callbackRouter_: PageCallbackRouter;
382392
private pageHandler_: PageHandlerRemote;
@@ -627,6 +637,38 @@ export class AppElement extends AppElementBase {
627637
ModuleLoadStatus.MODULE_LOAD_IN_PROGRESS)) {
628638
this.recordBrowserPromoMetrics_();
629639
}
640+
641+
if (this.ntpRealboxNextEnabled_ && [
642+
'showComposebox_',
643+
'searchboxInputFocused_',
644+
'composeboxInputFocused_',
645+
].some((prop) => changedPrivateProperties.has(prop))) {
646+
/**
647+
* The current requirement is that the scrim should be shown when the
648+
* focus is placed on one of the input boxes and should be removed when
649+
* the focus moves outside.
650+
*
651+
* The additional OR operation with showComposebox_ is because the logic
652+
* does not close Composebox when a click outside is made while Composebox
653+
* is opened. What seems to be happening when showComposebox_ is used/not
654+
* used are as follows:
655+
* - Without it:
656+
* 1. A click outside is made.
657+
* 2. The focusout event first occurs.
658+
* 3. composeboxInputFocused_ is set to false.
659+
* 4. The scrim is removed.
660+
* 5. The click event fires.
661+
* 6. Since there is no scrim, the onclick handle of the scrim is not
662+
* called.
663+
* - With it:
664+
* 1-3. same as above
665+
* 4. The scrim is kept since showComposebox_ is still true.
666+
* 5. The onclick handler of the scrim runs and sets showComposebox_ to
667+
* false, and everything works as desired.
668+
*/
669+
this.showScrim_ = this.showComposebox_ || this.searchboxInputFocused_ ||
670+
this.composeboxInputFocused_;
671+
}
630672
}
631673

632674
override updated(changedProperties: PropertyValues<this>) {
@@ -1231,6 +1273,17 @@ export class AppElement extends AppElementBase {
12311273
this.dropdownIsVisible_ = e.detail.value;
12321274
}
12331275

1276+
protected onInputFocusChanged_(e: CustomEvent<{value: boolean}>) {
1277+
switch (e.type) {
1278+
case 'searchbox-input-focus-changed':
1279+
this.searchboxInputFocused_ = e.detail.value;
1280+
break;
1281+
case 'composebox-input-focus-changed':
1282+
this.composeboxInputFocused_ = e.detail.value;
1283+
break;
1284+
}
1285+
}
1286+
12341287
protected onRealboxHadSecondarySideChanged_(
12351288
e: CustomEvent<{value: boolean}>) {
12361289
this.realboxHadSecondarySide = e.detail.value;

chrome/test/data/webui/new_tab_page/app_test.ts

Lines changed: 23 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
1919
import {isMac} from 'chrome://resources/js/platform.js';
2020
import {PromiseResolver} from 'chrome://resources/js/promise_resolver.js';
2121
import {PageCallbackRouter as SearchboxPageCallbackRouter, PageHandlerRemote as SearchboxPageHandlerRemote} from 'chrome://resources/mojo/components/omnibox/browser/searchbox.mojom-webui.js';
22-
import type {AutocompleteMatch, AutocompleteResult} from 'chrome://resources/mojo/components/omnibox/browser/searchbox.mojom-webui.js';
2322
import {assertDeepEquals, assertEquals, assertFalse, assertNotEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
2423
import type {MetricsTracker} from 'chrome://webui-test/metrics_test_support.js';
2524
import {fakeMetricsPrivate} from 'chrome://webui-test/metrics_test_support.js';
@@ -119,65 +118,6 @@ suite('NewTabPageAppTest', () => {
119118
'#composeButton');
120119
}
121120

122-
function createAutocompleteMatch(): AutocompleteMatch {
123-
return {
124-
a11yLabel: '',
125-
actions: [],
126-
allowedToBeDefaultMatch: false,
127-
isSearchType: false,
128-
isEnterpriseSearchAggregatorPeopleType: false,
129-
swapContentsAndDescription: false,
130-
supportsDeletion: false,
131-
suggestionGroupId: -1, // Indicates a missing suggestion group Id.
132-
contents: '',
133-
contentsClass: [{offset: 0, style: 0}],
134-
description: '',
135-
descriptionClass: [{offset: 0, style: 0}],
136-
destinationUrl: {url: ''},
137-
inlineAutocompletion: '',
138-
fillIntoEdit: '',
139-
iconPath: '',
140-
iconUrl: {url: ''},
141-
imageDominantColor: '',
142-
imageUrl: '',
143-
isNoncannedAimSuggestion: false,
144-
removeButtonA11yLabel: '',
145-
type: '',
146-
isRichSuggestion: false,
147-
isWeatherAnswerSuggestion: null,
148-
answer: null,
149-
tailSuggestCommonPrefix: null,
150-
hasInstantKeyword: false,
151-
keywordChipHint: '',
152-
keywordChipA11y: '',
153-
};
154-
}
155-
156-
function createAutocompleteResult(
157-
modifiers: Partial<AutocompleteResult> = {}): AutocompleteResult {
158-
const base: AutocompleteResult = {
159-
input: '',
160-
matches: [],
161-
suggestionGroupsMap: {},
162-
smartComposeInlineHint: null,
163-
};
164-
165-
return Object.assign(base, modifiers);
166-
}
167-
168-
function createSearchMatch(modifiers: Partial<AutocompleteMatch> = {}):
169-
AutocompleteMatch {
170-
return Object.assign(
171-
createAutocompleteMatch(), {
172-
isSearchType: true,
173-
contents: 'hello world',
174-
destinationUrl: {url: 'https://www.google.com/search?q=hello+world'},
175-
fillIntoEdit: 'hello world',
176-
type: 'search-suggest',
177-
},
178-
modifiers);
179-
}
180-
181121
function getScrim(): HTMLElement|null {
182122
return app.shadowRoot.querySelector<HTMLElement>('#scrim');
183123
}
@@ -1920,45 +1860,30 @@ suite('NewTabPageAppTest', () => {
19201860
});
19211861
});
19221862
test(
1923-
'A scrim is applied when the dropdown is shown in searchbox',
1924-
async () => {
1925-
assertFalse(!!getScrim());
1863+
'A scrim is applied when the focus is on searchbox input', async () => {
1864+
const scrim = getScrim();
1865+
assertTrue(!!scrim);
1866+
assertTrue(scrim.hidden);
19261867
const realbox_input =
19271868
$$<SearchboxElement>(app, '#searchbox')!.$.input;
1928-
realbox_input.value = 'he';
1929-
realbox_input.dispatchEvent(new InputEvent('input'));
1869+
realbox_input.dispatchEvent(new FocusEvent('focus'));
19301870
await microtasksFinished();
1931-
const matches = [createSearchMatch()];
1932-
SearchboxBrowserProxy.getInstance()
1933-
.callbackRouter.$.bindNewPipeAndPassRemote()
1934-
.autocompleteResultChanged(createAutocompleteResult({
1935-
input: realbox_input.value.trimStart(),
1936-
matches: matches,
1937-
}));
1938-
await microtasksFinished();
1939-
const scrim = getScrim();
1940-
assertTrue(!!scrim);
1871+
assertFalse(scrim.hidden);
19411872

1942-
// The dropdown is closed when a keypress on Esc is made.
1943-
const escapeEvent = new KeyboardEvent('keydown', {
1944-
bubbles: true,
1945-
cancelable: true,
1946-
composed: true, // So it propagates across shadow DOM boundary.
1947-
key: 'Escape',
1948-
});
1949-
realbox_input.dispatchEvent(escapeEvent);
1873+
$$<SearchboxElement>(app, '#searchbox')!.$.inputWrapper.dispatchEvent(
1874+
new FocusEvent('focusout', {relatedTarget: scrim}));
19501875
await microtasksFinished();
1951-
assertFalse(!!getScrim());
1876+
assertTrue(scrim.hidden);
19521877
});
19531878
test(
1954-
'A scrim is applied when the dropdown is shown in composebox',
1879+
'A scrim is applied when the focus is on the composebox input',
19551880
async () => {
19561881
loadTimeData.overrideValues({
1957-
composeboxShowZps: true,
1958-
composeboxShowTypedSuggest: true,
19591882
composeboxCloseByClickOutside: true,
19601883
});
1961-
assertFalse(!!getScrim());
1884+
const scrim = getScrim();
1885+
assertTrue(!!scrim);
1886+
assertTrue(scrim?.hidden);
19621887
const realbox = $$(app, '#searchbox');
19631888
assertTrue(!!realbox);
19641889
realbox.dispatchEvent(new CustomEvent('open-composebox', {
@@ -1967,26 +1892,19 @@ suite('NewTabPageAppTest', () => {
19671892
await microtasksFinished();
19681893
const ntpComposebox = app.shadowRoot.querySelector('ntp-composebox');
19691894
assertTrue(!!ntpComposebox);
1970-
1971-
// Open the dropbox by satisfying its opening condition
1972-
ntpComposebox.$.input.value = 'Test';
1973-
ntpComposebox.$.input.style.height = '48px';
1974-
ntpComposebox.$.input.dispatchEvent(new Event('input'));
1975-
await microtasksFinished();
1976-
const matches = [createSearchMatch()];
1977-
ComposeboxProxyImpl.getInstance()
1978-
.searchboxCallbackRouter.$.bindNewPipeAndPassRemote()
1979-
.autocompleteResultChanged(createAutocompleteResult({
1980-
input: 'Test'.trimStart(),
1981-
matches: matches,
1982-
}));
1895+
ntpComposebox.$.input.dispatchEvent(new FocusEvent('focus'));
19831896
await microtasksFinished();
1984-
const scrim = getScrim();
1985-
assertTrue(!!scrim);
19861897

1987-
scrim.click(); // closes the composebox and thus the dropdown
1898+
assertFalse(scrim.hidden);
1899+
1900+
ntpComposebox.$.input.dispatchEvent(
1901+
new FocusEvent('focusout', {relatedTarget: scrim}));
1902+
await microtasksFinished();
1903+
scrim.click();
19881904
await microtasksFinished();
1989-
assertFalse(!!getScrim());
1905+
assertTrue(scrim?.hidden);
1906+
// Composebox should have been closed.
1907+
assertFalse(!!app.shadowRoot.querySelector('ntp-composebox'));
19901908
});
19911909
test('searchbox text carries over to composebox', async () => {
19921910
// Arrange.

ui/webui/resources/cr_components/composebox/composebox.html.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ export function getHtml(this: ComposeboxElement) {
3737
.value="${this.input_}"
3838
@input=${this.handleInput_}
3939
@scroll="${this.handleScroll_}"
40-
@focusin="${this.handleInputFocusIn_}"></textarea>
40+
@focusin="${this.handleInputFocusIn_}"
41+
@focusout="${this.handleInputFocusOut_}"></textarea>
4142
${this.shouldShowSmartComposeInlineHint_() ? html`
4243
<div id="smartCompose">
4344
<!-- Comments in between spans to eliminate spacing between

ui/webui/resources/cr_components/composebox/composebox.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,15 @@ export class ComposeboxElement extends I18nMixinLit
664664
if (this.lastQueriedInput_ && this.result_?.matches.length) {
665665
this.$.matches.selectFirst();
666666
}
667+
if (this.ntpRealboxNextEnabled) {
668+
this.fire('composebox-input-focus-changed', {value: true});
669+
}
670+
}
671+
672+
protected handleInputFocusOut_() {
673+
if (this.ntpRealboxNextEnabled) {
674+
this.fire('composebox-input-focus-changed', {value: false});
675+
}
667676
}
668677

669678
protected handleComposeboxFocusIn_(e: FocusEvent) {

ui/webui/resources/cr_components/searchbox/searchbox.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -526,13 +526,18 @@ export class SearchboxElement extends SearchboxElementBase {
526526
this.showThumbnail = !!this.thumbnailUrl_;
527527
}
528528

529-
if (this.ntpRealboxNextEnabled &&
530-
changedPrivateProperties.has('dropdownIsVisible')) {
531-
this.dispatchEvent(new CustomEvent('dropdown-visible-changed', {
532-
bubbles: true,
533-
composed: true,
534-
detail: {value: this.dropdownIsVisible},
535-
}));
529+
if (this.ntpRealboxNextEnabled) {
530+
if (changedPrivateProperties.has('dropdownIsVisible')) {
531+
this.dispatchEvent(new CustomEvent('dropdown-visible-changed', {
532+
bubbles: true,
533+
composed: true,
534+
detail: {value: this.dropdownIsVisible},
535+
}));
536+
}
537+
538+
if (changedPrivateProperties.has('inputFocused_')) {
539+
this.fire('searchbox-input-focus-changed', {value: this.inputFocused_});
540+
}
536541
}
537542
}
538543

0 commit comments

Comments
 (0)