downshift
Advanced tools
Comparing version 1.0.0-beta.11 to 1.0.0-beta.12
@@ -27,2 +27,4 @@ 'use strict'; | ||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | ||
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } | ||
@@ -54,2 +56,3 @@ | ||
_this.items = []; | ||
_this.previousResultCount = 0; | ||
@@ -74,3 +77,3 @@ _this.getItemFromIndex = function (index) { | ||
_this.getItemNodeFromIndex = function (index) { | ||
return _this._rootNode.querySelector(`[data-autocomplete-item-index="${index}"]`); | ||
return _this._rootNode.querySelector('[data-autocomplete-item-index="' + index + '"]'); | ||
}; | ||
@@ -81,3 +84,3 @@ | ||
_this.internalSetState({ highlightedIndex }, function () { | ||
_this.internalSetState({ highlightedIndex: highlightedIndex }, function () { | ||
_this.maybeScrollToHighlightedElement(highlightedIndex); | ||
@@ -89,3 +92,3 @@ }); | ||
var highlightedIndex = _this.getIndexFromValue(_this.getState().selectedValue) || 0; | ||
_this.internalSetState({ highlightedIndex }, function () { | ||
_this.internalSetState({ highlightedIndex: highlightedIndex }, function () { | ||
_this.maybeScrollToHighlightedElement(highlightedIndex, true); | ||
@@ -192,2 +195,4 @@ }); | ||
_this.getRootProps = function () { | ||
var _extends2; | ||
var _ref4 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
@@ -203,6 +208,3 @@ | ||
_this.getRootProps.called = true; | ||
return _extends({ | ||
[refKey]: _this.rootRef, | ||
onClick: (0, _utils.composeEventHandlers)(onClick, _this.root_handleClick) | ||
}, rest); | ||
return _extends((_extends2 = {}, _defineProperty(_extends2, refKey, _this.rootRef), _defineProperty(_extends2, 'onClick', (0, _utils.composeEventHandlers)(onClick, _this.root_handleClick)), _extends2), rest); | ||
}; | ||
@@ -225,3 +227,3 @@ | ||
_this.keyDownHandlers = { | ||
ArrowDown(event) { | ||
ArrowDown: function ArrowDown(event) { | ||
event.preventDefault(); | ||
@@ -231,4 +233,3 @@ var amount = event.shiftKey ? 5 : 1; | ||
}, | ||
ArrowUp(event) { | ||
ArrowUp: function ArrowUp(event) { | ||
event.preventDefault(); | ||
@@ -238,4 +239,3 @@ var amount = event.shiftKey ? -5 : -1; | ||
}, | ||
Enter(event) { | ||
Enter: function Enter(event) { | ||
event.preventDefault(); | ||
@@ -246,4 +246,3 @@ if (this.getState().isOpen) { | ||
}, | ||
Escape(event) { | ||
Escape: function Escape(event) { | ||
event.preventDefault(); | ||
@@ -254,4 +253,3 @@ this.reset(); | ||
_this.buttonKeyDownHandlers = _extends({}, _this.keyDownHandlers, { | ||
' '(event) { | ||
' ': function _(event) { | ||
event.preventDefault(); | ||
@@ -306,2 +304,15 @@ | ||
_this.getLabelProps = function () { | ||
var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
_this.getLabelProps.called = true; | ||
if (_this.getInputProps.called && props.htmlFor && props.htmlFor !== _this.inputId) { | ||
throw new Error('downshift: You provided the htmlFor of "' + props.htmlFor + '" for your label, but the id of your input is "' + _this.inputId + '". You must either remove the id from your input or set the htmlFor of the label equal to the input id.'); | ||
} | ||
_this.inputId = (0, _utils.firstDefined)(_this.inputId, props.htmlFor, (0, _utils.generateInputId)()); | ||
return _extends({}, props, { | ||
htmlFor: _this.inputId | ||
}); | ||
}; | ||
_this.getValue = function (itemValue) { | ||
@@ -319,2 +330,8 @@ return itemValue ? _this.props.getValue(itemValue) : ''; | ||
_this.getInputProps.called = true; | ||
if (_this.getLabelProps.called && rest.id && rest.id !== _this.inputId) { | ||
throw new Error('downshift: You provided the id of "' + rest.id + '" for your input, but the htmlFor of your label is "' + _this.inputId + '". You must either remove the id from your input or set the htmlFor of the label equal to the input id.'); | ||
} | ||
_this.inputId = (0, _utils.firstDefined)(_this.inputId, rest.id, (0, _utils.generateInputId)()); | ||
var _this$getState3 = _this.getState(), | ||
@@ -334,3 +351,5 @@ inputValue = _this$getState3.inputValue, | ||
onBlur: (0, _utils.composeEventHandlers)(onBlur, _this.input_handleBlur) | ||
}, rest); | ||
}, rest, { | ||
id: _this.inputId | ||
}); | ||
}; | ||
@@ -364,3 +383,3 @@ | ||
_this.items.push({ index, value }); | ||
_this.items.push({ index: index, value: value }); | ||
return _extends({ | ||
@@ -378,3 +397,3 @@ 'data-autocomplete-item-index': index, | ||
return { | ||
type, | ||
type: type, | ||
isOpen: false, | ||
@@ -424,8 +443,12 @@ highlightedIndex: null, | ||
} | ||
var item = _this.getItemFromIndex(_this.getState().highlightedIndex) || {}; | ||
var status = _this.props.getA11yStatusMessage({ | ||
resultCount: _this.items.length, | ||
highlightedItem: item.value, | ||
getValue: _this.getValue | ||
}); | ||
var state = _this.getState(); | ||
var item = _this.getItemFromIndex(state.highlightedIndex) || {}; | ||
var resultCount = _this.items.length; | ||
var status = _this.props.getA11yStatusMessage(_extends({ | ||
getValue: _this.getValue, | ||
previousResultCount: _this.previousResultCount, | ||
resultCount: resultCount, | ||
highlightedValue: item.value | ||
}, state)); | ||
_this.previousResultCount = resultCount; | ||
(0, _setA11yStatus2.default)(status); | ||
@@ -535,2 +558,7 @@ }, 200); | ||
(0, _utils.cbToCb)(cb)(); | ||
// We call this function whether we're controlled or not | ||
// It's mostly useful if we're controlled, but it can | ||
// definitely be useful for folks to know when something | ||
// happens internally. | ||
_this3.props.onStateChange(onStateChangeArg); | ||
// if the selectedValue changed | ||
@@ -541,7 +569,2 @@ // then let's call onChange! | ||
} | ||
// We call this function whether we're controlled or not | ||
// It's mostly useful if we're controlled, but it can | ||
// definitely be useful for folks to know when something | ||
// happens internally. | ||
_this3.props.onStateChange(onStateChangeArg); | ||
}); | ||
@@ -560,2 +583,3 @@ } | ||
getButtonProps = this.getButtonProps, | ||
getLabelProps = this.getLabelProps, | ||
getInputProps = this.getInputProps, | ||
@@ -575,23 +599,24 @@ getItemProps = this.getItemProps, | ||
// prop getters | ||
getRootProps, | ||
getButtonProps, | ||
getInputProps, | ||
getItemProps, | ||
getItemFromIndex, | ||
getRootProps: getRootProps, | ||
getButtonProps: getButtonProps, | ||
getLabelProps: getLabelProps, | ||
getInputProps: getInputProps, | ||
getItemProps: getItemProps, | ||
getItemFromIndex: getItemFromIndex, | ||
// actions | ||
openMenu, | ||
closeMenu, | ||
toggleMenu, | ||
selectItem, | ||
selectItemAtIndex, | ||
selectHighlightedItem, | ||
setHighlightedIndex, | ||
clearSelection, | ||
openMenu: openMenu, | ||
closeMenu: closeMenu, | ||
toggleMenu: toggleMenu, | ||
selectItem: selectItem, | ||
selectItemAtIndex: selectItemAtIndex, | ||
selectHighlightedItem: selectHighlightedItem, | ||
setHighlightedIndex: setHighlightedIndex, | ||
clearSelection: clearSelection, | ||
// state | ||
highlightedIndex, | ||
inputValue, | ||
isOpen, | ||
selectedValue | ||
highlightedIndex: highlightedIndex, | ||
inputValue: inputValue, | ||
isOpen: isOpen, | ||
selectedValue: selectedValue | ||
}; | ||
@@ -608,2 +633,6 @@ } | ||
/////////////////////////////// LABEL | ||
//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Label | ||
/////////////////////////////// INPUT | ||
@@ -652,8 +681,4 @@ | ||
key: 'componentDidUpdate', | ||
value: function componentDidUpdate(prevProps, prevState) { | ||
// TODO: what do we need to do for this when the | ||
// autocomplete is a controlled component? | ||
if (prevState.highlightedIndex !== this.state.highlightedIndex || this.state.selectedValue !== prevState.selectedValue) { | ||
this.updateStatus(); | ||
} | ||
value: function componentDidUpdate() { | ||
this.updateStatus(); | ||
} | ||
@@ -678,2 +703,6 @@ }, { | ||
this.getRootProps.called = false; | ||
// we do something similar for getLabelProps | ||
this.getLabelProps.called = false; | ||
// and something similar for getInputProps | ||
this.getInputProps.called = false; | ||
// doing React.Children.only for Preact support ⚛️ | ||
@@ -724,14 +753,27 @@ var element = _react2.default.Children.only(children(this.getControllerStateAndHelpers())); | ||
defaultValue: null, | ||
getA11yStatusMessage(_ref10) { | ||
var resultCount = _ref10.resultCount, | ||
highlightedItem = _ref10.highlightedItem, | ||
// eslint-disable-next-line complexity | ||
getA11yStatusMessage: function getA11yStatusMessage(_ref10) { | ||
var isOpen = _ref10.isOpen, | ||
highlightedValue = _ref10.highlightedValue, | ||
selectedValue = _ref10.selectedValue, | ||
resultCount = _ref10.resultCount, | ||
previousResultCount = _ref10.previousResultCount, | ||
getValue = _ref10.getValue; | ||
if (!isOpen) { | ||
if (selectedValue) { | ||
return getValue(selectedValue); | ||
} else { | ||
return ''; | ||
} | ||
} | ||
var resultCountChanged = resultCount !== previousResultCount; | ||
if (!resultCount) { | ||
return 'No results.'; | ||
} else if (!highlightedItem) { | ||
return `${resultCount} ${resultCount === 1 ? 'result is' : 'results are'} available, use up and down arrow keys to navigate.`; | ||
} else if (!highlightedValue || resultCountChanged) { | ||
return resultCount + ' ' + (resultCount === 1 ? 'result is' : 'results are') + ' available, use up and down arrow keys to navigate.'; | ||
} | ||
return getValue(highlightedItem); | ||
return getValue(highlightedValue); | ||
}, | ||
getValue: function getValue(i) { | ||
@@ -738,0 +780,0 @@ return String(i); |
@@ -21,3 +21,3 @@ 'use strict'; | ||
var div = getStatusDiv(); | ||
div.innerHTML = `${statuses.map(getStatusHtml).join('')}`; | ||
div.innerHTML = '' + statuses.filter(Boolean).map(getStatusHtml).join(''); | ||
} | ||
@@ -27,3 +27,3 @@ | ||
var display = index === statuses.length - 1 ? 'block' : 'none'; | ||
return `<div style="display:${display};">${status}</div>`; | ||
return '<div style="display:' + display + ';">' + status + '</div>'; | ||
} | ||
@@ -30,0 +30,0 @@ |
@@ -12,2 +12,4 @@ 'use strict'; | ||
var inputIdCounter = 1; | ||
/** | ||
@@ -166,2 +168,25 @@ * This will take a node and select the given range of text from start to end in a | ||
/** | ||
* This generates a unique ID for all autocomplete inputs | ||
* @return {String} the unique ID | ||
*/ | ||
function generateInputId() { | ||
return 'autocomplete-input-id-' + inputIdCounter++; | ||
} | ||
/** | ||
* Returns the first argument that is not undefined | ||
* @param {...*} args the arguments | ||
* @return {*} the defined value | ||
*/ | ||
function firstDefined() { | ||
for (var _len6 = arguments.length, args = Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { | ||
args[_key6] = arguments[_key6]; | ||
} | ||
return args.find(function (a) { | ||
return typeof a !== 'undefined'; | ||
}); | ||
} | ||
exports.cbToCb = cbToCb; | ||
@@ -173,2 +198,4 @@ exports.compose = compose; | ||
exports.selectAllText = selectAllText; | ||
exports.selectRangeOfText = selectRangeOfText; | ||
exports.selectRangeOfText = selectRangeOfText; | ||
exports.generateInputId = generateInputId; | ||
exports.firstDefined = firstDefined; |
{ | ||
"name": "downshift", | ||
"version": "1.0.0-beta.11", | ||
"version": "1.0.0-beta.12", | ||
"description": "A set of primitives to build simple, flexible, WAI-ARIA compliant React autocomplete components", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
@@ -98,3 +98,3 @@ <h1 align="center"> | ||
fontWeight: selectedValue === item ? 'bold' : 'normal', | ||
} | ||
}} | ||
> | ||
@@ -156,8 +156,29 @@ {item} | ||
> `function({ resultCount, highlightedItem, getValue})` | default messages provided in English | ||
> `function({/* see below */})` | default messages provided in English | ||
This function is passed as props to a `Status` component nested within and allows you to create your own assertive ARIA statuses. | ||
This function is passed as props to a `Status` component nested within and | ||
allows you to create your own assertive ARIA statuses. | ||
A default `getA11yStatusMessage` function is provided that will check `resultCount` and return "No results." or if there are results but no item is highlighted, "`resultCount` results are available, use up and down arrow keys to navigate." If an item is highlighted it will run `getValue(highlightedItem)` and display the value of the `highlightedItem`. | ||
A default `getA11yStatusMessage` function is provided that will check | ||
`resultCount` and return "No results." or if there are results but no item is | ||
highlighted, "`resultCount` results are available, use up and down arrow keys | ||
to navigate." If an item is highlighted it will run `getValue(highlightedItem)` | ||
and display the value of the `highlightedItem`. | ||
The object you are passed to generate your status message has the following | ||
properties: | ||
<!-- This table was generated via http://www.tablesgenerator.com/markdown_tables --> | ||
| property | type | description | | ||
|-----------------------|-----------------|------------------------------------------------------------------------------------------| | ||
| `getValue` | `function(any)` | The `getValue` function (see props) for getting the string value from one of the options | | ||
| `resultCount` | `number` | The total items showing in the dropdown | | ||
| `previousResultCount` | `number` | The total items showing in the dropdown the last time the status was updated | | ||
| `highlightedValue` | `any` | The value of the highlighted item | | ||
| `highlightedIndex` | `number`/`null` | The currently highlighted index | | ||
| `inputValue` | `string` | The current input value | | ||
| `isOpen` | `boolean` | The `isOpen` state | | ||
| `selectedValue` | `any` | The value of the currently selected item | | ||
#### onChange | ||
@@ -217,2 +238,3 @@ | ||
| `getInputProps` | `function({})` | returns the props you should apply to the `input` element that you render. Read more below | | ||
| `getLabelProps` | `function({})` | returns the props you should apply to the `label` element that you render. Read more below | | ||
| `getItemProps` | `function({})` | returns the props you should apply to any menu item elements you render. Read more below | | ||
@@ -265,2 +287,17 @@ | `getButtonProps` | `function({})` | returns the props you should apply to any menu toggle button element you render. Read more below | | ||
##### `getLabelProps` | ||
This method should be applied to the `label` you render. It is useful for | ||
ensuring that the `for` attribute on the `<label>` (`htmlFor` as a react prop) | ||
is the same as the `id` that appears on the `input`. If no `htmlFor` is provided | ||
then an ID will be generated and used for the `input` and the `label` `for` | ||
attribute. | ||
There are no required properties for this method. | ||
> Note: You can definitely get by without using this (just provide an `id` to | ||
> your input and the same `htmlFor` to your `label` and you'll be good with | ||
> accessibility). However, we include this so you don't forget and it makes | ||
> things a little nicer for you. You're welcome 😀 | ||
##### `getItemProps` | ||
@@ -346,3 +383,3 @@ | ||
| [<img src="https://avatars2.githubusercontent.com/u/15073300?v=4" width="100px;"/><br /><sub>monssef</sub>](https://github.com/rezof)<br />[💡](#example-rezof "Examples") | [<img src="https://avatars2.githubusercontent.com/u/5382443?v=4" width="100px;"/><br /><sub>Federico Zivolo</sub>](https://fezvrasta.github.io)<br />[📖](https://github.com/paypal/downshift/commits?author=FezVrasta "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/746482?v=4" width="100px;"/><br /><sub>Divyendu Singh</sub>](https://divyendusingh.com)<br />[💡](#example-divyenduz "Examples") | [<img src="https://avatars1.githubusercontent.com/u/841955?v=4" width="100px;"/><br /><sub>Muhammad Salman</sub>](https://github.com/salmanmanekia)<br />[💻](https://github.com/paypal/downshift/commits?author=salmanmanekia "Code") | [<img src="https://avatars3.githubusercontent.com/u/10820159?v=4" width="100px;"/><br /><sub>João Alberto</sub>](https://twitter.com/psicotropidev)<br />[💻](https://github.com/paypal/downshift/commits?author=psicotropicos "Code") | [<img src="https://avatars0.githubusercontent.com/u/16327281?v=4" width="100px;"/><br /><sub>Bernard Lin</sub>](https://github.com/bernard-lin)<br />[💻](https://github.com/paypal/downshift/commits?author=bernard-lin "Code") [📖](https://github.com/paypal/downshift/commits?author=bernard-lin "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/7330124?v=4" width="100px;"/><br /><sub>Geoff Davis</sub>](https://geoffdavis.info)<br />[💡](#example-geoffdavis92 "Examples") | | ||
| [<img src="https://avatars0.githubusercontent.com/u/3415488?v=4" width="100px;"/><br /><sub>Anup</sub>](https://github.com/reznord)<br />[📖](https://github.com/paypal/downshift/commits?author=reznord "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/340520?v=4" width="100px;"/><br /><sub>Ferdinand Salis</sub>](http://ferdinandsalis.com)<br />[🐛](https://github.com/paypal/downshift/issues?q=author%3Aferdinandsalis "Bug reports") [💻](https://github.com/paypal/downshift/commits?author=ferdinandsalis "Code") | | ||
| [<img src="https://avatars0.githubusercontent.com/u/3415488?v=4" width="100px;"/><br /><sub>Anup</sub>](https://github.com/reznord)<br />[📖](https://github.com/paypal/downshift/commits?author=reznord "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/340520?v=4" width="100px;"/><br /><sub>Ferdinand Salis</sub>](http://ferdinandsalis.com)<br />[🐛](https://github.com/paypal/downshift/issues?q=author%3Aferdinandsalis "Bug reports") [💻](https://github.com/paypal/downshift/commits?author=ferdinandsalis "Code") | [<img src="https://avatars0.githubusercontent.com/u/6290720?v=4" width="100px;"/><br /><sub>David Nguyen</sub>](http://github.com/nndung179/)<br />[💡](https://codesandbox.io/s/gOmNGvN6 "Material DownShift Example") | ||
<!-- ALL-CONTRIBUTORS-LIST:END --> | ||
@@ -349,0 +386,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
62169
877
419