Skip to content
This repository has been archived by the owner on Nov 14, 2023. It is now read-only.

Commit

Permalink
feat: Add InputDropdown. (#64)
Browse files Browse the repository at this point in the history
* feat: Add InputDropdown.

* Update case.

* Update.

* Add test case.

* Use higher precision in sass loader.

* Config docs sass precision.

* Update.
  • Loading branch information
lijianxin1202 authored and wangkailang committed Aug 30, 2019
1 parent 60e361d commit a1dcf2a
Show file tree
Hide file tree
Showing 9 changed files with 242 additions and 4 deletions.
14 changes: 12 additions & 2 deletions .storybook/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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, '../')
});
Expand All @@ -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')
Expand Down
37 changes: 37 additions & 0 deletions docs/content/components/input-dropdown.mdx
Original file line number Diff line number Diff line change
@@ -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 (<div style={{ width: '300px' }}>
<InputGroup>
<FormControl />
<InputDropdown
pullRight
defaultValue="GB"
onChange={updateValue}
value={value}
options={[
{ title: 'MB', value: 'MB' },
{ title: 'GB', value: 'GB' },
{ title: 'TB', value: 'TB' },
]} />
</InputGroup>
</div>);
}
```

## API
```jsx previewOnly
<PropTable of="inputDropdown" />
```
3 changes: 3 additions & 0 deletions docs/gatsby-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ module.exports = {
cssLoaderOptions: {
camelCase: false,
},
options: {
precision: 8,
},
},
],
}
60 changes: 60 additions & 0 deletions src/components/InputDropdown/index.test.tsx
Original file line number Diff line number Diff line change
@@ -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 (<div style={{ width: '300px' }}>
<InputGroup>
<FormControl />
<InputDropdown
pullRight
defaultValue="GB"
onChange={(key: any) => updateValue(key)}
value={value}
options={[
{ title: 'MB', value: 'MB' },
{ title: 'GB', value: 'GB' },
{ title: 'TB', value: 'TB' },
]} />
</InputGroup>
</div>);
}
const dropdown = mount(<Demo />);
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 (<div style={{ width: '300px' }}>
<InputGroup>
<FormControl />
<InputDropdown
pullRight
input={{ value, onChange: updateValue }}
options={[
{ title: 'MB', value: 'MB' },
{ title: 'GB', value: 'GB' },
{ title: 'TB', value: 'TB' },
]} />
</InputGroup>
</div>);
}
const dropdown = mount(<Demo />);
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 ');
});
});
77 changes: 77 additions & 0 deletions src/components/InputDropdown/index.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<DropdownButton
id={uuid()}
{...rest}
componentClass={InputGroup.Button}
onSelect={handleSelect}
title={getTitle()}
>
{options &&
options.map(option => (
<MenuItem key={option.value} eventKey={option.value}>
{option.title}
</MenuItem>
))}
</DropdownButton>
);
}

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;
2 changes: 2 additions & 0 deletions src/components/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -28,6 +29,7 @@ export {
Dropdown,
DropdownButton,
Icon,
InputDropdown,
Loader,
MenuItem,
Modal,
Expand Down
12 changes: 12 additions & 0 deletions src/interface.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
27 changes: 27 additions & 0 deletions stories/InputDropdown.stories.tsx
Original file line number Diff line number Diff line change
@@ -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 (<div style={{ width: '300px' }}>
<InputGroup>
<FormControl />
<InputDropdown
pullRight
defaultValue="GB"
onChange={(key: any) => updateValue(key)}
value={value}
options={[
{ title: 'MB', value: 'MB' },
{ title: 'GB', value: 'GB' },
{ title: 'TB', value: 'TB' },
]} />
</InputGroup>
</div>);
}
return <Demo />;
})
14 changes: 12 additions & 2 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,12 @@ module.exports = {
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader',
{
loader: require.resolve('sass-loader'),
options: {
precision: 8,
}
},
],
},
{
Expand All @@ -48,7 +53,12 @@ module.exports = {
},
},
},
'sass-loader'
{
loader: require.resolve('sass-loader'),
options: {
precision: 8,
}
},
],
},
]
Expand Down

0 comments on commit a1dcf2a

Please sign in to comment.