|
1 | 1 | import * as React from 'react';
|
2 | 2 | import { useState } from 'react';
|
| 3 | +import Logger from 'mo/common/logger'; |
3 | 4 | import RcCollapse, { Panel as CollapsePanel } from 'rc-collapse';
|
4 | 5 | import { Toolbar } from 'mo/components/toolbar';
|
5 | 6 | import { Icon } from 'mo/components/icon';
|
6 |
| -import { |
7 |
| - prefixClaName, |
8 |
| - classNames, |
9 |
| - getBEMElement, |
10 |
| - getBEMModifier, |
11 |
| -} from 'mo/common/className'; |
| 7 | +import { IActionBarItemProps } from 'mo/components/actionBar'; |
| 8 | +import { prefixClaName, classNames, getBEMElement } from 'mo/common/className'; |
12 | 9 |
|
13 |
| -export interface IExpandProps { |
14 |
| - isActive?: boolean; |
15 |
| -} |
16 |
| -export interface ICollapseProps<T = any> { |
17 |
| - data?: T; |
| 10 | +type RenderFunctionProps = (data: DataBaseProps) => React.ReactNode; |
| 11 | + |
| 12 | +interface DataBaseProps { |
| 13 | + id: React.Key; |
| 14 | + name: string; |
18 | 15 | className?: string;
|
19 |
| - onCollapseChange?: (keys) => void; |
20 |
| - onCollapseToolbar?: (item) => void; |
| 16 | + hidden?: boolean; |
| 17 | + toolbar?: IActionBarItemProps[]; |
| 18 | + renderPanel?: RenderFunctionProps; |
| 19 | + |
| 20 | + [key: string]: any; |
21 | 21 | }
|
22 | 22 |
|
23 |
| -interface IState { |
24 |
| - activePanelKeys: React.Key[]; |
| 23 | +export interface ICollapseProps { |
| 24 | + data?: Partial<DataBaseProps>[]; |
| 25 | + className?: string; |
| 26 | + onCollapseChange?: (keys: React.Key[]) => void; |
| 27 | + onToolbarClick?: ( |
| 28 | + item: IActionBarItemProps, |
| 29 | + parentPanel: DataBaseProps |
| 30 | + ) => void; |
25 | 31 | }
|
| 32 | + |
26 | 33 | const defaultCollapseClassName = prefixClaName('collapse');
|
27 |
| -export const contentPaddingClassName = getBEMModifier( |
28 |
| - getBEMElement(defaultCollapseClassName, 'content'), |
29 |
| - 'padding' |
| 34 | +const toolbarCollapseClassName = getBEMElement( |
| 35 | + defaultCollapseClassName, |
| 36 | + 'toolbar' |
30 | 37 | );
|
31 | 38 |
|
32 |
| -const initState = { |
33 |
| - activePanelKeys: [], |
34 |
| -}; |
35 |
| - |
36 | 39 | export function Collapse(props: ICollapseProps) {
|
37 |
| - const [state, setState] = useState<IState>(initState); |
| 40 | + const [activePanelKeys, setActivePanelKeys] = useState<React.Key[]>([]); |
| 41 | + |
38 | 42 | const {
|
39 | 43 | className,
|
40 | 44 | data = [],
|
41 | 45 | onCollapseChange,
|
42 |
| - onCollapseToolbar, |
| 46 | + onToolbarClick, |
43 | 47 | ...restProps
|
44 | 48 | } = props;
|
45 |
| - const onChangeCallback = (key: React.Key[]) => { |
| 49 | + |
| 50 | + const handleChangeCallback = (key: React.Key[]) => { |
46 | 51 | onCollapseChange?.(key);
|
47 |
| - setState((state: IState) => ({ ...state, activePanelKeys: key })); |
| 52 | + setActivePanelKeys(key || []); |
48 | 53 | };
|
49 |
| - const onClick = (e, item) => { |
| 54 | + |
| 55 | + const handleToolbarClick = ( |
| 56 | + e: React.MouseEvent, |
| 57 | + item: IActionBarItemProps, |
| 58 | + panel: DataBaseProps |
| 59 | + ) => { |
50 | 60 | e.stopPropagation();
|
51 |
| - onCollapseToolbar?.(item); |
52 |
| - console.log('onClick:', e, item); |
| 61 | + onToolbarClick?.(item, panel); |
53 | 62 | };
|
54 |
| - const render = (render) => { |
| 63 | + |
| 64 | + const renderPanels = ( |
| 65 | + data: DataBaseProps, |
| 66 | + render?: RenderFunctionProps |
| 67 | + ) => { |
55 | 68 | if (render) {
|
56 |
| - return render(); |
57 |
| - } else { |
58 |
| - return ( |
59 |
| - <span className={contentPaddingClassName}> |
60 |
| - Cannot provide... |
61 |
| - </span> |
62 |
| - ); |
| 69 | + return render(data); |
63 | 70 | }
|
| 71 | + return null; |
64 | 72 | };
|
65 |
| - const { activePanelKeys } = state; |
| 73 | + |
| 74 | + const filterData = data.filter((panel) => panel.id) as DataBaseProps[]; |
| 75 | + if (filterData.length < data.length) { |
| 76 | + Logger.warn(new SyntaxError('collapse data must have id')); |
| 77 | + } |
| 78 | + |
66 | 79 | return (
|
67 | 80 | <div className={classNames(defaultCollapseClassName, className)}>
|
68 | 81 | <RcCollapse
|
69 |
| - {...restProps} |
70 |
| - onChange={(activeKeys: React.Key[]) => { |
71 |
| - onChangeCallback(activeKeys); |
72 |
| - }} |
73 |
| - expandIcon={({ isActive }: IExpandProps) => ( |
| 82 | + onChange={handleChangeCallback} |
| 83 | + expandIcon={({ isActive }: { isActive: boolean }) => ( |
74 | 84 | <Icon type={isActive ? 'chevron-down' : 'chevron-right'} />
|
75 | 85 | )}
|
| 86 | + {...restProps} |
76 | 87 | >
|
77 |
| - {data.map((panel) => ( |
78 |
| - <CollapsePanel |
79 |
| - key={panel.id} |
80 |
| - header={panel.name} |
81 |
| - className={panel.className} |
82 |
| - extra={ |
83 |
| - activePanelKeys?.includes(panel.id) && ( |
84 |
| - <Toolbar |
85 |
| - key={panel.id} |
86 |
| - data={panel.toolbar} |
87 |
| - onClick={onClick} |
88 |
| - /> |
89 |
| - ) |
90 |
| - } |
91 |
| - > |
92 |
| - {render(panel.renderPanel)} |
93 |
| - </CollapsePanel> |
94 |
| - ))} |
| 88 | + {filterData |
| 89 | + .filter((p) => !p.hidden) |
| 90 | + .map((panel) => { |
| 91 | + const content = renderPanels(panel, panel.renderPanel); |
| 92 | + return ( |
| 93 | + <CollapsePanel |
| 94 | + tabIndex={-1} |
| 95 | + key={panel.id} |
| 96 | + panelKey={panel.id} |
| 97 | + header={panel.name} |
| 98 | + className={classNames( |
| 99 | + panel.className, |
| 100 | + content === null && 'empty' |
| 101 | + )} |
| 102 | + extra={ |
| 103 | + activePanelKeys.includes(panel.id) && ( |
| 104 | + <Toolbar |
| 105 | + className={toolbarCollapseClassName} |
| 106 | + key={panel.id} |
| 107 | + data={panel.toolbar || []} |
| 108 | + onClick={(e, item) => |
| 109 | + handleToolbarClick( |
| 110 | + e, |
| 111 | + item, |
| 112 | + panel |
| 113 | + ) |
| 114 | + } |
| 115 | + /> |
| 116 | + ) |
| 117 | + } |
| 118 | + > |
| 119 | + {content} |
| 120 | + </CollapsePanel> |
| 121 | + ); |
| 122 | + })} |
95 | 123 | </RcCollapse>
|
96 | 124 | </div>
|
97 | 125 | );
|
|
0 commit comments