Skip to content
This repository has been archived by the owner on Jun 11, 2021. It is now read-only.

Commit

Permalink
Improve select/modal/drawer (#190)
Browse files Browse the repository at this point in the history
* Improve select/modal/drawer

* fix test

* document
  • Loading branch information
jean9696 authored Mar 1, 2019
1 parent e918798 commit b1f69ac
Show file tree
Hide file tree
Showing 15 changed files with 92 additions and 41 deletions.
1 change: 1 addition & 0 deletions src/Drawer/Drawer.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ export default interface DrawerInterface {
closeButton?: React.ReactNode | ((props: InjectedRenderProps) => JSX.Element)
open: boolean
onClose: (e: React.FormEvent<HTMLInputElement>) => void
portal?: boolean
}
14 changes: 11 additions & 3 deletions src/Drawer/Drawer.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { PureComponent } from 'react'
import { createPortal } from 'react-dom'

import { isFunction } from '../_internal/data'

Expand All @@ -21,7 +22,8 @@ class Drawer extends PureComponent<DrawerProps> {

static defaultProps = {
open: false,
position: 'right'
position: 'right',
portal: true
}

constructor (props) {
Expand Down Expand Up @@ -101,10 +103,10 @@ class Drawer extends PureComponent<DrawerProps> {
}

render () {
const { children, title, closeButton, ...props } = this.props
const { children, title, closeButton, portal, ...props } = this.props
const currentState = this.getCurrentState()

return (
const drawer = (
<Overlay data-state={currentState} onClick={this.handleClick}>
<div ref={this.ref} onClick={e => e.stopPropagation()}>
<DrawerContainer data-state={currentState} {...props}>
Expand All @@ -121,6 +123,12 @@ class Drawer extends PureComponent<DrawerProps> {
</div>
</Overlay>
)

if (portal && typeof document === 'object') {
return createPortal(drawer, document.body)
}

return drawer
}
}

Expand Down
1 change: 1 addition & 0 deletions src/Modal/Modal.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ export default interface ModalProps extends CardProps {
open: boolean
onClose: (e: React.FormEvent<HTMLInputElement>) => void
animated?: boolean
portal?: boolean
}
14 changes: 11 additions & 3 deletions src/Modal/Modal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { Fragment, PureComponent } from 'react'
import { createPortal } from 'react-dom'

import { isFunction } from '../_internal/data'

Expand All @@ -21,7 +22,8 @@ class Modal extends PureComponent<ModalProps> {
static defaultProps = {
open: false,
persistent: false,
animated: true
animated: true,
portal: true
}

static getDerivedStateFromProps (nextProps) {
Expand Down Expand Up @@ -117,10 +119,10 @@ class Modal extends PureComponent<ModalProps> {
}

render () {
const { children, title, open, closeButton, animated, ...props } = this.props
const { children, title, open, closeButton, animated, portal, ...props } = this.props
const currentState = this.getCurrentState()

return (
const modal = (
<Fragment>
<Overlay data-state={currentState} onClick={this.handleClick}>
<div ref={this.ref} onClick={e => e.stopPropagation()}>
Expand All @@ -137,6 +139,12 @@ class Modal extends PureComponent<ModalProps> {
{open && <RemoveBodyScroll />}
</Fragment>
)

if (portal && typeof document === 'object') {
createPortal(modal, document.body)
}

return modal
}
}

Expand Down
1 change: 1 addition & 0 deletions src/Select/Option/Option.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export default interface OptionProps extends DOMNode {
compact: boolean
label: string
selected: boolean
disabled: boolean
}
12 changes: 10 additions & 2 deletions src/Select/Option/Option.style.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import styled from 'styled-components'
import styled, { css } from 'styled-components'

import fontSizes from '../../fontSizes'
import { getMainColor } from '../../_internal/colors'
Expand All @@ -22,7 +22,15 @@ export const OptionContainer = styled.div`
&:hover,
&:focus,
&[data-selected="true"] {
&[data-selected="true"]{
background-color: ${props => getMainColor(props, { themeKey: 'neutralLighter' })};
}
&[disabled] {
opacity: 0.5;
user-focus: none;
&:hover, &:focus {
background-color: transparent;
cursor: auto;
}
}
`
3 changes: 2 additions & 1 deletion src/Select/Option/Option.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,14 @@ class Option extends React.Component<OptionProps> {
}

render () {
const { multi, label, selected, ...props } = this.props
const { multi, label, selected, disabled, ...props } = this.props
return (
<OptionContainer
{...props}
data-selected={selected}
ref={this.ref}
tabIndex='0'
disabled={disabled}
>
{multi && <Toggle state={selected ? 'full' : 'empty'} />}
{ label }
Expand Down
2 changes: 2 additions & 0 deletions src/Select/Options/Options.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@ export default interface OptionsProps {
selectAllLabel?: string
allSelected: boolean
onClose: () => void
optionDisabled: (option: any) => boolean
wrapperWidth?: number
}
7 changes: 4 additions & 3 deletions src/Select/Options/Options.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,18 @@ import Option from '../Option'
import colors from '../../colors'

export const OptionsContainer = styled.div`
position: fixed;
box-shadow: ${shadows.light};
position: absolute;
top: calc(100% - 1px);
opacity: 0;
overflow: hidden;
margin-top: -1px;
background-color: #ffffff;
border-radius: 0 0 4px 4px;
border-top: 1px solid ${props => getMainColor(props, { themeKey: 'neutral' })};
max-height: 0;
min-width: 100%;
min-width: ${({ minWidth }) => minWidth ? `${minWidth}px` : 'auto'};
z-index: 5;
transition: all ease-in-out 300ms;
Expand Down
32 changes: 19 additions & 13 deletions src/Select/Options/Options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ const Options: React.StatelessComponent<OptionsProps> = ({
onSelectAll,
canSelectAll,
selectAllLabel,
onClose
onClose,
optionDisabled,
wrapperWidth
}) => {
const isSmallScreen = useIsSmallScreen()

Expand All @@ -54,17 +56,21 @@ const Options: React.StatelessComponent<OptionsProps> = ({
label={selectAllLabel || 'Select all'}
/>
)}
{options.map(option => (
<Option
key={option.value}
selected={isOptionSelected(option)}
onClick={() => onSelect(option)}
focused={option === focusedItem}
multi={multi}
compact={compact}
{...option}
/>
))}
{options.map(option => {
const disabled = optionDisabled(option)
return (
<Option
key={option.value}
selected={isOptionSelected(option)}
onClick={() => !disabled ? onSelect(option) : null}
focused={option === focusedItem}
multi={multi}
compact={compact}
disabled={disabled}
{...option}
/>
)
})}
</React.Fragment>
) : (
<EmptyOptions>Aucune option</EmptyOptions>
Expand All @@ -88,7 +94,7 @@ const Options: React.StatelessComponent<OptionsProps> = ({
}

return (
<OptionsContainer data-open={open}>
<OptionsContainer data-open={open} minWidth={wrapperWidth}>
{content}
</OptionsContainer>
)
Expand Down
3 changes: 3 additions & 0 deletions src/Select/Select.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export default interface SelectProps extends Input<any> {
multi?: boolean
canSelectAll?: boolean
selectAllLabel?: string

optionDisabled?: (option: any) => boolean
}

export interface SelectState {
Expand All @@ -28,4 +30,5 @@ export interface SelectState {
rawValue: any,
options: formOption[],
value: any | any[]
wrapperWidth?: number
}
3 changes: 3 additions & 0 deletions src/Select/Select.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,6 @@ storiesOf('Inputs/Select', module)
.add('multi items with select all', () => (
<SelectWithState multi canSelectAll />
))
.add('with disabled options', () => (
<SelectWithState optionDisabled={option => option.value > 1} />
))
8 changes: 8 additions & 0 deletions src/Select/Select.style.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,11 @@ export const ResetIcon = styled(FontIcon)`
opacity: 0;
}
`

export const Overlay = styled.div`
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
`
26 changes: 13 additions & 13 deletions src/Select/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import {
LabelIcons,
CustomIconContainer,
Placeholder,
ResetIcon
ResetIcon,
Overlay
} from './Select.style'

const INTERNAL_PROPS = [
Expand All @@ -46,7 +47,8 @@ export class BaseSelect extends React.Component<SelectProps, SelectState> {
multi: false,
canReset: true,
filterable: false,
compact: false
compact: false,
optionDisabled: () => false
}

static getDerivedStateFromProps (nextProps, prevState) {
Expand Down Expand Up @@ -97,16 +99,16 @@ export class BaseSelect extends React.Component<SelectProps, SelectState> {
rawOptions: null,
rawValue: null,
options: null,
value: this.props.multi ? [] : null
value: this.props.multi ? [] : null,
wrapperWidth: null
}

componentDidMount () {
window.addEventListener('click', this.handleClickOutside)
this.setState({ wrapperWidth: this.wrapperRef.current.clientWidth })
window.addEventListener('keydown', this.handleKeyDown)
}

componentWillUnmount () {
window.removeEventListener('click', this.handleClickOutside)
window.removeEventListener('keydown', this.handleKeyDown)
}

Expand Down Expand Up @@ -189,12 +191,6 @@ export class BaseSelect extends React.Component<SelectProps, SelectState> {
return options.length === value.length
}

handleClickOutside = () => {
if (this.wrapperRef && !this.wrapperRef.current.contains(event.target) && this.state.open) {
this.handleToggle()
}
}

handleKeyDown = event => {
const { open, focusedItem } = this.state
const { key } = event
Expand Down Expand Up @@ -294,7 +290,7 @@ export class BaseSelect extends React.Component<SelectProps, SelectState> {
}

render () {
const { open, search, focusedItem } = this.state
const { open, search, focusedItem, wrapperWidth } = this.state
const {
multi,
description,
Expand All @@ -306,7 +302,8 @@ export class BaseSelect extends React.Component<SelectProps, SelectState> {
filterable,
compact,
canSelectAll,
selectAllLabel
selectAllLabel,
optionDisabled
} = this.props

const safeProps = omit(this.props, INTERNAL_PROPS)
Expand Down Expand Up @@ -361,7 +358,9 @@ export class BaseSelect extends React.Component<SelectProps, SelectState> {
<FontIcon icon={open ? 'arrow_drop_up' : 'arrow_drop_down'} color={darkColor} />
</LabelIcons>
</SelectContent>
{open && <Overlay onClick={this.handleToggle}/>}
<Options
optionDisabled={optionDisabled}
options={options}
open={open}
multi={multi}
Expand All @@ -376,6 +375,7 @@ export class BaseSelect extends React.Component<SelectProps, SelectState> {
canSelectAll={!!canSelectAll}
selectAllLabel={selectAllLabel}
onClose={this.handleToggle}
wrapperWidth={wrapperWidth}
/>
</SelectContainer>
)
Expand Down
6 changes: 3 additions & 3 deletions src/TextInput/TextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { getMainColor } from '../_internal/colors'
import TextInputProps from './TextInput.interface'
import { InputContainer, Input, InputSpinner, RightElementContainer } from './TextInput.style'

const BaseTextInput: React.StatelessComponent<TextInputProps> = props => {
const BaseTextInput: React.ComponentType<TextInputProps & React.ClassAttributes<any>> = React.forwardRef((props, ref) => {
const {
onChange,
value,
Expand All @@ -31,7 +31,7 @@ const BaseTextInput: React.StatelessComponent<TextInputProps> = props => {
<Input
value={value}
onChange={e => onChange(e.target.value)}
ref={inputRef}
ref={inputRef || ref}
loading={loading}
disabled={disabled}
placeholder={placeholder}
Expand All @@ -55,7 +55,7 @@ const BaseTextInput: React.StatelessComponent<TextInputProps> = props => {
}
</InputContainer>
)
}
})

BaseTextInput.defaultProps = {
onChange: () => null
Expand Down

0 comments on commit b1f69ac

Please sign in to comment.