-
Notifications
You must be signed in to change notification settings - Fork 889
[Feature Notification] Add a euiAnimation method on the EuiHeaderSectionItemButton ref #4424
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
915a2d1
14d5b51
cc5c874
4f5c09f
e020d7a
c6f7bc3
41a54c8
e4b21e1
d5923d3
4d3c970
8253863
46a3d77
f88a657
aba5d8e
d13e053
f3a8851
733ae30
4634390
b4eb475
10736bd
4b396ac
36c586d
67d1c48
c5b041e
d431074
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,7 @@ import React, { useState } from 'react'; | |
| import { | ||
| EuiAvatar, | ||
| EuiBadge, | ||
| EuiButton, | ||
| EuiButtonEmpty, | ||
| EuiFlexGroup, | ||
| EuiFlexItem, | ||
|
|
@@ -29,42 +30,14 @@ import { | |
| } from '../../../../src/components'; | ||
| import { htmlIdGenerator } from '../../../../src/services'; | ||
|
|
||
| export default () => { | ||
| const [position, setPosition] = useState('static'); | ||
|
|
||
| return ( | ||
| <> | ||
| <EuiSwitch | ||
| label={'Make header fixed position and put alerts in flyout'} | ||
| checked={position === 'fixed'} | ||
| onChange={(e) => setPosition(e.target.checked ? 'fixed' : 'static')} | ||
| /> | ||
| <EuiSpacer /> | ||
| <EuiHeader position={position}> | ||
| <EuiHeaderSection grow={false}> | ||
| <EuiHeaderSectionItem border="right"> | ||
| <EuiHeaderLogo>Elastic</EuiHeaderLogo> | ||
| </EuiHeaderSectionItem> | ||
| </EuiHeaderSection> | ||
|
|
||
| <EuiHeaderSection side="right"> | ||
| <EuiHeaderSectionItem> | ||
| <HeaderUpdates | ||
| flyoutOrPopover={position === 'fixed' ? 'flyout' : 'popover'} | ||
| /> | ||
| </EuiHeaderSectionItem> | ||
| <EuiHeaderSectionItem> | ||
| <HeaderUserMenu /> | ||
| </EuiHeaderSectionItem> | ||
| </EuiHeaderSection> | ||
| </EuiHeader> | ||
| </> | ||
| ); | ||
| }; | ||
|
|
||
| const HeaderUpdates = ({ flyoutOrPopover = 'flyout' }) => { | ||
| const HeaderUpdates = ({ | ||
| showNotification, | ||
| setShowNotification, | ||
| notificationsNumber, | ||
| isAnimating, | ||
| }) => { | ||
| const [isFlyoutVisible, setIsFlyoutVisible] = useState(false); | ||
| const [showBadge, setShowBadge] = useState(true); | ||
| const [isPopoverVisible, setIsPopoverVisible] = useState(false); | ||
|
|
||
| const alerts = [ | ||
| { | ||
|
|
@@ -146,88 +119,64 @@ const HeaderUpdates = ({ flyoutOrPopover = 'flyout' }) => { | |
| setIsFlyoutVisible(false); | ||
| }; | ||
|
|
||
| const closePopover = () => { | ||
| setIsPopoverVisible(false); | ||
| }; | ||
|
|
||
| const showFlyout = () => { | ||
| setShowBadge(false); | ||
| setShowNotification(false); | ||
| setIsFlyoutVisible(!isFlyoutVisible); | ||
| }; | ||
|
|
||
| const button = ( | ||
| const showPopover = () => { | ||
| setShowNotification(false); | ||
| setIsPopoverVisible(!isPopoverVisible); | ||
| }; | ||
|
|
||
| const bellButton = ( | ||
| <EuiHeaderSectionItemButton | ||
| aria-controls="headerNewsFeed" | ||
| aria-controls="headerFlyoutNewsFeed" | ||
| aria-expanded={isFlyoutVisible} | ||
| aria-haspopup="true" | ||
| aria-label={`News feed: ${ | ||
| showBadge ? 'Updates available' : 'No updates' | ||
| showNotification ? 'Updates available' : 'No updates' | ||
| }`} | ||
| onClick={() => showFlyout()} | ||
| notification={showBadge}> | ||
| <EuiIcon type="cheer" size="m" /> | ||
| notification={showNotification} | ||
| animation={isAnimating} | ||
| hasBackground> | ||
| <EuiIcon type="bell" /> | ||
| </EuiHeaderSectionItemButton> | ||
| ); | ||
|
|
||
| let content; | ||
| if (flyoutOrPopover === 'flyout') { | ||
| content = ( | ||
| <> | ||
| {button} | ||
| {isFlyoutVisible && ( | ||
| <EuiPortal> | ||
| <EuiFlyout | ||
| onClose={() => closeFlyout()} | ||
| size="s" | ||
| id="headerNewsFeed" | ||
| aria-labelledby="flyoutSmallTitle"> | ||
| <EuiFlyoutHeader hasBorder> | ||
| <EuiTitle size="s"> | ||
| <h2 id="flyoutSmallTitle">What's new</h2> | ||
| </EuiTitle> | ||
| </EuiFlyoutHeader> | ||
| <EuiFlyoutBody> | ||
| {alerts.map((alert, i) => ( | ||
| <EuiHeaderAlert | ||
| key={`alert-${i}`} | ||
| title={alert.title} | ||
| action={alert.action} | ||
| text={alert.text} | ||
| date={alert.date} | ||
| badge={alert.badge} | ||
| /> | ||
| ))} | ||
| </EuiFlyoutBody> | ||
| <EuiFlyoutFooter> | ||
| <EuiFlexGroup justifyContent="spaceBetween" alignItems="center"> | ||
| <EuiFlexItem grow={false}> | ||
| <EuiButtonEmpty | ||
| iconType="cross" | ||
| onClick={() => closeFlyout()} | ||
| flush="left"> | ||
| Close | ||
| </EuiButtonEmpty> | ||
| </EuiFlexItem> | ||
| <EuiFlexItem grow={false}> | ||
| <EuiText color="subdued" size="s"> | ||
| <p>Version 7.0</p> | ||
| </EuiText> | ||
| </EuiFlexItem> | ||
| </EuiFlexGroup> | ||
| </EuiFlyoutFooter> | ||
| </EuiFlyout> | ||
| </EuiPortal> | ||
| )} | ||
| </> | ||
| ); | ||
| } | ||
| const cheerButton = ( | ||
| <EuiHeaderSectionItemButton | ||
| aria-controls="headerPopoverNewsFeed" | ||
| aria-expanded={isPopoverVisible} | ||
| aria-haspopup="true" | ||
| aria-label={`News feed: ${ | ||
| showNotification ? 'Updates available' : 'No updates' | ||
| }`} | ||
| onClick={() => showPopover()} | ||
| notification={showNotification && notificationsNumber} | ||
| animation={isAnimating}> | ||
| <EuiIcon type="cheer" /> | ||
| </EuiHeaderSectionItemButton> | ||
| ); | ||
|
|
||
| if (flyoutOrPopover === 'popover') { | ||
| content = ( | ||
| <EuiPopover | ||
| button={button} | ||
| isOpen={isFlyoutVisible} | ||
| closePopover={() => closeFlyout()} | ||
| panelPaddingSize="none"> | ||
| <EuiPopoverTitle paddingSize="s">What's new</EuiPopoverTitle> | ||
| <div style={{ maxHeight: '40vh', overflowY: 'auto', padding: 4 }}> | ||
| <EuiSpacer size="s" /> | ||
| const flyout = ( | ||
| <EuiPortal> | ||
| <EuiFlyout | ||
| onClose={() => closeFlyout()} | ||
| size="s" | ||
| id="headerFlyoutNewsFeed" | ||
| aria-labelledby="flyoutSmallTitle"> | ||
| <EuiFlyoutHeader hasBorder> | ||
| <EuiTitle size="s"> | ||
| <h2 id="flyoutSmallTitle">What's new</h2> | ||
| </EuiTitle> | ||
| </EuiFlyoutHeader> | ||
| <EuiFlyoutBody> | ||
| {alerts.map((alert, i) => ( | ||
| <EuiHeaderAlert | ||
| key={`alert-${i}`} | ||
|
|
@@ -238,17 +187,66 @@ const HeaderUpdates = ({ flyoutOrPopover = 'flyout' }) => { | |
| badge={alert.badge} | ||
| /> | ||
| ))} | ||
| </div> | ||
| <EuiPopoverFooter paddingSize="s"> | ||
| <EuiText color="subdued" size="s"> | ||
| <p>Version 7.0</p> | ||
| </EuiText> | ||
| </EuiPopoverFooter> | ||
| </EuiPopover> | ||
| ); | ||
| } | ||
| </EuiFlyoutBody> | ||
| <EuiFlyoutFooter> | ||
| <EuiFlexGroup justifyContent="spaceBetween" alignItems="center"> | ||
| <EuiFlexItem grow={false}> | ||
| <EuiButtonEmpty | ||
| iconType="cross" | ||
| onClick={() => closeFlyout()} | ||
| flush="left"> | ||
| Close | ||
| </EuiButtonEmpty> | ||
| </EuiFlexItem> | ||
| <EuiFlexItem grow={false}> | ||
| <EuiText color="subdued" size="s"> | ||
| <p>Version 7.0</p> | ||
| </EuiText> | ||
| </EuiFlexItem> | ||
| </EuiFlexGroup> | ||
| </EuiFlyoutFooter> | ||
| </EuiFlyout> | ||
| </EuiPortal> | ||
| ); | ||
|
|
||
| return content; | ||
| const popover = ( | ||
| <EuiPopover | ||
| id="headerPopoverNewsFeed" | ||
| ownFocus | ||
| repositionOnScroll | ||
| button={cheerButton} | ||
| isOpen={isPopoverVisible} | ||
| closePopover={() => closePopover()} | ||
|
elizabetdev marked this conversation as resolved.
Outdated
|
||
| panelPaddingSize="none"> | ||
| <EuiPopoverTitle paddingSize="s">What's new</EuiPopoverTitle> | ||
| <div style={{ maxHeight: '40vh', overflowY: 'auto', padding: 4 }}> | ||
| <EuiSpacer size="s" /> | ||
| {alerts.map((alert, i) => ( | ||
| <EuiHeaderAlert | ||
| key={`alert-${i}`} | ||
| title={alert.title} | ||
| action={alert.action} | ||
| text={alert.text} | ||
| date={alert.date} | ||
| badge={alert.badge} | ||
| /> | ||
| ))} | ||
| </div> | ||
| <EuiPopoverFooter paddingSize="s"> | ||
| <EuiText color="subdued" size="s"> | ||
| <p>Version 7.0</p> | ||
| </EuiText> | ||
| </EuiPopoverFooter> | ||
| </EuiPopover> | ||
| ); | ||
|
|
||
| return ( | ||
| <> | ||
| {bellButton} | ||
| {popover} | ||
| {isFlyoutVisible && flyout} | ||
| </> | ||
| ); | ||
| }; | ||
|
|
||
| const HeaderUserMenu = () => { | ||
|
|
@@ -319,3 +317,84 @@ const HeaderUserMenu = () => { | |
| </EuiPopover> | ||
| ); | ||
| }; | ||
|
|
||
| export default () => { | ||
| const [position, setPosition] = useState('static'); | ||
| const [showNotification, setShowNotification] = useState(true); | ||
| const [isAnimating, setIsAnimating] = useState(false); | ||
| const [theme, setTheme] = useState('light'); | ||
| const [notificationsNumber, setNotificationsNumber] = useState(1); | ||
|
|
||
| const animate = () => { | ||
| setIsAnimating(false); | ||
|
|
||
| setTimeout(() => { | ||
| setIsAnimating(true); | ||
| }, 100); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is an important piece that consumers will not see. This is the only way they'd be able to reset the animation after each go. I think there's a couple paths:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks @cchaos,
@chandlerprall can you recommend what you believe is the best way to inject the CSS class
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of a prop which needs to toggle off/on to animate, we could add a method to the component's ref, If that sounds better I can put that together. Alternatively, we could use the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @cchaos what do you think of this approach?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that approach works. My only concern would be discoverability. Of course we'd have it hooked up in our docs, but would there be any autocompletion in IDE's that would help surface this option.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PR showing the method-based approach at elizabetdev#8
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks @chandlerprall. I found it a really bit difficult to document/exemplify this solution. So do you think this would work elizabetdev#9? |
||
| }; | ||
|
|
||
| const notify = () => { | ||
| if (!showNotification) { | ||
| setNotificationsNumber(1); | ||
| setShowNotification(true); | ||
| } else { | ||
| setNotificationsNumber(notificationsNumber + 1); | ||
| } | ||
| }; | ||
|
|
||
| return ( | ||
| <> | ||
| <EuiFlexGroup alignItems="center" gutterSize="m"> | ||
| <EuiFlexItem grow={false}> | ||
| <EuiSwitch | ||
| label={'Make header fixed position'} | ||
| checked={position === 'fixed'} | ||
| onChange={(e) => setPosition(e.target.checked ? 'fixed' : 'static')} | ||
| /> | ||
| </EuiFlexItem> | ||
|
|
||
| <EuiFlexItem grow={false}> | ||
| <EuiSwitch | ||
| label={'Change theme to dark'} | ||
| checked={theme === 'dark'} | ||
| onChange={(e) => setTheme(e.target.checked ? 'dark' : 'light')} | ||
| /> | ||
| </EuiFlexItem> | ||
|
|
||
| <EuiFlexItem grow={false}> | ||
| <EuiButton size="s" onClick={notify}> | ||
| Notify | ||
| </EuiButton> | ||
| </EuiFlexItem> | ||
|
|
||
| <EuiFlexItem grow={false}> | ||
| <EuiButton size="s" onClick={animate}> | ||
| Animate | ||
| </EuiButton> | ||
| </EuiFlexItem> | ||
| </EuiFlexGroup> | ||
|
|
||
| <EuiSpacer /> | ||
| <EuiHeader position={position} theme={theme}> | ||
| <EuiHeaderSection grow={false}> | ||
| <EuiHeaderSectionItem border="right"> | ||
| <EuiHeaderLogo>Elastic</EuiHeaderLogo> | ||
| </EuiHeaderSectionItem> | ||
| </EuiHeaderSection> | ||
| <EuiHeaderSection side="right"> | ||
| <EuiHeaderSectionItem> | ||
| <HeaderUpdates | ||
| showNotification={showNotification} | ||
| setShowNotification={() => setShowNotification()} | ||
| notificationsNumber={notificationsNumber} | ||
| isAnimating={isAnimating} | ||
| /> | ||
| </EuiHeaderSectionItem> | ||
| <EuiHeaderSectionItem> | ||
| <HeaderUserMenu isAnimating={isAnimating} /> | ||
| </EuiHeaderSectionItem> | ||
| </EuiHeaderSection> | ||
| </EuiHeader> | ||
| </> | ||
| ); | ||
| }; | ||
Uh oh!
There was an error while loading. Please reload this page.