diff --git a/pages/autosuggest/search.page.tsx b/pages/autosuggest/search.page.tsx new file mode 100644 index 00000000000..f3e7500c9c9 --- /dev/null +++ b/pages/autosuggest/search.page.tsx @@ -0,0 +1,99 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import React, { useContext, useRef, useState } from 'react'; + +import { Badge, Box, Checkbox, ExpandableSection, Header, SpaceBetween } from '~components'; +import Autosuggest, { AutosuggestProps } from '~components/autosuggest'; + +import AppContext, { AppContextType } from '../app/app-context'; + +type PageContext = React.Context< + AppContextType<{ + empty?: boolean; + showEnteredTextOption?: boolean; + showMatchesCount?: boolean; + }> +>; + +const options = [ + { value: '__apple__', label: 'Apple' }, + { value: '__orange__', label: 'Orange', tags: ['sweet'] }, + { value: '__banana__', label: 'Banana', tags: ['sweet'] }, + { value: '__pineapple__', label: 'Pineapple', description: 'pine+apple' }, +]; +const enteredTextLabel = (value: string) => `Use: ${value}`; + +export default function AutosuggestPage() { + const { + urlParams: { empty = false, showEnteredTextOption = true, showMatchesCount = true }, + setUrlParams, + } = useContext(AppContext as PageContext); + const [value, setValue] = useState(''); + const [selection, setSelection] = useState(''); + const ref = useRef(null); + return ( + + +
+ Search +
+ + + setUrlParams({ empty: detail.checked })}> + Empty + + setUrlParams({ showEnteredTextOption: detail.checked })} + > + Show entered text option + + setUrlParams({ showMatchesCount: detail.checked })} + > + Show matches count + + + + setValue(event.detail.value)} + onSelect={event => { + if (options.some(o => o.value === event.detail.value)) { + setSelection(event.detail.value); + setValue(''); + } + }} + enteredTextLabel={enteredTextLabel} + ariaLabel={'simple autosuggest'} + selectedAriaLabel="Selected" + empty="No suggestions" + showEnteredTextOption={showEnteredTextOption} + filteringResultsText={ + showMatchesCount + ? matchesCount => { + matchesCount = showEnteredTextOption ? matchesCount - 1 : matchesCount; + return matchesCount ? `${matchesCount} items` : `No matches`; + } + : undefined + } + /> + + + Selection: {selection || 'none'} + {options.map(option => ( + + {option.label} + + ))} + +
+
+ ); +} diff --git a/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap b/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap index 9fab7d22ebe..03e659eb711 100644 --- a/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap +++ b/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap @@ -2052,6 +2052,14 @@ This is required to provide a good screen reader experience. For more informatio "optional": true, "type": "string", }, + { + "defaultValue": "true", + "description": "Defines whether entered text option is shown as the first option in the dropdown when value is non-empty. +Defaults to \`true\`.", + "name": "showEnteredTextOption", + "optional": true, + "type": "boolean", + }, { "defaultValue": "'finished'", "description": "Specifies the current status of loading more options. diff --git a/src/autosuggest/index.tsx b/src/autosuggest/index.tsx index 05de5d7460c..616c1ea2746 100644 --- a/src/autosuggest/index.tsx +++ b/src/autosuggest/index.tsx @@ -15,7 +15,13 @@ export { AutosuggestProps }; const Autosuggest = React.forwardRef( ( - { filteringType = 'auto', statusType = 'finished', disableBrowserAutocorrect = false, ...props }: AutosuggestProps, + { + filteringType = 'auto', + statusType = 'finished', + disableBrowserAutocorrect = false, + showEnteredTextOption = true, + ...props + }: AutosuggestProps, ref: React.Ref ) => { const baseComponentProps = useBaseComponent('Autosuggest', { @@ -26,6 +32,7 @@ const Autosuggest = React.forwardRef( filteringType, readOnly: props.readOnly, virtualScroll: props.virtualScroll, + showEnteredTextOption, }, }); @@ -43,6 +50,7 @@ const Autosuggest = React.forwardRef( filteringType={filteringType} statusType={statusType} disableBrowserAutocorrect={disableBrowserAutocorrect} + showEnteredTextOption={showEnteredTextOption} {...externalProps} {...baseComponentProps} ref={ref} diff --git a/src/autosuggest/interfaces.ts b/src/autosuggest/interfaces.ts index 0863a04ec40..6c06a435eef 100644 --- a/src/autosuggest/interfaces.ts +++ b/src/autosuggest/interfaces.ts @@ -80,6 +80,12 @@ export interface AutosuggestProps */ enteredTextLabel?: AutosuggestProps.EnteredTextLabel; + /** + * Defines whether entered text option is shown as the first option in the dropdown when value is non-empty. + * Defaults to `true`. + */ + showEnteredTextOption?: boolean; + /** * Specifies the text to display with the number of matches at the bottom of the dropdown menu while filtering. */ diff --git a/src/autosuggest/internal.tsx b/src/autosuggest/internal.tsx index 03b36eac847..25b6cc4872e 100644 --- a/src/autosuggest/internal.tsx +++ b/src/autosuggest/internal.tsx @@ -53,6 +53,7 @@ const InternalAutosuggest = React.forwardRef((props: InternalAutosuggestProps, r ariaLabel, ariaRequired, enteredTextLabel, + showEnteredTextOption, filteringResultsText, onKeyDown, virtualScroll, @@ -91,7 +92,7 @@ const InternalAutosuggest = React.forwardRef((props: InternalAutosuggestProps, r filterText: value, filteringType, enteredTextLabel, - hideEnteredTextLabel: false, + hideEnteredTextLabel: !showEnteredTextOption, onSelectItem: (option: AutosuggestItem) => { const value = option.value || ''; fireNonCancelableEvent(onChange, { value }); @@ -196,6 +197,7 @@ const InternalAutosuggest = React.forwardRef((props: InternalAutosuggestProps, r }); const shouldRenderDropdownContent = !isEmpty || dropdownStatus.content; + const dropdownExpanded = autosuggestItemsState.items.length > 1 || dropdownStatus.content !== null; return ( 1 || dropdownStatus.content !== null} + dropdownExpanded={dropdownExpanded} dropdownContent={ - shouldRenderDropdownContent && ( + shouldRenderDropdownContent && + dropdownExpanded && (