From 0ceff02640e7e79edfa5521e42aa17da8d24e47c Mon Sep 17 00:00:00 2001 From: mfrances Date: Thu, 8 Feb 2024 10:26:09 -0500 Subject: [PATCH] update composability based on PR review --- .../DualListSelector/DualListSelector.tsx | 6 +- .../DualListSelectorControlsWrapper.tsx | 2 +- .../DualListSelector/DualListSelectorList.tsx | 2 +- .../DualListSelectorListItem.tsx | 6 +- .../DualListSelectorListWrapper.tsx | 2 +- .../DualListSelector/DualListSelectorPane.tsx | 233 +++------------ .../DualListSelector/DualListSelectorTree.tsx | 30 +- .../DualListSelectorTreeItem.tsx | 14 +- .../DualListSelector.test.tsx.snap | 276 +----------------- 9 files changed, 80 insertions(+), 491 deletions(-) diff --git a/packages/react-core/src/next/components/DualListSelector/DualListSelector.tsx b/packages/react-core/src/next/components/DualListSelector/DualListSelector.tsx index 277ca9d6c22..355766b39b2 100644 --- a/packages/react-core/src/next/components/DualListSelector/DualListSelector.tsx +++ b/packages/react-core/src/next/components/DualListSelector/DualListSelector.tsx @@ -11,11 +11,11 @@ import { DualListSelectorContext } from './DualListSelectorContext'; export interface DualListSelectorProps { /** Additional classes applied to the dual list selector. */ className?: string; - /** Id of the dual list selector. */ + /** ID of the dual list selector. */ id?: string; - /** Flag indicating if the dual list selector uses trees instead of simple lists */ + /** Flag indicating if the dual list selector uses trees instead of simple lists. */ isTree?: boolean; - /** Content to be rendered in the dual list selector. Panes & controls will not be built dynamically when children are provided. */ + /** Content to be rendered in the dual list selector. */ children?: React.ReactNode; } diff --git a/packages/react-core/src/next/components/DualListSelector/DualListSelectorControlsWrapper.tsx b/packages/react-core/src/next/components/DualListSelector/DualListSelectorControlsWrapper.tsx index 0d58a25722b..66d69b0373a 100644 --- a/packages/react-core/src/next/components/DualListSelector/DualListSelectorControlsWrapper.tsx +++ b/packages/react-core/src/next/components/DualListSelector/DualListSelectorControlsWrapper.tsx @@ -6,7 +6,7 @@ import { handleArrows } from '../../../helpers'; /** Acts as the container for the DualListSelectorControl sub-components. */ export interface DualListSelectorControlsWrapperProps extends React.HTMLProps { - /** Anything that can be rendered inside of the wrapper. */ + /** Content to be rendered inside of the controls wrapper. */ children?: React.ReactNode; /** Additional classes added to the wrapper. */ className?: string; diff --git a/packages/react-core/src/next/components/DualListSelector/DualListSelectorList.tsx b/packages/react-core/src/next/components/DualListSelector/DualListSelectorList.tsx index cc0224eef1f..bd565a36b07 100644 --- a/packages/react-core/src/next/components/DualListSelector/DualListSelectorList.tsx +++ b/packages/react-core/src/next/components/DualListSelector/DualListSelectorList.tsx @@ -7,7 +7,7 @@ import { DualListSelectorListContext } from './DualListSelectorContext'; /** Acts as the container for DualListSelectorListItem sub-components. */ export interface DualListSelectorListProps extends React.HTMLProps { - /** Content rendered inside the dual list selector list */ + /** Content rendered inside the dual list selector list. */ children?: React.ReactNode; } diff --git a/packages/react-core/src/next/components/DualListSelector/DualListSelectorListItem.tsx b/packages/react-core/src/next/components/DualListSelector/DualListSelectorListItem.tsx index 91dd7ff0eb7..b52d2d85c2a 100644 --- a/packages/react-core/src/next/components/DualListSelector/DualListSelectorListItem.tsx +++ b/packages/react-core/src/next/components/DualListSelector/DualListSelectorListItem.tsx @@ -25,11 +25,11 @@ export interface DualListSelectorListItemProps extends React.HTMLProps; - /** Flag indicating this item is draggable for reordering */ + /** Flag indicating this item is draggable for reordering. */ isDraggable?: boolean; - /** Accessible label for the draggable button on draggable list items */ + /** Accessible label for the draggable button on draggable list items. */ draggableButtonAriaLabel?: string; - /** Flag indicating if the dual list selector is in a disabled state */ + /** Flag indicating if the dual list selector is in a disabled state. */ isDisabled?: boolean; } diff --git a/packages/react-core/src/next/components/DualListSelector/DualListSelectorListWrapper.tsx b/packages/react-core/src/next/components/DualListSelector/DualListSelectorListWrapper.tsx index 405a3389531..f704eb9c971 100644 --- a/packages/react-core/src/next/components/DualListSelector/DualListSelectorListWrapper.tsx +++ b/packages/react-core/src/next/components/DualListSelector/DualListSelectorListWrapper.tsx @@ -10,7 +10,7 @@ export interface DualListSelectorListWrapperProps extends React.HTMLProps void; - /** @hide Callback for when a tree option is checked. Optionally used only when options prop is provided. */ - onOptionCheck?: ( - event: React.MouseEvent | React.ChangeEvent | React.KeyboardEvent, - isChecked: boolean, - itemData: DualListSelectorTreeItemData - ) => void; - /** @hide Flag indicating a dynamically built search bar should be included above the pane. */ - isSearchable?: boolean; /** Flag indicating whether the component is disabled. */ isDisabled?: boolean; /** Callback for search input. To be used when isSearchable is true. */ onSearch?: (event: React.ChangeEvent) => void; - /** @hide A callback for when the search input value for changes. To be used when isSearchable is true. */ - onSearchInputChanged?: (event: React.FormEvent, value: string) => void; - /** @hide Callback for search input clear button */ - onSearchInputClear?: (event: React.SyntheticEvent) => void; - /** @hide Filter function for custom filtering based on search string. To be used when isSearchable is true. */ - filterOption?: (option: React.ReactNode, input: string) => boolean; - /** @hide Accessible label for the search input. To be used when isSearchable is true. */ - searchInputAriaLabel?: string; - /** @hide Callback for updating the filtered options in DualListSelector. To be used when isSearchable is true. */ - onFilterUpdate?: (newFilteredOptions: React.ReactNode[], paneType: string, isSearchReset: boolean) => void; /** Minimum height of the list of options rendered in the pane. **/ listMinHeight?: string; } @@ -77,169 +44,51 @@ export const DualListSelectorPane: React.FunctionComponent { - const [input, setInput] = React.useState(''); - const { isTree } = React.useContext(DualListSelectorContext); - - // only called when search input is dynamically built - const onChange = (e: React.FormEvent, newValue: string) => { - let filtered: React.ReactNode[]; - if (isTree) { - filtered = options - .map((opt) => Object.assign({}, opt)) - .filter((item) => filterInput(item as React.ReactNode[] & DualListSelectorTreeItemData, newValue)); - } else { - filtered = options.filter((option) => { - if (displayOption(option)) { - return option; - } - }); - } - onFilterUpdate(filtered, isChosen ? 'chosen' : 'available', newValue === ''); - - if (onSearchInputChanged) { - onSearchInputChanged(e, newValue); - } - setInput(newValue); - }; - - // only called when options are passed via options prop and isTree === true - const filterInput = (item: DualListSelectorTreeItemData, input: string): boolean => { - if (filterOption) { - return filterOption(item as DualListSelectorTreeItemData & React.ReactNode, input); - } else { - if (item.text.toLowerCase().includes(input.toLowerCase()) || input === '') { - return true; - } - } - if (item.children) { - return ( - (item.children = item.children - .map((opt) => Object.assign({}, opt)) - .filter((child) => filterInput(child, input))).length > 0 - ); - } - }; - - // only called when options are passed via options prop and isTree === false - const displayOption = (option: React.ReactNode) => { - if (filterOption) { - return filterOption(option, input); - } else { - return option.toString().toLowerCase().includes(input.toLowerCase()); - } - }; - - return ( -
- {title && ( -
-
-
{title}
-
-
- )} - {(actions || searchInput || isSearchable) && ( -
- {(isSearchable || searchInput) && ( -
- {searchInput ? ( - searchInput - ) : ( - onChange(e as React.FormEvent, '') - } - isDisabled={isDisabled} - aria-label={searchInputAriaLabel} - /> - )} -
- )} - {actions &&
{actions}
} +}: DualListSelectorPaneProps) => ( +
+ {title && ( +
+
+
{title}
- )} - {status && ( -
-
- {status} +
+ )} + {(actions || searchInput) && ( +
+ {searchInput && ( +
+ {searchInput ? searchInput : }
-
- )} - - {!isTree && ( - onOptionSelect(e, index, isChosen, id)} - displayOption={displayOption} - id={`${id}-list`} - isDisabled={isDisabled} - {...(listMinHeight && { - style: { [cssMenuMinHeight.name]: listMinHeight } as React.CSSProperties - })} - > - {children} - )} - {isTree && ( - - {options.length > 0 ? ( - - Object.assign({}, opt)) - .filter((item) => - filterInput(item as React.ReactNode[] & DualListSelectorTreeItemData, input) - ) as React.ReactNode[] & DualListSelectorTreeItemData[]) - : (options as React.ReactNode[] & DualListSelectorTreeItemData[]) - } - onOptionCheck={onOptionCheck} - id={`${id}-tree`} - isDisabled={isDisabled} - /> - - ) : ( - children - )} - - )} - -
- ); -}; + {actions &&
{actions}
} +
+ )} + {status && ( +
+
+ {status} +
+
+ )} + + + {children} + + +
+); DualListSelectorPane.displayName = 'DualListSelectorPane'; diff --git a/packages/react-core/src/next/components/DualListSelector/DualListSelectorTree.tsx b/packages/react-core/src/next/components/DualListSelector/DualListSelectorTree.tsx index a151d625050..8fb28a289b9 100644 --- a/packages/react-core/src/next/components/DualListSelector/DualListSelectorTree.tsx +++ b/packages/react-core/src/next/components/DualListSelector/DualListSelectorTree.tsx @@ -10,26 +10,26 @@ export interface DualListSelectorTreeItemData { className?: string; /** Flag indicating this option is expanded by default. */ defaultExpanded?: boolean; - /** Flag indicating this option has a badge */ + /** Flag indicating this option has a badge. */ hasBadge?: boolean; - /** Callback fired when an option is checked */ + /** Callback fired when an option is checked. */ onOptionCheck?: ( event: React.MouseEvent | React.ChangeEvent | React.KeyboardEvent, isChecked: boolean, isChosen: boolean, itemData: DualListSelectorTreeItemData ) => void; - /** ID of the option */ + /** ID of the option. */ id: string; - /** Text of the option */ + /** Text of the option. */ text: string; - /** Parent id of an option */ + /** Parent ID of an option. */ parentId?: string; - /** Checked state of the option */ + /** Checked state of the option. */ isChecked: boolean; - /** Additional properties to pass to the option checkbox */ + /** Additional properties to pass to the option checkbox. */ checkProps?: any; - /** Additional properties to pass to the option badge */ + /** Additional properties to pass to the option badge. */ badgeProps?: any; /** Flag indicating whether the component is disabled. */ isDisabled?: boolean; @@ -40,19 +40,19 @@ export interface DualListSelectorTreeItemData { */ export interface DualListSelectorTreeProps extends Omit, 'data'> { - /** Data of the tree view */ + /** Data of the tree view. */ data: DualListSelectorTreeItemData[] | (() => DualListSelectorTreeItemData[]); - /** ID of the tree view */ + /** ID of the tree view. */ id?: string; - /** @hide Flag indicating if the list is nested */ + /** @hide Flag indicating if the list is nested. */ isNested?: boolean; - /** Flag indicating if all options should have badges */ + /** Flag indicating if all options should have badges. */ hasBadges?: boolean; - /** Sets the default expanded behavior */ + /** Sets the default expanded behavior. */ defaultAllExpanded?: boolean; - /** Flag indicating if the dual list selector tree is in the disabled state */ + /** Flag indicating if the dual list selector tree is in the disabled state. */ isDisabled?: boolean; - /** Callback fired when an option is checked */ + /** Callback fired when an option is checked. */ onOptionCheck?: ( event: React.MouseEvent | React.ChangeEvent | React.KeyboardEvent, isChecked: boolean, diff --git a/packages/react-core/src/next/components/DualListSelector/DualListSelectorTreeItem.tsx b/packages/react-core/src/next/components/DualListSelector/DualListSelectorTreeItem.tsx index 7b450b1aa74..bfefccc81f8 100644 --- a/packages/react-core/src/next/components/DualListSelector/DualListSelectorTreeItem.tsx +++ b/packages/react-core/src/next/components/DualListSelector/DualListSelectorTreeItem.tsx @@ -14,25 +14,25 @@ export interface DualListSelectorTreeItemProps extends React.HTMLProps | React.KeyboardEvent, isChecked: boolean, itemData: DualListSelectorTreeItemData ) => void; - /** ID of the option */ + /** ID of the option. */ id: string; - /** Text of the option */ + /** Text of the option. */ text: string; /** Flag indicating if this open is checked. */ isChecked?: boolean; - /** Additional properties to pass to the option checkbox */ + /** Additional properties to pass to the option checkbox. */ checkProps?: any; - /** Additional properties to pass to the option badge */ + /** Additional properties to pass to the option badge. */ badgeProps?: any; - /** Raw data of the option */ + /** Raw data of the option. */ itemData?: DualListSelectorTreeItemData; /** Flag indicating whether the component is disabled. */ isDisabled?: boolean; diff --git a/packages/react-core/src/next/components/DualListSelector/__tests__/__snapshots__/DualListSelector.test.tsx.snap b/packages/react-core/src/next/components/DualListSelector/__tests__/__snapshots__/DualListSelector.test.tsx.snap index aae1de17ac2..e0220647955 100644 --- a/packages/react-core/src/next/components/DualListSelector/__tests__/__snapshots__/DualListSelector.test.tsx.snap +++ b/packages/react-core/src/next/components/DualListSelector/__tests__/__snapshots__/DualListSelector.test.tsx.snap @@ -4,69 +4,15 @@ exports[`DualListSelector basic 1`] = `
    -
  • -
    - - - - Option 1 - - - -
    -
  • -
  • -
    - - - - Option 2 - - - -
    -
  • -
+ />
@@ -76,70 +22,15 @@ exports[`DualListSelector basic with disabled controls 1`] = `
    -
  • -
    - - - - Option 1 - - - -
    -
  • -
  • -
    - - - - Option 2 - - - -
    -
  • -
+ />
@@ -149,6 +40,7 @@ exports[`DualListSelector with custom status 1`] = `
    -
  • -
    - - - - Option 1 - - - -
    -
  • -
  • -
    - - - - Option 2 - - - -
    -
  • -
+ />
@@ -231,112 +68,15 @@ exports[`DualListSelector with search inputs 1`] = `
-
-
-
-
- - - - - - -
-
-
-
    -
  • -
    - - - - Option 1 - - - -
    -
  • -
  • -
    - - - - Option 2 - - - -
    -
  • -
+ />