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

feat: Add InputDropdown. #64

Merged
merged 8 commits into from
Aug 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return value || defaultValue

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这么写和原逻辑就不一致了,value 为 0,空字符串都会返回 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