diff --git a/.storybook/webpack.config.js b/.storybook/webpack.config.js index 2436ed51..3caf0a64 100644 --- a/.storybook/webpack.config.js +++ b/.storybook/webpack.config.js @@ -29,7 +29,12 @@ module.exports = async ({ config, mode }) => { use: [ 'style-loader', 'css-loader', - 'sass-loader', + { + loader: require.resolve('sass-loader'), + options: { + precision: 8, + } + }, ], include: path.resolve(__dirname, '../') }); @@ -56,7 +61,12 @@ module.exports = async ({ config, mode }) => { }, }, }, - 'sass-loader' + { + loader: require.resolve('sass-loader'), + options: { + precision: 8, + } + }, ], },) config.resolve.extensions.push('.ts', '.tsx') diff --git a/docs/content/components/input-dropdown.mdx b/docs/content/components/input-dropdown.mdx new file mode 100644 index 00000000..cc15a6a7 --- /dev/null +++ b/docs/content/components/input-dropdown.mdx @@ -0,0 +1,37 @@ +--- +title: InputDropdown Input 下拉框 +date: 2019-08-23 +author: lijianxin1202 +--- +作为 Input 一部分的下拉框 + +## 使用方式 +通常和 Input 一起使用,在 Input 的前面或者后部,用来增强 Input 功能 + +## 基本用法 + +```jsx +() => { + const [value, updateValue] = React.useState('MB'); + return (
+ + + + +
); +} +``` + +## API +```jsx previewOnly + +``` \ No newline at end of file diff --git a/docs/gatsby-config.js b/docs/gatsby-config.js index 352774b7..702df995 100644 --- a/docs/gatsby-config.js +++ b/docs/gatsby-config.js @@ -65,6 +65,9 @@ module.exports = { cssLoaderOptions: { camelCase: false, }, + options: { + precision: 8, + }, }, ], } diff --git a/src/components/InputDropdown/index.test.tsx b/src/components/InputDropdown/index.test.tsx new file mode 100644 index 00000000..e56ba74a --- /dev/null +++ b/src/components/InputDropdown/index.test.tsx @@ -0,0 +1,60 @@ +import React from 'react'; +import InputDropdown from './index'; +import { mount } from 'enzyme'; +import { InputGroup, FormControl } from 'react-bootstrap'; + +describe('InputDropdown', () => { + it('should render corrent dropdown', () => { + const Demo = () => { + const [value, updateValue] = React.useState('MB'); + return (
+ + + updateValue(key)} + value={value} + options={[ + { title: 'MB', value: 'MB' }, + { title: 'GB', value: 'GB' }, + { title: 'TB', value: 'TB' }, + ]} /> + +
); + } + const dropdown = mount(); + const button = dropdown.find('button'); + expect(dropdown.find('.dropdown.input-group-btn').length).toBe(1); + button.simulate('click'); + const tb = dropdown.find('a').at(2); + tb.simulate('click'); + expect(dropdown.find('button[value="TB"]').length).toBe(1); + }); + + it('should render corrent with input', () => { + const Demo = () => { + const [value, updateValue] = React.useState('MB'); + return (
+ + + + +
); + } + const dropdown = mount(); + const button = dropdown.find('button'); + button.simulate('click'); + const tb = dropdown.find('a').at(2); + tb.simulate('click'); + // @ts-ignore + expect(dropdown.find('button').instance().textContent).toBe('TB '); + }); +}); \ No newline at end of file diff --git a/src/components/InputDropdown/index.tsx b/src/components/InputDropdown/index.tsx new file mode 100644 index 00000000..3ef8ad2f --- /dev/null +++ b/src/components/InputDropdown/index.tsx @@ -0,0 +1,77 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { find, get } from 'lodash'; +import { DropdownButton, MenuItem, InputGroup } from 'react-bootstrap'; +import { uuid } from '../../utils'; +import { InputDropdownProps } from '../../interface'; + +const InputDropdown = (props: InputDropdownProps) => { + function getValue() { + const { input, value, defaultValue } = props; + if (input && input.value !== undefined) { + return input.value; + } + return value !== undefined ? value : defaultValue; + } + + function getTitle() { + const { options } = props; + const option = find(options, { value: getValue() }); + return get(option, 'title'); + } + + function handleSelect(eventKey: any) { + const { input, onChange } = props; + if (onChange) { + onChange(eventKey); + } else if (input) { + input.onChange(eventKey); + } + } + const { input, meta, options, ...rest } = props; + return ( + + {options && + options.map(option => ( + + {option.title} + + ))} + + ); +} + +InputDropdown.propTypes = { + /** + * 下拉选项 + **/ + options: PropTypes.array, + /** + * 下拉框是否右对齐,默认为 true + **/ + pullRight: PropTypes.bool, + /** + * 默认值 + **/ + defaultValue: PropTypes.string, + /** + * value 变化后回调 + **/ + onChange: PropTypes.func, + /** + * value,传入 value 时变为受控组件 + **/ + value: PropTypes.string, +}; + +InputDropdown.defaultProps = { + pullRight: true, +}; + +export default InputDropdown; \ No newline at end of file diff --git a/src/components/index.tsx b/src/components/index.tsx index 92a7fb9e..e5bd8dd4 100644 --- a/src/components/index.tsx +++ b/src/components/index.tsx @@ -3,6 +3,7 @@ import Badge from './Badge'; import Dropdown from './Dropdown'; import DropdownButton from './DropdownButton'; import Icon from './Icon'; +import InputDropdown from './InputDropdown'; import Loader from './Loader'; import Modal from './Modal'; import Navigation from './Navigation'; @@ -28,6 +29,7 @@ export { Dropdown, DropdownButton, Icon, + InputDropdown, Loader, MenuItem, Modal, diff --git a/src/interface.tsx b/src/interface.tsx index bb0bec32..94a65fa4 100644 --- a/src/interface.tsx +++ b/src/interface.tsx @@ -227,6 +227,18 @@ export interface DropdownProps extends DropdownDefaultProps { children?: React.ReactNode; } +export interface MenuItemOptions { + title: string; + value: string; +} +export interface InputDropdownProps { + options?: MenuItemOptions[]; + defaultValue?: string; + value?: string; + onChange?: SelectCallback; + input?: any; + meta?: any; +} export interface Query { offset: number; limit: number; diff --git a/stories/InputDropdown.stories.tsx b/stories/InputDropdown.stories.tsx new file mode 100644 index 00000000..c6bdd98f --- /dev/null +++ b/stories/InputDropdown.stories.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { storiesOf } from '@storybook/react'; +import { InputDropdown } from '../src'; +import { FormControl, InputGroup } from 'react-bootstrap'; + +storiesOf('InputDropdown', module) + .add('default', () => { + const Demo = () => { + const [value, updateValue] = React.useState('MB'); + return (
+ + + updateValue(key)} + value={value} + options={[ + { title: 'MB', value: 'MB' }, + { title: 'GB', value: 'GB' }, + { title: 'TB', value: 'TB' }, + ]} /> + +
); + } + return ; + }) \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index dd78eb7d..b2da0d15 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -32,7 +32,12 @@ module.exports = { use: [ MiniCssExtractPlugin.loader, 'css-loader', - 'sass-loader', + { + loader: require.resolve('sass-loader'), + options: { + precision: 8, + } + }, ], }, { @@ -48,7 +53,12 @@ module.exports = { }, }, }, - 'sass-loader' + { + loader: require.resolve('sass-loader'), + options: { + precision: 8, + } + }, ], }, ]