From f94dcdd12c7f7b74fd2f18aa828fa6c41da27a38 Mon Sep 17 00:00:00 2001 From: Martynas <43886789+MartynasStrazdas@users.noreply.github.com> Date: Thu, 16 Jan 2025 14:19:24 +0200 Subject: [PATCH] Add option to disable button based filtering (#840) * disable button based filtering implementation * extract-api * change * adjustments * extract-api * Update packages/hierarchies-react/src/test/itwinui/Tree.test.tsx Co-authored-by: Grigas <35135765+grigasp@users.noreply.github.com> * documentation change * updated change * Documentation adjustment 3rd try --------- Co-authored-by: Grigas <35135765+grigasp@users.noreply.github.com> --- .changeset/little-vans-sell.md | 8 ++++++++ .../api/presentation-hierarchies-react.api.md | 5 +++-- .../itwinui/TreeNodeRenderer.tsx | 13 ++++++++++++- .../itwinui/TreeRenderer.tsx | 18 ++++++++++++++++-- .../src/test/itwinui/Tree.test.tsx | 19 +++++++++++++++++++ 5 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 .changeset/little-vans-sell.md diff --git a/.changeset/little-vans-sell.md b/.changeset/little-vans-sell.md new file mode 100644 index 000000000..37367b725 --- /dev/null +++ b/.changeset/little-vans-sell.md @@ -0,0 +1,8 @@ +--- +"@itwin/presentation-hierarchies-react": minor +--- + +Added `filterButtonsVisibility` to `treeNodeRenderer`. Which allows configuring filter buttons visibility for the whole tree. + +- `show-on-hover` - default value, shows filter buttons on node hover or focus. +- `hide` - hides filter buttons on focus and hover, but will continue to show buttons on nodes in which filter is applied. Reaching hierarchy limit will continue to provide a way to filter nodes. diff --git a/packages/hierarchies-react/api/presentation-hierarchies-react.api.md b/packages/hierarchies-react/api/presentation-hierarchies-react.api.md index 9e2e9afd7..f5e955fe6 100644 --- a/packages/hierarchies-react/api/presentation-hierarchies-react.api.md +++ b/packages/hierarchies-react/api/presentation-hierarchies-react.api.md @@ -168,6 +168,7 @@ export const TreeNodeRenderer: React.ForwardRefExoticComponent ReactElement | undefined; getLabel?: (node: PresentationHierarchyNode) => ReactElement | undefined; getSublabel?: (node: PresentationHierarchyNode) => ReactElement | undefined; @@ -192,7 +193,7 @@ type TreeNodeRendererProps_2 = ComponentPropsWithoutRef type TreeProps = ComponentPropsWithoutRef>; // @public -export function TreeRenderer({ rootNodes, expandNode, selectNodes, isNodeSelected, onFilterClick, getIcon, getLabel, getSublabel, getHierarchyLevelDetails, reloadTree, selectionMode, localizedStrings, size, ...treeProps }: TreeRendererProps): JSX_3.Element; +export function TreeRenderer({ rootNodes, expandNode, selectNodes, isNodeSelected, onFilterClick, getIcon, getLabel, getSublabel, getHierarchyLevelDetails, reloadTree, selectionMode, localizedStrings, size, filterButtonsVisibility, ...treeProps }: TreeRendererProps): JSX_3.Element; // @public (undocumented) interface TreeRendererOwnProps { @@ -201,7 +202,7 @@ interface TreeRendererOwnProps { } // @public (undocumented) -type TreeRendererProps = Pick, "rootNodes" | "expandNode"> & Partial, "selectNodes" | "isNodeSelected" | "getHierarchyLevelDetails" | "reloadTree">> & Pick & TreeRendererOwnProps & Omit & ComponentPropsWithoutRef; +type TreeRendererProps = Pick, "rootNodes" | "expandNode"> & Partial, "selectNodes" | "isNodeSelected" | "getHierarchyLevelDetails" | "reloadTree">> & Pick & TreeRendererOwnProps & Omit & ComponentPropsWithoutRef; // @public export function UnifiedSelectionProvider({ storage, children }: PropsWithChildren<{ diff --git a/packages/hierarchies-react/src/presentation-hierarchies-react/itwinui/TreeNodeRenderer.tsx b/packages/hierarchies-react/src/presentation-hierarchies-react/itwinui/TreeNodeRenderer.tsx index d0244c890..fb63f8e92 100644 --- a/packages/hierarchies-react/src/presentation-hierarchies-react/itwinui/TreeNodeRenderer.tsx +++ b/packages/hierarchies-react/src/presentation-hierarchies-react/itwinui/TreeNodeRenderer.tsx @@ -39,6 +39,16 @@ interface TreeNodeRendererOwnProps { actionButtonsClassName?: string; /** Tree node size. Should match the size passed to `TreeRenderer` component. */ size?: "default" | "small"; + /** + * Configures filter buttons visibility. + * + * Options: + * - `show-on-hover` - show filter buttons when hovering over node, or the node is in focus. + * - `hide` - hide filter buttons, but will show them if the filter is applied. + * + * Default value: `show-on-hover` + */ + filterButtonsVisibility?: "show-on-hover" | "hide"; } /** @public */ @@ -71,6 +81,7 @@ export const TreeNodeRenderer: React.ForwardRefExoticComponent ) : null} - {onFilterClick && node.isFilterable ? ( + {onFilterClick && node.isFilterable && (filterButtonsVisibility !== "hide" || node.isFiltered) ? ( , "rootNodes" | "expandNode"> & Partial, "selectNodes" | "isNodeSelected" | "getHierarchyLevelDetails" | "reloadTree">> & - Pick & + Pick & TreeRendererOwnProps & Omit & ComponentPropsWithoutRef; @@ -54,6 +54,7 @@ export function TreeRenderer({ selectionMode, localizedStrings, size, + filterButtonsVisibility, ...treeProps }: TreeRendererProps) { const { onNodeClick, onNodeKeyDown } = useSelectionHandler({ @@ -66,6 +67,7 @@ export function TreeRenderer({ return ( ); }, - [expandNode, getHierarchyLevelDetails, onFilterClick, onNodeClick, onNodeKeyDown, getIcon, getLabel, getSublabel, reloadTree, size], + [ + filterButtonsVisibility, + expandNode, + getHierarchyLevelDetails, + onFilterClick, + onNodeClick, + onNodeKeyDown, + getIcon, + getLabel, + getSublabel, + reloadTree, + size, + ], ); const getNode = useCallback((node) => createRenderedTreeNodeData(node, isNodeSelected ?? noopIsNodeSelected), [isNodeSelected]); diff --git a/packages/hierarchies-react/src/test/itwinui/Tree.test.tsx b/packages/hierarchies-react/src/test/itwinui/Tree.test.tsx index a22962369..beadbf518 100644 --- a/packages/hierarchies-react/src/test/itwinui/Tree.test.tsx +++ b/packages/hierarchies-react/src/test/itwinui/Tree.test.tsx @@ -353,6 +353,25 @@ describe("Tree", () => { expect(onFilterClick).to.be.calledOnceWith(hierarchyLevelDetails); }); + it("renders filter button when filter buttons are hidden, but node is filtered", async () => { + const rootNodes = createNodes([ + { + id: "root-1", + isFilterable: true, + isFiltered: true, + }, + ]); + + const hierarchyLevelDetails = {} as unknown as HierarchyLevelDetails; + getHierarchyLevelDetails.returns(hierarchyLevelDetails); + + const { user, queryByText, getByRole } = render(); + + expect(queryByText("root-1")).to.not.be.null; + await user.click(getByRole("button", { name: "Apply filter" })); + expect(onFilterClick).to.be.calledOnceWith(hierarchyLevelDetails); + }); + describe("`ResultSetTooLarge` node", () => { it("renders `ResultSetTooLarge` node with filtering and override support", async () => { const rootNodes = createNodes([