|
| 1 | +import toArray from 'rc-util/lib/Children/toArray'; |
| 2 | +import React from 'react'; |
| 3 | +import type { CollapsePanelProps, CollapseProps, ItemType } from '../interface'; |
| 4 | +import CollapsePanel from '../Panel'; |
| 5 | + |
| 6 | +type Props = Pick<CollapsePanelProps, 'prefixCls' | 'onItemClick' | 'openMotion' | 'expandIcon'> & |
| 7 | + Pick<CollapseProps, 'accordion' | 'collapsible' | 'destroyInactivePanel'> & { |
| 8 | + activeKey: React.Key[]; |
| 9 | + }; |
| 10 | + |
| 11 | +const convertItemsToNodes = (items: ItemType[], props: Props) => { |
| 12 | + const { |
| 13 | + prefixCls, |
| 14 | + accordion, |
| 15 | + collapsible, |
| 16 | + destroyInactivePanel, |
| 17 | + onItemClick, |
| 18 | + activeKey, |
| 19 | + openMotion, |
| 20 | + expandIcon, |
| 21 | + } = props; |
| 22 | + |
| 23 | + return items.map((item, index) => { |
| 24 | + const { |
| 25 | + children, |
| 26 | + label, |
| 27 | + key: rawKey, |
| 28 | + collapsible: rawCollapsible, |
| 29 | + onItemClick: rawOnItemClick, |
| 30 | + destroyInactivePanel: rawDestroyInactivePanel, |
| 31 | + ...restProps |
| 32 | + } = item; |
| 33 | + |
| 34 | + // You may be puzzled why you want to convert them all into strings, me too. |
| 35 | + // Maybe: https://github.com/react-component/collapse/blob/aac303a8b6ff30e35060b4f8fecde6f4556fcbe2/src/Collapse.tsx#L15 |
| 36 | + const key = String(rawKey ?? index); |
| 37 | + const mergeCollapsible = rawCollapsible ?? collapsible; |
| 38 | + const mergeDestroyInactivePanel = rawDestroyInactivePanel ?? destroyInactivePanel; |
| 39 | + |
| 40 | + const handleItemClick = (value: React.Key) => { |
| 41 | + if (mergeCollapsible === 'disabled') return; |
| 42 | + onItemClick(value); |
| 43 | + rawOnItemClick?.(value); |
| 44 | + }; |
| 45 | + |
| 46 | + let isActive = false; |
| 47 | + if (accordion) { |
| 48 | + isActive = activeKey[0] === key; |
| 49 | + } else { |
| 50 | + isActive = activeKey.indexOf(key) > -1; |
| 51 | + } |
| 52 | + |
| 53 | + return ( |
| 54 | + <CollapsePanel |
| 55 | + {...restProps} |
| 56 | + prefixCls={prefixCls} |
| 57 | + key={key} |
| 58 | + panelKey={key} |
| 59 | + isActive={isActive} |
| 60 | + accordion={accordion} |
| 61 | + openMotion={openMotion} |
| 62 | + expandIcon={expandIcon} |
| 63 | + header={label} |
| 64 | + collapsible={mergeCollapsible} |
| 65 | + onItemClick={handleItemClick} |
| 66 | + destroyInactivePanel={mergeDestroyInactivePanel} |
| 67 | + > |
| 68 | + {children} |
| 69 | + </CollapsePanel> |
| 70 | + ); |
| 71 | + }); |
| 72 | +}; |
| 73 | + |
| 74 | +/** |
| 75 | + * @deprecated The next major version will be removed |
| 76 | + */ |
| 77 | +const getNewChild = ( |
| 78 | + child: React.ReactElement<CollapsePanelProps>, |
| 79 | + index: number, |
| 80 | + props: Props, |
| 81 | +) => { |
| 82 | + if (!child) return null; |
| 83 | + |
| 84 | + const { |
| 85 | + prefixCls, |
| 86 | + accordion, |
| 87 | + collapsible, |
| 88 | + destroyInactivePanel, |
| 89 | + onItemClick, |
| 90 | + activeKey, |
| 91 | + openMotion, |
| 92 | + expandIcon, |
| 93 | + } = props; |
| 94 | + |
| 95 | + const key = child.key || String(index); |
| 96 | + |
| 97 | + const { |
| 98 | + header, |
| 99 | + headerClass, |
| 100 | + destroyInactivePanel: childDestroyInactivePanel, |
| 101 | + collapsible: childCollapsible, |
| 102 | + onItemClick: childOnItemClick, |
| 103 | + } = child.props; |
| 104 | + |
| 105 | + let isActive = false; |
| 106 | + if (accordion) { |
| 107 | + isActive = activeKey[0] === key; |
| 108 | + } else { |
| 109 | + isActive = activeKey.indexOf(key) > -1; |
| 110 | + } |
| 111 | + |
| 112 | + const mergeCollapsible = childCollapsible ?? collapsible; |
| 113 | + |
| 114 | + const handleItemClick = (value: React.Key) => { |
| 115 | + if (mergeCollapsible === 'disabled') return; |
| 116 | + onItemClick(value); |
| 117 | + childOnItemClick?.(value); |
| 118 | + }; |
| 119 | + |
| 120 | + const childProps = { |
| 121 | + key, |
| 122 | + panelKey: key, |
| 123 | + header, |
| 124 | + headerClass, |
| 125 | + isActive, |
| 126 | + prefixCls, |
| 127 | + destroyInactivePanel: childDestroyInactivePanel ?? destroyInactivePanel, |
| 128 | + openMotion, |
| 129 | + accordion, |
| 130 | + children: child.props.children, |
| 131 | + onItemClick: handleItemClick, |
| 132 | + expandIcon, |
| 133 | + collapsible: mergeCollapsible, |
| 134 | + }; |
| 135 | + |
| 136 | + // https://github.com/ant-design/ant-design/issues/20479 |
| 137 | + if (typeof child.type === 'string') { |
| 138 | + return child; |
| 139 | + } |
| 140 | + |
| 141 | + Object.keys(childProps).forEach((propName) => { |
| 142 | + if (typeof childProps[propName] === 'undefined') { |
| 143 | + delete childProps[propName]; |
| 144 | + } |
| 145 | + }); |
| 146 | + |
| 147 | + return React.cloneElement(child, childProps); |
| 148 | +}; |
| 149 | + |
| 150 | +function useItems( |
| 151 | + items?: ItemType[], |
| 152 | + rawChildren?: React.ReactNode, |
| 153 | + props?: Props, |
| 154 | +): React.ReactElement<CollapsePanelProps>[] { |
| 155 | + if (Array.isArray(items)) { |
| 156 | + return convertItemsToNodes(items, props); |
| 157 | + } |
| 158 | + |
| 159 | + return toArray(rawChildren).map((child, index) => getNewChild(child, index, props)); |
| 160 | +} |
| 161 | + |
| 162 | +export default useItems; |
0 commit comments