This repository has been archived by the owner on Mar 13, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* WIP * [MM-28199] Dropdown Input Common Component * Remove commented code * Inset focus borders * More CSS fixes * Refactor to use classnames * Blank line * Added cursor:pointer for the input and menu Co-authored-by: Mattermod <[email protected]>
- Loading branch information
1 parent
abe2586
commit f8e7fc9
Showing
6 changed files
with
244 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
.DropdownInput { | ||
&.Input_container { | ||
margin-top: 20px; | ||
} | ||
|
||
.Input_wrapper { | ||
padding: 0 1px; | ||
} | ||
|
||
.Input { | ||
font-size: 14px; | ||
line-height: 20px; | ||
|
||
&.Input___focus .a11y--focused { | ||
box-shadow: none; | ||
} | ||
} | ||
|
||
.Input_legend { | ||
margin-left: 8px; | ||
} | ||
} | ||
|
||
.DropdownInput__indicatorsContainer { | ||
margin-right: 8px; | ||
|
||
i { | ||
color: rgba(var(--center-channel-color-rgb), 0.64); | ||
font-weight: normal; | ||
|
||
&::before { | ||
margin: 0; | ||
} | ||
} | ||
} | ||
|
||
.DropdownInput__option > div { | ||
padding: 10px 24px; | ||
line-height: 16px; | ||
cursor: pointer; | ||
} | ||
|
||
.DropdownInput__option.selected > div { | ||
background-color: rgba(var(--button-bg-rgb), 0.08); | ||
color: var(--center-channel-color); | ||
} | ||
|
||
.DropdownInput__option.focused > div { | ||
background-color: rgba(var(--center-channel-color-rgb), 0.08); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||
// See LICENSE.txt for license information. | ||
|
||
import React, {useState, CSSProperties} from 'react'; | ||
import ReactSelect, {Props as SelectProps, ActionMeta, components} from 'react-select'; | ||
import classNames from 'classnames'; | ||
|
||
import './dropdown_input.scss'; | ||
|
||
// TODO: This component needs work, should not be used outside of AddressInfo until this comment is removed. | ||
|
||
type ValueType = { | ||
label: string; | ||
value: string; | ||
} | ||
|
||
type Props<T> = Omit<SelectProps<T>, 'onChange'> & { | ||
value?: T; | ||
legend?: string; | ||
error?: string; | ||
onChange: (value: T, action: ActionMeta<T>) => void; | ||
}; | ||
|
||
const baseStyles = { | ||
input: (provided: CSSProperties) => ({ | ||
...provided, | ||
color: 'var(--center-channel-color)', | ||
}), | ||
control: (provided: CSSProperties) => ({ | ||
...provided, | ||
border: 'none', | ||
boxShadow: 'none', | ||
padding: '0 2px', | ||
cursor: 'pointer', | ||
}), | ||
indicatorSeparator: (provided: CSSProperties) => ({ | ||
...provided, | ||
display: 'none', | ||
}), | ||
}; | ||
|
||
const IndicatorsContainer = (props: any) => { | ||
return ( | ||
<div className='DropdownInput__indicatorsContainer'> | ||
<components.IndicatorsContainer {...props}> | ||
<i className='icon icon-chevron-down'/> | ||
</components.IndicatorsContainer> | ||
</div> | ||
); | ||
}; | ||
|
||
const Option = (props: any) => { | ||
return ( | ||
<div | ||
className={classNames('DropdownInput__option', { | ||
selected: props.isSelected, | ||
focused: props.isFocused, | ||
})} | ||
> | ||
<components.Option {...props}/> | ||
</div> | ||
); | ||
}; | ||
|
||
const renderError = (error?: string) => { | ||
if (!error) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<div className='Input___error'> | ||
<i className='icon icon-alert-outline'/> | ||
<span>{error}</span> | ||
</div> | ||
); | ||
}; | ||
|
||
const DropdownInput = <T extends ValueType>(props: Props<T>) => { | ||
const {value, placeholder, className, addon, name, textPrefix, legend, onChange, styles, options, error, ...otherProps} = props; | ||
|
||
const [focused, setFocused] = useState(false); | ||
|
||
const onInputFocus = (event: React.FocusEvent<HTMLElement>) => { | ||
const {onFocus} = props; | ||
|
||
setFocused(true); | ||
|
||
if (onFocus) { | ||
onFocus(event); | ||
} | ||
}; | ||
|
||
const onInputBlur = (event: React.FocusEvent<HTMLElement>) => { | ||
const {onBlur} = props; | ||
|
||
setFocused(false); | ||
|
||
if (onBlur) { | ||
onBlur(event); | ||
} | ||
}; | ||
|
||
const showLegend = Boolean(focused || value); | ||
|
||
return ( | ||
<div className='DropdownInput Input_container'> | ||
<fieldset | ||
className={classNames('Input_fieldset', className, { | ||
Input_fieldset___error: error, | ||
Input_fieldset___legend: showLegend, | ||
})} | ||
> | ||
<legend className={classNames('Input_legend', {Input_legend___focus: showLegend})}> | ||
{showLegend ? (legend || placeholder) : null} | ||
</legend> | ||
<div | ||
className='Input_wrapper' | ||
onFocus={onInputFocus} | ||
onBlur={onInputBlur} | ||
> | ||
{textPrefix && <span>{textPrefix}</span>} | ||
<ReactSelect | ||
id={`DropdownInput_${name}`} | ||
options={options} | ||
placeholder={focused ? '' : placeholder} | ||
components={{ | ||
IndicatorsContainer, | ||
Option, | ||
}} | ||
className={classNames('Input', className, {Input__focus: showLegend})} | ||
value={value} | ||
onChange={onChange as any} // types are not working correctly for multiselect | ||
styles={{...baseStyles, ...styles}} | ||
{...otherProps} | ||
/> | ||
</div> | ||
{addon} | ||
</fieldset> | ||
{renderError(error)} | ||
</div> | ||
); | ||
}; | ||
|
||
export default DropdownInput; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters