Skip to content

Commit

Permalink
feat(select): independent select
Browse files Browse the repository at this point in the history
Remove list component dependency

fix growingio#677
  • Loading branch information
shiliqian committed Jan 25, 2021
1 parent 49003cc commit ead092d
Show file tree
Hide file tree
Showing 13 changed files with 1,294 additions and 574 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"rc-trigger": "^4.3.0",
"rc-upload": "^3.2.0",
"rc-util": "^5.0.5",
"rc-virtual-list": "^3.2.6",
"react-dnd": "^11.1.3",
"react-dnd-html5-backend": "^11.1.3",
"react-use": "^15.3.3",
Expand Down
220 changes: 176 additions & 44 deletions src/components/pagination/__test__/__snapshots__/Pagination.test.js.snap

Large diffs are not rendered by default.

63 changes: 30 additions & 33 deletions src/components/select/Empty.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,40 @@ import './style/empty.less';

function SvgComponent(): React.ReactElement {
return (
// <svg width={60} height={61} viewBox="0 0 60 61">
// <g fill="none" fillRule="evenodd">
// <path d="M.588 36.882l10-21.764h38.824l10 21.764h-23.53a5.882 5.882 0 11-11.764 0H.588z" fill="#F7F8FC" />
// <path
// d="M.588 36.882h23.53a5.882 5.882 0 1011.764 0h23.53v20.53a3 3 0 01-3 3H3.588a3 3 0 01-3-3v-20.53z"
// fill="#FFF"
// />
// <path
// d="M47.436 15.618a3.497 3.497 0 013.18 2.038h0l8.564 18.64c.211.458.32.957.32 1.461h0V57c0 .966-.392 1.841-1.025 2.475A3.489 3.489 0 0156 60.5h0H4a3.489 3.489 0 01-2.475-1.025A3.489 3.489 0 01.5 57h0V37.757a3.5 3.5 0 01.32-1.46h0l8.564-18.64a3.497 3.497 0 013.18-2.04h0z"
// stroke="#DCDFED"
// />
// <path
// d="M.588 36.882h23.53a5.882 5.882 0 1011.764 0h23.53"
// stroke="#DCDFED"
// strokeLinecap="round"
// strokeLinejoin="round"
// />
// <path
// stroke="#DCDFED"
// strokeWidth={1.5}
// strokeLinecap="round"
// strokeLinejoin="round"
// d="M30 1v9.412M40.588 2.261l-4.706 8.151M19.412 2.261l4.706 8.151"
// />
// </g>
// </svg>
<svg viewBox="0 0 60 60" width={48} height={48}>
<g id="图层_2" data-name="图层 2">
<g id="图层_1-2" data-name="图层 1">
<g className="cls-2">
<path id="路径-6" className="cls-3" d="M.59,35.88,9.38,16.74a4.5,4.5,0,0,1,4.09-2.62H46.53a4.5,4.5,0,0,1,4.09,2.62l8.79,19.14H35.88a5.88,5.88,0,1,1-11.76,0H.59Z" />
<path id="矩形" className="cls-4" d="M.59,35.88H24.12a5.88,5.88,0,1,0,11.76,0H59.41V56.41a3,3,0,0,1-3,3H3.59a3,3,0,0,1-3-3V35.88Z" />
<path className="cls-5" d="M56,60H4a4,4,0,0,1-4-4V36.76a3.87,3.87,0,0,1,.37-1.67L8.93,16.45a3.94,3.94,0,0,1,1.48-1.7,4,4,0,0,1,2.15-.63H47.44a4,4,0,0,1,2.15.63,3.94,3.94,0,0,1,1.48,1.7l8.56,18.64A3.87,3.87,0,0,1,60,36.76V56a4,4,0,0,1-4,4ZM12.56,15.12a3,3,0,0,0-1.62.47,3,3,0,0,0-1.1,1.28L1.27,35.5A3,3,0,0,0,1,36.76V56a3,3,0,0,0,3,3H56a3,3,0,0,0,3-3V36.76a3,3,0,0,0-.27-1.26L50.16,16.87a2.94,2.94,0,0,0-1.11-1.28,3,3,0,0,0-1.61-.47Z" />
<path className="cls-5" d="M30,42.26a6.38,6.38,0,0,1-6.36-5.88H.59a.5.5,0,0,1-.5-.5.5.5,0,0,1,.5-.5H24.12a.51.51,0,0,1,.5.5,5.38,5.38,0,1,0,10.76,0,.51.51,0,0,1,.5-.5H59.41a.5.5,0,0,1,.5.5.5.5,0,0,1-.5.5h-23A6.38,6.38,0,0,1,30,42.26Z" />
<path className="cls-5" d="M30,10.91a.75.75,0,0,1-.75-.75V.75a.75.75,0,0,1,1.5,0v9.41A.75.75,0,0,1,30,10.91Z" />
<path className="cls-5" d="M35.88,10.91a.71.71,0,0,1-.37-.1.75.75,0,0,1-.28-1l4.71-8.15a.74.74,0,0,1,1-.28.76.76,0,0,1,.28,1l-4.71,8.15A.75.75,0,0,1,35.88,10.91Z" />
<path className="cls-5" d="M24.12,10.91a.75.75,0,0,1-.65-.37L18.76,2.39a.76.76,0,0,1,.28-1,.75.75,0,0,1,1,.28l4.71,8.15a.75.75,0,0,1-.28,1A.71.71,0,0,1,24.12,10.91Z" />
<path
id="路径-6"
className="cls-3"
d="M.59,35.88,9.38,16.74a4.5,4.5,0,0,1,4.09-2.62H46.53a4.5,4.5,0,0,1,4.09,2.62l8.79,19.14H35.88a5.88,5.88,0,1,1-11.76,0H.59Z"
/>
<path
id="矩形"
className="cls-4"
d="M.59,35.88H24.12a5.88,5.88,0,1,0,11.76,0H59.41V56.41a3,3,0,0,1-3,3H3.59a3,3,0,0,1-3-3V35.88Z"
/>
<path
className="cls-5"
d="M56,60H4a4,4,0,0,1-4-4V36.76a3.87,3.87,0,0,1,.37-1.67L8.93,16.45a3.94,3.94,0,0,1,1.48-1.7,4,4,0,0,1,2.15-.63H47.44a4,4,0,0,1,2.15.63,3.94,3.94,0,0,1,1.48,1.7l8.56,18.64A3.87,3.87,0,0,1,60,36.76V56a4,4,0,0,1-4,4ZM12.56,15.12a3,3,0,0,0-1.62.47,3,3,0,0,0-1.1,1.28L1.27,35.5A3,3,0,0,0,1,36.76V56a3,3,0,0,0,3,3H56a3,3,0,0,0,3-3V36.76a3,3,0,0,0-.27-1.26L50.16,16.87a2.94,2.94,0,0,0-1.11-1.28,3,3,0,0,0-1.61-.47Z"
/>
<path
className="cls-5"
d="M30,42.26a6.38,6.38,0,0,1-6.36-5.88H.59a.5.5,0,0,1-.5-.5.5.5,0,0,1,.5-.5H24.12a.51.51,0,0,1,.5.5,5.38,5.38,0,1,0,10.76,0,.51.51,0,0,1,.5-.5H59.41a.5.5,0,0,1,.5.5.5.5,0,0,1-.5.5h-23A6.38,6.38,0,0,1,30,42.26Z"
/>
<path
className="cls-5"
d="M30,10.91a.75.75,0,0,1-.75-.75V.75a.75.75,0,0,1,1.5,0v9.41A.75.75,0,0,1,30,10.91Z"
/>
<path
className="cls-5"
d="M35.88,10.91a.71.71,0,0,1-.37-.1.75.75,0,0,1-.28-1l4.71-8.15a.74.74,0,0,1,1-.28.76.76,0,0,1,.28,1l-4.71,8.15A.75.75,0,0,1,35.88,10.91Z"
/>
<path
className="cls-5"
d="M24.12,10.91a.75.75,0,0,1-.65-.37L18.76,2.39a.76.76,0,0,1,.28-1,.75.75,0,0,1,1,.28l4.71,8.15a.75.75,0,0,1-.28,1A.71.71,0,0,1,24.12,10.91Z"
/>
</g>
</g>
</g>
Expand Down
141 changes: 141 additions & 0 deletions src/components/select/OptionsList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import React, { useMemo } from 'react';
import { isNull, noop } from 'lodash';
import classnames from 'classnames';
import VirtualList from './VirtualList';
import { OptionsListProps, Option } from './interface';
import Tooltip from '../tooltip';
import Checkbox from '../checkbox';

const OptionsList: React.FC<OptionsListProps> = (props) => {
const {
labelRenderer,
prefixCls,
data,
groupStyle,
optionStyle,
selected,
multiple,
hasGroup,
height,
itemHeight,
onOptionClick,
...restProps
} = props;

const flettensOptions = useMemo(() => {
const groupMap = new Map();
if (!hasGroup) return data;
data?.map((cur: Option) => {
const gvalue = groupMap.get(cur.groupValue);
if (gvalue) {
const { options, ...rest } = gvalue;
return groupMap.set(cur.groupValue, {
options: [...options, cur],
...rest,
});
}
return groupMap.set(cur.groupValue, {
label: cur.groupLabel,
value: cur.groupValue,
isSelectOptGroup: true,
options: [cur],
});
});
const flettenOption: Option[] = [];
groupMap.forEach((value) => {
flettenOption.push(value);
flettenOption.push(...value.options);
});
return flettenOption;
}, [data, hasGroup]);

const renderGroupItem = (option: Option) => {
const { value, label } = option;
return (
<div className={`${prefixCls}-list-group`} style={groupStyle} aria-hidden="true">
{label !== undefined ? label : value}
</div>
);
};

const renderTootip = (option: Option, render: JSX.Element & React.ReactNode) => {
const { tooltip } = option;
if (tooltip) {
return (
<Tooltip title={tooltip} placement="top">
{render}
</Tooltip>
);
}
return render;
};

const renderOption = (option: Option) => {
const { value, disabled, tooltip, groupValue, groupLabel, label, title, ...restOption } = option;
const isSelected =
typeof selected === 'string' ||
typeof selected === 'number' ||
isNull(selected) ||
typeof selected === 'undefined'
? selected === value
: selected.includes(value);
const onClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
event.stopPropagation();
event.preventDefault();
if (onOptionClick) {
onOptionClick(value);
}
};
const labelNode = labelRenderer
? labelRenderer(
{
value,
disabled,
tooltip,
groupValue,
groupLabel,
label,
...restOption,
},
false
)
: title || label;
return (
<div className={`${prefixCls}-list-option-container`} style={optionStyle}>
<div
className={classnames(`${prefixCls}-list-option`, {
[`${prefixCls}-list-option-isSelected`]: isSelected,
[`${prefixCls}-list-option-disabled`]: disabled,
})}
onClick={disabled ? undefined : onClick}
onKeyDown={noop}
aria-hidden="true"
>
{multiple && (
<>
<Checkbox checked={isSelected} disabled={disabled} onChange={noop} />
<span style={{ width: 10 }} />
</>
)}
{labelNode}
</div>
</div>
);
};
return (
<VirtualList
itemKey="value"
prefixCls={prefixCls}
data={flettensOptions}
height={height}
itemHeight={itemHeight}
{...restProps}
>
{(option: Option & { isSelectOptGroup: boolean }) => {
return option.isSelectOptGroup ? renderGroupItem(option) : renderTootip(option, renderOption(option));
}}
</VirtualList>
);
};

export default OptionsList;
43 changes: 36 additions & 7 deletions src/components/select/Select.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import React from 'react';
import React, { useRef } from 'react';
import { Story, Meta } from '@storybook/react/types-6-0';

import Select from './index';
import { SelectProps } from './interface';
import Select, { OptionProps, SelectProps } from './index';
import './style';

export default {
title: 'Components/Functional/Select',
component: Select,
subcomponents: {
Group: Select.Group,
Option: Select.Option,
},
} as Meta;

const labels = ['全部', '已上线', '待上线', '已下线', '草稿'];
Expand All @@ -17,11 +19,38 @@ const optionsWithoutGroup = values.map((value, index) => ({
label: labels[index],
}));

export const Default: Story<SelectProps> = (args) => <Select {...args} />;
const Template: Story<SelectProps> = (args) => {
const ref = useRef(null);
return <Select {...args} ref={ref} />;
};

export const Default = Template.bind({});
Default.args = {
size: 'small',
style: { width: 140 },
placeholder: '请选择',
searchable: true,
disabled: false,
multiple: false,
bordered: true,
allowClear: true,
className: 'gio-demo',
allowCustomOption: true,
size: 'small',
options: optionsWithoutGroup,
style: { width: 160 },
onChange: (value: string | number, option: OptionProps) => {
console.log('onchange', value, option);
},
onSearch: (input: string) => {
console.log('input', input);
},
onSelect: (value: string | number, option: OptionProps) => {
console.log('onselect', value, option);
},
allowDeselect: false,
onDeSelect: (value: string | number, option: OptionProps) => {
console.log('ondeselect', value, option);
},
onClear: () => {
console.log('clear');
},
};
Loading

0 comments on commit ead092d

Please sign in to comment.