feat(DATAUI-3610): add suggest#2596
Conversation
|
Preview is ready. |
|
🎭 Component Tests Report is ready. |
ca4d0eb to
869d946
Compare
313deb2 to
190b2ee
Compare
There was a problem hiding this comment.
I guess input should have clear button?
c4dbafd to
81f826b
Compare
| import {Flex} from '../layout'; | ||
|
|
||
| export type SuggestProps<T> = TextInputProps & { | ||
| items?: ListItemData<T>[]; |
There was a problem hiding this comment.
I would expect Suggest being almost identical to Select in almost every aspect except for the trigger (which is TextInput in this case) and the lack of filter in Popup
So the property should be called options and other props should be copied as is as well (with some exceptions)
I would expect the same visuals and behaviors as well
@amje what do you think?
There's also an inline mode in common's Suggest. Do you plan do add it as well?
There was a problem hiding this comment.
@Ruminat Which props do you want to copy? I agree with the naming of items
There was a problem hiding this comment.
@korvin89 These, I guess:
// at least these props, I guess
Pick<SelectProps,
| "onUpdate"
| "renderOption"
| "renderOptionGroup"
| "renderEmptyOptions"
| "renderPopup"
| "renderCounter"
| "getOptionHeight"
| "getOptionGroupHeight"
| "value"
| "defaultValue"
| "options"
| "error"
| "errorMessage"
| "errorPlacement"
| "validationState"
| "multiple"
| "filter"
| "onFilterChange"
| "disablePortal"
| "loading"
| "onLoadMore"
| "id"
| "hasCounter"
| "renderCounter"
| "disabled"
>
// Would like to see these ones as well
type NiceToHaveProps = {
readonly?: boolean;
inline?: boolean;
};eba7320 to
6e9ebd7
Compare
eaae402 to
79cba7f
Compare
There was a problem hiding this comment.
Please add readme-ru like the other components
| popupClassName?: PopupProps['className']; | ||
| popupPlacement?: PopupProps['placement']; | ||
| popupQa?: PopupProps['qa']; | ||
| popupWidth?: 'fit' | 'auto' | number; |
There was a problem hiding this comment.
Let's make an interface here like in Select
uikit/src/components/Select/types.ts
Line 115 in 436ad28
| import {Flex} from '../layout'; | ||
|
|
||
| export type SuggestProps<T> = TextInputProps & { | ||
| items?: ListItemData<T>[]; |
There was a problem hiding this comment.
Let's probably call it options like in Select
|
|
||
| export type SuggestProps<T> = TextInputProps & { | ||
| items?: ListItemData<T>[]; | ||
| onItemClick?: ListProps<T>['onItemClick']; |
There was a problem hiding this comment.
Accordingly, this is onOptionClick
| popupPlacement?: PopupProps['placement']; | ||
| popupQa?: PopupProps['qa']; | ||
| popupWidth?: 'fit' | 'auto' | number; | ||
| renderItem?: ListProps<T>['renderItem']; |
There was a problem hiding this comment.
renderItem -> renderOption
| ref: React.Ref<HTMLSpanElement>, | ||
| ) { | ||
| const listRef = React.useRef<List<T>>(null); | ||
| const [open, setOpen] = React.useState(false); |
There was a problem hiding this comment.
Let's use useOpenState here
| [textInputProps], | ||
| ); | ||
|
|
||
| const handleKeyDown = React.useCallback( |
There was a problem hiding this comment.
It's probably worth processing the esc click here
|
The component implements a classic combobox pattern (text input + popup list), but the required ARIA markup is missing entirely. At minimum, the <TextInput
controlProps={{
role: 'combobox',
'aria-expanded': open,
'aria-controls': popupId,
'aria-autocomplete': 'list',
'aria-activedescendant': activeIndex !== undefined
? `${popupId}-item-${activeIndex}`
: undefined,
}}
...
<Popup id={popupId} ...>
<List .../>
</Popup>
/> |
| @@ -0,0 +1 @@ | |||
| export {Suggest} from './Suggest'; | |||
| import {Suggest} from '@gravity-ui/uikit'; | ||
| ``` | ||
|
|
||
| `Suggest` is a lightweight building block for “type to filter + popup list” scenarios. It renders a `TextInput` and a |
There was a problem hiding this comment.
Add this sentence please: Suggest is a basic implementation of "combobox" pattern
| `Suggest` supports all `TextInput` props. The table below lists the props specific to `Suggest`: | ||
|
|
||
| | Name | Description | Default | Type | | ||
| | :------------- | :-------------------------------------------------- | :------ | :----------------------------------------------------- | |
There was a problem hiding this comment.
Please use the same table structure as in all other readmes: Name, Description, Type, Default, where Type and Default are center aligned
| | Name | Description | Default | Type | | ||
| | :------------- | :-------------------------------------------------- | :------ | :----------------------------------------------------- | | ||
| | items | Items rendered by `List` | | `Array<ListItemData<T>>` | | ||
| | onItemClick | Fires when list item is clicked | | `ListProps<T>['onItemClick']` | |
There was a problem hiding this comment.
Maybe we shouldn't expose List types, it will be deprecated soon, lets' just copy them
| title: 'Components/Inputs/Suggest', | ||
| component: Suggest, | ||
| argTypes: {}, | ||
| parameters: {}, |
| }; | ||
|
|
||
| export const Default: Story = { | ||
| render: () => { |
There was a problem hiding this comment.
You should pass args from here to the component props
| const items = React.useMemo(() => baseFilter(value), [value]); | ||
| const handelItemClick = React.useCallback((item: TItem) => { | ||
| setValue(item.content); | ||
| console.log('onItemClick', item); |
There was a problem hiding this comment.
Instead of using console.log use Storybook's dedicated actions
| render: () => { | ||
| const [value, setValue] = React.useState(''); | ||
| return ( | ||
| <Flex direction="column" gap={4}> |
There was a problem hiding this comment.
For stories layout we have Showcase* components. Please use them
| onUpdate={setValue} | ||
| placeholder="Search..." | ||
| renderItem={(item) => <div>{item.content}</div>} | ||
| value={value} |
There was a problem hiding this comment.
Instead of repeating props, utilize Storybook's args for story. Pass common props to the Default story, and then reuse them in other stories. See Button's stories as a reference
There was a problem hiding this comment.
You should rebase main branch, test names are different now
| const smokeScenarios = createSmokeScenarios<TestSuggestProps>(defaultProps, { | ||
| size: ['s', 'm', 'l', 'xl'], | ||
| disabled: [true], | ||
| hasClear: [true], |
There was a problem hiding this comment.
That's incorrect usage. Please follow the same structure as in other tests
| await expectScreenshot({themes: ['light']}); | ||
| }); | ||
|
|
||
| test('smoke opened', {tag: ['@smoke']}, async ({mount, page, expectScreenshot}) => { |
There was a problem hiding this comment.
Why it's a separate smoke test?
| await expectScreenshot({themes: ['light']}); | ||
| }); | ||
|
|
||
| test('smoke customPopup', {tag: ['@smoke']}, async ({mount, page, expectScreenshot}) => { |
There was a problem hiding this comment.
That's not a smoke test. Smoke test is just simple snapshot of props combinations. For custom popup do a normal visual test


No description provided.