From 631443a1430e54dc248268d43bab1956a9952b57 Mon Sep 17 00:00:00 2001 From: Bernardo Sunderhus Date: Wed, 4 Oct 2023 10:28:11 +0000 Subject: [PATCH] bugfix: ensure TreeItem emits events properly --- ...-5bf1ff30-ae1d-4a2b-9c0a-11587529003a.json | 7 ++ .../react-tree/etc/react-tree.api.md | 9 +- .../src/components/Tree/Tree.types.ts | 6 ++ .../src/components/TreeItem/useTreeItem.tsx | 87 ++++++++++++------- 4 files changed, 76 insertions(+), 33 deletions(-) create mode 100644 change/@fluentui-react-tree-5bf1ff30-ae1d-4a2b-9c0a-11587529003a.json diff --git a/change/@fluentui-react-tree-5bf1ff30-ae1d-4a2b-9c0a-11587529003a.json b/change/@fluentui-react-tree-5bf1ff30-ae1d-4a2b-9c0a-11587529003a.json new file mode 100644 index 00000000000000..8d976d181491a5 --- /dev/null +++ b/change/@fluentui-react-tree-5bf1ff30-ae1d-4a2b-9c0a-11587529003a.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "bugfix: ensure TreeItem emits events properly", + "packageName": "@fluentui/react-tree", + "email": "bernardo.sunderhus@gmail.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-components/react-tree/etc/react-tree.api.md b/packages/react-components/react-tree/etc/react-tree.api.md index 17e47dbf6d63ee..bd930a132fc429 100644 --- a/packages/react-components/react-tree/etc/react-tree.api.md +++ b/packages/react-components/react-tree/etc/react-tree.api.md @@ -336,7 +336,14 @@ export type TreeOpenChangeData = { } | { event: React_2.MouseEvent; type: 'Click'; -} | { +} +/** +* @deprecated +* Use `type: 'Click'` instead of Enter, +* an enter press will trigger a click event, which will trigger an open change, +* so there is no need to have a separate type for it. +*/ +| { event: React_2.KeyboardEvent; type: typeof Enter; } | { diff --git a/packages/react-components/react-tree/src/components/Tree/Tree.types.ts b/packages/react-components/react-tree/src/components/Tree/Tree.types.ts index 3a1a7a826f2dff..ec1113b16399f1 100644 --- a/packages/react-components/react-tree/src/components/Tree/Tree.types.ts +++ b/packages/react-components/react-tree/src/components/Tree/Tree.types.ts @@ -41,6 +41,12 @@ export type TreeOpenChangeData = { } & ( | { event: React.MouseEvent; type: 'ExpandIconClick' } | { event: React.MouseEvent; type: 'Click' } + /** + * @deprecated + * Use `type: 'Click'` instead of Enter, + * an enter press will trigger a click event, which will trigger an open change, + * so there is no need to have a separate type for it. + */ | { event: React.KeyboardEvent; type: typeof Enter } | { event: React.KeyboardEvent; type: typeof ArrowRight } | { event: React.KeyboardEvent; type: typeof ArrowLeft } diff --git a/packages/react-components/react-tree/src/components/TreeItem/useTreeItem.tsx b/packages/react-components/react-tree/src/components/TreeItem/useTreeItem.tsx index 809c963d7a913b..8550598d0504d7 100644 --- a/packages/react-components/react-tree/src/components/TreeItem/useTreeItem.tsx +++ b/packages/react-components/react-tree/src/components/TreeItem/useTreeItem.tsx @@ -30,7 +30,19 @@ export function useTreeItem_unstable(props: TreeItemProps, ref: React.Ref { + const setActionsVisibleIfNotFromSubtree = React.useCallback((event: React.SyntheticEvent) => { const isTargetFromSubtree = Boolean( subtreeRef.current && elementContains(subtreeRef.current, event.target as Node), ); if (!isTargetFromSubtree) { setActionsVisible(true); } + }, []); + const setActionsInvisibleIfNotFromSubtree = React.useCallback( + (event: React.MouseEvent | React.FocusEvent) => { + const isTargetFromSubtree = Boolean( + subtreeRef.current && elementContains(subtreeRef.current, event.target as Node), + ); + const isRelatedTargetFromActions = Boolean( + actionsRef.current && elementContains(actionsRef.current, event.relatedTarget as Node), + ); + if (isRelatedTargetFromActions) { + return setActionsVisible(true); + } + if (!isTargetFromSubtree) { + return setActionsVisible(false); + } + }, + [], + ); + + const handleMouseOver = useEventCallback((event: React.MouseEvent) => { + onMouseOver?.(event); + setActionsVisibleIfNotFromSubtree(event); }); - const handleActionsInvisible = useEventCallback((event: React.FocusEvent | React.MouseEvent) => { - const isTargetFromSubtree = Boolean( - subtreeRef.current && elementContains(subtreeRef.current, event.target as Node), - ); - const isRelatedTargetFromActions = Boolean( - actionsRef.current && elementContains(actionsRef.current, event.relatedTarget as Node), - ); - if (isRelatedTargetFromActions) { - return setActionsVisible(true); - } - if (!isTargetFromSubtree) { - return setActionsVisible(false); - } + const handleFocus = useEventCallback((event: React.FocusEvent) => { + onFocus?.(event); + setActionsVisibleIfNotFromSubtree(event); + }); + + const handleMouseOut = useEventCallback((event: React.MouseEvent) => { + onMouseOut?.(event); + setActionsInvisibleIfNotFromSubtree(event); + }); + const handleBlur = useEventCallback((event: React.FocusEvent) => { + onBlur?.(event); + setActionsInvisibleIfNotFromSubtree(event); }); const handleChange = useEventCallback((event: React.ChangeEvent) => { + onChange?.(event); if (event.isDefaultPrevented()) { return; } @@ -267,10 +290,10 @@ export function useTreeItem_unstable(props: TreeItemProps, ref: React.Ref