Stream Rebranding (#2926)

* [CORL-901] Rebrand comment actions and body (#2889)

* [ADR] Use Relay over Apollo (#2881)

* chore: ADR on Relay and Apollo

* chore: typo

* chore: add neg cons

* chore: add another pos

* chore: remove neg, because apollo needed an introspection query as a build step too..

* chore: fix number

* chore: deco

* chore: typo

* chore: clarification

Co-authored-by: Wyatt Johnson <wyattjoh@gmail.com>

* chore: bump 6.0.0 (#2891)

* fix: added more checks to migration (#2894)

* Update stream username to new branding variables

CORL-901

* Update badges/tags to use new v2 controls

CORL-901

* Update timestamps to use new branding stream side

CORL-901

* Update stream edit action to new branding

CORL-901

* Update comment html body to new branding

CORL-901

* Update comment action buttons to new branding

CORL-901

* Update responsive styles for action buttons

CORL-901

* Set comment link colors to new branding blue

CORL-901

* Add children prop on ButtonsBar to align with tests

CORL-901

* Make Reported button text bolded and vivid red

CORL-901

* Make reaction buttons stream blue when reacted

CORL-901

* Make user badges bold text

CORL-901

* Set margins on comment action buttons

CORL-901

* Set aria-labels on reaction buttons

Ensures that we always have a usable aria
even when the reaction button is just an icon.

CORL-901

* Set aria-label's on Reply and Share button's

CORL-901

* Update tests to match stream branding changes

CORL-901

* Update color of "Read More of this conversation"

CORL-901

Co-authored-by: Vinh <vinh@vinh.tech>
Co-authored-by: Wyatt Johnson <wyattjoh@gmail.com>

* [CORL-942] In-Stream Mod rebranding (#2902)

* [ADR] Use Relay over Apollo (#2881)

* chore: ADR on Relay and Apollo

* chore: typo

* chore: add neg cons

* chore: add another pos

* chore: remove neg, because apollo needed an introspection query as a build step too..

* chore: fix number

* chore: deco

* chore: typo

* chore: clarification

Co-authored-by: Wyatt Johnson <wyattjoh@gmail.com>

* chore: bump 6.0.0 (#2891)

* fix: added more checks to migration (#2894)

* Update stream username to new branding variables

CORL-901

* Update badges/tags to use new v2 controls

CORL-901

* Update timestamps to use new branding stream side

CORL-901

* Update stream edit action to new branding

CORL-901

* Update comment html body to new branding

CORL-901

* Update comment action buttons to new branding

CORL-901

* Update responsive styles for action buttons

CORL-901

* Set comment link colors to new branding blue

CORL-901

* Add children prop on ButtonsBar to align with tests

CORL-901

* Make Reported button text bolded and vivid red

CORL-901

* Make reaction buttons stream blue when reacted

CORL-901

* Make user badges bold text

CORL-901

* Set margins on comment action buttons

CORL-901

* Set aria-labels on reaction buttons

Ensures that we always have a usable aria
even when the reaction button is just an icon.

CORL-901

* Set aria-label's on Reply and Share button's

CORL-901

* Update tests to match stream branding changes

CORL-901

* Update color of "Read More of this conversation"

CORL-901

* Update caret container to new branding

CORL-942

* Update moderation menu buttons to new branding

CORL-942

* Update in-stream ban popover to new branding

CORL-942

* Update reject tombstone to new branding

CORL-942

Co-authored-by: Vinh <vinh@vinh.tech>
Co-authored-by: Wyatt Johnson <wyattjoh@gmail.com>

* [CORL-939] Rebrand RTE and reply (#2904)

* [ADR] Use Relay over Apollo (#2881)

* chore: ADR on Relay and Apollo

* chore: typo

* chore: add neg cons

* chore: add another pos

* chore: remove neg, because apollo needed an introspection query as a build step too..

* chore: fix number

* chore: deco

* chore: typo

* chore: clarification

Co-authored-by: Wyatt Johnson <wyattjoh@gmail.com>

* chore: bump 6.0.0 (#2891)

* fix: added more checks to migration (#2894)

* Update stream username to new branding variables

CORL-901

* Update badges/tags to use new v2 controls

CORL-901

* Update timestamps to use new branding stream side

CORL-901

* Update stream edit action to new branding

CORL-901

* Update comment html body to new branding

CORL-901

* Update comment action buttons to new branding

CORL-901

* Update responsive styles for action buttons

CORL-901

* Set comment link colors to new branding blue

CORL-901

* Add children prop on ButtonsBar to align with tests

CORL-901

* Make Reported button text bolded and vivid red

CORL-901

* Make reaction buttons stream blue when reacted

CORL-901

* Make user badges bold text

CORL-901

* Set margins on comment action buttons

CORL-901

* Set aria-labels on reaction buttons

Ensures that we always have a usable aria
even when the reaction button is just an icon.

CORL-901

* Set aria-label's on Reply and Share button's

CORL-901

* Update tests to match stream branding changes

CORL-901

* Update color of "Read More of this conversation"

CORL-901

* Update caret container to new branding

CORL-942

* Update moderation menu buttons to new branding

CORL-942

* Update in-stream ban popover to new branding

CORL-942

* Update reject tombstone to new branding

CORL-942

* Update replyTo and rte to new branding

CORL-939

Co-authored-by: Vinh <vinh@vinh.tech>
Co-authored-by: Wyatt Johnson <wyattjoh@gmail.com>

* Update message box to new branding

CORL-981

* Update user profile comment history to new branding

CORL-983

* Update stream tabs to new branding

CORL-982

* Update my profile tab bar to new branding

CORL-902

* Update download comments to new branding

CORL-902

* The Lord of the Buttons: Return of the Buttons

* Update the notification settings area to new branding

CORL-984

* Update the ignored users area to new branding

CORL-984

* Update change username to new branding

CORL-984

* Fixing snaps after rebase

* Use label instead of div for InputLabel's

Root element is now a label so that axe
will stop complaining that it can't find
the 'for' id on the label elements.

CORL-984

* More spacing tweaks for change username

CORL-903

* Update change email address to new branding

CORL-984

* Update change password to new branding

CORL-984

* Flesh out colour styles for v3 buttons

CORL-984

* Preliminarily update delete account to new branding

CORL-984

* Ensure client CSS style compatibility

CORL-984

* Update delete flow to new branding

CORL-984

* Add client classes to the delete account modal

CORL-984

* Further tweaks to the delete account modal

Modal callouts updated to new branding.
Deletion request callout updated to new
branding.
Fixing up tests that somehow were passing
before?
Fixing some margins and spacing around
deletion section.

* Move the account deletion callout to top

Puts it at the top of the my profile tab
so that it's clearly visible you are
deleting your account.

CORL-998

* Add first-class icon and title support to callouts

CORL-969

* Bold checkbox text when checked

CORL-984

* Finalize v3 buttons to match spec

This should be the last major change to
v3 buttons as the spec seems to have
solidified.

CORL-969

* Add in new stream red to colours

Use it for the negative v3 callouts

CORL-969

* Touch up some spacing on delete account

CORL-984

* Create tombstone component

Use it for ignored and deleted account
tombstones instead of the old callout.

CORL-969

* Use new tombstones in comment stream

CORL-969

* Update banned callout to new branding

CORL-969

* Set callout body text to regular font weight

CORL-969

* Update suspended callout to new branding

CORL-969

* Update closed stream callouts to new branding

CORL-969

* Update in-moderation callouts to new branding

CORL-969

* Update stream validation message to v3

CORL-969

* Improve ignored commenter management

Show "you are no longer ignoring" a
commenter when you choose to no longer
ignore them.

CORL-457

* Prettier cleanup after rebase off master

Somehow this was missed, probably needed to
kill and reload VSCode before I committed the
rebase.

* Switch previous callouts to use icon and title

CORL-969

* Update configure checkboxes to new branding

CORL-903

* Update Config > Q&A to new branding

CORL-903

* Update Config > Open/Close Stream to new branding

CORL-903

* Add validation message to config stream checkboxes

CORL-903

* Remove double list handling for Pref>Ignored

CORL-969

* Show experimental tag beside Q&A config

CORL-1051

* Move live update setting to its own section

CORL-903

* Remove moderation link from config area

CORL-903

* De-capitalize all the labels in configure

CORL-903

* Update message box config to new branding

Also moves it to new location in config.

CORL-903

* Re-brand the sign in/out field on the stream

CORL-1042

* Update tests for add message flow

CORl-903

* Rebrand Sign In/Up modals

CORL-999

* Re-brand SSO sign in/up modals

CORL-999

* Re-brand stream sorting controls

CORL-1043

* Create new stream focused colorFromMeta variant

* Rebrand go to moderation buttons

CORL-799

* Rebrand stream moderation drop-down

CORL-799

* Rebrand the report comment flow

Expands the report comment dialogs under
the comment instead of as a popover.
Also adds in the new branding styles.

CORL-941

* Rebrand the main stream tab bar

CORL-799

* Add new abusive reporting options

CORL-1009

* Rebrand featured comments

CORL-968

* Rebrand the community guidelines

CORL-1041

* Rebrand the share button

CORL-940

* Update style names on buttons

marginSize -> paddingSize
textSize -> fontSize

* Rebrand single conversation view

CORL-904

* Make indented comments grey coloured

CORL-904

* Make indented comment borders thinner

CORL-904

* Tweak colours/margins on single conversation view

CORL-904

* Add show comment on single conversation tombstones

CORL-412

* Rebrand single conversation view title

CORL-904

* Add clean target to package.json

Allows us to direct call gulp clean easily.

* Rebrand client side not found page

CORL-1025

* Rebrand password reset flow

CORL-1025

* Rebrand unsubscribe from notifications flow

CORL-1025

* Rebrand email confirmation flow

CORL-1025

* Rebrand download comments flow

CORL-1025

* Fix up account tests after rebrand

CORL-1025

* Add COMMENT_REPORTED_ABUSIVE to moderate card fragment

* Rebrand user ignore flow

Somehow this slipped through the cracks, fixed
it up now

* [CORL 1010] Collapse comment threads (#2976)

* toggle open and closed comment + replies

* show username and date for collapsed comment

* toggle comments and replies open and closed

* keep collapsed state of comments in reply list

* style collapsed comment toggle

* add css class overrides

* style answered comments when collapsed

* adjust spacing on collapse button:

* add hover styles

* add aria labels and update snapshots

* Fix tests and snaps after rebase

* Make main stream tabs visible on mobile (iPhone 5)

* Remove double horizontal rule under My Comments

Horizontal rule wasn't conditionally showing
when we toggled ability to let users download
comments on and off.

* Add aria labelling to main stream tabs

Can now pass in a localization id to assign
aria-label/title to the tab.

* Add localization to account not found

* Update snapshots

Co-authored-by: Vinh <vinh@vinh.tech>
Co-authored-by: Wyatt Johnson <wyattjoh@gmail.com>
Co-authored-by: Tessa Thornton <tessathornton@gmail.com>
This commit is contained in:
Nick Funk
2020-06-12 09:23:28 -06:00
committed by GitHub
co-authored by Vinh Wyatt Johnson Tessa Thornton
parent 8966dad344
commit ebe7731222
470 changed files with 24850 additions and 15475 deletions
@@ -600,7 +600,7 @@
&.mouseHover {
color: var(--palette-error-main);
& > span {
text-decoration: underline;
text-decoration: variantOutlined;
}
}
&.active,
@@ -0,0 +1,2 @@
.root {
}
@@ -0,0 +1,34 @@
import React, { FunctionComponent, useMemo } from "react";
import { useUIContext } from "coral-ui/components/v2";
import { PropTypesOf } from "coral-ui/types";
interface Props {
date: string;
className?: string;
locales?: string[];
}
const AbsoluteTime: FunctionComponent<Props> = ({
date,
className,
locales: localesFromProps,
}) => {
const { locales: localesFromContext } = useUIContext();
const locales = localesFromProps || localesFromContext || ["en-US"];
const formatted = useMemo(() => {
const formatter = new Intl.DateTimeFormat(locales, {
year: "numeric",
month: "long",
day: "numeric",
hour: "numeric",
minute: "2-digit",
});
return formatter.format(new Date(date));
}, [locales, date]);
return <span className={className}>{formatted}</span>;
};
export default AbsoluteTime;
export type AbsoluteTimeProps = PropTypesOf<typeof AbsoluteTime>;
@@ -0,0 +1 @@
export { default, AbsoluteTimeProps } from "./AbsoluteTime";
@@ -89,6 +89,15 @@ const BaseButton: FunctionComponent<Props> = ({
type = "button";
}
/**
* Added as a security workaround as per:
*
* https://www.jitbit.com/alexblog/256-targetblank---the-most-underestimated-vulnerability-ever/
*/
if (rest.target === "_blank") {
rest.rel = "noopener noreferrer";
}
const rootClassName = cn(classes.root, className, {
[classes.keyboardFocus]: keyboardFocus,
[classes.mouseHover]: mouseHover,
@@ -31,20 +31,24 @@ $button-regular-mono-background: var(--v2-colors-grey-500);
$button-regular-alert-background: var(--v2-colors-red-500);
$button-regular-alt-background: var(--v2-colors-green-500);
$button-regular-dark-background: var(--v2-colors-blue-500);
$button-regular-stream-background: var(--v2-colors-stream-blue-500);
$button-regular-regular-background-hover: var(--v2-colors-teal-700);
$button-regular-mono-background-hover: var(--v2-colors-grey-600);
$button-regular-alert-background-hover: var(--v2-colors-red-600);
$button-regular-alt-background-hover: var(--v2-colors-green-600);
$button-regular-dark-background-hover: var(--v2-colors-blue-600);
$button-regular-stream-background-hover: var(--v2-colors-stream-blue-600);
$button-regular-regular-background-active: var(--v2-colors-teal-800);
$button-regular-mono-background-active: var(--v2-colors-grey-700);
$button-regular-alert-background-active: var(--v2-colors-red-700);
$button-regular-alt-background-active: var(--v2-colors-green-700);
$button-regular-dark-background-active: var(--v2-colors-blue-700);
$button-regular-stream-background-active: var(--v2-colors-stream-blue-700);
$button-regular-background-disabled: var(--v2-colors-grey-300);
$button-regular-stream-background-disabled: var(--v2-colors-stream-blue-200);
/* outline button */
$button-outline-background: var(--v2-colors-pure-white);
@@ -196,7 +200,24 @@ $button-text-dark-foreground-active: var(--v2-colors-blue-700);
&:disabled,
&.disabled {
background-color: $button-regular-background-disabled;
&.colorRegular {
background-color: $button-regular-background-disabled;
}
&.colorStream {
background-color: $button-regular-stream-background-disabled;
}
&.colorMono {
background-color: $button-regular-background-disabled;
}
&.colorAlert {
background-color: $button-regular-background-disabled;
}
&.colorAlt {
background-color: $button-regular-background-disabled;
}
&.colorMono {
background-color: $button-regular-background-disabled;
}
}
&:not(.disabled),
@@ -213,6 +234,18 @@ $button-text-dark-foreground-active: var(--v2-colors-blue-700);
}
}
&.colorStream {
background-color: $button-regular-stream-background;
&:hover,
&.mouseHover {
background-color: $button-regular-stream-background-hover;
}
&:active,
&.active {
background-color: $button-regular-stream-background-active;
}
}
&.colorMono {
background-color: $button-regular-mono-background;
&:hover,
@@ -487,6 +520,139 @@ $button-text-dark-foreground-active: var(--v2-colors-blue-700);
}
}
.variantUnderlined {
padding-right: 0;
padding-left: 0;
border-radius: 0;
border-bottom: 1px solid currentColor;
padding: 0;
&.colorRegular {
color: $button-text-regular-foreground;
}
&.colorMono {
color: $button-text-mono-foreground;
}
&.colorAlt {
color: $button-text-alt-foreground;
}
&.colorAlert {
color: $button-text-alert-foreground;
}
&.colorDark {
color: $button-text-dark-foreground;
}
&:not(.disabled) {
&.colorRegular {
&.mouseHover {
color: $button-text-regular-foreground-hover;
}
&:active,
&.active {
color: $button-text-regular-foreground-active;
}
}
&.colorMono {
&.mouseHover {
color: $button-text-mono-foreground-hover;
}
&:active,
&.active {
color: $button-text-mono-foreground-active;
}
}
&.colorAlt {
&.mouseHover {
color: $button-text-alt-foreground-hover;
}
&:active,
&.active {
color: $button-text-alt-foreground-active;
}
}
&.colorAlert {
&.mouseHover {
color: $button-text-alert-foreground-hover;
}
&:active,
&.active {
color: $button-text-alert-foreground-active;
}
}
&.colorDark {
&.mouseHover {
color: $button-text-dark-foreground-hover;
}
&:active,
&.active {
color: $button-text-dark-foreground-active;
}
}
}
}
.variantTextUnderlined {
font-weight: var(--v2-font-weight-primary-bold);
font-family: var(--v2-font-family-primary);
text-decoration: underline;
&.colorRegular {
color: $button-text-regular-foreground;
}
&.colorMono {
color: $button-text-mono-foreground;
}
&.colorAlert {
color: $button-text-alert-foreground;
}
&:not(.disabled) {
&.colorRegular {
&.mouseHover {
color: $button-text-regular-foreground-hover;
& > span {
text-decoration: underline;
}
}
&.active,
&:active {
color: $button-text-regular-foreground-active;
}
}
&.colorMono {
&.mouseHover {
color: $button-text-mono-foreground-hover;
& > span {
text-decoration: underline;
}
}
&.active,
&:active {
color: $button-text-mono-foreground-active;
}
}
&.colorAlert {
&.mouseHover {
color: $button-text-alert-foreground-hover;
& > span {
text-decoration: variantOutlined;
}
}
&.active,
&:active {
color: $button-text-alert-foreground-active;
}
}
}
}
.linkButton {
text-decoration: none;
}
@@ -25,10 +25,16 @@ interface Props extends Omit<BaseButtonProps, "ref"> {
size?: "regular" | "large";
/** Color of the button */
color?: "regular" | "alert" | "mono" | "alt" | "dark";
color?: "regular" | "alert" | "mono" | "alt" | "dark" | "stream";
/** Variant of the button */
variant?: "regular" | "flat" | "outline" | "text";
variant?:
| "regular"
| "flat"
| "outline"
| "text"
| "underlined"
| "textUnderlined";
/* button is attached to the LEFT of an input element */
adornmentLeft?: boolean;
@@ -100,10 +106,13 @@ export class Button extends React.Component<Props> {
[classes.colorAlt]: color === "alt",
[classes.colorMono]: color === "mono",
[classes.colorDark]: color === "dark",
[classes.colorStream]: color === "stream",
[classes.variantRegular]: variant === "regular",
[classes.variantFlat]: variant === "flat",
[classes.variantOutline]: variant === "outline",
[classes.variantText]: variant === "text",
[classes.variantUnderlined]: variant === "underlined",
[classes.variantTextUnderlined]: variant === "textUnderlined",
[classes.uppercase]: uppercase,
[classes.fullWidth]: fullWidth,
[classes.active]: active,
@@ -40,6 +40,7 @@
height: 14px;
background: var(--v2-palette-input-background);
border: 1px solid var(--v2-palette-input-label);
border-radius: 2px;
box-sizing: border-box;
}
@@ -49,11 +50,21 @@
}
/* Box checked */
.input:checked + .label:before {
input:checked.default + .label:before {
background: var(--v2-palette-primary-main);
border: 1px solid var(--v2-palette-primary-main);
}
.input:checked.streamBlue + .label:before {
background: var(--v2-colors-stream-blue-500);
border: 1px solid var(--v2-colors-stream-blue-500);
}
input:checked + .label {
font-weight: var(--v2-font-weight-primary-bold);
}
/* Disabled state label. */
.input:disabled + .label {
cursor: auto;
@@ -40,6 +40,8 @@ export interface CheckBoxProps {
*/
light?: boolean;
variant?: "default" | "streamBlue";
// These handlers are passed down by the `withKeyboardFocus` HOC.
onFocus: EventHandler<FocusEvent<HTMLElement>>;
onBlur: EventHandler<FocusEvent<HTMLElement>>;
@@ -58,16 +60,27 @@ class CheckBox extends Component<CheckBoxProps> {
light,
children,
keyboardFocus,
variant = "default",
...rest
} = this.props;
const rootClassName = cn(classes.root, className);
const rootClassName = cn(
classes.root,
{
[classes.default]: variant === "default",
[classes.streamBlue]: variant === "streamBlue",
},
className
);
const finalID = id || this.state.randomID;
return (
<div className={rootClassName}>
<input
className={classes.input}
className={cn(classes.input, {
[classes.default]: variant === "default",
[classes.streamBlue]: variant === "streamBlue",
})}
type="checkbox"
id={finalID}
{...rest}
@@ -76,6 +89,8 @@ class CheckBox extends Component<CheckBoxProps> {
className={cn(classes.label, {
[classes.labelLight]: light,
[classes.focus]: keyboardFocus,
[classes.default]: variant === "default",
[classes.streamBlue]: variant === "streamBlue",
})}
htmlFor={finalID}
>
@@ -2,18 +2,18 @@
exports[`renders correctly 1`] = `
<div
className="CheckBox-root custom"
className="CheckBox-root CheckBox-default custom"
>
<input
checked={true}
className="CheckBox-input"
className="CheckBox-input CheckBox-default"
id="checkboxID"
onBlur={[Function]}
onFocus={[Function]}
type="checkbox"
/>
<label
className="CheckBox-label"
className="CheckBox-label CheckBox-default"
htmlFor="checkboxID"
>
<span
@@ -36,13 +36,13 @@
justify-content: baseline;
align-items: center;
color: var(--v2-palette-grey-main);
margin-right: var(--spacing-2);
margin-right: var(--v2-spacing-2);
}
.iconAfter {
display: flex;
align-items: center;
justify-content: baseline;
margin-left: var(--spacing-2);
margin-left: var(--v2-spacing-2);
text-decoration: unset;
}
.iconOpenInNew {
@@ -1,9 +1,9 @@
import cn from "classnames";
import React, { FunctionComponent } from "react";
import { Flex } from "coral-ui/components";
import Icon from "coral-ui/components/Icon";
import { Flex } from "coral-ui/components/v2";
import BaseButton, { BaseButtonProps } from "coral-ui/components/v2/BaseButton";
import Icon from "coral-ui/components/v2/Icon";
import { withStyles } from "coral-ui/hocs";
import styles from "./Button.css";
@@ -0,0 +1,5 @@
.root {
border: 0;
border-bottom: 1px solid var(--v2-colors-grey-300);
padding-top: 1px;
}
@@ -0,0 +1,14 @@
import cn from "classnames";
import React, { FunctionComponent } from "react";
import styles from "./HorizontalRule.css";
interface Props {
className?: string;
}
const HorizontalRule: FunctionComponent<Props> = ({ className }) => (
<hr className={cn(styles.root, className)} />
);
export default HorizontalRule;
@@ -0,0 +1 @@
export { default } from "./HorizontalRule";
@@ -57,3 +57,7 @@
.colorSuccess {
color: var(--v2-colors-green-500);
}
.colorStream {
color: var(--v2-colors-stream-blue-500);
}
@@ -6,6 +6,8 @@ import { PropTypesOf } from "coral-ui/types";
import styles from "./Icon.css";
export type IconColor = "inherit" | "primary" | "error" | "success" | "stream";
interface Props extends HTMLAttributes<HTMLSpanElement> {
/**
* This prop can be used to add custom classnames.
@@ -18,7 +20,7 @@ interface Props extends HTMLAttributes<HTMLSpanElement> {
/**
* The color of the component. It supports those theme colors that make sense for this component.
*/
color?: "inherit" | "primary" | "error" | "success";
color?: IconColor;
/** The name of the icon to render */
children: string;
@@ -37,6 +39,7 @@ const Icon: FunctionComponent<Props> = (props) => {
[classes.colorPrimary]: color === "primary",
[classes.colorError]: color === "error",
[classes.colorSuccess]: color === "success",
[classes.colorStream]: color === "stream",
},
className
);
@@ -28,9 +28,9 @@ const InputLabelProps: FunctionComponent<InputLabelProps> = (props) => {
const rootClassName = cn(classes.root, className);
return (
<div className={rootClassName} {...rest}>
<label className={rootClassName} {...rest}>
{children}
</div>
</label>
);
};
@@ -1,9 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<div
<label
className="InputLabel-root custom"
>
Hello
</div>
</label>
`;
@@ -0,0 +1,40 @@
---
name: MatchMedia
menu: UI Kit
---
import { Playground, PropsTable } from 'docz'
import MatchMedia from './MatchMedia'
# MatchMedia
`MatchMedia` uses media queries to provide responsive rendering.
## Basic usage
<Playground>
<MatchMedia lteWidth="xs">
I'm a very small screen
</MatchMedia>
<MatchMedia gtWidth="xs" lteWidth="sm">
I'm a small screen
</MatchMedia>
<MatchMedia gtWidth="sm" lteWidth="md">
I'm a medium screen
</MatchMedia>
<MatchMedia gtWidth="md" lteWidth="lg">
I'm a large screen
</MatchMedia>
<MatchMedia gtWidth="lg" lteWidth="xl">
I'm a very large screen
</MatchMedia>
<MatchMedia gtWidth="xl">
I'm a super large screen
</MatchMedia>
</Playground>
## Using render props
<Playground>
<MatchMedia lteWidth="lg">
{matches => <span>{matches ? "I'm big" : "I'm small"}</span>}
</MatchMedia>
</Playground>
@@ -0,0 +1,60 @@
import { mount } from "enzyme";
import React from "react";
import { MediaQueryMatchers } from "react-responsive";
import { createRenderer } from "react-test-renderer/shallow";
import { PropTypesOf } from "coral-ui/types";
import UIContext from "../UIContext";
import { default as MatchMediaWithContext, MatchMedia } from "./MatchMedia";
it("renders correctly", () => {
const props: PropTypesOf<typeof MatchMedia> = {
lteWidth: "xs",
gteWidth: "sm",
component: "div",
screen: true,
children: <div>Hello World</div>,
};
const renderer = createRenderer();
renderer.render(<MatchMedia {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
it("renders less than and great than correctly", () => {
const props: PropTypesOf<typeof MatchMedia> = {
ltWidth: "xs",
gtWidth: "sm",
children: <div>Hello World</div>,
};
const renderer = createRenderer();
renderer.render(<MatchMedia {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
it("map new speech prop to older aural prop", () => {
const props: PropTypesOf<typeof MatchMedia> = {
speech: true,
children: <div>Hello World</div>,
};
const renderer = createRenderer();
renderer.render(<MatchMedia {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
it("should get mediaQueryValues from context", () => {
const mediaQueryValues: Partial<MediaQueryMatchers> = {
width: 100,
};
const context: any = {
mediaQueryValues,
};
const wrapper = mount(
<UIContext.Provider value={context}>
<MatchMediaWithContext lteWidth="xs">
<span>Hello World</span>
</MatchMediaWithContext>
</UIContext.Provider>
);
expect(wrapper.find(MatchMedia).prop("values")).toEqual(mediaQueryValues);
});
@@ -0,0 +1,65 @@
import React, { FunctionComponent, ReactNode } from "react";
import Responsive, { MediaQueryMatchers } from "react-responsive";
import { UIContext } from "coral-ui/components/v2";
import theme from "coral-ui/theme/variables2";
import { PropTypesOf } from "coral-ui/types";
type Breakpoints = keyof typeof theme.breakpoints;
interface Props {
/** greater than or equal width. */
gteWidth?: Breakpoints;
/** greater than width. */
gtWidth?: Breakpoints;
/** less than equals width. */
lteWidth?: Breakpoints;
/** less than equals width. */
ltWidth?: Breakpoints;
children: ReactNode | ((matches: boolean) => React.ReactNode);
className?: string;
component?:
| string
| React.SFC<any>
| React.ClassType<any, any, any>
| React.ComponentClass<any>;
all?: boolean;
print?: boolean;
screen?: boolean;
speech?: boolean;
values?: Partial<MediaQueryMatchers>;
}
export const MatchMedia: FunctionComponent<Props> = (props) => {
const { speech, gteWidth, gtWidth, lteWidth, ltWidth, ...rest } = props;
const mapped = {
// TODO: Temporarily map newer speech to older aural type until
// react-responsive supports the speech prop.
aural: speech,
minWidth: gtWidth
? theme.breakpoints[gtWidth] + 1
: gteWidth
? theme.breakpoints[gteWidth]
: undefined,
maxWidth: ltWidth
? theme.breakpoints[ltWidth] - 1
: lteWidth
? theme.breakpoints[lteWidth]
: undefined,
};
return <Responsive {...rest} {...mapped} />;
};
const MatchMediaWithContext: FunctionComponent<Props> = (props) => (
<UIContext.Consumer>
{({ mediaQueryValues }) => (
<MatchMedia {...props} values={mediaQueryValues} />
)}
</UIContext.Consumer>
);
export default MatchMediaWithContext;
export type MatchMediaProps = PropTypesOf<typeof MatchMediaWithContext>;
@@ -0,0 +1,35 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`map new speech prop to older aural prop 1`] = `
<MediaQuery
aural={true}
>
<div>
Hello World
</div>
</MediaQuery>
`;
exports[`renders correctly 1`] = `
<MediaQuery
component="div"
maxWidth={320}
minWidth={640}
screen={true}
>
<div>
Hello World
</div>
</MediaQuery>
`;
exports[`renders less than and great than correctly 1`] = `
<MediaQuery
maxWidth={319}
minWidth={641}
>
<div>
Hello World
</div>
</MediaQuery>
`;
@@ -0,0 +1 @@
export { default, MatchMediaProps } from "./MatchMedia";
@@ -11,10 +11,21 @@
border: 1px solid var(--v2-palette-input-border);
}
.colorStreamBlue {
background-color: var(--v2-palette-input-background);
color: var(--v2-palette-input-value);
border: 1px solid var(--v2-palette-input-border);
&:focus {
border: 1px solid var(--v2-colors-stream-blue-500);
box-shadow: inset 0px 0px 0px 1px var(--v2-colors-stream-blue-500);
}
}
.colorError {
background-color: var(--v2-palette-input-background);
border-color: var(--v2-palette-error-main);
border: 2px solid var(--v2-palette-error-darkest);
border-color: var(--v2-colors-red-500);
border: 2px solid var(--v2-colors-red-500);
}
.fullWidth {
@@ -34,7 +34,7 @@ export interface PasswordFieldProps {
/**
* Color of the PasswordField
*/
color?: "regular" | "error";
color?: "regular" | "streamBlue" | "error";
/*
* If set renders a full width button
*/
@@ -124,6 +124,7 @@ class PasswordField extends Component<PasswordFieldProps, State> {
const inputClassName = cn(
{
[classes.colorRegular]: color === "regular",
[classes.colorStreamBlue]: color === "streamBlue",
[classes.colorError]: color === "error",
[classes.fullWidth]: fullWidth,
},
@@ -19,16 +19,23 @@
border: 1px solid var(--v2-palette-input-focused-border);
}
.select {
-webkit-appearance: none;
-moz-appearance: none;
.selectFont {
font-family: var(--v2-font-family-primary);
font-weight: var(--v2-font-weight-primary-regular);
font-size: var(--v2-font-size-3);
line-height: var(--v2-line-height-reset);
}
.selectColor {
color: var(--v2-palette-input-value);
}
.select {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
outline: none;
color: var(--v2-palette-input-value);
width: 100%;
&::-moz-focus-inner {
@@ -32,6 +32,7 @@ export interface SelectFieldProps {
autofocus?: boolean;
name?: string;
onChange?: EventHandler<ChangeEvent<HTMLSelectElement>>;
onClick?: EventHandler<React.MouseEvent>;
disabled?: boolean;
// These handlers are passed down by the `withKeyboardFocus` HOC.
@@ -58,9 +59,14 @@ const SelectField: FunctionComponent<SelectFieldProps> = (props) => {
[classes.fullWidth]: fullWidth,
});
const selectClassName = cn(classes.select, {
[classes.keyboardFocus]: keyboardFocus,
});
const selectClassName = cn(
classes.select,
classes.selectFont,
classes.selectColor,
{
[classes.keyboardFocus]: keyboardFocus,
}
);
const afterWrapperClassName = cn(classes.afterWrapper, {
[classes.afterWrapperDisabled]: disabled,
@@ -6,7 +6,7 @@ exports[`renders correctly 1`] = `
>
<select
autofocus={true}
className="SelectField-select"
className="SelectField-select SelectField-selectFont SelectField-selectColor"
disabled={true}
id="selectID"
name="selectName"
@@ -0,0 +1,23 @@
.root {
display: inline-block;
width: 20px;
height: 20px;
background-color: var(--v2-colors-pure-white);
border: 2px solid var(--v2-colors-grey-400);
box-sizing: border-box;
border-radius: 100%;
z-index: 1;
}
.active,
.completed {
background-color: var(--v2-colors-green-400);
border-color: var(--v2-colors-green-400);
}
.icon {
color: var(--v2-colors-pure-white);
font-weight: bold;
margin-top: -8px;
margin-left: 1px;
}
@@ -0,0 +1,25 @@
import cn from "classnames";
import React, { FunctionComponent } from "react";
import Icon from "../Icon";
import styles from "./Circle.css";
interface CircleProps {
active?: boolean;
completed?: boolean;
}
const Circle: FunctionComponent<CircleProps> = ({ active, completed }) => {
const rootClassName = cn(styles.root, {
[styles.active]: active,
[styles.completed]: completed,
});
return (
<span className={rootClassName}>
{completed && <Icon className={styles.icon}>done</Icon>}
</span>
);
};
export default Circle;
@@ -0,0 +1,12 @@
.root {
display: inline-block;
width: 200px;
height: 0px;
border: 1px solid var(--v2-colors-grey-400);
box-sizing: border-box;
z-index: 1;
}
.completed {
border-color: var(--v2-colors-green-400);
}
@@ -0,0 +1,22 @@
import cn from "classnames";
import React, { FunctionComponent } from "react";
import styles from "./Line.css";
interface LineProps {
completed?: boolean;
className?: string;
}
const Line: FunctionComponent<LineProps> = ({ completed, className }) => {
const rootClassName = cn(
styles.root,
{
[styles.completed]: completed,
},
className
);
return <span className={rootClassName} />;
};
export default Line;
@@ -0,0 +1,18 @@
.root {
position: relative;
}
.text {
font-family: var(--v2-font-family-primary);
font-weight: var(--v2-font-weight-primary-regular);
font-size: var(--v2-font-size-3);
line-height: var(--v2-line-height-5);
color: var(--v2-colors-mono-500);
position: absolute;
top: 26px;
transform: translateX(-50%);
left: 8%;
white-space: nowrap;
}
@@ -0,0 +1,49 @@
import React, { Component, ReactNode, ReactText } from "react";
import Flex from "coral-ui/components/v2/Flex";
import Circle from "./Circle";
import Line from "./Line";
import styles from "./Step.css";
interface StepProps {
children?: ReactText | ReactNode;
active?: boolean;
completed?: boolean;
last?: boolean;
hidden?: boolean;
classes?: {
line?: string;
};
}
class Step extends Component<StepProps> {
public render() {
const { children, completed, active, last, hidden, classes } = this.props;
if (hidden) {
return null;
}
return (
<div className={styles.root}>
<Flex
direction="row"
justifyContent="center"
alignItems="center"
itemGutter
>
<Circle completed={completed} active={active} />
{!last && (
<Line
completed={completed}
className={classes ? classes.line : undefined}
/>
)}
</Flex>
<div className={styles.text}>{children}</div>
</div>
);
}
}
export default Step;
@@ -0,0 +1,6 @@
.root {
width: 100%;
position: relative;
display: block;
padding: calc(2 * var(--mini-unit)) 0;
}
@@ -0,0 +1,43 @@
import cn from "classnames";
import React, { Component, ReactNode } from "react";
import Flex from "../Flex";
import styles from "./StepBar.css";
interface StepBarProps {
children: ReactNode;
currentStep: number;
className?: string;
}
class StepBar extends Component<StepBarProps> {
public render() {
const { children, currentStep } = this.props;
const steps = React.Children.toArray(children);
const stepsToRender = steps
.filter((child: React.ReactElement<any>) => !child.props.hidden)
.map((child: React.ReactElement<any>, index: number, arr) =>
React.cloneElement(child, {
last: arr.length - 1 === index,
active: currentStep === index,
completed: currentStep > index,
})
);
return (
<div className={cn(styles.root, this.props.className)}>
<Flex
direction="row"
itemGutter
alignItems="center"
justifyContent="center"
>
{stepsToRender}
</Flex>
</div>
);
}
}
export default StepBar;
@@ -0,0 +1,2 @@
export { default as StepBar } from "./StepBar";
export { default as Step } from "./Step";
@@ -0,0 +1,19 @@
---
name: Steps
menu: UI Kit
---
# Steps
### Examples
import { Playground } from 'docz'
import { Flex, Step, StepBar } from './index'
<Playground>
<StepBar currentStep={1}>
<Step>Create Admin Account</Step>
<Step>Add Organization Details</Step>
<Step>Add Permitted Domains</Step>
</StepBar>
</Playground>
+88 -5
View File
@@ -1,11 +1,12 @@
$tab-selected: var(--v2-colors-teal-600);
$tab-default: var(--v2-colors-mono-100);
$tab-stream-selected: var(--v2-colors-stream-blue-500);
$tab-stream-default: var(--v2-colors-mono-500);
.root {
display: inline-block;
list-style: none;
margin-right: var(--v2-spacing-3);
margin-bottom: -1px;
}
.button {
@@ -27,6 +28,9 @@ $tab-default: var(--v2-colors-mono-100);
}
.default {
margin-right: var(--v2-spacing-3);
margin-bottom: -1px;
font-family: var(--v2-font-family-primary);
font-weight: var(--v2-font-weight-primary-semi-bold);
color: $tab-default;
@@ -58,15 +62,94 @@ $tab-default: var(--v2-colors-mono-100);
}
.secondary {
font-family: var(--font-family-sans-serif);
margin-right: var(--v2-spacing-3);
margin-bottom: -1px;
font-family: var(--v2-font-family-primary);
color: $tab-default;
padding-bottom: var(--v2-spacing-2);
text-transform: uppercase;
&.active {
color: $tab-selected;
font-weight: var(--font-weight-medium);
font-weight: var(--v2-font-weight-primary-bold);
border-bottom: 3px solid $tab-selected;
padding-bottom: calc(var(--v2-spacing-2) - 3px);
}
}
.streamSecondary {
margin-right: var(--v2-spacing-3);
margin-bottom: -1px;
font-family: var(--v2-font-family-primary);
color: $tab-stream-default;
padding-bottom: var(--v2-spacing-2);
&.active {
color: $tab-stream-selected;
font-weight: var(--v2-font-weight-primary-bold);
border-bottom: 3px solid $tab-stream-selected;
padding-bottom: calc(var(--v2-spacing-2) - 3px);
}
}
.streamPrimary {
position: relative;
margin-right: 0px;
margin-bottom: -1px;
padding-top: var(--v2-spacing-3);
padding-bottom: var(--v2-spacing-3);
padding-left: var(--v2-spacing-6);
padding-right: var(--v2-spacing-6);
background: var(--v2-colors-grey-100);
border: 1px solid var(--v2-colors-grey-300);
border-bottom-width: 0px;
font-family: var(--v2-font-family-secondary);
font-style: normal;
font-weight: var(--v2-font-weight-secondary-regular);
font-size: var(--v2-font-size-4);
line-height: var(--v2-line-height-5);
color: var(--v2-colors-mono-500);
&.active {
z-index: 10;
background-color: var(--v2-colors-pure-white);
border-bottom: 0;
border-radius: 0;
color: var(--v2-colors-stream-blue-500);
font-weight: var(--v2-font-weight-secondary-bold);
border-top: 1px solid var(--v2-colors-stream-blue-500);
overflow: visible;
}
}
.streamPrimary.active::before {
position: absolute;
top: -1px;
left: -1px;
width: calc(100% + 2px);
height: 4px;
background-color: var(--v2-colors-stream-blue-500);
color: var(--v2-colors-stream-blue-500);
content: "active";
overflow: hidden;
}
.root:not(:first-child) .streamPrimary {
border-left-width: 0px;
}
.uppercase {
text-transform: uppercase;
}
+55 -14
View File
@@ -1,9 +1,9 @@
import { Localized } from "@fluent/react/compat";
import cn from "classnames";
import React from "react";
import { withStyles } from "coral-ui/hocs";
import BaseButton from "coral-ui/components/v2/BaseButton";
import { withStyles } from "coral-ui/hocs";
import styles from "./Tab.css";
@@ -27,11 +27,21 @@ export interface TabProps {
/**
* Style variant
*/
variant?: "primary" | "secondary" | "default";
variant?:
| "primary"
| "secondary"
| "default"
| "streamSecondary"
| "streamPrimary";
/**
* Action taken on tab click
*/
onTabClick?: (tabID: string) => void;
uppercase?: boolean;
ariaLabel?: string;
localizationId?: string;
}
class Tab extends React.Component<TabProps> {
@@ -42,14 +52,27 @@ class Tab extends React.Component<TabProps> {
};
public render() {
const { className, classes, children, tabID, active, variant } = this.props;
const {
className,
classes,
children,
tabID,
active,
variant,
uppercase,
ariaLabel,
localizationId,
} = this.props;
const buttonClassName = cn(
classes.button,
{
[classes.primary]: variant === "primary",
[classes.secondary]: variant === "secondary",
[classes.streamSecondary]: variant === "streamSecondary",
[classes.streamPrimary]: variant === "streamPrimary",
[classes.default]: variant === "default",
[classes.uppercase]: uppercase,
[classes.active]: active,
},
className
@@ -57,20 +80,38 @@ class Tab extends React.Component<TabProps> {
return (
<li
className={styles.root}
className={classes.root}
key={tabID}
id={`tab-${tabID}`}
role="presentation"
>
<BaseButton
className={buttonClassName}
aria-controls={`tabPane-${tabID}`}
role="tab"
aria-selected={active}
onClick={this.handleTabClick}
>
{children}
</BaseButton>
{localizationId ? (
<Localized
id={localizationId}
attrs={{ "aria-label": true, title: true }}
>
<BaseButton
className={buttonClassName}
aria-controls={`tabPane-${tabID}`}
role="tab"
aria-selected={active}
onClick={this.handleTabClick}
>
{children}
</BaseButton>
</Localized>
) : (
<BaseButton
className={buttonClassName}
aria-controls={`tabPane-${tabID}`}
role="tab"
aria-selected={active}
aria-label={ariaLabel}
onClick={this.handleTabClick}
>
{children}
</BaseButton>
)}
</li>
);
}
@@ -19,3 +19,11 @@ $moderateCardTabSecondaryColor: var(--v2-palette-divider);
.secondary {
border-bottom: 1px solid $moderateCardTabSecondaryColor;
}
.streamSecondary {
border-bottom: 1px solid $moderateCardTabSecondaryColor;
}
.streamPrimary {
border-bottom: 1px solid $moderateCardTabPrimaryColor;
}
@@ -17,7 +17,12 @@ export interface TabBarProps {
/**
* Style variant
*/
variant?: "primary" | "secondary" | "default";
variant?:
| "primary"
| "secondary"
| "default"
| "streamSecondary"
| "streamPrimary";
/**
* Active tab id/name
*/
@@ -49,6 +54,8 @@ const TabBar: FunctionComponent<TabBarProps> = (props) => {
{
[classes.primary]: variant === "primary",
[classes.secondary]: variant === "secondary",
[classes.streamSecondary]: variant === "streamSecondary",
[classes.streamPrimary]: variant === "streamPrimary",
[classes.default]: variant === "default",
},
],
@@ -37,6 +37,10 @@ $tag-pill-bg: var(--v2-colors-pure-white);
background-color: $tag-color-dark;
}
.colorStreamBlue {
background-color: var(--v2-colors-stream-blue-500);
}
.variantPill {
border-radius: 20px;
padding: 2px 10px;
@@ -57,6 +61,10 @@ $tag-pill-bg: var(--v2-colors-pure-white);
border: 1px solid $tag-color-dark;
color: $tag-color-dark;
}
&.colorStreamBlue {
border: 1px solid var(--v2-colors-stream-blue-500);
color: var(--v2-colors-stream-blue-500);
}
}
.uppercase {
+2 -1
View File
@@ -12,7 +12,7 @@ interface Props {
*/
classes: typeof styles;
children: React.ReactNode;
color?: "grey" | "primary" | "error" | "dark";
color?: "grey" | "primary" | "error" | "dark" | "streamBlue";
variant?: "regular" | "pill";
}
@@ -26,6 +26,7 @@ const Tag: FunctionComponent<Props> = (props) => {
[classes.colorError]: color === "error",
[classes.colorGrey]: color === "grey",
[classes.colorDarkest]: color === "dark",
[classes.colorStreamBlue]: color === "streamBlue",
[classes.uppercase]: variant !== "pill",
});
@@ -3,10 +3,11 @@ $input-border: var(--v2-colors-grey-500);
$input-background: var(--v2-colors-pure-white);
$input-placeholder: var(--v2-colors-mono-100);
$input-regular-focused-border: var(--v2-colors-teal-500);
$input-streamBlue-focused-border: var(--v2-colors-stream-blue-500);
$input-disabled-background: var(--v2-colors-white-500);
$input-disabled-value: var(--v2-colors-grey-400);
$input-disabled-border: var(--v2-colors-grey-400);
$input-error-border: var(--v2-palette-error-darkest);
$input-error-border: var(--v2-colors-red-500);
$input-dark-focused-border: var(--v2-colors-blue-500);
.root {
@@ -26,7 +27,7 @@ $input-dark-focused-border: var(--v2-colors-blue-500);
padding: var(--v2-spacing-2);
box-sizing: border-box;
background-color: $input-background;
border-radius: var(--round-corners);
border-radius: var(--v2-round-corners);
width: 100%;
align-self: stretch;
margin-top: 0;
@@ -64,6 +65,14 @@ $input-dark-focused-border: var(--v2-colors-blue-500);
}
}
.colorStreamBlue {
border: 1px solid $input-border;
&:focus {
border: 1px solid $input-streamBlue-focused-border;
box-shadow: inset 0px 0px 0px 1px $input-streamBlue-focused-border;
}
}
.colorDark {
border: 1px solid $input-border;
&:focus {
@@ -31,7 +31,7 @@ export interface TextFieldProps {
/**
* Color of the TextField
*/
color?: "regular" | "error" | "dark";
color?: "regular" | "streamBlue" | "error" | "dark";
/*
* If set renders a full width button
*/
@@ -105,6 +105,7 @@ const TextField: FunctionComponent<TextFieldProps> = (props) => {
const inputClassName = cn(classes.input, {
[classes.colorRegular]: color === "regular",
[classes.colorError]: color === "error",
[classes.colorStreamBlue]: color === "streamBlue",
[classes.colorDark]: color === "dark",
[classes.textAlignCenter]: textAlignCenter,
[classes.seamlessAdornment]: variant === "seamlessAdornment",
@@ -1,7 +1,7 @@
import cn from "classnames";
import React, { FunctionComponent, useCallback, useState } from "react";
import { AbsoluteTime, BaseButton, RelativeTime } from "coral-ui/components";
import { AbsoluteTime, BaseButton, RelativeTime } from "coral-ui/components/v2";
import styles from "./Timestamp.css";
@@ -9,15 +9,20 @@ export interface TimestampProps {
className?: string;
children: string;
toggleAbsolute?: boolean;
onToggleAbsolute?: (showAbsolute: boolean) => void;
}
const Timestamp: FunctionComponent<TimestampProps> = (props) => {
const [showAbsolute, setShowAbsolute] = useState(false);
const toggleShowAbsolute = useCallback(() => {
if (props.toggleAbsolute) {
if (props.onToggleAbsolute) {
props.onToggleAbsolute(!showAbsolute);
}
setShowAbsolute(!showAbsolute);
}
}, [showAbsolute, setShowAbsolute]);
}, [showAbsolute, setShowAbsolute, props]);
return (
<BaseButton className={styles.root} onClick={toggleShowAbsolute}>
{showAbsolute ? (
@@ -5,12 +5,18 @@ import { BaseButton, Icon } from "coral-ui/components/v2";
import { withForwardRef } from "coral-ui/hocs";
import { PropTypesOf } from "coral-ui/types";
import { IconColor } from "coral-ui/components/v2/Icon/Icon";
import styles from "./TooltipButton.css";
interface Props extends ButtonHTMLAttributes<HTMLButtonElement> {
active?: boolean;
activeColor?: IconColor;
className?: string;
classes?: typeof styles;
toggleVisibility: () => void;
ariaLabel?: string;
title?: string;
/** Internal: Forwarded Ref */
forwardRef?: Ref<HTMLButtonElement>;
@@ -19,18 +25,24 @@ interface Props extends ButtonHTMLAttributes<HTMLButtonElement> {
const TooltipButton: FunctionComponent<Props> = ({
active,
className,
classes,
toggleVisibility,
forwardRef,
activeColor = "primary",
ariaLabel,
title,
}) => (
<BaseButton
className={cn(styles.button, className)}
className={cn(classes ? classes.button : styles.button, className)}
onClick={(evt) => {
evt.stopPropagation();
toggleVisibility();
}}
ref={forwardRef}
aria-label={ariaLabel}
title={title}
>
<Icon color={active ? "primary" : "inherit"}>info</Icon>
<Icon color={active ? activeColor : "inherit"}>info</Icon>
</BaseButton>
);
@@ -14,8 +14,12 @@ export interface UIContextProps {
* current frame for `ClickOutside`
*/
registerClickFarAway?: ClickFarAwayRegister;
locales?: string[];
}
const UIContext = React.createContext<UIContextProps>({} as any);
export const useUIContext = () => React.useContext(UIContext);
export default UIContext;
@@ -1 +1 @@
export { default, UIContextProps } from "./UIContext";
export { default, UIContextProps, useUIContext } from "./UIContext";
+9 -1
View File
@@ -1,3 +1,4 @@
export { default as AbsoluteTime } from "./AbsoluteTime";
export { default as AriaInfo } from "./AriaInfo";
export {
AppBar,
@@ -9,7 +10,11 @@ export {
} from "./AppBar";
export { default as Backdrop } from "./Backdrop";
export { default as BaseButton } from "./BaseButton";
export { default as UIContext, UIContextProps } from "./UIContext";
export {
default as UIContext,
UIContextProps,
useUIContext,
} from "./UIContext";
export { default as ClickOutside } from "./ClickOutside";
export { default as Box } from "./Box";
export { default as Button } from "./Button";
@@ -28,6 +33,7 @@ export {
export { default as DurationField, DURATION_UNIT } from "./DurationField";
export { default as FieldSet } from "./FieldSet";
export { default as Flex } from "./Flex";
export { default as MatchMedia } from "./MatchMedia";
export { default as FormField } from "./FormField";
export { default as FormFieldDescription } from "./FormFieldDescription";
export { default as FormFieldHeader } from "./FormFieldHeader";
@@ -68,3 +74,5 @@ export {
export { BrandName, BrandMark, LogoHorizontal } from "./Brand";
export { default as InputLabel } from "./InputLabel";
export { default as AppNotification } from "./AppNotification";
export { default as HorizontalRule } from "./HorizontalRule";
export { StepBar, Step } from "./Steps";
@@ -0,0 +1,394 @@
.base {
border-radius: var(--v2-round-corners);
}
.upperCase {
text-transform: uppercase;
}
.fontFamilyPrimary {
font-family: var(--v2-font-family-primary);
}
.fontFamilySecondary{
font-family: var(--v2-font-family-secondary);
}
.fontWeightPrimaryBold {
font-weight: var(--v2-font-weight-primary-bold);
}
.fontWeightPrimarySemiBold {
font-weight: var(--v2-font-weight-primary-semi-bold);
}
.fontWeightPrimaryRegular {
font-weight: var(--v2-font-weight-primary-regular);
}
.fontWeightSecondaryBold {
font-weight: var(--v2-font-weight-secondary-bold);
}
.fontWeightSecondarySemiBold {
font-weight: var(--v2-font-weight-secondary-bold);
}
.fontWeightSecondaryRegular {
font-weight: var(--v2-font-weight-secondary-regular);
}
.fontSizeExtraSmall {
font-size: var(--v2-font-size-1);
line-height: var(--v2-line-height-3);
}
.fontSizeSmall {
font-size: var(--v2-font-size-2);
line-height: var(--v2-line-height-3);
}
.fontSizeMedium {
font-size: var(--v2-font-size-2);
line-height: var(--v2-line-height-3);
}
.fontSizeLarge {
font-size: var(--v2-font-size-3);
line-height: var(--v2-line-height-3);
}
.textAlignLeft {
text-align: left;
}
.textAlignCenter {
text-align: center;
}
.textAlignRight {
text-align: right;
}
.paddingSizeExtraSmall {
padding-left: var(--v2-spacing-2);
padding-right: var(--v2-spacing-2);
padding-top: var(--v2-spacing-1);
padding-bottom: var(--v2-spacing-1);
}
.paddingSizeSmall {
padding-left: var(--v2-spacing-3);
padding-right: var(--v2-spacing-3);
padding-top: var(--v2-spacing-2);
padding-bottom: var(--v2-spacing-2);
}
.paddingSizeMedium {
padding-left: var(--v2-spacing-4);
padding-right: var(--v2-spacing-4);
padding-top: var(--v2-spacing-3);
padding-bottom: var(--v2-spacing-3);
}
.paddingSizeLarge {
padding-left: var(--v2-spacing-5);
padding-right: var(--v2-spacing-5);
padding-top: var(--v2-spacing-4);
padding-bottom: var(--v2-spacing-4);
}
.filled {
border-style: solid;
border-width: 1px;
&.colorPrimary {
color: var(--v2-colors-pure-white);
&:not(.disabled),
&:not(:disabled) {
background-color: var(--v2-colors-stream-blue-500);
border-color: var(--v2-colors-stream-blue-500);
}
&:hover, &.mouseHover {
background-color: var(--v2-colors-stream-blue-600);
border-color: var(--v2-colors-stream-blue-600);
}
&:active, &.active {
background-color: var(--v2-colors-stream-blue-700);
border-color: var(--v2-colors-stream-blue-700);
}
&.disabled {
color: var(--v2-colors-grey-400);
background-color: var(--v2-colors-grey-200);
border-color: var(--v2-colors-grey-200);
}
}
&.colorSecondary {
color: var(--v2-colors-pure-white);
&:not(.disabled),
&:not(:disabled) {
background-color: var(--v2-colors-grey-500);
border-color: var(--v2-colors-grey-500);
}
&:hover, &.mouseHover {
background-color: var(--v2-colors-grey-600);
border-color: var(--v2-colors-grey-600);
}
&:active, &.active {
background-color: var(--v2-colors-grey-700);
border-color: var(--v2-colors-grey-700);
}
&.disabled {
color: var(--v2-colors-grey-400);
background-color: var(--v2-colors-grey-200);
border-color: var(--v2-colors-grey-200);
}
}
&.colorNegative {
color: var(--v2-colors-pure-white);
&:not(.disabled),
&:not(:disabled) {
background-color: var(--v2-colors-red-500);
border-color: var(--v2-colors-red-500);
}
&:hover, &.mouseHover {
background-color: var(--v2-colors-red-600);
border-color: var(--v2-colors-red-600);
}
&:active, &.active {
background-color: var(--v2-colors-red-700);
border-color: var(--v2-colors-red-700);
}
&.disabled {
color: var(--v2-colors-grey-400);
background-color: var(--v2-colors-grey-200);
border-color: var(--v2-colors-grey-200);
}
}
&.colorPositive {
color: var(--v2-colors-pure-white);
&:not(.disabled),
&:not(:disabled) {
background-color: var(--v2-colors-green-500);
border-color: var(--v2-colors-green-500);
}
&:hover, &.mouseHover {
background-color: var(--v2-colors-green-600);
border-color: var(--v2-colors-green-600);
}
&:active, &.active {
background-color: var(--v2-colors-green-700);
border-color: var(--v2-colors-green-700);
}
&.disabled {
color: var(--v2-colors-grey-400);
background-color: var(--v2-colors-grey-200);
border-color: var(--v2-colors-grey-200);
}
}
}
.outlined {
&.colorPrimary {
border-style: solid;
border-width: 1px;
&:not(.disabled),
&:not(:disabled) {
background-color: var(--v2-colors-pure-white);
border-color: var(--v2-colors-stream-blue-500);
color: var(--v2-colors-stream-blue-500);
}
&:hover, &.mouseHover {
background-color: var(--v2-colors-stream-blue-500);
border-color: var(--v2-colors-stream-blue-500);
color: var(--v2-colors-pure-white);
}
&:active, &.active {
background-color: var(--v2-colors-stream-blue-600);
border-color: var(--v2-colors-stream-blue-600);
color: var(--v2-colors-pure-white);
}
&.disabled {
background-color: var(--v2-colors-pure-white);
border-color: var(--v2-colors-grey-400);
color: var(--v2-colors-grey-400);
}
}
&.colorSecondary {
border-style: solid;
border-width: 1px;
&:not(.disabled),
&:not(:disabled) {
background-color: var(--v2-colors-pure-white);
border-color: var(--v2-colors-grey-500);
color: var(--v2-colors-grey-500);
}
&:hover, &.mouseHover {
background-color: var(--v2-colors-grey-500);
border-color: var(--v2-colors-grey-500);
color: var(--v2-colors-pure-white);
}
&:active, &.active {
background-color: var(--v2-colors-grey-600);
border-color: var(--v2-colors-grey-600);
color: var(--v2-colors-pure-white);
}
&.disabled {
background-color: var(--v2-colors-pure-white);
border-color: var(--v2-colors-grey-400);
color: var(--v2-colors-grey-400);
}
}
&.colorNegative {
border-style: solid;
border-width: 1px;
&:not(.disabled),
&:not(:disabled) {
background-color: var(--v2-colors-pure-white);
border-color: var(--v2-colors-red-500);
color: var(--v2-colors-red-500);
}
&:hover, &.mouseHover {
background-color: var(--v2-colors-red-500);
border-color: var(--v2-colors-red-500);
color: var(--v2-colors-pure-white);
}
&:active, &.active {
background-color: var(--v2-colors-red-600);
border-color: var(--v2-colors-red-600);
color: var(--v2-colors-pure-white);
}
&.disabled {
background-color: var(--v2-colors-pure-white);
border-color: var(--v2-colors-grey-400);
color: var(--v2-colors-grey-400);
}
}
&.colorPositive {
border-style: solid;
border-width: 1px;
&:not(.disabled),
&:not(:disabled) {
background-color: var(--v2-colors-pure-white);
border-color: var(--v2-colors-green-500);
color: var(--v2-colors-green-500);
}
&:hover, &.mouseHover {
background-color: var(--v2-colors-green-500);
border-color: var(--v2-colors-green-500);
color: var(--v2-colors-pure-white);
}
&:active, &.active {
background-color: var(--v2-colors-green-600);
border-color: var(--v2-colors-green-600);
color: var(--v2-colors-pure-white);
}
&.disabled {
background-color: var(--v2-colors-pure-white);
border-color: var(--v2-colors-grey-400);
color: var(--v2-colors-grey-400);
}
}
}
.flat {
background-color: transparent;
&.colorPrimary {
&:not(.disabled),
&:not(:disabled) {
color: var(--v2-colors-stream-blue-500);
}
&:hover, &.mouseHover {
color: var(--v2-colors-stream-blue-600);
}
&:active, &.active {
color: var(--v2-colors-stream-blue-700);
}
&.disabled {
color: var(--v2-colors-grey-400);
}
}
&.colorSecondary {
&:not(.disabled),
&:not(:disabled) {
color: var(--v2-colors-grey-500);
}
&:hover, &.mouseHover {
color: var(--v2-colors-grey-600);
}
&:active, &.active {
color: var(--v2-colors-grey-700);
}
&.disabled {
color: var(--v2-colors-grey-400);
}
}
&.colorNegative {
&:not(.disabled),
&:not(:disabled) {
color: var(--v2-colors-red-500);
}
&:hover, &.mouseHover {
color: var(--v2-colors-red-600);
}
&:active, &.active {
color: var(--v2-colors-red-700);
}
&.disabled {
color: var(--v2-colors-grey-400);
}
}
&.colorPositive{
&:not(.disabled),
&:not(:disabled) {
color: var(--v2-colors-green-500);
}
&:hover, &.mouseHover {
color: var(--v2-colors-green-600);
}
&:active, &.active {
color: var(--v2-colors-green-700);
}
&.disabled {
color: var(--v2-colors-grey-400);
}
}
}
.underline {
text-decoration: underline;
}
.fullWidth {
width: 100%;
}
@@ -0,0 +1,118 @@
import cn from "classnames";
import { pick } from "lodash";
import React from "react";
import { BaseButton } from "coral-ui/components/v2";
import { BaseButtonProps } from "coral-ui/components/v2/BaseButton";
import { withStyles } from "coral-ui/hocs";
import styles from "./Button.css";
interface Props extends Omit<BaseButtonProps, "ref"> {
anchor?: boolean;
href?: string;
target?: string;
to?: string;
classes: typeof styles & BaseButtonProps["classes"];
className?: string;
fontFamily?: "primary" | "secondary" | "none";
fontWeight?: "regular" | "semiBold" | "bold" | "none";
fontSize?: "extraSmall" | "small" | "medium" | "large" | "none";
textAlign?: "left" | "center" | "right";
paddingSize?: "extraSmall" | "small" | "medium" | "large" | "none";
color?: "primary" | "secondary" | "positive" | "negative" | "none";
variant?: "filled" | "outlined" | "flat" | "none";
upperCase?: boolean;
underline?: boolean;
disabled?: boolean;
fullWidth?: boolean;
}
export class Button extends React.Component<Props> {
public render() {
const {
classes,
className,
variant = "filled",
color = "primary",
textAlign = "center",
fontSize = "small",
fontFamily = "primary",
fontWeight = "bold",
paddingSize = "small",
children,
disabled = false,
to,
upperCase = false,
underline = false,
fullWidth = false,
href,
...rest
} = this.props;
const rootClassName = cn(
classes.root,
classes.base,
{
[classes.filled]: variant === "filled",
[classes.outlined]: variant === "outlined",
[classes.flat]: variant === "flat",
[classes.fontSizeExtraSmall]: fontSize === "extraSmall",
[classes.fontSizeSmall]: fontSize === "small",
[classes.fontSizeMedium]: fontSize === "medium",
[classes.fontSizeLarge]: fontSize === "large",
[classes.textAlignLeft]: textAlign === "left",
[classes.textAlignCenter]: textAlign === "center",
[classes.textAlignRight]: textAlign === "right",
[classes.fontFamilyPrimary]: fontFamily === "primary",
[classes.fontFamilySecondary]: fontFamily === "secondary",
[classes.fontWeightPrimaryRegular]:
fontFamily === "primary" && fontWeight === "regular",
[classes.fontWeightPrimarySemiBold]:
fontFamily === "primary" && fontWeight === "semiBold",
[classes.fontWeightPrimaryBold]:
fontFamily === "primary" && fontWeight === "bold",
[classes.fontWeightSecondaryRegular]:
fontFamily === "secondary" && fontWeight === "regular",
[classes.fontWeightSecondarySemiBold]:
fontFamily === "secondary" && fontWeight === "semiBold",
[classes.fontWeightSecondaryBold]:
fontFamily === "secondary" && fontWeight === "bold",
[classes.paddingSizeExtraSmall]: paddingSize === "extraSmall",
[classes.paddingSizeSmall]: paddingSize === "small",
[classes.paddingSizeMedium]: paddingSize === "medium",
[classes.paddingSizeLarge]: paddingSize === "large",
[classes.colorPrimary]: color === "primary",
[classes.colorSecondary]: color === "secondary",
[classes.colorPositive]: color === "positive",
[classes.colorNegative]: color === "negative",
[classes.disabled]: disabled,
[classes.upperCase]: upperCase,
[classes.underline]: underline,
[classes.fullWidth]: fullWidth,
},
className
);
return (
<BaseButton
className={rootClassName}
classes={pick(classes, "keyboardFocus", "mouseHover")}
disabled={disabled}
to={to}
href={href}
anchor={href ? true : false}
{...rest}
>
{children}
</BaseButton>
);
}
}
const enhanced = withStyles(styles)(Button);
export default enhanced;
@@ -0,0 +1 @@
export { default } from "./Button";
@@ -0,0 +1,104 @@
.root {
position: relative;
padding: var(--v2-spacing-2);
}
.topBorder {
border-top: 4px solid;
}
.leftBorder {
border-left: 4px solid;
}
.content {
width: calc(100% - 50px);
}
.title {
font-family: var(--v2-font-family-primary);
}
.titleBold {
font-weight: var(--v2-font-weight-primary-bold);
font-size: var(--v2-font-size-3);
line-height: var(--v2-line-height-5);
}
.titleSemiBold {
font-weight: var(--v2-font-weight-primary-semi-bold);
font-size: var(--v2-font-size-2);
line-height: var(--v2-line-height-5);
}
.titleMargin {
margin-bottom: var(--v2-spacing-2);
}
.body {
font-family: var(--v2-font-family-primary);
font-weight: var(--v2-font-weight-primary-regular);
font-size: var(--v2-font-size-2);
line-height: var(--v2-line-height-3);
}
.closeButton {
position: absolute;
top: var(--v2-spacing-1);
right: var(--v2-spacing-2);
}
.leftIcon {
margin-left: var(--v2-spacing-1);
margin-right: var(--v2-spacing-3);
}
.icon {
&.mono {
color: var(--v2-colors-mono-500);
}
&.positive {
color: var(--v2-colors-green-500);
}
&.negative {
color: var(--v2-colors-red-500);
}
&.primary {
color: var(--v2-colors-stream-blue-500);
}
&.warning {
color: var(--v2-colors-yellow-500);
}
}
.mono {
background-color: var(--v2-colors-grey-100);
border-color: var(--v2-colors-grey-500);
color: var(--v2-colors-mono-500);
}
.positive {
background-color: var(--v2-colors-green-100);
border-color: var(--v2-colors-green-500);
color: var(--v2-colors-mono-500);
}
.negative {
background-color: var(--v2-colors-stream-red-100);
border-color: var(--v2-colors-stream-red-500);
color: var(--v2-colors-mono-500);
}
.primary {
background-color: var(--v2-colors-stream-blue-100);
border-color: var(--v2-colors-stream-blue-500);
color: var(--v2-colors-mono-500);
}
.warning {
background-color: var(--v2-colors-yellow-100);
border-color: var(--v2-colors-yellow-500);
color: var(--v2-colors-mono-500);
}
@@ -0,0 +1,116 @@
import cn from "classnames";
import React, { FunctionComponent, useCallback } from "react";
import { BaseButton, Flex, Icon } from "coral-ui/components/v2";
import { withStyles } from "coral-ui/hocs";
import styles from "./CallOut.css";
type CallOutColor =
| "mono"
| "positive"
| "negative"
| "primary"
| "warning"
| "none";
type IconColor = "inherit" | "none";
interface Props {
children?: any;
color?: CallOutColor;
borderPosition?: "leftSide" | "top";
icon?: any;
iconPosition?: "left";
iconColor?: IconColor;
title?: any;
titleWeight?: "bold" | "semiBold" | "none";
className?: string;
classes: typeof styles;
visible?: boolean;
onClose?: () => void;
}
const CallOut: FunctionComponent<Props> = ({
color = "mono",
borderPosition = "leftSide",
icon = null,
iconPosition = "left",
iconColor = "inherit",
title = null,
titleWeight = "bold",
classes,
className,
children,
visible = true,
onClose,
}) => {
if (!visible) {
return null;
}
const rootClasses = cn(
classes.root,
{
[classes.mono]: color === "mono",
[classes.positive]: color === "positive",
[classes.negative]: color === "negative",
[classes.primary]: color === "primary",
[classes.warning]: color === "warning",
[classes.leftBorder]: borderPosition === "leftSide",
[classes.topBorder]: borderPosition === "top",
},
className
);
const iconClasses = cn(classes.icon, {
[classes.mono]: color === "mono" && iconColor === "inherit",
[classes.positive]: color === "positive" && iconColor === "inherit",
[classes.negative]: color === "negative" && iconColor === "inherit",
[classes.primary]: color === "primary" && iconColor === "inherit",
[classes.warning]: color === "warning" && iconColor === "inherit",
[classes.leftIcon]: iconPosition === "left",
});
const titleClasses = cn(classes.title, {
[classes.titleMargin]: children !== null && children !== undefined,
[classes.titleBold]: titleWeight === "bold",
[classes.titleSemiBold]: titleWeight === "semiBold",
});
const onCloseClicked = useCallback(() => {
if (!onClose) {
return;
}
onClose();
}, [onClose]);
return (
<div className={rootClasses}>
<Flex justifyContent="flex-start" alignItems="flex-start">
{iconPosition === "left" && icon !== null && (
<div className={iconClasses}>{icon}</div>
)}
<div className={classes.content}>
{title !== null && <div className={titleClasses}>{title}</div>}
<div className={classes.body}>{children}</div>
</div>
{onClose && (
<BaseButton
className={classes.closeButton}
onClick={onCloseClicked}
data-testid="callout-close-button"
>
<Icon size="sm">close</Icon>
</BaseButton>
)}
</Flex>
</div>
);
};
const enhanced = withStyles(styles)(CallOut);
export default enhanced;
@@ -0,0 +1 @@
export { default } from "./CallOut";
@@ -0,0 +1,22 @@
.root {
font-family: var(--v2-font-family-primary);
font-weight: var(--v2-font-weight-primary-bold);
font-size: var(--v2-font-size-2);
line-height: var(--v2-line-height-2);
border-radius: var(--v2-round-corners);
background-color: var(--v2-colors-stream-blue-100);
color: var(--v2-colors-stream-blue-500);
padding-top: var(--v2-spacing-1);
padding-bottom: var(--v2-spacing-1);
padding-left: var(--v2-spacing-2);
padding-right: var(--v2-spacing-2);
margin-right: var(--v2-spacing-1);
}
.button {
color: var(--v2-colors-mono-100);
}
@@ -0,0 +1,54 @@
import { Localized } from "@fluent/react/compat";
import React, { FunctionComponent } from "react";
import { Flex, Tooltip, TooltipButton } from "coral-ui/components/v2";
import { withStyles } from "coral-ui/hocs";
import styles from "./ExperimentalTag.css";
interface Props {
classes: typeof styles;
content?: React.ReactNode;
}
const ExperimentalTag: FunctionComponent<Props> = ({ classes, content }) => {
return (
<Flex alignItems="center">
<div className={classes.root}>
<Localized id="experimental-tag">Experimental</Localized>
</div>
<Tooltip
id="experimental-tag-tooltip"
title={
<Localized id="experimental-tag-tooltip-title">
<span>Experimental feature</span>
</Localized>
}
body={content}
button={({ toggleVisibility, ref, visible }) => (
<Localized
id="comments-featuredCommentTooltip-toggleButton"
attrs={{ "aria-label": true, title: true }}
>
<TooltipButton
classes={{
button: classes.button,
}}
active={visible}
activeColor="stream"
ariaLabel="Toggle experimental tooltip"
aria-label="Toggle experimental tooltip"
title="Toggle experimental tooltip"
toggleVisibility={toggleVisibility}
ref={ref}
/>
</Localized>
)}
/>
</Flex>
);
};
const enhanced = withStyles(styles)(ExperimentalTag);
export default enhanced;
@@ -0,0 +1 @@
export { default } from "./ExperimentalTag";
@@ -0,0 +1,17 @@
.root {
background-color: var(--v2-colors-grey-200);
font-family: var(--v2-font-family-primary);
font-weight: var(--v2-font-weight-primary-semi-bold);
font-size: var(--v2-font-size-2);
line-height: var(--v2-line-height-3);
color: var(--v2-colors-mono-500);
padding: var(--v2-spacing-4);
text-align: center;
}
.fullWidth {
width: 100%;
}
@@ -0,0 +1,33 @@
import cn from "classnames";
import React, { FunctionComponent } from "react";
import { withStyles } from "coral-ui/hocs";
import styles from "./Tombstone.css";
interface Props {
classes: typeof styles;
className?: string;
fullWidth?: boolean;
}
const Tombstone: FunctionComponent<Props> = ({
children,
fullWidth,
classes,
className,
}) => {
const rootClassName = cn(
classes.root,
{
[classes.fullWidth]: fullWidth,
},
className
);
return <div className={rootClassName}>{children}</div>;
};
const enhanced = withStyles(styles)(Tombstone);
export default enhanced;
@@ -0,0 +1 @@
export { default } from "./Tombstone";
@@ -0,0 +1,13 @@
.root {
font-family: var(--v2-font-family-primary);
font-weight: var(--v2-font-weight-primary-semi-bold);
font-size: var(--v2-font-size-2);
line-height: var(--v2-line-height-3);
color: var(--v2-colors-red-500);
}
.icon {
margin-right: var(--v2-spacing-1);
}
@@ -0,0 +1,52 @@
import cn from "classnames";
import React, { FunctionComponent, ReactNode } from "react";
import { FieldMeta, hasError } from "coral-framework/lib/form";
import { Flex, Icon } from "coral-ui/components/v2";
import { withStyles } from "coral-ui/hocs";
import styles from "./ValidationMessage.css";
interface Props {
children?: ReactNode;
variant?: "text" | "none";
classes: typeof styles;
className?: string;
meta?: FieldMeta;
}
const render = (content: any, classes: typeof styles, className?: string) => {
const rootClassName = cn(classes.root, className);
return (
<div className={rootClassName}>
<Flex alignItems="center">
<Icon size="sm" className={classes.icon}>
error
</Icon>
{content}
</Flex>
</div>
);
};
const ValidationMessage: FunctionComponent<Props> = ({
classes,
className,
children,
meta,
}) => {
if (children) {
return render(children, classes, className);
}
if (meta && hasError(meta)) {
return render(meta.error || meta.submitError, classes, className);
}
return null;
};
const enhanced = withStyles(styles)(ValidationMessage);
export default enhanced;
@@ -0,0 +1 @@
export { default } from "./ValidationMessage";
@@ -0,0 +1,5 @@
export { default as CallOut } from "./CallOut";
export { default as Button } from "./Button";
export { default as ValidationMessage } from "./ValidationMessage";
export { default as Tombstone } from "./Tombstone";
export { default as ExperimentalTag } from "./ExperimentalTag";
+37 -9
View File
@@ -44,15 +44,18 @@ const colors = {
red700: "#991F34",
red800: "#7B142E",
red900: "#660C2B",
yellow100: "#FFFADF",
yellow200: "#FFF4C0",
yellow300: "#FFECA1",
yellow400: "#FFE48A",
yellow500: "#FFD863",
yellow600: "#DBB248",
yellow700: "#B78F31",
yellow800: "#936D1F",
yellow900: "#7A5513",
streamRed100: "#FFEAE9",
streamRed200: "#FFA29E",
streamRed300: "#FF7F78",
streamRed400: "#ED5454",
streamRed500: "#D53F3F",
streamRed600: "#B72E39",
streamRed700: "#991F34",
streamRed800: "#7B142E",
streamRed900: "#660C2B",
yellow100: "#FFFACC",
yellow500: "#FFE91F",
yellow900: "#FFD702",
teal100: "#E2FAF7",
teal200: "#C2F9EA",
teal300: "#9FECDF",
@@ -62,6 +65,15 @@ const colors = {
teal700: "#2C7B8C",
teal800: "#1C5B71",
teal900: "#11435D",
streamBlue100: "#EBF6FF",
streamBlue200: "#B7DCFF",
streamBlue300: "#61B3FF",
streamBlue400: "#2897FF",
streamBlue500: "#0070D9",
streamBlue600: "#0062BE",
streamBlue700: "#005AAE",
streamBlue800: "#004688",
streamBlue900: "#00386D",
mono900: "#14171A",
mono500: "#353F44",
mono100: "#65696B",
@@ -131,6 +143,14 @@ const variables2 = {
bodyShort: 1.3,
reset: 1,
title: 1.15,
1: "0.75rem",
2: "0.875rem",
3: "1rem",
4: "1.125rem",
5: "1.25rem",
6: "1.5rem",
7: "1.75rem",
8: "2rem",
},
fontSize: {
1: "0.75rem",
@@ -141,6 +161,7 @@ const variables2 = {
6: "1.5rem",
7: "1.75rem",
8: "2rem",
9: "2.25rem",
iconLarge: "1.5rem",
iconMedium: "1.125rem",
iconSmall: "0.875rem",
@@ -169,6 +190,13 @@ const variables2 = {
9: "84px",
},
roundCorners: "3px",
breakpoints: {
xs: 320,
sm: 640,
md: 1024,
lg: 1400,
xl: 1600,
},
};
export default variables2;