From 8ca1e8abbacf5339c1506aabb50d66e720387dc6 Mon Sep 17 00:00:00 2001 From: Hernan Anabalon Date: Wed, 26 Feb 2020 14:00:01 -0300 Subject: [PATCH 1/2] refactor: edit Input option from child component to array prop & edit styles --- package-lock.json | 87 +++++++++++++----- src/demo/App.js | 42 +++++---- src/lib/components/AdvanceSearchBar.css | 74 ++++++++-------- src/lib/components/AdvanceSearchBar.jsx | 88 ++++++++++--------- src/lib/components/Input.css | 71 +++++++-------- src/lib/components/Input.jsx | 26 +++--- src/lib/components/InputOption.jsx | 14 --- src/lib/components/InputOptionList.css | 42 +++++---- src/lib/components/InputOptionList.jsx | 38 ++++---- src/lib/components/InputOptionListHelper.jsx | 16 ++-- .../components/InputOptionListTextField.css | 17 ++-- .../components/InputOptionListTextField.jsx | 7 +- src/lib/index.js | 4 +- 13 files changed, 284 insertions(+), 242 deletions(-) delete mode 100644 src/lib/components/InputOption.jsx diff --git a/package-lock.json b/package-lock.json index 93faeff..f9c5867 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4056,7 +4056,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.1.1", @@ -4107,7 +4108,8 @@ "balanced-match": { "version": "0.4.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "bcrypt-pbkdf": { "version": "1.0.1", @@ -4122,6 +4124,7 @@ "version": "0.0.9", "bundled": true, "dev": true, + "optional": true, "requires": { "inherits": "~2.0.0" } @@ -4130,6 +4133,7 @@ "version": "2.10.1", "bundled": true, "dev": true, + "optional": true, "requires": { "hoek": "2.x.x" } @@ -4138,6 +4142,7 @@ "version": "1.1.7", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^0.4.1", "concat-map": "0.0.1" @@ -4146,7 +4151,8 @@ "buffer-shims": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "caseless": { "version": "0.12.0", @@ -4163,12 +4169,14 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "combined-stream": { "version": "1.0.5", "bundled": true, "dev": true, + "optional": true, "requires": { "delayed-stream": "~1.0.0" } @@ -4176,22 +4184,26 @@ "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "cryptiles": { "version": "2.0.5", "bundled": true, "dev": true, + "optional": true, "requires": { "boom": "2.x.x" } @@ -4231,7 +4243,8 @@ "delayed-stream": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "delegates": { "version": "1.0.0", @@ -4263,7 +4276,8 @@ "extsprintf": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "forever-agent": { "version": "0.6.1", @@ -4285,12 +4299,14 @@ "fs.realpath": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "fstream": { "version": "1.0.11", "bundled": true, "dev": true, + "optional": true, "requires": { "graceful-fs": "^4.1.2", "inherits": "~2.0.0", @@ -4346,6 +4362,7 @@ "version": "7.1.2", "bundled": true, "dev": true, + "optional": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -4358,7 +4375,8 @@ "graceful-fs": { "version": "4.1.11", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "har-schema": { "version": "1.0.5", @@ -4386,6 +4404,7 @@ "version": "3.1.3", "bundled": true, "dev": true, + "optional": true, "requires": { "boom": "2.x.x", "cryptiles": "2.x.x", @@ -4396,7 +4415,8 @@ "hoek": { "version": "2.16.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "http-signature": { "version": "1.1.1", @@ -4413,6 +4433,7 @@ "version": "1.0.6", "bundled": true, "dev": true, + "optional": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -4421,7 +4442,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.4", @@ -4433,6 +4455,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -4446,7 +4469,8 @@ "isarray": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "isstream": { "version": "0.1.2", @@ -4519,12 +4543,14 @@ "mime-db": { "version": "1.27.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "mime-types": { "version": "2.1.15", "bundled": true, "dev": true, + "optional": true, "requires": { "mime-db": "~1.27.0" } @@ -4533,6 +4559,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -4540,12 +4567,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "mkdirp": { "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -4600,7 +4629,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "oauth-sign": { "version": "0.8.2", @@ -4618,6 +4648,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -4647,7 +4678,8 @@ "path-is-absolute": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "performance-now": { "version": "0.2.0", @@ -4658,7 +4690,8 @@ "process-nextick-args": { "version": "1.0.7", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "punycode": { "version": "1.4.1", @@ -4696,6 +4729,7 @@ "version": "2.2.9", "bundled": true, "dev": true, + "optional": true, "requires": { "buffer-shims": "~1.0.0", "core-util-is": "~1.0.0", @@ -4740,6 +4774,7 @@ "version": "2.6.1", "bundled": true, "dev": true, + "optional": true, "requires": { "glob": "^7.0.5" } @@ -4747,7 +4782,8 @@ "safe-buffer": { "version": "5.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "semver": { "version": "5.3.0", @@ -4771,6 +4807,7 @@ "version": "1.0.9", "bundled": true, "dev": true, + "optional": true, "requires": { "hoek": "2.x.x" } @@ -4804,6 +4841,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -4814,6 +4852,7 @@ "version": "1.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.0.1" } @@ -4828,6 +4867,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -4842,6 +4882,7 @@ "version": "2.2.1", "bundled": true, "dev": true, + "optional": true, "requires": { "block-stream": "*", "fstream": "^1.0.2", @@ -4897,7 +4938,8 @@ "util-deprecate": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "uuid": { "version": "3.0.1", @@ -4926,7 +4968,8 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, diff --git a/src/demo/App.js b/src/demo/App.js index e41f897..900419e 100644 --- a/src/demo/App.js +++ b/src/demo/App.js @@ -1,5 +1,5 @@ import React from 'react'; -import { AdvanceSearchBar, InputOption } from '../lib'; +import { AdvanceSearchBar } from '../lib'; const FIRST_OPTIONS = [ { name: 'first_suboption0', label: 'Suboption 0' }, @@ -7,27 +7,33 @@ const FIRST_OPTIONS = [ ]; const SECOND_OPTIONS = [ - { name: 'fifth_suboption0', label: 'Suboption 0' }, - { name: 'fifth_suboption1', label: 'Suboption 1' }, - { name: 'fifth_suboption2', label: 'Suboption 2' }, - { name: 'fifth_suboption3', label: 'Suboption 3' } + { name: 'second_suboption0', label: 'Suboption 0' }, + { name: 'second_suboption1', label: 'Suboption 1' }, + { name: 'second_suboption2', label: 'Suboption 2' }, + { name: 'second_suboption3', label: 'Suboption 3' } +]; + +const options = [ + { + name: 'first_option', + label: 'First option', + allowMulti: false + }, + { + name: 'second_option', + label: 'Second option', + allowMulti: true, + options: SECOND_OPTIONS + } ]; // You should pass allowMulti prop in order to make multiple values search! const App = () => ( -
- { window.alert(`Searching parameters\n${Object.keys(params).reduce((memo, key) => { return memo + `${key}: ${params[key]}\n`; }, '')}`); }} - emptyCallback={() => { console.log('Empty'); }} - > - - - - - - - -
+ { window.alert(`Searching parameters\n${Object.keys(params).reduce((memo, key) => { return memo + `${key}: ${params[key]}\n`; }, '')}`); }} + emptyCallback={() => { console.log('Empty'); }} + options={options} + /> ); export default App; diff --git a/src/lib/components/AdvanceSearchBar.css b/src/lib/components/AdvanceSearchBar.css index 1a18949..ffac06c 100644 --- a/src/lib/components/AdvanceSearchBar.css +++ b/src/lib/components/AdvanceSearchBar.css @@ -1,65 +1,66 @@ :root { - --search-bar-active-color: #5b7fb2; + --search-bar-active-color: #f8cb65; --search-bar-inactive-color: #d4d4d4; - --search-bar-height: 40px; - --search-bar-label-height: 20px; + --search-bar-height: 50px; + --search-bar-half-height: 25px; } .search-bar { - align-items: center; - border-radius: 5px; - box-sizing: border-box; + width: 100%; + height: auto; display: flex; - height: 40px; - height: calc(var(--search-bar-height) + var(--search-bar-label-height)); - padding-right: 10px; position: relative; - width: 100%; + border-radius: 4px; + flex-flow: row wrap; + align-items: center; + box-sizing: border-box; background-color: #fff; + box-shadow: 0 8px 8px 0 rgba(0, 0, 0, 0.24), 0 0 8px 0 rgba(0,0,0,0.12); } .search-bar__container { - align-self: flex-end; - border-bottom-left-radius: 4px; - border-top-left-radius: 4px; - display: inline-flex; - height: var(--search-bar-height); + width: 100%; + display: flex; + padding: 0 24px; overflow-x: auto; overflow-y: hidden; + position: relative; white-space: nowrap; - width: 100%; + align-items: center; + border-bottom: solid 1px rgba(0,0,0,0.12); + height: calc(var(--search-bar-height)); } .search-bar__label { - -moz-osx-font-smoothing: grayscale; - -o-text-overflow: ellipsis; - color: #9c9c9c; + top: var(--search-bar-half-height); + left: 24px; + z-index: 0; cursor: text; - font-family: Roboto,sans-serif; + color: #9c9c9c; font-size: 1rem; font-weight: 100; - left: 16px; - letter-spacing: .00937em; - letter-spacing: 0.3px; - line-height: 1.15rem; overflow: hidden; - pointer-events: none; - position: absolute; text-align: left; + position: absolute; + white-space: nowrap; + line-height: 1.15rem; + pointer-events: none; + letter-spacing: 0.3px; text-overflow: ellipsis; - top: 50%; + -o-text-overflow: ellipsis; transform: translateY(-50%); + font-family: Roboto,sans-serif; + -moz-osx-font-smoothing: grayscale; transition: transform .15s cubic-bezier(.4,0,.2,1),color .15s cubic-bezier(.4,0,.2,1),-webkit-transform .15s cubic-bezier(.4,0,.2,1); - white-space: nowrap; - z-index: 1; } .search-bar__label--float { - transform: translateY(calc((-80% - var(--search-bar-height))/2)) translateX(-15px) scale(.75); - color: var(--search-bar-active-color); - padding: 5px 8px; + display: none; left: 8px; + padding: 5px 8px; border-radius: 4px; + color: var(--search-bar-active-color); + transform: translateY(calc((-30% - var(--search-bar-height))/2)) translateX(-15px) scale(.75); } /* BIG TODO */ @@ -92,12 +93,11 @@ } .search-bar__clean { - cursor: pointer; - margin: auto; - position: absolute; - top: 17px; - right: 60px; + right: 0; z-index: 1; + margin: auto; + cursor: pointer; + position: relative; } .search-bar__clean > svg { diff --git a/src/lib/components/AdvanceSearchBar.jsx b/src/lib/components/AdvanceSearchBar.jsx index fd143cb..2cf7e13 100644 --- a/src/lib/components/AdvanceSearchBar.jsx +++ b/src/lib/components/AdvanceSearchBar.jsx @@ -51,9 +51,9 @@ export default class AdvanceSearchBar extends React.Component { // function checking children and setup the only child here setOnlyOption () { - const { children } = this.props; - if (React.Children.count(children) !== 1) return; - const { name, allowMulti } = children.props; + const { options } = this.props; + if (options !== 1) return; + const { name, allowMulti } = options; this.setState({ focus: true, @@ -85,7 +85,7 @@ export default class AdvanceSearchBar extends React.Component { } handleOptionTextChange (value, inputOption, index) { - const { allowMulti, name } = inputOption.props; + const { allowMulti, name } = inputOption; const selectedOptionsCopy = { ...this.state.selectedOptions }; if (allowMulti) { @@ -104,7 +104,7 @@ export default class AdvanceSearchBar extends React.Component { searchIndexSelected: index }); } - + toggleHelper (value) { let optionList = this.getOptionList(); if (optionList.length === 0) return; @@ -122,7 +122,7 @@ export default class AdvanceSearchBar extends React.Component { handleOptionSelect (selectedOption, value = '') { if (!selectedOption) return; - const { name, allowMulti } = selectedOption.props; + const { name, allowMulti } = selectedOption; const selectedOptionsCopy = { ...this.state.selectedOptions }; if (selectedOptionsCopy[name]) { @@ -265,7 +265,7 @@ export default class AdvanceSearchBar extends React.Component { let inputs = []; for (let [key, value] of Object.entries(this.state.selectedOptions)) { - let inputOption = React.Children.toArray(this.props.children).find(({ props }) => props.name === key); + let inputOption = this.props.options.find(({ name }) => name === key); inputs.push( - { optionList } - + /> ); if (inputs.length > 1 || this.state.searchInputValue.length >= 1) { @@ -304,9 +305,9 @@ export default class AdvanceSearchBar extends React.Component { return inputs; } - isAllSubOptionsSelected (child) { + isAllSubOptionsSelected (option) { const { selectedOptions } = this.state; - const { options, name } = child.props; + const { options, name } = option; if (!options || !selectedOptions[name]) return false; @@ -314,13 +315,13 @@ export default class AdvanceSearchBar extends React.Component { } getOptionList = () => { + const { options } = this.props; const { selectedOptions } = this.state; - let children = React.Children.toArray(this.props.children); - return children.filter(child => { - const { allowMulti, name } = child.props; + return options.filter(option => { + const { allowMulti, name } = option; - return (allowMulti && !this.isAllSubOptionsSelected(child)) || !selectedOptions[name]; + return (allowMulti && !this.isAllSubOptionsSelected(option)) || !selectedOptions[name]; }); } @@ -344,43 +345,49 @@ export default class AdvanceSearchBar extends React.Component { const searchValid = this.isSearchValid(); const showHelper = this.showHelper(); let optionList = this.getOptionList(); - let list; + let list = ; if (this.state.showHelper) { - list = - { optionList } - ; + helperTextButton={this.props.helperTextButton} + optionList={optionList} + />; } else if (this.state.isSearching) { list = - { optionList } - ; + notTagFound={this.props.notTagFound} + optionList={optionList} + />; } return (
{ this.getCurrentTags(optionList) } -
- - + - { this.props.labelText && } + { this.props.labelText && } +
{ list } ); @@ -391,7 +398,6 @@ AdvanceSearchBar.propTypes = { callback: PropTypes.func.isRequired, emptyCallback: PropTypes.func, helperTitleFunction: PropTypes.func, - children: PropTypes.node.isRequired, labelText: PropTypes.string, buttonText: PropTypes.node, notTagFound: PropTypes.string, diff --git a/src/lib/components/Input.css b/src/lib/components/Input.css index 466546e..47a00e9 100644 --- a/src/lib/components/Input.css +++ b/src/lib/components/Input.css @@ -1,54 +1,51 @@ .search-bar__input-tag { - display: -ms-inline-flexbox; - display: inline-flex; + z-index: 1; font-weight: 100; align-items: center; + display: inline-flex; + display: -ms-inline-flexbox; } .search-bar__input-tag > * { - font-family: Roboto,sans-serif; - font-size: .875rem; - line-height: 1.25rem; - text-decoration: inherit; - text-transform: inherit; - position: relative; - -ms-flex-align: center; - align-items: center; - -webkit-box-sizing: border-box; - box-sizing: border-box; - padding: 7px 12px; outline: none; - overflow: hidden; - min-height: 25px; - max-height: calc(var(--search-bar-height) - 15px); display: flex; + overflow: hidden; + height: 25px; + font-size: 12px; + position: relative; align-items: center; + box-sizing: border-box; justify-content: center; + font-family: Roboto, sans-serif; } .search-bar__input-tag .input-tag__start { - border-bottom-left-radius: 16px; + padding: 0 12px; + font-weight: bolder; + color: rgba(0,0,0,0.52); border-top-left-radius: 16px; - margin-left: 10px; + border-bottom-left-radius: 16px; background-color: var(--search-bar-active-color); - color: #fff; - font-weight: bolder; } .search-bar__input-tag .input-tag__second { - border-bottom-right-radius: 16px; + padding-right: 12px; + background-color: #fff; border-top-right-radius: 16px; - background-color: #e0e0e0; + border-bottom-right-radius: 16px; + color: var(--search-bar-active-color); + border: 1px solid var(--search-bar-active-color); } .input-tag__second input, .input-tag__second select { - font-family: Roboto,sans-serif; - font-size: .875rem; - text-align: center; - background-color: #e0e0e0; border: none; - margin-left: 0px; cursor: pointer; + margin-left: 0px; + font-size: 12px; + text-align: center; + background-color: #fff; + font-family: Roboto, sans-serif; + color: var(--search-bar-active-color); } .input-tag__second input:focus, .input-tag__second select:focus { @@ -56,29 +53,29 @@ } .input-tag__delete { - text-align: center; - display: inline-block; - background: #bbb; width: 18px; height: 18px; - border-radius: 50%; cursor: pointer; - text-decoration: inherit; + text-align: center; + border-radius: 50%; + display: inline-block; text-transform: inherit; + text-decoration: inherit; + background: var(--search-bar-active-color); } .input-tag__delete svg { - height: 14px; + top: 0; + height: 100%; position: relative; - top: 1px; } .input-tag__delete svg path { - fill: #777; + fill: #fff; } -.input-tag__delete:hover svg path { - fill: #333; +.input-tag__delete:hover { + opacity: 0.5; } .input-tag__separator { diff --git a/src/lib/components/Input.jsx b/src/lib/components/Input.jsx index 5f1ad3e..04116dc 100644 --- a/src/lib/components/Input.jsx +++ b/src/lib/components/Input.jsx @@ -1,6 +1,5 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { getInputDisplayName } from './InputOption.jsx'; import DeleteIcon from './DeleteIcon.jsx'; import './Input.css'; @@ -24,7 +23,7 @@ export default class Input extends React.Component { const { value } = this.props; const { inputOption } = this.props; - if (inputOption.props.allowMulti && value[value.length - 1] === '' && (prevProps.value.length < value.length)) { + if (inputOption.allowMulti && value[value.length - 1] === '' && (prevProps.value.length < value.length)) { this.triggerInputStart(); } } @@ -39,29 +38,34 @@ export default class Input extends React.Component { triggerDelete (e) { const { inputOption } = this.props; - this.props.deleteChip(inputOption.props.name); + this.props.deleteChip(inputOption.name); } onKeyPress (event, index) { if (event.key === 'Enter') { event.preventDefault(); + // finaliza el ingreso del input this.props.triggerInputEnd(); + // realiza la busqueda + // - opcional: podría solamente finalizar el input y dejar la responsabilidad del search para el botón this.props.triggerSearch(); } else if (event.key === 'Backspace') { + // elimina la ultima seleccion en caso de ser multi + // si no es multi, elimina el option this.handleBackspace(index); } } handleBackspace (index) { const { inputOption } = this.props; - const allowMulti = inputOption.props.allowMulti; + const allowMulti = inputOption.allowMulti; if (!allowMulti && this.props.value.length === 0) { this.props.triggerInputEnd(); } if (allowMulti && this.props.value[index].length === 0) { - this.props.deleteOptionValueAt(inputOption.props.name, index); + this.props.deleteOptionValueAt(inputOption.name, index); } } @@ -71,9 +75,9 @@ export default class Input extends React.Component { getSelects () { const { value, inputOption, separatorComponent } = this.props; - const values = inputOption.props.allowMulti ? value : [value]; + const values = inputOption.allowMulti ? value : [value]; - const options = this.props.inputOption.props.options; + const options = this.props.inputOption.options; const suboptions = options.map(opt => (