Refactor search component expand behavior and add auto-expand-width prop to search component

In preparation for I30c670e3f195f77a27715c6b494a3088b7a55712, refactor
the search component expand behavior so that it can accomodate the new
changes in WVUI while maintaining backwards compatibility with the
status quo.

Additionally, pass/enable the `auto-expand-width` prop to the main
header's search. This will be inert until the new changes in WVUI have
landed.

Bug: T297531
Change-Id: Id8d3bd4aa74113b91ecaf66cb58cf5625db8a302
This commit is contained in:
Nicholas Ray 2021-12-15 20:13:56 -07:00
parent dce2ea9566
commit 3028a4f9d8
6 changed files with 101 additions and 55 deletions

View File

@ -105,7 +105,8 @@ class SkinVector extends SkinMustache {
'tabindex' => '-1',
'class' => 'sticky-header-icon'
];
private const SEARCH_EXPANDING_CLASS = 'vector-search-box-show-thumbnail';
private const SEARCH_SHOW_THUMBNAIL_CLASS = 'vector-search-box-show-thumbnail';
private const SEARCH_AUTO_EXPAND_WIDTH_CLASS = 'vector-search-box-auto-expand-width';
private const STICKY_HEADER_ENABLED_CLASS = 'vector-sticky-header-enabled';
private const CLASS_QUIET_BUTTON = 'mw-ui-button mw-ui-quiet';
private const CLASS_PROGRESSIVE = 'mw-ui-progressive';
@ -583,7 +584,8 @@ class SkinVector extends SkinMustache {
!$this->isLegacy(),
// is primary mode of search
true,
'searchform'
'searchform',
true
),
'data-vector-sticky-header' => VectorServices::getFeatureManager()->isFeatureEnabled(
Constants::FEATURE_STICKY_HEADER
@ -593,7 +595,8 @@ class SkinVector extends SkinMustache {
// Collapse inside search box is disabled.
false,
false,
'vector-sticky-search-form'
'vector-sticky-search-form',
false
),
VectorServices::getFeatureManager()->isFeatureEnabled(
Constants::FEATURE_STICKY_HEADER_EDIT
@ -657,9 +660,16 @@ class SkinVector extends SkinMustache {
* @param bool $isCollapsible
* @param bool $isPrimary
* @param string $formId
* @param bool $autoExpandWidth
* @return array modified version of $searchBoxData
*/
private function getSearchData( array $searchBoxData, bool $isCollapsible, bool $isPrimary, string $formId ) {
private function getSearchData(
array $searchBoxData,
bool $isCollapsible,
bool $isPrimary,
string $formId,
bool $autoExpandWidth
) {
$searchClass = '';
// Determine the search widget treatment to send to the user
@ -671,8 +681,9 @@ class SkinVector extends SkinMustache {
$searchClass .= ' vector-search-box-collapses ';
}
if ( $this->shouldSearchExpand() ) {
$searchClass .= ' ' . self::SEARCH_EXPANDING_CLASS;
if ( $this->doesSearchHaveThumbnails() ) {
$searchClass .= ' ' . self::SEARCH_SHOW_THUMBNAIL_CLASS .
( $autoExpandWidth ? ' ' . self::SEARCH_AUTO_EXPAND_WIDTH_CLASS : '' );
}
// Annotate search box with a component class.
@ -728,15 +739,12 @@ class SkinVector extends SkinMustache {
}
/**
* Determines whether or not the search input should expand when focused
* before WVUI search is loaded. In WVUI, the search input expands to
* accomodate thumbnails in the suggestion list. When thumbnails are
* disabled, the input should not expand. Note this is only relevant for WVUI
* search (not legacy search).
* Returns `true` if WVUI is enabled to show thumbnails and `false` otherwise.
* Note this is only relevant for WVUI search (not legacy search).
*
* @return bool
*/
private function shouldSearchExpand(): bool {
private function doesSearchHaveThumbnails(): bool {
$featureManager = VectorServices::getFeatureManager();
return $featureManager->isFeatureEnabled( Constants::FEATURE_USE_WVUI_SEARCH ) &&

View File

@ -17,6 +17,7 @@
:show-thumbnail="showThumbnail"
:show-description="showDescription"
:highlight-query="highlightQuery"
:auto-expand-width="autoExpandWidth"
@fetch-start="instrumentation.onFetchStart"
@fetch-end="instrumentation.onFetchEnd"
@suggestion-click="instrumentation.onSuggestionClick"
@ -121,6 +122,10 @@ module.exports = {
highlightQuery: {
type: Boolean,
default: true
},
autoExpandWidth: {
type: Boolean,
default: false
}
},
data: function () {

View File

@ -6,18 +6,18 @@ var
config = require( './config.json' );
/**
* @param {Element} searchForm
* @param {Element} searchBox
* @return {void}
*/
function initApp( searchForm ) {
var
function initApp( searchBox ) {
var searchForm = searchBox.querySelector( '.vector-search-box-form' ),
titleInput = /** @type {HTMLInputElement|null} */ (
searchForm.querySelector( 'input[name=title]' )
searchBox.querySelector( 'input[name=title]' )
),
search = /** @type {HTMLInputElement|null} */ ( searchForm.querySelector( 'input[name="search"]' ) ),
search = /** @type {HTMLInputElement|null} */ ( searchBox.querySelector( 'input[name="search"]' ) ),
searchPageTitle = titleInput && titleInput.value;
if ( !search || !titleInput ) {
if ( !searchForm || !search || !titleInput ) {
throw new Error( 'Attempted to create Vue search element from an incompatible element.' );
}
@ -31,7 +31,8 @@ function initApp( searchForm ) {
searchPageTitle: searchPageTitle,
searchTitle: search.getAttribute( 'title' ),
searchPlaceholder: search.getAttribute( 'placeholder' ),
searchQuery: search.value
searchQuery: search.value,
autoExpandWidth: searchBox ? searchBox.classList.contains( 'vector-search-box-auto-expand-width' ) : false
// Pass additional config from server.
}, config )
)
@ -42,11 +43,10 @@ function initApp( searchForm ) {
* @return {void}
*/
function main( document ) {
var
searchForms = document.querySelectorAll( '.vector-search-box-form' );
var searchBoxes = document.querySelectorAll( '.vector-search-box' );
searchForms.forEach( function ( searchForm ) {
initApp( searchForm );
searchBoxes.forEach( function ( searchBox ) {
initApp( searchBox );
} );
}
main( document );

View File

@ -32,9 +32,20 @@
flex-grow: 1;
}
// Allocate space for the extra width of the input when the search component
// has thumbnails.
//
// FIXME: This can be removed when WVUI in core has been upgraded to use the
// `.wvui-typeahead-search--auto-expand-width` class.
.wvui-typeahead-search--show-thumbnail:not( .wvui-typeahead-search--auto-expand-width ) {
margin-left: @size-search-expand;
}
@media ( min-width: @width-breakpoint-desktop ) {
@margin-start-search: 40px;
.vector-search-box {
margin-left: unit( 40px / @font-size-browser / @font-size-base, em ); // 2.85714286em @ 16 & 0.875em
margin-left: unit( @margin-start-search / @font-size-browser / @font-size-base, em ); // 2.85714286em @ 16 & 0.875em
margin-right: @margin-end-search;
// Support: IE 8, Firefox 18-, Chrome 19-, Safari 5.1-, Opera 19-, Android 4.4.4-.
@ -45,10 +56,17 @@
min-width: @min-width-search-desktop;
flex-basis: @min-width-search;
&-form,
.wvui-typeahead-search {
> div {
max-width: @max-width-search;
}
&.vector-search-box-show-thumbnail {
margin-left: unit( ( @margin-start-search - @size-search-expand ) / @font-size-browser / @font-size-base, em ); // 1.14285714em @ 16 & 0.875em
> div {
max-width: @max-width-search + unit( @size-search-expand / @font-size-browser / @font-size-base, em ); // 37.42857143em @ 16 & 0.875em
}
}
}
}
@ -75,15 +93,19 @@
margin-right: @margin-end-search;
}
// Increase the start margin of the search box to account for the input
// expanding on focus.
.vector-search-box-show-thumbnail {
margin-left: @size-search-expand + @padding-horizontal-tabs;
}
.wvui-typeahead-search__wrapper {
position: static;
}
// Position the start of suggestion list at the start of the input.
//
// FIXME: This can be removed when WVUI in core has been upgraded to use
// the `.wvui-typeahead-search--auto-expand-width` class.
.wvui-typeahead-search--show-thumbnail:not( .wvui-typeahead-search--auto-expand-width ) {
.wvui-typeahead-search__suggestions {
left: 0;
}
}
}
}
}

View File

@ -101,6 +101,11 @@
}
&.vector-header-search-toggled {
// .wvui-input__input left padding (36px) - the .wvui-icon svg width (20px)
// - the icon left padding (12px [1]) = 4px
// [1] see .wvui-typeahead-search--show-thumbnail .wvui-input__input:focus)
@margin-start-search-box: 4px;
.vector-sticky-header-search-toggle,
.vector-sticky-header-context-bar {
display: none;
@ -109,24 +114,27 @@
.vector-search-box {
display: block;
flex-basis: unit( 500px / @font-size-browser / @font-size-base, em );
.wvui-typeahead-search {
// .wvui-input__input left padding (36px) - the .wvui-icon svg width (20px)
// - the icon left padding (12px [1]) = 4px
// [1] see .wvui-typeahead-search--show-thumbnail .wvui-input__input:focus)
margin-left: 4px;
}
margin-left: @margin-start-search-box;
}
// T296318 Increase the start margin of the search box to account for the input
// expanding on focus.
// T296318 Decrease the start margin of the search box to account for the
// icon's increased start position when the search component has thumbnails.
.vector-search-box-show-thumbnail {
margin-left: @margin-end-search;
margin-left: @margin-start-search-box - ( @size-search-expand / 2 );
.wvui-input__start-icon {
color: @colorGray2;
}
}
// Allocate space for the extra width of the input when the search component
// has thumbnails.
//
// FIXME: This can be removed when WVUI in core has been upgraded
// to use the `.wvui-typeahead-search--full-width` class.
.wvui-typeahead-search--show-thumbnail:not( .wvui-typeahead-search--full-width ) {
margin-left: @size-search-expand;
}
}
}

View File

@ -81,7 +81,7 @@
bottom: 0;
// Accounts for the 1px input border. Derived from
// https://gerrit.wikimedia.org/g/wvui/+/refs/changes/93/650593/10/src/components/input/Input.vue#163
left: 1px;
left: @border-width-base;
// Increase size to match WVUI.
width: @size-search-figure;
}
@ -93,13 +93,23 @@
}
.vector-search-box-show-thumbnail {
.searchButton {
// Accounts for the margin that allocates space for the input expanding and
// 1px input border.
left: @size-search-expand + @border-width-base;
}
.vector-search-box-input {
margin-left: @size-search-expand;
width: ~'calc( 100% - @{size-search-expand} )';
}
// Recreate WVUI expanding input.
.vector-search-box-input:focus {
position: relative;
margin-left: 0;
// Use ~ and fixed values to disable the LESS transformation in ResourceLoader LESS implementation.
padding-left: ~'calc( @{size-search-figure} + @{size-search-expand} )';
width: ~'calc( 100% + @{size-search-expand} )';
left: ~'calc( -1 * @{size-search-expand} )';
width: 100%;
}
// Reposition search icon for expanded input.
@ -107,15 +117,8 @@
// Derived from
// https://gerrit.wikimedia.org/g/wvui/+/refs/changes/93/650593/10/src/components/typeahead-search/TypeaheadSearch.vue#655
// (12px of space between the border and the icon) with 1px to account for the focused input border.
@space-icon-start: 12px;
left: -@size-search-expand + @space-icon-start + @border-width-base;
}
// Update search loader to match width and position of WVUI expanding input.
.vector-search-box-inner.search-form__loader:after {
width: ~'calc( 100% + @{size-search-expand} )';
left: ~'calc( -1 * @{size-search-expand} )';
padding-left: @size-search-expand;
@space-icon-start: @size-search-expand / 2;
left: @space-icon-start + @border-width-base;
}
}
}