[next] Admin Configure (#2076)

* feat: Add RadioButton and CheckBox

* feat: configure facebook and google auth

* feat: configure sso, localAuth and displayName + some tests

* test: add integration tests for configure auth

* test: more integration tests

* feat: add oidc support

* test: add oidc integration test

* feat: generate sso key initially

* fix: import fetchQuery from correct package

* fix: admin url

* fix: set timezone to utc when testing

* refactor: improve route config

* fix: remove obsolete line

* fix: clientMutationId increment

* fix: oidc only create when enabled

* fix: copy

* test: update snapshots

* feat: fixed graphql logging extension

* Update src/locales/en-US/admin.ftl

Co-Authored-By: cvle <vinh@wikiwi.io>

* Apply suggestions from code review

Co-Authored-By: cvle <vinh@wikiwi.io>

* test: update snapshots

* fix: change Local Auth to Email Authentication

* fix: copy updates
This commit is contained in:
Kiwi
2018-11-19 22:47:32 +00:00
committed by Wyatt Johnson
parent 3f949b3712
commit 05350d651f
215 changed files with 7774 additions and 939 deletions
@@ -4,7 +4,7 @@ import React, { AllHTMLAttributes, Ref, StatelessComponent } from "react";
import { withForwardRef, withStyles } from "talk-ui/hocs";
import { PropTypesOf } from "talk-ui/types";
import * as styles from "./AriaInfo.css";
import styles from "./AriaInfo.css";
interface InnerProps extends AllHTMLAttributes<HTMLElement> {
/**
@@ -16,7 +16,7 @@ import {
} from "talk-ui/hocs";
import { PropTypesOf } from "talk-ui/types";
import * as styles from "./BaseButton.css";
import styles from "./BaseButton.css";
interface InnerProps extends ButtonHTMLAttributes<HTMLButtonElement> {
/** If set renders an anchor tag instead */
@@ -44,7 +44,6 @@ interface InnerProps extends ButtonHTMLAttributes<HTMLButtonElement> {
// These handlers are passed down by the `withKeyboardFocus` HOC.
onFocus: EventHandler<FocusEvent<HTMLElement>>;
onBlur: EventHandler<FocusEvent<HTMLElement>>;
onMouseDown: EventHandler<MouseEvent<HTMLElement>>;
keyboardFocus: boolean;
}
@@ -5,7 +5,6 @@ exports[`renders as anchor 1`] = `
className="BaseButton-root"
onBlur={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
@@ -20,7 +19,6 @@ exports[`renders correctly 1`] = `
className="BaseButton-root my-class"
onBlur={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
@@ -6,7 +6,7 @@ import { withForwardRef, withStyles } from "talk-ui/hocs";
import { PropTypesOf } from "talk-ui/types";
import BaseButton, { BaseButtonProps } from "../BaseButton";
import * as styles from "./Button.css";
import styles from "./Button.css";
// This should extend from BaseButton instead but we can't because of this bug
// TODO: add bug link.
@@ -5,7 +5,7 @@ import Icon, { IconProps } from "talk-ui/components/Icon";
import { withForwardRef, withStyles } from "talk-ui/hocs";
import { PropTypesOf } from "talk-ui/types";
import * as styles from "./ButtonIcon.css";
import styles from "./ButtonIcon.css";
interface InnerProps extends HTMLAttributes<HTMLSpanElement> {
/**
@@ -2,7 +2,7 @@ import cn from "classnames";
import React from "react";
import { ReactNode, StatelessComponent } from "react";
import { withStyles } from "talk-ui/hocs";
import * as styles from "./CallOut.css";
import styles from "./CallOut.css";
export interface CallOutProps {
/**
@@ -0,0 +1,85 @@
.root {
}
.input {
cursor: pointer;
position: absolute; /* take it out of document flow */
opacity: 0; /* hide it */
}
.label {
composes: bodyCopy from "talk-ui/shared/typography.css";
display: inline-flex;
align-items: center;
position: relative;
cursor: pointer;
user-select: none;
}
.labelSpan {
padding-bottom: 1px;
}
.labelLight {
color: var(--palette-text-light);
}
/* Box. */
.input + .label:before {
content: "";
margin-right: 10px;
display: inline-block;
width: 14px;
height: 14px;
background: var(--palette-common-white);
border: 1px solid var(--palette-text-primary);
box-sizing: border-box;
}
/* Box focus */
.label.focus:before {
outline-width: 3px;
outline-color: Highlight;
outline-color: -webkit-focus-ring-color;
outline-style: auto;
}
/* Box checked */
.input:checked + .label:before {
background: var(--palette-primary-main);
border: 1px solid var(--palette-primary-main);
}
/* Disabled state label. */
.input:disabled + .label {
cursor: auto;
opacity: 0.6;
}
/* Disabled box. */
.input:disabled + .label:before {
box-shadow: none;
border: 1px solid var(--palette-grey-main);
background: var(--palette-grey-lightest);
}
/* Checkmark. Could be replaced with an image */
.input:checked + .label:after {
content: "";
position: absolute;
left: 2px;
top: 10px;
color: var(--palette-text-light);
background: currentColor;
width: 2px;
height: 2px;
box-shadow: 2px 0 0 currentColor, 4px 0 0 currentColor,
4px -2px 0 currentColor, 4px -4px 0 currentColor, 4px -6px 0 currentColor,
4px -8px 0 currentColor;
transform: rotate(45deg);
box-sizing: border-box;
}
.input:checked:disabled + .label:after {
color: var(--palette-text-primary);
}
@@ -0,0 +1,19 @@
---
name: CheckBox
menu: UI Kit
---
import { Playground, PropsTable } from 'docz'
import CheckBox from './CheckBox.tsx'
import HorizontalGutter from '../HorizontalGutter'
# CheckBox
## Basic Use
<Playground>
<HorizontalGutter>
<CheckBox value="true">Yes I agree</CheckBox>
<CheckBox value="false" disabled>No I don't agree</CheckBox>
<CheckBox value="undefined" disabled checked>I don't know</CheckBox>
</HorizontalGutter>
</Playground>
@@ -0,0 +1,17 @@
import React from "react";
import TestRenderer from "react-test-renderer";
import { PropTypesOf } from "talk-ui/types";
import CheckBox from "./CheckBox";
it("renders correctly", () => {
const props: PropTypesOf<typeof CheckBox> = {
className: "custom",
id: "checkboxID",
checked: true,
children: "Yes I agree",
};
const renderer = TestRenderer.create(<CheckBox {...props} />);
expect(renderer.toJSON()).toMatchSnapshot();
});
@@ -0,0 +1,89 @@
import cn from "classnames";
import React, { ChangeEvent, Component, EventHandler, FocusEvent } from "react";
import uuid from "uuid/v4";
import { withKeyboardFocus, withStyles } from "talk-ui/hocs";
import styles from "./CheckBox.css";
export interface CheckBoxProps {
id?: string;
/**
* checked or not.
*/
checked?: boolean;
/**
* Convenient prop to override the root styling.
*/
className?: string;
/**
* Override or extend the styles applied to the component.
*/
classes: typeof styles;
/**
* Mark as readonly
*/
readOnly?: boolean;
/**
* Name
*/
name?: string;
/**
* onChange
*/
onChange?: EventHandler<ChangeEvent<HTMLInputElement>>;
disabled?: boolean;
children: React.ReactNode;
/**
* Display a light text.
*/
light?: boolean;
// These handlers are passed down by the `withKeyboardFocus` HOC.
onFocus: EventHandler<FocusEvent<HTMLElement>>;
onBlur: EventHandler<FocusEvent<HTMLElement>>;
keyboardFocus: boolean;
}
class CheckBox extends Component<CheckBoxProps> {
public state = {
randomID: uuid(),
};
public render() {
const {
className,
classes,
id,
light,
children,
keyboardFocus,
...rest
} = this.props;
const rootClassName = cn(classes.root, className);
const finalID = this.props.id || this.state.randomID;
return (
<div className={rootClassName}>
<input
className={classes.input}
type="checkbox"
id={finalID}
{...rest}
/>
<label
className={cn(classes.label, {
[classes.labelLight]: light,
[classes.focus]: keyboardFocus,
})}
htmlFor={finalID}
>
<span className={classes.labelSpan}>{children}</span>
</label>
</div>
);
}
}
const enhanced = withStyles(styles)(withKeyboardFocus(CheckBox));
export default enhanced;
@@ -0,0 +1,26 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<div
className="CheckBox-root custom"
>
<input
checked={true}
className="CheckBox-input"
id="checkboxID"
onBlur={[Function]}
onFocus={[Function]}
type="checkbox"
/>
<label
className="CheckBox-label"
htmlFor="checkboxID"
>
<span
className="CheckBox-labelSpan"
>
Yes I agree
</span>
</label>
</div>
`;
@@ -0,0 +1,2 @@
export * from "./CheckBox";
export { default } from "./CheckBox";
+1 -1
View File
@@ -6,7 +6,7 @@ import { pascalCase } from "talk-common/utils";
import { withForwardRef, withStyles } from "talk-ui/hocs";
import { PropTypesOf } from "talk-ui/types";
import * as styles from "./Flex.css";
import styles from "./Flex.css";
interface InnerProps {
/**
@@ -5,7 +5,7 @@ import { StatelessComponent } from "react";
import { withStyles } from "talk-ui/hocs";
import HorizontalGutter from "../HorizontalGutter";
import * as styles from "./FormField.css";
import styles from "./FormField.css";
interface InnerProps {
children: ReactNode;
@@ -17,6 +17,14 @@
margin: 0 !important;
}
}
.oneAndAHalf {
& > * {
margin: 0 0 calc(1.5 * var(--spacing-unit)) 0 !important;
}
& > *:last-child {
margin: 0 !important;
}
}
.double {
& > * {
margin: 0 0 calc(2 * var(--spacing-unit)) 0 !important;
@@ -4,7 +4,7 @@ import React, { HTMLAttributes, Ref, StatelessComponent } from "react";
import { withForwardRef, withStyles } from "talk-ui/hocs";
import { PropTypesOf } from "talk-ui/types";
import * as styles from "./HorizontalGutter.css";
import styles from "./HorizontalGutter.css";
interface InnerProps extends HTMLAttributes<HTMLSpanElement> {
/**
@@ -13,7 +13,7 @@ interface InnerProps extends HTMLAttributes<HTMLSpanElement> {
*/
classes: typeof styles;
size?: "half" | "full" | "double";
size?: "half" | "full" | "double" | "oneAndAHalf";
/** The name of the HorizontalGutter to render */
children?: React.ReactNode;
+1 -1
View File
@@ -4,7 +4,7 @@ import React, { HTMLAttributes, Ref, StatelessComponent } from "react";
import { withForwardRef, withStyles } from "talk-ui/hocs";
import { PropTypesOf } from "talk-ui/types";
import * as styles from "./Icon.css";
import styles from "./Icon.css";
interface InnerProps extends HTMLAttributes<HTMLSpanElement> {
/**
@@ -1,10 +1,12 @@
import React, { ReactNode, StatelessComponent } from "react";
import { Typography } from "talk-ui/components";
import { PropTypesOf } from "talk-ui/types";
interface InputDescriptionProps {
children: ReactNode;
id?: string;
className?: string;
container?: PropTypesOf<typeof Typography>["container"];
}
const InputDescription: StatelessComponent<InputDescriptionProps> = props => {
@@ -3,7 +3,7 @@ import React, { ReactNode } from "react";
import { StatelessComponent } from "react";
import { withStyles } from "talk-ui/hocs";
import Typography from "../Typography";
import * as styles from "./InputLabel.css";
import styles from "./InputLabel.css";
export interface InputLabelProps {
/**
@@ -1,7 +1,7 @@
import cn from "classnames";
import React, { ReactNode, StatelessComponent } from "react";
import { withStyles } from "talk-ui/hocs";
import * as styles from "./Message.css";
import styles from "./Message.css";
export interface MessageProps {
/**
@@ -4,7 +4,7 @@ import React, { HTMLAttributes, Ref, StatelessComponent } from "react";
import Icon, { IconProps } from "talk-ui/components/Icon";
import { withForwardRef, withStyles } from "talk-ui/hocs";
import * as styles from "./MessageIcon.css";
import styles from "./MessageIcon.css";
interface InnerProps extends HTMLAttributes<HTMLSpanElement> {
/**
@@ -11,7 +11,7 @@ import {
import { withStyles } from "talk-ui/hocs";
import AriaInfo from "../AriaInfo";
import * as styles from "./Popover.css";
import styles from "./Popover.css";
type Placement =
| "top-start"
@@ -0,0 +1,78 @@
.root {
}
.input {
cursor: pointer;
position: absolute; /* take it out of document flow */
opacity: 0; /* hide it */
}
.label {
composes: bodyCopy from "talk-ui/shared/typography.css";
display: inline-flex;
align-items: center;
position: relative;
cursor: pointer;
user-select: none;
}
.labelLight {
color: var(--palette-text-light);
}
/* Box. */
.input + .label:before {
content: "";
margin-right: 10px;
display: inline-block;
width: 14px;
height: 14px;
background: var(--palette-common-white);
border: 1px solid var(--palette-text-primary);
border-radius: 50%;
box-sizing: border-box;
}
/* Box focus */
.label.focus:before {
outline-width: 3px;
outline-color: Highlight;
outline-color: -webkit-focus-ring-color;
outline-style: auto;
}
/* Box checked */
.input:checked + .label:before {
border: 1px solid var(--palette-primary-main);
background: var(--palette-common-white);
}
/* Disabled state label. */
.input:disabled + .label {
cursor: auto;
opacity: 0.6;
}
/* Disabled box. */
.input:disabled + .label:before {
box-shadow: none;
border: 1px solid var(--palette-grey-main);
background: var(--palette-grey-lightest);
}
/* Checkmark. Could be replaced with an image */
.input:checked + .label:after {
content: "";
background: var(--palette-primary-main);
border-radius: 50%;
position: absolute;
left: 3px;
top: 6px;
width: 8px;
height: 8px;
box-sizing: border-box;
}
.input:checked:disabled + .label:after {
background: var(--palette-text-primary);
}
@@ -0,0 +1,20 @@
---
name: RadioButton
menu: UI Kit
---
import { Playground, PropsTable } from 'docz'
import RadioButton from './RadioButton.tsx'
import HorizontalGutter from '../HorizontalGutter'
# RadioButton
## Basic Use
<Playground>
<HorizontalGutter>
<RadioButton name="key" value="true">Yes I agree</RadioButton>
<RadioButton name="key" value="false">I don't agree</RadioButton>
<RadioButton name="key" value="disabled" disabled>Disabled</RadioButton>
<RadioButton name="another" value="undefined" disabled checked>Disabled + Checked</RadioButton>
</HorizontalGutter>
</Playground>
@@ -0,0 +1,18 @@
import React from "react";
import TestRenderer from "react-test-renderer";
import { PropTypesOf } from "talk-ui/types";
import RadioButton from "./RadioButton";
it("renders correctly", () => {
const props: PropTypesOf<typeof RadioButton> = {
className: "custom",
id: "radioID",
name: "key",
value: "true",
children: "Yes I agree",
};
const renderer = TestRenderer.create(<RadioButton {...props} />);
expect(renderer.toJSON()).toMatchSnapshot();
});
@@ -0,0 +1,88 @@
import cn from "classnames";
import React, { ChangeEvent, Component, EventHandler, FocusEvent } from "react";
import uuid from "uuid/v4";
import { Flex } from "talk-ui/components";
import { withKeyboardFocus, withStyles } from "talk-ui/hocs";
import styles from "./RadioButton.css";
export interface RadioButtonProps {
id?: string;
/**
* The content value of the component.
*/
value?: string;
checked?: boolean;
/**
* Convenient prop to override the root styling.
*/
className?: string;
/**
* Override or extend the styles applied to the component.
*/
classes: typeof styles;
/**
* Mark as readonly
*/
readOnly?: boolean;
/**
* Name
*/
name?: string;
/**
* onChange
*/
onChange?: EventHandler<ChangeEvent<HTMLInputElement>>;
disabled?: boolean;
children: React.ReactNode;
/**
* Display a light text.
*/
light?: boolean;
// These handlers are passed down by the `withKeyboardFocus` HOC.
onFocus: EventHandler<FocusEvent<HTMLElement>>;
onBlur: EventHandler<FocusEvent<HTMLElement>>;
keyboardFocus: boolean;
}
class RadioButton extends Component<RadioButtonProps> {
public state = {
randomID: uuid(),
};
public render() {
const {
className,
classes,
id,
light,
children,
keyboardFocus,
...rest
} = this.props;
const rootClassName = cn(classes.root, className);
const finalID = this.props.id || this.state.randomID;
return (
<Flex alignItems="center" className={rootClassName}>
<input className={classes.input} type="radio" id={finalID} {...rest} />
<label
className={cn(classes.label, {
[classes.labelLight]: light,
[classes.focus]: keyboardFocus,
})}
htmlFor={finalID}
>
{children}
</label>
</Flex>
);
}
}
const enhanced = withStyles(styles)(withKeyboardFocus(RadioButton));
export default enhanced;
@@ -0,0 +1,23 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<div
className="Flex-root RadioButton-root custom Flex-flex Flex-alignCenter"
>
<input
className="RadioButton-input"
id="radioID"
name="key"
onBlur={[Function]}
onFocus={[Function]}
type="radio"
value="true"
/>
<label
className="RadioButton-label"
htmlFor="radioID"
>
Yes I agree
</label>
</div>
`;
@@ -0,0 +1,2 @@
export * from "./RadioButton";
export { default } from "./RadioButton";
@@ -6,7 +6,7 @@ import { UIContext } from "talk-ui/components";
import { withForwardRef, withStyles } from "talk-ui/hocs";
import { PropTypesOf } from "talk-ui/types";
import * as styles from "./RelativeTime.css";
import styles from "./RelativeTime.css";
interface InnerProps {
date: string;
@@ -1,16 +1,11 @@
import cn from "classnames";
import React, {
ChangeEvent,
EventHandler,
FocusEvent,
MouseEvent,
} from "react";
import React, { ChangeEvent, EventHandler, FocusEvent } from "react";
import { StatelessComponent } from "react";
import { withKeyboardFocus, withStyles } from "talk-ui/hocs";
import Icon from "../Icon";
import * as styles from "./SelectField.css";
import styles from "./SelectField.css";
export interface SelectFieldProps {
/**
@@ -42,7 +37,6 @@ export interface SelectFieldProps {
// These handlers are passed down by the `withKeyboardFocus` HOC.
onFocus: EventHandler<FocusEvent<HTMLSelectElement>>;
onBlur: EventHandler<FocusEvent<HTMLSelectElement>>;
onMouseDown: EventHandler<MouseEvent<HTMLSelectElement>>;
keyboardFocus: boolean;
}
@@ -13,7 +13,6 @@ exports[`renders correctly 1`] = `
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
value="pie"
/>
<span
@@ -1,7 +1,7 @@
import cn from "classnames";
import React, { StatelessComponent } from "react";
import { withStyles } from "talk-ui/hocs";
import * as styles from "./Spinner.css";
import styles from "./Spinner.css";
export interface SpinnerProps {
/**
@@ -1,7 +1,7 @@
import cn from "classnames";
import React, { StatelessComponent } from "react";
import Icon from "../Icon";
import * as styles from "./Circle.css";
import styles from "./Circle.css";
interface CircleProps {
active?: boolean;
+1 -1
View File
@@ -1,6 +1,6 @@
import cn from "classnames";
import React, { StatelessComponent } from "react";
import * as styles from "./Line.css";
import styles from "./Line.css";
interface CircleProps {
active?: boolean;
+1 -1
View File
@@ -3,7 +3,7 @@ import Flex from "../Flex";
import Typography from "../Typography";
import Circle from "./Circle";
import Line from "./Line";
import * as styles from "./Step.css";
import styles from "./Step.css";
interface StepProps {
children: ReactText | ReactNode;
@@ -1,7 +1,7 @@
import cn from "classnames";
import React, { Component, ReactNode } from "react";
import Flex from "../Flex";
import * as styles from "./StepBar.css";
import styles from "./StepBar.css";
interface StepBarProps {
children: ReactNode;
+1 -1
View File
@@ -2,7 +2,7 @@ import cn from "classnames";
import React from "react";
import { withStyles } from "talk-ui/hocs";
import BaseButton from "../BaseButton";
import * as styles from "./Tab.css";
import styles from "./Tab.css";
export interface TabProps {
/**
@@ -1,7 +1,7 @@
import cn from "classnames";
import React, { StatelessComponent } from "react";
import { withStyles } from "talk-ui/hocs";
import * as styles from "./TabBar.css";
import styles from "./TabBar.css";
export interface TabBarProps {
/**
@@ -12,7 +12,6 @@ exports[`renders correctly 1`] = `
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
@@ -17,7 +17,6 @@ exports[`renders correctly 1`] = `
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
@@ -39,7 +38,6 @@ exports[`renders correctly 1`] = `
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
@@ -61,7 +59,6 @@ exports[`renders correctly 1`] = `
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
@@ -7,6 +7,15 @@
border-radius: var(--round-corners);
height: 36px;
line-height: 36px;
width: calc(29 * var(--spacing-unit));
&:read-only {
background-color: var(--palette-grey-lightest);
}
&:disabled {
color: var(--palette-text-secondary);
background-color: var(--palette-grey-lightest);
}
}
.colorRegular {
@@ -1,8 +1,8 @@
import cn from "classnames";
import React, { ChangeEvent, EventHandler } from "react";
import React, { AllHTMLAttributes, ChangeEvent, EventHandler } from "react";
import { StatelessComponent } from "react";
import { withStyles } from "talk-ui/hocs";
import * as styles from "./TextField.css";
import styles from "./TextField.css";
export interface TextFieldProps {
id?: string;
@@ -52,6 +52,11 @@ export interface TextFieldProps {
onChange?: EventHandler<ChangeEvent<HTMLInputElement>>;
disabled?: boolean;
autoComplete?: AllHTMLAttributes<HTMLInputElement>["autoComplete"];
autoCorrect?: AllHTMLAttributes<HTMLInputElement>["autoCorrect"];
autoCapitalize?: AllHTMLAttributes<HTMLInputElement>["autoCapitalize"];
spellCheck?: AllHTMLAttributes<HTMLInputElement>["spellCheck"];
}
const TextField: StatelessComponent<TextFieldProps> = props => {
@@ -0,0 +1,4 @@
.root {
color: var(--palette-primary-main);
text-decoration: underline;
}
@@ -0,0 +1,19 @@
---
name: TextLink
menu: UI Kit
---
import { Playground, PropsTable } from 'docz'
import TextLink from './TextLink.tsx'
import HorizontalGutter from '../HorizontalGutter'
# TextLink
## Basic Use
<Playground>
<HorizontalGutter>
<TextLink href="https://coralproject.net">Well... Hello there.</TextLink>
</HorizontalGutter>
</Playground>
@@ -0,0 +1,14 @@
import React from "react";
import TestRenderer from "react-test-renderer";
import { PropTypesOf } from "talk-ui/types";
import TextLink from "./TextLink";
it("renders correctly", () => {
const props: PropTypesOf<typeof TextLink> = {
className: "custom",
};
const renderer = TestRenderer.create(<TextLink {...props}>Hello</TextLink>);
expect(renderer.toJSON()).toMatchSnapshot();
});
@@ -0,0 +1,31 @@
import cn from "classnames";
import React, { AnchorHTMLAttributes } from "react";
import { StatelessComponent } from "react";
import { withStyles } from "talk-ui/hocs";
import styles from "./TextLink.css";
interface Props extends AnchorHTMLAttributes<HTMLAnchorElement> {
/**
* Override or extend the styles applied to the component.
*/
classes: typeof styles;
}
const TextLinkProps: StatelessComponent<Props> = props => {
const { className, children, classes, ...rest } = props;
const rootClassName = cn(classes.root, className);
return (
<a
className={rootClassName}
href={props.href || (children as string)}
{...rest}
>
{children}
</a>
);
};
const enhanced = withStyles(styles)(TextLinkProps);
export default enhanced;
@@ -0,0 +1,10 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<a
className="TextLink-root custom"
href="Hello"
>
Hello
</a>
`;
@@ -0,0 +1 @@
export { default } from "./TextLink";
@@ -5,7 +5,7 @@ import { HTMLAttributes, ReactNode, StatelessComponent } from "react";
import { withForwardRef, withStyles } from "talk-ui/hocs";
import { PropTypesOf } from "talk-ui/types";
import * as styles from "./Typography.css";
import styles from "./Typography.css";
type Variant =
| "heading1"
+3
View File
@@ -24,3 +24,6 @@ export { default as Message, MessageIcon } from "./Message";
export { Tab, TabBar, TabContent, TabPane } from "./Tabs";
export { StepBar, Step } from "./Steps";
export { SelectField, Option, OptGroup } from "./SelectField";
export { default as TextLink } from "./TextLink";
export { default as CheckBox } from "./CheckBox";
export { default as RadioButton } from "./RadioButton";