diff --git a/packages/devui/package.json b/packages/devui/package.json index ce8c031b..dccf8c8a 100755 --- a/packages/devui/package.json +++ b/packages/devui/package.json @@ -66,7 +66,7 @@ "react-icons": "^3.10.0", "react-is": "^16.13.1", "react-jsonschema-form": "^1.8.1", - "react-select": "^1.3.0", + "react-select": "^3.1.0", "redux-devtools-themes": "^1.0.0", "simple-element-resize-detector": "^1.3.0", "styled-components": "^5.1.1" diff --git a/packages/devui/src/Select/Select.js b/packages/devui/src/Select/Select.js index 014fd5bc..2ba359b4 100644 --- a/packages/devui/src/Select/Select.js +++ b/packages/devui/src/Select/Select.js @@ -1,37 +1,53 @@ import React, { PureComponent, Component } from 'react'; import PropTypes from 'prop-types'; import ReactSelect from 'react-select'; -import createStyledComponent from '../utils/createStyledComponent'; -import styles from './styles'; - -const SelectContainer = createStyledComponent(styles, ReactSelect); +import createThemedComponent from '../utils/createThemedComponent'; /** - * Wrapper around [React Select](https://github.com/JedWatson/react-select) with themes and new props like `openOuterUp` and `menuMaxHeight`. + * Wrapper around [React Select](https://github.com/JedWatson/react-select). */ -export default class Select extends (PureComponent || Component) { +class Select extends (PureComponent || Component) { render() { - return ; + return ( + ({ + ...theme, + borderRadius: this.props.theme.inputBorderRadius, + colors: { + ...theme.colors, + + primary: this.props.theme.base05, + primary50: this.props.theme.base03, + primary25: this.props.theme.base01, + + dangerLight: this.props.theme.base03, + danger: this.props.theme.base07, + + neutral0: this.props.theme.base00, + neutral5: this.props.theme.base01, + neutral10: this.props.theme.base02, + neutral20: this.props.theme.base03, + neutral30: this.props.theme.base04, + neutral40: this.props.theme.base05, + neutral60: this.props.theme.base06, + neutral80: this.props.theme.base07, + }, + })} + /> + ); } } Select.propTypes = { - autosize: PropTypes.bool, // whether to enable autosizing or not - clearable: PropTypes.bool, // should it be possible to reset value - disabled: PropTypes.bool, // whether the Select is disabled or not + isClearable: PropTypes.bool, // should it be possible to reset value + isDisabled: PropTypes.bool, // whether the Select is disabled or not isLoading: PropTypes.bool, // whether the Select is loading externally or not - menuMaxHeight: PropTypes.number, // maximum css height for the opened menu of options - multi: PropTypes.bool, // multi-value input - searchable: PropTypes.bool, // whether to enable searching feature or not - simpleValue: PropTypes.bool, // pass the value with label to onChange + maxMenuHeight: PropTypes.number, // maximum css height for the opened menu of options + isMulti: PropTypes.bool, // multi-value input + isSearchable: PropTypes.bool, // whether to enable searching feature or not value: PropTypes.any, // initial field value - valueKey: PropTypes.string, // path of the label value in option objects - openOuterUp: PropTypes.bool, // value to control the opening direction + menuPlacement: PropTypes.oneOf(['auto', 'bottom', 'top']), // value to control the opening direction }; -Select.defaultProps = { - autosize: true, - clearable: false, - simpleValue: true, - menuMaxHeight: 200, -}; +export default createThemedComponent(Select); diff --git a/packages/devui/src/Select/Select.stories.js b/packages/devui/src/Select/Select.stories.js index 43400152..c431ff40 100644 --- a/packages/devui/src/Select/Select.stories.js +++ b/packages/devui/src/Select/Select.stories.js @@ -20,25 +20,29 @@ export default { component: Select, }; -const Template = (args) => ( +const Template = ({ value, ...args }) => ( - option.value === value)} + {...args} + /> ); export const Default = Template.bind({}); Default.args = { value: 'one', - menuMaxHeight: 200, - autosize: false, - clearable: false, - disabled: false, + maxMenuHeight: 300, + isClearable: false, + isDisabled: false, isLoading: false, - multi: false, - searchable: true, - openOuterUp: false, + isMulti: false, + isSearchable: true, + menuPlacement: 'bottom', }; Default.argTypes = { - simpleValue: { control: { disable: true } }, - valueKey: { control: { disable: true } }, + onChange: { + action: 'selected', + }, }; diff --git a/packages/devui/src/Select/styles/index.js b/packages/devui/src/Select/styles/index.js deleted file mode 100644 index 4c5a5ec5..00000000 --- a/packages/devui/src/Select/styles/index.js +++ /dev/null @@ -1,361 +0,0 @@ -import { css } from 'styled-components'; -import { fadeIn, spinner } from '../../utils/animations'; - -export default ({ theme, openOuterUp, menuMaxHeight }) => css` - &.Select { - position: relative; - - &, - & div, - & input, - & span { - box-sizing: border-box; - } - - &.is-disabled > .Select-control { - background-color: ${theme.base02}; - - &:hover { - box-shadow: none; - } - } - - &.is-disabled .Select-arrow-zone { - cursor: default; - pointer-events: none; - } - } - - .Select-control { - background-color: ${theme.base00}; - border-color: ${theme.inputBorderColor}; - border-radius: ${theme.inputBorderRadius}px; - border-style: solid; - border-width: ${theme.inputBorderWidth}px; - color: ${theme.base07}; - cursor: default; - display: table; - border-spacing: 0; - border-collapse: separate; - height: ${theme.inputHeight}px; - outline: none; - overflow: hidden; - position: relative; - width: 100%; - - &:hover { - box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06); - } - - .Select-input:focus { - outline: none; - } - } - - &.is-searchable { - &.is-open > .Select-control { - cursor: text; - } - } - - &.is-open > .Select-control { - border-radius: ${openOuterUp - ? `0 0 ${theme.inputBorderRadius}px ${theme.inputBorderRadius}px` - : `${theme.inputBorderRadius}px ${theme.inputBorderRadius}px 0 0`}; - } - - &.is-searchable { - &.is-focused:not(.is-open) > .Select-control { - cursor: text; - } - } - - &.is-focused > .Select-control { - ${theme.inputFocusedStyle} - } - - .Select-placeholder, - &.Select--single > .Select-control .Select-value { - bottom: 0; - color: ${theme.base03}; - left: 0; - line-height: ${theme.inputInternalHeight}px; - padding: 0 ${theme.inputPadding}px; - position: absolute; - right: 0; - top: 0; - max-width: 100%; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - &.has-value.Select--single > .Select-control .Select-value, - &.has-value.is-pseudo-focused.Select--single > .Select-control .Select-value { - .Select-value-label { - color: ${theme.base07}; - } - - a.Select-value-label { - cursor: pointer; - text-decoration: none; - - &:hover, - &:focus { - color: ${theme.base0D}; - outline: none; - text-decoration: underline; - } - } - } - - .Select-input { - height: ${theme.inputInternalHeight}px; - padding-left: ${theme.inputPadding}px; - padding-right: ${theme.inputPadding}px; - vertical-align: middle; - - > input { - color: ${theme.base07}; - background: none transparent; - border: 0 none; - box-shadow: none; - width: 100%; - cursor: default; - display: inline-block; - font-family: inherit; - font-size: inherit; - margin: 0; - outline: none; - line-height: 14px; - padding: ${(theme.inputInternalHeight - 14) / 2 - 2}px 0; - -webkit-appearance: none; - - .is-focused & { - cursor: text; - } - } - } - - &.has-value.is-pseudo-focused .Select-input { - opacity: 0; - } - - .Select-control:not(.is-searchable) > .Select-input { - outline: none; - } - - .Select-loading-zone { - cursor: pointer; - display: table-cell; - position: relative; - text-align: center; - vertical-align: middle; - width: ${theme.spinnerSize}px; - } - - .Select-loading { - ${spinner(theme)} - vertical-align: middle; - } - - .Select-clear-zone { - animation: ${fadeIn} 200ms; - color: ${theme.base03}; - cursor: pointer; - display: table-cell; - position: relative; - text-align: center; - vertical-align: middle; - - &:hover { - color: #d0021b; - } - } - - .Select-clear { - display: inline-block; - font-size: ${Math.floor(theme.inputHeight / 2)}px; - line-height: 1px; - } - - .Select-clear-zone, - .Select--multi .Select-clear-zone { - width: ${theme.inputInternalHeight / 2}px; - } - - .Select--multi .Select-multi-value-wrapper { - display: inline-block; - } - - &.Select .Select-aria-only { - display: inline-block; - position: absolute; - height: 1px; - width: 1px; - margin: -1px; - clip: rect(0, 0, 0, 0); - overflow: hidden; - } - - .Select-arrow-zone { - cursor: pointer; - display: table-cell; - position: relative; - text-align: center; - vertical-align: middle; - width: ${theme.selectArrowWidth * 5}px; - padding-right: ${theme.selectArrowWidth}px; - } - - .Select-arrow { - border-color: ${theme.base03} transparent transparent; - border-style: solid; - border-width: ${theme.selectArrowWidth}px ${theme.selectArrowWidth}px - ${theme.selectArrowWidth / 2}px; - display: inline-block; - height: 0; - width: 0; - } - - .is-open .Select-arrow, - .Select-arrow-zone:hover > .Select-arrow { - border-top-color: ${theme.base04}; - } - - .Select-menu-outer { - border: 1px solid ${theme.base02}; - box-shadow: 0 ${openOuterUp ? '-1px' : '1px'} 0 rgba(0, 0, 0, 0.06); - box-sizing: border-box; - /* stylelint-disable declaration-empty-line-before */ - ${openOuterUp ? 'margin-bottom' : 'margin-top'}: -1px; - /* stylelint-enable */ - max-height: ${menuMaxHeight}px; - position: absolute; - top: auto; - left: 0; - bottom: ${openOuterUp ? '100%' : 'auto'}; - width: 100%; - min-width: 70px; - z-index: 1000; - -webkit-overflow-scrolling: touch; - } - - .Select-menu { - max-height: ${menuMaxHeight - 2}px; - overflow-y: auto; - } - - .Select-option { - box-sizing: border-box; - background-color: ${theme.base00}; - color: ${theme.base07}; - cursor: pointer; - display: block; - padding: ${theme.inputHeight / 3}px; - line-height: ${theme.inputInternalHeight / 2}px; - - &.is-selected { - background-color: ${theme.base01}; - color: ${theme.base07}; - } - - &.is-focused { - background-color: ${theme.base02}; - color: ${theme.base07}; - } - - &.is-disabled { - color: ${theme.base05}; - cursor: default; - } - } - - .Select-noresults { - box-sizing: border-box; - color: ${theme.base06}; - background-color: ${theme.base00}; - cursor: default; - display: block; - padding: ${theme.inputPadding}px; - } - - &.Select--multi { - .Select-input { - display: inline-block; - vertical-align: middle; - margin-left: ${theme.inputPadding}px; - padding: 0; - } - - &.has-value .Select-input { - margin-left: ${theme.selectArrowWidth}px; - } - - .Select-value { - background-color: ${theme.base00}; - border-radius: ${theme.inputBorderRadius}px; - border: 1px solid ${theme.base02}; - color: ${theme.base07}; - display: inline-block; - font-size: 0.9em; - margin-left: ${theme.inputPadding / 2}px; - margin-top: 0; - vertical-align: middle; - } - - .Select-value-icon, - .Select-value-label { - display: inline-block; - vertical-align: middle; - } - - .Select-value-label { - border-bottom-right-radius: ${theme.inputBorderRadius}px; - border-top-right-radius: ${theme.inputBorderRadius}px; - cursor: default; - padding: ${Math.floor(theme.inputPadding / 4)}px - ${Math.floor(theme.inputPadding / 2)}px; - } - - a.Select-value-label { - color: ${theme.base07}; - cursor: pointer; - text-decoration: none; - - &:hover { - text-decoration: underline; - } - } - - .Select-value-icon { - cursor: pointer; - border-bottom-left-radius: ${theme.inputBorderRadius}px; - border-top-left-radius: ${theme.inputBorderRadius}px; - border-right: 1px solid ${theme.base02}; - padding: 0px ${Math.floor(theme.inputPadding / 2)}px; - - &:hover, - &:focus { - background-color: ${theme.base03}; - color: ${theme.base00}; - } - - &:active { - background-color: ${theme.base06}; - } - } - } - - &.Select--multi.is-disabled { - .Select-value { - background-color: ${theme.base00}; - border: 1px solid ${theme.base01}; - color: ${theme.base05}; - } - - .Select-value-icon { - cursor: not-allowed; - } - } -`; diff --git a/packages/devui/src/utils/createThemedComponent.js b/packages/devui/src/utils/createThemedComponent.js new file mode 100644 index 00000000..019c4035 --- /dev/null +++ b/packages/devui/src/utils/createThemedComponent.js @@ -0,0 +1,13 @@ +import React from 'react'; +import getDefaultTheme from '../themes/default'; +import { withTheme } from 'styled-components'; + +export default (UnthemedComponent) => (props) => + props.theme && props.theme.type ? ( + withTheme() + ) : ( + // used outside of container (theme provider) + + ); + +// TODO: memoize it? diff --git a/packages/devui/tests/Select.test.js b/packages/devui/tests/Select.test.js index efbb687c..c8dc73f8 100644 --- a/packages/devui/tests/Select.test.js +++ b/packages/devui/tests/Select.test.js @@ -30,7 +30,9 @@ describe('Select', function () { it('should select another option', () => { const onChange = jest.fn(); - const wrapper = mount( + ); const input = wrapper.find('input'); input.at(0).instance().value = 'two'; diff --git a/packages/devui/tests/__snapshots__/Dialog.test.js.snap b/packages/devui/tests/__snapshots__/Dialog.test.js.snap index c3fba651..1251b826 100644 --- a/packages/devui/tests/__snapshots__/Dialog.test.js.snap +++ b/packages/devui/tests/__snapshots__/Dialog.test.js.snap @@ -2,7 +2,7 @@ exports[`Dialog renders correctly 1`] = `
@@ -45,7 +45,7 @@ exports[`Dialog renders correctly 1`] = ` exports[`Dialog renders modal 1`] = `
@@ -85,7 +85,7 @@ exports[`Dialog renders modal 1`] = ` exports[`Dialog renders with props 1`] = `
diff --git a/packages/devui/tests/__snapshots__/Editor.test.js.snap b/packages/devui/tests/__snapshots__/Editor.test.js.snap index 8f345360..e1b1b93e 100644 --- a/packages/devui/tests/__snapshots__/Editor.test.js.snap +++ b/packages/devui/tests/__snapshots__/Editor.test.js.snap @@ -12,7 +12,7 @@ exports[`Editor renders correctly 1`] = ` >
diff --git a/packages/devui/tests/__snapshots__/Notification.test.js.snap b/packages/devui/tests/__snapshots__/Notification.test.js.snap index 1d1a5148..56412e85 100644 --- a/packages/devui/tests/__snapshots__/Notification.test.js.snap +++ b/packages/devui/tests/__snapshots__/Notification.test.js.snap @@ -2,7 +2,7 @@ exports[`Notification renders correctly 1`] = `
@@ -13,7 +13,7 @@ exports[`Notification renders correctly 1`] = ` exports[`Notification renders with props 1`] = `
Select...
-
+ class="" + style="display:inline-block" + > + +
+
- - + +
`; exports[`Select renders with props 1`] = `
- - One - -   - - + Select...
-
`; exports[`Select should select another option 1`] = ` - -
-
-
- -
- -
- two -
-
-
-
- - - -
-
-
-
-
- - - + +
+ + +
+ + +
+ +
+ +
+ two +
+
+
+
+
+ +
+
+
+ + +
+ + + + + + + + +
+
+
+
+
+ + + + +
+ + + + +
+ +
+
+
+
+
+
+
+
+
+
+ + + + + + `; exports[`Select shouldn't find any results 1`] = ` - -
-
-
- -
- -
+
+ + +
+ + +
+ +
+ +
+ text +
+
+
+
+
+ +
+
+
+ + +
+ + + + + + + + +
+
+
+
+ + + + - text -
-
-
-
- - - -
-
-
-
- No results found + +
+ + + + +
+ + +
+ No options +
+
+
+
+
+
+
+
+
+
+ +
-
-
-
- - - + + + + + + `; diff --git a/packages/devui/tests/__snapshots__/Slider.test.js.snap b/packages/devui/tests/__snapshots__/Slider.test.js.snap index 4cfba5c9..a1e3ba6c 100644 --- a/packages/devui/tests/__snapshots__/Slider.test.js.snap +++ b/packages/devui/tests/__snapshots__/Slider.test.js.snap @@ -2,7 +2,7 @@ exports[`Slider renders correctly 1`] = `