Skip to content

Commit

Permalink
fix(select): option disabled style (#762)
Browse files Browse the repository at this point in the history
Co-authored-by: shiliqian <shiliqian@growingio.com>
  • Loading branch information
berber1016 and shiliqian authored Feb 4, 2021
1 parent 6f6381d commit 95cc0c0
Show file tree
Hide file tree
Showing 14 changed files with 9,841 additions and 8,980 deletions.
16,860 changes: 8,639 additions & 8,221 deletions src/components/pagination/__test__/__snapshots__/Pagination.test.js.snap

Large diffs are not rendered by default.

122 changes: 92 additions & 30 deletions src/components/select/OptionsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,21 @@ interface OptionProp {
children?: React.ReactNode;
}

const RenderGroup: React.FC<GroupProps> = (props) => {
const RenderGroup: React.ForwardRefRenderFunction<unknown, GroupProps> = (props, ref) => {
const {
option: { value, label },
prefixCls,
groupStyle,
} = props;

return (
<div className={`${prefixCls}-list-group`} style={groupStyle} aria-hidden="true">
<div ref={ref as any} className={`${prefixCls}-list-group`} style={groupStyle} aria-hidden="true">
{label !== undefined ? label : value}
</div>
);
};

const RenderOption: React.FC<OptionProp> = (props) => {
const RenderOption: React.ForwardRefRenderFunction<unknown, OptionProp> = (props, ref) => {
const {
option: { value, disabled, tooltip, groupValue, groupLabel, label, title, ...restOption },
selected,
Expand All @@ -53,6 +54,7 @@ const RenderOption: React.FC<OptionProp> = (props) => {
optionStyle,
multiple,
} = props;

const isSelected =
typeof selected === 'string' || typeof selected === 'number' || isNull(selected) || typeof selected === 'undefined'
? selected === value
Expand All @@ -79,7 +81,7 @@ const RenderOption: React.FC<OptionProp> = (props) => {
)
: title || label;
return (
<div className={`${prefixCls}-list-option-container`} style={optionStyle}>
<div ref={ref as any} className={`${prefixCls}-list-option-container`} style={optionStyle}>
<div
className={classnames(`${prefixCls}-list-option`, {
[`${prefixCls}-list-option-isSelected`]: isSelected,
Expand All @@ -101,18 +103,22 @@ const RenderOption: React.FC<OptionProp> = (props) => {
);
};

const RenderTooltip: React.FC<TooltipProps> = (props) => {
const RenderTooltip: React.ForwardRefRenderFunction<unknown, TooltipProps> = (props, ref) => {
const { tooltip, render, getContainer } = props;
if (tooltip) {
return (
<Tooltip title={tooltip} destroyTooltipOnHide placement="top" getTooltipContainer={getContainer}>
{render}
</Tooltip>
<div ref={ref as any}>
<Tooltip title={tooltip} destroyTooltipOnHide placement="top" getTooltipContainer={getContainer}>
{render}
</Tooltip>
</div>
);
}
return render;
return <div ref={ref as any}>{render}</div>;
};

const ForwardRenderGroup = React.forwardRef(RenderGroup);
const ForwardRenderOption = React.forwardRef(RenderOption);
const ForwardRenderTooltip = React.forwardRef(RenderTooltip);
const getFlattenOptions = (data: Option[], hasGroup: boolean) => {
const groupMap = new Map();
if (!hasGroup) return data;
Expand All @@ -139,30 +145,86 @@ const getFlattenOptions = (data: Option[], hasGroup: boolean) => {
});
return flattenOption;
};

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

const flattenOptions = useMemo(() => getFlattenOptions(data, hasGroup), [data, hasGroup]);
const filterflattenOptions = useMemo(
() =>
flattenOptions.filter((filterOption: Option & { isSelectOptGroup: boolean }) => !filterOption.isSelectOptGroup),
[flattenOptions]
);
const isChecked = useMemo(() => {
return selected && (selected as []).length >= 1;
}, [selected]);
const isIndeterminate = isChecked && selected && (selected as []).length < filterflattenOptions.length;

const onAllClick = () => {
if (isChecked) {
onAllChange?.(null);
} else {
onAllChange?.(
filterflattenOptions.reduce((prev: any[], curr: Option) => {
prev.push(curr.value || curr.label);
return prev;
}, [])
);
}
};
const renderAllOptions = () => {
return (
<div
className={classnames(`${prefixCls}-list-option-all`, {})}
onClick={(e) => {
e.stopPropagation();
onAllClick();
}}
aria-hidden="true"
>
<>
<Checkbox checked={isChecked as boolean} indeterminate={isIndeterminate as boolean} />
<span style={{ width: 10 }} />
</>
全部
</div>
);
};
return (
<VirtualList
itemKey="value"
prefixCls={prefixCls}
data={flattenOptions}
height={height}
itemHeight={itemHeight}
{...restProps}
>
{(option: Option & { isSelectOptGroup: boolean }) => {
return option.isSelectOptGroup ? (
<RenderGroup option={option} prefixCls={prefixCls} groupStyle={groupStyle} />
) : (
<RenderTooltip
tooltip={option?.tooltip}
render={<RenderOption option={option} prefixCls={prefixCls} {...restProps} />}
/>
);
}}
</VirtualList>
<>
{mode === 'all' ? renderAllOptions() : undefined}
<VirtualList
itemKey="value"
prefixCls={prefixCls}
data={flattenOptions}
// ref={virtualListRef}
height={height}
itemHeight={itemHeight}
{...restProps}
>
{(option: Option & { isSelectOptGroup: boolean }) => {
return option.isSelectOptGroup ? (
<ForwardRenderGroup option={option} prefixCls={prefixCls} groupStyle={groupStyle} />
) : (
<ForwardRenderTooltip
tooltip={option?.tooltip}
render={<ForwardRenderOption option={option} prefixCls={prefixCls} selected={selected} {...restProps} />}
/>
);
}}
</VirtualList>
</>
);
};

Expand Down
94 changes: 88 additions & 6 deletions src/components/select/Select.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useRef } from 'react';
import { Story, Meta } from '@storybook/react/types-6-0';
import Select, { OptionProps, SelectProps } from './index';
import './style';
import Tooltip from '../tooltip';

export default {
title: 'Components/Functional/Select',
Expand All @@ -12,24 +13,75 @@ export default {
},
} as Meta;

const labels = ['全部', '已上线', '待上线', '已下线', '草稿'];
const values = ['all', 'online', 'pending', 'off', 'draft'];
const optionsWithoutGroup = values.map((value, index) => ({
value,
label: labels[index],
const labels = ['a', 'b', 'c', 'd', 'e'];
const options = new Array(50).fill(0).map((value, index) => ({
value: `${labels[index % 5]}${index}`,
label: `${labels[index % 5]}${index}`,
}));

const optionsWithoutGroup = new Array(20).fill(0).map((value, index) => ({
value: `${labels[index % 5]}${index}`,
label: `${labels[index % 5]}${index}`,
disabled: index % 5 === 0,
groupLabel: `${labels[index % 5]}__optionGroup`,
groupValue: `${labels[index % 5]}__optionGroup`,
}));

const optionsWithCustomLabel = new Array(20).fill(0).map((value, index) => ({
value: `${labels[index % 5]}${index}`,
disabled: index % 5 === 0,
label: (
<Tooltip title="测试">
<div style={{ height: 50, width: '100%', background: 'aliceblue' }}>{`${labels[index % 5]}${index}`}</div>
</Tooltip>
),
groupLabel: (
<div style={{ height: 88, width: '100%', background: 'antiquewhite' }}>{`${labels[index % 5]}${index}`}</div>
),
groupValue: `${labels[index % 5]}`,
}));
const Template: Story<SelectProps> = (args) => {
const ref = useRef(null);
return <Select {...args} ref={ref} />;
};

export const Default = Template.bind({});
export const Group = Template.bind({});
export const customOption = Template.bind({});
Default.args = {
placeholder: '请选择',
searchable: true,
disabled: false,
multiple: false,
bordered: true,
allowClear: true,
className: 'gio-demo',
allowCustomOption: true,
size: 'small',
options,
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');
},
};

Group.args = {
placeholder: '请选择',
searchable: true,
disabled: false,
multiple: true,
bordered: true,
allowClear: true,
className: 'gio-demo',
Expand All @@ -54,3 +106,33 @@ Default.args = {
console.log('clear');
},
};

customOption.args = {
placeholder: '请选择',
searchable: true,
disabled: false,
multiple: true,
bordered: true,
allowClear: true,
className: 'gio-demo',
allowCustomOption: true,
size: 'small',
options: optionsWithCustomLabel,
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

1 comment on commit 95cc0c0

@vercel
Copy link

@vercel vercel bot commented on 95cc0c0 Feb 4, 2021

Choose a reason for hiding this comment

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

Please sign in to comment.