Skip to content

Commit

Permalink
feat: Add readOnly prop to SelectField and make MultiSelectField use …
Browse files Browse the repository at this point in the history
…it instead of custom div
  • Loading branch information
HriBB committed Aug 20, 2016
1 parent 8e0993a commit a82a4e4
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 93 deletions.
39 changes: 23 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
# React-MDL SelectField

> Selectfield component for [React Material Design Lite](https://github.com/tleunen/react-mdl)
Selectfield component for [React Material Design Lite](https://github.com/tleunen/react-mdl)

## Installation

```
npm install --save react-mdl-selectfield
```

## Examples

https://hribb.github.io/react-mdl-selectfield/

## Installation

```
npm install --save react-mdl-selectfield
git clone https://github.com/HriBB/react-mdl-selectfield
cd react-mdl-selectfield
npm install
npm run storybook
open http://localhost:9002/
```


## Usage

```
Expand All @@ -30,7 +39,10 @@ render() {
}
```

NOTE: `<Option>` component requires a string `children` prop for filtering.
`<Option>` component requires a string `children` prop for filtering to work.
This sucks, because you cannot put anything complex (such as `Icon`) inside `Option`.
That is why `AutoCompleteField` component is on its way ;)
Until then you should stringify your `<Option>` children:

```
<SelectField label={'Select me'} editable>
Expand All @@ -42,19 +54,14 @@ NOTE: `<Option>` component requires a string `children` prop for filtering.
</SelectField>
```

## Development
## TODO

```
cd react-mdl-selectfield/
npm install
npm run storybook
```
- [x] Add `readOnly` prop to `SelectField` and `MultiSelectField`
- [ ] Make `SelectField` and `MultiSelectField` completely stateless?
- [ ] Create `AutoCompleteField`
- [x] Pray for a good `Selectfield` in [`mdl v2`](https://github.com/google/material-design-lite/issues/4475)

## Component boilerplate

Using [react-component-boilerplate](https://github.com/ritz078/react-component-boilerplate)

## TODO

- [ ] Add readOnly to `MultiSelectField`
- [ ] Make both `SelectField` and `MultiSelectField` stateless
with some modifications and improvements.
35 changes: 14 additions & 21 deletions src/MultiSelectField/MultiSelectField.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,27 +91,20 @@ export default class MultiSelectField extends Component {
return (
<div className={mainClass}>

{readOnly &&
<div className={'mdl-textfield mdl-textfield--readOnly'}>
<div className={'mdl-textfield__input'}>
{label}
</div>
</div>}

{!readOnly &&
<SelectField
floatingLabel={floatingLabel}
label={label}
multiple
error={error}
editable={editable}
skipValues={value}
onFocus={onFocus}
onBlur={onBlur}
onChange={this.onSelectChange}
>
{children}
</SelectField>}
<SelectField
floatingLabel={floatingLabel}
label={label}
multiple
error={error}
editable={editable}
readOnly={readOnly}
skipValues={value}
onFocus={onFocus}
onBlur={onBlur}
onChange={this.onSelectChange}
>
{children}
</SelectField>

<div className={'mdl-taglist'}>
{tags.map(tag =>
Expand Down
13 changes: 0 additions & 13 deletions src/MultiSelectField/MultiSelectField.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,6 @@
position: relative;
width: 300px;

.mdl-textfield__label {
//color: #757575;
}

.mdl-textfield--readOnly {

.mdl-textfield__input {
font-size: 16px;
padding: 4px 0 2px 0;
color: rgba(0, 0, 0, 0.26);
}
}

.mdl-taglist {
margin-top: 5px;

Expand Down
95 changes: 61 additions & 34 deletions src/SelectField/SelectField.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ export default class SelectField extends Component {

constructor(props) {
super(props)

if (props.readOnly && props.editable) {
throw new Error('MultiSelectField cannot be both "editable" and "readOnly"!')
}

this.state = {
value: null,
inputValue: '',
Expand All @@ -42,6 +47,8 @@ export default class SelectField extends Component {
selectFieldIndex++

// override material menu if needed
// this needs to be done in the constructor
// otherwise menu does not work properly
if (!overrideApplied) applyOverride()

this.showMenu = this.showMenu.bind(this)
Expand Down Expand Up @@ -184,48 +191,68 @@ export default class SelectField extends Component {
}

render() {
const { floatingLabel, className, label, error, multiple, editable } = this.props
const { value, inputValue, focused } = this.state
const {
floatingLabel, className, label,
error, multiple, readOnly, editable,
} = this.props

const {
value, inputValue, focused,
} = this.state

const children = this.getChildren()

const mainClass = classnames({
'mdl-selectfield': true,
'mdl-selectfield--editable': editable,
'mdl-selectfield--error': error,
}, className)

const inputProps = {
id: this.id,
className: menuSkipForClass,
type: 'text',
value: !multiple ? inputValue : '',
error,
label,
floatingLabel,
readOnly: !editable,
ref: ref => this.input = ref,
}

if (!readOnly) {
inputProps.onFocus = this.onTextfieldFocus
inputProps.onBlur = this.onTextfieldBlur
inputProps.onChange = this.onTextfieldChange
inputProps.onKeyDown = this.onTextfieldKeyDown
}

return (
<div className={mainClass}>
<Textfield
id={this.id}
className={menuSkipForClass}
floatingLabel={floatingLabel}
type={'text'}
label={label}
error={error}
value={!multiple ? inputValue : ''}
readOnly={!editable}
onFocus={this.onTextfieldFocus}
onBlur={this.onTextfieldBlur}
onChange={this.onTextfieldChange}
onKeyDown={this.onTextfieldKeyDown}
ref={ref => this.input = ref}
/>
<Icon
className={'mdl-selectfield__arrow'}
name={`arrow_drop_${focused ? 'up' : 'down'}`}
onClick={this.showMenu}
/>
<Menu target={this.id} ripple>
{Children.map(children, child => {
const className = classnames({
'mdl-menu__item--selected': !multiple && child.props.value === value,
'mdl-menu__item--disabled': child.props.disabled,
})
return React.cloneElement(child, {
className,
onClick: () => this.onMenuItemClick(child),
})
})}
</Menu>

<Textfield {...inputProps}/>

{!readOnly &&
<Icon
className={'mdl-selectfield__arrow'}
name={`arrow_drop_${focused ? 'up' : 'down'}`}
onClick={this.showMenu}
/>}

{!readOnly &&
<Menu target={this.id} ripple>
{Children.map(children, child => {
const className = classnames({
'mdl-menu__item--selected': !multiple && child.props.value === value,
'mdl-menu__item--disabled': child.props.disabled,
})
return React.cloneElement(child, {
className,
onClick: () => this.onMenuItemClick(child),
})
})}
</Menu>}

</div>
)
}
Expand Down
27 changes: 18 additions & 9 deletions stories/SelectField.story.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,24 @@ storiesOf('SelectField', module)
<Option value={5}>Five</Option>
</SelectField>
))
.add('editable', () => (
<SelectField label={'Select me'} editable>
<Option value={1}>One</Option>
<Option value={2}>Two</Option>
<Option value={3}>Three</Option>
<Option value={4}>Four</Option>
<Option value={5}>Five</Option>
</SelectField>
))
.add('readonly', () => (
<SelectField label={'Select me'} readOnly value={3}>
<Option value={1}>One</Option>
<Option value={2}>Two</Option>
<Option value={3}>Three</Option>
<Option value={4}>Four</Option>
<Option value={5}>Five</Option>
</SelectField>
))
.add('empty option', () => (
<SelectField label={'Select me'}>
<Option value={''} disabled>-- Select value --</Option>
Expand All @@ -51,15 +69,6 @@ storiesOf('SelectField', module)
<Option value={5}>Five</Option>
</SelectField>
))
.add('editable input', () => (
<SelectField label={'Select me'} editable>
<Option value={1}>One</Option>
<Option value={2}>Two</Option>
<Option value={3}>Three</Option>
<Option value={4}>Four</Option>
<Option value={5}>Five</Option>
</SelectField>
))
.add('lots of values', () => (
<SelectField label={'Select me'} editable>
{[...Array(45).keys()].map(i =>
Expand Down

0 comments on commit a82a4e4

Please sign in to comment.