From 790504fed182e4d43c9bdd4ba06a1b323bd30400 Mon Sep 17 00:00:00 2001 From: Alexandru Munteanu <alexandru.munteanu@thinslices.com> Date: Wed, 10 Jan 2018 15:48:57 +0200 Subject: [PATCH] Add dropdown and steps components --- .../component-wizard/components/Dropdown.js | 67 +++++++++++++++++++ .../components/Dropdown.local.scss | 57 ++++++++++++++++ .../app/component-wizard/components/Steps.js | 40 +++++++++++ .../components/Steps.local.scss | 41 ++++++++++++ .../app/component-wizard/components/Wizard.js | 47 +++++++------ .../app/component-wizard/index.js | 2 + 6 files changed, 233 insertions(+), 21 deletions(-) create mode 100644 packages/xpub-faraday/app/component-wizard/components/Dropdown.js create mode 100644 packages/xpub-faraday/app/component-wizard/components/Dropdown.local.scss create mode 100644 packages/xpub-faraday/app/component-wizard/components/Steps.js create mode 100644 packages/xpub-faraday/app/component-wizard/components/Steps.local.scss diff --git a/packages/xpub-faraday/app/component-wizard/components/Dropdown.js b/packages/xpub-faraday/app/component-wizard/components/Dropdown.js new file mode 100644 index 000000000..e2e124cda --- /dev/null +++ b/packages/xpub-faraday/app/component-wizard/components/Dropdown.js @@ -0,0 +1,67 @@ +import React from 'react' +import { compose, withState, withHandlers } from 'recompose' +import classnames from 'classnames' + +import classes from './Dropdown.local.scss' + +const DropdownOptions = ({ visible, options, onSelect }) => + visible ? ( + <div className={classes.options}> + {options.map(opt => ( + <div key={opt.value} onClick={onSelect(opt)}> + {opt.label} + </div> + ))} + </div> + ) : null + +const Dropdown = ({ + label, + showDropdown, + inputValue, + changeInput, + defaultValue = null, + options, + onChange, + setDropdown, + selectValue, +}) => ( + <div className={classes.container}> + <span className={classes.label}>{label}</span> + <div className={classes.inputContainer}> + <input + onChange={changeInput} + onFocus={setDropdown(true)} + placeholder="Type or select from dropdown" + type="text" + value={inputValue.label} + /> + <span className={classnames({ [classes.downarrow]: showDropdown })}> + ► + </span> + </div> + <DropdownOptions + onSelect={selectValue} + options={options.filter(opt => opt.label.indexOf(inputValue.label) > -1)} + visible={showDropdown} + /> + </div> +) + +export default compose( + withState('inputValue', 'setInputValue', ({ defaultValue }) => defaultValue), + withState('showDropdown', 'setDropdownVisibility', false), + withHandlers({ + changeInput: ({ setInputValue }) => e => { + e.persist() + setInputValue(prev => ({ ...prev, label: e.target.value })) + }, + setDropdown: ({ setDropdownVisibility }) => visibilty => e => { + setDropdownVisibility(visibilty) + }, + selectValue: ({ setInputValue, setDropdownVisibility }) => value => e => { + setInputValue(value) + setDropdownVisibility(false) + }, + }), +)(Dropdown) diff --git a/packages/xpub-faraday/app/component-wizard/components/Dropdown.local.scss b/packages/xpub-faraday/app/component-wizard/components/Dropdown.local.scss new file mode 100644 index 000000000..ffe230262 --- /dev/null +++ b/packages/xpub-faraday/app/component-wizard/components/Dropdown.local.scss @@ -0,0 +1,57 @@ +.container { + display: flex; + flex-direction: column; + margin: 5px 0; + position: relative; +} + +.label { + font-size: 16px; + font-weight: 400; + margin: 5px 0; +} + +.inputContainer { + align-items: center; + display: flex; + position: relative; + + input { + border: 1px solid #888; + border-radius: 2px; + display: flex; + flex: 1; + height: 20px; + padding: 0 2px; + + &:focus { + outline: none; + } + } + + span { + position: absolute; + right: 10px; + top: 1px; + transform: rotateZ(90deg); + transition: transform 0.2s linear; + } +} + +.options { + background-color: #eee; + cursor: pointer; + left: 0; + position: absolute; + top: 50px; + width: 100%; + z-index: 1000; + + :hover { + background-color: #aaa; + } +} + +.downarrow { + transform: rotateZ(270deg) !important; +} diff --git a/packages/xpub-faraday/app/component-wizard/components/Steps.js b/packages/xpub-faraday/app/component-wizard/components/Steps.js new file mode 100644 index 000000000..01b18ae28 --- /dev/null +++ b/packages/xpub-faraday/app/component-wizard/components/Steps.js @@ -0,0 +1,40 @@ +import React from 'react' +import PropTypes from 'prop-types' +import { compose, withHandlers, withContext, getContext } from 'recompose' + +import classes from './Steps.local.scss' + +const Separator = () => <div className={classes.separator} /> + +const Step = ({ title, index, currentStep }) => ( + <div className={classes.step}> + {index <= currentStep && <div className={classes.bullet} />} + <span className={classes.stepTitle}>{`${index + 1}. ${title}`}</span> + </div> +) + +const Steps = ({ currentStep, children, renderSeparator, renderSteps }) => ( + <div className={classes.container}>{renderSteps()}</div> +) + +const DecoratedSteps = compose( + withHandlers({ + renderSteps: ({ children, currentStep }) => () => { + const c = [] + React.Children.forEach(children, (child, idx) => { + c.push(child) + if (idx !== React.Children.count(children) - 1) { + c.push(<Separator key={Math.random()} />) + } + }) + return c + }, + }), + withContext({ currentStep: PropTypes.number }, ({ currentStep }) => ({ + currentStep, + })), +)(Steps) + +DecoratedSteps.Step = getContext({ currentStep: PropTypes.number })(Step) + +export default DecoratedSteps diff --git a/packages/xpub-faraday/app/component-wizard/components/Steps.local.scss b/packages/xpub-faraday/app/component-wizard/components/Steps.local.scss new file mode 100644 index 000000000..887b70766 --- /dev/null +++ b/packages/xpub-faraday/app/component-wizard/components/Steps.local.scss @@ -0,0 +1,41 @@ +.container { + align-items: center; + display: flex; + flex-direction: row; + justify-content: space-between; + margin: 0 40px; + min-width: 400px; +} + +.separator { + background-color: #444; + flex: 1; + height: 2px; +} + +.step { + align-items: center; + border: 2px solid #555; + border-radius: 50%; + display: flex; + height: 16px; + justify-content: center; + position: relative; + width: 16px; +} + +.bullet { + background-color: #555; + border-radius: 50%; + height: 10px; + width: 10px; +} + +.stepTitle { + font-size: 14px; + left: -40px; + position: absolute; + top: 25px; + white-space: normal; + width: 120px; +} diff --git a/packages/xpub-faraday/app/component-wizard/components/Wizard.js b/packages/xpub-faraday/app/component-wizard/components/Wizard.js index af2abb592..37f1fe26c 100644 --- a/packages/xpub-faraday/app/component-wizard/components/Wizard.js +++ b/packages/xpub-faraday/app/component-wizard/components/Wizard.js @@ -1,32 +1,37 @@ import React from 'react' -import { compose, withHandlers } from 'recompose' +import { compose, withHandlers, withState } from 'recompose' import { withJournal } from 'xpub-journal' -const Wizard = ({ journal: { wizard }, renderStep }) => ( +import { Dropdown, Steps } from '../' + +const { Step } = Steps + +const options = [ + { label: 'opt 1', value: 'opt1' }, + { label: 'caca 2', value: 'opt2' }, + { label: 'maca 3', value: 'opt3' }, + { label: 'vaca 4', value: 'opt4' }, +] + +const Wizard = ({ journal: { wizard }, getSteps, step, incrementStep }) => ( <div> - {wizard.map((e, i) => ( - <div key={Math.random()}> - {e.label} - {e.title} - {e.children && e.children.map((c, i) => renderStep(c.type))} - </div> - ))} + <Dropdown defaultValue={options[0]} label="My dropdown" options={options} /> + <Dropdown defaultValue={options[1]} label="Altceva" options={options} /> + <Dropdown defaultValue={options[3]} label="Trei" options={options} /> + <button onClick={incrementStep}>Increment step</button> + <Steps currentStep={step}> + {getSteps().map((step, index) => ( + <Step index={index} key={step} title={step} /> + ))} + </Steps> </div> ) export default compose( + withJournal, + withState('step', 'changeStep', 0), withHandlers({ - renderStep: props => type => { - switch (type) { - case 'dropdown': - return <div>render dropdown</div> - case 'radio': - return <div>render radio</div> - case 'checkbox': - return <div>render checkbox</div> - default: - return null - } - }, + getSteps: ({ journal: { wizard } }) => () => wizard.map(w => w.label), + incrementStep: ({ changeStep }) => () => changeStep(step => step + 1), }), - withJournal, )(Wizard) diff --git a/packages/xpub-faraday/app/component-wizard/index.js b/packages/xpub-faraday/app/component-wizard/index.js index 88e2a880e..142a3246f 100644 --- a/packages/xpub-faraday/app/component-wizard/index.js +++ b/packages/xpub-faraday/app/component-wizard/index.js @@ -1 +1,3 @@ +export { default as Steps } from './components/Steps' export { default as Wizard } from './components/Wizard' +export { default as Dropdown } from './components/Dropdown' -- GitLab