Skip to content

Commit

Permalink
feat(search-with-typeahead/masthead): support initial search term (ca…
Browse files Browse the repository at this point in the history
…rbon-design-system#11668)

### Related Ticket(s)

Closes carbon-design-system#11617

### Description

I couldn't find definitive proof this property ever existed on either the Search with Typeahead or Masthead web components. Maybe it existed on react versions of these?

In any case, I've added the requested attribute to `<c4d-search-with-typeahead>` and `<c4d-masthead-composite/container>`. It will set the `value` attribute of the search's text input when users open the search bar, unless the user has previously opened the search and modified the default value. In that case, we respect the user's changes and don't set the `value`. This brings up a potential improvement to cache the user's input and use that instead if they close & reopen the search bar, but I'll leave that for another issue 🙂 

### Changelog

**New**

- Adds `initial-search-term` attribute on both `<c4d-search-with-typeahead>` and `<c4d-masthead-composite/container>` elements that sets default query in search input.
- Documents `initial-search-term` feature in Storybook.

**Changed**

- Adds Storybook knobs for `<c4d-search-with-typeahead>`'s "open on load" (`active`) and `should-remain-open` features.

### Testing

Test the "initial search term" knob on both the [Search with Typeahead](https://ibmdotcom-webcomponents.s3.us-east.cloud-object-storage.appdomain.cloud/deploy-previews/11668/index.html?path=/story/components-search-with-typeahead--default) and [Masthead](https://ibmdotcom-webcomponents.s3.us-east.cloud-object-storage.appdomain.cloud/deploy-previews/11668/index.html?path=/story/components-masthead--default) deploy preview stories.

<!-- React and Web Component deploy previews are enabled by default. -->
<!-- To enable additional available deploy previews, apply the following -->
<!-- labels for the corresponding package: -->
<!-- *** "test: e2e": Codesandbox examples and e2e integration tests -->
<!-- *** "package: services": Services -->
<!-- *** "package: utilities": Utilities -->
<!-- *** "RTL": React / Web Components (RTL) -->
<!-- *** "feature flag": React / Web Components (experimental) -->
  • Loading branch information
jkaeser authored Apr 2, 2024
1 parent 2597367 commit 78015dc
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export const Default = (args) => {
hasProfile,
hasSearch,
hasContact,
initialSearchTerm,
selectedMenuItem,
searchPlaceholder,
userStatus,
Expand All @@ -112,6 +113,7 @@ export const Default = (args) => {
<c4d-masthead-container
selected-menu-item="${ifDefined(selectedMenuItem)}"
user-status="${ifDefined(userStatus)}"
initial-search-term="${ifDefined(initialSearchTerm)}"
searchPlaceholder="${ifDefined(searchPlaceholder)}"
has-profile="${hasProfile}"
has-search="${hasSearch}"
Expand All @@ -129,6 +131,7 @@ export const Default = (args) => {
data-endpoint="${dataEndpoints['v2.1']}"
selected-menu-item="${ifNonEmpty(selectedMenuItem)}"
user-status="${ifNonEmpty(userStatus)}"
initial-search-term="${ifDefined(initialSearchTerm)}"
searchPlaceholder="${ifNonEmpty(searchPlaceholder)}"
has-profile="${hasProfile}"
has-search="${hasSearch}"
Expand Down Expand Up @@ -199,7 +202,8 @@ WithCustomTypeahead.story = {
};

export const searchOpenOnload = (args) => {
const { searchPlaceholder, useMock } = args?.MastheadComposite ?? {};
const { initialSearchTerm, searchPlaceholder, useMock } =
args?.MastheadComposite ?? {};
return html`
<style>
${styles}
Expand All @@ -215,6 +219,7 @@ export const searchOpenOnload = (args) => {
unauthenticatedProfileItems
)}"
activate-search="true"
initial-search-term="${ifDefined(initialSearchTerm)}"
searchPlaceholder="${ifDefined(
searchPlaceholder
)}"></c4d-masthead-container>
Expand All @@ -223,6 +228,7 @@ export const searchOpenOnload = (args) => {
<c4d-masthead-container
data-endpoint="${dataEndpoints['v2.1']}"
activate-search="true"
initial-search-term="${ifDefined(initialSearchTerm)}"
searchPlaceholder="${ifDefined(
searchPlaceholder
)}"></c4d-masthead-container>
Expand Down Expand Up @@ -538,6 +544,10 @@ export default {
['true', 'false'],
'true'
),
initialSearchTerm: textNullable(
'initial search term (initial-search-term)',
''
),
searchPlaceholder: textNullable(
'search placeholder (searchPlaceholder)',
'Search all of IBM'
Expand Down Expand Up @@ -566,6 +576,7 @@ export default {
platform: null,
hasProfile: 'true',
hasSearch: 'true',
initialSearchTerm: '',
searchPlaceholder: 'Search all of IBM',
selectedMenuItem: 'Services & Consulting',
userStatus: userStatuses.unauthenticated,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1093,6 +1093,7 @@ class C4DMastheadComposite extends HostListenerMixin(LitElement) {
currentSearchResults,
customTypeaheadAPI,
hasSearch,
initialSearchTerm,
inputTimeout,
language,
openSearchDropdown,
Expand All @@ -1106,6 +1107,7 @@ class C4DMastheadComposite extends HostListenerMixin(LitElement) {
?active="${activateSearch}"
.currentSearchResults="${ifDefined(currentSearchResults)}"
?custom-typeahead-api="${ifDefined(customTypeaheadAPI)}"
initial-search-term="${ifDefined(initialSearchTerm)}"
input-timeout="${inputTimeout}"
language="${ifDefined(language)}"
?open="${openSearchDropdown}"
Expand Down Expand Up @@ -1271,6 +1273,12 @@ class C4DMastheadComposite extends HostListenerMixin(LitElement) {
@property({ attribute: 'search-open-on-load' })
searchOpenOnload = this.activateSearch;

/**
* Sets a default query in the masthead's search input.
*/
@property({ attribute: 'initial-search-term', reflect: true })
initialSearchTerm?: string;

/**
* The profile items for authenticated state.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ button, the search bar will contract back to its single search button, ready to
be activated again.

```html
<c4d-search-with-typeahead></search-with-typeahead>
<c4d-search-with-typeahead></c4d-search-with-typeahead>
```

### Search Open On Load
Expand All @@ -48,7 +48,7 @@ page. The close functionality will still apply upon focusing out or clicking the
close button.

```html
<c4d-search-with-typeahead active></search-with-typeahead>
<c4d-search-with-typeahead active></c4d-search-with-typeahead>
```

### Search Should Remain Open
Expand All @@ -58,7 +58,15 @@ out or close button is clicked. You can combine the previous attribute with this
one to ensure it will always be open.

```html
<c4d-search-with-typeahead should-remain-open></search-with-typeahead>
<c4d-search-with-typeahead should-remain-open></c4d-search-with-typeahead>
```

### Initial Search Term

This will set a default query in the search's text input.

```html
<c4d-search-with-typeahead initial-search-term="Example search text"></c4d-search-with-typeahead>
```

## Slots
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* @license
*
* Copyright IBM Corp. 2020, 2023
* Copyright IBM Corp. 2020, 2024
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
Expand All @@ -11,14 +11,33 @@ import { html } from 'lit';
import '../index';
import readme from './README.stories.mdx';
import styles from '../../carousel/__stories__/carousel.stories.scss';
import textNullable from '../../../../.storybook/knob-text-nullable';
import { boolean } from '@storybook/addon-knobs';

export const Default = () => html`
<c4d-search-with-typeahead> </c4d-search-with-typeahead>
`;
export const Default = (args) => {
const { initialSearchTerm, openOnLoad, shouldRemainOpen } =
args?.SearchWithTypeahead ?? {};
return html`
<c4d-search-with-typeahead
initial-search-term="${initialSearchTerm}"
?active=${openOnLoad}
?should-remain-open=${shouldRemainOpen}>
</c4d-search-with-typeahead>
`;
};

export const Alternate = () => html`
<c4d-search-with-typeahead leadspace-search> </c4d-search-with-typeahead>
`;
export const Alternate = (args) => {
const { initialSearchTerm, openOnLoad, shouldRemainOpen } =
args?.SearchWithTypeahead ?? {};
return html`
<c4d-search-with-typeahead
initial-search-term="${initialSearchTerm}"
leadspace-search
?active=${openOnLoad}
?should-remain-open=${shouldRemainOpen}>
</c4d-search-with-typeahead>
`;
};

export default {
title: 'Components/Search with typeahead',
Expand All @@ -37,5 +56,27 @@ export default {
parameters: {
...readme.parameters,
hasStoryPadding: true,
knobs: {
SearchWithTypeahead: () => ({
initialSearchTerm: textNullable(
'Initial search term (initial-search-term)',
''
),
openOnLoad: boolean('Open on load (active)', false),
shouldRemainOpen: boolean(
'Should remain open (should-remain-open)',
false
),
}),
},
propsSet: {
default: {
SearchWithTypeahead: {
initialSearchTerm: '',
openOnLoad: false,
shouldRemainOpen: false,
},
},
},
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import { ifDefined } from 'lit/directives/if-defined.js';
import { classMap } from 'lit/directives/class-map.js';
import { html } from 'lit';
import { property, query } from 'lit/decorators.js';
import { property, query, state } from 'lit/decorators.js';
import Close20 from '../../internal/vendor/@carbon/web-components/icons/close/20.js';
import Search20 from '../../internal/vendor/@carbon/web-components/icons/search/20.js';
import CDSDropdown, {
Expand Down Expand Up @@ -82,6 +82,9 @@ class C4DSearchWithTypeahead extends HostListenerMixin(
@property()
groupedResults;

@property({ attribute: 'initial-search-term', reflect: true })
initialSearchTerm?: string;

@property({ attribute: 'scope-parameters' })
scopeParameters;

Expand All @@ -97,6 +100,9 @@ class C4DSearchWithTypeahead extends HostListenerMixin(
@property({ attribute: 'scope-value', reflect: true })
scopeValue;

@state()
userHasInputSearch = false;

/**
* The `<button>` to open the search box.
*/
Expand Down Expand Up @@ -388,6 +394,7 @@ class C4DSearchWithTypeahead extends HostListenerMixin(
* Handles `input` event in the search input.
*/
private _handleInput(event: InputEvent) {
const { userHasInputSearch } = this;
const { target } = event;
const { value } = target as HTMLInputElement;
this.removeAttribute('unfocused');
Expand Down Expand Up @@ -435,6 +442,10 @@ class C4DSearchWithTypeahead extends HostListenerMixin(
}
}

if (!userHasInputSearch) {
this.userHasInputSearch = true;
}

// accomodate search results box's width with the scope dropdown
if (
gridBreakpoint < document.body.clientWidth &&
Expand Down Expand Up @@ -600,8 +611,10 @@ class C4DSearchWithTypeahead extends HostListenerMixin(
*/
protected _renderTriggerContent() {
const {
initialSearchTerm,
searchPlaceholder,
searchLabel,
userHasInputSearch,
_handleInput: handleInput,
_handleKeyInput: handleKeyInput,
} = this;
Expand All @@ -612,6 +625,7 @@ class C4DSearchWithTypeahead extends HostListenerMixin(
class="${prefix}--header__search--input"
name="q"
placeholder="${searchPlaceholder}"
value="${!userHasInputSearch ? initialSearchTerm : ''}"
autocomplete="off"
aria-controls="result-list"
aria-autocomplete="list"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,25 @@ describe('c4d-masthead | default (desktop)', () => {
cy.takeSnapshots();
});

it('should respect initial search term option', () => {
const initialTerm = 'initialsearchterm';
cy.visit(`/${_pathDefault}&knob-initial%20search%20term%20(initial-search-term)=${initialTerm}`)
.get('c4d-masthead > c4d-search-with-typeahead')
.as('search')
.shadow()
.find('.cds--header__search--search')
.click();

cy.get('@search')
.shadow()
.find('.cds--header__search--input')
.then(([input]) => {
expect(input.value).to.equal(initialTerm);
});

cy.takeSnapshots();
});

it('should allow keywords in the search bar and display 10 suggested results', () => {
cy.get('c4d-masthead > c4d-search-with-typeahead')
.shadow()
Expand Down

0 comments on commit 78015dc

Please sign in to comment.