Skip to content

Commit 1058e3f

Browse files
committed
[added] disable individual dropdown/combobox options
1 parent 5d1b530 commit 1058e3f

File tree

9 files changed

+146
-104
lines changed

9 files changed

+146
-104
lines changed

docs/components/pages/ComboBox.api.md

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,53 +21,65 @@ the string value of the {widgetName} will be returned.
2121

2222
### onSelect?{ type: 'Function(Any value)' }
2323

24-
This handler fires when an item has been selected from the list. It fires before the `onChange` handler, and fires
24+
This handler fires when an item has been selected from the list. It fires before the `onChange` handler, and fires
2525
regardless of whether the value has actually changed.
2626

2727
<EditableExample codeText={require('../examples/onSelect')(widgetName)}/>
2828

2929
### data?{ type: 'Array<Any>' }
3030

3131
An array of possible values for the {widgetName}. If an array of `objects` is provided you
32-
should usethe `valueField` and `textField` props, to specify which object
32+
should use the `valueField` and `textField` props, to specify which object
3333
properties comprise the value field (such as an id) and the field used to label the item.
3434

3535
### valueField?{ type: 'String' }
3636

37-
A dataItem field name for uniquely identifying items in the `data` list. A `valueField` is required
37+
A dataItem field name for uniquely identifying items in the `data` list. A `valueField` is required
3838
when the `value` prop is not itself a dataItem. A `valueField` is useful when specifying the selected item, by
3939
its `id` instead of using the model as the value.
4040

4141

42-
When a `valueField` is not provided, the {widgetName} will use strict equality checks (`===`) to locate
42+
When a `valueField` is not provided, the {widgetName} will use strict equality checks (`===`) to locate
4343
the `value` in the `data` list.
4444

4545
<EditableExample codeText={require('../examples/valueField')(widgetName)}/>
4646

4747
### textField?{ type: 'String | Function(dataItem)' }
4848

49-
Specify which data item field to display in the ${widgetName} and selected item. The textField` prop
49+
Specify which data item field to display in the ${widgetName} and selected item. The textField` prop
5050
may also also used as to find an item in the list as you type. Providing an accessor function allows for computed text values
5151

5252
<EditableExample codeText={require('../examples/textField')(widgetName, false, true)}/>
5353

5454
### itemComponent?{ type: 'Component' }
5555

56-
This component is used to render each possible item in the DropdownList. The default component
56+
This component is used to render each possible item in the ${widgetName}. The default component
5757
renders the text of the selected item (specified by `textfield`)
5858

5959
<EditableExample codeText={require('../examples/itemComponent')(widgetName)}/>
6060

61+
### disabled?{ type: '[Boolean, Array]' }
62+
63+
Disable the widget, if an `Array` of values is passed in only those values will be disabled.
64+
65+
<EditableExample codeText={require('../examples/disabled')(widgetName, 'disabled', false)}/>
66+
67+
### readOnly?{ type: '[Boolean, Array]' }
68+
69+
Place the {widgetName} in a read-only mode, If an `Array` of values is passed in only those values will be read-only.
70+
71+
<EditableExample codeText={require('../examples/disabled')(widgetName, 'readOnly', false)}/>
72+
6173
### groupBy?{ type: 'String | Function(Any dataItem)' }
6274

63-
Determines how to group the {widgetName} dropdown list. Providing a `string` will group
75+
Determines how to group the {widgetName}. Providing a `string` will group
6476
the `data` array by that property. You can also provide a function which should return the group value.
6577

6678
<EditableExample codeText={require('../examples/groupby')(widgetName)}/>
6779

6880
### groupComponent?{ type: 'Component' }
6981

70-
This component is used to render each option group, when `groupBy` is specified. By
82+
This component is used to render each option group, when `groupBy` is specified. By
7183
default the `groupBy` value will be used.
7284

