[CORL-139, CORL-140] Community (#2239)

* feat: Add table ui component

* feat: community user table

* feat: filters and role change

* fix: add some comments

* fix: user viewer

* fix: snapshots

* test: add tests

* fix: better popover experience

* fix: test

* chore: use enum

* feat: prevent server side setting your own role

* fix: cleanup
This commit is contained in:
Kiwi
2019-03-22 20:13:11 +00:00
committed by Wyatt Johnson
parent e70f6f5c7f
commit 538e1fca9d
76 changed files with 2016 additions and 179 deletions
@@ -2,6 +2,7 @@ import cn from "classnames";
import React from "react";
import { Manager, Popper, Reference, RefHandler } from "react-popper";
import { oncePerFrame } from "talk-common/utils";
import { withStyles } from "talk-ui/hocs";
import AriaInfo from "../AriaInfo";
@@ -58,22 +59,33 @@ class Popover extends React.Component<PopoverProps> {
visible: false,
};
public toggleVisibility = (event?: React.SyntheticEvent | Event) => {
if (event && event.stopPropagation) {
event.stopPropagation();
private toggleVisibility = (() => {
let fn = (event?: React.SyntheticEvent | Event) => {
this.setState((state: State) => ({
visible: !state.visible,
}));
};
if (process.env.NODE_ENV !== "test") {
/**
* Only run this once per frame in the browser, otherwise
* we might get into a situation where this is called twice
* by different event handlers cancelling each other out.
*
* We don't wan this behavior when running in a simulated browser
* environment with simulated events.
*/
fn = oncePerFrame(fn);
}
this.setState((state: State) => ({
visible: !state.visible,
}));
};
return fn;
})();
public close = () => {
private close = () => {
this.setState((state: State) => ({
visible: false,
}));
};
public handleEsc = (e: KeyboardEvent) => {
private handleEsc = (e: KeyboardEvent) => {
if (e.key === "Escape") {
e.preventDefault();
this.close();
@@ -26,6 +26,6 @@ exports[`uses formatter from props 1`] = `
dateTime="2018-12-17T03:24:00.000Z"
title="2018-12-17T03:24:00.000Z"
>
My Context Formatter
My Props Formatter
</time>
`;
@@ -0,0 +1,8 @@
.root {
border-collapse: collapse;
box-sizing: border-box;
}
.fullWidth {
width: 100%;
}
@@ -0,0 +1,36 @@
---
name: Table
menu: UI Kit
---
import { Playground, PropsTable } from "docz";
import { Table, TableBody, TableHead, TableRow, TableCell } from "./";
# Table
## Basic usage
<Playground>
<Table fullWidth>
<TableHead>
<TableRow>
<TableCell>Username</TableCell>
<TableCell>E-Mail Address</TableCell>
<TableCell>Member Since</TableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell>ButFirstCoffee</TableCell>
<TableCell>coffee@mail.com</TableCell>
<TableCell>01/27/2019</TableCell>
</TableRow>
<TableRow>
<TableCell>SneaksOnSneaks</TableCell>
<TableCell>hisairness@mail.com</TableCell>
<TableCell>04/27/2019</TableCell>
</TableRow>
</TableBody>
</Table>
</Playground>
@@ -0,0 +1,32 @@
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { Table, TableBody, TableCell, TableHead, TableRow } from ".";
it("renders correctly", () => {
const renderer = createRenderer();
renderer.render(
<Table fullWidth>
<TableHead>
<TableRow>
<TableCell>Username</TableCell>
<TableCell>E-Mail Address</TableCell>
<TableCell>Member Since</TableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell>ButFirstCoffee</TableCell>
<TableCell>coffee@mail.com</TableCell>
<TableCell>01/27/2019</TableCell>
</TableRow>
<TableRow>
<TableCell>SneaksOnSneaks</TableCell>
<TableCell>hisairness@mail.com</TableCell>
<TableCell>04/27/2019</TableCell>
</TableRow>
</TableBody>
</Table>
);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -0,0 +1,36 @@
import cn from "classnames";
import React, { StatelessComponent } from "react";
import { withStyles } from "talk-ui/hocs";
import styles from "./Table.css";
interface Props extends React.HTMLAttributes<HTMLTableElement> {
className?: string;
/**
* Override or extend the styles applied to the component.
*/
classes: typeof styles;
fullWidth?: boolean;
}
const Table: StatelessComponent<Props> = ({
classes,
className,
fullWidth,
children,
...rest
}) => {
const rootClassName = cn(classes.root, className, {
[classes.fullWidth]: fullWidth,
});
return (
<table className={rootClassName} {...rest}>
{children}
</table>
);
};
const enhanced = withStyles(styles)(Table);
export default enhanced;
@@ -0,0 +1,2 @@
.root {
}
@@ -0,0 +1,31 @@
import cn from "classnames";
import React, { StatelessComponent } from "react";
import { withStyles } from "talk-ui/hocs";
import styles from "./TableBody.css";
interface Props extends React.HTMLAttributes<HTMLTableSectionElement> {
className?: string;
/**
* Override or extend the styles applied to the component.
*/
classes: typeof styles;
}
const TableBody: StatelessComponent<Props> = ({
classes,
className,
children,
...rest
}) => {
const rootClassName = cn(classes.root, className);
return (
<tbody className={rootClassName} {...rest}>
{children}
</tbody>
);
};
const enhanced = withStyles(styles)(TableBody);
export default enhanced;
@@ -0,0 +1,25 @@
.root {
/* acts like min-width in a cell */
height: calc(4.5 * var(--spacing-unit));
text-align: left;
padding: var(--spacing-unit) calc(1.5 * var(--spacing-unit));
box-sizing: border-box;
}
.header {
composes: bodyCopy from "talk-ui/shared/typography.css";
color: var(--palette-grey-dark);
}
.body {
composes: detail from "talk-ui/shared/typography.css";
color: var(--palette-grey-dark);
}
.alignCenter {
text-align: center;
}
.alignEnd {
text-align: right;
}
@@ -0,0 +1,45 @@
import cn from "classnames";
import React, { StatelessComponent, useContext } from "react";
import { withStyles } from "talk-ui/hocs";
import { Omit } from "talk-ui/types";
import { TableHeadContext } from "./TableHead";
import styles from "./TableCell.css";
interface Props
extends Omit<React.TdHTMLAttributes<HTMLTableCellElement>, "align"> {
className?: string;
/**
* Override or extend the styles applied to the component.
*/
classes: typeof styles;
align?: "begin" | "center" | "end";
}
const TableCell: StatelessComponent<Props> = ({
align,
classes,
className,
children,
...rest
}) => {
const inTableHead = useContext(TableHeadContext);
const rootClassName = cn(classes.root, className, {
[classes.header]: inTableHead,
[classes.body]: !inTableHead,
[classes.alignCenter]: align === "center",
[classes.alignEnd]: align === "end",
});
const Component = inTableHead ? "th" : "td";
return (
<Component className={rootClassName} {...rest}>
{children}
</Component>
);
};
const enhanced = withStyles(styles)(TableCell);
export default enhanced;
@@ -0,0 +1,5 @@
.root {
background: var(--palette-grey-lightest);
border: 1px solid var(--palette-grey-lighter);
box-sizing: border-box;
}
@@ -0,0 +1,35 @@
import cn from "classnames";
import React, { StatelessComponent } from "react";
import { withStyles } from "talk-ui/hocs";
import styles from "./TableHead.css";
export const TableHeadContext = React.createContext<boolean>(false);
interface Props extends React.HTMLAttributes<HTMLTableSectionElement> {
className?: string;
/**
* Override or extend the styles applied to the component.
*/
classes: typeof styles;
}
const TableHead: StatelessComponent<Props> = ({
classes,
className,
children,
...rest
}) => {
const rootClassName = cn(classes.root, className);
return (
<TableHeadContext.Provider value>
<thead className={rootClassName} {...rest}>
{children}
</thead>
</TableHeadContext.Provider>
);
};
const enhanced = withStyles(styles)(TableHead);
export default enhanced;
@@ -0,0 +1,15 @@
.root {
box-sizing: border-box;
}
.body:nth-child(even) {
background-color: var(--palette-grey-lightest);
}
.body:first-child:hover {
border-top: 1px solid var(--palette-primary-main);
}
.body:hover {
background-color: var(--palette-primary-lightest);
box-shadow: inset 0px 0px 0px 1px var(--palette-primary-main);
}
@@ -0,0 +1,36 @@
import cn from "classnames";
import React, { StatelessComponent, useContext } from "react";
import { withStyles } from "talk-ui/hocs";
import { TableHeadContext } from "./TableHead";
import styles from "./TableRow.css";
interface Props extends React.HTMLAttributes<HTMLTableRowElement> {
className?: string;
/**
* Override or extend the styles applied to the component.
*/
classes: typeof styles;
}
const TableRow: StatelessComponent<Props> = ({
classes,
className,
children,
...rest
}) => {
const inTableHead = useContext(TableHeadContext);
const rootClassName = cn(classes.root, className, {
[classes.body]: !inTableHead,
});
return (
<tr className={rootClassName} {...rest}>
{children}
</tr>
);
};
const enhanced = withStyles(styles)(TableRow);
export default enhanced;
@@ -0,0 +1,51 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<Table
classes={
Object {
"fullWidth": "Table-fullWidth",
"root": "Table-root",
}
}
fullWidth={true}
>
<withPropsOnChange(TableHead)>
<withPropsOnChange(TableRow)>
<withPropsOnChange(TableCell)>
Username
</withPropsOnChange(TableCell)>
<withPropsOnChange(TableCell)>
E-Mail Address
</withPropsOnChange(TableCell)>
<withPropsOnChange(TableCell)>
Member Since
</withPropsOnChange(TableCell)>
</withPropsOnChange(TableRow)>
</withPropsOnChange(TableHead)>
<withPropsOnChange(TableBody)>
<withPropsOnChange(TableRow)>
<withPropsOnChange(TableCell)>
ButFirstCoffee
</withPropsOnChange(TableCell)>
<withPropsOnChange(TableCell)>
coffee@mail.com
</withPropsOnChange(TableCell)>
<withPropsOnChange(TableCell)>
01/27/2019
</withPropsOnChange(TableCell)>
</withPropsOnChange(TableRow)>
<withPropsOnChange(TableRow)>
<withPropsOnChange(TableCell)>
SneaksOnSneaks
</withPropsOnChange(TableCell)>
<withPropsOnChange(TableCell)>
hisairness@mail.com
</withPropsOnChange(TableCell)>
<withPropsOnChange(TableCell)>
04/27/2019
</withPropsOnChange(TableCell)>
</withPropsOnChange(TableRow)>
</withPropsOnChange(TableBody)>
</Table>
`;
@@ -0,0 +1,5 @@
export { default as Table } from "./Table";
export { default as TableBody } from "./TableBody";
export { default as TableHead } from "./TableHead";
export { default as TableRow } from "./TableRow";
export { default as TableCell } from "./TableCell";
+1
View File
@@ -53,3 +53,4 @@ export {
Divider as DropdownDivider,
Button as DropdownButton,
} from "./Dropdown";
export { Table, TableBody, TableHead, TableRow, TableCell } from "./Table";