-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: implement auto reflow for MessageBar layouts (#29328)
* feat: Initial implementation Adds an initial implementation of MessageBar that includes design for different intents and multiline handling. * remove TODOs * fix multiline alignment * fix slot type misalign * fix tests * rename to secondaryActions * fix warnings * break out into components * remove stories * revert tsconfig changes * remove outdated keyborg cypress test * add keyborg test again * add tsconfig paths to cypress * feat: Implement auto reflow for MessageBar layouts * update api * pr comments * cleanup
- Loading branch information
Showing
18 changed files
with
221 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 88 additions & 0 deletions
88
...act-components/react-message-bar-preview/src/components/MessageBar/useMessageBarReflow.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import * as React from 'react'; | ||
import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts'; | ||
import { isHTMLElement } from '@fluentui/react-utilities'; | ||
|
||
export function useMessageBarReflow(enabled: boolean = false) { | ||
const { targetDocument } = useFluent(); | ||
const forceUpdate = React.useReducer(() => ({}), {})[1]; | ||
const reflowingRef = React.useRef(false); | ||
const resizeObserverRef = React.useRef<ResizeObserver | null>(null); | ||
const prevInlineSizeRef = React.useRef(-1); | ||
|
||
const handleResize: ResizeObserverCallback = React.useCallback( | ||
entries => { | ||
// Resize observer is only owned by this component - one resize observer entry expected | ||
// No need to support mutliple fragments - one border box entry expected | ||
if (process.env.NODE_ENV !== 'production' && entries.length > 1) { | ||
// eslint-disable-next-line no-console | ||
console.error( | ||
[ | ||
'useMessageBarReflow: Resize observer should only have one entry. ', | ||
'If multiple entries are observed, the first entry will be used.', | ||
'This is a bug, please report it to the Fluent UI team.', | ||
].join(' '), | ||
); | ||
} | ||
|
||
const entry = entries[0]; | ||
const borderBoxSize = entry?.borderBoxSize[0]; | ||
if (!borderBoxSize || !entry) { | ||
return; | ||
} | ||
|
||
const { inlineSize } = borderBoxSize; | ||
const { target } = entry; | ||
|
||
if (!isHTMLElement(target)) { | ||
return; | ||
} | ||
|
||
let nextReflowing: boolean | undefined; | ||
|
||
// No easy way to really determine when the single line layout will fit | ||
// Just keep try to set single line layout as long as the size is growing | ||
// Will cause flickering when size is being adjusted gradually (i.e. drag) - but this should not be a common case | ||
if (reflowingRef.current) { | ||
if (prevInlineSizeRef.current < inlineSize) { | ||
nextReflowing = false; | ||
} | ||
} else { | ||
const scrollWidth = target.scrollWidth; | ||
if (inlineSize < scrollWidth) { | ||
nextReflowing = true; | ||
} | ||
} | ||
|
||
prevInlineSizeRef.current = inlineSize; | ||
if (typeof nextReflowing !== 'undefined' && reflowingRef.current !== nextReflowing) { | ||
reflowingRef.current = nextReflowing; | ||
forceUpdate(); | ||
} | ||
}, | ||
[forceUpdate], | ||
); | ||
|
||
const ref = React.useCallback( | ||
(el: HTMLElement | null) => { | ||
if (!enabled || !el || !targetDocument?.defaultView) { | ||
return; | ||
} | ||
|
||
resizeObserverRef.current?.disconnect(); | ||
|
||
const win = targetDocument.defaultView; | ||
const resizeObserver = new win.ResizeObserver(handleResize); | ||
resizeObserverRef.current = resizeObserver; | ||
resizeObserver.observe(el, { box: 'border-box' }); | ||
}, | ||
[targetDocument, handleResize, enabled], | ||
); | ||
|
||
React.useEffect(() => { | ||
return () => { | ||
resizeObserverRef.current?.disconnect(); | ||
}; | ||
}, []); | ||
|
||
return { ref, reflowing: reflowingRef.current }; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
packages/react-components/react-message-bar-preview/src/contexts/messageBarContext.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
32 changes: 32 additions & 0 deletions
32
...es/react-components/react-message-bar-preview/stories/MessageBar/ManualLayout.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import * as React from 'react'; | ||
import { Button, Link, Switch } from '@fluentui/react-components'; | ||
import { DismissRegular } from '@fluentui/react-icons'; | ||
import { MessageBar, MessageBarActions, MessageBarBody, MessageBarTitle } from '@fluentui/react-message-bar-preview'; | ||
|
||
const intents = ['info', 'warning', 'error', 'success'] as const; | ||
export const ManualLayout = () => { | ||
const [single, setSingle] = React.useState(true); | ||
return ( | ||
<> | ||
<Switch | ||
label={single ? 'Single line layout' : 'Multi line layout'} | ||
checked={single} | ||
onChange={(_, { checked }) => setSingle(checked)} | ||
/> | ||
<div style={{ display: 'flex', flexDirection: 'column', gap: '10px' }}> | ||
{intents.map(intent => ( | ||
<MessageBar key={intent} layout={single ? 'singleline' : 'multiline'} intent={intent}> | ||
<MessageBarBody> | ||
<MessageBarTitle>Descriptive title</MessageBarTitle> | ||
Message providing information to the user with actionable insights. <Link>Link</Link> | ||
</MessageBarBody> | ||
<MessageBarActions containerAction={<Button appearance="transparent" icon={<DismissRegular />} />}> | ||
<Button>Action</Button> | ||
<Button>Action</Button> | ||
</MessageBarActions> | ||
</MessageBar> | ||
))} | ||
</div> | ||
</> | ||
); | ||
}; |
23 changes: 0 additions & 23 deletions
23
packages/react-components/react-message-bar-preview/stories/MessageBar/Multiline.stories.tsx
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.