[next] Implement configuration panes (#2173)

* feat: moderation config

* feat: configure banned and suspect words

* chore: upgrade react and test libs to the newest version <3

* chore: upgrade typescript + some refactor

* feat: general, organization and advanced configuration panes

* fix: translation

* feat: speedup fetching markdown editor

* feat: localize markdown editor

* chore: refactor container names

* chore: rename infobox to communityGuidelines

* feat: closing comment streams duration config

* test: add feature tests for configurations

* fix: mock only console.error

* chore: upgrade node

* chore: require node >= 10

* fix: better validation and default values

* feat: Make DurationField a general purpose component and reuse for Edit Comment Timeframe

* test: add unit test for duration field

* fix: patch for bug when built in production

* chore: bump npm version to latest

* fix: adapted Dockerfile to new version of node

* refactor: harmonized seconds/milliseconds to seconds

* fix: resolve bug from merge conflict
This commit is contained in:
Kiwi
2019-02-07 01:10:51 +01:00
committed by GitHub
parent 9fa5900acc
commit 53e168ae93
228 changed files with 10582 additions and 2774 deletions
@@ -15,14 +15,16 @@ interface InnerProps extends AllHTMLAttributes<HTMLElement> {
component?: string;
children: React.ReactNode;
/** Internal: Forwarded Ref */
forwardRef?: Ref<HTMLButtonElement>;
forwardRef?: Ref<HTMLElement>;
}
const AriaInfo: StatelessComponent<InnerProps> = props => {
const { component, className, classes, ...rest } = props;
const Component = component!;
const { component, className, classes, forwardRef: ref, ...rest } = props;
const Component: React.ComponentType<
React.HTMLAttributes<HTMLElement> & React.ClassAttributes<HTMLElement>
> = component! as any;
const rootClassName = cn(classes.root, className);
return <Component className={rootClassName} {...rest} />;
return <Component className={rootClassName} {...rest} ref={ref} />;
};
AriaInfo.defaultProps = {
@@ -32,7 +32,7 @@ interface InnerProps extends ButtonHTMLAttributes<HTMLButtonElement> {
classes: typeof styles;
/** Internal: Forwarded Ref */
forwardRef?: Ref<HTMLButtonElement>;
forwardRef?: Ref<HTMLButtonElement | HTMLAnchorElement>;
type?: "submit" | "reset" | "button";
@@ -62,10 +62,13 @@ const BaseButton: StatelessComponent<InnerProps> = ({
type,
...rest
}) => {
let Element = "button";
let Element: React.ComponentType<
React.ButtonHTMLAttributes<HTMLButtonElement | HTMLAnchorElement> &
React.ClassAttributes<HTMLButtonElement | HTMLAnchorElement>
> = "button" as any;
if (anchor) {
Element = "a";
Element = "a" as any;
}
if (anchor && type) {
@@ -3,7 +3,7 @@ import { pick } from "lodash";
import React, { Ref } from "react";
import { withForwardRef, withStyles } from "talk-ui/hocs";
import { PropTypesOf } from "talk-ui/types";
import { Omit, PropTypesOf } from "talk-ui/types";
import BaseButton, { BaseButtonProps } from "../BaseButton";
@@ -11,7 +11,7 @@ import styles from "./Button.css";
// This should extend from BaseButton instead but we can't because of this bug
// TODO: add bug link.
interface InnerProps extends BaseButtonProps {
interface InnerProps extends Omit<BaseButtonProps, "ref"> {
/** If set renders an anchor tag instead */
anchor?: boolean;
href?: string;
@@ -88,7 +88,7 @@ export class Button extends React.Component<InnerProps> {
className={rootClassName}
classes={pick(classes, "keyboardFocus", "mouseHover")}
disabled={disabled}
forwardRef={forwardRef}
ref={forwardRef}
type={type}
{...rest}
/>
@@ -26,7 +26,7 @@ interface InnerProps extends HTMLAttributes<HTMLSpanElement> {
export const ButtonIcon: StatelessComponent<InnerProps> = props => {
const { classes, className, forwardRef, ...rest } = props;
const rootClassName = cn(classes.root, className);
return <Icon className={rootClassName} {...rest} forwardRef={forwardRef} />;
return <Icon className={rootClassName} {...rest} ref={forwardRef} />;
};
ButtonIcon.defaultProps = {
@@ -1,35 +1,34 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`forwards ref 1`] = `
<withPropsOnChange(WithMouseHover)
<ForwardRef(forwardRef)
className=""
classes={Object {}}
forwardRef={[Function]}
>
Push me
</withPropsOnChange(WithMouseHover)>
</ForwardRef(forwardRef)>
`;
exports[`renders a regular sized, primary colored ghost button with fullWidth 1`] = `
<withPropsOnChange(WithMouseHover)
<ForwardRef(forwardRef)
className="sizeRegular colorPrimary variantGhost fullWidth"
classes={Object {}}
>
Push me
</withPropsOnChange(WithMouseHover)>
</ForwardRef(forwardRef)>
`;
exports[`renders active state 1`] = `
<withPropsOnChange(WithMouseHover)
<ForwardRef(forwardRef)
className="active"
classes={Object {}}
>
Push me
</withPropsOnChange(WithMouseHover)>
</ForwardRef(forwardRef)>
`;
exports[`renders correctly 1`] = `
<withPropsOnChange(WithMouseHover)
<ForwardRef(forwardRef)
className=""
classes={
Object {
@@ -39,5 +38,5 @@ exports[`renders correctly 1`] = `
}
>
Push me
</withPropsOnChange(WithMouseHover)>
</ForwardRef(forwardRef)>
`;
@@ -1,20 +1,19 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`forwards ref 1`] = `
<withPropsOnChange(Icon)
<ForwardRef(forwardRef)
className=""
forwardRef={[Function]}
size="sm"
>
Push me
</withPropsOnChange(Icon)>
</ForwardRef(forwardRef)>
`;
exports[`renders correctly 1`] = `
<withPropsOnChange(Icon)
<ForwardRef(forwardRef)
className="root"
size="sm"
>
Push me
</withPropsOnChange(Icon)>
</ForwardRef(forwardRef)>
`;
@@ -3,12 +3,13 @@ import React, { ReactNode } from "react";
import { StatelessComponent } from "react";
import { withStyles } from "talk-ui/hocs";
import { Omit, PropTypesOf } from "talk-ui/types";
import HorizontalGutter from "../HorizontalGutter";
import styles from "./FormField.css";
interface InnerProps {
interface InnerProps extends Omit<PropTypesOf<typeof HorizontalGutter>, "ref"> {
children: ReactNode;
classes: typeof styles;
id?: string;
@@ -22,10 +22,14 @@ exports[`works with multiple form components 1`] = `
>
A unique identifier displayed on your comments. You may use “_” and “.”
</p>
<input
className="TextField-root TextField-colorRegular"
placeholder=""
type="text"
/>
<div
className="TextField-root"
>
<input
className="TextField-input TextField-colorRegular"
placeholder=""
type="text"
/>
</div>
</div>
`;
@@ -1,4 +1,7 @@
.root {
display: block;
border: 0;
padding: 0;
}
.half {
@@ -2,11 +2,13 @@ import cn from "classnames";
import React, { ReactNode } from "react";
import { StatelessComponent } from "react";
import { withStyles } from "talk-ui/hocs";
import Typography from "../Typography";
import { Omit, PropTypesOf } from "talk-ui/types";
import Typography from "../Typography";
import styles from "./InputLabel.css";
export interface InputLabelProps {
export interface InputLabelProps
extends Omit<PropTypesOf<typeof Typography>, "ref"> {
id?: string;
htmlFor?: string;
/**
@@ -25,7 +25,7 @@ interface InnerProps extends HTMLAttributes<HTMLSpanElement> {
export const MessageIcon: StatelessComponent<InnerProps> = props => {
const { classes, className, forwardRef, ...rest } = props;
const rootClassName = cn(classes.root, className);
return <Icon className={rootClassName} {...rest} forwardRef={forwardRef} />;
return <Icon className={rootClassName} {...rest} ref={forwardRef} />;
};
MessageIcon.defaultProps = {
@@ -43,7 +43,7 @@
/* Box checked */
.input:checked + .label:before {
border: 1px solid var(--palette-primary-main);
border: 1px solid var(--palette-text-primary);
background: var(--palette-common-white);
}
@@ -63,7 +63,7 @@
/* Checkmark. Could be replaced with an image */
.input:checked + .label:after {
content: "";
background: var(--palette-primary-main);
background: var(--palette-text-primary);
border-radius: 50%;
position: absolute;
left: 3px;
@@ -44,7 +44,7 @@
color: var(--palette-text-secondary);
}
border: 1px solid var(--palette-text-primary);
border: 1px solid var(--palette-grey-light);
border-radius: var(--round-corners);
background-color: var(--palette-common-white);
@@ -1,4 +1,10 @@
.root {
display: flex;
width: calc(29 * var(--spacing-unit));
align-items: center;
}
.input {
composes: inputText placeholderPseudo from "talk-ui/shared/typography.css";
position: relative;
display: block;
@@ -7,7 +13,7 @@
border-radius: var(--round-corners);
height: 36px;
line-height: 36px;
width: calc(29 * var(--spacing-unit));
width: 100%;
&:read-only {
background-color: var(--palette-grey-lightest);
@@ -18,6 +24,10 @@
}
}
.input + * {
padding-left: calc(0.5 * var(--spacing-unit));
}
.colorRegular {
background-color: var(--palette-common-white);
color: var(--palette-common-black);
@@ -33,3 +43,7 @@
.fullWidth {
width: 100%;
}
.textAlignCenter {
text-align: center;
}
@@ -3,18 +3,27 @@ name: TextField
menu: UI Kit
---
import { Playground, PropsTable } from 'docz'
import TextField from './TextField.tsx'
import HorizontalGutter from '../HorizontalGutter'
import { Playground, PropsTable } from "docz";
import TextField from "./TextField.tsx";
import HorizontalGutter from "../HorizontalGutter";
# TextField
## Basic Use
<Playground>
<HorizontalGutter>
<TextField placeholder="This is a placeholder" />
<TextField defaultValue="This is an input field" />
<TextField color="error" defaultValue="A TextField with an error" />
<TextField color="error" defaultValue="A TextField with an error" fullWidth/>
<TextField
color="error"
defaultValue="A TextField with an error"
fullWidth
/>
<TextField
placeholder="This is a placeholder"
adornment={<span>Seconds</span>}
/>
</HorizontalGutter>
</Playground>
@@ -9,6 +9,7 @@ it("renders correctly", () => {
const props: PropTypesOf<typeof TextField> = {
className: "custom",
defaultValue: "Hello World",
adornment: "Unit",
};
const renderer = TestRenderer.create(<TextField {...props} />);
expect(renderer.toJSON()).toMatchSnapshot();
@@ -59,6 +59,9 @@ export interface TextFieldProps {
autoCorrect?: AllHTMLAttributes<HTMLInputElement>["autoCorrect"];
autoCapitalize?: AllHTMLAttributes<HTMLInputElement>["autoCapitalize"];
spellCheck?: AllHTMLAttributes<HTMLInputElement>["spellCheck"];
textAlignCenter?: boolean;
adornment?: React.ReactNode;
}
const TextField: StatelessComponent<TextFieldProps> = props => {
@@ -69,26 +72,35 @@ const TextField: StatelessComponent<TextFieldProps> = props => {
fullWidth,
value,
placeholder,
adornment,
textAlignCenter,
...rest
} = props;
const rootClassName = cn(
classes.root,
{
[classes.colorRegular]: color === "regular",
[classes.colorError]: color === "error",
[classes.fullWidth]: fullWidth,
},
className
);
const inputClassName = cn(classes.input, {
[classes.colorRegular]: color === "regular",
[classes.colorError]: color === "error",
[classes.textAlignCenter]: textAlignCenter,
});
return (
<input
className={rootClassName}
placeholder={placeholder}
value={value}
{...rest}
/>
<div className={rootClassName}>
<input
className={inputClassName}
placeholder={placeholder}
value={value}
{...rest}
/>
{adornment}
</div>
);
};
@@ -1,10 +1,15 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<input
className="TextField-root TextField-colorRegular custom"
defaultValue="Hello World"
placeholder=""
type="text"
/>
<div
className="TextField-root custom"
>
<input
className="TextField-input TextField-colorRegular"
defaultValue="Hello World"
placeholder=""
type="text"
/>
Unit
</div>
`;