Skip to content

Commit

Permalink
Allow custom afterDropdownInputFocus on FilterSearch (#432)
Browse files Browse the repository at this point in the history
EmilyZhang777
Member
EmilyZhang777 commented 4 days ago • 
This change adds a param so that callers can pass in a custom afterDropdownInputFocus method for FilterSearch's input box. This request was brought up to allow analytics event logging upon clicking on the input box.

This change also bump the version to 1.6.0-beta.432.
  • Loading branch information
EmilyZhang777 authored Mar 18, 2024
1 parent 0479954 commit 4946b76
Show file tree
Hide file tree
Showing 15 changed files with 113 additions and 18 deletions.
Binary file modified .storybook/snapshots/__snapshots__/mapboxmap--multiple-pins.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions docs/search-ui-react.afterdropdowninputfocusprops.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@yext/search-ui-react](./search-ui-react.md) &gt; [AfterDropdownInputFocusProps](./search-ui-react.afterdropdowninputfocusprops.md)

## AfterDropdownInputFocusProps interface

The parameters that are passed into [FilterSearchProps.afterDropdownInputFocus](./search-ui-react.filtersearchprops.afterdropdowninputfocus.md)<!-- -->.

**Signature:**

```typescript
interface AfterDropdownInputFocusProps
```

## Properties

| Property | Modifiers | Type | Description |
| --- | --- | --- | --- |
| [value](./search-ui-react.afterdropdowninputfocusprops.value.md) | | string | The input element's value. |

13 changes: 13 additions & 0 deletions docs/search-ui-react.afterdropdowninputfocusprops.value.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@yext/search-ui-react](./search-ui-react.md) &gt; [AfterDropdownInputFocusProps](./search-ui-react.afterdropdowninputfocusprops.md) &gt; [value](./search-ui-react.afterdropdowninputfocusprops.value.md)

## AfterDropdownInputFocusProps.value property

The input element's value.

**Signature:**

```typescript
value: string;
```
4 changes: 2 additions & 2 deletions docs/search-ui-react.filtersearch.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ A component which allows a user to search for filters associated with specific e
**Signature:**

```typescript
declare function FilterSearch({ searchFields, label, placeholder, searchOnSelect, onSelect, onDropdownInputChange, sectioned, customCssClasses }: FilterSearchProps): JSX.Element;
declare function FilterSearch({ searchFields, label, placeholder, searchOnSelect, onSelect, onDropdownInputChange, afterDropdownInputFocus, sectioned, customCssClasses }: FilterSearchProps): JSX.Element;
```

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| { searchFields, label, placeholder, searchOnSelect, onSelect, onDropdownInputChange, sectioned, customCssClasses } | [FilterSearchProps](./search-ui-react.filtersearchprops.md) | |
| { searchFields, label, placeholder, searchOnSelect, onSelect, onDropdownInputChange, afterDropdownInputFocus, sectioned, customCssClasses } | [FilterSearchProps](./search-ui-react.filtersearchprops.md) | |

**Returns:**

Expand Down
13 changes: 13 additions & 0 deletions docs/search-ui-react.filtersearchprops.afterdropdowninputfocus.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@yext/search-ui-react](./search-ui-react.md) &gt; [FilterSearchProps](./search-ui-react.filtersearchprops.md) &gt; [afterDropdownInputFocus](./search-ui-react.filtersearchprops.afterdropdowninputfocus.md)

## FilterSearchProps.afterDropdownInputFocus property

A function which is called immediately after the input gains focus. It does not replace the default focus behavior.

**Signature:**

```typescript
afterDropdownInputFocus?: (params: AfterDropdownInputFocusProps) => void;
```
1 change: 1 addition & 0 deletions docs/search-ui-react.filtersearchprops.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ interface FilterSearchProps

