Skip to content

Commit

Permalink
fix(list): support empty (#1682)
Browse files Browse the repository at this point in the history
  • Loading branch information
berber1016 committed Dec 20, 2021
1 parent b647ee9 commit c1500f6
Show file tree
Hide file tree
Showing 16 changed files with 139 additions and 53 deletions.
6 changes: 5 additions & 1 deletion src/cascader/Cascader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ export const Cascader: React.FC<CascaderProps> = ({
maxWidth,
hidePrefix,
renderTrigger: propsRenderTrigger,
empty,
needEmpty = true,
...rest
}) => {
const defaultPrefixCls = usePrefixCls(prefixCls);
Expand Down Expand Up @@ -120,13 +122,15 @@ export const Cascader: React.FC<CascaderProps> = ({
style={contentStyle}
model="cascader"
itemStrategy={itemStrategy}
empty={empty}
needEmpty={needEmpty}
>
{children}
</List>
);

return (
<ListContext.Provider value={{ value, onChange: handleChange, setOptions }}>
<ListContext.Provider value={{ value, onChange: handleChange, setOptions, emptyNode: empty, isEmpty: needEmpty }}>
<Popover
content={renderOverlay()}
trigger="click"
Expand Down
38 changes: 25 additions & 13 deletions src/list-picker/demos/List-picker.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import Tabs, { Tab } from '../../tabs';
import List from '../../list';
import Recent from '../Recent';
import Docs from './List-pickerPage';
import { Card, Divider, Popover, Skeleton, Table, Tag } from '../..';
import { Card, Divider, Popover, Skeleton, Table, Tag, Page } from '../..';

interface Tmesurements {
id: string;
Expand Down Expand Up @@ -327,18 +327,30 @@ export const Selection = (args: ListPickerProps) => {
export const Default: Story<ListPickerProps> = (args: ListPickerProps) => {
const [activeTab, setActiveTab] = useState('tab1');
return (
<ListPicker
{...args}
style={{ width: '240px' }}
placeholder="请选择"
getContainer={(node) => node?.parentElement || document.body}
>
<Tabs value={activeTab} defaultValue="tab1" onChange={(key: string) => setActiveTab(key)}>
<Tab label="tab1" value="tab1">
<List style={{ width: '240px' }} options={simpleLargeOptions} />
</Tab>
</Tabs>
</ListPicker>
<>
<ListPicker
{...args}
style={{ width: '240px' }}
placeholder="请选择"
getContainer={(node) => node?.parentElement || document.body}
>
<Tabs value={activeTab} defaultValue="tab1" onChange={(key: string) => setActiveTab(key)}>
<Tab label="tab1" value="tab1">
<List style={{ width: '240px' }} options={simpleLargeOptions} />
</Tab>
<Tab label="tab2" value="tab2">
<List style={{ width: '240px' }} options={[]} />
</Tab>
<Tab label="tab3" value="tab3">
<List
style={{ width: '240px' }}
options={[]}
empty={<Page type="noFind" description="暂无数据" size="small" />}
/>
</Tab>
</Tabs>
</ListPicker>
</>
);
};
const getGroup = (type: string, isSystem = false) => {
Expand Down
3 changes: 2 additions & 1 deletion src/list-picker/interfance.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React from 'react';
import { InputButtonProps } from '../input';
// import { OptionProps as CascaderOptionProps } from '../cascader/interfance';
import { OptionProps } from '../list/interfance';
import { Placement, TriggerAction } from '../popover/interface';
import { ListProps } from '../list';

export interface ListPickerProps extends Pick<ListProps, 'model'> {
export interface ListPickerProps extends Pick<ListProps, 'model' | 'empty' | 'needEmpty'> {
size?: 'small' | 'normal';
/**
* 触发方式
Expand Down
5 changes: 4 additions & 1 deletion src/list-picker/listPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ export const ListPicker: React.FC<ListPickerProps> = (props) => {
contentClassName,
model = 'single',
needConfim = model === 'multiple',

empty,
needEmpty = true,
allowClear,
title,
triggerPrefix,
Expand Down Expand Up @@ -166,6 +167,8 @@ export const ListPicker: React.FC<ListPickerProps> = (props) => {
getOptionByValue,
getOptionsByValue,
getLabelByValue,
emptyNode: empty,
isEmpty: needEmpty,
recentId: propsRecentId,
}}
>
Expand Down
14 changes: 11 additions & 3 deletions src/list/Empty.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
import { useLocale } from '@gio-design/utils';
import React from 'react';
import Page from '../page';
import { collectOptions } from './util';
import defaultLocaleTextObject from './locales/zh-CN';

const Empty: React.FC<any> = ({ children }) => {
interface EmptyProps {
emptyNode?: React.ReactNode;
children?: React.ReactElement;
}

const Empty: React.FC<EmptyProps> = ({ children, emptyNode }) => {
const options = collectOptions(children);
const localeTextObject: typeof defaultLocaleTextObject = useLocale('List') || defaultLocaleTextObject;
if (options.length === 0) {
return (
<div style={{ width: '100%', padding: '30px 0' }}>
<Page type="noData" description="暂无数据" size="small" />
{emptyNode ?? <Page type="noData" description={localeTextObject.exptyText} size="small" />}
</div>
);
}
return children;
return children ?? <></>;
};

export default Empty;
27 changes: 25 additions & 2 deletions src/list/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ export const InnerList = WithRef<HTMLDivElement, ListProps>((props, ref?) => {
renderItem,
onClick,
itemStrategy,
empty,
needEmpty = false,
...listRestProps
} = props;

Expand All @@ -52,6 +54,8 @@ export const InnerList = WithRef<HTMLDivElement, ListProps>((props, ref?) => {
isSelection,
} = context;
const mergedModel = useMemo(() => model ?? contextModel, [contextModel, model]);
const mergedEmpty = empty ?? context.emptyNode;
const mergedIsEmpty = needEmpty || context.isEmpty;
const mergedDisabled = disabled ?? contextDisabled;
/** end */

Expand Down Expand Up @@ -128,7 +132,24 @@ export const InnerList = WithRef<HTMLDivElement, ListProps>((props, ref?) => {
return childs;
};
if (mergedOptions.length === 0) {
return <></>;
if (isSelection || !mergedIsEmpty) {
return <></>;
}
return (
<div
className={classNames(`${prefixCls}`, className, {
[`${usePrefixCls('cascader')}`]: mergedModel === 'cascader',
[`${usePrefixCls('list')}--empty`]: mergedOptions.length === 0,
})}
data-testid="list-empty"
style={style}
ref={ref}
id={id}
title={title}
>
<Empty emptyNode={mergedEmpty} />
</div>
);
}
const renderExpandedItem = (needCollapse = false) => {
if (needCollapse) {
Expand Down Expand Up @@ -157,6 +178,8 @@ export const InnerList = WithRef<HTMLDivElement, ListProps>((props, ref?) => {
value={{
...context,
model: mergedModel,
isEmpty: mergedIsEmpty,
emptyNode: mergedEmpty,
value,
disabled: mergedDisabled,
prefix,
Expand All @@ -177,7 +200,7 @@ export const InnerList = WithRef<HTMLDivElement, ListProps>((props, ref?) => {
title={title}
{...listRestProps}
>
{isSelection ? renderContent : <Empty>{renderContent}</Empty>}
{isSelection || !mergedIsEmpty ? renderContent : <Empty emptyNode={mergedEmpty}>{renderContent}</Empty>}
</div>
</ListContext.Provider>
);
Expand Down
10 changes: 6 additions & 4 deletions src/list/Selection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import Empty from './Empty';
type nodeType = React.ReactElement<ListProps> & { type: { isGIOList: boolean; isRecent: boolean } };

const Selection: React.FC<SelectionProps> & { isSelection?: boolean } = (props) => {
const { className, style, options = [], children, ...rest } = props;
const { className, style, options = [], children, empty, ...rest } = props;
const prefixCls = `${usePrefixCls(PREFIX)}--selection`;
const isSelection = options?.every((val) => 'groupId' in val) ?? false;

Expand All @@ -24,7 +24,7 @@ const Selection: React.FC<SelectionProps> & { isSelection?: boolean } = (props)
);
const cache = useCacheOptions();
const contextVal = useContext(ListContext);
const { setOptions: contextSetOptions, onChange: contextOnChange } = contextVal;
const { setOptions: contextSetOptions, onChange: contextOnChange, emptyNode, isEmpty: needEmpty } = contextVal;
const setOptions = (opts?: OptionProps[]) => {
cache?.setOptions(opts);
contextSetOptions?.(opts);
Expand Down Expand Up @@ -85,7 +85,9 @@ const Selection: React.FC<SelectionProps> & { isSelection?: boolean } = (props)
{!isSelection && !isEmpty(selectionOptions) && <List options={selectionOptions as OptionProps[]} />}
</div>
);
return selectionProvider(<Empty>{renderOptionsChildren}</Empty>);
return selectionProvider(
needEmpty ? <Empty emptyNode={empty ?? emptyNode}>{renderOptionsChildren}</Empty> : renderOptionsChildren
);
}

if (isFunction(children)) {
Expand All @@ -104,7 +106,7 @@ const Selection: React.FC<SelectionProps> & { isSelection?: boolean } = (props)
{toArray(children)?.map((node: nodeType) => renderContent(node))}
</div>
);
return selectionProvider(<Empty>{renderNormal}</Empty>);
return selectionProvider(needEmpty ? <Empty emptyNode={empty ?? emptyNode}>{renderNormal}</Empty> : renderNormal);
};
Selection.isSelection = true;
export default Selection;
2 changes: 2 additions & 0 deletions src/list/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface ListContextProps {
disabled?: boolean;
isSelection?: boolean;
isEmpty?: boolean;
emptyNode?: React.ReactNode;
selectParent?: any;
onChange?: (value?: MaybeArray<string | number>, options?: OptionProps | OptionProps[]) => void;
onClick?: (value?: string | number, event?: React.MouseEvent<HTMLLIElement | HTMLInputElement>) => void;
Expand All @@ -34,6 +35,7 @@ const defaultList: ListContextProps = {
setOptions: noop,
prefix: undefined,
suffix: undefined,
emptyNode: undefined,
getOptionByValue: undefined,
getOptionsByValue: undefined,
getLabelByValue: undefined,
Expand Down
51 changes: 28 additions & 23 deletions src/list/demos/List.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -242,29 +242,34 @@ const ItemTemplate: Story<ItemProps> = () => {
};
const ref = useRef(null);
return (
<div className="demo-box">
<List onChange={() => console.log('list onChange触发')} ref={ref}>
<Item value="first">第1条咸鱼</Item>
<Item value="second" prefix={<PlusOutlined size="14px" />}>
第2条咸鱼
</Item>
<Item value="second-1" prefix={<PlusOutlined size="14px" />} suffix={<FilterOutlined size="14px" />}>
第2-1条咸鱼
</Item>
<Item value="third" suffix={<FilterOutlined size="14px" />} onClick={itemClick}>
mouseEvent
</Item>
<Item value="third" onClick={itemClick} suffix={<FilterOutlined size="14px" onClick={suffixClick} />}>
第3-1 拦截suffix点击
</Item>
<Item value="four" disabled onClick={itemClick}>
第4条咸鱼
</Item>
<Item value="five" disabled disabledTooltip="disabledTooltip">
第5条咸鱼
</Item>
<Item value="six">{'第666666条咸鱼'.repeat(5)}</Item>
</List>
<div style={{ display: 'flex' }}>
<div className="demo-box">
<List onChange={() => console.log('list onChange触发')} ref={ref}>
<Item value="first">第1条咸鱼</Item>
<Item value="second" prefix={<PlusOutlined size="14px" />}>
第2条咸鱼
</Item>
<Item value="second-1" prefix={<PlusOutlined size="14px" />} suffix={<FilterOutlined size="14px" />}>
第2-1条咸鱼
</Item>
<Item value="third" suffix={<FilterOutlined size="14px" />} onClick={itemClick}>
mouseEvent
</Item>
<Item value="third" onClick={itemClick} suffix={<FilterOutlined size="14px" onClick={suffixClick} />}>
第3-1 拦截suffix点击
</Item>
<Item value="four" disabled onClick={itemClick}>
第4条咸鱼
</Item>
<Item value="five" disabled disabledTooltip="disabledTooltip">
第5条咸鱼
</Item>
<Item value="six">{'第666666条咸鱼'.repeat(5)}</Item>
</List>
</div>
<div className="demo-box">
<List options={[]} needEmpty />
</div>
</div>
);
};
Expand Down
16 changes: 14 additions & 2 deletions src/list/inner/CascaderItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,13 @@ const CascaderItem: React.ForwardRefRenderFunction<
if (!isEmpty(childrens)) {
return (
<ListContext.Provider
value={{ ...context, disabled: mergedDisabled, model: 'cascader', selectParent: childSelectPrent }}
value={{
...context,
isEmpty: false,
disabled: mergedDisabled,
model: 'cascader',
selectParent: childSelectPrent,
}}
>
<List className={`${prefixCls}--list`}>
{childrens?.map((child) => (
Expand All @@ -67,7 +73,13 @@ const CascaderItem: React.ForwardRefRenderFunction<
/** JSX */
return (
<ListContext.Provider
value={{ ...context, disabled: mergedDisabled, model: 'cascader', selectParent: childSelectPrent }}
value={{
...context,
isEmpty: false,
disabled: mergedDisabled,
model: 'cascader',
selectParent: childSelectPrent,
}}
>
{React.isValidElement(children)
? React.cloneElement(children, { className: classNames(children?.props?.className, `${prefixCls}--list`) })
Expand Down
2 changes: 2 additions & 0 deletions src/list/interfance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ export interface ListProps {
*/
renderItem?: (option: OptionProps) => React.ReactElement;
itemStrategy?: 'fixed' | 'absolute';
empty?: React.ReactNode;
needEmpty?: boolean;
}

export interface DragListProps extends Omit<ListProps, 'model' | 'onChange' | 'value' | 'children'> {
Expand Down
1 change: 1 addition & 0 deletions src/list/locales/en-US.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export default {
if (isNil(text)) return `Expand All`;
return `Expand All(${text})`;
},
exptyText: 'No data',
};
1 change: 1 addition & 0 deletions src/list/locales/zh-CN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export default {
if (isNil(text)) return `展开全部`;
return `展开全部(${text})`;
},
exptyText: '暂无数据',
};
7 changes: 7 additions & 0 deletions src/select/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ const Select: React.FC<SelectProps> & { isSelect?: boolean } = (props) => {
onClear,
renderTrigger: propsRenderTrigger,
autoWidth = false,
empty,
needEmpty = true,
// list props
...rest
} = props;
Expand Down Expand Up @@ -124,6 +126,8 @@ const Select: React.FC<SelectProps> & { isSelect?: boolean } = (props) => {
suffix={suffix}
options={mergedOptions}
disabled={disabled}
empty={empty}
needEmpty={needEmpty}
{...omit({ ...rest }, 'data-testid')}
/>
);
Expand All @@ -133,6 +137,9 @@ const Select: React.FC<SelectProps> & { isSelect?: boolean } = (props) => {
value={{
value,
options: cacheOptions,
isEmpty: needEmpty,
emptyNode: empty,
isSelection: false,
getLabelByValue,
getOptionByValue,
getOptionsByValue,
Expand Down

1 comment on commit c1500f6

@vercel
Copy link

@vercel vercel bot commented on c1500f6 Dec 20, 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.