Skip to content

Commit

Permalink
New SelectMenu component (#2665)
Browse files Browse the repository at this point in the history
* Component draft

* Add @floating-ui/react

* Use combobox and listbox role html elements to render selected value and options. Handle option click. Add story with value change

* Allow expanding and collapsing options list

* Use floating-ui wrapper for options list

* Import Select scss file

* Handle expanded state and option change on controlled and uncontrolled component

* Create useSelect hook

* Add placeholder

* Handle defaultExpanded

* Create useFloatingSelect hook

* Add listeners that dismiss (close) the floating element

* Display subject icons

* Add multiple options select

* Remove expanded controlled story, as clicking outside of select closes it automatically. Rename isControlled to isExpandedControlled

* Remove option groups support

* Create SelectOption component. Use useListNavigation

* Layout improvements

* Display caret up on the select when expanded

* Style select element, add story with long label, add support for full width select

* Add spacing between icon and label in the select element

* Adjust popup position when no space available

* Add fallback placement for the popup position

* Add popup offset

* Make select popup scroll when not enough space

* Fix border radius on the select popup

* Add more items to the story

* Remove unused import

* Handle size change, move select display value declaration to the Select component

* Select element sizing. Fix 'defaultExpanded' and 'size' story arg types

* Use custom text sizes, so they match other form elements

* Add isTouchScreen util. Do not allow interactions with outside elements on non-touch screens

* Add disabled state

* Create variants story in mdx

* Add missing aria attribute

* Add valid and invalid states

* Add invariant, cleanup imports order

* Change active border color on valid and invalid states

* Change option padding when multiselect

* Create options floating container so border radius can be applied to scrollbar

* Add white color type

* Add props documentation. Attach onClick event to the component

* Delete redundant mergeRefs function

* Fix variants story select color

* Fix Select colors for hover and expanded states

* Prevent focusing disabled element

* Remove unnecessary import

* Tests

* Do not require onToggle to be defined

* Ensure floating container preserves margins from the screen sides

* Fix popup positioning, add story with different positions

* Add missing fullscreen param

* Add expand and close height transition

* Apply expand and close height animation based on the popup position

* Fix preventing isExpanded change before transition is finished

* Create hook for select animations

* Add scroll only, when options list is bigger than the container

* Do not use default expanded on the positions story

* Use UX motion tokens

* Size popup accordingly to the select element size

* Add story representing different select element and popup widths

* Allow options to fill the whole popup width

* Fix transform origins for another positions

* Animate floating container position

* Animate select icon

* Animate opacity

* Add transition on the select background and border

* Add transition on the option background change

* Fix icon rotation

* Disable scroll when component is animating

* Alter opacity exit animation

* Fix unmounting component delay

* Handle reduce-motion

* Fix small select input paddings

* Do not move popup content on the popup animation

* Preserve space for tick

* Fix invariant

* Always make Select to fill the available space, adjust stories. Handle option change on different lengths story

* Extend options API so it supports regular icons

* Add press feedback to the option

* Add appear animation to subject input label icon

* Fix popup positon when the option list is scrollable

* Add keyboard navigation

* Change animation name

* Add aria label to the select element

* Remove padding, so the container doesn't flip if the select is at the edge of the screen

* Scroll to selected element

* Add tests and apply fixes

* Fix icon size

* Fix checkboxes flickering

* Fix scrollbar appearance

* Hide checkbox input so it doesn't mess up the layout animation

* Fix icon size

* Fix popup expanding over max width

* Do not enable focus on hover

* add accessibility rules

* Change placeholder color

* add status to rules

* open listbox on Space press

* add test about label and description

* Fix scrolled content width issue. Fix popup shadow on reduced motion

* Fix focusing items when the popup is opened by click

* Allow escaping focus out of the popup. Fix roles

* add Windows High Contrast Mode

* add test for listbox

* add Select test for Enter

* darken input placeholder color to increase contrast

* update accessibility rules after fixes

* add aria-multiselectable

* improve tests for SelectOption

* add test: selecting option by pressing enter

* Tests improvements, fixes

* Change funcion

* Tests improvements

* Darken invalid state colors

* Fix caret icon not animating on first click

* Fix select element states styles

* Change story

* Do not use zindex to change overlay display

* Do not block clicking outside of the overlay and hovering elements, when the exit animation plays

* Fix stories height

* Rename SelectNew to SelectMenu

* Change placeholder

* Add snippet with selecting items

* Add chromatic stories

* omit rules with `:not(:hover)` in generating hover styles

* Add hovers and expanded popups chromatic stories

* Fix types in chromatic stories

* Enable disabling chromatic snapshots in a story

* Create chromatic stories for SelectMenu

* Change SelectMenu options in chromatic story, mock function

* Disable user select

* Ensure there's enough space for the popup to display (story)

* Reset popup height to 0 on the animation start

* Parameterise value

* Add sg-* prefix to animate-on-transforms class

* Remove redundant story

* Use English labels

* Cleanup

* Use English labels in chromatic stories

* Upgrade @floating-ui to v0.22.0

* Use CSS variables

* Downgrade @floating-ui/react version as there's a bug with handling keyboard events

* Improve handling keyboard events

* Use waitForElementToBeRemoved() for popup disappearance

* Tests fixes

* Tests fixes

* Chromatic test visual fix

* Fix chromatic story layout

* Cleanup hovers chromatic story

---------

Co-authored-by: katarzynatobis <[email protected]>
  • Loading branch information
domidomi and katarzynatobis authored Mar 21, 2023
1 parent 378e8de commit 02e0063
Show file tree
Hide file tree
Showing 20 changed files with 2,719 additions and 4 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"@aws-sdk/client-lambda": "^3.210.0",
"@codesandbox/sandpack-react": "^1.17.0",
"@codesandbox/sandpack-themes": "^1.17.0",
"@floating-ui/react": "^0.21.1",
"@types/react": "^16.2.0",
"chalk": "4.1.2",
"classnames": "^2.3.2",
Expand Down
6 changes: 5 additions & 1 deletion src/chromatic/HoverStyle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ const generateUnhoveredSelector = (

const hoverSelectorText = selectorText
.split(', ')
.filter(text => text.includes(':hover') || text.includes('--hover'))
.filter(
text =>
(text.includes(':hover') || text.includes('--hover')) &&
!text.includes(':not(:hover)')
)
.map(selector =>
`#${hoverContainerId} ${selector}`
.replace(/:hover/i, '')
Expand Down
6 changes: 5 additions & 1 deletion src/chromatic/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ export const generateChromaticStory: any = (

const mergeStories: any = module => {
const stories = Object.keys(module)
.filter(moduleExports => moduleExports !== 'default')
.filter(
moduleExports =>
moduleExports !== 'default' &&
!module[moduleExports].parameters?.chromatic?.disableSnapshot
)
.map(moduleExportName => {
return {
name: moduleExportName,
Expand Down
163 changes: 163 additions & 0 deletions src/components/select-menu/SelectMenu.chromatic.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import * as React from 'react';
import * as SelectMenuStories from './SelectMenu.stories.mdx';
import {generateChromaticStory} from '../../chromatic/utils';
import SelectMenu, {SIZE as SELECT_SIZE} from './SelectMenu';

import Text from '../text/Text';
import Flex from '../flex/Flex';

const onOptionChange = () => null;

export const Sizes = args => {
return (
<div style={{display: 'flex', flexDirection: 'row'}}>
{Object.values(SELECT_SIZE).map(size => (
<div style={{width: '200px'}} key={size}>
<SelectMenu
{...args}
defaultExpanded
size={size}
onOptionChange={onOptionChange}
/>
</div>
))}
</div>
);
};

export const DifferentPopupLenghts = args => {
return (
<Flex direction="row" style={{gap: '40px'}}>
<div style={{width: '320px'}}>
<div style={{width: '200px'}}>
<Text>Popup with wide content:</Text>
<SelectMenu
options={[
{
value: 'tv',
label: 'I heard about Brainly in a TV commercial',
icon: {
name: 'physics',
isSubjectIcon: true,
},
},
{
value: 'fb',
label: 'Social media',
icon: {
name: 'history',
isSubjectIcon: true,
},
},
{
value: 'search',
label: 'Search engine',
icon: {
name: 'science',
isSubjectIcon: true,
},
},
]}
defaultExpanded
onOptionChange={onOptionChange}
/>
</div>
</div>
<div style={{width: '320px'}}>
<Text>
Popup with short content that stretches to 70% of the input:
</Text>
<SelectMenu
{...args}
withIcons={false}
defaultExpanded
options={[
{
value: 'tv',
label: '1',
},
{value: 'fb', label: '2'},
{
value: 'search',
label: '3',
},
]}
placeholder="Select something from the list"
onOptionChange={onOptionChange}
/>
</div>
<div>
<Text>Popup with short content and short input:</Text>
<div style={{width: '120px'}}>
<SelectMenu
{...args}
withIcons={false}
defaultExpanded
options={[
{
value: 'tv',
label: '1',
},
{value: 'fb', label: '2'},
{
value: 'search',
label: '3',
},
]}
placeholder="Age"
onOptionChange={onOptionChange}
/>
</div>
</div>
</Flex>
);
};

const Hovers = args => {
const types = [{name: 'default'}, {disabled: true, name: 'disabled'}];

return (
<Flex direction="column" style={{gap: '10px'}}>
{types.map(t => (
<Flex
key={t.name}
style={{width: '500px', padding: '10px'}}
justifyContent="space-between"
alignItems="center"
>
{t.name}
<SelectMenu {...args} {...t} onOptionChange={onOptionChange} />
</Flex>
))}
{types.map(t => (
<div key={t.name} style={{background: 'black'}}>
<Flex
style={{width: '500px', padding: '10px'}}
justifyContent="space-between"
alignItems="center"
>
<span style={{color: 'white'}}>White: {t.name}</span>
<SelectMenu
{...args}
{...t}
color="white"
onOptionChange={onOptionChange}
/>
</Flex>
</div>
))}
</Flex>
);
};

export const Default = generateChromaticStory(
{
...SelectMenuStories,
},
{
storiesToHover: [Hovers],
}
);
const {includeStories, ...meta} = SelectMenuStories.default;

export default meta;
Loading

0 comments on commit 02e0063

Please sign in to comment.