@odopod/odo-dropdown
Advanced tools
Comparing version 2.1.0 to 2.1.1
@@ -29,10 +29,2 @@ import OdoDevice from '@odopod/odo-device'; | ||
var inherits = function (subClass, superClass) { | ||
@@ -54,12 +46,2 @@ if (typeof superClass !== "function" && superClass !== null) { | ||
var possibleConstructorReturn = function (self, call) { | ||
@@ -66,0 +48,0 @@ if (!self) { |
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('@odopod/odo-device'), require('@odopod/odo-helpers'), require('@odopod/odo-base-component')) : | ||
typeof define === 'function' && define.amd ? define(['@odopod/odo-device', '@odopod/odo-helpers', '@odopod/odo-base-component'], factory) : | ||
(global.OdoDropdown = factory(global.OdoDevice,global.OdoHelpers,global.OdoBaseComponent)); | ||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('@odopod/odo-device'), require('@odopod/odo-helpers'), require('@odopod/odo-base-component')) : | ||
typeof define === 'function' && define.amd ? define(['@odopod/odo-device', '@odopod/odo-helpers', '@odopod/odo-base-component'], factory) : | ||
(global.OdoDropdown = factory(global.OdoDevice,global.OdoHelpers,global.OdoBaseComponent)); | ||
}(this, (function (OdoDevice,odoHelpers,OdoBaseComponent) { 'use strict'; | ||
OdoDevice = OdoDevice && OdoDevice.hasOwnProperty('default') ? OdoDevice['default'] : OdoDevice; | ||
OdoBaseComponent = OdoBaseComponent && OdoBaseComponent.hasOwnProperty('default') ? OdoBaseComponent['default'] : OdoBaseComponent; | ||
OdoDevice = OdoDevice && OdoDevice.hasOwnProperty('default') ? OdoDevice['default'] : OdoDevice; | ||
OdoBaseComponent = OdoBaseComponent && OdoBaseComponent.hasOwnProperty('default') ? OdoBaseComponent['default'] : OdoBaseComponent; | ||
var classCallCheck = function (instance, Constructor) { | ||
if (!(instance instanceof Constructor)) { | ||
throw new TypeError("Cannot call a class as a function"); | ||
} | ||
}; | ||
var createClass = function () { | ||
function defineProperties(target, props) { | ||
for (var i = 0; i < props.length; i++) { | ||
var descriptor = props[i]; | ||
descriptor.enumerable = descriptor.enumerable || false; | ||
descriptor.configurable = true; | ||
if ("value" in descriptor) descriptor.writable = true; | ||
Object.defineProperty(target, descriptor.key, descriptor); | ||
var classCallCheck = function (instance, Constructor) { | ||
if (!(instance instanceof Constructor)) { | ||
throw new TypeError("Cannot call a class as a function"); | ||
} | ||
} | ||
return function (Constructor, protoProps, staticProps) { | ||
if (protoProps) defineProperties(Constructor.prototype, protoProps); | ||
if (staticProps) defineProperties(Constructor, staticProps); | ||
return Constructor; | ||
}; | ||
}(); | ||
var createClass = function () { | ||
function defineProperties(target, props) { | ||
for (var i = 0; i < props.length; i++) { | ||
var descriptor = props[i]; | ||
descriptor.enumerable = descriptor.enumerable || false; | ||
descriptor.configurable = true; | ||
if ("value" in descriptor) descriptor.writable = true; | ||
Object.defineProperty(target, descriptor.key, descriptor); | ||
} | ||
} | ||
return function (Constructor, protoProps, staticProps) { | ||
if (protoProps) defineProperties(Constructor.prototype, protoProps); | ||
if (staticProps) defineProperties(Constructor, staticProps); | ||
return Constructor; | ||
}; | ||
}(); | ||
var inherits = function (subClass, superClass) { | ||
if (typeof superClass !== "function" && superClass !== null) { | ||
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); | ||
} | ||
subClass.prototype = Object.create(superClass && superClass.prototype, { | ||
constructor: { | ||
value: subClass, | ||
enumerable: false, | ||
writable: true, | ||
configurable: true | ||
} | ||
}); | ||
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; | ||
}; | ||
var possibleConstructorReturn = function (self, call) { | ||
if (!self) { | ||
throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); | ||
} | ||
return call && (typeof call === "object" || typeof call === "function") ? call : self; | ||
}; | ||
var inherits = function (subClass, superClass) { | ||
if (typeof superClass !== "function" && superClass !== null) { | ||
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); | ||
var id = 0; | ||
function uniqueId() { | ||
id += 1; | ||
return 'ododropdown-' + id; | ||
} | ||
subClass.prototype = Object.create(superClass && superClass.prototype, { | ||
constructor: { | ||
value: subClass, | ||
enumerable: false, | ||
writable: true, | ||
configurable: true | ||
} | ||
}); | ||
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; | ||
}; | ||
var Dropdown = function (_OdoBaseComponent) { | ||
inherits(Dropdown, _OdoBaseComponent); | ||
function Dropdown(element) { | ||
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
classCallCheck(this, Dropdown); | ||
/** | ||
* Override any defaults with the given options. | ||
* @type {Object} | ||
*/ | ||
var _this = possibleConstructorReturn(this, _OdoBaseComponent.call(this, element)); | ||
_this.options = Object.assign({}, Dropdown.Defaults, options); | ||
/** | ||
* Unique id for this instance. | ||
* @type {string} | ||
*/ | ||
_this.id = uniqueId(); | ||
/** | ||
* Whether the dropdown is currently open. | ||
* @type {boolean} | ||
*/ | ||
_this._isOpen = false; | ||
/** | ||
* The <select> element. | ||
* @type {HTMLSelectElement} | ||
*/ | ||
_this._select = _this.getElementByClass(Dropdown.Classes.SELECT); | ||
// Give the select an id if it doesn't have one. | ||
odoHelpers.giveId(_this._select, _this.id); | ||
/** | ||
* The <label> for the <select>. | ||
* @type {?HTMLLabelElement} | ||
*/ | ||
_this._label = document.querySelector('label[for="' + _this._select.id + '"]'); | ||
// Generate the custom markup for options. | ||
if (_this.options.insertMarkup) { | ||
_this._insertMarkup(); | ||
} | ||
// Save Element references. | ||
_this._optionsContainer = _this.getElementByClass(Dropdown.Classes.OPTIONS_CONTAINER); | ||
_this._button = _this.getElementByClass(Dropdown.Classes.BUTTON); | ||
_this._placeholder = _this.getElementByClass(Dropdown.Classes.DEFAULT); | ||
_this._valueContainer = _this.getElementByClass(Dropdown.Classes.VALUE); | ||
var possibleConstructorReturn = function (self, call) { | ||
if (!self) { | ||
throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); | ||
} | ||
// Set the selected option. | ||
_this._selectedOption = _this._getCustomSelectedOption(); | ||
return call && (typeof call === "object" || typeof call === "function") ? call : self; | ||
}; | ||
_this._onSelectChange = _this._handleSelectChange.bind(_this); | ||
_this._onPageClick = _this._handlePageClick.bind(_this); | ||
_this._onButtonClick = _this._showOptions.bind(_this); | ||
_this._onKey = _this._handleKey.bind(_this); | ||
var id = 0; | ||
function uniqueId() { | ||
id += 1; | ||
return 'ododropdown-' + id; | ||
} | ||
_this._transitionId = null; | ||
var Dropdown = function (_OdoBaseComponent) { | ||
inherits(Dropdown, _OdoBaseComponent); | ||
_this._initialize(); | ||
return _this; | ||
} | ||
function Dropdown(element) { | ||
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
classCallCheck(this, Dropdown); | ||
/** | ||
* Override any defaults with the given options. | ||
* @type {Object} | ||
* Determines whether to create custom dropdown module, | ||
* or use native select element | ||
*/ | ||
var _this = possibleConstructorReturn(this, _OdoBaseComponent.call(this, element)); | ||
_this.options = Object.assign({}, Dropdown.Defaults, options); | ||
/** | ||
* Unique id for this instance. | ||
* @type {string} | ||
*/ | ||
_this.id = uniqueId(); | ||
Dropdown.prototype._initialize = function _initialize() { | ||
this._valueContainer.setAttribute('aria-hidden', true); | ||
/** | ||
* Whether the dropdown is currently open. | ||
* @type {boolean} | ||
*/ | ||
_this._isOpen = false; | ||
if (this.options.useNative) { | ||
this._initializeNativeDropdown(); | ||
} else { | ||
this._initializeCustomDropdown(); | ||
} | ||
}; | ||
/** | ||
* The <select> element. | ||
* @type {HTMLSelectElement} | ||
* Return the selected custom option element. | ||
* @return {Element} | ||
*/ | ||
_this._select = _this.getElementByClass(Dropdown.Classes.SELECT); | ||
// Give the select an id if it doesn't have one. | ||
odoHelpers.giveId(_this._select, _this.id); | ||
Dropdown.prototype._getCustomSelectedOption = function _getCustomSelectedOption() { | ||
return this.getCustomOptions()[this._select.selectedIndex]; | ||
}; | ||
/** | ||
* The <label> for the <select>. | ||
* @type {?HTMLLabelElement} | ||
* Insert the custom option html markup before the <select> element. | ||
*/ | ||
_this._label = document.querySelector('label[for="' + _this._select.id + '"]'); | ||
// Generate the custom markup for options. | ||
if (_this.options.insertMarkup) { | ||
_this._insertMarkup(); | ||
} | ||
// Save Element references. | ||
_this._optionsContainer = _this.getElementByClass(Dropdown.Classes.OPTIONS_CONTAINER); | ||
_this._button = _this.getElementByClass(Dropdown.Classes.BUTTON); | ||
_this._placeholder = _this.getElementByClass(Dropdown.Classes.DEFAULT); | ||
_this._valueContainer = _this.getElementByClass(Dropdown.Classes.VALUE); | ||
Dropdown.prototype._insertMarkup = function _insertMarkup() { | ||
var markup = this.getCustomOptionsHtml(); | ||
this._select.insertAdjacentHTML('beforebegin', markup); | ||
}; | ||
// Set the selected option. | ||
_this._selectedOption = _this._getCustomSelectedOption(); | ||
/** | ||
* Listen for change events on the <select>. | ||
*/ | ||
_this._onSelectChange = _this._handleSelectChange.bind(_this); | ||
_this._onPageClick = _this._handlePageClick.bind(_this); | ||
_this._onButtonClick = _this._showOptions.bind(_this); | ||
_this._onKey = _this._handleKey.bind(_this); | ||
_this._transitionId = null; | ||
Dropdown.prototype._initializeNativeDropdown = function _initializeNativeDropdown() { | ||
this.element.classList.add(Dropdown.Classes.BASE_NATIVE); | ||
this._select.addEventListener('change', this._onSelectChange); | ||
_this._initialize(); | ||
return _this; | ||
} | ||
// Hide the <button> from the screen reader so that it only reads the | ||
// <select> element. The <select> is actually positioned on top of the | ||
// <button> with zero opacity. | ||
this._button.setAttribute('aria-hidden', true); | ||
this._button.tabIndex = -1; | ||
}; | ||
/** | ||
* Determines whether to create custom dropdown module, | ||
* or use native select element | ||
*/ | ||
/** | ||
* Listen for clicks to trigger the menu and keyboard input. | ||
*/ | ||
Dropdown.prototype._initialize = function _initialize() { | ||
this._valueContainer.setAttribute('aria-hidden', true); | ||
Dropdown.prototype._initializeCustomDropdown = function _initializeCustomDropdown() { | ||
if (this._label) { | ||
odoHelpers.giveId(this._label, this.id + '-label'); | ||
var _id = this._label.id; | ||
if (this.options.useNative) { | ||
this._initializeNativeDropdown(); | ||
} else { | ||
this._initializeCustomDropdown(); | ||
} | ||
}; | ||
this._optionsContainer.setAttribute('aria-labelledby', _id); | ||
} | ||
/** | ||
* Return the selected custom option element. | ||
* @return {Element} | ||
*/ | ||
this._select.tabIndex = -1; | ||
this._select.setAttribute('aria-hidden', true); | ||
this._button.setAttribute('aria-haspopup', 'true'); | ||
this._button.setAttribute('aria-controls', this._select.id); | ||
this._button.setAttribute('aria-expanded', false); | ||
this._toggleButtonListener(true); | ||
this.element.addEventListener('keydown', this._onKey); | ||
}; | ||
Dropdown.prototype._getCustomSelectedOption = function _getCustomSelectedOption() { | ||
return this.getCustomOptions()[this._select.selectedIndex]; | ||
}; | ||
/** | ||
* Key down event occured. | ||
* @param {KeyboardEvent} e Event object. | ||
*/ | ||
/** | ||
* Insert the custom option html markup before the <select> element. | ||
*/ | ||
Dropdown.prototype._handleKey = function _handleKey(e) { | ||
var code = e.which; | ||
Dropdown.prototype._insertMarkup = function _insertMarkup() { | ||
var markup = this.getCustomOptionsHtml(); | ||
this._select.insertAdjacentHTML('beforebegin', markup); | ||
}; | ||
if (this._isOpen) { | ||
switch (code) { | ||
case Dropdown.Key.ESC: | ||
case Dropdown.Key.TAB: | ||
this._hideOptions(); | ||
break; | ||
/** | ||
* Listen for change events on the <select>. | ||
*/ | ||
case Dropdown.Key.DOWN: | ||
case Dropdown.Key.UP: | ||
e.preventDefault(); | ||
Dropdown._moveFocus(code === Dropdown.Key.DOWN); | ||
break; | ||
case Dropdown.Key.SPACE: | ||
case Dropdown.Key.ENTER: | ||
e.preventDefault(); | ||
this._selectOption(e.target); | ||
break; | ||
// no default | ||
} | ||
} else { | ||
switch (code) { | ||
case Dropdown.Key.SPACE: | ||
case Dropdown.Key.DOWN: | ||
case Dropdown.Key.UP: | ||
case Dropdown.Key.ENTER: | ||
e.preventDefault(); | ||
this._showOptions(); | ||
break; | ||
// no default | ||
} | ||
} | ||
}; | ||
Dropdown.prototype._initializeNativeDropdown = function _initializeNativeDropdown() { | ||
this.element.classList.add(Dropdown.Classes.BASE_NATIVE); | ||
this._select.addEventListener('change', this._onSelectChange); | ||
/** | ||
* Transer focus from one option to the next or prev enabled option. | ||
* @param {boolean} isNext Whether to focus on the next or previous option. | ||
*/ | ||
// Hide the <button> from the screen reader so that it only reads the | ||
// <select> element. The <select> is actually positioned on top of the | ||
// <button> with zero opacity. | ||
this._button.setAttribute('aria-hidden', true); | ||
this._button.tabIndex = -1; | ||
}; | ||
/** | ||
* Listen for clicks to trigger the menu and keyboard input. | ||
*/ | ||
Dropdown._moveFocus = function _moveFocus(isNext) { | ||
var selector = Dropdown.Selector.ENABLED_OPTION; | ||
var enabledOption = isNext ? Dropdown._nextMatch(document.activeElement, selector) : Dropdown._prevMatch(document.activeElement, selector); | ||
if (enabledOption) { | ||
enabledOption.focus(); | ||
} | ||
}; | ||
Dropdown.prototype._initializeCustomDropdown = function _initializeCustomDropdown() { | ||
if (this._label) { | ||
odoHelpers.giveId(this._label, this.id + '-label'); | ||
var _id = this._label.id; | ||
/** | ||
* Find the next sibling which matches a selector. | ||
* @param {Element} element Element to test. | ||
* @param {string} selector Selector to match. | ||
* @return {?Element} The element or null if there isn't one. | ||
*/ | ||
this._optionsContainer.setAttribute('aria-labelledby', _id); | ||
} | ||
this._select.tabIndex = -1; | ||
this._select.setAttribute('aria-hidden', true); | ||
this._button.setAttribute('aria-haspopup', 'true'); | ||
this._button.setAttribute('aria-controls', this._select.id); | ||
this._button.setAttribute('aria-expanded', false); | ||
Dropdown._nextMatch = function _nextMatch(element, selector) { | ||
while (element = element.nextElementSibling) { | ||
// eslint-disable-line | ||
if (element.matches(selector)) { | ||
return element; | ||
} | ||
} | ||
this._toggleButtonListener(true); | ||
this.element.addEventListener('keydown', this._onKey); | ||
}; | ||
return null; | ||
}; | ||
/** | ||
* Key down event occured. | ||
* @param {KeyboardEvent} e Event object. | ||
*/ | ||
/** | ||
* Find the previous sibling which matches a selector. | ||
* @param {Element} element Element to test. | ||
* @param {string} selector Selector to match. | ||
* @return {?Element} The element or null if there isn't one. | ||
*/ | ||
Dropdown.prototype._handleKey = function _handleKey(e) { | ||
var code = e.which; | ||
if (this._isOpen) { | ||
switch (code) { | ||
case Dropdown.Key.ESC: | ||
case Dropdown.Key.TAB: | ||
this._hideOptions(); | ||
break; | ||
case Dropdown.Key.DOWN: | ||
case Dropdown.Key.UP: | ||
e.preventDefault(); | ||
Dropdown._moveFocus(code === Dropdown.Key.DOWN); | ||
break; | ||
case Dropdown.Key.SPACE: | ||
case Dropdown.Key.ENTER: | ||
e.preventDefault(); | ||
this._selectOption(e.target); | ||
break; | ||
// no default | ||
Dropdown._prevMatch = function _prevMatch(element, selector) { | ||
while (element = element.previousElementSibling) { | ||
// eslint-disable-line | ||
if (element.matches(selector)) { | ||
return element; | ||
} | ||
} | ||
} else { | ||
switch (code) { | ||
case Dropdown.Key.SPACE: | ||
case Dropdown.Key.DOWN: | ||
case Dropdown.Key.UP: | ||
case Dropdown.Key.ENTER: | ||
e.preventDefault(); | ||
this._showOptions(); | ||
break; | ||
// no default | ||
} | ||
} | ||
}; | ||
/** | ||
* Transer focus from one option to the next or prev enabled option. | ||
* @param {boolean} isNext Whether to focus on the next or previous option. | ||
*/ | ||
return null; | ||
}; | ||
/** | ||
* Delegated click event on the document. Check to see if it was an option, | ||
* otherwise hide the dropdown menu. | ||
* @param {MouseEvent} e Event object. | ||
*/ | ||
Dropdown._moveFocus = function _moveFocus(isNext) { | ||
var selector = Dropdown.Selector.ENABLED_OPTION; | ||
var enabledOption = isNext ? Dropdown._nextMatch(document.activeElement, selector) : Dropdown._prevMatch(document.activeElement, selector); | ||
if (enabledOption) { | ||
enabledOption.focus(); | ||
} | ||
}; | ||
/** | ||
* Find the next sibling which matches a selector. | ||
* @param {Element} element Element to test. | ||
* @param {string} selector Selector to match. | ||
* @return {?Element} The element or null if there isn't one. | ||
*/ | ||
Dropdown._nextMatch = function _nextMatch(element, selector) { | ||
while (element = element.nextElementSibling) { | ||
// eslint-disable-line | ||
if (element.matches(selector)) { | ||
return element; | ||
Dropdown.prototype._handlePageClick = function _handlePageClick(e) { | ||
var option = e.target.closest('.' + Dropdown.Classes.OPTION); | ||
if (option) { | ||
this._selectOption(option); | ||
} else { | ||
this._hideOptions(); | ||
} | ||
} | ||
}; | ||
return null; | ||
}; | ||
/** | ||
* Set the current value from an option element. | ||
* @param {Element} option Custom option element. | ||
*/ | ||
/** | ||
* Find the previous sibling which matches a selector. | ||
* @param {Element} element Element to test. | ||
* @param {string} selector Selector to match. | ||
* @return {?Element} The element or null if there isn't one. | ||
*/ | ||
Dropdown._prevMatch = function _prevMatch(element, selector) { | ||
while (element = element.previousElementSibling) { | ||
// eslint-disable-line | ||
if (element.matches(selector)) { | ||
return element; | ||
Dropdown.prototype._selectOption = function _selectOption(option) { | ||
// Avoid selecting disabled options or a target which is not an option (if | ||
// the user rapidly presses space|enter, this method could be called with | ||
// an event target which is not an option element because the transition | ||
// hasn't finished). | ||
if (option.classList.contains(Dropdown.Classes.OPTION_DISABLED) || !option.classList.contains(Dropdown.Classes.OPTION)) { | ||
return; | ||
} | ||
} | ||
return null; | ||
}; | ||
var value = option.getAttribute('data-value'); | ||
this.value = value; | ||
this._hideOptions(); | ||
/** | ||
* Delegated click event on the document. Check to see if it was an option, | ||
* otherwise hide the dropdown menu. | ||
* @param {MouseEvent} e Event object. | ||
*/ | ||
// Emit event to notify watchers that this has changed. | ||
this.emit(Dropdown.EventType.CHANGE, { | ||
name: this.select.name, | ||
value: this.value | ||
}); | ||
}; | ||
/** | ||
* The native <select> input changed. Update the display. | ||
*/ | ||
Dropdown.prototype._handlePageClick = function _handlePageClick(e) { | ||
var option = e.target.closest('.' + Dropdown.Classes.OPTION); | ||
if (option) { | ||
this._selectOption(option); | ||
} else { | ||
this._hideOptions(); | ||
} | ||
}; | ||
/** | ||
* Set the current value from an option element. | ||
* @param {Element} option Custom option element. | ||
*/ | ||
Dropdown.prototype._handleSelectChange = function _handleSelectChange() { | ||
this.value = this._select.value; | ||
// Emit event to notify watchers that this has changed. | ||
this.emit(Dropdown.EventType.CHANGE, { | ||
name: this.select.name, | ||
value: this.value | ||
}); | ||
}; | ||
Dropdown.prototype._selectOption = function _selectOption(option) { | ||
// Avoid selecting disabled options or a target which is not an option (if | ||
// the user rapidly presses space|enter, this method could be called with | ||
// an event target which is not an option element because the transition | ||
// hasn't finished). | ||
if (option.classList.contains(Dropdown.Classes.OPTION_DISABLED) || !option.classList.contains(Dropdown.Classes.OPTION)) { | ||
return; | ||
} | ||
/** | ||
* Add or remove click listener for custom select display element | ||
* @params {boolean} add Whether to add or remove click listener | ||
*/ | ||
var value = option.getAttribute('data-value'); | ||
this.value = value; | ||
this._hideOptions(); | ||
// Emit event to notify watchers that this has changed. | ||
this.emit(Dropdown.EventType.CHANGE, { | ||
name: this.select.name, | ||
value: this.value | ||
}); | ||
}; | ||
Dropdown.prototype._toggleButtonListener = function _toggleButtonListener(add) { | ||
if (add) { | ||
this._button.addEventListener('click', this._onButtonClick); | ||
} else { | ||
this._button.removeEventListener('click', this._onButtonClick); | ||
} | ||
}; | ||
/** | ||
* The native <select> input changed. Update the display. | ||
*/ | ||
/** | ||
* Show the options dropdown menu. | ||
*/ | ||
Dropdown.prototype._handleSelectChange = function _handleSelectChange() { | ||
this.value = this._select.value; | ||
Dropdown.prototype._showOptions = function _showOptions() { | ||
this._isOpen = true; | ||
// Emit event to notify watchers that this has changed. | ||
this.emit(Dropdown.EventType.CHANGE, { | ||
name: this.select.name, | ||
value: this.value | ||
}); | ||
}; | ||
// Clear any pending transition ends. | ||
odoHelpers.cancelTransitionEnd(this._transitionId); | ||
/** | ||
* Add or remove click listener for custom select display element | ||
* @params {boolean} add Whether to add or remove click listener | ||
*/ | ||
// Remove click listener on button. | ||
this._toggleButtonListener(false); | ||
this.element.classList.add(Dropdown.Classes.OPEN); | ||
this._optionsContainer.setAttribute('aria-hidden', false); | ||
this._button.setAttribute('aria-expanded', true); | ||
this._button.tabIndex = -1; | ||
odoHelpers.causeLayout(this._optionsContainer); | ||
this._optionsContainer.classList.add(Dropdown.Classes.OPTIONS_CONTAINER_OPEN); | ||
this._transitionId = odoHelpers.onTransitionEnd(this._optionsContainer, this._handleOptionsShown, this); | ||
}; | ||
Dropdown.prototype._toggleButtonListener = function _toggleButtonListener(add) { | ||
if (add) { | ||
this._button.addEventListener('click', this._onButtonClick); | ||
} else { | ||
this._button.removeEventListener('click', this._onButtonClick); | ||
} | ||
}; | ||
/** | ||
* Options dropdown finished show animation. | ||
*/ | ||
/** | ||
* Show the options dropdown menu. | ||
*/ | ||
Dropdown.prototype._handleOptionsShown = function _handleOptionsShown() { | ||
document.body.addEventListener('click', this._onPageClick); | ||
Dropdown.prototype._showOptions = function _showOptions() { | ||
this._isOpen = true; | ||
// If all the options are disabled, a selected option doesn't exist. | ||
if (this._selectedOption) { | ||
this._selectedOption.focus(); | ||
} | ||
}; | ||
// Clear any pending transition ends. | ||
odoHelpers.cancelTransitionEnd(this._transitionId); | ||
/** | ||
* Hide the options dropdown. | ||
*/ | ||
// Remove click listener on button. | ||
this._toggleButtonListener(false); | ||
this.element.classList.add(Dropdown.Classes.OPEN); | ||
this._optionsContainer.setAttribute('aria-hidden', false); | ||
this._button.setAttribute('aria-expanded', true); | ||
this._button.tabIndex = -1; | ||
odoHelpers.causeLayout(this._optionsContainer); | ||
this._optionsContainer.classList.add(Dropdown.Classes.OPTIONS_CONTAINER_OPEN); | ||
this._transitionId = odoHelpers.onTransitionEnd(this._optionsContainer, this._handleOptionsShown, this); | ||
}; | ||
Dropdown.prototype._hideOptions = function _hideOptions() { | ||
this._isOpen = false; | ||
/** | ||
* Options dropdown finished show animation. | ||
*/ | ||
// Clear any pending transition ends. | ||
odoHelpers.cancelTransitionEnd(this._transitionId); | ||
document.body.removeEventListener('click', this._onPageClick); | ||
this._optionsContainer.setAttribute('aria-hidden', true); | ||
this._button.tabIndex = 0; | ||
this._button.setAttribute('aria-expanded', false); | ||
this._optionsContainer.classList.remove(Dropdown.Classes.OPTIONS_CONTAINER_OPEN); | ||
this._transitionId = odoHelpers.onTransitionEnd(this._optionsContainer, this._handleOptionsHidden, this); | ||
}; | ||
Dropdown.prototype._handleOptionsShown = function _handleOptionsShown() { | ||
document.body.addEventListener('click', this._onPageClick); | ||
/** | ||
* Options dropdown finished hiding. | ||
*/ | ||
// If all the options are disabled, a selected option doesn't exist. | ||
if (this._selectedOption) { | ||
this._selectedOption.focus(); | ||
} | ||
}; | ||
/** | ||
* Hide the options dropdown. | ||
*/ | ||
Dropdown.prototype._handleOptionsHidden = function _handleOptionsHidden() { | ||
this.element.classList.remove(Dropdown.Classes.OPEN); | ||
this._button.focus(); | ||
this._toggleButtonListener(true); | ||
}; | ||
/** | ||
* Generate the HTML to show on non-touch devices. | ||
* @return {string} A string of HTML. | ||
* @protected | ||
*/ | ||
Dropdown.prototype._hideOptions = function _hideOptions() { | ||
this._isOpen = false; | ||
// Clear any pending transition ends. | ||
odoHelpers.cancelTransitionEnd(this._transitionId); | ||
Dropdown.prototype.getCustomOptionsHtml = function getCustomOptionsHtml() { | ||
return '<div class="' + Dropdown.Classes.OPTIONS_CONTAINER + '" role="menu" aria-hidden="true">' + this.getOptionsMarkup() + '</div>'; | ||
}; | ||
document.body.removeEventListener('click', this._onPageClick); | ||
this._optionsContainer.setAttribute('aria-hidden', true); | ||
this._button.tabIndex = 0; | ||
this._button.setAttribute('aria-expanded', false); | ||
this._optionsContainer.classList.remove(Dropdown.Classes.OPTIONS_CONTAINER_OPEN); | ||
this._transitionId = odoHelpers.onTransitionEnd(this._optionsContainer, this._handleOptionsHidden, this); | ||
}; | ||
/** | ||
* Generate an HTML string for custom options based on the current options | ||
* in the <select> | ||
* @return {string} Markup. | ||
* @protected | ||
*/ | ||
/** | ||
* Options dropdown finished hiding. | ||
*/ | ||
Dropdown.prototype.getOptionsMarkup = function getOptionsMarkup() { | ||
var _this2 = this; | ||
Dropdown.prototype._handleOptionsHidden = function _handleOptionsHidden() { | ||
this.element.classList.remove(Dropdown.Classes.OPEN); | ||
this._button.focus(); | ||
this._toggleButtonListener(true); | ||
}; | ||
return this.getNativeOptions().reduce(function (str, option) { | ||
return str + _this2.getOptionMarkup(option); | ||
}, ''); | ||
}; | ||
/** | ||
* Generate the HTML to show on non-touch devices. | ||
* @return {string} A string of HTML. | ||
* @protected | ||
*/ | ||
/** | ||
* Create an HTML string to be used for a custom option. | ||
* @param {HTMLOptionElement} option Native option element. | ||
* @return {string} Markup. | ||
* @protected | ||
*/ | ||
Dropdown.prototype.getCustomOptionsHtml = function getCustomOptionsHtml() { | ||
return '<div class="' + Dropdown.Classes.OPTIONS_CONTAINER + '" role="menu" aria-hidden="true">' + this.getOptionsMarkup() + '</div>'; | ||
}; | ||
Dropdown.prototype.getOptionMarkup = function getOptionMarkup(option) { | ||
var selected = option.selected ? ' ' + Dropdown.Classes.OPTION_SELECTED : ''; | ||
var disabled = option.disabled ? ' ' + Dropdown.Classes.OPTION_DISABLED : ''; | ||
var className = Dropdown.Classes.OPTION + selected + disabled; | ||
return '<div class="' + className + '" data-value="' + option.value + '" tabindex="-1" role="menuitem">' + option.text + '</div>'; | ||
}; | ||
/** | ||
* Generate an HTML string for custom options based on the current options | ||
* in the <select> | ||
* @return {string} Markup. | ||
* @protected | ||
*/ | ||
/** | ||
* Return an array of custom option elements. | ||
* @return {Array.<HTMLDivElement>} | ||
*/ | ||
Dropdown.prototype.getOptionsMarkup = function getOptionsMarkup() { | ||
var _this2 = this; | ||
Dropdown.prototype.getCustomOptions = function getCustomOptions() { | ||
return this.getElementsByClass(Dropdown.Classes.OPTION); | ||
}; | ||
return this.getNativeOptions().reduce(function (str, option) { | ||
return str + _this2.getOptionMarkup(option); | ||
}, ''); | ||
}; | ||
/** | ||
* Return an array of option elements. | ||
* @return {Array.<HTMLOptionElement>} | ||
*/ | ||
/** | ||
* Create an HTML string to be used for a custom option. | ||
* @param {HTMLOptionElement} option Native option element. | ||
* @return {string} Markup. | ||
* @protected | ||
*/ | ||
Dropdown.prototype.getNativeOptions = function getNativeOptions() { | ||
return Array.from(this.select.options); | ||
}; | ||
Dropdown.prototype.getOptionMarkup = function getOptionMarkup(option) { | ||
var selected = option.selected ? ' ' + Dropdown.Classes.OPTION_SELECTED : ''; | ||
var disabled = option.disabled ? ' ' + Dropdown.Classes.OPTION_DISABLED : ''; | ||
var className = Dropdown.Classes.OPTION + selected + disabled; | ||
return '<div class="' + className + '" data-value="' + option.value + '" tabindex="-1" role="menuitem">' + option.text + '</div>'; | ||
}; | ||
/** | ||
* Retrieve the text to display inside the button. | ||
* @param {number} selectedIndex Index of the selected option. | ||
* @return {string} Text to display. | ||
* @protected | ||
*/ | ||
/** | ||
* Return an array of custom option elements. | ||
* @return {Array.<HTMLDivElement>} | ||
*/ | ||
Dropdown.prototype.getDisplayText = function getDisplayText(selectedIndex) { | ||
return this.select.options[selectedIndex].text; | ||
}; | ||
Dropdown.prototype.getCustomOptions = function getCustomOptions() { | ||
return this.getElementsByClass(Dropdown.Classes.OPTION); | ||
}; | ||
/** | ||
* Retrieve the selected index of the <select> | ||
* @return {number} | ||
*/ | ||
/** | ||
* Return an array of option elements. | ||
* @return {Array.<HTMLOptionElement>} | ||
*/ | ||
/** | ||
* Toggle the state of an option. | ||
* @param {string} value Value of the option to toggle. | ||
* @param {boolean} isDisabled Whether to disable it or not. | ||
* @return {Dropdown} This instance for chaining. | ||
*/ | ||
Dropdown.prototype.toggleOptionByValue = function toggleOptionByValue(value, isDisabled) { | ||
var customOption = this._optionsContainer.querySelector('[data-value="' + value + '"]'); | ||
var nativeOption = this._select.querySelector('[value="' + value + '"]'); | ||
Dropdown.prototype.getNativeOptions = function getNativeOptions() { | ||
return Array.from(this.select.options); | ||
}; | ||
customOption.classList.toggle(Dropdown.Classes.OPTION_DISABLED, isDisabled); | ||
if (isDisabled) { | ||
customOption.setAttribute('aria-disabled', true); | ||
} else { | ||
customOption.removeAttribute('aria-disabled'); | ||
} | ||
/** | ||
* Retrieve the text to display inside the button. | ||
* @param {number} selectedIndex Index of the selected option. | ||
* @return {string} Text to display. | ||
* @protected | ||
*/ | ||
nativeOption.disabled = isDisabled; | ||
return this; | ||
}; | ||
Dropdown.prototype.getDisplayText = function getDisplayText(selectedIndex) { | ||
return this.select.options[selectedIndex].text; | ||
}; | ||
/** | ||
* Disable an option. | ||
* @param {string} value Value of the option to disable. | ||
* @return {Dropdown} This instance. | ||
*/ | ||
/** | ||
* Retrieve the selected index of the <select> | ||
* @return {number} | ||
*/ | ||
Dropdown.prototype.disableOptionByValue = function disableOptionByValue(value) { | ||
return this.toggleOptionByValue(value, true); | ||
}; | ||
/** | ||
* Toggle the state of an option. | ||
* @param {string} value Value of the option to toggle. | ||
* @param {boolean} isDisabled Whether to disable it or not. | ||
* @return {Dropdown} This instance for chaining. | ||
*/ | ||
Dropdown.prototype.toggleOptionByValue = function toggleOptionByValue(value, isDisabled) { | ||
var customOption = this._optionsContainer.querySelector('[data-value="' + value + '"]'); | ||
var nativeOption = this._select.querySelector('[value="' + value + '"]'); | ||
/** | ||
* Enable an option. | ||
* @param {string} value Value of the option to enable. | ||
* @return {Dropdown} This instance. | ||
*/ | ||
customOption.classList.toggle(Dropdown.Classes.OPTION_DISABLED, isDisabled); | ||
if (isDisabled) { | ||
customOption.setAttribute('aria-disabled', true); | ||
} else { | ||
customOption.removeAttribute('aria-disabled'); | ||
} | ||
nativeOption.disabled = isDisabled; | ||
Dropdown.prototype.enableOptionByValue = function enableOptionByValue(value) { | ||
return this.toggleOptionByValue(value, false); | ||
}; | ||
return this; | ||
}; | ||
Dropdown.prototype.dispose = function dispose() { | ||
this._select.removeEventListener('change', this._onSelectChange); | ||
this._button.removeEventListener('click', this._onButtonClick); | ||
document.body.removeEventListener('click', this._onPageClick); | ||
this._optionsContainer.parentNode.removeChild(this._optionsContainer); | ||
/** | ||
* Disable an option. | ||
* @param {string} value Value of the option to disable. | ||
* @return {Dropdown} This instance. | ||
*/ | ||
// Prefer resetting the tabIndex property by using removeAttribute to lets the | ||
// browser decide if it should go back to 0 (like if it was a button) or to | ||
// -1 if it wasn't originally focusable. | ||
this._select.removeAttribute('tabindex'); | ||
this._select.removeAttribute('aria-hidden'); | ||
this._button.removeAttribute('tabindex'); | ||
this._button.removeAttribute('aria-hidden'); | ||
this._button.removeAttribute('aria-haspopup'); | ||
this._button.removeAttribute('aria-controls'); | ||
this._button.removeAttribute('aria-expanded'); | ||
this._selectedOption = null; | ||
this._optionsContainer = null; | ||
this._button = null; | ||
this._placeholder = null; | ||
this._valueContainer = null; | ||
this._select = null; | ||
_OdoBaseComponent.prototype.dispose.call(this); | ||
}; | ||
Dropdown.prototype.disableOptionByValue = function disableOptionByValue(value) { | ||
return this.toggleOptionByValue(value, true); | ||
}; | ||
createClass(Dropdown, [{ | ||
key: 'selectedIndex', | ||
get: function get$$1() { | ||
return this._select.selectedIndex; | ||
} | ||
/** | ||
* Enable an option. | ||
* @param {string} value Value of the option to enable. | ||
* @return {Dropdown} This instance. | ||
*/ | ||
/** | ||
* Set the selected option by index. | ||
* @param {number} index Index to select. | ||
*/ | ||
, | ||
set: function set$$1(index) { | ||
this.value = this._select.options[index].value; | ||
} | ||
/** | ||
* Returns the <select>. | ||
* @return {HTMLSelectElement} | ||
*/ | ||
Dropdown.prototype.enableOptionByValue = function enableOptionByValue(value) { | ||
return this.toggleOptionByValue(value, false); | ||
}; | ||
}, { | ||
key: 'select', | ||
get: function get$$1() { | ||
return this._select; | ||
} | ||
Dropdown.prototype.dispose = function dispose() { | ||
this._select.removeEventListener('change', this._onSelectChange); | ||
this._button.removeEventListener('click', this._onButtonClick); | ||
document.body.removeEventListener('click', this._onPageClick); | ||
this._optionsContainer.parentNode.removeChild(this._optionsContainer); | ||
/** | ||
* Returns the button to open the select menu. | ||
* @return {HTMLButtonElement} | ||
*/ | ||
// Prefer resetting the tabIndex property by using removeAttribute to lets the | ||
// browser decide if it should go back to 0 (like if it was a button) or to | ||
// -1 if it wasn't originally focusable. | ||
this._select.removeAttribute('tabindex'); | ||
this._select.removeAttribute('aria-hidden'); | ||
this._button.removeAttribute('tabindex'); | ||
this._button.removeAttribute('aria-hidden'); | ||
this._button.removeAttribute('aria-haspopup'); | ||
this._button.removeAttribute('aria-controls'); | ||
this._button.removeAttribute('aria-expanded'); | ||
}, { | ||
key: 'button', | ||
get: function get$$1() { | ||
return this._button; | ||
} | ||
this._selectedOption = null; | ||
this._optionsContainer = null; | ||
this._button = null; | ||
this._placeholder = null; | ||
this._valueContainer = null; | ||
this._select = null; | ||
_OdoBaseComponent.prototype.dispose.call(this); | ||
}; | ||
/** | ||
* Return the display text for the currently selected option. | ||
* @returns {string} | ||
*/ | ||
createClass(Dropdown, [{ | ||
key: 'selectedIndex', | ||
get: function get$$1() { | ||
return this._select.selectedIndex; | ||
} | ||
}, { | ||
key: 'selectedText', | ||
get: function get$$1() { | ||
return this._select.options[this._select.selectedIndex].text; | ||
} | ||
/** | ||
* Set the selected option by index. | ||
* @param {number} index Index to select. | ||
*/ | ||
, | ||
set: function set$$1(index) { | ||
this.value = this._select.options[index].value; | ||
} | ||
/** | ||
* Retrieve the selected value. | ||
* @return {string} | ||
*/ | ||
/** | ||
* Returns the <select>. | ||
* @return {HTMLSelectElement} | ||
*/ | ||
}, { | ||
key: 'value', | ||
get: function get$$1() { | ||
return this._select.value; | ||
} | ||
}, { | ||
key: 'select', | ||
get: function get$$1() { | ||
return this._select; | ||
} | ||
/** | ||
* Set the value of the <select> and the custom menu. | ||
* @param {string} value Value which matches one of the options. | ||
*/ | ||
, | ||
set: function set$$1(value) { | ||
// Remove the old selected class. | ||
if (this._selectedOption) { | ||
this._selectedOption.classList.remove(Dropdown.Classes.OPTION_SELECTED); | ||
} | ||
/** | ||
* Returns the button to open the select menu. | ||
* @return {HTMLButtonElement} | ||
*/ | ||
// Set new value. | ||
this._select.value = value; | ||
}, { | ||
key: 'button', | ||
get: function get$$1() { | ||
return this._button; | ||
} | ||
// Update currently selected option. | ||
this._selectedOption = this._getCustomSelectedOption(); | ||
/** | ||
* Return the display text for the currently selected option. | ||
* @returns {string} | ||
*/ | ||
if (this._selectedOption) { | ||
// Read the text for the new value. | ||
var text = this.getDisplayText(this.selectedIndex); | ||
}, { | ||
key: 'selectedText', | ||
get: function get$$1() { | ||
return this._select.options[this._select.selectedIndex].text; | ||
} | ||
this._selectedOption.classList.add(Dropdown.Classes.OPTION_SELECTED); | ||
/** | ||
* Retrieve the selected value. | ||
* @return {string} | ||
*/ | ||
// Update display. | ||
this._placeholder.style.display = 'none'; | ||
this._placeholder.setAttribute('aria-hidden', true); | ||
this._valueContainer.textContent = text; | ||
this._valueContainer.removeAttribute('aria-hidden'); | ||
} else { | ||
this._placeholder.style.display = ''; | ||
this._placeholder.removeAttribute('aria-hidden'); | ||
this._valueContainer.textContent = ''; | ||
this._valueContainer.setAttribute('aria-hidden', true); | ||
} | ||
} | ||
}, { | ||
key: 'value', | ||
get: function get$$1() { | ||
return this._select.value; | ||
} | ||
/** | ||
* Get the disabled state of the component. | ||
* @return {boolean} | ||
*/ | ||
/** | ||
* Set the value of the <select> and the custom menu. | ||
* @param {string} value Value which matches one of the options. | ||
*/ | ||
, | ||
set: function set$$1(value) { | ||
// Remove the old selected class. | ||
if (this._selectedOption) { | ||
this._selectedOption.classList.remove(Dropdown.Classes.OPTION_SELECTED); | ||
}, { | ||
key: 'disabled', | ||
get: function get$$1() { | ||
return this.select.disabled; | ||
} | ||
// Set new value. | ||
this._select.value = value; | ||
/** | ||
* Set the disabled state of the component. | ||
* @param {boolean} isDisabled Whether it's disabled or not. | ||
*/ | ||
, | ||
set: function set$$1(isDisabled) { | ||
this.select.disabled = isDisabled; | ||
this.button.disabled = isDisabled; | ||
} | ||
}]); | ||
return Dropdown; | ||
}(OdoBaseComponent); | ||
// Update currently selected option. | ||
this._selectedOption = this._getCustomSelectedOption(); | ||
Dropdown.Classes = { | ||
BASE: 'odo-dropdown', | ||
OPEN: 'odo-dropdown--open', | ||
BUTTON: 'odo-dropdown__button', | ||
OPTIONS_CONTAINER_OPEN: 'odo-dropdown__options--open', | ||
OPTIONS_CONTAINER: 'odo-dropdown__options', | ||
OPTION: 'odo-dropdown__option', | ||
OPTION_SELECTED: 'odo-dropdown__option--active', | ||
OPTION_DISABLED: 'odo-dropdown__option--disabled', | ||
SELECT: 'odo-dropdown__select', | ||
VALUE: 'odo-dropdown__value', | ||
DEFAULT: 'odo-dropdown__default', | ||
BASE_NATIVE: 'odo-dropdown--native' | ||
}; | ||
if (this._selectedOption) { | ||
// Read the text for the new value. | ||
var text = this.getDisplayText(this.selectedIndex); | ||
Dropdown.Key = { | ||
TAB: 9, | ||
ENTER: 13, | ||
ESC: 27, | ||
SPACE: 32, | ||
UP: 38, | ||
DOWN: 40 | ||
}; | ||
this._selectedOption.classList.add(Dropdown.Classes.OPTION_SELECTED); | ||
Dropdown.EventType = { | ||
CHANGE: 'ododropdown:change' | ||
}; | ||
// Update display. | ||
this._placeholder.style.display = 'none'; | ||
this._placeholder.setAttribute('aria-hidden', true); | ||
this._valueContainer.textContent = text; | ||
this._valueContainer.removeAttribute('aria-hidden'); | ||
} else { | ||
this._placeholder.style.display = ''; | ||
this._placeholder.removeAttribute('aria-hidden'); | ||
this._valueContainer.textContent = ''; | ||
this._valueContainer.setAttribute('aria-hidden', true); | ||
} | ||
} | ||
Dropdown.Selector = { | ||
ENABLED_OPTION: '.' + Dropdown.Classes.OPTION + ':not(.' + Dropdown.Classes.OPTION_DISABLED + ')' | ||
}; | ||
/** | ||
* Get the disabled state of the component. | ||
* @return {boolean} | ||
*/ | ||
Dropdown.Defaults = { | ||
insertMarkup: true, | ||
useNative: OdoDevice.HAS_TOUCH_EVENTS | ||
}; | ||
}, { | ||
key: 'disabled', | ||
get: function get$$1() { | ||
return this.select.disabled; | ||
} | ||
/** | ||
* Set the disabled state of the component. | ||
* @param {boolean} isDisabled Whether it's disabled or not. | ||
*/ | ||
, | ||
set: function set$$1(isDisabled) { | ||
this.select.disabled = isDisabled; | ||
this.button.disabled = isDisabled; | ||
} | ||
}]); | ||
return Dropdown; | ||
}(OdoBaseComponent); | ||
Dropdown.Classes = { | ||
BASE: 'odo-dropdown', | ||
OPEN: 'odo-dropdown--open', | ||
BUTTON: 'odo-dropdown__button', | ||
OPTIONS_CONTAINER_OPEN: 'odo-dropdown__options--open', | ||
OPTIONS_CONTAINER: 'odo-dropdown__options', | ||
OPTION: 'odo-dropdown__option', | ||
OPTION_SELECTED: 'odo-dropdown__option--active', | ||
OPTION_DISABLED: 'odo-dropdown__option--disabled', | ||
SELECT: 'odo-dropdown__select', | ||
VALUE: 'odo-dropdown__value', | ||
DEFAULT: 'odo-dropdown__default', | ||
BASE_NATIVE: 'odo-dropdown--native' | ||
}; | ||
Dropdown.Key = { | ||
TAB: 9, | ||
ENTER: 13, | ||
ESC: 27, | ||
SPACE: 32, | ||
UP: 38, | ||
DOWN: 40 | ||
}; | ||
Dropdown.EventType = { | ||
CHANGE: 'ododropdown:change' | ||
}; | ||
Dropdown.Selector = { | ||
ENABLED_OPTION: '.' + Dropdown.Classes.OPTION + ':not(.' + Dropdown.Classes.OPTION_DISABLED + ')' | ||
}; | ||
Dropdown.Defaults = { | ||
insertMarkup: true, | ||
useNative: OdoDevice.HAS_TOUCH_EVENTS | ||
}; | ||
return Dropdown; | ||
}))); | ||
//# sourceMappingURL=odo-dropdown.js.map |
{ | ||
"name": "@odopod/odo-dropdown", | ||
"description": "Custom dropdown component that defaults to native select elements on touch devices.", | ||
"version": "2.1.0", | ||
"version": "2.1.1", | ||
"main": "dist/odo-dropdown.js", | ||
@@ -23,4 +23,4 @@ "module": "dist/odo-dropdown.esm.js", | ||
"@odopod/odo-base-component": "^1.2.1", | ||
"@odopod/odo-device": "^1.2.0", | ||
"@odopod/odo-helpers": "^2.0.1" | ||
"@odopod/odo-device": "^1.3.0", | ||
"@odopod/odo-helpers": "^2.0.2" | ||
}, | ||
@@ -27,0 +27,0 @@ "homepage": "https://github.com/odopod/code-library/tree/master/packages/odo-dropdown", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
162911
Updated@odopod/odo-device@^1.3.0
Updated@odopod/odo-helpers@^2.0.2