Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
38f8960
initial setup for SearchAutocomplete
reidbarber Aug 10, 2021
62f3510
fix autocomplete hook logic and input render
reidbarber Aug 23, 2021
8aff449
added more stories
reidbarber Aug 23, 2021
db37d94
add docs for SearchAutocomplete
reidbarber Aug 23, 2021
6fa39ae
always allow custom value
reidbarber Aug 23, 2021
6d3c234
fix lint
reidbarber Aug 23, 2021
017028e
Merge branch 'main' into Issue-2084-SearchAutoComplete
reidbarber Aug 23, 2021
01dfd2a
fix autocomplete type
reidbarber Aug 24, 2021
a3aa51c
fix onSubmit action
reidbarber Aug 24, 2021
93a02d1
fix input styles
reidbarber Aug 26, 2021
59555cd
handle onSubmit event
reidbarber Aug 27, 2021
87ea309
add Sections example to docs
reidbarber Aug 27, 2021
1caa8f1
set selectionMode: none on listbox
reidbarber Aug 27, 2021
64781eb
add story actions
reidbarber Aug 27, 2021
529f990
add mobile support
reidbarber Aug 27, 2021
60628c6
add search icon to mobile tray
reidbarber Aug 27, 2021
8fd3e7a
remove default onSubmit
reidbarber Aug 30, 2021
7d66d63
fix search styles
reidbarber Aug 30, 2021
81c62fd
add clear button to mobile trigger input
reidbarber Aug 30, 2021
ab98be9
add i18n formatted strings
reidbarber Aug 30, 2021
bdf85a9
fix state hook use
reidbarber Aug 30, 2021
235ef02
Merge branch 'main' into Issue-2084-SearchAutoComplete
reidbarber Aug 31, 2021
71344fb
update imports in docs
reidbarber Aug 31, 2021
e3ba038
add default onSubmit
reidbarber Aug 31, 2021
817eb74
fix lint
reidbarber Aug 31, 2021
0c53302
fix double focus/blur
reidbarber Sep 7, 2021
15889f0
fix onSubmit logic
reidbarber Sep 7, 2021
8a6cfd6
clearnup useSearchAutocomplete
reidbarber Sep 7, 2021
44fa1cf
update story format
reidbarber Sep 7, 2021
938127c
fix lint
reidbarber Sep 7, 2021
2bc9e4d
fix import change
reidbarber Sep 7, 2021
b503389
add chromatic stories
reidbarber Sep 7, 2021
f5baffc
add useSearchAutocomplete docs
reidbarber Sep 13, 2021
9b1f910
fix after_version
reidbarber Sep 13, 2021
d7ee865
fix labelProps used in hook
reidbarber Sep 14, 2021
1a31270
fix onSubmit handling
reidbarber Sep 14, 2021
2ec58e2
update searchfield deps
reidbarber Sep 14, 2021
778d7bc
add SearchAutocomplete tests
reidbarber Sep 14, 2021
47e8e02
fix lint
reidbarber Sep 14, 2021
17790c2
remove yarn-error.log
reidbarber Sep 14, 2021
c737701
Merge branch 'main' into Issue-2084-SearchAutoComplete
reidbarber Sep 14, 2021
8b803d0
fix SearchAutocomplete docs
reidbarber Sep 15, 2021
5c544af
fix useSearchAutocomplete docs
reidbarber Sep 15, 2021
3a8006f
update Arabic loading translation
reidbarber Sep 15, 2021
746105b
fix SearchAutocomplete stories
reidbarber Sep 15, 2021
96f463a
fix SearchAutocomplete typos
reidbarber Sep 15, 2021
37193a5
set null selectedKey and defaultSelectedKey
reidbarber Sep 15, 2021
172f8a3
update example to use onSubmit
reidbarber Sep 15, 2021
d31811c
fixed controlled useSearchAutocomplete example
reidbarber Sep 15, 2021
02b5a7b
set selectKey props to undefined
reidbarber Sep 15, 2021
60a6ad5
add own styles instead of using combobox's
reidbarber Sep 15, 2021
513213f
remove selectedkey chromatic story
reidbarber Sep 15, 2021
cca6148
cleanup hook useage in mobile
reidbarber Sep 15, 2021
d8f82d7
cleanup onSubmit call
reidbarber Sep 15, 2021
4949e4e
fix RTL chromatic
reidbarber Sep 15, 2021
191f003
fix lint
reidbarber Sep 16, 2021
9a12c40
fix typescript
reidbarber Sep 16, 2021
d75a1b3
close tray and fire onSubmit w/ Enter on mobile
reidbarber Sep 17, 2021
bcef68f
fix react-spectrum/searchfield deps
reidbarber Sep 20, 2021
d259ae3
fix react-aria/searchfield deps
reidbarber Sep 20, 2021
9b3fe99
fix lint
reidbarber Sep 20, 2021
1a43c00
fix self dep
reidbarber Sep 20, 2021
8586c75
Merge branch 'main' into Issue-2084-SearchAutoComplete
reidbarber Sep 20, 2021
c1b47ee
fix searchfield type dep
reidbarber Sep 20, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
596 changes: 596 additions & 0 deletions packages/@react-aria/searchfield/docs/useSearchAutocomplete.mdx

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions packages/@react-aria/searchfield/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@
},
"dependencies": {
"@babel/runtime": "^7.6.2",
"@react-aria/combobox": "^3.0.1",
"@react-aria/i18n": "^3.3.2",
"@react-aria/interactions": "^3.6.0",
"@react-aria/listbox": "^3.3.1",
"@react-aria/textfield": "^3.4.0",
"@react-aria/utils": "^3.9.0",
"@react-stately/combobox": "^3.0.1",
"@react-stately/searchfield": "^3.1.3",
"@react-types/button": "^3.4.1",
"@react-types/searchfield": "^3.1.2",
Expand Down
1 change: 1 addition & 0 deletions packages/@react-aria/searchfield/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@
*/

export * from './useSearchField';
export * from './useSearchAutocomplete';
97 changes: 97 additions & 0 deletions packages/@react-aria/searchfield/src/useSearchAutocomplete.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Copyright 2020 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/

import {AriaButtonProps} from '@react-types/button';
import {AriaListBoxOptions} from '@react-aria/listbox';
import {ComboBoxState} from '@react-stately/combobox';
import {HTMLAttributes, InputHTMLAttributes, RefObject} from 'react';
import {KeyboardDelegate} from '@react-types/shared';
import {mergeProps} from '@react-aria/utils';
import {SearchAutocompleteProps} from '@react-types/searchfield';
import {useComboBox} from '@react-aria/combobox';
import {useSearchField} from './useSearchField';

interface AriaSearchAutocompleteProps<T> extends SearchAutocompleteProps<T> {
/** The ref for the input element. */
inputRef: RefObject<HTMLInputElement | HTMLTextAreaElement>,
/** The ref for the list box popover. */
popoverRef: RefObject<HTMLDivElement>,
/** The ref for the list box. */
listBoxRef: RefObject<HTMLElement>,
/** An optional keyboard delegate implementation, to override the default. */
keyboardDelegate?: KeyboardDelegate
}

interface SearchAutocompleteAria<T> {
/** Props for the label element. */
labelProps: HTMLAttributes<HTMLElement>,
/** Props for the search input element. */
inputProps: InputHTMLAttributes<HTMLInputElement>,
/** Props for the list box, to be passed to [useListBox](useListBox.html). */
listBoxProps: AriaListBoxOptions<T>,
/** Props for the search input's clear button. */
clearButtonProps: AriaButtonProps
}

/**
* Provides the behavior and accessibility implementation for a search autocomplete component.
* A search autocomplete combines a combobox with a searchfield, allowing users to filter a list of options to items matching a query.
* @param props - Props for the search autocomplete.
* @param state - State for the search autocomplete, as returned by `useSearchAutocomplete`.
*/
export function useSearchAutocomplete<T>(props: AriaSearchAutocompleteProps<T>, state: ComboBoxState<T>): SearchAutocompleteAria<T> {
let {
popoverRef,
inputRef,
listBoxRef,
keyboardDelegate,
onSubmit = () => {}
} = props;

let {inputProps, clearButtonProps} = useSearchField({
...props,
value: state.inputValue,
onChange: state.setInputValue,
autoComplete: 'off',
onClear: () => state.setInputValue(''),
onSubmit: (value) => {
// Prevent submission from search field if menu item was selected
if (state.selectionManager.focusedKey === null) {
onSubmit(value, null);
}
}
}, {
value: state.inputValue,
setValue: state.setInputValue
}, inputRef);


let {listBoxProps, labelProps, inputProps: comboBoxInputProps} = useComboBox(
Comment thread
reidbarber marked this conversation as resolved.
{
...props,
keyboardDelegate,
popoverRef,
listBoxRef,
inputRef,
onFocus: undefined,
onBlur: undefined
},
state
);

return {
labelProps,
inputProps: mergeProps(inputProps, comboBoxInputProps),
listBoxProps,
clearButtonProps
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
* Copyright 2020 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/

import {generatePowerset} from '@react-spectrum/story-utils';
import {Grid, repeat} from '@react-spectrum/layout';
import {Item, SearchAutocomplete} from '../';
import {Meta, Story} from '@storybook/react';
import React from 'react';
import {SpectrumSearchAutocompleteProps} from '@react-types/searchfield';

// Skipping focus styles because don't have a way of applying it via classnames
// No controlled open state also means no menu
let states = [
{isQuiet: true},
{isReadOnly: true},
{isDisabled: true},
{validationState: ['valid', 'invalid']},
{isRequired: true},
{necessityIndicator: 'label'}
];

let combinations = generatePowerset(states);

function shortName(key, value) {
let returnVal = '';
switch (key) {
case 'isQuiet':
returnVal = 'quiet';
break;
case 'isReadOnly':
returnVal = 'ro';
break;
case 'isDisabled':
returnVal = 'disable';
break;
case 'validationState':
returnVal = `vs ${value}`;
break;
case 'isRequired':
returnVal = 'req';
break;
case 'necessityIndicator':
returnVal = 'necInd=label';
break;
}
return returnVal;
}

const meta: Meta<SpectrumSearchAutocompleteProps<object>> = {
title: 'SearchAutocomplete',
parameters: {
chromaticProvider: {colorSchemes: ['light', 'dark', 'lightest', 'darkest'], locales: ['en-US'], scales: ['medium', 'large']}
}
};

export default meta;

let items = [
{name: 'Aardvark', id: '1'},
{name: 'Kangaroo', id: '2'},
{name: 'Snake', id: '3'}
];

const Template: Story<SpectrumSearchAutocompleteProps<object>> = (args) => (
<Grid columns={repeat(4, '1fr')} autoFlow="row" gap="size-200">
{combinations.map(c => {
let key = Object.keys(c).map(k => shortName(k, c[k])).join(' ');
if (!key) {
key = 'empty';
}

return (
<SearchAutocomplete key={key} {...args} {...c} label={args['aria-label'] ? undefined : key} defaultItems={items}>
{(item: any) => <Item>{item.name}</Item>}
</SearchAutocomplete>
);
})}
</Grid>
);

// Chromatic can't handle the size of the side label story so removed some extraneous props that don't matter for side label case.
const TemplateSideLabel: Story<SpectrumSearchAutocompleteProps<object>> = (args) => (
<Grid columns={repeat(2, '1fr')} autoFlow="row" gap="size-200" width={800}>
{combinations.filter(combo => !(combo.isReadOnly || combo.isDisabled)).map(c => {
let key = Object.keys(c).map(k => shortName(k, c[k])).join(' ');
if (!key) {
key = 'empty';
}

return (
<SearchAutocomplete key={key} {...args} {...c} label={key} defaultItems={items}>
{(item: any) => <Item>{item.name}</Item>}
</SearchAutocomplete>
);
})}
</Grid>
);

export const PropDefaults = Template.bind({});
PropDefaults.storyName = 'default';
PropDefaults.args = {};

export const PropInputValue = Template.bind({});
PropInputValue.storyName = 'inputValue: Blah';
PropInputValue.args = {inputValue: 'Blah'};

export const PropAriaLabelled = Template.bind({});
PropAriaLabelled.storyName = 'aria-label';
PropAriaLabelled.args = {'aria-label': 'Label'};

export const PropLabelEnd = Template.bind({});
PropLabelEnd.storyName = 'label end';
PropLabelEnd.args = {...PropDefaults.args, labelAlign: 'end'};

export const PropLabelSide = TemplateSideLabel.bind({});
PropLabelSide.storyName = 'label side';
PropLabelSide.args = {...PropDefaults.args, labelPosition: 'side'};

export const PropCustomWidth = Template.bind({});
PropCustomWidth.storyName = 'custom width';
PropCustomWidth.args = {...PropDefaults.args, width: 'size-1600'};
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright 2020 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/

import {Meta} from '@storybook/react';

// Original SearchAutocomplete chromatic story was too large to be processed
const meta: Meta = {
title: 'SearchAutocompleteRTL',
parameters: {
chromaticProvider: {colorSchemes: ['light', 'dark', 'lightest', 'darkest'], locales: ['ar-AE'], scales: ['medium', 'large']}
}
};

export default meta;

export {PropDefaults, PropInputValue, PropAriaLabelled, PropLabelEnd, PropLabelSide, PropCustomWidth} from './SearchAutocomplete.chromatic';
Loading