diff --git a/change/@fluentui-priority-overflow-a6802865-2d8b-43e0-8ac7-09dcca1570c8.json b/change/@fluentui-priority-overflow-a6802865-2d8b-43e0-8ac7-09dcca1570c8.json new file mode 100644 index 00000000000000..6a7987d6b1e111 --- /dev/null +++ b/change/@fluentui-priority-overflow-a6802865-2d8b-43e0-8ac7-09dcca1570c8.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "fix: overflowManager should always dispatch initial state", + "packageName": "@fluentui/priority-overflow", + "email": "lingfangao@hotmail.com", + "dependentChangeType": "patch" +} diff --git a/change/@fluentui-react-overflow-3a8651a5-c348-403c-a0a7-eaab0b660b52.json b/change/@fluentui-react-overflow-3a8651a5-c348-403c-a0a7-eaab0b660b52.json new file mode 100644 index 00000000000000..442f8805a44809 --- /dev/null +++ b/change/@fluentui-react-overflow-3a8651a5-c348-403c-a0a7-eaab0b660b52.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "refactor: Consolidate all overflow state into one object", + "packageName": "@fluentui/react-overflow", + "email": "lingfangao@hotmail.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-components/priority-overflow/src/overflowManager.ts b/packages/react-components/priority-overflow/src/overflowManager.ts index 15c24ded2c02af..3dece40e104728 100644 --- a/packages/react-components/priority-overflow/src/overflowManager.ts +++ b/packages/react-components/priority-overflow/src/overflowManager.ts @@ -12,7 +12,8 @@ export function createOverflowManager(): OverflowManager { // Set as true when resize observer is observing let observing = false; // If true, next update will dispatch to onUpdateOverflow even if queue top states don't change - let forceDispatch = false; + // Initially true to force dispatch on first mount + let forceDispatch = true; const options: Required = { padding: 10, overflowAxis: 'horizontal', diff --git a/packages/react-components/react-overflow/src/Overflow.cy.tsx b/packages/react-components/react-overflow/src/Overflow.cy.tsx index 6d427e2ab7bc93..66ee268948f971 100644 --- a/packages/react-components/react-overflow/src/Overflow.cy.tsx +++ b/packages/react-components/react-overflow/src/Overflow.cy.tsx @@ -8,6 +8,7 @@ import { useIsOverflowGroupVisible, useOverflowMenu, useOverflowContext, + useIsOverflowItemVisible, } from '@fluentui/react-overflow'; import { Portal } from '@fluentui/react-portal'; @@ -539,4 +540,35 @@ describe('Overflow', () => { setContainerSize(500); cy.contains('Update priority').click().get('#foo-visibility').should('have.text', 'visible'); }); + + it('Should have correct initial visibility state', () => { + const mapHelper = new Array(10).fill(0).map((_, i) => i); + const Assert = () => { + const isVisible = mapHelper.map(i => { + // eslint-disable-next-line react-hooks/rules-of-hooks + return useIsOverflowItemVisible(i.toString()); + }); + + if (isVisible.every(x => x)) { + return ; + } + + return null; + }; + + mount( + + {mapHelper.map(i => ( + + {i} + + ))} + + + , + ); + + setContainerSize(500); + cy.get('[data-passed="true"]').should('exist'); + }); }); diff --git a/packages/react-components/react-overflow/src/components/Overflow.tsx b/packages/react-components/react-overflow/src/components/Overflow.tsx index 3dbd46e94a6e43..1a599fd3c65f36 100644 --- a/packages/react-components/react-overflow/src/components/Overflow.tsx +++ b/packages/react-components/react-overflow/src/components/Overflow.tsx @@ -7,6 +7,12 @@ import { OverflowContext } from '../overflowContext'; import { updateVisibilityAttribute, useOverflowContainer } from '../useOverflowContainer'; import { useOverflowStyles } from './useOverflowStyles.styles'; +interface OverflowState { + hasOverflow: boolean; + itemVisibility: Record; + groupVisibility: Record; +} + /** * Overflow Props */ @@ -24,21 +30,27 @@ export const Overflow = React.forwardRef((props: OverflowProps, ref) => { const { children, minimumVisible, overflowAxis = 'horizontal', overflowDirection, padding } = props; - const [hasOverflow, setHasOverflow] = React.useState(false); - const [itemVisibility, setItemVisibility] = React.useState>({}); - const [groupVisibility, setGroupVisibility] = React.useState>({}); + const [overflowState, setOverflowState] = React.useState({ + hasOverflow: false, + itemVisibility: {}, + groupVisibility: {}, + }); // useOverflowContainer wraps this method in a useEventCallback. - // TODO: Do we need a useEventCallback here too? const update: OnUpdateOverflow = data => { - setHasOverflow(() => data.invisibleItems.length > 0); - setItemVisibility(() => { - const newState: Record = {}; - data.visibleItems.forEach(x => (newState[x.id] = true)); - data.invisibleItems.forEach(x => (newState[x.id] = false)); - return newState; + const { visibleItems, invisibleItems, groupVisibility } = data; + + const itemVisibility: Record = {}; + visibleItems.forEach(x => (itemVisibility[x.id] = true)); + invisibleItems.forEach(x => (itemVisibility[x.id] = false)); + + setOverflowState(() => { + return { + hasOverflow: data.invisibleItems.length > 0, + itemVisibility, + groupVisibility, + }; }); - setGroupVisibility(data.groupVisibility); }; const { containerRef, registerItem, updateOverflow, registerOverflowMenu } = useOverflowContainer(update, { @@ -57,9 +69,9 @@ export const Overflow = React.forwardRef((props: OverflowProps, ref) => { return (