From 61732c4c44e88635bbbb6f3e4b5b6beaf11b490f Mon Sep 17 00:00:00 2001 From: Jeffrey Burt Date: Fri, 8 May 2020 21:57:32 -0400 Subject: [PATCH 01/18] extend Card to make an Alert component --- .gitignore | 1 + src/Alert/Alert.story.mdx | 89 ++++++++++++++++++++++++++++++++ src/Alert/Alert.tsx | 106 ++++++++++++++++++++++++++++++++++++++ src/Alert/index.ts | 1 + src/Card/Card.tsx | 7 ++- 5 files changed, 202 insertions(+), 2 deletions(-) create mode 100644 src/Alert/Alert.story.mdx create mode 100644 src/Alert/Alert.tsx create mode 100644 src/Alert/index.ts diff --git a/.gitignore b/.gitignore index 2bd81678..d26a2c97 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ tsconfig.tsbuildinfo # Other modules /*-????????.js* /AbstractTooltip +/Alert /Button /colors /ConfirmationTooltip diff --git a/src/Alert/Alert.story.mdx b/src/Alert/Alert.story.mdx new file mode 100644 index 00000000..7739f2f8 --- /dev/null +++ b/src/Alert/Alert.story.mdx @@ -0,0 +1,89 @@ +import { colors } from "../colors"; +import { Alert } from "../Alert"; +import { Button } from "../Button"; +import { + Description, + Meta, + Story, + Props, + Preview, +} from "@storybook/addon-docs/blocks"; + + + +# Alert + + + +## Info Alert + +Informational alerts present general info about something you are doing or working with. It is neutral and conveys no implications of success or failure. + + + + undefined} level="info" heading="Informational alert"> + This is a general informational message telling you about something. Learn + more + + + + +## Warning Alert + +Warning alerts present information about the action that is about to be taken that alerts the user to consequences of the action and asks for confirmation that the action still be taken in light of the consequences. + + + + undefined} + level="warn" + heading="Warning alert" + actions={ + + } + > + exceededSubLimitAt is a deprecated field. You can use it but it may not + work as expected. + + + + +## Error Alert + +Error alerts let the user know that something has gone wrong or is blocked in the given workflow they are trying to complete. When possible, error alerts should contain helpful information about what has happened to help unblock the user (such as steps to resolve or a link to a docs article). + + + + undefined} + level="error" + heading="Error alert" + style={{ marginBottom: 20 }} + > + Something is broken. You cannot perform this action at this time. + + + + +## Success Alert + +Success alerts are confirmation that the action the user was trying to take has succeeded. + + + + undefined} level="success" heading="Success alert"> + A new schema registry has been created by timbotnik. + + + + +## Props + +### `Alert` + + diff --git a/src/Alert/Alert.tsx b/src/Alert/Alert.tsx new file mode 100644 index 00000000..b9dcd69b --- /dev/null +++ b/src/Alert/Alert.tsx @@ -0,0 +1,106 @@ +/** @jsx jsx */ +import { jsx, css } from "@emotion/core"; +import React, { useMemo } from "react"; +import PropTypes from "prop-types"; + +import { Card, CardSeperator, CardProps } from "../Card"; +import { IconErrorSolid } from "../icons/IconErrorSolid"; +import { IconInfoSolid } from "../icons/IconInfoSolid"; +import { IconWarningSolid } from "../icons/IconWarningSolid"; +import { IconSuccessSolid } from "../icons/IconSuccessSolid"; +import { IconClose } from "../icons/IconClose"; +import { colors } from "../colors"; + +type AlertLevel = "info" | "warn" | "error" | "success"; + +interface AlertProps extends Omit { + level: AlertLevel; + /** + * callback for handling the clicks on the close button. + */ + onClose: () => void; +} + +export const Alert: React.FC = ({ + level, + heading, + onClose, + children, + actions, + ...cardProps +}) => { + const { Icon, color } = useMemo(() => { + switch (level) { + case "info": + return { color: colors.blue, Icon: IconInfoSolid }; + case "warn": + return { color: colors.yellow, Icon: IconWarningSolid }; + case "error": + return { color: colors.red, Icon: IconErrorSolid }; + case "success": + return { color: colors.green, Icon: IconSuccessSolid }; + default: + return {}; + } + }, [level]); + + return ( + + {Icon && ( + + )} +
+ {heading} +
+ + + } + css={{ + borderRadius: 4, + padding: 15, + "& > div:first-child": { marginBottom: 14 }, + }} + > + +
+ {children} +
+ {actions} +
+ ); +}; + +Alert.propTypes = { + level: PropTypes.oneOf(["info", "warn", "error", "success"] as AlertLevel[]) + .isRequired, + onClose: PropTypes.func.isRequired, +}; diff --git a/src/Alert/index.ts b/src/Alert/index.ts new file mode 100644 index 00000000..b8e17a03 --- /dev/null +++ b/src/Alert/index.ts @@ -0,0 +1 @@ +export * from "./Alert"; diff --git a/src/Card/Card.tsx b/src/Card/Card.tsx index 248c2194..b1799abd 100644 --- a/src/Card/Card.tsx +++ b/src/Card/Card.tsx @@ -8,7 +8,7 @@ import classnames from "classnames"; const descriptionMaxWidth = 760; -interface CardProps +export interface CardProps extends React.DetailedHTMLProps< React.HTMLAttributes, HTMLDivElement @@ -204,8 +204,11 @@ CardSection.propTypes = { /** * A border line that can go between two card sections, with appropriate margin applied */ -export const CardSeperator: React.FC = () => ( +export const CardSeperator: React.FC<{ className?: string }> = ({ + className, +}) => (
Date: Wed, 20 May 2020 21:11:50 -0400 Subject: [PATCH 02/18] use orange instead of yellow --- src/Alert/Alert.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Alert/Alert.tsx b/src/Alert/Alert.tsx index b9dcd69b..a15b3665 100644 --- a/src/Alert/Alert.tsx +++ b/src/Alert/Alert.tsx @@ -34,7 +34,7 @@ export const Alert: React.FC = ({ case "info": return { color: colors.blue, Icon: IconInfoSolid }; case "warn": - return { color: colors.yellow, Icon: IconWarningSolid }; + return { color: colors.orange, Icon: IconWarningSolid }; case "error": return { color: colors.red, Icon: IconErrorSolid }; case "success": From 049ebc2d0084b352c6631482e8cef215285fd46d Mon Sep 17 00:00:00 2001 From: Jeffrey Burt Date: Wed, 20 May 2020 21:40:15 -0400 Subject: [PATCH 03/18] copy card code --- src/Alert/Alert.tsx | 148 ++++++++++++++++++++++++++++++++------------ 1 file changed, 107 insertions(+), 41 deletions(-) diff --git a/src/Alert/Alert.tsx b/src/Alert/Alert.tsx index a15b3665..d9c46ac1 100644 --- a/src/Alert/Alert.tsx +++ b/src/Alert/Alert.tsx @@ -1,9 +1,10 @@ /** @jsx jsx */ -import { jsx, css } from "@emotion/core"; -import React, { useMemo } from "react"; +import { jsx, ClassNames } from "@emotion/core"; +import React, { useMemo, CSSProperties, Fragment } from "react"; import PropTypes from "prop-types"; +import classnames from "classnames"; -import { Card, CardSeperator, CardProps } from "../Card"; +import { base } from "../typography"; import { IconErrorSolid } from "../icons/IconErrorSolid"; import { IconInfoSolid } from "../icons/IconInfoSolid"; import { IconWarningSolid } from "../icons/IconWarningSolid"; @@ -13,21 +14,49 @@ import { colors } from "../colors"; type AlertLevel = "info" | "warn" | "error" | "success"; -interface AlertProps extends Omit { +interface AlertProps { + heading?: React.ReactNode; + + /** + * actions could be a button + * or a tooltip or anything the card should display + * aligned with the title on the right + */ + actions?: React.ReactNode; + + /** + * The content of the card, + * appears below the title and description + */ + children?: React.ReactNode; + + /** + * Override how the `header` is rendered. You can pass either an intrinisic + * jsx element as a string (like "h1") or a react element (`

`) + * + * If you pass a react element, props that we add are spread onto the input. + * + * @default "h2" + */ + headingAs?: React.ReactElement | keyof JSX.IntrinsicElements; + level: AlertLevel; /** * callback for handling the clicks on the close button. */ onClose: () => void; + className?: string; + style?: CSSProperties; } export const Alert: React.FC = ({ level, heading, onClose, - children, actions, - ...cardProps + headingAs = "h2", + children, + ...otherProps }) => { const { Icon, color } = useMemo(() => { switch (level) { @@ -45,46 +74,83 @@ export const Alert: React.FC = ({ }, [level]); return ( - - {Icon && ( - - )} -
- {heading} -
- - - } +
div:first-child": { marginBottom: 14 }, }} > - + + {({ css, cx }) => { + const headingProps = { + className: cx( + css({ + fontWeight: 600, + marginBottom: 0, + marginTop: 0, + width: "100%", + display: "flex", + color: color?.darker, + ...base.base, + }) + ), + children: ( + + {Icon && ( + + )} + {heading} + + ), + }; + + return React.isValidElement(headingAs) + ? React.cloneElement(headingAs, { + ...headingProps, + className: classnames( + headingProps.className, + headingAs.props.className + ), + }) + : React.createElement(headingAs, headingProps); + }} + + + + +
+
= ({ {children}
{actions} - +
); }; From 195bb0ea77e9cbd49c5d4ebb38f501efd5787ea5 Mon Sep 17 00:00:00 2001 From: Jeffrey Burt Date: Wed, 20 May 2020 21:58:49 -0400 Subject: [PATCH 04/18] accept color and icon instead of level --- src/Alert/Alert.story.mdx | 24 ++++++++++-- src/Alert/Alert.tsx | 77 ++++++++++++++++++++------------------- 2 files changed, 59 insertions(+), 42 deletions(-) diff --git a/src/Alert/Alert.story.mdx b/src/Alert/Alert.story.mdx index 7739f2f8..460f4237 100644 --- a/src/Alert/Alert.story.mdx +++ b/src/Alert/Alert.story.mdx @@ -1,6 +1,10 @@ import { colors } from "../colors"; import { Alert } from "../Alert"; import { Button } from "../Button"; +import { IconInfoSolid } from "../icons/IconInfoSolid"; +import { IconErrorSolid } from "../icons/IconErrorSolid"; +import { IconWarningSolid } from "../icons/IconWarningSolid"; +import { IconSuccessSolid } from "../icons/IconSuccessSolid"; import { Description, Meta, @@ -24,7 +28,12 @@ Informational alerts present general info about something you are doing or worki - undefined} level="info" heading="Informational alert"> + undefined} + color={colors.blue.base} + Icon={IconInfoSolid} + heading="Informational alert" + > This is a general informational message telling you about something. Learn more @@ -39,7 +48,8 @@ Warning alerts present information about the action that is about to be taken th undefined} - level="warn" + color={colors.orange.base} + Icon={IconWarningSolid} heading="Warning alert" actions={ + } + > + exceededSubLimitAt is a deprecated field. You can use it but it may not + work as expected. + + + undefined} color={colors.orange.base} Icon={IconWarningSolid} heading="Warning alert" + theme="dark" actions={ - } + actions={} > exceededSubLimitAt is a deprecated field. You can use it but it may not work as expected. @@ -81,7 +107,7 @@ Warning alerts present information about the action that is about to be taken th heading="Warning alert" theme="dark" actions={ - } diff --git a/src/Alert/Alert.tsx b/src/Alert/Alert.tsx index 07184b04..d22dd526 100644 --- a/src/Alert/Alert.tsx +++ b/src/Alert/Alert.tsx @@ -55,6 +55,13 @@ interface AlertProps { */ onClose: () => void; + /** + * layout for longer content + * + * @default false + */ + extended?: boolean; + className?: string; style?: CSSProperties; } @@ -68,6 +75,7 @@ export const Alert: React.FC = ({ color, Icon, theme = "light", + extended = false, ...otherProps }) => { return ( @@ -85,7 +93,13 @@ export const Alert: React.FC = ({ padding: 15, }} > -
+
{({ css, cx }) => { const headingProps = { @@ -136,31 +150,37 @@ export const Alert: React.FC = ({ />
-
+ {extended && ( +
+ )} +
+
+ {children} +
-
- {children} + {actions}
- {actions} ); }; Alert.propTypes = { + extended: PropTypes.bool, onClose: PropTypes.func.isRequired, children: PropTypes.node, heading: PropTypes.node.isRequired, From 1dff30a0be5703b5432202cbf0ac7ad4bd2f082f Mon Sep 17 00:00:00 2001 From: Jeffrey Burt Date: Tue, 26 May 2020 22:19:18 -0400 Subject: [PATCH 10/18] switch Icon to element instead of component --- src/Alert/Alert.story.mdx | 20 ++++++++++---------- src/Alert/Alert.tsx | 26 ++++++++++++++++++++------ 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/Alert/Alert.story.mdx b/src/Alert/Alert.story.mdx index 13cc113b..f9714d94 100644 --- a/src/Alert/Alert.story.mdx +++ b/src/Alert/Alert.story.mdx @@ -31,7 +31,7 @@ Informational alerts present general info about something you are doing or worki undefined} color={colors.blue.base} - Icon={IconInfoSolid} + icon={} heading="Informational alert" > This is a general informational message telling you about something. Learn @@ -42,7 +42,7 @@ Informational alerts present general info about something you are doing or worki undefined} color={colors.blue.base} - Icon={IconInfoSolid} + icon={} theme="dark" heading="Informational alert" > @@ -59,7 +59,7 @@ Informational alerts present general info about something you are doing or worki undefined} color={colors.blue.base} - Icon={IconInfoSolid} + icon={} heading="Informational alert" extended={true} > @@ -71,7 +71,7 @@ Informational alerts present general info about something you are doing or worki undefined} color={colors.blue.base} - Icon={IconInfoSolid} + icon={} theme="dark" heading="Informational alert" extended={true} @@ -91,7 +91,7 @@ Warning alerts present information about the action that is about to be taken th undefined} color={colors.orange.base} - Icon={IconWarningSolid} + icon={} heading="Warning alert" actions={} > @@ -103,7 +103,7 @@ Warning alerts present information about the action that is about to be taken th undefined} color={colors.orange.base} - Icon={IconWarningSolid} + icon={} heading="Warning alert" theme="dark" actions={ @@ -127,7 +127,7 @@ Error alerts let the user know that something has gone wrong or is blocked in th undefined} color={colors.red.base} - Icon={IconErrorSolid} + icon={} heading="Error alert" style={{ marginBottom: 20 }} > @@ -138,7 +138,7 @@ Error alerts let the user know that something has gone wrong or is blocked in th undefined} color={colors.red.base} - Icon={IconErrorSolid} + icon={} heading="Error alert" theme="dark" style={{ marginBottom: 20 }} @@ -157,7 +157,7 @@ Success alerts are confirmation that the action the user was trying to take has undefined} color={colors.green.base} - Icon={IconSuccessSolid} + icon={} heading="Success alert" > A new schema registry has been created by timbotnik. @@ -167,7 +167,7 @@ Success alerts are confirmation that the action the user was trying to take has undefined} color={colors.green.base} - Icon={IconSuccessSolid} + icon={} theme="dark" heading="Success alert" > diff --git a/src/Alert/Alert.tsx b/src/Alert/Alert.tsx index d22dd526..ab5c1d19 100644 --- a/src/Alert/Alert.tsx +++ b/src/Alert/Alert.tsx @@ -25,7 +25,7 @@ interface AlertProps { /** * The icon displayed to the left of the heading text */ - Icon: React.ComponentType<{ className?: string }>; + icon: React.ReactElement<{ className?: string }>; heading: React.ReactNode; @@ -73,7 +73,7 @@ export const Alert: React.FC = ({ headingAs = "h2", children, color, - Icon, + icon, theme = "light", extended = false, ...otherProps @@ -120,9 +120,23 @@ export const Alert: React.FC = ({ ), children: ( - + + {({ css, cx }) => + React.cloneElement(icon, { + className: classnames( + icon.props.className, + cx( + css({ + width: 20, + height: 20, + color, + marginRight: 13, + }) + ) + ), + }) + } + {heading} ), @@ -190,5 +204,5 @@ Alert.propTypes = { .map((color) => Object.values(color)) .reduce((a, b) => a.concat(b)) as PaletteColor[] ).isRequired, - Icon: PropTypes.func.isRequired, + icon: PropTypes.element.isRequired, }; From d3a7d75bf9dd34adcf4b762a4db2580d085621b0 Mon Sep 17 00:00:00 2001 From: Jeffrey Burt Date: Tue, 26 May 2020 22:26:45 -0400 Subject: [PATCH 11/18] assert unexpected theme values are unreachable and make common assertUnreachable --- src/Alert/Alert.tsx | 14 ++++++++++++-- src/Button/Button.tsx | 6 +----- src/MenuItem/index.tsx | 6 +----- src/Modal/Modal.tsx | 6 +----- src/shared/assertUnreachable.ts | 5 +++++ 5 files changed, 20 insertions(+), 17 deletions(-) create mode 100644 src/shared/assertUnreachable.ts diff --git a/src/Alert/Alert.tsx b/src/Alert/Alert.tsx index ab5c1d19..fe3150ba 100644 --- a/src/Alert/Alert.tsx +++ b/src/Alert/Alert.tsx @@ -8,6 +8,7 @@ import { base } from "../typography"; import { IconClose } from "../icons/IconClose"; import { colors, PaletteColor } from "../colors"; import { getOffsetInPalette } from "../colors/utils/getOffsetInPalette"; +import { assertUnreachable } from "../shared/assertUnreachable"; interface AlertProps { /** @@ -83,8 +84,17 @@ export const Alert: React.FC = ({ {...otherProps} css={{ backgroundColor: - theme === "light" ? colors.white : colors.black.lighter, - color: theme === "light" ? colors.black.base : colors.white, + theme === "light" + ? colors.white + : theme === "dark" + ? colors.black.lighter + : assertUnreachable(theme), + color: + theme === "light" + ? colors.black.base + : theme === "dark" + ? colors.white + : assertUnreachable(theme), boxShadow: `0 4px 8px 0 rgba(0, 0, 0, .04)`, borderStyle: "solid", borderRadius: 4, diff --git a/src/Button/Button.tsx b/src/Button/Button.tsx index 99b1b51e..df0a2541 100644 --- a/src/Button/Button.tsx +++ b/src/Button/Button.tsx @@ -7,14 +7,10 @@ import tinycolor from "tinycolor2"; import React from "react"; import classnames from "classnames"; import { LoadingSpinner } from "../Loaders"; +import { assertUnreachable } from "../shared/assertUnreachable"; type TLength = string | 0 | number; -/* istanbul ignore next */ -function assertUnreachable(value: never): never { - throw new TypeError(`Unreachable value reached ${value}`); -} - /** * Save a default color so we can check if we used the default or not. The * default color has a few special properties. diff --git a/src/MenuItem/index.tsx b/src/MenuItem/index.tsx index da2cdfb7..dc3ac3ad 100644 --- a/src/MenuItem/index.tsx +++ b/src/MenuItem/index.tsx @@ -6,11 +6,7 @@ import { css, jsx } from "@emotion/core"; import { colors } from "../colors"; import { useMenuIconSize } from "../MenuConfig"; import { useMenuItemClickListener } from "../MenuItemClickListener"; - -/* istanbul ignore next */ -function assertUnreachable(value: never): never { - throw new TypeError(`Unreachable value reached ${value}`); -} +import { assertUnreachable } from "../shared/assertUnreachable"; function getIconHorizontalPadding( iconSize: ReturnType diff --git a/src/Modal/Modal.tsx b/src/Modal/Modal.tsx index f0b4dc5e..5ee5199c 100644 --- a/src/Modal/Modal.tsx +++ b/src/Modal/Modal.tsx @@ -8,6 +8,7 @@ import { colors } from "../colors"; import * as CSS from "csstype"; import classnames from "classnames"; import { useSpaceKitProvider } from "../SpaceKitProvider"; +import { assertUnreachable } from "../shared/assertUnreachable"; interface Props { /** @@ -103,11 +104,6 @@ const modalBackdrop = css` } `; -/* istanbul ignore next */ -function assertUnreachable(value: never): never { - throw new TypeError(`Unreachable value reached ${value}`); -} - type TLength = string | 0 | number; function getModalWidth(size: Props["size"]): CSS.WidthProperty { diff --git a/src/shared/assertUnreachable.ts b/src/shared/assertUnreachable.ts new file mode 100644 index 00000000..245b0eb3 --- /dev/null +++ b/src/shared/assertUnreachable.ts @@ -0,0 +1,5 @@ +// @see https://www.typescriptlang.org/docs/handbook/advanced-types.html#exhaustiveness-checking +/* istanbul ignore next */ +export function assertUnreachable(value: never): never { + throw new TypeError(`Unreachable value reached ${value}`); +} From c47b8db2a609aa33314ff24e6c683e4346ddb03b Mon Sep 17 00:00:00 2001 From: Jeffrey Burt Date: Tue, 26 May 2020 22:53:20 -0400 Subject: [PATCH 12/18] add proptype for headingAs --- src/Alert/Alert.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Alert/Alert.tsx b/src/Alert/Alert.tsx index fe3150ba..200946b4 100644 --- a/src/Alert/Alert.tsx +++ b/src/Alert/Alert.tsx @@ -215,4 +215,8 @@ Alert.propTypes = { .reduce((a, b) => a.concat(b)) as PaletteColor[] ).isRequired, icon: PropTypes.element.isRequired, + headingAs: PropTypes.oneOfType([ + PropTypes.element.isRequired, + PropTypes.string.isRequired as any, // Using PropTypes.string to match keyof JSX.IntrinsicElements + ]), }; From d84a8333e3c1928ed3faaf79b7609771e066ad67 Mon Sep 17 00:00:00 2001 From: Jeffrey Burt Date: Thu, 28 May 2020 11:15:08 -0400 Subject: [PATCH 13/18] style inner svg shape --- src/Alert/Alert.story.mdx | 8 ++++---- src/icons/svgs/solids/icon-error-solid.svg | 8 +++----- src/icons/svgs/solids/icon-info-solid-sl.svg | 5 ++++- src/icons/svgs/solids/icon-success-solid-sl.svg | 5 ++++- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/Alert/Alert.story.mdx b/src/Alert/Alert.story.mdx index f9714d94..62b6910d 100644 --- a/src/Alert/Alert.story.mdx +++ b/src/Alert/Alert.story.mdx @@ -42,7 +42,7 @@ Informational alerts present general info about something you are doing or worki undefined} color={colors.blue.base} - icon={} + icon={} theme="dark" heading="Informational alert" > @@ -71,7 +71,7 @@ Informational alerts present general info about something you are doing or worki undefined} color={colors.blue.base} - icon={} + icon={} theme="dark" heading="Informational alert" extended={true} @@ -138,7 +138,7 @@ Error alerts let the user know that something has gone wrong or is blocked in th undefined} color={colors.red.base} - icon={} + icon={} heading="Error alert" theme="dark" style={{ marginBottom: 20 }} @@ -167,7 +167,7 @@ Success alerts are confirmation that the action the user was trying to take has undefined} color={colors.green.base} - icon={} + icon={} theme="dark" heading="Success alert" > diff --git a/src/icons/svgs/solids/icon-error-solid.svg b/src/icons/svgs/solids/icon-error-solid.svg index 3393324a..43e02947 100644 --- a/src/icons/svgs/solids/icon-error-solid.svg +++ b/src/icons/svgs/solids/icon-error-solid.svg @@ -1,6 +1,4 @@ - - - - - + + + \ No newline at end of file diff --git a/src/icons/svgs/solids/icon-info-solid-sl.svg b/src/icons/svgs/solids/icon-info-solid-sl.svg index 171cee31..496e1d0c 100644 --- a/src/icons/svgs/solids/icon-info-solid-sl.svg +++ b/src/icons/svgs/solids/icon-info-solid-sl.svg @@ -1 +1,4 @@ -Exported from Streamline App (https://app.streamlineicons.com) \ No newline at end of file + + + + \ No newline at end of file diff --git a/src/icons/svgs/solids/icon-success-solid-sl.svg b/src/icons/svgs/solids/icon-success-solid-sl.svg index c75d01cb..d24e0b80 100644 --- a/src/icons/svgs/solids/icon-success-solid-sl.svg +++ b/src/icons/svgs/solids/icon-success-solid-sl.svg @@ -1 +1,4 @@ - \ No newline at end of file + + + + \ No newline at end of file From 11716d3d7fe17b445e6698d6009a289868b76d29 Mon Sep 17 00:00:00 2001 From: Jeffrey Burt Date: Thu, 28 May 2020 14:22:37 -0400 Subject: [PATCH 14/18] guard all theme usages --- src/Alert/Alert.tsx | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/Alert/Alert.tsx b/src/Alert/Alert.tsx index 200946b4..91233632 100644 --- a/src/Alert/Alert.tsx +++ b/src/Alert/Alert.tsx @@ -98,7 +98,12 @@ export const Alert: React.FC = ({ boxShadow: `0 4px 8px 0 rgba(0, 0, 0, .04)`, borderStyle: "solid", borderRadius: 4, - borderWidth: theme === "light" ? 1 : 0, + borderWidth: + theme === "light" + ? 1 + : theme === "dark" + ? 0 + : assertUnreachable(theme), borderColor: colors.silver.dark, padding: 15, }} @@ -122,7 +127,11 @@ export const Alert: React.FC = ({ display: "flex", color: getOffsetInPalette( 2, - theme === "light" ? "darker" : "lighter", + theme === "light" + ? "darker" + : theme === "dark" + ? "lighter" + : assertUnreachable(theme), color ), ...base.base, @@ -180,7 +189,11 @@ export const Alert: React.FC = ({ height: 1, borderWidth: 0, backgroundColor: - theme === "dark" ? colors.grey.dark : colors.silver.dark, + theme === "light" + ? colors.silver.dark + : theme === "dark" + ? colors.grey.dark + : assertUnreachable(theme), marginTop: 14, marginBottom: 14, }} From 34622f4fccfc424912cf3edab752df66fbb96c51 Mon Sep 17 00:00:00 2001 From: Jeffrey Burt Date: Mon, 1 Jun 2020 13:07:13 -0400 Subject: [PATCH 15/18] use font helper --- src/Alert/Alert.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Alert/Alert.tsx b/src/Alert/Alert.tsx index 91233632..2891002d 100644 --- a/src/Alert/Alert.tsx +++ b/src/Alert/Alert.tsx @@ -202,8 +202,7 @@ export const Alert: React.FC = ({
From 0ede668e31bf2b381d78c405443fd988f5e3a522 Mon Sep 17 00:00:00 2001 From: Jeffrey Burt Date: Mon, 1 Jun 2020 23:31:13 -0400 Subject: [PATCH 16/18] update copy in alert story --- src/Alert/Alert.story.mdx | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/Alert/Alert.story.mdx b/src/Alert/Alert.story.mdx index 62b6910d..e500b508 100644 --- a/src/Alert/Alert.story.mdx +++ b/src/Alert/Alert.story.mdx @@ -54,6 +54,8 @@ Informational alerts present general info about something you are doing or worki ### Extended +The extended card variant is for rare use cases where an alert is the most appropriate format for explaining longer instructions. + - This is a general informational message telling you about something. Learn - more + In some cases it may be appropriate for the toast card to give a longer + message, or a set of instructions helping users navigate complicated + situations in the workflow. +
+
+ It is typically preferrable to link out to a docs article in situations like + this, but there are cases where you may also need to include a lengthy amount + of content with the card because it will be immediately useful to the user + in their workflow. +
+
+ If a toast card’s content requires more than one paragraph, use the + expanded content toast variant.
@@ -76,8 +89,19 @@ Informational alerts present general info about something you are doing or worki heading="Informational alert" extended={true} > - This is a general informational message telling you about something. Learn - more + In some cases it may be appropriate for the toast card to give a longer + message, or a set of instructions helping users navigate complicated + situations in the workflow. +
+
+ It is typically preferrable to link out to a docs article in situations like + this, but there are cases where you may also need to include a lengthy amount + of content with the card because it will be immediately useful to the user + in their workflow. +
+
+ If a toast card’s content requires more than one paragraph, use the + expanded content toast variant.
From 8c31c3c60f470fb8e761d2411822df0c5f4dcad8 Mon Sep 17 00:00:00 2001 From: Jeffrey Burt Date: Mon, 1 Jun 2020 23:47:07 -0400 Subject: [PATCH 17/18] rename Alert to AlertCard --- src/Alert/index.ts | 1 - .../AlertCard.story.mdx} | 52 +++++++++---------- .../Alert.tsx => AlertCard/AlertCard.tsx} | 6 +-- src/AlertCard/index.ts | 1 + 4 files changed, 30 insertions(+), 30 deletions(-) delete mode 100644 src/Alert/index.ts rename src/{Alert/Alert.story.mdx => AlertCard/AlertCard.story.mdx} (90%) rename src/{Alert/Alert.tsx => AlertCard/AlertCard.tsx} (98%) create mode 100644 src/AlertCard/index.ts diff --git a/src/Alert/index.ts b/src/Alert/index.ts deleted file mode 100644 index b8e17a03..00000000 --- a/src/Alert/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./Alert"; diff --git a/src/Alert/Alert.story.mdx b/src/AlertCard/AlertCard.story.mdx similarity index 90% rename from src/Alert/Alert.story.mdx rename to src/AlertCard/AlertCard.story.mdx index e500b508..0e4ad487 100644 --- a/src/Alert/Alert.story.mdx +++ b/src/AlertCard/AlertCard.story.mdx @@ -1,5 +1,5 @@ import { colors } from "../colors"; -import { Alert } from "../Alert"; +import { AlertCard } from "../AlertCard"; import { Button } from "../Button"; import { IconInfoSolid } from "../icons/IconInfoSolid"; import { IconErrorSolid } from "../icons/IconErrorSolid"; @@ -13,13 +13,13 @@ import { Preview, } from "@storybook/addon-docs/blocks"; - + -# Alert +# AlertCard ## Info Alert @@ -28,7 +28,7 @@ Informational alerts present general info about something you are doing or worki - undefined} color={colors.blue.base} icon={} @@ -36,10 +36,10 @@ Informational alerts present general info about something you are doing or worki > This is a general informational message telling you about something. Learn more - + - undefined} color={colors.blue.base} icon={} @@ -48,7 +48,7 @@ Informational alerts present general info about something you are doing or worki > This is a general informational message telling you about something. Learn more - + @@ -58,7 +58,7 @@ The extended card variant is for rare use cases where an alert is the most appro - undefined} color={colors.blue.base} icon={} @@ -78,10 +78,10 @@ The extended card variant is for rare use cases where an alert is the most appro
If a toast card’s content requires more than one paragraph, use the expanded content toast variant. -
+
- undefined} color={colors.blue.base} icon={} @@ -102,7 +102,7 @@ The extended card variant is for rare use cases where an alert is the most appro
If a toast card’s content requires more than one paragraph, use the expanded content toast variant. -
+
@@ -112,7 +112,7 @@ Warning alerts present information about the action that is about to be taken th - undefined} color={colors.orange.base} icon={} @@ -121,10 +121,10 @@ Warning alerts present information about the action that is about to be taken th > exceededSubLimitAt is a deprecated field. You can use it but it may not work as expected. - + - undefined} color={colors.orange.base} icon={} @@ -138,7 +138,7 @@ Warning alerts present information about the action that is about to be taken th > exceededSubLimitAt is a deprecated field. You can use it but it may not work as expected. - + @@ -148,7 +148,7 @@ Error alerts let the user know that something has gone wrong or is blocked in th - undefined} color={colors.red.base} icon={} @@ -156,10 +156,10 @@ Error alerts let the user know that something has gone wrong or is blocked in th style={{ marginBottom: 20 }} > Something is broken. You cannot perform this action at this time. - + - undefined} color={colors.red.base} icon={} @@ -168,7 +168,7 @@ Error alerts let the user know that something has gone wrong or is blocked in th style={{ marginBottom: 20 }} > Something is broken. You cannot perform this action at this time. - + @@ -178,17 +178,17 @@ Success alerts are confirmation that the action the user was trying to take has - undefined} color={colors.green.base} icon={} heading="Success alert" > A new schema registry has been created by timbotnik. - + - undefined} color={colors.green.base} icon={} @@ -196,7 +196,7 @@ Success alerts are confirmation that the action the user was trying to take has heading="Success alert" > A new schema registry has been created by timbotnik. - + @@ -204,4 +204,4 @@ Success alerts are confirmation that the action the user was trying to take has ### `Alert` - + diff --git a/src/Alert/Alert.tsx b/src/AlertCard/AlertCard.tsx similarity index 98% rename from src/Alert/Alert.tsx rename to src/AlertCard/AlertCard.tsx index 2891002d..358ac8cf 100644 --- a/src/Alert/Alert.tsx +++ b/src/AlertCard/AlertCard.tsx @@ -10,7 +10,7 @@ import { colors, PaletteColor } from "../colors"; import { getOffsetInPalette } from "../colors/utils/getOffsetInPalette"; import { assertUnreachable } from "../shared/assertUnreachable"; -interface AlertProps { +interface AlertCardProps { /** * color theme for alert * @default "light" @@ -67,7 +67,7 @@ interface AlertProps { style?: CSSProperties; } -export const Alert: React.FC = ({ +export const AlertCard: React.FC = ({ heading, onClose, actions, @@ -215,7 +215,7 @@ export const Alert: React.FC = ({ ); }; -Alert.propTypes = { +AlertCard.propTypes = { extended: PropTypes.bool, onClose: PropTypes.func.isRequired, children: PropTypes.node, diff --git a/src/AlertCard/index.ts b/src/AlertCard/index.ts new file mode 100644 index 00000000..2029fbb9 --- /dev/null +++ b/src/AlertCard/index.ts @@ -0,0 +1 @@ +export * from "./AlertCard"; From 2b26b8677febc626e6a1f867d0ec09c68a1da87e Mon Sep 17 00:00:00 2001 From: Jeffrey Burt Date: Thu, 11 Jun 2020 16:59:32 -0400 Subject: [PATCH 18/18] switch back to type of alert prop --- src/AlertCard/AlertCard.story.mdx | 39 ++++---------- src/AlertCard/AlertCard.tsx | 86 +++++++++++++++---------------- 2 files changed, 51 insertions(+), 74 deletions(-) diff --git a/src/AlertCard/AlertCard.story.mdx b/src/AlertCard/AlertCard.story.mdx index 0e4ad487..7c06628a 100644 --- a/src/AlertCard/AlertCard.story.mdx +++ b/src/AlertCard/AlertCard.story.mdx @@ -1,10 +1,5 @@ -import { colors } from "../colors"; import { AlertCard } from "../AlertCard"; import { Button } from "../Button"; -import { IconInfoSolid } from "../icons/IconInfoSolid"; -import { IconErrorSolid } from "../icons/IconErrorSolid"; -import { IconWarningSolid } from "../icons/IconWarningSolid"; -import { IconSuccessSolid } from "../icons/IconSuccessSolid"; import { Description, Meta, @@ -30,8 +25,7 @@ Informational alerts present general info about something you are doing or worki undefined} - color={colors.blue.base} - icon={} + type="info" heading="Informational alert" > This is a general informational message telling you about something. Learn @@ -41,8 +35,7 @@ Informational alerts present general info about something you are doing or worki undefined} - color={colors.blue.base} - icon={} + type="info" theme="dark" heading="Informational alert" > @@ -60,8 +53,7 @@ The extended card variant is for rare use cases where an alert is the most appro undefined} - color={colors.blue.base} - icon={} + type="info" heading="Informational alert" extended={true} > @@ -83,8 +75,7 @@ The extended card variant is for rare use cases where an alert is the most appro undefined} - color={colors.blue.base} - icon={} + type="info" theme="dark" heading="Informational alert" extended={true} @@ -114,8 +105,7 @@ Warning alerts present information about the action that is about to be taken th undefined} - color={colors.orange.base} - icon={} + type="warn" heading="Warning alert" actions={} > @@ -126,8 +116,7 @@ Warning alerts present information about the action that is about to be taken th undefined} - color={colors.orange.base} - icon={} + type="warn" heading="Warning alert" theme="dark" actions={ @@ -150,8 +139,7 @@ Error alerts let the user know that something has gone wrong or is blocked in th undefined} - color={colors.red.base} - icon={} + type="error" heading="Error alert" style={{ marginBottom: 20 }} > @@ -161,8 +149,7 @@ Error alerts let the user know that something has gone wrong or is blocked in th undefined} - color={colors.red.base} - icon={} + type="error" heading="Error alert" theme="dark" style={{ marginBottom: 20 }} @@ -178,20 +165,14 @@ Success alerts are confirmation that the action the user was trying to take has - undefined} - color={colors.green.base} - icon={} - heading="Success alert" - > + undefined} type="success" heading="Success alert"> A new schema registry has been created by timbotnik. undefined} - color={colors.green.base} - icon={} + type="success" theme="dark" heading="Success alert" > diff --git a/src/AlertCard/AlertCard.tsx b/src/AlertCard/AlertCard.tsx index 358ac8cf..cc999f5d 100644 --- a/src/AlertCard/AlertCard.tsx +++ b/src/AlertCard/AlertCard.tsx @@ -1,14 +1,17 @@ /** @jsx jsx */ import { jsx, ClassNames } from "@emotion/core"; -import React, { CSSProperties, Fragment } from "react"; +import React, { CSSProperties, Fragment, useMemo } from "react"; import PropTypes from "prop-types"; import classnames from "classnames"; import { base } from "../typography"; import { IconClose } from "../icons/IconClose"; -import { colors, PaletteColor } from "../colors"; -import { getOffsetInPalette } from "../colors/utils/getOffsetInPalette"; +import { colors } from "../colors"; import { assertUnreachable } from "../shared/assertUnreachable"; +import { IconInfoSolid } from "../icons/IconInfoSolid"; +import { IconWarningSolid } from "../icons/IconWarningSolid"; +import { IconErrorSolid } from "../icons/IconErrorSolid"; +import { IconSuccessSolid } from "../icons/IconSuccessSolid"; interface AlertCardProps { /** @@ -17,17 +20,6 @@ interface AlertCardProps { */ theme?: "light" | "dark"; - /** - * The color used for the heading icon, the heading text will be 2 shades - * darker if light theme and 2 shaders lighter if a dark theme - */ - color: PaletteColor; - - /** - * The icon displayed to the left of the heading text - */ - icon: React.ReactElement<{ className?: string }>; - heading: React.ReactNode; /** @@ -65,6 +57,11 @@ interface AlertCardProps { className?: string; style?: CSSProperties; + + /** + * Type of alert, this is used to determine the color and icon in the title + */ + type: "info" | "warn" | "error" | "success"; } export const AlertCard: React.FC = ({ @@ -73,12 +70,25 @@ export const AlertCard: React.FC = ({ actions, headingAs = "h2", children, - color, - icon, theme = "light", extended = false, + type, ...otherProps }) => { + const { Icon, color: colorTemp } = useMemo(() => { + switch (type) { + case "info": + return { color: colors.blue, Icon: IconInfoSolid }; + case "warn": + return { color: colors.orange, Icon: IconWarningSolid }; + case "error": + return { color: colors.red, Icon: IconErrorSolid }; + case "success": + return { color: colors.green, Icon: IconSuccessSolid }; + default: + assertUnreachable(type); + } + }, [type]); return (
= ({ marginTop: 0, width: "100%", display: "flex", - color: getOffsetInPalette( - 2, + color: theme === "light" - ? "darker" + ? colorTemp.darker : theme === "dark" - ? "lighter" + ? colorTemp.lighter : assertUnreachable(theme), - color - ), ...base.base, }) ), children: ( - - {({ css, cx }) => - React.cloneElement(icon, { - className: classnames( - icon.props.className, - cx( - css({ - width: 20, - height: 20, - color, - marginRight: 13, - }) - ) - ), - }) - } - + {heading} ), @@ -221,12 +221,8 @@ AlertCard.propTypes = { children: PropTypes.node, heading: PropTypes.node.isRequired, actions: PropTypes.node, - color: PropTypes.oneOf( - Object.values(colors) - .map((color) => Object.values(color)) - .reduce((a, b) => a.concat(b)) as PaletteColor[] - ).isRequired, - icon: PropTypes.element.isRequired, + type: PropTypes.oneOf(["info", "warn", "error", "success"] as const) + .isRequired, headingAs: PropTypes.oneOfType([ PropTypes.element.isRequired, PropTypes.string.isRequired as any, // Using PropTypes.string to match keyof JSX.IntrinsicElements