-
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 3, 2020
1 parent
3e0f03e
commit c1008d9
Showing
25 changed files
with
1,656 additions
and
1 deletion.
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
102 changes: 102 additions & 0 deletions
102
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,102 @@ | ||
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 state: State = { | ||
options: [], | ||
value: undefined, | ||
keyword: '', | ||
}; | ||
|
||
public componentDidMount() { | ||
this.setState({ | ||
value: this.props.value, | ||
options: this.props.options, | ||
}); | ||
} | ||
|
||
public componentWillReceiveProps(nextProps: SelectCoreProps) { | ||
this.setState({ | ||
value: nextProps.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; | ||
} | ||
} | ||
} |
175 changes: 175 additions & 0 deletions
175
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,175 @@ | ||
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, {}> { | ||
constructor(props: SelectListProps) { | ||
super(props); | ||
this.ref = React.createRef(); | ||
} | ||
|
||
public ref: React.RefObject<HTMLDivElement>; | ||
|
||
public static defaultProps: Partial<SelectListProps> = { | ||
disabledOptions: [], | ||
isMultiple: false, | ||
width: 280, | ||
height: 450, | ||
}; | ||
|
||
public state: State = { | ||
value: null, | ||
}; | ||
|
||
public render() { | ||
return ( | ||
<div className="gio-select-list-wrapper" ref={this.ref}> | ||
{this.renderList()} | ||
</div> | ||
); | ||
} | ||
|
||
private getPopupContainer = () => { | ||
return 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.