mirror of
https://github.com/wassname/talk.git
synced 2026-09-11 12:51:33 +08:00
[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:
@@ -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";
|
||||
@@ -53,3 +53,4 @@ export {
|
||||
Divider as DropdownDivider,
|
||||
Button as DropdownButton,
|
||||
} from "./Dropdown";
|
||||
export { Table, TableBody, TableHead, TableRow, TableCell } from "./Table";
|
||||
|
||||
Reference in New Issue
Block a user