| Property | Modifiers | Type | Description |
| --- | --- | --- | --- |
| [afterDropdownInputFocus?](./search-ui-react.filtersearchprops.afterdropdowninputfocus.md) | | (params: [AfterDropdownInputFocusProps](./search-ui-react.afterdropdowninputfocusprops.md)<!-- -->) =&gt; void | _(Optional)_ A function which is called immediately after the input gains focus. It does not replace the default focus behavior. |
| [customCssClasses?](./search-ui-react.filtersearchprops.customcssclasses.md) | | [FilterSearchCssClasses](./search-ui-react.filtersearchcssclasses.md) | _(Optional)_ CSS classes for customizing the component styling. |
| [label?](./search-ui-react.filtersearchprops.label.md) | | string | _(Optional)_ The display label for the component. |
| [onDropdownInputChange?](./search-ui-react.filtersearchprops.ondropdowninputchange.md) | | (params: [OnDropdownInputChangeProps](./search-ui-react.ondropdowninputchangeprops.md)<!-- -->) =&gt; void | _(Optional)_ A function which is called when the input element's value changes. Replaces the default behavior. |
Expand Down
3 changes: 2 additions & 1 deletion docs/search-ui-react.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
| [executeSearch(searchActions)](./search-ui-react.executesearch.md) | Executes a universal/vertical search. |
| [Facets(props)](./search-ui-react.facets.md) | A component that displays all facets applicable to the current vertical search. |
| [FilterDivider({ className })](./search-ui-react.filterdivider.md) | A divider component used to separate NumericalFacets, HierarchicalFacets, StandardFacets, and StaticFilters. |
| [FilterSearch({ searchFields, label, placeholder, searchOnSelect, onSelect, onDropdownInputChange, sectioned, customCssClasses })](./search-ui-react.filtersearch.md) | A component which allows a user to search for filters associated with specific entities and fields. |
| [FilterSearch({ searchFields, label, placeholder, searchOnSelect, onSelect, onDropdownInputChange, afterDropdownInputFocus, sectioned, customCssClasses })](./search-ui-react.filtersearch.md) | A component which allows a user to search for filters associated with specific entities and fields. |
| [Geolocation\_2({ geolocationOptions, radius, label, GeolocationIcon, handleClick, customCssClasses, })](./search-ui-react.geolocation_2.md) | A React Component which collects location information to create a location filter and perform a new search. |
| [getSearchIntents(searchActions)](./search-ui-react.getsearchintents.md) | Get search intents of the current query stored in headless using autocomplete request. |
| [getUserLocation(geolocationOptions)](./search-ui-react.getuserlocation.md) | Retrieves user's location using navigator.geolocation API. |
Expand Down Expand Up @@ -52,6 +52,7 @@

| Interface | Description |
| --- | --- |
| [AfterDropdownInputFocusProps](./search-ui-react.afterdropdowninputfocusprops.md) | The parameters that are passed into [FilterSearchProps.afterDropdownInputFocus](./search-ui-react.filtersearchprops.afterdropdowninputfocus.md)<!-- -->. |
| [AlternativeVerticalsCssClasses](./search-ui-react.alternativeverticalscssclasses.md) | The CSS class interface used for [AlternativeVerticals()](./search-ui-react.alternativeverticals.md)<!-- -->. |
| [AlternativeVerticalsProps](./search-ui-react.alternativeverticalsprops.md) | Props for [AlternativeVerticals()](./search-ui-react.alternativeverticals.md)<!-- -->. |
| [AppliedFiltersCssClasses](./search-ui-react.appliedfilterscssclasses.md) | The CSS class interface used for [AppliedFilters()](./search-ui-react.appliedfilters.md)<!-- -->. |
Expand Down
8 changes: 7 additions & 1 deletion etc/search-ui-react.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ import { UniversalLimit } from '@yext/search-headless-react';
import { UnknownFieldValueDirectAnswer } from '@yext/search-headless-react';
import { VerticalResults as VerticalResults_2 } from '@yext/search-headless-react';

// @public
export interface AfterDropdownInputFocusProps {
value: string;
}

// @public
export function AlternativeVerticals({ currentVerticalLabel, verticalConfigMap, displayAllOnNoResults, customCssClasses }: AlternativeVerticalsProps): JSX.Element | null;

Expand Down Expand Up @@ -268,7 +273,7 @@ export interface FilterOptionConfig {
}

// @public
export function FilterSearch({ searchFields, label, placeholder, searchOnSelect, onSelect, onDropdownInputChange, sectioned, customCssClasses }: FilterSearchProps): JSX.Element;
export function FilterSearch({ searchFields, label, placeholder, searchOnSelect, onSelect, onDropdownInputChange, afterDropdownInputFocus, sectioned, customCssClasses }: FilterSearchProps): JSX.Element;

