From 4c08ca57ef402c96fd34d10b61ce818da3fddadc Mon Sep 17 00:00:00 2001 From: Ray Winkelman Date: Mon, 28 Sep 2026 16:43:57 +0700 Subject: [PATCH 1/3] fix(react-keytips): handle KEYTIP_REMOVED/UPDATED in useKeytipsManager --- packages/react-keytips/src/hooks/useKeytipsManager.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/react-keytips/src/hooks/useKeytipsManager.ts b/packages/react-keytips/src/hooks/useKeytipsManager.ts index e9093d25a..53defa18a 100644 --- a/packages/react-keytips/src/hooks/useKeytipsManager.ts +++ b/packages/react-keytips/src/hooks/useKeytipsManager.ts @@ -23,6 +23,14 @@ export function useKeytipsManager(): { keytips.current[keytip.uniqueId] = keytip; }); + subscribe(EVENTS.KEYTIP_UPDATED, (keytip) => { + keytips.current[keytip.uniqueId] = keytip; + }); + + subscribe(EVENTS.KEYTIP_REMOVED, (uniqueId) => { + delete keytips.current[uniqueId]; + }); + subscribe(EVENTS.ENTER_KEYTIP_MODE, () => { isKeytipModeEnabled.current = true; }); From 25c01b53e5fb38694ca74d10a29152c8634a3d17 Mon Sep 17 00:00:00 2001 From: Shadow Date: Sat, 24 Oct 2026 17:21:01 +0700 Subject: [PATCH 2/3] chore: add beachball change file for react-keytips fix --- ...react-keytips-e09c85ce-05b9-4911-9379-5a37ee4d4f68.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/@fluentui-contrib-react-keytips-e09c85ce-05b9-4911-9379-5a37ee4d4f68.json diff --git a/change/@fluentui-contrib-react-keytips-e09c85ce-05b9-4911-9379-5a37ee4d4f68.json b/change/@fluentui-contrib-react-keytips-e09c85ce-05b9-4911-9379-5a37ee4d4f68.json new file mode 100644 index 000000000..4ab6429c7 --- /dev/null +++ b/change/@fluentui-contrib-react-keytips-e09c85ce-05b9-4911-9379-5a37ee4d4f68.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "fix(react-keytips): handle KEYTIP_REMOVED/UPDATED in useKeytipsManager", + "packageName": "@fluentui-contrib/react-keytips", + "email": "rwinkelman@users.noreply.github.com", + "dependentChangeType": "patch" +} From 6ac4f62936cb47e352021758135f4338ab888b43 Mon Sep 17 00:00:00 2001 From: Shadow Date: Mon, 2 Nov 2026 04:59:18 +0700 Subject: [PATCH 3/3] test(react-keytips): cover registry update and removal Register a keytip, update it, and unregister it through useKeytipsManager so a stale registry cannot come back unnoticed. --- .../src/hooks/useKeytipsManager.test.ts | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 packages/react-keytips/src/hooks/useKeytipsManager.test.ts diff --git a/packages/react-keytips/src/hooks/useKeytipsManager.test.ts b/packages/react-keytips/src/hooks/useKeytipsManager.test.ts new file mode 100644 index 000000000..2ea9f9e85 --- /dev/null +++ b/packages/react-keytips/src/hooks/useKeytipsManager.test.ts @@ -0,0 +1,49 @@ +import { useKeytipsManager } from './useKeytipsManager'; +import { renderHook } from '@testing-library/react'; + +jest.mock('@fluentui/react-components', () => { + return { + useId: () => 'keytip-id', + useFluent: jest.fn().mockReturnValue({ + targetDocument: document, + }), + }; +}); + +describe('useKeytipsManager', () => { + it('keeps registered keytips in sync through update and removal', () => { + const { result } = renderHook(() => useKeytipsManager()); + + const uniqueId = result.current.register({ + content: 'A', + keySequences: ['a'], + }); + + expect(result.current.getKeytips()[uniqueId]).toEqual( + expect.objectContaining({ + uniqueId, + content: 'A', + keySequences: ['a'], + }) + ); + + result.current.update({ + uniqueId, + content: 'B', + keySequences: ['b'], + }); + + expect(result.current.getKeytips()[uniqueId]).toEqual( + expect.objectContaining({ + uniqueId, + content: 'B', + keySequences: ['b'], + }) + ); + expect(result.current.getKeytips()[uniqueId].content).toBe('B'); + + result.current.unregister(uniqueId); + + expect(result.current.getKeytips()[uniqueId]).toBeUndefined(); + }); +});