mirror of
https://github.com/wassname/talk.git
synced 2026-09-09 11:38:08 +08:00
[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:
@@ -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>
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user