diff --git a/src/hooks/useItems.tsx b/src/hooks/useItems.tsx index 4b937a9..1ee76f7 100644 --- a/src/hooks/useItems.tsx +++ b/src/hooks/useItems.tsx @@ -2,6 +2,7 @@ import toArray from '@rc-component/util/lib/Children/toArray'; import React from 'react'; import type { CollapsePanelProps, CollapseProps, ItemType } from '../interface'; import CollapsePanel from '../Panel'; +import clsx from 'clsx'; type Props = Pick< CollapsePanelProps, @@ -11,6 +12,30 @@ type Props = Pick< activeKey: React.Key[]; }; +function mergeSemantic(src: T, tgt: T, mergeFn: (a: any, b: any) => any) { + if (!src || !tgt) { + return src || tgt; + } + + const keys = Array.from(new Set([...Object.keys(src), ...Object.keys(tgt)])); + const result = {}; + keys.forEach((key) => { + result[key] = mergeFn(src[key], tgt[key]); + }); + return result; +} + +function mergeSemanticClassNames(src: T, tgt: T) { + return mergeSemantic(src, tgt, (a: string, b: string) => clsx(a, b)); +} + +function mergeSemanticStyles(src: T, tgt: T) { + return mergeSemantic(src, tgt, (a: React.CSSProperties, b: React.CSSProperties) => ({ + ...a, + ...b, + })); +} + const convertItemsToNodes = (items: ItemType[], props: Props) => { const { prefixCls, @@ -22,7 +47,7 @@ const convertItemsToNodes = (items: ItemType[], props: Props) => { openMotion, expandIcon, classNames: collapseClassNames, - styles, + styles: collapseStyles, } = props; return items.map((item, index) => { @@ -33,6 +58,8 @@ const convertItemsToNodes = (items: ItemType[], props: Props) => { collapsible: rawCollapsible, onItemClick: rawOnItemClick, destroyOnHidden: rawDestroyOnHidden, + classNames, + styles, ...restProps } = item; @@ -60,8 +87,8 @@ const convertItemsToNodes = (items: ItemType[], props: Props) => { return ( { expect(titleElement.style.color).toBe('green'); expect(iconElement.style.color).toBe('yellow'); }); + + it('should support styles and classNames in panel', () => { + const customStyles = { + header: { color: 'red' }, + body: { color: 'blue' }, + title: { color: 'green' }, + icon: { color: 'yellow' }, + }; + const customClassnames = { + header: 'custom-header', + body: 'custom-body', + }; + + const { container } = render( + , + ); + const headerElement = container.querySelector('.rc-collapse-header') as HTMLElement; + const bodyElement = container.querySelector('.rc-collapse-body') as HTMLElement; + const titleElement = container.querySelector('.rc-collapse-title') as HTMLElement; + const iconElement = container.querySelector('.rc-collapse-expand-icon') as HTMLElement; + + // check classNames + expect(headerElement.classList).toContain('custom-header'); + expect(headerElement.classList).toContain('custom-header-panel'); + expect(bodyElement.classList).toContain('custom-body'); + expect(bodyElement.classList).toContain('custom-body-panel'); + + // check styles + expect(headerElement).toHaveStyle({ color: 'blue', fontSize: '20px' }); + expect(bodyElement).toHaveStyle({ color: 'blue', fontSize: '20px' }); + expect(titleElement).toHaveStyle({ color: 'red' }); + expect(iconElement).toHaveStyle({ color: 'blue' }); + }); }); });