7385
<EditableExample codeText={require('../examples/groupComponent')(widgetName)}/>
@@ -80,7 +92,7 @@ are always "startsWith", meaning it will search from the start of the `textField
8092
### filter?{ type: '[Boolean, String, Function(dataItem, searchTerm)]', default: 'false' }
8193

8294
Specify a filtering method used to reduce the items in the dropdown as you type. It can be used in conjunction with
83-
the `suggest` prop or instead of it. There are a few prebuilt filtering methods that can be specified
95+
the `suggest` prop or instead of it. There are a few built-in filtering methods that can be specified
8496
by passing the `String` name. You can explicitly opt out of filtering by setting filter
8597
to `false`
8698

docs/components/pages/DropdownList.api.md

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,59 +12,71 @@ Change event Handler that is called when the value is changed.
1212

1313
### onSelect?{ type: 'Function(Any value)' }
1414

15-
This handler fires when an item has been selected from the list. It fires before the `onChange` handler, and fires
15+
This handler fires when an item has been selected from the list. It fires before the `onChange` handler, and fires
1616
regardless of whether the value has actually changed.
1717

1818
<EditableExample codeText={require('../examples/onSelect')(widgetName)}/>
1919

2020
### data?{ type: 'Array<Any>' }
2121

22-
provide an array of possible values for the DropdownList. If an array of `objects` is provided you
22+
provide an array of possible values for the ${widgetName}. If an array of `objects` is provided you
2323
should use the `valueField` and `textField` props, to specify which object
2424
properties comprise the value field (such as an id) and the field used to label the item.
2525

2626
### valueField?{ type: 'String' }
2727

28-
A dataItem field name for uniquely identifying items in the `data` list. A `valueField` is required
28+
A dataItem field name for uniquely identifying items in the `data` list. A `valueField` is required
2929
when the `value` prop is not itself a dataItem. A `valueField` is useful when specifying the selected item, by
3030
its `id` instead of using the model as the value.
3131

32-
When a `valueField` is not provided, the {widgetName} will use strict equality checks (`===`) to locate
32+
When a `valueField` is not provided, the {widgetName} will use strict equality checks (`===`) to locate
3333
the `value` in the `data` list.
3434

3535
<EditableExample codeText={require('../examples/valueField')(widgetName)}/>
3636

3737
### textField?{ type: 'String | Function(dataItem)' }
3838

39-
{`Specify which data item field to display in the ${widgetName} and selected item. The `}`textField`{`prop
39+
{`Specify which data item field to display in the ${widgetName} and selected item. The `}`textField`{`prop
4040
may also also used as to find an item in the list as you type. Providing an accessor function allows for computed text values`}
4141

4242
<EditableExample codeText={require('../examples/textField')(widgetName)}/>
4343

4444
### valueComponent?{ type: 'Component' }
4545

46-
This component is used to render the selected value of the combobox. The default component
46+
This component is used to render the selected value of the ${widgetName}. The default component
4747
renders the text of the selected item (specified by `textfield`)
4848

4949
<EditableExample codeText={require('../examples/valueComponent')(widgetName)}/>
5050

5151
### itemComponent?{ type: 'Component' }
5252

53-
This component is used to render each possible item in the DropdownList. The default component
53+
This component is used to render each possible item in the ${widgetName}. The default component
5454
renders the text of the selected item (specified by `textfield`)
5555

5656
<EditableExample codeText={require('../examples/itemComponent')(widgetName)}/>
5757

58+
### disabled?{ type: '[Boolean, Array]' }
59+
60+
Disable the widget, if an `Array` of values is passed in only those values will be disabled.
61+
62+
<EditableExample codeText={require('../examples/disabled')(widgetName, 'disabled', false)}/>
63+
64+
### readOnly?{ type: '[Boolean, Array]' }
65+
66+
Place the {widgetName} in a read-only mode, If an `Array` of values is passed in only those values will be read-only.
67+
68+
<EditableExample codeText={require('../examples/disabled')(widgetName, 'readOnly', false)}/>
69+
5870
### groupBy?{ type: 'String | Function(Any dataItem)' }
5971

60-
Determines how to group the {widgetName} dropdown list. Providing a `string` will group
72+
Determines how to group the {widgetName}. Providing a `string` will group
6173
the `data` array by that property. You can also provide a function which should return the group value.
6274

6375
<EditableExample codeText={require('../examples/groupby')(widgetName)}/>
6476

6577
### groupComponent?{ type: 'Component' }
6678

