From ef7e4ebd57c17e3fda194aed282f92f16da4c622 Mon Sep 17 00:00:00 2001 From: Andrew Durber Date: Wed, 27 Dec 2017 09:21:32 +0000 Subject: [PATCH] feat(render-prop): Added render prop support New prop that supports custom rendering of items. Docs updated. closes #7 --- README.md | 99 ++++++++++++++++++++++++++++++++++++--------- docs/README.md | 99 ++++++++++++++++++++++++++++++++++++--------- src/Picky.js | 51 ++++++++++++++++------- tests/Picky.test.js | 15 +++++++ 4 files changed, 211 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index dd87eb0..c3d78a0 100644 --- a/README.md +++ b/README.md @@ -66,19 +66,20 @@ Picky.defaultProps = { filterDebounce: 150, dropdownHeight: 300, onChange: () => {}, - placeholder: 'None selected' + itemHeight: 35 }; Picky.propTypes = { placeholder: PropTypes.string, value: PropTypes.oneOfType([ PropTypes.array, PropTypes.string, - PropTypes.number + PropTypes.number, + PropTypes.object ]), numberDisplayed: PropTypes.number, multiple: PropTypes.bool, - options: PropTypes.array, - onChange: PropTypes.func, + options: PropTypes.array.isRequired, + onChange: PropTypes.func.isRequired, open: PropTypes.bool, includeSelectAll: PropTypes.bool, includeFilter: PropTypes.bool, @@ -86,27 +87,87 @@ Picky.propTypes = { dropdownHeight: PropTypes.number, onFiltered: PropTypes.func, onOpen: PropTypes.func, - onClose: PropTypes.func + onClose: PropTypes.func, + valueKey: PropTypes.string, + labelKey: PropTypes.string, + render: PropTypes.func, + itemHeight: PropTypes.number }; ``` ### Prop descriptions -* `placeholder` - Default message when no items are selected +* `placeholder` - Default message when no items are selected. * `value` - The selected value(s), array if multiple is true. +* `numberDisplayed` - Then number of selected options displayed until it turns into '(selected count) selected'. +* `multiple` - Set to true for a multiselect, defaults to false. +* `options` - Array of possible options. +* `onChange` - Called whenever selected value(s) have changed. This is a controlled component. Pass the selected value back into `value`. +* `open` - Can open or close the dropdown manually. Defaults to false. +* `includeSelectAll` - If set to `true` will add a `Select All` checkbox at the top of the list. +* `includeFilter` - If set to `true` will add an input at the top of the dropdown for filtering the results. +* `filterDebounce` - Debounce timeout, used to limit the rate the internal `onFilterChange` gets called. Defaults to 150ms. +* `dropdownHeight` - The height of the dropdown. Defaults to 300px. +* `onFiltered` - Called after a filter has been done with the filtered options. +* `onOpen` - Called after the dropdown has opened. +* `onClose` - Called after the dropdown has closed. +* `valueKey` - If supplying an array of objects as options, this is required. It's used to identify which property on the object is the value. +* `labelKey` - If supplying an array of objects as options, this is required. It's used to identify which property on the object is the label. +* `render` - Used for custom rendering of items in the dropdown. More info below. +* `itemHeight` - Used when dropdown item height is larger than 35px. This is so the virtualised list can calculate correctly. + +## Custom rendering + +You can render out custom items for the dropdown. + +**Example** -- `numberDisplayed` - Then number of selected options displayed until it turns into '(selected count) selected' -- `multiple` - Set to true for a multiselect, defaults to false -- `options` - Array of possible options -- `onChange` - Called whenever selected value(s) have changed. This is a controlled component. Pass the selected value back into `value`. -- `open` - Can open or close the dropdown manually. Defaults to false. -- `includeSelectAll` - If set to `true` will add a `Select All` checkbox at the top of the list. -- `includeFilter` - If set to `true` will add an input at the top of the dropdown for filtering the results -- `filterDebounce` - Debounce timeout, used to limit the rate the internal `onFilterChange` gets called. Defaults to 150ms -- `dropdownHeight` - The height of the dropdown. Defaults to 300px. -- `onFiltered` - Called after a filter has been done with the filtered options -- `onOpen` - Called after the dropdown has opened. -- `onClose` - Called after the dropdown has closed. - # Internals +```javascript + { + return ( +
  • selectValue(item)} + > + {' '} + // required to select item + + {item[labelKey]} +
  • + ); + }} +/> +``` + +The render callback gets called with the following properties: +style, isSelected, item, labelKey, valueKey, selectValue + +* `style` - object - used by react-tiny-virtual-list for rendering out the items. It needs these to calculate the items location and size. This is required. +* `isSelected` - boolean - true if item is selected. Use this for styling accordingly. +* `item` - object | number | string - The item to render. +* `labelKey` - Used to get the label if item is an object +* `valueKey` - Used to get the value if item is an object, good for keys. +* `selectValue` - function(item) - Selects the item on click + +**Note** + +* If your rendered item affects the height of the item in anyway. Supply `itemHeight` to Picky. +* If you wish to show a radio button or a checkbox, be sure to add `readOnly` prop to the input. + +# Internals The component uses [React Tiny Virtual List](https://github.com/clauderic/react-tiny-virtual-list) for rendering out the items. This is a for a performance gain. You can have 1,000,000 items in the dropdown with no performance drop! It's such a great little library. This is why we have a dropdown height. diff --git a/docs/README.md b/docs/README.md index dd87eb0..c3d78a0 100644 --- a/docs/README.md +++ b/docs/README.md @@ -66,19 +66,20 @@ Picky.defaultProps = { filterDebounce: 150, dropdownHeight: 300, onChange: () => {}, - placeholder: 'None selected' + itemHeight: 35 }; Picky.propTypes = { placeholder: PropTypes.string, value: PropTypes.oneOfType([ PropTypes.array, PropTypes.string, - PropTypes.number + PropTypes.number, + PropTypes.object ]), numberDisplayed: PropTypes.number, multiple: PropTypes.bool, - options: PropTypes.array, - onChange: PropTypes.func, + options: PropTypes.array.isRequired, + onChange: PropTypes.func.isRequired, open: PropTypes.bool, includeSelectAll: PropTypes.bool, includeFilter: PropTypes.bool, @@ -86,27 +87,87 @@ Picky.propTypes = { dropdownHeight: PropTypes.number, onFiltered: PropTypes.func, onOpen: PropTypes.func, - onClose: PropTypes.func + onClose: PropTypes.func, + valueKey: PropTypes.string, + labelKey: PropTypes.string, + render: PropTypes.func, + itemHeight: PropTypes.number }; ``` ### Prop descriptions -* `placeholder` - Default message when no items are selected +* `placeholder` - Default message when no items are selected. * `value` - The selected value(s), array if multiple is true. +* `numberDisplayed` - Then number of selected options displayed until it turns into '(selected count) selected'. +* `multiple` - Set to true for a multiselect, defaults to false. +* `options` - Array of possible options. +* `onChange` - Called whenever selected value(s) have changed. This is a controlled component. Pass the selected value back into `value`. +* `open` - Can open or close the dropdown manually. Defaults to false. +* `includeSelectAll` - If set to `true` will add a `Select All` checkbox at the top of the list. +* `includeFilter` - If set to `true` will add an input at the top of the dropdown for filtering the results. +* `filterDebounce` - Debounce timeout, used to limit the rate the internal `onFilterChange` gets called. Defaults to 150ms. +* `dropdownHeight` - The height of the dropdown. Defaults to 300px. +* `onFiltered` - Called after a filter has been done with the filtered options. +* `onOpen` - Called after the dropdown has opened. +* `onClose` - Called after the dropdown has closed. +* `valueKey` - If supplying an array of objects as options, this is required. It's used to identify which property on the object is the value. +* `labelKey` - If supplying an array of objects as options, this is required. It's used to identify which property on the object is the label. +* `render` - Used for custom rendering of items in the dropdown. More info below. +* `itemHeight` - Used when dropdown item height is larger than 35px. This is so the virtualised list can calculate correctly. + +## Custom rendering + +You can render out custom items for the dropdown. + +**Example** -- `numberDisplayed` - Then number of selected options displayed until it turns into '(selected count) selected' -- `multiple` - Set to true for a multiselect, defaults to false -- `options` - Array of possible options -- `onChange` - Called whenever selected value(s) have changed. This is a controlled component. Pass the selected value back into `value`. -- `open` - Can open or close the dropdown manually. Defaults to false. -- `includeSelectAll` - If set to `true` will add a `Select All` checkbox at the top of the list. -- `includeFilter` - If set to `true` will add an input at the top of the dropdown for filtering the results -- `filterDebounce` - Debounce timeout, used to limit the rate the internal `onFilterChange` gets called. Defaults to 150ms -- `dropdownHeight` - The height of the dropdown. Defaults to 300px. -- `onFiltered` - Called after a filter has been done with the filtered options -- `onOpen` - Called after the dropdown has opened. -- `onClose` - Called after the dropdown has closed. - # Internals +```javascript + { + return ( +
  • selectValue(item)} + > + {' '} + // required to select item + + {item[labelKey]} +
  • + ); + }} +/> +``` + +The render callback gets called with the following properties: +style, isSelected, item, labelKey, valueKey, selectValue + +* `style` - object - used by react-tiny-virtual-list for rendering out the items. It needs these to calculate the items location and size. This is required. +* `isSelected` - boolean - true if item is selected. Use this for styling accordingly. +* `item` - object | number | string - The item to render. +* `labelKey` - Used to get the label if item is an object +* `valueKey` - Used to get the value if item is an object, good for keys. +* `selectValue` - function(item) - Selects the item on click + +**Note** + +* If your rendered item affects the height of the item in anyway. Supply `itemHeight` to Picky. +* If you wish to show a radio button or a checkbox, be sure to add `readOnly` prop to the input. + +# Internals The component uses [React Tiny Virtual List](https://github.com/clauderic/react-tiny-virtual-list) for rendering out the items. This is a for a performance gain. You can have 1,000,000 items in the dropdown with no performance drop! It's such a great little library. This is why we have a dropdown height. diff --git a/src/Picky.js b/src/Picky.js index e6e78ad..778ff5d 100644 --- a/src/Picky.js +++ b/src/Picky.js @@ -85,14 +85,21 @@ class Picky extends React.Component { } renderOptions() { - const { options, value, dropdownHeight, labelKey, valueKey } = this.props; + const { + options, + value, + dropdownHeight, + labelKey, + valueKey, + itemHeight + } = this.props; const items = this.state.filtered ? this.state.filteredOptions : options; return ( { const item = items[index]; const key = isDataObject(item, labelKey, valueKey) @@ -103,17 +110,28 @@ class Picky extends React.Component { (Array.isArray(value) && value.includes(item)) || (!Array.isArray(value) && value === item); - return ( -