Skip to content

Commit

Permalink
Merge branch feat_tabs_overflowList into release
Browse files Browse the repository at this point in the history
  • Loading branch information
pointhalo committed Jun 18, 2024
2 parents b99504c + c2d3fb0 commit 21c7597
Show file tree
Hide file tree
Showing 8 changed files with 531 additions and 244 deletions.
314 changes: 216 additions & 98 deletions content/navigation/tabs/index-en-US.md

Large diffs are not rendered by default.

328 changes: 221 additions & 107 deletions content/navigation/tabs/index.md

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions content/show/overflowlist/index-en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,11 +215,12 @@ import { IconAlarm, IconBookmark, IconCamera, IconDuration, IconEdit, IconFolder

## API Reference

| Properties | Instructions | type | Default | version |
| ---------- | ------------- | --------------------- | ------- | ------- |
| className | Class name. | string | - | 1.1.0 |
| renderMode | Render mode. | `collapse`\| `scroll` | `true` | - |
| style | OverflowList style | React.CSSProperties | - | 1.1.0 |
| Properties | Instructions | type | Default | version |
| ---------- |----------------------------------------| --------------------- | ------- | ------- |
| className | Class name. | string | - | 1.1.0 |
| onVisibleStateChange | Hide and display state change callback | (visibleState: Map\<string, boolean\>) => void; | - | 2.61.0 |
| renderMode | Render mode. | `collapse`\| `scroll` | `true` | - |
| style | OverflowList style | React.CSSProperties | - | 1.1.0 |

### renderMode='collapse'

Expand Down
26 changes: 14 additions & 12 deletions content/show/overflowlist/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,11 +214,11 @@ import { IconAlarm, IconBookmark, IconCamera, IconDuration, IconEdit, IconFolder

## API 参考

| 属性 | 说明 | 类型 | 默认值 | 版本 |
| ---------- | -------- | --------------------- | ---------- | ----- |
| className | 类名 | string | - | 1.1.0 |
| renderMode | 渲染模式 | `collapse`\| `scroll` | `collapse` | 1.1.0 |
| style | OverflowList的样式 | React.CSSProperties | - | 1.1.0 |
| 属性 | 说明 | 类型 | 默认值 | 版本 |
| ---------- | -------- |-------------------------------------------------|------------|--------|
| className | 类名 | string | - | 1.1.0 |
| renderMode | 渲染模式 | `collapse`\| `scroll` | `collapse` | 1.1.0 |
| style | OverflowList的样式 | React.CSSProperties | - | 1.1.0 |

### renderMode='collapse'

Expand All @@ -233,12 +233,14 @@ import { IconAlarm, IconBookmark, IconCamera, IconDuration, IconEdit, IconFolder

### renderMode='scroll'

| 属性 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| items | 渲染项目,**要求必含 key 项** | Record<string, any>[] | - | 1.1.0 |
| 属性 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- |------------------------------------------------------------------------------------------------------------------------------------| --- | --- |
| items | 渲染项目,**要求必含 key 项** | Record<string, any>[] | - | 1.1.0 |
| onIntersect | 溢出回调 | ({[key: string]: [IntersectionObserverEntry](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry)}) => void | - | 1.1.0 |
| overflowRenderer | 溢出项的自定义渲染函数 | (overflowItems: Record<string, any>[]) => React.ReactNode[] | - | 1.1.0 |
| threshold | 触发溢出回调的阈值 | number | 0.75 | 1.1.0 |
| visibleItemRenderer | 展示项的自定义渲染函数 | (item: Record<string, any>, index: number) => React.ReactElement | - | 1.1.0 |
| wrapperClassName | 滚动 wrapper 的类名 | string | - | 1.1.0 |
| onVisibleStateChange | 隐藏显示状态变化回调 | (visibleState: Map\<string, boolean\>) => void; | - | 2.61.0 |
| overflowRenderer | 溢出项的自定义渲染函数 | (overflowItems: Record<string, any>[]) => React.ReactNode[] | - | 1.1.0 |
| threshold | 触发溢出回调的阈值 | number | 0.75 | 1.1.0 |
| visibleItemRenderer | 展示项的自定义渲染函数 | (item: Record<string, any>, index: number) => React.ReactElement | - | 1.1.0 |
| wrapperClassName | 滚动 wrapper 的类名 | string | - | 1.1.0 |
| wrapperStyle | 滚动 wrapper 的样式 | React.CSSProperties | - | 1.1.0 |

32 changes: 24 additions & 8 deletions packages/semi-ui/overflowList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ export interface OverflowListProps {
visibleItemRenderer?: (item: OverflowItem, index: number) => ReactElement;
wrapperClassName?: string;
wrapperStyle?: CSSProperties;
itemKey?: Key | ((item: OverflowItem) => Key)
itemKey?: Key | ((item: OverflowItem) => Key);
onVisibleStateChange?: (visibleState: Map<string, boolean>) => void;
overflowRenderDirection?: "both"|"start"|'end' // used in tabs, not exposed to user
}

export interface OverflowListState {
Expand Down Expand Up @@ -64,6 +66,7 @@ class OverflowList extends BaseComponent<OverflowListProps, OverflowListState> {
threshold: 0.75,
visibleItemRenderer: (): ReactElement => null,
onOverflow: () => null,
overflowRenderDirection: "both",
})
static propTypes = {
// if render in scroll mode, key is required in items
Expand All @@ -81,6 +84,8 @@ class OverflowList extends BaseComponent<OverflowListProps, OverflowListState> {
visibleItemRenderer: PropTypes.func,
wrapperClassName: PropTypes.string,
wrapperStyle: PropTypes.object,
collapseMask: PropTypes.object,
overflowRenderDirection: PropTypes.string,
};

constructor(props: OverflowListProps) {
Expand Down Expand Up @@ -143,7 +148,9 @@ class OverflowList extends BaseComponent<OverflowListProps, OverflowListState> {
return {
...super.adapter,
updateVisibleState: (visibleState): void => {
this.setState({ visibleState });
this.setState({ visibleState }, ()=>{
this.props.onVisibleStateChange?.(visibleState);
});
},
updateStates: (states): void => {
this.setState({ ...states });
Expand Down Expand Up @@ -257,9 +264,8 @@ class OverflowList extends BaseComponent<OverflowListProps, OverflowListState> {
}
const inner =
renderMode === RenderMode.SCROLL ?
[
overflow[0],
<div
(()=>{
const list = [<div
className={cls(wrapperClassName, `${prefixCls}-scroll-wrapper`)}
ref={(ref): void => {
this.scroller = ref;
Expand All @@ -275,9 +281,19 @@ class OverflowList extends BaseComponent<OverflowListProps, OverflowListState> {
key,
});
})}
</div>,
overflow[1],
] :
</div>];
if (this.props.overflowRenderDirection === "both") {
list.unshift(overflow[0]);
list.push(overflow[1]);
} else if (this.props.overflowRenderDirection === "start") {
list.unshift(overflow[1]);
list.unshift(overflow[0]);
} else {
list.push(overflow[0]);
list.push(overflow[1]);
}
return list;
})() :
[
collapseFrom === Boundary.START ? overflow : null,
visible.map((item, idx) => {
Expand Down
35 changes: 25 additions & 10 deletions packages/semi-ui/tabs/TabBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ export interface TabBarState {
endInd: number;
rePosKey: number;
startInd: number;
uuid: string
uuid: string;
currentVisibleItems: string[]
}

export interface OverflowItem extends PlainTab {
Expand Down Expand Up @@ -50,6 +51,7 @@ class TabBar extends React.Component<TabBarProps, TabBarState> {
rePosKey: 0,
startInd: 0,
uuid: '',
currentVisibleItems: []
};
}

Expand Down Expand Up @@ -106,11 +108,10 @@ class TabBar extends React.Component<TabBarProps, TabBarState> {
renderTabItem = (panel: PlainTab): ReactNode => {
const { size, type, deleteTabItem, handleKeyDown, tabPosition } = this.props;
const isSelected = this._isActive(panel.itemKey);

return (
<TabItem
{...pick(panel, ['disabled', 'icon', 'itemKey', 'tab', 'closable'])}
key={this._getItemKey(panel.itemKey)}
key={this._getBarItemKeyByItemKey(panel.itemKey)}
selected={isSelected}
size={size}
type={type}
Expand All @@ -128,7 +129,7 @@ class TabBar extends React.Component<TabBarProps, TabBarState> {
}

scrollActiveTabItemIntoView = (logicalPosition?: ScrollLogicalPosition) => {
const key = this._getItemKey(this.props.activeKey);
const key = this._getBarItemKeyByItemKey(this.props.activeKey);
this.scrollTabItemIntoViewByKey(key, logicalPosition);
}

Expand All @@ -139,7 +140,7 @@ class TabBar extends React.Component<TabBarProps, TabBarState> {
if (!lastItem) {
return;
}
const key = this._getItemKey(lastItem.itemKey);
const key = this._getBarItemKeyByItemKey(lastItem.itemKey);
this.scrollTabItemIntoViewByKey(key);
};

Expand Down Expand Up @@ -218,9 +219,12 @@ class TabBar extends React.Component<TabBarProps, TabBarState> {
);
};

renderOverflow = (items: any[]): Array<ReactNode> => items.map((item, ind) => {
const icon = ind === 0 ? <IconChevronLeft /> : <IconChevronRight />;
const pos = ind === 0 ? 'start' : 'end';
renderOverflow = (items: any[]): Array<ReactNode> => items.map((item, index) => {
const pos = index === 0 ? 'start' : 'end';
if (this.props.renderArrow) {
return this.props.renderArrow(item, pos, ()=>this.handleArrowClick(item, pos));
}
const icon = index === 0 ? <IconChevronLeft/> : <IconChevronRight/>;
return this.renderCollapse(item, icon, pos);
});

Expand All @@ -229,16 +233,26 @@ class TabBar extends React.Component<TabBarProps, TabBarState> {
const { list } = this.props;
const renderedList = list.map(item => {
const { itemKey } = item;
return { key: this._getItemKey(itemKey), active: this._isActive(itemKey), ...item };
return { key: this._getBarItemKeyByItemKey(itemKey), active: this._isActive(itemKey), ...item };
});
return (
<OverflowList
items={renderedList}
overflowRenderDirection={this.props.arrowPosition}
wrapperStyle={this.props.visibleTabsStyle}
overflowRenderer={this.renderOverflow}
renderMode="scroll"
className={`${cssClasses.TABS_BAR}-overflow-list`}
visibleItemRenderer={this.renderTabItem as any}
onVisibleStateChange={(visibleMap)=>{
const visibleMapWithItemKey: Map<string, boolean> = new Map();
visibleMap.forEach((v, k )=>{
visibleMapWithItemKey.set(this._getItemKeyByBarItemKey(k), v);
});
this.props.onVisibleTabsChange?.(visibleMapWithItemKey);
}}
/>

);
};

Expand Down Expand Up @@ -322,7 +336,8 @@ class TabBar extends React.Component<TabBarProps, TabBarState> {

private _isActive = (key: string): boolean => key === this.props.activeKey;

private _getItemKey = (key: string): string => `${key}-bar`;
private _getBarItemKeyByItemKey = (key: string): string => `${key}-bar`;
private _getItemKeyByBarItemKey = (key: string): string => key.replace(/-bar$/, "");
}

export default TabBar;
13 changes: 12 additions & 1 deletion packages/semi-ui/tabs/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ class Tabs extends BaseComponent<TabsProps, TabsState> {
onTabClose: PropTypes.func,
preventScroll: PropTypes.bool,
more: PropTypes.oneOfType([PropTypes.number, PropTypes.object]),
arrowPosition: PropTypes.string,
renderArrow: PropTypes.func,
};
static __SemiComponentName__ = "Tabs";
static defaultProps: TabsProps = getDefaultPropsFromGlobalConfig(Tabs.__SemiComponentName__, {
Expand All @@ -68,7 +70,8 @@ class Tabs extends BaseComponent<TabsProps, TabsState> {
tabPosition: 'top',
type: 'line',
onTabClose: () => undefined,
showRestInDropdown: true
showRestInDropdown: true,
arrowPosition: "both",
});

contentRef: RefObject<HTMLDivElement>;
Expand Down Expand Up @@ -258,6 +261,10 @@ class Tabs extends BaseComponent<TabsProps, TabsState> {
tabPosition,
type,
more,
onVisibleTabsChange,
visibleTabsStyle,
arrowPosition,
renderArrow,
...restProps
} = this.props;
const { panes, activeKey } = this.state;
Expand Down Expand Up @@ -286,6 +293,10 @@ class Tabs extends BaseComponent<TabsProps, TabsState> {
deleteTabItem: this.deleteTabItem,
handleKeyDown: this.foundation.handleKeyDown,
more,
onVisibleTabsChange,
visibleTabsStyle,
arrowPosition,
renderArrow
} as TabBarProps;

const tabBar = renderTabBar ? renderTabBar(tabBarProps, TabBar) : <TabBar {...tabBarProps} />;
Expand Down
16 changes: 13 additions & 3 deletions packages/semi-ui/tabs/interface.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React, { ComponentType, CSSProperties, MouseEvent, ReactNode } from 'react';
import { Motion } from '../_base/base';
import TabBar from './TabBar';
import TabBar, { OverflowItem } from './TabBar';
import { DropdownProps } from "../dropdown";
import { OverflowListProps } from "../overflowList";

export type TabType = 'line' | 'card' | 'button';
export type TabSize = 'small' | 'medium' | 'large';
Expand Down Expand Up @@ -40,7 +41,11 @@ export interface TabsProps {
type?: TabType;
onTabClose?: (tabKey: string) => void;
preventScroll?: boolean;
more?: number | { count: number; render?: () => ReactNode; dropdownProps?: DropdownProps }
more?: number | { count: number; render?: () => ReactNode; dropdownProps?: DropdownProps };
onVisibleTabsChange?: TabBarProps["onVisibleTabsChange"];
visibleTabsStyle?: TabBarProps['visibleTabsStyle'];
arrowPosition?: TabBarProps['arrowPosition'];
renderArrow?: TabBarProps['renderArrow']
}

export interface TabBarProps {
Expand All @@ -60,7 +65,12 @@ export interface TabBarProps {
closable?: boolean;
deleteTabItem?: (tabKey: string, event: MouseEvent<Element>) => void;
handleKeyDown?: (event: React.KeyboardEvent, itemKey: string, closable: boolean) => void;
more?: TabsProps['more']
more?: TabsProps['more'];
onVisibleTabsChange?: (visibleState: Map<string, boolean>) => void;
visibleTabsStyle?: CSSProperties;
arrowPosition?: OverflowListProps['overflowRenderDirection'];
renderArrow?: (items: OverflowItem[], pos: "start"|"end", handleArrowClick: () => void) => ReactNode

}

export interface TabPaneProps {
Expand Down

0 comments on commit 21c7597

Please sign in to comment.