// @public
export interface FilterSearchCssClasses extends AutocompleteResultCssClasses {
Expand All @@ -288,6 +293,7 @@ export interface FilterSearchCssClasses extends AutocompleteResultCssClasses {

// @public
export interface FilterSearchProps {
afterDropdownInputFocus?: (params: AfterDropdownInputFocusProps) => void;
customCssClasses?: FilterSearchCssClasses;
label?: string;
onDropdownInputChange?: (params: OnDropdownInputChangeProps) => void;
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@yext/search-ui-react",
"version": "1.5.0",
"version": "1.6.0-beta.432",
"description": "A library of React Components for powering Yext Search integrations",
"author": "[email protected]",
"license": "BSD-3-Clause",
Expand Down
17 changes: 16 additions & 1 deletion src/components/FilterSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,16 @@ export interface OnDropdownInputChangeProps {
executeFilterSearch: (query?: string) => Promise<FilterSearchResponse | undefined>
}

/**
* The parameters that are passed into {@link FilterSearchProps.afterDropdownInputFocus}.
*
* @public
*/
export interface AfterDropdownInputFocusProps {
/** The input element's value. */
value: string,
}

/**
* The props for the {@link FilterSearch} component.
*
Expand All @@ -95,6 +105,8 @@ export interface FilterSearchProps {
onSelect?: (params: OnSelectParams) => void,
/** A function which is called when the input element's value changes. Replaces the default behavior. */
onDropdownInputChange?: (params: OnDropdownInputChangeProps) => void,
/** A function which is called immediately after the input gains focus. It does not replace the default focus behavior. */
afterDropdownInputFocus?: (params: AfterDropdownInputFocusProps) => void,
/** Determines whether or not the results of the filter search are separated by field. Defaults to false. */
sectioned?: boolean,
/** CSS classes for customizing the component styling. */
Expand All @@ -116,6 +128,7 @@ export function FilterSearch({
searchOnSelect,
onSelect,
onDropdownInputChange,
afterDropdownInputFocus,
sectioned = false,
customCssClasses
}: FilterSearchProps): JSX.Element {
Expand Down Expand Up @@ -293,7 +306,9 @@ export function FilterSearch({
if (value) {
executeFilterSearch(value);
}
}, [executeFilterSearch]);

afterDropdownInputFocus?.({value});
}, [afterDropdownInputFocus, executeFilterSearch]);

return (
<div className={cssClasses.filterSearchContainer}>
Expand Down
3 changes: 2 additions & 1 deletion src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ export {
FilterSearchCssClasses,
FilterSearchProps,
OnSelectParams,
OnDropdownInputChangeProps
OnDropdownInputChangeProps,
AfterDropdownInputFocusProps,
} from './FilterSearch';

export {
Expand Down
2 changes: 1 addition & 1 deletion test-site/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions tests/components/FilterSearch.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const meta: Meta<typeof FilterSearch> = {
args: {
label: 'Filter',
onDropdownInputChange: undefined,
afterDropdownInputFocus: undefined,
}
};
export default meta;
Expand Down
40 changes: 32 additions & 8 deletions tests/components/FilterSearch.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,10 @@ describe('search with section labels', () => {

await userEvent.type(searchBarElement, 'n');
expect(executeFilterSearch).toHaveBeenCalled();

const autocompleteSection = screen.getByText('First name');
expect(autocompleteSection).toBeDefined();

});

it('input value stays the same when a user selects a filter', async () => {
Expand Down Expand Up @@ -193,7 +193,7 @@ describe('search with section labels', () => {
},
selected: false
});

expect(setFilterOption).toBeCalledWith({
filter: {
kind: 'fieldValue',
Expand Down Expand Up @@ -650,7 +650,7 @@ describe('search without section labels', () => {
await userEvent.keyboard('{enter}');
expect(inputNode).toHaveValue('first name 1');
});

it('when an onDropdownInputChange prop is specified, it gets called each time after the input changes and executeFilterSearch does not', async () => {
const mockedOnDropdownInputChange = jest.fn();
const executeFilterSearch = jest
Expand All @@ -659,7 +659,31 @@ describe('search without section labels', () => {
await userEvent.type(screen.getByRole('textbox'), 'a');
expect(mockedOnDropdownInputChange).toHaveBeenCalledTimes(1);
expect(executeFilterSearch).toHaveBeenCalledTimes(0);
})
});

it('when an afterDropdownInputFocus prop is provided, invokes it in addition to the original ' +
'behavior when input gains focus', async () => {
const mockedAfterDropdownInputFocus = jest.fn();
const executeFilterSearch = jest.spyOn(SearchHeadless.prototype, 'executeFilterSearch');
renderFilterSearch(
{searchFields: searchFieldsProp, afterDropdownInputFocus: mockedAfterDropdownInputFocus});

// Click into input. ExecuteFilterSearch wouldn't be triggered since the input is empty.
await userEvent.click(screen.getByRole('textbox'));
expect(mockedAfterDropdownInputFocus).toHaveBeenCalledTimes(1);
expect(executeFilterSearch).toHaveBeenCalledTimes(0);

// Update input.
await userEvent.type(screen.getByRole('textbox'), 'a');
expect(executeFilterSearch).toHaveBeenCalledTimes(1);

// Click out of input and then click into input.
// ExecuteFilterSearch would be triggered since input no longer empty.
await userEvent.click(document.body);
await userEvent.click(screen.getByRole('textbox'));
expect(executeFilterSearch).toHaveBeenCalledTimes(2);
expect(mockedAfterDropdownInputFocus).toHaveBeenCalledTimes(2);
});
});

describe('screen reader', () => {
Expand All @@ -675,7 +699,7 @@ describe('screen reader', () => {
expect(executeFilterSearch).toHaveBeenCalled();

const expectedScreenReaderMessage = '2 First name autocomplete options found. 1 Last name autocomplete option found.';

const screenReaderMessage = screen.getByText(expectedScreenReaderMessage);
expect(screenReaderMessage).toBeDefined();
});
Expand All @@ -693,7 +717,7 @@ describe('screen reader', () => {

const expectedScreenReaderMessage = '3 autocomplete options found.';
const screenReaderMessage = screen.getByText(expectedScreenReaderMessage);

expect(screenReaderMessage).toBeDefined();
});

Expand All @@ -709,7 +733,7 @@ describe('screen reader', () => {

const expectedScreenReaderMessage = '0 autocomplete options found.';
const screenReaderMessage = screen.getByText(expectedScreenReaderMessage);

expect(screenReaderMessage).toBeDefined();
});
});
Expand Down

0 comments on commit 4946b76

Please sign in to comment.