From 6ec65a4d6d8187391f7c46568f1889dfddeefe16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Vall=C3=A9?= <31360150+ffffffelix@users.noreply.github.com> Date: Thu, 16 Nov 2023 11:14:54 +0100 Subject: [PATCH] MOON-351: Add highlight state for TreeView and MenuItem (#401) --- src/components/Menu/Menu.stories.tsx | 3 +- src/components/Menu/MenuItem.scss | 6 + src/components/Menu/MenuItem.tsx | 4 +- src/components/Menu/MenuItem.types.ts | 5 + .../TreeView/ControlledTreeView.tsx | 13 +- .../TreeView/ControlledTreeView.types.ts | 70 ------ src/components/TreeView/TreeView.scss | 9 + src/components/TreeView/TreeView.spec.js | 194 ----------------- src/components/TreeView/TreeView.spec.tsx | 200 ++++++++++++++++++ src/components/TreeView/TreeView.stories.jsx | 4 + src/components/TreeView/TreeView.tsx | 6 +- src/components/TreeView/TreeView.types.ts | 55 +++-- .../TreeView/UncontrolledTreeView.tsx | 19 +- .../TreeView/UncontrolledTreeView.types.ts | 59 ------ src/icons/utils/toIconComponent.tsx | 2 +- 15 files changed, 292 insertions(+), 357 deletions(-) delete mode 100644 src/components/TreeView/ControlledTreeView.types.ts delete mode 100644 src/components/TreeView/TreeView.spec.js create mode 100644 src/components/TreeView/TreeView.spec.tsx delete mode 100644 src/components/TreeView/UncontrolledTreeView.types.ts diff --git a/src/components/Menu/Menu.stories.tsx b/src/components/Menu/Menu.stories.tsx index 4968de9b..acaa4640 100644 --- a/src/components/Menu/Menu.stories.tsx +++ b/src/components/Menu/Menu.stories.tsx @@ -31,7 +31,8 @@ export const Default: Story = args => ( - + + ); Default.args = { diff --git a/src/components/Menu/MenuItem.scss b/src/components/Menu/MenuItem.scss index d650341f..0c4bc53a 100644 --- a/src/components/Menu/MenuItem.scss +++ b/src/components/Menu/MenuItem.scss @@ -26,6 +26,12 @@ background-color: var(--color-accent); } + &.moonstone-highlighted { + color: var(--color-light); + + background-color: var(--color-gray60); + } + &:focus { outline: none; box-shadow: inset 0 0 0 2px var(--color-accent); diff --git a/src/components/Menu/MenuItem.tsx b/src/components/Menu/MenuItem.tsx index 0c1d5fd9..cc669f0f 100644 --- a/src/components/Menu/MenuItem.tsx +++ b/src/components/Menu/MenuItem.tsx @@ -7,8 +7,9 @@ import {MenuItemProps, MenuItemVariants} from './MenuItem.types'; export const MenuItem: React.FC = ({ variant = MenuItemVariants.Default, isHover, - isSelected, + isSelected = false, isDisabled = false, + isHighlighted = false, iconStart = null, iconSize = null, iconEnd = null, @@ -27,6 +28,7 @@ export const MenuItem: React.FC = ({ 'moonstone-hover': isHover, 'moonstone-selected': isSelected, 'moonstone-disabled': isDisabled, + 'moonstone-highlighted': isHighlighted && !isSelected, 'moonstone-title': variant === MenuItemVariants.Title }, image && 'moonstone-menuItem-image', diff --git a/src/components/Menu/MenuItem.types.ts b/src/components/Menu/MenuItem.types.ts index fb84812a..584174b2 100644 --- a/src/components/Menu/MenuItem.types.ts +++ b/src/components/Menu/MenuItem.types.ts @@ -29,6 +29,11 @@ export type MenuItemProps = { */ isDisabled?: boolean, + /** + * Is item highlighted, cannot be selected at the same time + */ + isHighlighted?: boolean, + /** * MenuItem label */ diff --git a/src/components/TreeView/ControlledTreeView.tsx b/src/components/TreeView/ControlledTreeView.tsx index a841cc48..8f2aba6f 100644 --- a/src/components/TreeView/ControlledTreeView.tsx +++ b/src/components/TreeView/ControlledTreeView.tsx @@ -1,8 +1,7 @@ import React from 'react'; import clsx from 'clsx'; import './TreeView.scss'; -import {ControlledTreeViewProps} from './ControlledTreeView.types'; -import {TreeViewData} from './TreeView.types'; +import type {ControlledTreeViewProps, TreeViewData} from './TreeView.types'; import {Loading, ChevronDown, ChevronRight, CheckboxChecked, CheckboxUnchecked} from '~/icons'; import {Typography} from '~/components/Typography'; @@ -33,6 +32,7 @@ const ControlledTreeViewForwardRef: React.ForwardRefRenderFunction undefined, onDoubleClickItem = () => undefined, @@ -55,6 +55,7 @@ const ControlledTreeViewForwardRef: React.ForwardRefRenderFunction {showCheckbox ? - (isSelected ? : ) : + (isSelected ? : ) : (displayIcon(node.iconStart, 'small', 'moonstone-treeView_itemIconStart', parentHasIconStart))} void; - - /** - * Trigger on opening node - */ - onCloseItem?: (node: TreeViewData, e?: React.MouseEvent) => void; - - /** - * Trigger by clicking on node - */ - onClickItem?: (node: TreeViewData, e?: React.MouseEvent, toggleNode?: (e: React.MouseEvent) => void) => void; - - /** - * Trigger by double clicking on node - */ - onDoubleClickItem?: (node: TreeViewData, e?: React.MouseEvent) => void; - - /** - * Trigger by right clicking on node - */ - onContextMenuItem?: (node: TreeViewData, e?: React.MouseEvent) => void; - - /** - * Reverse color useful for context with dark background - */ - isReversed?: boolean; - - /** - * Component used for the list (ul) - */ - component?: string; - - /** - * Component used for every item (li) - */ - itemComponent?: string; - - /** - * TreeView row sizes - */ - size?: 'small' | 'default'; - -}; - diff --git a/src/components/TreeView/TreeView.scss b/src/components/TreeView/TreeView.scss index d206621e..69b64ae7 100644 --- a/src/components/TreeView/TreeView.scss +++ b/src/components/TreeView/TreeView.scss @@ -3,11 +3,13 @@ --treeItem-color: inherit; --treeItem-color_hover: var(--color-dark); --treeItem-color_selected: var(--color-light); + --treeItem-color_highlighted: var(--color-light); --treeItem-color_selected_hover: var(--color-light); --treeItem-background: inherit; --treeItem-background_hover: var(--color-gray_light40); --treeItem-background_selected: var(--color-accent); --treeItem-background_selected_hover: var(--color-accent); + --treeItem-background_highlighted: var(--color-gray60); } .moonstone-treeView_item { @@ -44,11 +46,18 @@ } } + &.moonstone-highlighted { + color: var(--treeItem-color_highlighted); + + background-color: var(--treeItem-background_highlighted); + } + // Theme reversed &.moonstone-reversed { --treeItem-color: var(--color-gray_light); --treeItem-color_hover: var(--color-light); --treeItem-background_hover: var(--color-gray40); + --treeItem-background_highlighted: var(--color-gray_light40); } &.moonstone-disabled { diff --git a/src/components/TreeView/TreeView.spec.js b/src/components/TreeView/TreeView.spec.js deleted file mode 100644 index 922260dd..00000000 --- a/src/components/TreeView/TreeView.spec.js +++ /dev/null @@ -1,194 +0,0 @@ -import React from 'react'; -import {shallow} from 'component-test-utils-react'; -import {ControlledTreeView} from './ControlledTreeView'; -import {UncontrolledTreeView} from './UncontrolledTreeView'; -import {TreeView} from './TreeView'; -import {Love, Cloud} from '~/icons'; -import {toIconComponent} from '~/icons'; - -const tree = [ - { - id: 'A', - label: 'A level1', - iconStart: toIconComponent('http://www.google.com/s2/favicons?domain=www.jahia.com'), - iconEnd: , - children: [ - {id: 'A1', label: 'A-1 level2', iconStart: } - ] - } -]; - -describe('TreeView', () => { - it('should not display TreeView when data is not an array', () => { - const wrapper = shallow(); - expect(wrapper.html()).toEqual(''); - }); - - it('should not display TreeView when data is empty', () => { - const wrapper = shallow(); - expect(wrapper.html()).toEqual(''); - }); - - it('should display TreeView', () => { - const wrapper = shallow(); - expect(wrapper.html()); - }); - - it('should not display icon for items without children', () => { - const wrapper = shallow(); - expect(wrapper.querySelector('.moonstone-treeView_itemToggle')).toHaveProperty('nodeNotExistError'); - }); - - it('should open node set in openItems', () => { - const wrapper = shallow(); - - expect(wrapper.html()).toContain('A-1 level2'); - }); - - it('should display ChevronRight when node is closed', () => { - const wrapper = shallow(); - - expect(wrapper.html()).toContain('ChevronRight'); - }); - - it('should display ChevronDown when node is opened', () => { - const wrapper = shallow(); - - expect(wrapper.html()).toContain('ChevronDown'); - }); - - it('should open a node by clicking on arrow icon', () => { - const wrapper = shallow( - , {mocks: {ControlledTreeView: true}} - ); - - wrapper.querySelector('.moonstone-treeView_itemToggle').dispatchEvent('click'); - expect(wrapper.html()).toContain('A-1 level2'); - }); - - it('should open a node by clicking on an item when no onClickItem is provided', () => { - const wrapper = shallow( - , {mocks: {ControlledTreeView: true}} - ); - - wrapper.querySelector('.moonstone-treeView_itemLabel').dispatchEvent('click'); - expect(wrapper.html()).toContain('A-1 level2'); - }); - - it('should display icon provide by moonstone', () => { - const wrapper = shallow( - - ); - - expect(wrapper.html()).toContain('SvgLove'); - }); - - it('should display end icon of treeView_item', () => { - const wrapper = shallow( - - ); - - expect(wrapper.html()).toContain('SvgCloud'); - }); - - it('should display loading icon if node is loading', () => { - const wrapper = shallow( - - ); - - expect(wrapper.html()).toContain('moonstone-icon_isLoading'); - }); - - it('should not display iconEnd if node is loading', () => { - const wrapper = shallow( - - ); - - expect(wrapper.html()).not.toContain('fakeURL'); - }); - - it('should add specific class if TreeView is reversed', () => { - const wrapper = shallow( - - ); - - expect(wrapper.html()).toContain('reversed'); - }); - - it('should add specific class if a node is selected', () => { - const wrapper = shallow( - - ); - - expect(wrapper.html()).toContain('selected'); - }); - - it('should not throw error when there is no onDoubleClick defined', () => { - const wrapper = shallow( - - ); - - // No error should occur when there is no onDoubleClick defined - wrapper.querySelector('.moonstone-treeView_itemLabel').dispatchEvent('doubleClick'); - }); - - it('should call onDoubleClick when double click on an item', () => { - const clickHandler = jest.fn(); - const wrapper = shallow( - - ); - - wrapper.querySelector('.moonstone-treeView_itemLabel').dispatchEvent('doubleClick'); - - expect(clickHandler).toHaveBeenCalled(); - }); - - it('should not throw error when there is no onClick defined', () => { - const wrapper = shallow( - - ); - - // No error should occur when there is no onClick defined - wrapper.querySelector('.moonstone-treeView_itemLabel').dispatchEvent('click'); - }); - - it('should call onClick when clicking on label', () => { - const clickHandler = jest.fn(); - const wrapper = shallow( - - ); - wrapper.querySelector('.moonstone-treeView_itemLabel').dispatchEvent('click'); - expect(clickHandler).toHaveBeenCalled(); - }); - - it('should call onClickToOpen when the node opens', () => { - const clickHandler = jest.fn(); - const wrapper = shallow( - - ); - - wrapper.querySelector('.moonstone-treeView_itemToggle').dispatchEvent('click'); - - expect(clickHandler).toHaveBeenCalled(); - }); - - it('should not call onClickToOpen when the node closes', () => { - const clickHandler = jest.fn(); - const openedItems = ['A']; - - const wrapper = shallow( - - ); - - wrapper.querySelector('.moonstone-treeView_itemToggle').dispatchEvent('click'); - - expect(clickHandler).not.toHaveBeenCalled(); - }); - - it('should add extra attribute', () => { - const wrapper = shallow( - - ); - expect(wrapper.html()).toContain('data-custom="test"'); - }); -}); diff --git a/src/components/TreeView/TreeView.spec.tsx b/src/components/TreeView/TreeView.spec.tsx new file mode 100644 index 00000000..73b02a0d --- /dev/null +++ b/src/components/TreeView/TreeView.spec.tsx @@ -0,0 +1,200 @@ +import React from 'react'; +import {render, screen} from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +import {TreeView} from './TreeView'; +import {Love, Cloud} from '~/icons'; +import {toIconComponent} from '~/icons'; + +import type {TreeViewData} from './TreeView.types'; + +const tree: TreeViewData[] = [ + { + id: 'A', + label: 'A level1', + iconStart: toIconComponent('http://www.google.com/s2/favicons?domain=www.jahia.com'), + iconEnd: , + children: [ + {id: 'A1', label: 'A-1 level2', iconStart: } + ] + } +]; + +describe('TreeView', () => { + it('should not display TreeView when data is empty', () => { + render(); + expect(screen.queryByTestId('moonstone-treeView')).not.toBeInTheDocument(); + }); + + it('should display TreeView', () => { + render(); + expect(screen.getByRole('treeitem')).toBeInTheDocument(); + }); + + it('should not display chevron for items without children', () => { + const {container} = render(); + expect(container.querySelector('.moonstone-treeView_itemToggle')).not.toBeInTheDocument(); + }); + + it('should open node set in openItems', () => { + render(); + + expect(screen.getByRole('treeitem', {expanded: true})).toHaveTextContent('A level1'); + }); + + it('should display end icon of treeView_item', () => { + render(); + expect(screen.getByTestId('test-iconEnd')).toBeInTheDocument(); + }); + + it('should display start icon of treeView_item', () => { + render(}]}/>); + expect(screen.getByTestId('test-iconStart')).toBeInTheDocument(); + }); + + it('should display loading icon if node is loading', () => { + render(); + expect(screen.getAllByRole('treeitem')[0]).toHaveAttribute('aria-busy', 'true'); + }); + + it('should not display iconEnd if node is loading', () => { + render(); + expect(screen.queryByTestId('test-iconEnd')).not.toBeInTheDocument(); + }); + + it('should add specific class if TreeView is reversed', () => { + const {container} = render(); + expect(container.getElementsByClassName('reversed')).toBeTruthy(); + }); + + it('should select item set with selectedItems', () => { + render(); + expect(screen.getByRole('treeitem', {selected: true})).toHaveTextContent('A level1'); + }); + + it('should call onClick when clicking on an item', () => { + const clickHandler = jest.fn(); + render(); + userEvent.click(screen.getByText('A level1')); + + expect(clickHandler).toHaveBeenCalled(); + }); + + it('should not call onClick when clicking on an disabled item', () => { + const clickHandler = jest.fn(); + render(); + userEvent.click(screen.getByText('A level1')); + + expect(clickHandler).not.toHaveBeenCalled(); + }); + + it('should call onOpenItem when the node opens', () => { + const openHandler = jest.fn(); + const closeHandler = jest.fn(); + const {container} = render(); + + userEvent.click(container.querySelector('.moonstone-treeView_itemToggle')); + + expect(closeHandler).not.toHaveBeenCalled(); + expect(openHandler).toHaveBeenCalled(); + }); + + it('should call onCloseItem when the node closes', () => { + const openHandler = jest.fn(); + const closeHandler = jest.fn(); + const {container} = render(); + + userEvent.click(container.querySelector('.moonstone-treeView_itemToggle')); + + expect(closeHandler).toHaveBeenCalled(); + expect(openHandler).not.toHaveBeenCalled(); + }); + + it('should add extra attribute', () => { + render(); + expect(screen.getByTestId('moonstone-treeView')).toHaveAttribute('data-custom', 'test'); + }); + + it('should highlight the item set with highltedItem', () => { + render(); + + expect(screen.getByRole('treeitem', {current: 'page'})).toBeInTheDocument(); + }); + + it('should not highlight the item when it is already selected', () => { + render(); + + expect(screen.queryByRole('treeitem', {current: 'page'})).not.toBeInTheDocument(); + }); + + it('should display checkboxes when showCheckbox is set', () => { + render(); + + expect(screen.getByRole('checkbox')).toBeInTheDocument(); + }); + + it('should checked the checkbox when the item is selected with `showCheckbox`', () => { + render(); + + expect(screen.getByRole('treeitem', {selected: true})).toContainElement(screen.getByRole('checkbox', {checked: true})); + }); +}); + +describe('Uncontrolled TreeView', () => { + it('should have all nodes closed by default (uncontrolled)', () => { + render(); + + expect(screen.queryAllByRole('treeitem', {expanded: true})).toHaveLength(0); + }); + + it('should open node set in defaultOpenedItems', () => { + render(); + + expect(screen.getByRole('treeitem', {expanded: true})).toHaveTextContent('A level1'); + }); + + it('should open a node by clicking on arrow icon when onClickItem function is provided', () => { + const clickHandler = jest.fn(); + const {container} = render(); + + userEvent.click(container.querySelector('.moonstone-treeView_itemToggle')); + + expect(screen.queryByRole('treeitem', {expanded: true})).toBeInTheDocument(); + }); + + it('should open a node by clicking on the item when no onClickItem function is provided', () => { + render(); + + userEvent.click(screen.getByText('A level1')); + + expect(screen.getByRole('treeitem', {expanded: true})).toBeInTheDocument(); + }); + + it('should close a node by clicking on arrow icon when onClickItem function is provided', () => { + const clickHandler = jest.fn(); + const {container} = render(); + + userEvent.click(container.querySelector('.moonstone-treeView_itemToggle')); + + expect(screen.queryByRole('treeitem', {expanded: true})).not.toBeInTheDocument(); + }); + + it('should close a node by clicking on the item when no onClickItem function is provided', () => { + render(); + + userEvent.click(screen.getByText('A level1')); + + expect(screen.queryByRole('treeitem', {expanded: true})).not.toBeInTheDocument(); + }); + + it('should call onCloseItem when the node closes', () => { + const openHandler = jest.fn(); + const closeHandler = jest.fn(); + const {container} = render(); + + userEvent.click(container.querySelector('.moonstone-treeView_itemToggle')); + + expect(closeHandler).toHaveBeenCalled(); + expect(openHandler).not.toHaveBeenCalled(); + }); +}); diff --git a/src/components/TreeView/TreeView.stories.jsx b/src/components/TreeView/TreeView.stories.jsx index bf82c181..69485e5d 100644 --- a/src/components/TreeView/TreeView.stories.jsx +++ b/src/components/TreeView/TreeView.stories.jsx @@ -54,6 +54,10 @@ export const Selection = (args, {globals: {theme}}) => { ); }; +export const Highlight = (args, {globals: {theme}}) => ( + +); + export const Controlled = (args, {globals: {theme}}) => { const [openedItems, setOpenedItems] = useState([]); const handleOpen = node => { diff --git a/src/components/TreeView/TreeView.tsx b/src/components/TreeView/TreeView.tsx index 4aebfa14..504a16a2 100644 --- a/src/components/TreeView/TreeView.tsx +++ b/src/components/TreeView/TreeView.tsx @@ -1,16 +1,16 @@ import React from 'react'; -import {TreeViewProps} from './TreeView.types'; +import type {TreeViewProps} from './TreeView.types'; import {UncontrolledTreeView} from './UncontrolledTreeView'; import {ControlledTreeView} from './ControlledTreeView'; -const TreeViewForwardRef: React.ForwardRefRenderFunction = ({openedItems, defaultOpenedItems, onOpenItem, onCloseItem, data, ...others}, ref) => { +const TreeViewForwardRef: React.ForwardRefRenderFunction = ({openedItems, defaultOpenedItems, data, onOpenItem, onCloseItem, ...others}, ref) => { // If no data render nothing if (!Array.isArray(data) || data.length < 1) { return null; } if (typeof openedItems === 'undefined') { - return ; + return ; } return ; diff --git a/src/components/TreeView/TreeView.types.ts b/src/components/TreeView/TreeView.types.ts index abf69172..bb3aaa3e 100644 --- a/src/components/TreeView/TreeView.types.ts +++ b/src/components/TreeView/TreeView.types.ts @@ -16,40 +16,28 @@ export type TreeViewData = { treeItemProps?: object; }; -export type TreeViewProps = { +type BaseTreeViewProps = { /** * Data to generate the tree */ data: TreeViewData[]; - /** - * Opened items ids. If set, component is controlled - */ - openedItems?: string[]; - /** - * Opened items ids by default, when uncontrolled - */ - defaultOpenedItems?: string[]; /** * Selected items' ids */ selectedItems?: string[]; /** - * Show checkbox for selected items - */ - showCheckbox?: boolean; - /** - * Trigger on opening node + * IDs of the highlighted items */ - onOpenItem?: (node: TreeViewData, e?: React.MouseEvent) => void; + highlightedItems?: string[]; /** - * Trigger on opening node + * Show checkbox for selected items */ - onCloseItem?: (node: TreeViewData, e?: React.MouseEvent) => void; + showCheckbox?: boolean; /** * Trigger by clicking on node. * In the parameters, access to the current node, event, and a method to toggle the node open/close is given. */ - onClickItem?: (node: TreeViewData, e?: React.MouseEvent) => void; + onClickItem?: (node: TreeViewData, e?: React.MouseEvent, toggleNode?: (e: React.MouseEvent) => void) => void; /** * Trigger by double clicking on node */ @@ -76,3 +64,34 @@ export type TreeViewProps = { size?: 'small' | 'default'; }; +export type TreeViewProps = BaseTreeViewProps & Partial; + +export type ControlledTreeViewProps = BaseTreeViewProps & { + /** + * Opened items ids. If set, component is controlled + */ + openedItems: string[]; + /** + * Trigger on opening node + */ + onOpenItem: (node: TreeViewData, e?: React.MouseEvent) => void; + /** + * Trigger on opening node + */ + onCloseItem: (node: TreeViewData, e?: React.MouseEvent) => void; +} + +export type UncontrolledTreeViewProps = BaseTreeViewProps & { + /** + * Opened items ids by default, when uncontrolled + */ + defaultOpenedItems?: string[]; + /** + * Trigger on opening node + */ + onOpenItem?: (node: TreeViewData, e?: React.MouseEvent) => void; + /** + * Trigger on opening node + */ + onCloseItem?: (node: TreeViewData, e?: React.MouseEvent) => void; +} diff --git a/src/components/TreeView/UncontrolledTreeView.tsx b/src/components/TreeView/UncontrolledTreeView.tsx index 85bf0fab..56efcfdc 100644 --- a/src/components/TreeView/UncontrolledTreeView.tsx +++ b/src/components/TreeView/UncontrolledTreeView.tsx @@ -1,20 +1,27 @@ import React, {useState} from 'react'; -import {UncontrolledTreeViewProps} from './UncontrolledTreeView.types'; -import {TreeViewData} from './TreeView.types'; +import type {UncontrolledTreeViewProps, TreeViewData} from './TreeView.types'; + import {ControlledTreeView} from './ControlledTreeView'; -const UncontrolledTreeViewForwardRef: React.ForwardRefRenderFunction = ({defaultOpenedItems = [], ...others}, ref) => { +const UncontrolledTreeViewForwardRef: React.ForwardRefRenderFunction = ({defaultOpenedItems = [], onCloseItem, onOpenItem, ...others}, ref) => { const [openedItems, setOpenedItems] = useState(defaultOpenedItems); - const onOpenItem = (node: TreeViewData) => { + const handleOpenItem = (node: TreeViewData) => { setOpenedItems(prevOpenedItems => [...prevOpenedItems, node.id]); + + if (typeof onOpenItem !== 'undefined') { + onOpenItem(node); + } }; - const onCloseItem = (node: TreeViewData) => { + const handleCloseItem = (node: TreeViewData) => { setOpenedItems(prevOpenedItems => prevOpenedItems.filter(item => item !== node.id)); + if (typeof onCloseItem !== 'undefined') { + onCloseItem(node); + } }; - return ; + return ; }; export const UncontrolledTreeView = React.forwardRef(UncontrolledTreeViewForwardRef); diff --git a/src/components/TreeView/UncontrolledTreeView.types.ts b/src/components/TreeView/UncontrolledTreeView.types.ts deleted file mode 100644 index 3dd59e75..00000000 --- a/src/components/TreeView/UncontrolledTreeView.types.ts +++ /dev/null @@ -1,59 +0,0 @@ -import {TreeViewData} from './TreeView.types'; - -export type UncontrolledTreeViewProps = { - /** - * Data to generate the tree - */ - data: TreeViewData[]; - - /** - * Opened items' ids - */ - defaultOpenedItems?: string[]; - - /** - * Selected items' ids - */ - selectedItems?: string[]; - - /** - * Show checkbox for selected items - */ - showCheckbox?: boolean; - - /** - * Trigger by clicking on node - */ - onClickItem?: (node: TreeViewData, e?: React.MouseEvent) => void; - - /** - * Trigger by double clicking on node - */ - onDoubleClickItem?: (node: TreeViewData, e?: React.MouseEvent) => void; - - /** - * Trigger by right clicking on node - */ - onContextMenuItem?: (node: TreeViewData, e?: React.MouseEvent) => void; - - /** - * Reverse color useful for context with dark background - */ - isReversed?: boolean; - - /** - * Component used for the list (ul) - */ - component?: string; - - /** - * Component used for every item (li) - */ - itemComponent?: string; - - /** - * TreeView row sizes - */ - size?: 'small' | 'default'; -}; - diff --git a/src/icons/utils/toIconComponent.tsx b/src/icons/utils/toIconComponent.tsx index f6122692..bc635494 100644 --- a/src/icons/utils/toIconComponent.tsx +++ b/src/icons/utils/toIconComponent.tsx @@ -44,7 +44,7 @@ export const toIconComponentFunction = (icon: string | ReactElement): FunctionCo return (props: PropsWithChildren) => ; }; -export const toIconComponent = (icon: string | ReactElement, props: SvgWrapperProps & Attributes) => { +export const toIconComponent = (icon: string | ReactElement, props?: SvgWrapperProps & Attributes) => { return React.createElement(toIconComponentFunction(icon), props); };