@madie/madie-design-system 1.2.62 → 2.0.1
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 +14 -2
- package/.eslintrc.js +1 -1
- package/.storybook/.babelrc +2 -1
- package/.storybook/main.js +3 -11
- package/.storybook/preview.js +1 -1
- package/components/Accordion/index.jsx +32 -36
- package/components/AutoComplete/AutoComplete.jsx +2 -17
- package/components/Button/Button.stories.js +0 -7
- package/components/Button/index.js +34 -44
- package/components/DateField/DateField.jsx +2 -15
- package/components/DateField/DateField.stories.jsx +23 -10
- package/components/DateTimeField/DateTimeField.jsx +7 -11
- package/components/DateTimeField/DateTimeField.stories.jsx +29 -19
- package/components/InputLabel/index.jsx +1 -6
- package/components/Instant/Instant.stories.js +14 -6
- package/components/Instant/index.jsx +0 -16
- package/components/Link/index.js +14 -33
- package/components/MadieAlert/MadieAlert.stories.js +35 -29
- package/components/MadieAlert/index.jsx +5 -44
- package/components/MadieConfirmDialog/MadieConfirmDialog.stories.js +17 -32
- package/components/MadieConfirmDialog/index.jsx +0 -8
- package/components/MadieDeleteDialog/MadieDeleteDialog.stories.js +9 -24
- package/components/MadieDeleteDialog/index.jsx +0 -7
- package/components/MadieDialog/MadieDialog.stories.js +45 -121
- package/components/MadieDialog/index.jsx +4 -23
- package/components/MadieDiscardDialog/MadieDiscardDialog.stories.js +5 -12
- package/components/MadieDiscardDialog/index.jsx +0 -7
- package/components/MadieSpinner/MadieSpinner.stories.js +1 -9
- package/components/MadieSpinner/index.jsx +0 -5
- package/components/MadieTooltip/MadieTooltip.stories.js +7 -2
- package/components/MadieTooltip/index.jsx +0 -6
- package/components/MadieTooltipIcon/index.jsx +0 -5
- package/components/Modal/Modal.jsx +31 -43
- package/components/Modal/Modal.stories.js +18 -89
- package/components/Modal/index.jsx +6 -8
- package/components/NumberInput/NumberInput.stories.js +50 -67
- package/components/NumberInput/index.jsx +0 -13
- package/components/Pagination/index.jsx +0 -17
- package/components/Popover/Popover.stories.js +6 -14
- package/components/Popover/index.js +0 -23
- package/components/RadioButton/RadioButton.jsx +5 -15
- package/components/RadioButton/RadioButton.stories.jsx +6 -2
- package/components/ReadOnlyTextField/ReadOnlyTextField.stories.js +3 -8
- package/components/ReadOnlyTextField/index.jsx +1 -9
- package/components/RichTextEditor/RichTextEditor.stories.js +10 -8
- package/components/RichTextEditor/index.jsx +14 -30
- package/components/SanitizedContent/index.jsx +0 -8
- package/components/Search/Search.stories.js +2 -4
- package/components/Search/index.js +26 -40
- package/components/Select/Select.stories.js +59 -164
- package/components/Select/index.jsx +2 -17
- package/components/Tabs/Tab.js +29 -25
- package/components/Tabs/TabPanel.js +15 -19
- package/components/Tabs/Tabs.stories.js +43 -211
- package/components/Tabs/index.js +10 -28
- package/components/TextArea/TextArea.stories.js +87 -113
- package/components/TextArea/index.jsx +2 -14
- package/components/TextField/TextField.stories.js +100 -129
- package/components/TextField/index.jsx +2 -17
- package/components/TimeField/TimeField.jsx +0 -10
- package/components/TimeField/TimeField.stories.js +18 -8
- package/components/Toast/Toast.stories.js +42 -102
- package/components/Toast/index.jsx +0 -14
- package/components/TruncateText/TruncateText.stories.js +22 -17
- package/components/TruncateText/index.js +0 -8
- package/components/hooks/useGetConfig.js +2 -2
- package/components/{index.js → index.mjs} +37 -57
- package/dist/index.js +3 -1
- package/dist/index.js.LICENSE.txt +16 -0
- package/dist/index.js.map +1 -0
- package/dist/react/index.html +1 -1
- package/dist/react/index.mjs +103 -0
- package/dist/react/{index.js.LICENSE.txt → index.mjs.LICENSE.txt} +3 -52
- package/dist/react/index.mjs.map +1 -0
- package/dist/react/package.json +1 -0
- package/eslint.config.cjs +59 -0
- package/index.js +7 -9
- package/jest.config.mjs +10 -0
- package/lib/Chevron.jsx +2 -10
- package/package.json +57 -82
- package/styles/_main.scss +4 -3
- package/test/components/Accordion.test.js +1 -1
- package/test/components/AutoComplete.test.js +11 -6
- package/test/components/Button.test.js +13 -19
- package/test/components/DateField.test.js +25 -29
- package/test/components/DateTimeField.test.js +21 -25
- package/test/components/Instant.test.js +1 -1
- package/test/components/MadieAlert.test.js +22 -22
- package/test/components/MadieConfirmDialog.test.js +42 -64
- package/test/components/MadieDeleteDialog.test.js +51 -69
- package/test/components/MadieDialog.test.js +13 -13
- package/test/components/MadieDiscardDialog.test.js +28 -45
- package/test/components/MadieSpinner.test.js +12 -17
- package/test/components/Modal.test.js +115 -0
- package/test/components/Pagination.test.js +2 -2
- package/test/components/RadioButton.test.js +7 -7
- package/test/components/ReadOnlyTextField.test.js +4 -2
- package/test/components/RichTextEditor.test.js +90 -6
- package/test/components/Search.test.js +75 -0
- package/test/components/Select.test.js +97 -107
- package/test/components/Tabs.test.js +22 -24
- package/test/components/TextArea.test.js +78 -92
- package/test/components/TextField.test.js +128 -147
- package/test/components/Toast.test.js +67 -78
- package/test/components/TruncateText.test.js +75 -0
- package/test/components/index.test.js +23 -0
- package/webpack.config.mjs +79 -0
- package/webpack.config.react.mjs +72 -0
- package/.eslintignore +0 -5
- package/components/Alert/Alert.stories.js +0 -70
- package/components/Alert/index.js +0 -55
- package/components/Breadcrumb/Breadcrumb.md +0 -28
- package/components/Breadcrumb/Breadcrumb.stories.js +0 -76
- package/components/Breadcrumb/index.js +0 -92
- package/components/CalloutBox/CalloutBox.stories.js +0 -94
- package/components/CalloutBox/index.js +0 -109
- package/components/Card/Card.stories.js +0 -163
- package/components/Card/index.js +0 -144
- package/components/Dropdown/Dropdown.stories.js +0 -94
- package/components/Dropdown/index.js +0 -85
- package/components/Error/Collapsible.jsx +0 -93
- package/components/Error/ErrorUI.jsx +0 -31
- package/components/Error/error.js +0 -26
- package/components/FlashNotification/FlashNotificationUI.jsx +0 -91
- package/components/FlashNotification/index.js +0 -30
- package/components/Footer/Footer.stories.js +0 -20
- package/components/Footer/FooterUI.jsx +0 -137
- package/components/Footer/LegacyFooterUI.jsx +0 -204
- package/components/Footer/SocialLinks.jsx +0 -63
- package/components/Footer/Subscribe.jsx +0 -34
- package/components/Footer/footer.js +0 -30
- package/components/Infotip/Infotip.jsx +0 -75
- package/components/Infotip/Infotip.stories.js +0 -52
- package/components/Infotip/InfotipIcon.jsx +0 -41
- package/components/Infotip/index.js +0 -3
- package/components/Link/Link.stories.js +0 -82
- package/components/NotificationBanner/NotificationBanner.stories.js +0 -23
- package/components/NotificationBanner/index.js +0 -279
- package/components/Spinner/index.js +0 -9
- package/components/TextInput/TextInput.stories.js +0 -118
- package/components/TextInput/index.js +0 -137
- package/components/Tooltip/Tooltip.jsx +0 -88
- package/components/Tooltip/Tooltip.stories.js +0 -80
- package/components/Tooltip/index.js +0 -3
- package/components/Tooltip/position.js +0 -76
- package/components/UnwrappedSpinner/index.js +0 -8
- package/dist/browser.js +0 -1
- package/dist/react/index.js +0 -185
- package/dist/react/index.js.map +0 -1
- package/jest.config.js +0 -17
- package/test/components/ErrorUI.test.js +0 -32
- package/test/components/FooterUI.test.js +0 -122
- package/test/components/Infotip.test.js +0 -76
- package/test/components/Tooltip.test.js +0 -147
- package/webpack.config.js +0 -124
- package/webpack.config.react.js +0 -104
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import PropTypes from "prop-types";
|
|
3
|
-
import Tooltip from "../Tooltip";
|
|
4
|
-
import InfotipIcon from "./InfotipIcon";
|
|
5
|
-
|
|
6
|
-
const BUTTON_SIZE = "16px";
|
|
7
|
-
|
|
8
|
-
const buttonStyle = {
|
|
9
|
-
background: "transparent",
|
|
10
|
-
border: 0,
|
|
11
|
-
padding: 0,
|
|
12
|
-
width: BUTTON_SIZE,
|
|
13
|
-
height: BUTTON_SIZE,
|
|
14
|
-
WebkitTouchCallout: "none",
|
|
15
|
-
WebkitUserSelect: "none",
|
|
16
|
-
userSelect: "none",
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
// Use basic touch handlers for mobile "tap-to-open" ui. Mobile touch
|
|
20
|
-
// is currently not supported by @reach/tooltip; this may change in future.
|
|
21
|
-
// Leverages @reach/tooltip "focus" behavior to open tooltip on tap,
|
|
22
|
-
// and close tooltip on second tap or loss of focus.
|
|
23
|
-
// TODO: We may want to improve this by tracking touch positions to ensure
|
|
24
|
-
// that a 'touchend' event must be reasonably close to the tooltip target.
|
|
25
|
-
const touchHandlers = {
|
|
26
|
-
onTouchStart: (e) => {
|
|
27
|
-
e.stopPropagation();
|
|
28
|
-
},
|
|
29
|
-
onTouchEnd: (e) => {
|
|
30
|
-
if (document.activeElement !== e.currentTarget) {
|
|
31
|
-
e.preventDefault();
|
|
32
|
-
e.currentTarget.focus();
|
|
33
|
-
} else {
|
|
34
|
-
e.preventDefault();
|
|
35
|
-
e.currentTarget.blur();
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Tooltip with styled information icon
|
|
42
|
-
*/
|
|
43
|
-
const Infotip = ({ label, lightIcon, ...props }) => (
|
|
44
|
-
<Tooltip label={label} {...props}>
|
|
45
|
-
<button
|
|
46
|
-
type="button"
|
|
47
|
-
aria-label="Information"
|
|
48
|
-
style={buttonStyle}
|
|
49
|
-
{...touchHandlers}
|
|
50
|
-
>
|
|
51
|
-
<InfotipIcon
|
|
52
|
-
lightIcon={lightIcon}
|
|
53
|
-
width={BUTTON_SIZE}
|
|
54
|
-
height={BUTTON_SIZE}
|
|
55
|
-
aria-hidden
|
|
56
|
-
style={{ float: "left" }}
|
|
57
|
-
/>
|
|
58
|
-
</button>
|
|
59
|
-
</Tooltip>
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
Infotip.propTypes = {
|
|
63
|
-
label: PropTypes.string.isRequired,
|
|
64
|
-
ariaLabel: PropTypes.string,
|
|
65
|
-
lightIcon: PropTypes.bool,
|
|
66
|
-
DEBUG_STYLE: PropTypes.bool,
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
Infotip.defaultProps = {
|
|
70
|
-
ariaLabel: undefined,
|
|
71
|
-
lightIcon: false,
|
|
72
|
-
DEBUG_STYLE: undefined,
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
export default Infotip;
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import Infotip from "./index";
|
|
3
|
-
import { withKnobs, boolean } from "@storybook/addon-knobs";
|
|
4
|
-
|
|
5
|
-
export default {
|
|
6
|
-
title: "Infotip",
|
|
7
|
-
component: Infotip,
|
|
8
|
-
decorators: [
|
|
9
|
-
withKnobs,
|
|
10
|
-
(storyFn) => (
|
|
11
|
-
<div style={{ marginTop: "120px", marginLeft: "100px" }}>
|
|
12
|
-
{storyFn()}
|
|
13
|
-
</div>
|
|
14
|
-
),
|
|
15
|
-
],
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export const ExampleInfoTip = () => (
|
|
19
|
-
<Infotip label="Tooltip Content!" lightIcon={boolean("lightIcon", false)} />
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
ExampleInfoTip.storyName = "qpp themed Infotip";
|
|
23
|
-
|
|
24
|
-
export const PositionCollisionInfotip = () => (
|
|
25
|
-
<Infotip
|
|
26
|
-
DEBUG_STYLE
|
|
27
|
-
label="The DEBUG_STYLE prop is supported by the useTooltip hook and should only
|
|
28
|
-
be used for development."
|
|
29
|
-
/>
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
PositionCollisionInfotip.storyName = "position collision";
|
|
33
|
-
|
|
34
|
-
export const LongContentInfotip = () => (
|
|
35
|
-
<div style={{ paddingTop: "50px" }}>
|
|
36
|
-
<span style={{ marginLeft: "120px" }} />
|
|
37
|
-
<Infotip
|
|
38
|
-
DEBUG_STYLE
|
|
39
|
-
label="Initial Eligibility determination covers data collected from Oct. 1, 2018 to Sept. 31, 2019. Determination was released in Dec. 2019. Final eligibility will be released in Nov. 2020."
|
|
40
|
-
/>
|
|
41
|
-
</div>
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
LongContentInfotip.storyName = "long content";
|
|
45
|
-
|
|
46
|
-
export const LightIconInfotip = () => (
|
|
47
|
-
<div style={{ backgroundColor: "#04838A", padding: "20px", width: "16px" }}>
|
|
48
|
-
<Infotip lightIcon label="Light Icon Infotip" />
|
|
49
|
-
</div>
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
LightIconInfotip.storyName = "alternate light icon";
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import PropTypes from "prop-types";
|
|
3
|
-
|
|
4
|
-
const InfotipIcon = ({ lightIcon, ...props }) => (
|
|
5
|
-
<svg
|
|
6
|
-
width="20px"
|
|
7
|
-
height="20px"
|
|
8
|
-
viewBox="0 0 20 20"
|
|
9
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
10
|
-
{...props}
|
|
11
|
-
>
|
|
12
|
-
<g fill="none" fillRule="evenodd">
|
|
13
|
-
<path
|
|
14
|
-
d="M9.721 19.158c-4.947 0-8.973-4.126-8.973-9.196C.748 4.892 4.774.766 9.72.766c4.948 0 8.974 4.126 8.974 9.196 0 5.07-4.026 9.196-8.974 9.196z"
|
|
15
|
-
fill="#2EB1ED"
|
|
16
|
-
fillRule="nonzero"
|
|
17
|
-
/>
|
|
18
|
-
<path
|
|
19
|
-
d="M9.721 0C4.361 0 0 4.469 0 9.962c0 5.493 4.36 9.962 9.721 9.962 5.36 0 9.722-4.469 9.722-9.962C19.443 4.469 15.082 0 9.72 0z"
|
|
20
|
-
fill={lightIcon ? "#FFF" : "#04838A"}
|
|
21
|
-
/>
|
|
22
|
-
<path
|
|
23
|
-
d="M9.721 14.765c-.206 0-.374.112-.374.25v.5c0 .138.168.25.374.25.207 0 .374-.112.374-.25v-.5c0-.138-.167-.25-.374-.25zM9.764 4.706H9.72c-.792 0-1.536.29-2.1.821a2.767 2.767 0 0 0-.89 2.03c0 .197.166.356.373.356s.374-.159.374-.356c0-.577.237-1.118.668-1.523a2.268 2.268 0 0 1 1.607-.615c1.182.016 2.195.98 2.211 2.107.011.743-.373 1.427-1.028 1.83-.995.61-1.589 1.691-1.589 2.89v1.013c0 .197.168.357.374.357.207 0 .374-.16.374-.357v-1.013c0-.941.477-1.82 1.246-2.292.873-.537 1.386-1.448 1.371-2.438-.022-1.527-1.345-2.788-2.948-2.81z"
|
|
24
|
-
stroke={lightIcon ? "#04838A" : "#FFF"}
|
|
25
|
-
strokeWidth=".5"
|
|
26
|
-
fill={lightIcon ? "#04838A" : "#FFF"}
|
|
27
|
-
fillRule="nonzero"
|
|
28
|
-
/>
|
|
29
|
-
</g>
|
|
30
|
-
</svg>
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
export default InfotipIcon;
|
|
34
|
-
|
|
35
|
-
InfotipIcon.propTypes = {
|
|
36
|
-
lightIcon: PropTypes.bool,
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
InfotipIcon.defaultProps = {
|
|
40
|
-
lightIcon: false,
|
|
41
|
-
};
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import DSLink from "./index";
|
|
3
|
-
import { withKnobs } from "@storybook/addon-knobs";
|
|
4
|
-
import OpenInNewIcon from "@mui/icons-material/OpenInNew";
|
|
5
|
-
|
|
6
|
-
export default {
|
|
7
|
-
title: "Link",
|
|
8
|
-
component: DSLink,
|
|
9
|
-
decorators: [withKnobs],
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export const LinkLabel = () => <DSLink href="#">Link Label</DSLink>;
|
|
13
|
-
|
|
14
|
-
export const LinkColorVariants = () => (
|
|
15
|
-
<>
|
|
16
|
-
<div className=" qpp-dark-background qpp-u-padding--16">
|
|
17
|
-
<DSLink href="#" variant="white">
|
|
18
|
-
Link Label
|
|
19
|
-
</DSLink>
|
|
20
|
-
</div>
|
|
21
|
-
<p>
|
|
22
|
-
<DSLink href="#" variant="gray">
|
|
23
|
-
Link Label
|
|
24
|
-
</DSLink>
|
|
25
|
-
</p>
|
|
26
|
-
</>
|
|
27
|
-
);
|
|
28
|
-
|
|
29
|
-
export const inlineLinks = () => (
|
|
30
|
-
<div className="qpp-u-padding--16">
|
|
31
|
-
<p className="qpp-u-width--60">
|
|
32
|
-
Aenean lacinia <DSLink href="#">inline link</DSLink> nulla sed{" "}
|
|
33
|
-
<DSLink href="#">inline link</DSLink>. Integer posuere erat a ante
|
|
34
|
-
venenatis dapibus posuere velit aliquet. Integer posuere erat a ante
|
|
35
|
-
venenatis <DSLink href="#">inline link</DSLink> dapibus posuere
|
|
36
|
-
velit aliquet.
|
|
37
|
-
</p>
|
|
38
|
-
</div>
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
export const inlineLinksDarkBackground = () => (
|
|
42
|
-
<div className="qpp-dark-background qpp-u-padding--16">
|
|
43
|
-
Aenean lacinia{" "}
|
|
44
|
-
<DSLink href="#" variant="white">
|
|
45
|
-
inline link
|
|
46
|
-
</DSLink>{" "}
|
|
47
|
-
nulla sed{" "}
|
|
48
|
-
<DSLink href="#" variant="white">
|
|
49
|
-
inline link
|
|
50
|
-
</DSLink>
|
|
51
|
-
. Integer posuere erat a ante venenatis dapibus posuere velit aliquet.
|
|
52
|
-
Integer posuere erat a ante venenatis{" "}
|
|
53
|
-
<DSLink href="#" variant="white">
|
|
54
|
-
inline link
|
|
55
|
-
</DSLink>{" "}
|
|
56
|
-
dapibus posuere velit aliquet.
|
|
57
|
-
</div>
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
export const linkWithIcon = () => {
|
|
61
|
-
const icon = <OpenInNewIcon classes={{ root: "qpp-icon-mat" }} />;
|
|
62
|
-
return (
|
|
63
|
-
<div className="qpp-u-padding--16">
|
|
64
|
-
<DSLink href="#">
|
|
65
|
-
Standalone Link With Icon
|
|
66
|
-
{icon}
|
|
67
|
-
</DSLink>{" "}
|
|
68
|
-
<p className=" qpp-u-width--60">
|
|
69
|
-
Aenean lacinia{" "}
|
|
70
|
-
<DSLink href="#">
|
|
71
|
-
inline link
|
|
72
|
-
{icon}
|
|
73
|
-
</DSLink>{" "}
|
|
74
|
-
nulla sed <DSLink href="#">inline link {icon}</DSLink>. Integer
|
|
75
|
-
posuere erat a ante venenatis dapibus posuere velit aliquet.
|
|
76
|
-
Integer posuere erat a ante venenatis{" "}
|
|
77
|
-
<DSLink href="#">inline link {icon}</DSLink> dapibus posuere
|
|
78
|
-
velit aliquet.
|
|
79
|
-
</p>
|
|
80
|
-
</div>
|
|
81
|
-
);
|
|
82
|
-
};
|
|
@@ -1,23 +0,0 @@
|
|
|
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";
|
|
@@ -1,279 +0,0 @@
|
|
|
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(
|
|
41
|
-
notifications.content
|
|
42
|
-
),
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
setBannerHeight() {
|
|
49
|
-
const {
|
|
50
|
-
result: {
|
|
51
|
-
content: { content },
|
|
52
|
-
},
|
|
53
|
-
} = this.props;
|
|
54
|
-
if (content) {
|
|
55
|
-
this.bannerContainer.style.transition = "none";
|
|
56
|
-
|
|
57
|
-
this.state.expanded
|
|
58
|
-
? this.collapsedBanner.setAttribute("tabIndex", "-1")
|
|
59
|
-
: this.collapsedBanner.setAttribute("tabIndex", " ");
|
|
60
|
-
|
|
61
|
-
this.setState({
|
|
62
|
-
height: this.state.expanded
|
|
63
|
-
? "100%"
|
|
64
|
-
: this.collapsedWrapper.offsetHeight + "px",
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
isNotificationExpanded(notification) {
|
|
70
|
-
const dateDismissed = new Date(notification.dateDismissed);
|
|
71
|
-
const dateUpdated = new Date(notification.dateUpdated);
|
|
72
|
-
const notDismissed =
|
|
73
|
-
(this.isDateValid(dateUpdated) &&
|
|
74
|
-
this.isDateValid(dateDismissed) &&
|
|
75
|
-
dateUpdated >= dateDismissed) ||
|
|
76
|
-
!this.isDateValid(dateDismissed);
|
|
77
|
-
|
|
78
|
-
return notDismissed;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Whether the date is valid, i.e. not null
|
|
83
|
-
*
|
|
84
|
-
* @param {Date} date
|
|
85
|
-
* @return {Boolean}
|
|
86
|
-
*/
|
|
87
|
-
isDateValid(date) {
|
|
88
|
-
return !isNaN(Date.parse(date));
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Try to find this NotificationBanner instance in localStorage, or else add
|
|
93
|
-
* a minimal version of it, and mark it with a dateDismissed, then update
|
|
94
|
-
* localStorage.
|
|
95
|
-
*/
|
|
96
|
-
markNotificationClosed() {
|
|
97
|
-
const { result } = this.props;
|
|
98
|
-
const dateDismissed = new Date().toISOString();
|
|
99
|
-
const storageNotification = result || {};
|
|
100
|
-
|
|
101
|
-
if (
|
|
102
|
-
storageNotification &&
|
|
103
|
-
Object.keys(storageNotification).length > 0
|
|
104
|
-
) {
|
|
105
|
-
window.localStorage.setItem(
|
|
106
|
-
"notifications",
|
|
107
|
-
JSON.stringify({
|
|
108
|
-
...storageNotification,
|
|
109
|
-
content: {
|
|
110
|
-
...storageNotification.content,
|
|
111
|
-
dateDismissed,
|
|
112
|
-
},
|
|
113
|
-
})
|
|
114
|
-
);
|
|
115
|
-
} else {
|
|
116
|
-
window.localStorage.setItem(
|
|
117
|
-
"notifications",
|
|
118
|
-
JSON.stringify({
|
|
119
|
-
...storageNotification,
|
|
120
|
-
content: {
|
|
121
|
-
name: "header-notification",
|
|
122
|
-
dateDismissed,
|
|
123
|
-
},
|
|
124
|
-
})
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Callback when the user dimisses a notification. Mark it as dismissed in
|
|
131
|
-
* localStorage, empty the contents, and dispatch a custom event to notify
|
|
132
|
-
* any observers that it has been dismissed.
|
|
133
|
-
*/
|
|
134
|
-
collapseNotification(e) {
|
|
135
|
-
e.stopPropagation();
|
|
136
|
-
this.markNotificationClosed();
|
|
137
|
-
this.collapsedBanner.setAttribute("tabIndex", " ");
|
|
138
|
-
this.bannerContainer.style.transition = "height .2s ease-out";
|
|
139
|
-
this.setState({
|
|
140
|
-
expanded: false,
|
|
141
|
-
height: this.collapsedWrapper.offsetHeight + "px",
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
expandNotification() {
|
|
146
|
-
if (!this.state.expanded) {
|
|
147
|
-
this.collapsedBanner.setAttribute("tabIndex", "-1");
|
|
148
|
-
this.bannerContainer.style.transition = "height .2s ease-out";
|
|
149
|
-
this.setState({
|
|
150
|
-
expanded: true,
|
|
151
|
-
height: "100%",
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Renders the close button if the notification instance is dismissable.
|
|
158
|
-
*
|
|
159
|
-
* @return {String} HTML content
|
|
160
|
-
*/
|
|
161
|
-
renderCloseButton() {
|
|
162
|
-
const {
|
|
163
|
-
result: {
|
|
164
|
-
content: { dismissable },
|
|
165
|
-
},
|
|
166
|
-
} = this.props;
|
|
167
|
-
if (dismissable) {
|
|
168
|
-
return (
|
|
169
|
-
<button
|
|
170
|
-
onClick={this._collapseNotification}
|
|
171
|
-
type="button"
|
|
172
|
-
className="notification-banner-close"
|
|
173
|
-
>
|
|
174
|
-
<svg
|
|
175
|
-
className="close-icon"
|
|
176
|
-
aria-hidden="true"
|
|
177
|
-
focusable="false"
|
|
178
|
-
>
|
|
179
|
-
<CloseXIcon />
|
|
180
|
-
</svg>
|
|
181
|
-
<span className="sr-only">Close</span>
|
|
182
|
-
</button>
|
|
183
|
-
);
|
|
184
|
-
} else {
|
|
185
|
-
return "";
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Render the notification if it has any contents.
|
|
191
|
-
*
|
|
192
|
-
* @return {String} HTML content
|
|
193
|
-
*/
|
|
194
|
-
render() {
|
|
195
|
-
const { expanded, height } = this.state;
|
|
196
|
-
const { result: { content: { enabled, content } = {} } = {} } =
|
|
197
|
-
this.props;
|
|
198
|
-
if (!content || !enabled) {
|
|
199
|
-
return <div id="notification-banner" />;
|
|
200
|
-
} else {
|
|
201
|
-
const notificationStatus = expanded ? "expanded" : "collapsed";
|
|
202
|
-
const { color = "blue", label = "Update" } = content;
|
|
203
|
-
const className = `notification-banner notification-banner-${color} ${notificationStatus}`;
|
|
204
|
-
|
|
205
|
-
return (
|
|
206
|
-
<div
|
|
207
|
-
style={{ height }}
|
|
208
|
-
ref={(elem) => (this.bannerContainer = elem)}
|
|
209
|
-
className={className}
|
|
210
|
-
>
|
|
211
|
-
<div
|
|
212
|
-
ref={(elem) => (this.expandedWrapper = elem)}
|
|
213
|
-
className={`notification-banner-wrapper expanded-view`}
|
|
214
|
-
>
|
|
215
|
-
<div className="notification-banner-label">{label}</div>
|
|
216
|
-
<div className="notification-banner-content">
|
|
217
|
-
<SanitizedContent
|
|
218
|
-
html={
|
|
219
|
-
expanded
|
|
220
|
-
? content
|
|
221
|
-
: "<p>Nothing to see here</p>"
|
|
222
|
-
}
|
|
223
|
-
/>
|
|
224
|
-
</div>
|
|
225
|
-
{expanded && this._renderCloseButton()}
|
|
226
|
-
</div>
|
|
227
|
-
|
|
228
|
-
<div
|
|
229
|
-
ref={(elem) => (this.collapsedWrapper = elem)}
|
|
230
|
-
className={`notification-banner-wrapper collapsed-view`}
|
|
231
|
-
onClick={this._expandNotification}
|
|
232
|
-
>
|
|
233
|
-
<button
|
|
234
|
-
ref={(elem) => (this.collapsedBanner = elem)}
|
|
235
|
-
className={`notification-banner-label`}
|
|
236
|
-
>
|
|
237
|
-
{label}
|
|
238
|
-
<span className="bell-icon">
|
|
239
|
-
<svg aria-hidden="true" focusable="false">
|
|
240
|
-
<BellOutline />
|
|
241
|
-
</svg>
|
|
242
|
-
</span>
|
|
243
|
-
</button>
|
|
244
|
-
</div>
|
|
245
|
-
</div>
|
|
246
|
-
);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
NotificationBanner.propTypes = {
|
|
252
|
-
result: PropTypes.shape({
|
|
253
|
-
content: PropTypes.shape({
|
|
254
|
-
content: PropTypes.string,
|
|
255
|
-
label: PropTypes.string,
|
|
256
|
-
color: PropTypes.string,
|
|
257
|
-
dismissable: PropTypes.bool,
|
|
258
|
-
}),
|
|
259
|
-
}),
|
|
260
|
-
};
|
|
261
|
-
|
|
262
|
-
NotificationBanner.defaultProps = {
|
|
263
|
-
result: {
|
|
264
|
-
content: {
|
|
265
|
-
content: null,
|
|
266
|
-
label: "Update",
|
|
267
|
-
color: "blue",
|
|
268
|
-
dismissable: true,
|
|
269
|
-
},
|
|
270
|
-
},
|
|
271
|
-
};
|
|
272
|
-
|
|
273
|
-
export default withGetConfig(NotificationBanner, {
|
|
274
|
-
timeout: 5,
|
|
275
|
-
url: "/config/notification",
|
|
276
|
-
localStorageName: "active_notification",
|
|
277
|
-
equalityCheckExclude: ["dateDismissed", "dateUpdated"],
|
|
278
|
-
defaultContent: {},
|
|
279
|
-
});
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import PropTypes from "prop-types";
|
|
3
|
-
import TextInput from "./index";
|
|
4
|
-
import { withKnobs } from "@storybook/addon-knobs";
|
|
5
|
-
|
|
6
|
-
export default {
|
|
7
|
-
title: "Text Input",
|
|
8
|
-
component: TextInput,
|
|
9
|
-
decorators: [withKnobs],
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
const optionalProps = {
|
|
13
|
-
"aria-label": "example label",
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
const Wrapper = ({ children }) => (
|
|
17
|
-
<div className="qpp-u-padding--16">{children}</div>
|
|
18
|
-
);
|
|
19
|
-
Wrapper.propTypes = {
|
|
20
|
-
children: PropTypes.node,
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
export const InputField = () => (
|
|
24
|
-
<Wrapper>
|
|
25
|
-
<TextInput
|
|
26
|
-
style={{ width: "auto" }}
|
|
27
|
-
id="example"
|
|
28
|
-
name="single-example"
|
|
29
|
-
value="Example value"
|
|
30
|
-
label="Input Field"
|
|
31
|
-
{...optionalProps}
|
|
32
|
-
/>
|
|
33
|
-
</Wrapper>
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
export const InputFieldWithPlaceholder = () => (
|
|
37
|
-
<Wrapper>
|
|
38
|
-
<TextInput
|
|
39
|
-
id="placeholder-example"
|
|
40
|
-
name="placheholder"
|
|
41
|
-
label="Placeholder Example"
|
|
42
|
-
placeholder="Placeholder value"
|
|
43
|
-
/>
|
|
44
|
-
</Wrapper>
|
|
45
|
-
);
|
|
46
|
-
export const DisabledInputField = () => (
|
|
47
|
-
<Wrapper>
|
|
48
|
-
<TextInput
|
|
49
|
-
disabled={true}
|
|
50
|
-
id="disabled-example"
|
|
51
|
-
name="disabled_example"
|
|
52
|
-
value="Example value"
|
|
53
|
-
label="Disabled Example"
|
|
54
|
-
/>
|
|
55
|
-
</Wrapper>
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
export const FocusedInputField = () => (
|
|
59
|
-
<Wrapper>
|
|
60
|
-
<TextInput
|
|
61
|
-
id="focused-example"
|
|
62
|
-
name="focused_example"
|
|
63
|
-
value="Example value"
|
|
64
|
-
label="Focused Example"
|
|
65
|
-
className="qpp-c-text-input--focus"
|
|
66
|
-
/>
|
|
67
|
-
</Wrapper>
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
export const ErrorInputField = () => (
|
|
71
|
-
<Wrapper>
|
|
72
|
-
<TextInput
|
|
73
|
-
className="qpp-u-margin-bottom--8"
|
|
74
|
-
id="error-example"
|
|
75
|
-
name="error_example"
|
|
76
|
-
value="Example value"
|
|
77
|
-
error="Error Message"
|
|
78
|
-
label="Error Example"
|
|
79
|
-
/>
|
|
80
|
-
</Wrapper>
|
|
81
|
-
);
|
|
82
|
-
|
|
83
|
-
export const SuccessInputField = () => (
|
|
84
|
-
<Wrapper>
|
|
85
|
-
<TextInput
|
|
86
|
-
variant="success"
|
|
87
|
-
id="success-example"
|
|
88
|
-
name="success"
|
|
89
|
-
value="Example value"
|
|
90
|
-
label="Success Example"
|
|
91
|
-
/>
|
|
92
|
-
</Wrapper>
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
export const InputFieldWithHint = () => (
|
|
96
|
-
<Wrapper>
|
|
97
|
-
<TextInput
|
|
98
|
-
className="qpp-u-margin-bottom--8"
|
|
99
|
-
id="hint-example"
|
|
100
|
-
name="hint"
|
|
101
|
-
value="Example value"
|
|
102
|
-
label="Hint Example"
|
|
103
|
-
hint="Hint Message"
|
|
104
|
-
/>
|
|
105
|
-
</Wrapper>
|
|
106
|
-
);
|
|
107
|
-
|
|
108
|
-
export const BigInput = () => (
|
|
109
|
-
<Wrapper>
|
|
110
|
-
<TextInput
|
|
111
|
-
id="big-example"
|
|
112
|
-
name="hint"
|
|
113
|
-
value="Example value"
|
|
114
|
-
label="Big Example"
|
|
115
|
-
size="big"
|
|
116
|
-
/>
|
|
117
|
-
</Wrapper>
|
|
118
|
-
);
|