-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
chen_gh
committed
Sep 8, 2020
1 parent
46bd78e
commit 6d90b07
Showing
32 changed files
with
2,306 additions
and
3 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
101 changes: 101 additions & 0 deletions
101
packages/components/src/components/list/components/SelectCore/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
import React from 'react'; | ||
import SelectList from '../SelectList'; | ||
import { SelectCoreProps } from '../../interface'; | ||
|
||
interface State { | ||
options: any[]; | ||
value?: string | string[]; | ||
keyword: string; | ||
} | ||
|
||
class SelectCore extends React.Component<SelectCoreProps, State> { | ||
public static defaultProps: Partial<SelectCoreProps> = { | ||
showSearch: true, | ||
searchableFields: ['name'], | ||
valueKey: 'id', | ||
isMultiple: false, | ||
isLoading: false, | ||
required: false, | ||
height: 400, | ||
rowHeight: 40, | ||
emptyPlaceholder: '没有找到相关结果', | ||
}; | ||
|
||
public static getDerivedStateFromProps(nextProps: SelectCoreProps) { | ||
return { | ||
value: nextProps.value, | ||
// options: this.props.options, | ||
}; | ||
} | ||
|
||
public state: State = { | ||
options: [], | ||
value: undefined, | ||
keyword: '', | ||
}; | ||
|
||
public componentDidMount() { | ||
this.setState({ | ||
value: this.props.value, | ||
options: this.props.options, | ||
}); | ||
} | ||
public render() { | ||
const { | ||
disabledOptions, | ||
valueKey, | ||
renderKey, | ||
isMultiple, | ||
allowDuplicate, | ||
required, | ||
max, | ||
width, | ||
height, | ||
getGroupIcon, | ||
onSelect, | ||
onDeselect, | ||
emptyPlaceholder, | ||
labelRenderer, | ||
rowHeight, | ||
} = this.props; | ||
|
||
if (this.state.options && this.state.options.length) { | ||
return ( | ||
<div className="gio-select-core"> | ||
<SelectList | ||
options={this.state.options} | ||
disabledOptions={disabledOptions} | ||
value={this.state.value} | ||
valueKey={valueKey} | ||
renderKey={renderKey} | ||
isMultiple={isMultiple} | ||
allowDuplicate={allowDuplicate} | ||
required={required} | ||
max={max} | ||
width={width} | ||
height={height} | ||
onSelect={onSelect} | ||
onDeselect={onDeselect} | ||
onChange={this.handleSelect} | ||
getGroupIcon={getGroupIcon} | ||
labelRenderer={labelRenderer} | ||
rowHeight={rowHeight} | ||
/> | ||
</div> | ||
); | ||
} | ||
|
||
return ( | ||
<div className="gio-select-core"> | ||
<div style={{ padding: '50% 10px 0', textAlign: 'center', height }}>{emptyPlaceholder}</div> | ||
</div> | ||
); | ||
} | ||
|
||
private handleSelect = (value: any) => { | ||
this.setState({ value }); | ||
this.props.onChange(value); | ||
}; | ||
} | ||
|
||
export default SelectCore; |
35 changes: 35 additions & 0 deletions
35
packages/components/src/components/list/components/SelectCore/style.less
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
.gio-select-core { | ||
position: relative; | ||
|
||
.ant-tabs-ink-bar { | ||
background-color: #fc5f3a; | ||
} | ||
|
||
.ant-tabs-nav { | ||
.ant-tabs-tab { | ||
margin-right: 0; | ||
padding: 5px 15px; | ||
font-size: 12px; | ||
} | ||
.ant-tabs-tab-active { | ||
color: #5c4e61; | ||
} | ||
} | ||
|
||
.ant-tabs-bar { | ||
margin-bottom: 0; | ||
} | ||
|
||
&-header { | ||
padding: 10px; | ||
} | ||
|
||
.gio-user-picker-fetch-btn { | ||
opacity: 0.7; | ||
transition: 0.3s opacity ease; | ||
|
||
&:hover { | ||
opacity: 1; | ||
} | ||
} | ||
} |
171 changes: 171 additions & 0 deletions
171
packages/components/src/components/list/components/SelectList/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
import React from 'react'; | ||
import SelectOption from '../SelectOption'; | ||
import Group from '../SelectOption/Group'; | ||
import { get } from 'lodash'; | ||
import withGroupedOptions from '../../utils/withGroupedOptions'; | ||
import { List } from 'react-virtualized'; | ||
import { SelectListProps } from '../../interface'; | ||
|
||
import './style.less'; | ||
|
||
interface State { | ||
value: any | any[]; | ||
} | ||
|
||
class SelectList extends React.Component<SelectListProps, {}> { | ||
public static defaultProps: Partial<SelectListProps> = { | ||
disabledOptions: [], | ||
isMultiple: false, | ||
width: 280, | ||
height: 450, | ||
}; | ||
public ref: React.RefObject<HTMLDivElement>; | ||
public state: State = { | ||
value: null, | ||
}; | ||
|
||
public constructor(props: SelectListProps) { | ||
super(props); | ||
this.ref = React.createRef(); | ||
} | ||
|
||
public render() { | ||
return ( | ||
<div className="gio-select-list-wrapper" ref={this.ref}> | ||
{this.renderList()} | ||
</div> | ||
); | ||
} | ||
|
||
private getPopupContainer = () => this.ref.current as HTMLElement; | ||
|
||
private renderList = () => { | ||
const { width, height, disabledOptions, rowHeight } = this.props; | ||
const getRowHeight = ({ index }: { index: number }) => { | ||
if (typeof rowHeight === 'function') { | ||
return rowHeight(this.props.options[index]); | ||
} else { | ||
return rowHeight; | ||
} | ||
}; | ||
return ( | ||
<List | ||
value={this.props.value} | ||
width={width} | ||
height={height} | ||
rowCount={this.props.options.length} | ||
rowHeight={typeof rowHeight === 'function' ? getRowHeight : rowHeight} | ||
rowRenderer={this.renderListItem(this.props.options)} | ||
disabledOptions={disabledOptions} | ||
className="gio-select-list" | ||
/> | ||
); | ||
}; | ||
|
||
private checkIsMax = (option: any) => { | ||
const { isMultiple, value, max } = this.props; | ||
if (Array.isArray(value) && !this.getSelected(option) && isMultiple && max) { | ||
return value.length >= max; | ||
} else { | ||
return false; | ||
} | ||
}; | ||
|
||
private renderListItem = (options: any) => ({ index, style }: { index: number; style: React.CSSProperties }) => { | ||
const { isMultiple, required, value, valueKey, renderKey, disabledOptions, labelRenderer } = this.props; | ||
const option = options[index]; | ||
const isGroup = get(option, 'type') === 'groupName'; | ||
const label = labelRenderer ? labelRenderer(option) : get(option, 'name') || option; | ||
|
||
const optionKey = renderKey || valueKey; | ||
const key = optionKey ? option[optionKey] : option; | ||
|
||
const isSelectedAndRequired = this.getSelected(option) && required && (isMultiple ? value?.length === 1 : true); | ||
|
||
const isMax = this.checkIsMax(option); | ||
|
||
const disabled = | ||
isSelectedAndRequired || | ||
isMax || | ||
disabledOptions.indexOf(valueKey ? option[valueKey] : option) > -1 || | ||
option.disabled; | ||
|
||
const groupIcon = this.props.getGroupIcon ? this.props.getGroupIcon(option.group) : null; | ||
|
||
return isGroup ? ( | ||
<Group | ||
key={option.name} | ||
name={option.name} | ||
option={option} | ||
style={style} | ||
icon={groupIcon} | ||
isSelected={this.getSelected(option)} | ||
isMultiple={!!this.props.isMultiple} | ||
labelRenderer={labelRenderer} | ||
/> | ||
) : ( | ||
<SelectOption | ||
key={key} | ||
style={style} | ||
option={option} | ||
title={!labelRenderer ? label : undefined} | ||
isSelected={this.getSelected(option)} | ||
isMultiple={!!this.props.isMultiple} | ||
allowDuplicate={this.props.allowDuplicate} | ||
onSelect={this.handleSelect} | ||
disabled={disabled} | ||
hasGroupIcon={!!groupIcon} | ||
getPopupContainer={this.getPopupContainer} | ||
> | ||
{label} | ||
</SelectOption> | ||
); | ||
}; | ||
|
||
private handleSelect = (option: any) => { | ||
const { isMultiple, allowDuplicate, onSelect, onDeselect, onChange } = this.props; | ||
|
||
const isMax = this.checkIsMax(option); | ||
|
||
if (isMax) { | ||
return; | ||
} | ||
|
||
const selectedValue = this.getValue(option); | ||
const isSelected = this.getSelected(option); | ||
let value; | ||
if (isSelected && !allowDuplicate) { | ||
if (onDeselect) { | ||
onDeselect(selectedValue, this.props.value, option); | ||
} | ||
value = isMultiple ? this.props.value.filter((v: any) => v !== selectedValue) : null; | ||
} else { | ||
if (onSelect) { | ||
onSelect(selectedValue, this.props.value, option); | ||
} | ||
value = isMultiple ? [...(this.props.value || []), selectedValue] : selectedValue; | ||
} | ||
if (onChange) { | ||
onChange(value); | ||
} | ||
}; | ||
|
||
private getValue = (option: any) => { | ||
const { valueKey } = this.props; | ||
return valueKey ? option[valueKey] : option; | ||
}; | ||
|
||
private getSelected = (option: any) => { | ||
const { value, getSelected, isMultiple, valueKey } = this.props; | ||
if (getSelected) { | ||
return getSelected(option, value); | ||
} | ||
const target = valueKey ? option[valueKey] : option; | ||
|
||
return isMultiple ? value && value.indexOf(target) > -1 : value === target; | ||
}; | ||
} | ||
|
||
const WithGroupList = withGroupedOptions(SelectList); | ||
|
||
export default WithGroupList; |
9 changes: 9 additions & 0 deletions
9
packages/components/src/components/list/components/SelectList/style.less
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
.gio-select-list-wrapper { | ||
background-color: #fff; | ||
|
||
.gio-select-list { | ||
&:focus { | ||
outline: none; | ||
} | ||
} | ||
} |
37 changes: 37 additions & 0 deletions
37
packages/components/src/components/list/components/SelectOption/Group.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import React from 'react'; | ||
import Checkbox from 'antd/lib/checkbox'; | ||
import noop from 'lodash/noop'; | ||
import { GroupProps } from '../../interface'; | ||
|
||
export default class Group extends React.PureComponent<GroupProps> { | ||
public static defaultProps = { | ||
onSelect: noop, | ||
style: {}, | ||
}; | ||
|
||
public render() { | ||
const { | ||
name, | ||
icon, | ||
style, | ||
isMultiple, | ||
showGroupCheckBox = false, | ||
isSelected, | ||
indeterminate, | ||
option, | ||
labelRenderer, | ||
} = this.props; | ||
|
||
return ( | ||
<div className="gio-select-option group" style={{ ...style, color: '#1248E9' }} onClick={this.handleSelect}> | ||
{icon} | ||
{isMultiple && showGroupCheckBox && <Checkbox checked={isSelected} indeterminate={indeterminate} />} | ||
{labelRenderer ? labelRenderer(option, true) : name} | ||
</div> | ||
); | ||
} | ||
|
||
private handleSelect = () => { | ||
this.props.onSelect && this.props.onSelect(this.props.option); | ||
}; | ||
} |
Oops, something went wrong.