From 8a09ef2e4349a341c25e971f10431a0e80cea52d Mon Sep 17 00:00:00 2001 From: Jochen Berger Date: Thu, 18 May 2017 15:04:47 +0200 Subject: [PATCH] remove create-react-class dependency from main sources --- package.json | 2 +- src/AsyncCreatable.js | 11 +- src/Creatable.js | 167 +++++++++--------- src/Option.js | 61 ++++--- src/Select.js | 393 ++++++++++++++++++++++-------------------- src/Value.js | 45 +++-- 6 files changed, 362 insertions(+), 317 deletions(-) diff --git a/package.json b/package.json index 2b8fc4caea..6393024add 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,6 @@ "url": "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/JedWatson/react-select.git" }, "dependencies": { - "create-react-class": "^15.5.2", "classnames": "^2.2.4", "react-input-autosize": "^1.1.3", "prop-types": "^15.5.8" @@ -21,6 +20,7 @@ "babel-eslint": "^4.1.3", "chai": "^3.5.0", "coveralls": "^2.11.12", + "create-react-class": "^15.5.2", "eslint": "^1.10.3", "eslint-plugin-react": "^3.15.0", "gulp": "^3.9.1", diff --git a/src/AsyncCreatable.js b/src/AsyncCreatable.js index 40c5ed45db..55dd602f1b 100644 --- a/src/AsyncCreatable.js +++ b/src/AsyncCreatable.js @@ -1,5 +1,4 @@ import React from 'react'; -import createClass from 'create-react-class'; import Select from './Select'; function reduce(obj, props = {}){ @@ -11,12 +10,11 @@ function reduce(obj, props = {}){ }, props); } -const AsyncCreatable = createClass({ - displayName: 'AsyncCreatableSelect', +class AsyncCreatableSelect extends React.Component { focus () { this.select.focus(); - }, + } render () { return ( @@ -42,6 +40,7 @@ const AsyncCreatable = createClass({ ); } -}); +}; + +module.exports = AsyncCreatableSelect; -module.exports = AsyncCreatable; diff --git a/src/Creatable.js b/src/Creatable.js index 2f1d843a0b..e4666dc8f5 100644 --- a/src/Creatable.js +++ b/src/Creatable.js @@ -1,78 +1,19 @@ import React from 'react'; -import createClass from 'create-react-class'; import PropTypes from 'prop-types'; import Select from './Select'; import defaultFilterOptions from './utils/defaultFilterOptions'; import defaultMenuRenderer from './utils/defaultMenuRenderer'; -const Creatable = createClass({ - displayName: 'CreatableSelect', +class CreatableSelect extends React.Component { + constructor (props, context) { + super(props, context); - propTypes: { - // Child function responsible for creating the inner Select component - // This component can be used to compose HOCs (eg Creatable and Async) - // (props: Object): PropTypes.element - children: PropTypes.func, - - // See Select.propTypes.filterOptions - filterOptions: PropTypes.any, - - // Searches for any matching option within the set of options. - // This function prevents duplicate options from being created. - // ({ option: Object, options: Array, labelKey: string, valueKey: string }): boolean - isOptionUnique: PropTypes.func, - - // Determines if the current input text represents a valid option. - // ({ label: string }): boolean - isValidNewOption: PropTypes.func, - - // See Select.propTypes.menuRenderer - menuRenderer: PropTypes.any, - - // Factory to create new option. - // ({ label: string, labelKey: string, valueKey: string }): Object - newOptionCreator: PropTypes.func, - - // input change handler: function (inputValue) {} - onInputChange: PropTypes.func, - - // input keyDown handler: function (event) {} - onInputKeyDown: PropTypes.func, - - // new option click handler: function (option) {} - onNewOptionClick: PropTypes.func, - - // See Select.propTypes.options - options: PropTypes.array, - - // Creates prompt/placeholder option text. - // (filterText: string): string - promptTextCreator: PropTypes.func, - - // Decides if a keyDown event (eg its `keyCode`) should result in the creation of a new option. - shouldKeyDownEventCreateNewOption: PropTypes.func, - }, - - // Default prop methods - statics: { - isOptionUnique, - isValidNewOption, - newOptionCreator, - promptTextCreator, - shouldKeyDownEventCreateNewOption - }, - - getDefaultProps () { - return { - filterOptions: defaultFilterOptions, - isOptionUnique, - isValidNewOption, - menuRenderer: defaultMenuRenderer, - newOptionCreator, - promptTextCreator, - shouldKeyDownEventCreateNewOption, - }; - }, + this.filterOptions = this.filterOptions.bind(this); + this.menuRenderer = this.menuRenderer.bind(this); + this.onInputKeyDown = this.onInputKeyDown.bind(this); + this.onInputChange = this.onInputChange.bind(this); + this.onOptionSelect = this.onOptionSelect .bind(this); + } createNewOption () { const { @@ -98,7 +39,7 @@ const Creatable = createClass({ } } } - }, + } filterOptions (...params) { const { filterOptions, isValidNewOption, options, promptTextCreator } = this.props; @@ -140,7 +81,7 @@ const Creatable = createClass({ } return filteredOptions; - }, + } isOptionUnique ({ option, @@ -156,7 +97,7 @@ const Creatable = createClass({ options, valueKey: this.valueKey }); - }, + } menuRenderer (params) { const { menuRenderer } = this.props; @@ -166,7 +107,7 @@ const Creatable = createClass({ onSelect: this.onOptionSelect, selectValue: this.onOptionSelect }); - }, + } onInputChange (input) { const { onInputChange } = this.props; @@ -177,7 +118,7 @@ const Creatable = createClass({ // This value may be needed in between Select mounts (when this.select is null) this.inputValue = input; - }, + } onInputKeyDown (event) { const { shouldKeyDownEventCreateNewOption, onInputKeyDown } = this.props; @@ -195,7 +136,7 @@ const Creatable = createClass({ } else if (onInputKeyDown) { onInputKeyDown(event); } - }, + } onOptionSelect (option, event) { if (option === this._createPlaceholderOption) { @@ -203,11 +144,11 @@ const Creatable = createClass({ } else { this.select.selectValue(option); } - }, + } focus () { this.select.focus(); - }, + } render () { const { @@ -245,7 +186,7 @@ const Creatable = createClass({ return children(props); } -}); +}; function defaultChildren (props) { return ( @@ -269,9 +210,9 @@ function isValidNewOption ({ label }) { function newOptionCreator ({ label, labelKey, valueKey }) { const option = {}; option[valueKey] = label; - option[labelKey] = label; - option.className = 'Select-create-option-placeholder'; - return option; + option[labelKey] = label; + option.className = 'Select-create-option-placeholder'; + return option; }; function promptTextCreator (label) { @@ -289,4 +230,68 @@ function shouldKeyDownEventCreateNewOption ({ keyCode }) { return false; }; -module.exports = Creatable; + // Default prop methods +CreatableSelect.isOptionUnique = isOptionUnique; +CreatableSelect.isValidNewOption = isValidNewOption; +CreatableSelect.newOptionCreator = newOptionCreator; +CreatableSelect.promptTextCreator = promptTextCreator; +CreatableSelect.shouldKeyDownEventCreateNewOption = shouldKeyDownEventCreateNewOption; + + +CreatableSelect.defaultProps = { + filterOptions: defaultFilterOptions, + isOptionUnique, + isValidNewOption, + menuRenderer: defaultMenuRenderer, + newOptionCreator, + promptTextCreator, + shouldKeyDownEventCreateNewOption +}; + +CreatableSelect.propTypes = { + // Child function responsible for creating the inner Select component + // This component can be used to compose HOCs (eg Creatable and Async) + // (props: Object): PropTypes.element + children: PropTypes.func, + + // See Select.propTypes.filterOptions + filterOptions: PropTypes.any, + + // Searches for any matching option within the set of options. + // This function prevents duplicate options from being created. + // ({ option: Object, options: Array, labelKey: string, valueKey: string }): boolean + isOptionUnique: PropTypes.func, + + // Determines if the current input text represents a valid option. + // ({ label: string }): boolean + isValidNewOption: PropTypes.func, + + // See Select.propTypes.menuRenderer + menuRenderer: PropTypes.any, + + // Factory to create new option. + // ({ label: string, labelKey: string, valueKey: string }): Object + newOptionCreator: PropTypes.func, + + // input change handler: function (inputValue) {} + onInputChange: PropTypes.func, + + // input keyDown handler: function (event) {} + onInputKeyDown: PropTypes.func, + + // new option click handler: function (option) {} + onNewOptionClick: PropTypes.func, + + // See Select.propTypes.options + options: PropTypes.array, + + // Creates prompt/placeholder option text. + // (filterText: string): string + promptTextCreator: PropTypes.func, + + // Decides if a keyDown event (eg its `keyCode`) should result in the creation of a new option. + shouldKeyDownEventCreateNewOption: PropTypes.func, +}; + + +module.exports = CreatableSelect; diff --git a/src/Option.js b/src/Option.js index ca38e89517..7cb94802ad 100644 --- a/src/Option.js +++ b/src/Option.js @@ -1,22 +1,20 @@ import React from 'react'; -import createClass from 'create-react-class'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -const Option = createClass({ - propTypes: { - children: PropTypes.node, - className: PropTypes.string, // className (based on mouse position) - instancePrefix: PropTypes.string.isRequired, // unique prefix for the ids (used for aria) - isDisabled: PropTypes.bool, // the option is disabled - isFocused: PropTypes.bool, // the option is focused - isSelected: PropTypes.bool, // the option is selected - onFocus: PropTypes.func, // method to handle mouseEnter on option element - onSelect: PropTypes.func, // method to handle click on option element - onUnfocus: PropTypes.func, // method to handle mouseLeave on option element - option: PropTypes.object.isRequired, // object that is base for that option - optionIndex: PropTypes.number, // index of the option, used to generate unique ids for aria - }, +class Option extends React.Component { + + constructor(props) { + super(props); + + this.handleMouseDown = this.handleMouseDown.bind(this); + this.handleMouseEnter = this.handleMouseEnter.bind(this); + this.handleMouseMove = this.handleMouseMove.bind(this); + this.handleTouchStart = this.handleTouchStart.bind(this); + this.onFocus = this.onFocus.bind(this); + } + + blockEvent (event) { event.preventDefault(); event.stopPropagation(); @@ -28,21 +26,21 @@ const Option = createClass({ } else { window.location.href = event.target.href; } - }, + } handleMouseDown (event) { event.preventDefault(); event.stopPropagation(); this.props.onSelect(this.props.option, event); - }, + } handleMouseEnter (event) { this.onFocus(event); - }, + } handleMouseMove (event) { this.onFocus(event); - }, + } handleTouchEnd(event){ // Check if the view is being dragged, In this case @@ -50,23 +48,24 @@ const Option = createClass({ if(this.dragging) return; this.handleMouseDown(event); - }, + } handleTouchMove (event) { // Set a flag that the view is being dragged this.dragging = true; - }, + } handleTouchStart (event) { // Set a flag that the view is not being dragged this.dragging = false; - }, + } onFocus (event) { if (!this.props.isFocused) { this.props.onFocus(this.props.option, event); } - }, + } + render () { var { option, instancePrefix, optionIndex } = this.props; var className = classNames(this.props.className, option.className); @@ -93,6 +92,20 @@ const Option = createClass({ ); } -}); +}; + +Option.propTypes = { + children: PropTypes.node, + className: PropTypes.string, // className (based on mouse position) + instancePrefix: PropTypes.string.isRequired, // unique prefix for the ids (used for aria) + isDisabled: PropTypes.bool, // the option is disabled + isFocused: PropTypes.bool, // the option is focused + isSelected: PropTypes.bool, // the option is selected + onFocus: PropTypes.func, // method to handle mouseEnter on option element + onSelect: PropTypes.func, // method to handle click on option element + onUnfocus: PropTypes.func, // method to handle mouseLeave on option element + option: PropTypes.object.isRequired, // object that is base for that option + optionIndex: PropTypes.number, // index of the option, used to generate unique ids for aria +}; module.exports = Option; diff --git a/src/Select.js b/src/Select.js index 54c6634a21..6edbdfe34e 100644 --- a/src/Select.js +++ b/src/Select.js @@ -5,7 +5,6 @@ */ import React from 'react'; -import createClass from 'create-react-class'; import PropTypes from 'prop-types'; import ReactDOM from 'react-dom'; import AutosizeInput from 'react-input-autosize'; @@ -42,137 +41,42 @@ const stringOrNode = PropTypes.oneOfType([ let instanceId = 1; -const Select = createClass({ - - displayName: 'Select', - - propTypes: { - addLabelText: PropTypes.string, // placeholder displayed when you want to add a label on a multi-value input - 'aria-describedby': PropTypes.string, // HTML ID(s) of element(s) that should be used to describe this input (for assistive tech) - 'aria-label': PropTypes.string, // Aria label (for assistive tech) - 'aria-labelledby': PropTypes.string, // HTML ID of an element that should be used as the label (for assistive tech) - arrowRenderer: PropTypes.func, // Create drop-down caret element - autoBlur: PropTypes.bool, // automatically blur the component when an option is selected - autofocus: PropTypes.bool, // autofocus the component on mount - autosize: PropTypes.bool, // whether to enable autosizing or not - backspaceRemoves: PropTypes.bool, // whether backspace removes an item if there is no text input - backspaceToRemoveMessage: PropTypes.string, // Message to use for screenreaders to press backspace to remove the current item - {label} is replaced with the item label - className: PropTypes.string, // className for the outer element - clearAllText: stringOrNode, // title for the "clear" control when multi: true - clearRenderer: PropTypes.func, // create clearable x element - clearValueText: stringOrNode, // title for the "clear" control - clearable: PropTypes.bool, // should it be possible to reset value - deleteRemoves: PropTypes.bool, // whether backspace removes an item if there is no text input - delimiter: PropTypes.string, // delimiter to use to join multiple values for the hidden field value - disabled: PropTypes.bool, // whether the Select is disabled or not - escapeClearsValue: PropTypes.bool, // whether escape clears the value when the menu is closed - filterOption: PropTypes.func, // method to filter a single option (option, filterString) - filterOptions: PropTypes.any, // boolean to enable default filtering or function to filter the options array ([options], filterString, [values]) - ignoreAccents: PropTypes.bool, // whether to strip diacritics when filtering - ignoreCase: PropTypes.bool, // whether to perform case-insensitive filtering - inputProps: PropTypes.object, // custom attributes for the Input - inputRenderer: PropTypes.func, // returns a custom input component - instanceId: PropTypes.string, // set the components instanceId - isLoading: PropTypes.bool, // whether the Select is loading externally or not (such as options being loaded) - joinValues: PropTypes.bool, // joins multiple values into a single form field with the delimiter (legacy mode) - labelKey: PropTypes.string, // path of the label value in option objects - matchPos: PropTypes.string, // (any|start) match the start or entire string when filtering - matchProp: PropTypes.string, // (any|label|value) which option property to filter on - menuBuffer: PropTypes.number, // optional buffer (in px) between the bottom of the viewport and the bottom of the menu - menuContainerStyle: PropTypes.object, // optional style to apply to the menu container - menuRenderer: PropTypes.func, // renders a custom menu with options - menuStyle: PropTypes.object, // optional style to apply to the menu - multi: PropTypes.bool, // multi-value input - name: PropTypes.string, // generates a hidden tag with this field name for html forms - noResultsText: stringOrNode, // placeholder displayed when there are no matching search results - onBlur: PropTypes.func, // onBlur handler: function (event) {} - onBlurResetsInput: PropTypes.bool, // whether input is cleared on blur - onChange: PropTypes.func, // onChange handler: function (newValue) {} - onClose: PropTypes.func, // fires when the menu is closed - onCloseResetsInput: PropTypes.bool, // whether input is cleared when menu is closed through the arrow - onFocus: PropTypes.func, // onFocus handler: function (event) {} - onInputChange: PropTypes.func, // onInputChange handler: function (inputValue) {} - onInputKeyDown: PropTypes.func, // input keyDown handler: function (event) {} - onMenuScrollToBottom: PropTypes.func, // fires when the menu is scrolled to the bottom; can be used to paginate options - onOpen: PropTypes.func, // fires when the menu is opened - onValueClick: PropTypes.func, // onClick handler for value labels: function (value, event) {} - openAfterFocus: PropTypes.bool, // boolean to enable opening dropdown when focused - openOnFocus: PropTypes.bool, // always open options menu on focus - optionClassName: PropTypes.string, // additional class(es) to apply to the