67-
This component is used to render each option group, when `groupBy` is specified. By
79+
This component is used to render each option group, when `groupBy` is specified. By
6880
default the `groupBy` value will be used.
6981

7082

@@ -79,7 +91,7 @@ Text to display when the value is empty.
7991

8092
The string value of the current search being typed into the {widgetName}. When
8193
unset (`undefined`) the {widgetName} will handle the filtering internally.
82-
The `defaultSearchTerm` prop can be used to set an initialization value for uncontrolled widgets. searchTerm is only
94+
The `defaultSearchTerm` prop can be used to set an initialization value for uncontrolled widgets. `searchTerm` is only
8395
relevant when the `filter` prop is set.
8496

8597

@@ -105,7 +117,7 @@ when the `open` prop is set otherwise the widget open buttons won't work.
105117

106118
### filter?{ type: '[String, Function(dataItem, searchTerm)]', default: 'false' }
107119

108-
Specify a filtering method used to reduce the items in the dropdown as you type. There are a few prebuilt filtering
120+
Specify a filtering method used to reduce the items in the dropdown as you type. There are a few built-in filtering
109121
methods that can be specified by passing the `String` name.
110122

111123
To handle custom filtering techniques provide a `function` that returns `true` or `false` for each passed in item
@@ -168,4 +180,4 @@ Text to display when the the current filter does not return any results.
168180
- <kbd>home</kbd> move focus to first item
169181
- <kbd>end</kbd> move focus to last item
170182
- <kbd>enter</kbd> select focused item
171-
- <kbd>any key</kbd> search list for item starting with key
183+
- <kbd>any key</kbd> search list for item starting with key

src/Combobox.jsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import GroupableList from './ListGroupable';
1212
import validateList from './util/validateListInterface';
1313
import createUncontrolledWidget from 'uncontrollable';
1414
import { dataItem, dataText, dataIndexOf } from './util/dataHelpers';
15-
import { widgetEditable, widgetEnabled } from './util/interaction';
15+
import { widgetEditable, widgetEnabled, isDisabled, isReadOnly } from './util/interaction';
1616
import { instanceId, notify, isFirstFocusedRender } from './util/widgetHelpers';
1717

