@madie/madie-design-system 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.babelrc +10 -0
- package/.editorconfig +22 -0
- package/.eslintignore +5 -0
- package/.eslintrc.js +31 -0
- package/.storybook/.babelrc +4 -0
- package/.storybook/main.js +89 -0
- package/.storybook/preview-head.html +9 -0
- package/.storybook/preview.js +5 -0
- package/README.md +5 -0
- package/components/Accordion/Accordion.stories.js +20 -0
- package/components/Accordion/index.jsx +93 -0
- package/components/Alert/Alert.stories.js +61 -0
- package/components/Alert/index.js +46 -0
- package/components/Breadcrumb/Breadcrumb.md +28 -0
- package/components/Breadcrumb/Breadcrumb.stories.js +76 -0
- package/components/Breadcrumb/index.js +83 -0
- package/components/Button/Button.stories.js +121 -0
- package/components/Button/index.js +90 -0
- package/components/CalloutBox/CalloutBox.stories.js +94 -0
- package/components/CalloutBox/index.js +109 -0
- package/components/Card/Card.stories.js +163 -0
- package/components/Card/index.js +137 -0
- package/components/Dropdown/Dropdown.stories.js +94 -0
- package/components/Dropdown/index.js +85 -0
- package/components/Error/Collapsible.jsx +88 -0
- package/components/Error/ErrorUI.jsx +31 -0
- package/components/Error/error.js +26 -0
- package/components/FlashNotification/FlashNotificationUI.jsx +91 -0
- package/components/FlashNotification/index.js +30 -0
- package/components/Footer/Footer.stories.js +20 -0
- package/components/Footer/FooterUI.jsx +269 -0
- package/components/Footer/LegacyFooterUI.jsx +194 -0
- package/components/Footer/SocialLinks.jsx +60 -0
- package/components/Footer/Subscribe.jsx +34 -0
- package/components/Footer/footer.js +30 -0
- package/components/Header/Header.md +111 -0
- package/components/Header/Header.stories.js +32 -0
- package/components/Header/HeaderAccountMenu.jsx +169 -0
- package/components/Header/HeaderCancel.jsx +16 -0
- package/components/Header/HeaderContainer.jsx +63 -0
- package/components/Header/HeaderLogo.jsx +42 -0
- package/components/Header/HeaderMenuButton.js +50 -0
- package/components/Header/HeaderMenuItem.jsx +232 -0
- package/components/Header/HeaderMenuLink.js +50 -0
- package/components/Header/HeaderMenuSignOutButton.js +62 -0
- package/components/Header/HeaderMobileButton.js +37 -0
- package/components/Header/HeaderUI.jsx +167 -0
- package/components/Header/HelpIcon.jsx +32 -0
- package/components/Header/ImpersonatorBanner.jsx +57 -0
- package/components/Header/NavigationButtonIcon.jsx +27 -0
- package/components/Header/default-content.json +280 -0
- package/components/Header/header.js +40 -0
- package/components/Header/hooks.js +52 -0
- package/components/Header/utag-helpers.js +9 -0
- package/components/Infotip/Infotip.jsx +75 -0
- package/components/Infotip/Infotip.stories.js +50 -0
- package/components/Infotip/InfotipIcon.jsx +41 -0
- package/components/Infotip/index.js +3 -0
- package/components/Link/Link.stories.js +81 -0
- package/components/Link/index.js +61 -0
- package/components/Modal/LegacyModal.jsx +72 -0
- package/components/Modal/Modal.jsx +140 -0
- package/components/Modal/Modal.stories.js +159 -0
- package/components/Modal/index.jsx +22 -0
- package/components/NotificationBanner/NotificationBanner.stories.js +23 -0
- package/components/NotificationBanner/index.js +265 -0
- package/components/SanitizedContent/index.jsx +200 -0
- package/components/Search/Search.stories.js +21 -0
- package/components/Search/index.js +85 -0
- package/components/SessionDialog/sessionDialog.js +26 -0
- package/components/SessionDialogUI.jsx +261 -0
- package/components/SideNav/AnimationGroup/AnimationGroup.jsx +27 -0
- package/components/SideNav/Chart/ScoreChart.jsx +268 -0
- package/components/SideNav/Chart/__tests__/ScoreChart.test.js +22 -0
- package/components/SideNav/Chart/__tests__/__snapshots__/ScoreChart.test.js.snap +173 -0
- package/components/SideNav/Chart/index.js +3 -0
- package/components/SideNav/Content/LevelOneContent.jsx +208 -0
- package/components/SideNav/Content/LevelTwoContent.jsx +216 -0
- package/components/SideNav/Content/index.js +4 -0
- package/components/SideNav/Details/IndividualDetails.jsx +18 -0
- package/components/SideNav/Details/PracticeDetails.jsx +45 -0
- package/components/SideNav/Details/index.js +4 -0
- package/components/SideNav/Links/CmsSwitchLink.jsx +41 -0
- package/components/SideNav/Links/NavItemInline.jsx +54 -0
- package/components/SideNav/Links/NavLinkContainer.jsx +38 -0
- package/components/SideNav/Links/NavLinkDrawer.jsx +249 -0
- package/components/SideNav/Links/NavLinkInline.jsx +107 -0
- package/components/SideNav/Links/NavLinkToggle.jsx +34 -0
- package/components/SideNav/Links/index.js +13 -0
- package/components/SideNav/SideNav.md +50 -0
- package/components/SideNav/SideNav.stories.js +379 -0
- package/components/SideNav/UI/SideNavUI.jsx +333 -0
- package/components/SideNav/UI/default-content.json +99 -0
- package/components/SideNav/UI/index.js +3 -0
- package/components/SideNav/helpers.js +49 -0
- package/components/SideNav/index.js +53 -0
- package/components/Spinner/index.js +9 -0
- package/components/Tabs/Tab.js +26 -0
- package/components/Tabs/TabPanel.js +34 -0
- package/components/Tabs/Tabs.stories.js +120 -0
- package/components/Tabs/index.js +95 -0
- package/components/TextInput/TextInput.stories.js +118 -0
- package/components/TextInput/index.js +137 -0
- package/components/Tooltip/Tooltip.jsx +88 -0
- package/components/Tooltip/Tooltip.stories.js +80 -0
- package/components/Tooltip/index.js +3 -0
- package/components/Tooltip/position.js +68 -0
- package/components/UnwrappedSpinner/index.js +8 -0
- package/components/hooks/useGetConfig.js +74 -0
- package/components/index.js +126 -0
- package/dist/browser.js +3 -0
- package/dist/browser.js.LICENSE.txt +54 -0
- package/dist/browser.js.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.LICENSE.txt +54 -0
- package/dist/index.js.map +1 -0
- package/dist/react/index.js +3 -0
- package/dist/react/index.js.LICENSE.txt +71 -0
- package/dist/react/index.js.map +1 -0
- package/fonts/FontAwesome.otf +0 -0
- package/fonts/OFL.txt +92 -0
- package/fonts/Rubik-Black.ttf +0 -0
- package/fonts/Rubik-BlackItalic.ttf +0 -0
- package/fonts/Rubik-Bold.ttf +0 -0
- package/fonts/Rubik-BoldItalic.ttf +0 -0
- package/fonts/Rubik-Italic.ttf +0 -0
- package/fonts/Rubik-Light.ttf +0 -0
- package/fonts/Rubik-LightItalic.ttf +0 -0
- package/fonts/Rubik-Medium.ttf +0 -0
- package/fonts/Rubik-MediumItalic.ttf +0 -0
- package/fonts/Rubik-Regular.ttf +0 -0
- package/fonts/fontawesome-webfont.eot +0 -0
- package/fonts/fontawesome-webfont.svg +2671 -0
- package/fonts/fontawesome-webfont.ttf +0 -0
- package/fonts/fontawesome-webfont.woff +0 -0
- package/fonts/fontawesome-webfont.woff2 +0 -0
- package/images/favicon/android-chrome-192x192.png +0 -0
- package/images/favicon/android-chrome-256x256.png +0 -0
- package/images/favicon/apple-touch-icon.png +0 -0
- package/images/favicon/browserconfig.xml +9 -0
- package/images/favicon/favicon-16x16.png +0 -0
- package/images/favicon/favicon-32x32.png +0 -0
- package/images/favicon/favicon.ico +0 -0
- package/images/favicon/manifest.json +18 -0
- package/images/favicon/mstile-150x150.png +0 -0
- package/images/favicon/safari-pinned-tab.svg +32 -0
- package/images/hhs-logo-black.svg +10 -0
- package/images/hhs-logo-white.svg +10 -0
- package/images/icons/close-x.svg +6 -0
- package/images/icons/help-headset.svg +21 -0
- package/images/icons/svg/arrow-down.svg +1 -0
- package/images/icons/svg/arrow-download.svg +1 -0
- package/images/icons/svg/arrow-right.svg +1 -0
- package/images/icons/svg/calendar.svg +1 -0
- package/images/icons/svg/close.svg +1 -0
- package/images/icons/svg/download.svg +1 -0
- package/images/icons/svg/external.svg +1 -0
- package/images/icons/svg/file-upload.svg +1 -0
- package/images/icons/svg/print.svg +1 -0
- package/images/icons/svg/search.svg +7 -0
- package/images/icons/svg/tooltip-question.svg +6 -0
- package/images/icons/svg/trash.svg +1 -0
- package/images/icons/svg/upload.svg +1 -0
- package/images/qpp_logo_reversed.png +0 -0
- package/images/qpp_logo_rgb_color.png +0 -0
- package/index.js +31 -0
- package/jest/mediaFileTransformer.js +9 -0
- package/jest.config.js +188 -0
- package/lib/Chevron.jsx +32 -0
- package/lib/SvgComponents.jsx +539 -0
- package/lib/svg-definitions.svg +125 -0
- package/package.json +125 -0
- package/session/index.js +5 -0
- package/session/logout.js +65 -0
- package/session/refresh.js +49 -0
- package/session/ttl.js +37 -0
- package/styles/_global.scss +106 -0
- package/styles/_main.scss +15 -0
- package/styles/_paths.scss +1 -0
- package/styles/_qpp-style.scss +31 -0
- package/styles/components/_accordion.scss +289 -0
- package/styles/components/_alerts.scss +54 -0
- package/styles/components/_autocomplete.scss +47 -0
- package/styles/components/_breadcrumbs.scss +64 -0
- package/styles/components/_buttons.scss +580 -0
- package/styles/components/_error-page.scss +56 -0
- package/styles/components/_flash-notification.scss +98 -0
- package/styles/components/_fonts.scss +42 -0
- package/styles/components/_forms.scss +277 -0
- package/styles/components/_grid.scss +37 -0
- package/styles/components/_info-modal.scss +139 -0
- package/styles/components/_links.scss +12 -0
- package/styles/components/_modals.scss +18 -0
- package/styles/components/_notification-banner.scss +165 -0
- package/styles/components/_panels.scss +61 -0
- package/styles/components/_pie-chart.scss +13 -0
- package/styles/components/_score-chart.scss +164 -0
- package/styles/components/_spinner.scss +7 -0
- package/styles/components/_tables.scss +111 -0
- package/styles/components/_tabs.scss +69 -0
- package/styles/components/_text.scss +150 -0
- package/styles/components/_toggles.scss +3 -0
- package/styles/components/_tooltip.scss +23 -0
- package/styles/components/_variables.scss +157 -0
- package/styles/components/_wells.scss +92 -0
- package/styles/qppds/README.md +0 -0
- package/styles/qppds/base/_backgrounds.scss +7 -0
- package/styles/qppds/base/_fonts.scss +26 -0
- package/styles/qppds/base/_icon.scss +23 -0
- package/styles/qppds/base/_layout.scss +5 -0
- package/styles/qppds/base/_typography.scss +85 -0
- package/styles/qppds/base/index.scss +8 -0
- package/styles/qppds/components/_alert.scss +95 -0
- package/styles/qppds/components/_breadcrumbs.scss +70 -0
- package/styles/qppds/components/_button.scss +292 -0
- package/styles/qppds/components/_card.scss +175 -0
- package/styles/qppds/components/_dropdown.scss +55 -0
- package/styles/qppds/components/_footer.scss +597 -0
- package/styles/qppds/components/_header.scss +892 -0
- package/styles/qppds/components/_link.scss +52 -0
- package/styles/qppds/components/_modal.scss +118 -0
- package/styles/qppds/components/_page-header.scss +67 -0
- package/styles/qppds/components/_pagination.scss +227 -0
- package/styles/qppds/components/_search.scss +112 -0
- package/styles/qppds/components/_sidebar.scss +9 -0
- package/styles/qppds/components/_table.scss +139 -0
- package/styles/qppds/components/_tabs.scss +197 -0
- package/styles/qppds/components/_text-input.scss +60 -0
- package/styles/qppds/components/index.scss +16 -0
- package/styles/qppds/components/sidebar/_animations.scss +38 -0
- package/styles/qppds/components/sidebar/_cms.scss +61 -0
- package/styles/qppds/components/sidebar/_details.scss +58 -0
- package/styles/qppds/components/sidebar/_links.scss +444 -0
- package/styles/qppds/components/sidebar/_sidebar-animation.scss +125 -0
- package/styles/qppds/components/sidebar/_sidebar-tooltip.scss +33 -0
- package/styles/qppds/components/sidebar/_sidebar.scss +146 -0
- package/styles/qppds/components/sidebar/project-specific/_wi.scss +42 -0
- package/styles/qppds/index.scss +4 -0
- package/styles/qppds/settings/_functions.scss +4 -0
- package/styles/qppds/settings/_index.scss +3 -0
- package/styles/qppds/settings/mixins/_borders.scss +6 -0
- package/styles/qppds/settings/mixins/_focus.scss +28 -0
- package/styles/qppds/settings/mixins/_icons.scss +33 -0
- package/styles/qppds/settings/mixins/_index.scss +8 -0
- package/styles/qppds/settings/mixins/_layout.scss +74 -0
- package/styles/qppds/settings/mixins/_lists.scss +12 -0
- package/styles/qppds/settings/mixins/_table.scss +91 -0
- package/styles/qppds/settings/mixins/_type.scss +65 -0
- package/styles/qppds/settings/mixins/_visually-hidden.scss +30 -0
- package/styles/qppds/settings/variables/_color.scss +86 -0
- package/styles/qppds/settings/variables/_index.scss +3 -0
- package/styles/qppds/settings/variables/_layout.scss +67 -0
- package/styles/qppds/settings/variables/_type.scss +132 -0
- package/styles/qppds/utilities/_background-color.scss +134 -0
- package/styles/qppds/utilities/_color.scss +32 -0
- package/styles/qppds/utilities/_display-visibility.scss +83 -0
- package/styles/qppds/utilities/_flexbox.scss +240 -0
- package/styles/qppds/utilities/_font-family.scss +9 -0
- package/styles/qppds/utilities/_font-size.scss +8 -0
- package/styles/qppds/utilities/_font-weight.scss +8 -0
- package/styles/qppds/utilities/_height.scss +38 -0
- package/styles/qppds/utilities/_margin.scss +136 -0
- package/styles/qppds/utilities/_padding.scss +76 -0
- package/styles/qppds/utilities/_position.scss +24 -0
- package/styles/qppds/utilities/_text-align.scss +40 -0
- package/styles/qppds/utilities/_text-transform.scss +7 -0
- package/styles/qppds/utilities/_truncate.scss +8 -0
- package/styles/qppds/utilities/_width.scss +79 -0
- package/styles/qppds/utilities/index.scss +15 -0
- package/styles/qppds.scss +2 -0
- package/styles/third-party/_legacy-bootstrap.scss +19 -0
- package/styles/third-party/legacy-bootstrap/_buttons.scss +126 -0
- package/styles/third-party/legacy-bootstrap/_dropdowns.scss +211 -0
- package/styles/third-party/legacy-bootstrap/_forms.scss +510 -0
- package/styles/third-party/legacy-bootstrap/_grid.scss +73 -0
- package/styles/third-party/legacy-bootstrap/_mixins.scss +27 -0
- package/styles/third-party/legacy-bootstrap/_navbar.scss +644 -0
- package/styles/third-party/legacy-bootstrap/_navs.scss +193 -0
- package/styles/third-party/legacy-bootstrap/_normalize.scss +385 -0
- package/styles/third-party/legacy-bootstrap/_scaffolding.scss +116 -0
- package/styles/third-party/legacy-bootstrap/_variables.scss +858 -0
- package/styles/third-party/legacy-bootstrap/mixins/_buttons.scss +70 -0
- package/styles/third-party/legacy-bootstrap/mixins/_clearfix.scss +22 -0
- package/styles/third-party/legacy-bootstrap/mixins/_forms.scss +108 -0
- package/styles/third-party/legacy-bootstrap/mixins/_grid-framework.scss +86 -0
- package/styles/third-party/legacy-bootstrap/mixins/_grid.scss +112 -0
- package/styles/third-party/legacy-bootstrap/mixins/_labels.scss +12 -0
- package/styles/third-party/legacy-bootstrap/mixins/_nav-divider.scss +10 -0
- package/styles/third-party/legacy-bootstrap/mixins/_nav-vertical-align.scss +9 -0
- package/styles/third-party/legacy-bootstrap/mixins/_opacity.scss +7 -0
- package/styles/third-party/legacy-bootstrap/mixins/_panels.scss +30 -0
- package/styles/third-party/legacy-bootstrap/mixins/_reset-filter.scss +7 -0
- package/styles/third-party/legacy-bootstrap/mixins/_reset-text.scss +18 -0
- package/styles/third-party/legacy-bootstrap/mixins/_resize.scss +6 -0
- package/styles/third-party/legacy-bootstrap/mixins/_responsive-visibility.scss +25 -0
- package/styles/third-party/legacy-bootstrap/mixins/_size.scss +10 -0
- package/styles/third-party/legacy-bootstrap/mixins/_tab-focus.scss +9 -0
- package/styles/third-party/legacy-bootstrap/mixins/_table-row.scss +28 -0
- package/styles/third-party/legacy-bootstrap/mixins/_text-emphasis.scss +12 -0
- package/styles/third-party/legacy-bootstrap/mixins/_text-overflow.scss +8 -0
- package/styles/third-party/legacy-bootstrap/mixins/_vendor-prefixes.scss +182 -0
- package/styles/utility/_mixins.scss +46 -0
- package/styles/utility/_utilities.scss +73 -0
- package/test/components/Accordion.test.js +12 -0
- package/test/components/ErrorUI.test.js +33 -0
- package/test/components/FooterUI.test.js +90 -0
- package/test/components/HeaderUI.test.js +45 -0
- package/test/components/Infotip.test.js +73 -0
- package/test/components/SessionDialogUI.test.js +339 -0
- package/test/components/SideNavUI.test.js +23 -0
- package/test/components/Tooltip.test.js +147 -0
- package/test/index.test.js +8 -0
- package/test/session/session.test.js +221 -0
- package/test-setup.js +9 -0
- package/webpack.config.js +147 -0
- package/webpack.config.react.js +86 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import React, { Component } from 'react';
|
|
2
|
+
import { render } from 'react-dom';
|
|
3
|
+
import ReactModal from 'react-modal';
|
|
4
|
+
import { CloseXIcon } from '../../lib/SvgComponents.jsx';
|
|
5
|
+
import SanitizedContent from '../SanitizedContent';
|
|
6
|
+
import PropTypes from 'prop-types';
|
|
7
|
+
|
|
8
|
+
class Modal extends Component {
|
|
9
|
+
constructor() {
|
|
10
|
+
super();
|
|
11
|
+
|
|
12
|
+
this.state = {
|
|
13
|
+
showModal: true,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
this.handleOpenModal = this.handleOpenModal.bind(this);
|
|
17
|
+
this.handleCloseModal = this.handleCloseModal.bind(this);
|
|
18
|
+
|
|
19
|
+
ReactModal.setAppElement('body > *:not(.ReactModalPortal)');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
handleOpenModal() {
|
|
23
|
+
this.setState({ showModal: true });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
handleCloseModal() {
|
|
27
|
+
this.setState({ showModal: false });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
UNSAFE_componentWillReceiveProps(newProps) {
|
|
31
|
+
this.setState({
|
|
32
|
+
showModal: newProps.showModal,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
render() {
|
|
37
|
+
return (
|
|
38
|
+
<div>
|
|
39
|
+
<ReactModal
|
|
40
|
+
role="alertdialog"
|
|
41
|
+
contentLabel={this.props.contentLabel || 'Informational Modal Dialog'}
|
|
42
|
+
isOpen={this.state.showModal}
|
|
43
|
+
className="info-modal-content"
|
|
44
|
+
overlayClassName="info-modal-overlay"
|
|
45
|
+
onRequestClose={this.handleCloseModal}
|
|
46
|
+
>
|
|
47
|
+
<button
|
|
48
|
+
className="closeModal"
|
|
49
|
+
aria-label="Close modal"
|
|
50
|
+
onClick={this.handleCloseModal}
|
|
51
|
+
>
|
|
52
|
+
<svg className="close-icon" aria-hidden="true">
|
|
53
|
+
<CloseXIcon />
|
|
54
|
+
</svg>
|
|
55
|
+
</button>
|
|
56
|
+
<SanitizedContent html={this.props.content} />
|
|
57
|
+
</ReactModal>
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const displayModal = ({ content, main }) => {
|
|
64
|
+
render(<Modal content={content} showModal={true} />, main);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
Modal.propTypes = {
|
|
68
|
+
contentLabel: PropTypes.string,
|
|
69
|
+
content: PropTypes.string,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export default displayModal;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import React, { useRef, useState, useEffect } from 'react';
|
|
2
|
+
import ReactModal from 'react-modal';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
|
|
5
|
+
import { CloseXIcon2 } from '../../lib/SvgComponents.jsx';
|
|
6
|
+
|
|
7
|
+
const Modal = ({
|
|
8
|
+
children,
|
|
9
|
+
onRequestClose,
|
|
10
|
+
title,
|
|
11
|
+
primary,
|
|
12
|
+
secondary,
|
|
13
|
+
appElement,
|
|
14
|
+
isOpen,
|
|
15
|
+
...props
|
|
16
|
+
}) => {
|
|
17
|
+
const [overflowSeparator, setOverflowSeparator] = useState(false);
|
|
18
|
+
const closeButtonRef = useRef(null);
|
|
19
|
+
const contentRef = useRef(null);
|
|
20
|
+
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
ReactModal.setAppElement(appElement);
|
|
23
|
+
}, []);
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<ReactModal
|
|
27
|
+
onRequestClose={onRequestClose}
|
|
28
|
+
portalClassName="qpp-c-modal"
|
|
29
|
+
className="qpp-c-modal__content"
|
|
30
|
+
overlayClassName="qpp-c-modal__overlay"
|
|
31
|
+
bodyOpenClassName="qpp-c-modal__body-open"
|
|
32
|
+
isOpen={isOpen}
|
|
33
|
+
onAfterOpen={() => {
|
|
34
|
+
// Add heading separator based on overflow
|
|
35
|
+
if (
|
|
36
|
+
contentRef.current?.scrollHeight >
|
|
37
|
+
document.documentElement.clientHeight * 0.6
|
|
38
|
+
) {
|
|
39
|
+
setOverflowSeparator(true);
|
|
40
|
+
} else {
|
|
41
|
+
setOverflowSeparator(false);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Set default focus
|
|
45
|
+
if (closeButtonRef?.current) {
|
|
46
|
+
closeButtonRef.current.focus();
|
|
47
|
+
}
|
|
48
|
+
}}
|
|
49
|
+
aria={{
|
|
50
|
+
labelledby: 'modal-heading',
|
|
51
|
+
describedby: 'modal-body',
|
|
52
|
+
}}
|
|
53
|
+
{...props}
|
|
54
|
+
>
|
|
55
|
+
<div
|
|
56
|
+
className={`qpp-c-modal__header ${
|
|
57
|
+
overflowSeparator ? 'qpp-c-modal__header-sep' : ''
|
|
58
|
+
}`}
|
|
59
|
+
>
|
|
60
|
+
<h3 id="modal-heading">{title}</h3>
|
|
61
|
+
<button
|
|
62
|
+
className="closex qpp-c-button qpp-c-button--text qpp-u-color--black"
|
|
63
|
+
aria-label="close modal"
|
|
64
|
+
data-testid="modal-close-btn"
|
|
65
|
+
onClick={onRequestClose}
|
|
66
|
+
ref={closeButtonRef}
|
|
67
|
+
>
|
|
68
|
+
<CloseXIcon2 />
|
|
69
|
+
</button>
|
|
70
|
+
</div>
|
|
71
|
+
<div
|
|
72
|
+
id="modal-body"
|
|
73
|
+
className="qpp-c-modal__body"
|
|
74
|
+
ref={contentRef}
|
|
75
|
+
tabIndex={overflowSeparator ? "0" : undefined}
|
|
76
|
+
>
|
|
77
|
+
{children}
|
|
78
|
+
</div>
|
|
79
|
+
{(primary || secondary) && (
|
|
80
|
+
<div className="qpp-c-modal__footer">
|
|
81
|
+
{secondary && (
|
|
82
|
+
<button
|
|
83
|
+
className={`qpp-c-button qpp-c-button--secondary ${
|
|
84
|
+
primary ? 'qpp-u-margin-right--16' : ''
|
|
85
|
+
}`}
|
|
86
|
+
loading={secondary.loading}
|
|
87
|
+
onClick={secondary.onClick || onRequestClose}
|
|
88
|
+
aria-label={secondary.title}
|
|
89
|
+
data-testid="modal-secondary-btn"
|
|
90
|
+
>
|
|
91
|
+
{secondary.title}
|
|
92
|
+
</button>
|
|
93
|
+
)}
|
|
94
|
+
{primary && (
|
|
95
|
+
<button
|
|
96
|
+
className="qpp-c-button"
|
|
97
|
+
loading={primary.loading}
|
|
98
|
+
onClick={primary.onClick}
|
|
99
|
+
data-testid="modal-primary-btn"
|
|
100
|
+
aria-label={primary.title}
|
|
101
|
+
>
|
|
102
|
+
{primary.title}
|
|
103
|
+
</button>
|
|
104
|
+
)}
|
|
105
|
+
</div>
|
|
106
|
+
)}
|
|
107
|
+
</ReactModal>
|
|
108
|
+
);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
Modal.propTypes = {
|
|
112
|
+
title: PropTypes.string,
|
|
113
|
+
children: PropTypes.node.isRequired,
|
|
114
|
+
primary: PropTypes.shape({
|
|
115
|
+
title: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
|
|
116
|
+
onClick: PropTypes.func,
|
|
117
|
+
loading: PropTypes.bool,
|
|
118
|
+
loadingText: PropTypes.string,
|
|
119
|
+
}),
|
|
120
|
+
secondary: PropTypes.shape({
|
|
121
|
+
title: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
|
|
122
|
+
onClick: PropTypes.func,
|
|
123
|
+
loading: PropTypes.bool,
|
|
124
|
+
loadingText: PropTypes.string,
|
|
125
|
+
}),
|
|
126
|
+
onRequestClose: PropTypes.func,
|
|
127
|
+
appElement: PropTypes.string,
|
|
128
|
+
isOpen: PropTypes.bool,
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
Modal.defaultProps = {
|
|
132
|
+
onRequestClose: () => {},
|
|
133
|
+
title: undefined,
|
|
134
|
+
primary: null,
|
|
135
|
+
secondary: null,
|
|
136
|
+
appElement: 'body > *:not(.qpp-c-modal)',
|
|
137
|
+
isOpen: false,
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
export default Modal;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import Modal from './index';
|
|
3
|
+
import { withKnobs, boolean, text } from '@storybook/addon-knobs';
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'Modal',
|
|
7
|
+
component: Modal,
|
|
8
|
+
decorators: [withKnobs],
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const useModal = () => {
|
|
12
|
+
const [open, setOpen] = useState(false);
|
|
13
|
+
const openModal = () => setOpen(true);
|
|
14
|
+
const closeModal = () => setOpen(false);
|
|
15
|
+
return [open, openModal, closeModal];
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const WithDesignSystem = () => {
|
|
19
|
+
const [open, openModal, closeModal] = useModal();
|
|
20
|
+
const knobIsOpen = boolean('isOpen', false);
|
|
21
|
+
return (
|
|
22
|
+
<div className="qpp-u-padding--12">
|
|
23
|
+
<button className="qpp-c-button" onClick={openModal}>
|
|
24
|
+
Open Modal
|
|
25
|
+
</button>
|
|
26
|
+
<Modal
|
|
27
|
+
useDesignSystem
|
|
28
|
+
isOpen={open || knobIsOpen}
|
|
29
|
+
title={text('Title text', 'Title Text')}
|
|
30
|
+
onRequestClose={closeModal}
|
|
31
|
+
>
|
|
32
|
+
<p>
|
|
33
|
+
{text(
|
|
34
|
+
'bodyText',
|
|
35
|
+
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus ac pulvinar massa, in mattis ligula. Vestibulum enim velit, ullamcorper vitae lorem ullamcorper, blandit fringilla mauris.'
|
|
36
|
+
)}
|
|
37
|
+
</p>
|
|
38
|
+
</Modal>
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const WithDesignSystemDialog = () => {
|
|
44
|
+
const [open, openModal, closeModal] = useModal();
|
|
45
|
+
const knobIsOpen = boolean('isOpen', false);
|
|
46
|
+
return (
|
|
47
|
+
<div className="qpp-u-padding--12">
|
|
48
|
+
<button className="qpp-c-button" onClick={openModal}>
|
|
49
|
+
Open Modal
|
|
50
|
+
</button>
|
|
51
|
+
<Modal
|
|
52
|
+
useDesignSystem
|
|
53
|
+
isOpen={open || knobIsOpen}
|
|
54
|
+
title={text('Title text', 'Title Text')}
|
|
55
|
+
onRequestClose={closeModal}
|
|
56
|
+
primary={{
|
|
57
|
+
title: 'Yes, go for it',
|
|
58
|
+
onClick: () => {
|
|
59
|
+
console.log('submit');
|
|
60
|
+
closeModal();
|
|
61
|
+
},
|
|
62
|
+
}}
|
|
63
|
+
secondary={{
|
|
64
|
+
title: 'No, take me back',
|
|
65
|
+
}}
|
|
66
|
+
>
|
|
67
|
+
<p>
|
|
68
|
+
{text(
|
|
69
|
+
'bodyText',
|
|
70
|
+
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus ac pulvinar massa, in mattis ligula. Vestibulum enim velit, ullamcorper vitae lorem ullamcorper, blandit fringilla mauris.'
|
|
71
|
+
)}
|
|
72
|
+
</p>
|
|
73
|
+
</Modal>
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const WithDesignSystemOverflow = () => {
|
|
79
|
+
const [open, openModal, closeModal] = useModal();
|
|
80
|
+
const knobIsOpen = boolean('isOpen', false);
|
|
81
|
+
return (
|
|
82
|
+
<div className="qpp-u-padding--12">
|
|
83
|
+
<button className="qpp-c-button" onClick={openModal}>
|
|
84
|
+
Open Modal
|
|
85
|
+
</button>
|
|
86
|
+
<Modal
|
|
87
|
+
useDesignSystem
|
|
88
|
+
isOpen={open || knobIsOpen}
|
|
89
|
+
title={text('Title text', 'Title Text')}
|
|
90
|
+
onRequestClose={closeModal}
|
|
91
|
+
primary={{
|
|
92
|
+
title: 'Yes, go for it',
|
|
93
|
+
onClick: () => {
|
|
94
|
+
console.log('submit');
|
|
95
|
+
closeModal();
|
|
96
|
+
},
|
|
97
|
+
}}
|
|
98
|
+
secondary={{
|
|
99
|
+
title: 'No, take me back',
|
|
100
|
+
}}
|
|
101
|
+
>
|
|
102
|
+
<p>
|
|
103
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus ac
|
|
104
|
+
pulvinar massa, in mattis ligula. Vestibulum enim velit, ullamcorper
|
|
105
|
+
vitae lorem ullamcorper, blandit fringilla mauris. Aenean odio nulla,
|
|
106
|
+
dapibus convallis est ac, tempor congue lorem. Aliquam facilisis
|
|
107
|
+
tortor eget lectus gravida bibendum. Suspendisse vel posuere risus.
|
|
108
|
+
Etiam condimentum sollicitudin est, eget auctor lectus suscipit nec.
|
|
109
|
+
Duis efficitur vitae risus at malesuada. Mauris tempus turpis sed
|
|
110
|
+
lacus lacinia, et mattis tortor eleifend. In sit amet felis vel quam
|
|
111
|
+
egestas ultricies ac ac nisl. Morbi elementum dui libero, non
|
|
112
|
+
convallis risus ornare vel. Maecenas posuere ipsum ut sem aliquet,
|
|
113
|
+
quis maximus dolor cursus. Praesent vulputate orci tellus, sed
|
|
114
|
+
fringilla arcu mollis sit amet. Phasellus eros turpis, consequat sit
|
|
115
|
+
amet placerat sed, mollis ac justo.
|
|
116
|
+
</p>
|
|
117
|
+
<p>
|
|
118
|
+
Cras quis pharetra elit. Mauris lacinia quam quis metus mattis
|
|
119
|
+
lobortis vel nec arcu. Fusce nec tellus vel nunc cursus vestibulum.
|
|
120
|
+
Quisque pretium, arcu at sagittis posuere, leo magna tempus nunc, vel
|
|
121
|
+
malesuada nunc mauris ac ante. Donec arcu velit, imperdiet vitae purus
|
|
122
|
+
nec, imperdiet auctor nisi. Cras ornare, elit sit amet viverra
|
|
123
|
+
bibendum, justo dolor congue mi, quis pretium erat orci a lorem. Sed
|
|
124
|
+
rhoncus quam ut tellus hendrerit accumsan.
|
|
125
|
+
</p>
|
|
126
|
+
<p>
|
|
127
|
+
Donec varius elit vitae elit efficitur fermentum. Vestibulum ante
|
|
128
|
+
ipsum primis in faucibus orci luctus et ultrices posuere cubilia
|
|
129
|
+
curae; Nulla facilisi. Ut malesuada venenatis varius. Nunc libero
|
|
130
|
+
massa, luctus sagittis sapien ultrices, pulvinar venenatis purus. In
|
|
131
|
+
nec orci ac nibh sagittis lobortis vel sed massa. Morbi pretium odio
|
|
132
|
+
vitae malesuada ullamcorper. Pellentesque facilisis posuere
|
|
133
|
+
consectetur. Nam maximus finibus ante, non eleifend neque euismod et.
|
|
134
|
+
</p>
|
|
135
|
+
<p>
|
|
136
|
+
Pellentesque vehicula nec massa nec accumsan. Pellentesque non odio eu
|
|
137
|
+
felis hendrerit pellentesque non sed neque. Morbi dui nisl, facilisis
|
|
138
|
+
id gravida non, vehicula at dui. In eleifend suscipit imperdiet.
|
|
139
|
+
Quisque facilisis augue et mi lobortis tristique. Praesent auctor
|
|
140
|
+
dictum erat, non mollis ante tempus id. Integer et libero iaculis,
|
|
141
|
+
imperdiet neque at, pharetra nisl. Suspendisse diam massa, vehicula eu
|
|
142
|
+
varius ullamcorper, semper vel velit. Morbi consequat mattis nisi, id
|
|
143
|
+
dignissim est bibendum non. Suspendisse semper laoreet neque, ac
|
|
144
|
+
tincidunt tortor. Ut posuere urna a convallis consectetur. Mauris
|
|
145
|
+
varius cursus libero sed molestie. Duis id dignissim arcu. Mauris
|
|
146
|
+
tincidunt egestas congue.
|
|
147
|
+
</p>
|
|
148
|
+
<p>
|
|
149
|
+
Donec rutrum erat vitae nulla ultricies, quis laoreet orci consequat.
|
|
150
|
+
Nunc et justo volutpat dolor feugiat convallis. Vivamus efficitur nisi
|
|
151
|
+
quis risus eleifend, ut tincidunt turpis volutpat. Nam commodo turpis
|
|
152
|
+
dolor, dapibus rutrum erat facilisis a. Ut a dictum urna. Maecenas vel
|
|
153
|
+
egestas odio. Ut venenatis est dolor, eget ullamcorper diam finibus
|
|
154
|
+
et. Proin tincidunt porta pellentesque.
|
|
155
|
+
</p>
|
|
156
|
+
</Modal>
|
|
157
|
+
</div>
|
|
158
|
+
);
|
|
159
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
|
|
4
|
+
import LegacyModal from './LegacyModal';
|
|
5
|
+
import DsModal from './Modal';
|
|
6
|
+
|
|
7
|
+
const Modal = ({ useDesignSystem, ...rest }) => {
|
|
8
|
+
if (useDesignSystem) {
|
|
9
|
+
return <DsModal {...rest} />;
|
|
10
|
+
}
|
|
11
|
+
return <LegacyModal {...rest} />;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
Modal.propTypes = {
|
|
15
|
+
useDesignSystem: PropTypes.bool,
|
|
16
|
+
};
|
|
17
|
+
Modal.defaultProps = {
|
|
18
|
+
useDesignSystem: false,
|
|
19
|
+
};
|
|
20
|
+
Modal.displayName = 'Modal';
|
|
21
|
+
|
|
22
|
+
export default Modal;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import NotificationBanner from './index';
|
|
3
|
+
import { withKnobs, boolean } from '@storybook/addon-knobs';
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'NotificationBanner',
|
|
7
|
+
component: NotificationBanner,
|
|
8
|
+
decorators: [withKnobs],
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const ExampleNotificationBanner = () => (
|
|
12
|
+
<NotificationBanner
|
|
13
|
+
result={{
|
|
14
|
+
content: 'CONTENT',
|
|
15
|
+
label: 'Label',
|
|
16
|
+
name: 'name',
|
|
17
|
+
color: 'blue',
|
|
18
|
+
dismissable: boolean('dismissable', false),
|
|
19
|
+
}}
|
|
20
|
+
/>
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
ExampleNotificationBanner.storyName = 'example NotificationBanner';
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import React, { Component } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
|
|
4
|
+
import SanitizedContent from '../SanitizedContent';
|
|
5
|
+
import { CloseXIcon, BellOutline } from '../../lib/SvgComponents.jsx';
|
|
6
|
+
import { withGetConfig } from '../hooks/useGetConfig';
|
|
7
|
+
|
|
8
|
+
class NotificationBanner extends Component {
|
|
9
|
+
constructor(props) {
|
|
10
|
+
super(props);
|
|
11
|
+
|
|
12
|
+
this.state = {
|
|
13
|
+
height: '100%',
|
|
14
|
+
expanded: true,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
this._renderCloseButton = this.renderCloseButton.bind(this);
|
|
18
|
+
this._collapseNotification = this.collapseNotification.bind(this);
|
|
19
|
+
this._expandNotification = this.expandNotification.bind(this);
|
|
20
|
+
this._setBannerHeight = this.setBannerHeight.bind(this);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
componentDidMount() {
|
|
24
|
+
if (window.innerWidth <= 767) {
|
|
25
|
+
this.setState({
|
|
26
|
+
expanded: false,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
window.addEventListener('load', this._setBannerHeight);
|
|
31
|
+
window.addEventListener('resize', this._setBannerHeight);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Populate state with notification from localStorage
|
|
35
|
+
componentDidUpdate(prevProps) {
|
|
36
|
+
if (prevProps.result !== this.props?.result) {
|
|
37
|
+
const { result: notifications } = this.props;
|
|
38
|
+
if (Object.keys(notifications).length > 0) {
|
|
39
|
+
this.setState({
|
|
40
|
+
expanded: this.isNotificationExpanded(notifications.content),
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
setBannerHeight() {
|
|
47
|
+
const {
|
|
48
|
+
result: {
|
|
49
|
+
content: { content },
|
|
50
|
+
},
|
|
51
|
+
} = this.props;
|
|
52
|
+
if (content) {
|
|
53
|
+
this.bannerContainer.style.transition = 'none';
|
|
54
|
+
|
|
55
|
+
this.state.expanded
|
|
56
|
+
? this.collapsedBanner.setAttribute('tabIndex', '-1')
|
|
57
|
+
: this.collapsedBanner.setAttribute('tabIndex', ' ');
|
|
58
|
+
|
|
59
|
+
this.setState({
|
|
60
|
+
height: this.state.expanded
|
|
61
|
+
? '100%'
|
|
62
|
+
: this.collapsedWrapper.offsetHeight + 'px',
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
isNotificationExpanded(notification) {
|
|
68
|
+
const dateDismissed = new Date(notification.dateDismissed);
|
|
69
|
+
const dateUpdated = new Date(notification.dateUpdated);
|
|
70
|
+
const notDismissed =
|
|
71
|
+
(this.isDateValid(dateUpdated) &&
|
|
72
|
+
this.isDateValid(dateDismissed) &&
|
|
73
|
+
dateUpdated >= dateDismissed) ||
|
|
74
|
+
!this.isDateValid(dateDismissed);
|
|
75
|
+
|
|
76
|
+
return notDismissed;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Whether the date is valid, i.e. not null
|
|
81
|
+
*
|
|
82
|
+
* @param {Date} date
|
|
83
|
+
* @return {Boolean}
|
|
84
|
+
*/
|
|
85
|
+
isDateValid(date) {
|
|
86
|
+
return !isNaN(Date.parse(date));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Try to find this NotificationBanner instance in localStorage, or else add
|
|
91
|
+
* a minimal version of it, and mark it with a dateDismissed, then update
|
|
92
|
+
* localStorage.
|
|
93
|
+
*/
|
|
94
|
+
markNotificationClosed() {
|
|
95
|
+
const { result } = this.props;
|
|
96
|
+
const dateDismissed = new Date().toISOString();
|
|
97
|
+
const storageNotification = result || {};
|
|
98
|
+
|
|
99
|
+
if (storageNotification && Object.keys(storageNotification).length > 0) {
|
|
100
|
+
window.localStorage.setItem(
|
|
101
|
+
'notifications',
|
|
102
|
+
JSON.stringify({
|
|
103
|
+
...storageNotification,
|
|
104
|
+
content: {
|
|
105
|
+
...storageNotification.content,
|
|
106
|
+
dateDismissed,
|
|
107
|
+
},
|
|
108
|
+
})
|
|
109
|
+
);
|
|
110
|
+
} else {
|
|
111
|
+
window.localStorage.setItem(
|
|
112
|
+
'notifications',
|
|
113
|
+
JSON.stringify({
|
|
114
|
+
...storageNotification,
|
|
115
|
+
content: {
|
|
116
|
+
name: 'header-notification',
|
|
117
|
+
dateDismissed,
|
|
118
|
+
},
|
|
119
|
+
})
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Callback when the user dimisses a notification. Mark it as dismissed in
|
|
126
|
+
* localStorage, empty the contents, and dispatch a custom event to notify
|
|
127
|
+
* any observers that it has been dismissed.
|
|
128
|
+
*/
|
|
129
|
+
collapseNotification(e) {
|
|
130
|
+
e.stopPropagation();
|
|
131
|
+
this.markNotificationClosed();
|
|
132
|
+
this.collapsedBanner.setAttribute('tabIndex', ' ');
|
|
133
|
+
this.bannerContainer.style.transition = 'height .2s ease-out';
|
|
134
|
+
this.setState({
|
|
135
|
+
expanded: false,
|
|
136
|
+
height: this.collapsedWrapper.offsetHeight + 'px',
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
expandNotification() {
|
|
141
|
+
if (!this.state.expanded) {
|
|
142
|
+
this.collapsedBanner.setAttribute('tabIndex', '-1');
|
|
143
|
+
this.bannerContainer.style.transition = 'height .2s ease-out';
|
|
144
|
+
this.setState({
|
|
145
|
+
expanded: true,
|
|
146
|
+
height: '100%',
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Renders the close button if the notification instance is dismissable.
|
|
153
|
+
*
|
|
154
|
+
* @return {String} HTML content
|
|
155
|
+
*/
|
|
156
|
+
renderCloseButton() {
|
|
157
|
+
const {
|
|
158
|
+
result: {
|
|
159
|
+
content: { dismissable },
|
|
160
|
+
},
|
|
161
|
+
} = this.props;
|
|
162
|
+
if (dismissable) {
|
|
163
|
+
return (
|
|
164
|
+
<button
|
|
165
|
+
onClick={this._collapseNotification}
|
|
166
|
+
type="button"
|
|
167
|
+
className="notification-banner-close"
|
|
168
|
+
>
|
|
169
|
+
<svg className="close-icon" aria-hidden="true" focusable="false">
|
|
170
|
+
<CloseXIcon />
|
|
171
|
+
</svg>
|
|
172
|
+
<span className="sr-only">Close</span>
|
|
173
|
+
</button>
|
|
174
|
+
);
|
|
175
|
+
} else {
|
|
176
|
+
return '';
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Render the notification if it has any contents.
|
|
182
|
+
*
|
|
183
|
+
* @return {String} HTML content
|
|
184
|
+
*/
|
|
185
|
+
render() {
|
|
186
|
+
const { expanded, height } = this.state;
|
|
187
|
+
const { result: { content: { enabled, content } = {} } = {} } = this.props;
|
|
188
|
+
if (!content || !enabled) {
|
|
189
|
+
return <div id="notification-banner" />;
|
|
190
|
+
} else {
|
|
191
|
+
const notificationStatus = expanded ? 'expanded' : 'collapsed';
|
|
192
|
+
const { color = 'blue', label = 'Update' } = content;
|
|
193
|
+
const className = `notification-banner notification-banner-${color} ${notificationStatus}`;
|
|
194
|
+
|
|
195
|
+
return (
|
|
196
|
+
<div
|
|
197
|
+
style={{ height }}
|
|
198
|
+
ref={(elem) => (this.bannerContainer = elem)}
|
|
199
|
+
className={className}
|
|
200
|
+
>
|
|
201
|
+
<div
|
|
202
|
+
ref={(elem) => (this.expandedWrapper = elem)}
|
|
203
|
+
className={`notification-banner-wrapper expanded-view`}
|
|
204
|
+
>
|
|
205
|
+
<div className="notification-banner-label">{label}</div>
|
|
206
|
+
<div className="notification-banner-content">
|
|
207
|
+
<SanitizedContent
|
|
208
|
+
html={expanded ? content : '<p>Nothing to see here</p>'}
|
|
209
|
+
/>
|
|
210
|
+
</div>
|
|
211
|
+
{expanded && this._renderCloseButton()}
|
|
212
|
+
</div>
|
|
213
|
+
|
|
214
|
+
<div
|
|
215
|
+
ref={(elem) => (this.collapsedWrapper = elem)}
|
|
216
|
+
className={`notification-banner-wrapper collapsed-view`}
|
|
217
|
+
onClick={this._expandNotification}
|
|
218
|
+
>
|
|
219
|
+
<button
|
|
220
|
+
ref={(elem) => (this.collapsedBanner = elem)}
|
|
221
|
+
className={`notification-banner-label`}
|
|
222
|
+
>
|
|
223
|
+
{label}
|
|
224
|
+
<span className="bell-icon">
|
|
225
|
+
<svg aria-hidden="true" focusable="false">
|
|
226
|
+
<BellOutline />
|
|
227
|
+
</svg>
|
|
228
|
+
</span>
|
|
229
|
+
</button>
|
|
230
|
+
</div>
|
|
231
|
+
</div>
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
NotificationBanner.propTypes = {
|
|
238
|
+
result: PropTypes.shape({
|
|
239
|
+
content: PropTypes.shape({
|
|
240
|
+
content: PropTypes.string,
|
|
241
|
+
label: PropTypes.string,
|
|
242
|
+
color: PropTypes.string,
|
|
243
|
+
dismissable: PropTypes.bool,
|
|
244
|
+
}),
|
|
245
|
+
}),
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
NotificationBanner.defaultProps = {
|
|
249
|
+
result: {
|
|
250
|
+
content: {
|
|
251
|
+
content: null,
|
|
252
|
+
label: 'Update',
|
|
253
|
+
color: 'blue',
|
|
254
|
+
dismissable: true,
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
export default withGetConfig(NotificationBanner, {
|
|
260
|
+
timeout: 5,
|
|
261
|
+
url: '/config/notification',
|
|
262
|
+
localStorageName: 'active_notification',
|
|
263
|
+
equalityCheckExclude: ['dateDismissed', 'dateUpdated'],
|
|
264
|
+
defaultContent: {},
|
|
265
|
+
});
|