Skip to content

Commit

Permalink
fix(popover): async render (#1495)
Browse files Browse the repository at this point in the history
Co-authored-by: shiliqian <shiliqian@growingio.com>
  • Loading branch information
berber1016 and shiliqian committed Nov 22, 2021
1 parent a690e18 commit 2d06edc
Show file tree
Hide file tree
Showing 16 changed files with 146 additions and 61 deletions.
4 changes: 3 additions & 1 deletion src/cascader/Cascader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const Cascader: React.FC<CascaderProps> = (props) => {
separator = '',
placement = 'bottomLeft',
children,
strategy = 'fixed',
...rest
} = props;
const defaultPrefixCls = usePrefixCls(prefixCls);
Expand Down Expand Up @@ -69,7 +70,7 @@ const Cascader: React.FC<CascaderProps> = (props) => {
className={classNames(`${defaultPrefixCls}-trigger`, className)}
style={style}
aria-hidden="true"
onClick={() => setVisible(!visible)}
onClick={() => !disabled && setVisible(!visible)}
>
<Trigger
value={title}
Expand Down Expand Up @@ -108,6 +109,7 @@ const Cascader: React.FC<CascaderProps> = (props) => {
overlayClassName={classNames(`${defaultPrefixCls}--content`, overlayClassName)}
overlayStyle={overlayStyle}
placement={placement}
strategy={strategy}
>
{renderTrigger()}
</Popover>
Expand Down
8 changes: 4 additions & 4 deletions src/cascader/demos/Cascader.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,15 @@ const Template: Story<CascaderProps> = (props) => {
</div>
<div className="demo-box">
<Cascader triggerProps={{ placeholder: '请选择', allowClear: false }} size="normal" {...props}>
<CascaderItem label="苹果" value="apple">
<List model="cascader">
<CascaderItem label="苹果" value="apple" disabled>
<List>
<CascaderItem label="切" value="cat">
<List model="cascader">
<List>
<CascaderItem label="坏了" value="bad" />
<CascaderItem label="没坏" value="good" />
</List>
</CascaderItem>
<CascaderItem label="掰开" value="bye" />
<CascaderItem prefix="233" label="掰开" value="bye" />
</List>
</CascaderItem>
</Cascader>
Expand Down
6 changes: 4 additions & 2 deletions src/cascader/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import CascaderItem from '../list/inner/CascaderItem';
import WithSubComponent from '../utils/withSubComponent';
import Cascader from './Cascader';

export { CascaderProps } from './interfance';

export default Cascader;
export { Cascader, CascaderItem };
export default WithSubComponent(Cascader, { Item: CascaderItem });
1 change: 1 addition & 0 deletions src/cascader/interfance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export interface CascaderProps extends Omit<ListProps, 'options' | 'onChange' |
contentClassName?: string;
contentStyle?: React.CSSProperties;
placement?: Placement;
strategy?: 'fixed' | 'absolute';
}
export interface OptionProps extends ListOptionProps {
label: string;
Expand Down
51 changes: 38 additions & 13 deletions src/list-picker/demos/List-picker.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useState } from 'react';
import { Story, Meta } from '@storybook/react/types-6-0';
import '../style';
import { uniqueId } from 'lodash';
import { OptionProps } from '../../list/interfance';
// import { uniqueId } from 'lodash';
// import { uniqBy, uniqueId } from 'lodash';
Expand All @@ -15,22 +16,21 @@ export default {
title: 'Upgraded/ListPicker',
component: ListPicker,
} as Meta;
// const groupIds = ['custom', 'virtual', 'tag', 'visible'];
// const groupNames = ['埋点', '虚拟', '标签', '属性'];
const groupIds = ['custom', 'virtual', 'tag', 'visible'];
const groupNames = ['埋点', '虚拟', '标签', '属性'];
// const selectionValues = ['all', 'apple', 'banana'];
// const selectionNames = ['全局', '苹果', '香蕉'];
// const createOption = (index: number) => ({
// label: uniqueId(`label-${index.toString()}`),
// value: uniqueId(`value-${index.toString()}`),
// groupId: groupIds[Math.floor(index % 4)],
// groupName: groupNames[Math.floor(index % 4)],
// selectionValue: selectionValues[Math.floor(index % 3)],
// selectionTitle: selectionNames[Math.floor(index % 3)],
// });
const createOption = (index: number) => ({
label: uniqueId(`label-${index.toString()}`),
value: uniqueId(`value-${index.toString()}`),
groupId: groupIds[Math.floor(index % 4)],
groupName: groupNames[Math.floor(index % 4)],
});
const largeOptions = new Array(200).fill(0).map((v, i) => createOption(i));

const Template: Story<ListPickerProps> = () => {
const [value, setValue] = useState('banana2');
const [multipleValue, setMultipleValue] = useState(['ziyi']);
const [value, setValue] = useState<undefined | string>('banana');
const [multipleValue, setMultipleValue] = useState<undefined | string[]>(undefined);
const [activeTab, setActiveTab] = useState('tab1');
const [search, setSearch] = useState('');
const onChange = (val?: string, opt?: OptionProps | OptionProps[]) => {
Expand All @@ -46,8 +46,9 @@ const Template: Story<ListPickerProps> = () => {
onChange={onChange}
overlayStyle={{ width: '240px' }}
onClear={() => {
setValue('');
// setValue(undefined);
}}
triggerProps={{ allowClear: true }}
placeholder="请选择"
>
<SearchBar
Expand Down Expand Up @@ -181,6 +182,30 @@ const Template: Story<ListPickerProps> = () => {
/>
</ListPicker>
</div>

<div className="demo-box">
<ListPicker
value={multipleValue}
onChange={(val) => {
console.log('multiple onChange 并不会触发', val);
}}
overlayStyle={{ width: '240px' }}
model="multiple"
onClear={() => {
setMultipleValue(undefined);
}}
onConfim={(val) => setMultipleValue(val as any)}
placeholder="请选择"
>
<SearchBar
size="small"
style={{ width: '100%' }}
placeholder="请搜索名称"
onSearch={(val: string) => setSearch(val)}
/>
<List.Selection options={largeOptions} />
</ListPicker>
</div>
</div>
</div>
);
Expand Down
18 changes: 14 additions & 4 deletions src/list-picker/listPicker.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useEffect, useState } from 'react';
import classNames from 'classnames';
import { isEqual } from 'lodash';
import { ListPickerProps } from './interfance';
import Popover from '../popover';
import Trigger from './Trigger';
Expand All @@ -19,6 +20,7 @@ const ListPicker: React.FC<ListPickerProps> = (props) => {
placeholder,
onClear,
value: controlledValue,
defaultValue,
trigger = 'click',
visible: controlledVisible,
onVisibleChange,
Expand All @@ -40,21 +42,28 @@ const ListPicker: React.FC<ListPickerProps> = (props) => {
} = props;
const defaultPrefix = usePrefixCls(prefixCls);
const [visible, setVisible] = useControlledState(controlledVisible, false);
const [value, setValue] = useState(controlledValue);
const [title, setTitle] = useState<string | React.ReactNode>('');
const [value, setValue] = useState(controlledValue || defaultValue);
const [title, setTitle] = useState<string | React.ReactNode>(undefined);

const { options, setOptions, getLabelByValue, getOptionsByValue } = useCacheOptions();

// title仅跟随controlledValue变动
useEffect(() => {
setTitle(getLabelByValue(controlledValue, separator));
}, [controlledValue, getLabelByValue, separator]);
}, [controlledValue, getLabelByValue, separator, options]);

useEffect(() => {
if (!needConfim) {
console.log('执行', controlledValue);
setValue(controlledValue);
}
}, [controlledValue, needConfim, setValue]);
useEffect(() => {
if (needConfim && !visible && !isEqual(controlledValue, value)) {
setValue(controlledValue);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [visible]);
// methods
const handVisibleChange = (vis: boolean) => {
setVisible(vis);
Expand Down Expand Up @@ -86,6 +95,7 @@ const ListPicker: React.FC<ListPickerProps> = (props) => {
}
return (
<Trigger
onClick={() => setVisible(!visible)}
value={title}
{...triggerProp}
// disabled={disabled}
Expand All @@ -101,7 +111,7 @@ const ListPicker: React.FC<ListPickerProps> = (props) => {
const renderOverlay = () => (
<div className={classNames(defaultPrefix, className)} style={style}>
{children}
{model === 'multiple' && (
{model === 'multiple' && needConfim && (
<Button style={{ width: '100%' }} onClick={() => handleConfim()}>
{confimText}
</Button>
Expand Down
18 changes: 18 additions & 0 deletions src/list-picker/style/index.less
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
@import '~@gio-design/utils/lib/less/mixins.less';
@list-picker-prefix-cls: ~'@{component-prefix}-list-picker--new';
@selection-prefix-cls: ~'@{component-prefix}-list-new--selection';
@tab-panel-cls: ~'@{component-prefix}-tabs-new-tabpanel';

@list-prefix-cls: ~'@{component-prefix}-list-new';
.@{list-picker-prefix-cls} {
box-sizing: border-box;
Expand Down Expand Up @@ -35,4 +37,20 @@
padding: 0;
.scrollbar();
}
& .@{tab-panel-cls} {
.@{selection-prefix-cls} {
height: auto;
max-height: 360px;
// margin-bottom: 8px;
padding-top: 8px;
.scrollbar();
}
& > .@{list-prefix-cls} {
height: auto;
max-height: 360px;
// margin-bottom: 8px;
padding-top: 8px;
.scrollbar();
}
}
}
4 changes: 2 additions & 2 deletions src/list/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ const List: React.ForwardRefRenderFunction<HTMLDivElement, ListProps> & {
<Item
{...option}
key={option.value}
prefix={prefix?.(option)}
suffix={suffix?.(option)}
prefix={option?.prefix ?? prefix?.(option)}
suffix={option?.suffix ?? suffix?.(option)}
disabled={option?.disabled ?? disabled}
isMultiple={isMultipe(mergedModel)}
isCascader={isCascader(mergedModel)}
Expand Down
5 changes: 3 additions & 2 deletions src/list/hooks/useCacheOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ const useCacheOptions = () => {

const getLabelByValue = (val?: string | string[], separator = '') => {
if (val === '' || typeof val === 'undefined') {
return '';
return undefined;
}

if (val?.includes('.')) {
return (val as any)
?.split('.')
Expand All @@ -46,7 +47,7 @@ const useCacheOptions = () => {
if (isArray(val)) {
return val?.reduce((prev, curr: string) => [...prev, getOptionByValue?.(curr)?.label], [])?.join(',');
}
return getOptionByValue(val)?.label ?? '';
return getOptionByValue(val)?.label;
};
return {
options: options.current,
Expand Down
4 changes: 3 additions & 1 deletion src/list/inner/CascaderItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,14 @@ const CascaderItem: React.ForwardRefRenderFunction<
const content = () => {
if (!isEmpty(childrens)) {
return (
<List model="cascader" className={prefixCls}>
<List model="cascader" className={prefixCls} disabled={disabled}>
{childrens?.map((child) => (
<CascaderItem
label={child?.label}
value={child?.value}
childrens={child?.childrens as CascaderItemProps[]}
selectParent={childSelectPrent}
disabled={disabled}
/>
))}
</List>
Expand All @@ -63,6 +64,7 @@ const CascaderItem: React.ForwardRefRenderFunction<
return React.cloneElement<ListProps>(children, {
...children.props,
model: 'cascader',
disabled,
className: classNames(children.props?.className, prefixCls),
children: React.Children.toArray(children?.props.children).map((child) =>
React.cloneElement<OptionProps>(child as React.ReactElement, {
Expand Down
2 changes: 1 addition & 1 deletion src/list/inner/baseItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const BaseItem: React.ForwardRefRenderFunction<
);
return (
<Tooltip
disabled={disabled && !isEmpty(disabledTooltip)}
disabled={!disabled || isEmpty(disabledTooltip)}
strategy="fixed"
getContainer={() => document.body}
title={disabledTooltip}
Expand Down
8 changes: 4 additions & 4 deletions src/list/interfance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ export interface OptionProps {
value: string;
disabled?: boolean;
disabledTooltip?: string;
prefix?: string | React.ReactNode;
suffix?: string | React.ReactNode;
[key: string]: unknown;
}

Expand All @@ -106,9 +108,9 @@ export interface ItemProps
| 'style'
| 'label'
| 'children'
| 'onClick'
| 'prefix'
| 'suffix'
| 'onClick'
| 'label'
| 'value'
| 'disabled'
Expand All @@ -118,15 +120,13 @@ export interface ItemProps
selectValue?: string | string[];
}

export interface BaseItemProps extends Pick<OptionProps, 'value' | 'disabled'> {
export interface BaseItemProps extends Pick<OptionProps, 'value' | 'disabled' | 'prefix' | 'suffix'> {
className?: string;
style?: React.CSSProperties;
label?: string | React.ReactNode;
contentRender?: (element: React.ReactNode) => React.ReactNode | Element;
children?: React.ReactNode;
disabledTooltip?: string;
selected?: boolean;
prefix?: string | React.ReactNode;
suffix?: string | React.ReactNode;
onClick?: (value: string) => void;
}
29 changes: 18 additions & 11 deletions src/list/style/index.less
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
}

&[data-popper-placement^='left'] {
padding-right: 12px !important;
margin-right: 8px !important;
}

&[data-popper-placement^='right'] {
Expand Down Expand Up @@ -130,10 +130,26 @@
&--actived:not(&--multiple) &-prefix-icon {
color: @blue-3;
}
&-prefix-icon {
display: inherit;
margin-right: 8px;
color: @gray-5;
}
&-suffix-icon {
display: inherit;
margin-left: 8px;
color: @gray-3;
}
&--disabled {
color: @gray-3;
cursor: not-allowed;
}
&--disabled > &-prefix-icon {
color: @gray-3;
}
&--disabled > &-suffix-icon {
color: @gray-3;
}
&--interval {
margin-top: 4px;
}
Expand All @@ -158,16 +174,7 @@
> span > .gio-text--black {
color: inherit;
}
&-prefix-icon {
display: inherit;
margin-right: 8px;
color: @gray-5;
}
&-suffix-icon {
display: inherit;
margin-left: 8px;
color: @gray-3;
}

&--checkbox {
font-size: 0;
}
Expand Down

1 comment on commit 2d06edc

@vercel
Copy link

@vercel vercel bot commented on 2d06edc Nov 22, 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.