1818
let defaultSuggest = f => f === true ? 'startsWith' : f ? f : 'eq'
@@ -41,8 +41,8 @@ let propTypes = {
4141
onSelect: React.PropTypes.func,
4242

4343
autoFocus: React.PropTypes.bool,
44-
disabled: CustomPropTypes.disabled,
45-
readOnly: CustomPropTypes.readOnly,
44+
disabled: CustomPropTypes.disabled.acceptsArray,
45+
readOnly: CustomPropTypes.readOnly.acceptsArray,
4646

4747
suggest: CustomPropTypes.filter,
4848
filter: CustomPropTypes.filter,
@@ -144,7 +144,7 @@ var ComboBox = React.createClass({
144144
className, tabIndex, filter, suggest
145145
, valueField, textField, groupBy
146146
, messages, data, busy, dropUp, name, autoFocus
147-
, placeholder, value, open, disabled, readOnly
147+
, placeholder, value, open
148148
, listComponent: List } = this.props;
149149

150150
List = List || (groupBy && GroupableList) || PlainList
@@ -156,6 +156,8 @@ var ComboBox = React.createClass({
156156
let { focusedItem, selectedItem, focused } = this.state;
157157

158158
let items = this._data()
159+
, disabled = isDisabled(this.props)
160+
, readOnly = isReadOnly(this.props)
159161
, valueItem = dataItem(data, value, valueField) // take value from the raw data
160162
, inputID = instanceId(this, '_input')
161163
, listID = instanceId(this, '_listbox')

src/DropdownList.jsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import validateList from './util/validateListInterface';
1212
import createUncontrolledWidget from 'uncontrollable';
1313

1414
import { dataItem, dataText, dataIndexOf } from './util/dataHelpers';
15-
import { widgetEditable, widgetEnabled } from './util/interaction';
15+
import { widgetEditable, widgetEnabled, isDisabled, isReadOnly } from './util/interaction';
1616
import { instanceId, notify, isFirstFocusedRender } from './util/widgetHelpers';
1717

1818
let { omit, pick, result } = _;
@@ -48,9 +48,8 @@ var propTypes = {
4848
dropUp: React.PropTypes.bool,
4949
duration: React.PropTypes.number, //popup
5050

51-
disabled: CustomPropTypes.disabled,
52-
53-
readOnly: CustomPropTypes.readOnly,
51+
disabled: CustomPropTypes.disabled.acceptsArray,
52+
readOnly: CustomPropTypes.readOnly.acceptsArray,
5453

5554
messages: React.PropTypes.shape({
5655
open: CustomPropTypes.message,
@@ -123,7 +122,7 @@ var DropdownList = React.createClass({
123122
className, tabIndex, filter
124123
, valueField, textField, groupBy
125124
, messages, data, busy, dropUp
126-
, placeholder, value, open, disabled, readOnly
125+
, placeholder, value, open
127126
, valueComponent: ValueComponent
128127
, listComponent: List } = this.props;
129128

@@ -136,6 +135,8 @@ var DropdownList = React.createClass({
136135
let { focusedItem, selectedItem, focused } = this.state;
137136

138137
let items = this._data()
138+
, disabled = isDisabled(this.props)
139+
, readOnly = isReadOnly(this.props)
139140
, valueItem = dataItem(data, value, valueField) // take value from the raw data
140141
, listID = instanceId(this, '__listbox');
141142

src/List.jsx

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import cn from 'classnames';
66
import _ from './util/_';
77
import { dataText, dataValue } from './util/dataHelpers';
88
import { instanceId, notify } from './util/widgetHelpers';
9+
import { isDisabledItem, isReadOnlyItem } from './util/interaction';
910

1011
let optionId = (id, idx)=> `${id}__option__${idx}`;
1112

@@ -26,12 +27,13 @@ export default React.createClass({
2627
optionComponent: CustomPropTypes.elementType,
2728
itemComponent: CustomPropTypes.elementType,
2829

29-
selectedIndex: React.PropTypes.number,
30-
focusedIndex: React.PropTypes.number,
31-
valueField: React.PropTypes.string,
30+
selected: React.PropTypes.any,
31+
focused: React.PropTypes.any,
32+
valueField: CustomPropTypes.accessor,
3233
textField: CustomPropTypes.accessor,
3334

34-
optionID: React.PropTypes.func,
35+
disabled: CustomPropTypes.disabled.acceptsArray,
36+
readOnly: CustomPropTypes.readOnly.acceptsArray,
3537

3638
messages: React.PropTypes.shape({
3739
emptyList: CustomPropTypes.message
@@ -41,7 +43,6 @@ export default React.createClass({
4143

4244
getDefaultProps(){
4345
return {
44-
optID: '',
4546
onSelect: ()=>{},
4647
optionComponent: ListOption,
4748
ariaActiveDescendantKey: 'list',
@@ -72,7 +73,6 @@ export default React.createClass({
7273
, focused, selected, messages, onSelect
7374
, itemComponent: ItemComponent
7475
, optionComponent: Option
75-
, optionID
7676
, ...props } = this.props
7777
, id = instanceId(this)
7878
, items;
@@ -83,22 +83,28 @@ export default React.createClass({
8383
{_.result(messages.emptyList, this.props)}
8484
</li>
8585
) : data.map((item, idx) => {
86-
var currentId = optionId(id, idx);
86+
var currentId = optionId(id, idx)
87+
, isDisabled = isDisabledItem(item, props)
88+
, isReadOnly = isReadOnlyItem(item, props);
8789

8890
return (
8991
<Option
9092
key={'item_' + idx}
9193
id={currentId}
9294
dataItem={item}
95+
disabled={isDisabled}
96+
readOnly={isReadOnly}
9397
focused={focused === item}
9498
selected={selected === item}
95-
onClick={onSelect.bind(null, item)}
99+
onClick={isDisabled || isReadOnly ? undefined : onSelect.bind(null, item)}
96100
>
97101
{ ItemComponent
98102
? <ItemComponent
99103
item={item}
100104
value={dataValue(item, valueField)}
101105
text={dataText(item, textField)}
106+
disabled={isDisabled}
107+
readOnly={isReadOnly}
102108
/>
103109
: dataText(item, textField)
104110
}

0 commit comments

Comments
 (0)