diff --git a/package-lock.json b/package-lock.json
index f4ddb8d3b..57e782760 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14289,6 +14289,12 @@
"css-mediaquery": "^0.1.2"
}
},
+ "material-design-icons": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/material-design-icons/-/material-design-icons-3.0.1.tgz",
+ "integrity": "sha1-mnHEh0chjrylHlGmbaaCA4zct78=",
+ "dev": true
+ },
"math-expression-evaluator": {
"version": "1.2.17",
"resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz",
diff --git a/package.json b/package.json
index b7e66c3d5..dfd500620 100644
--- a/package.json
+++ b/package.json
@@ -115,6 +115,7 @@
"jest": "^23.4.1",
"jsdom": "^11.11.0",
"loader-utils": "^1.1.0",
+ "material-design-icons": "^3.0.1",
"npm-run-all": "^4.1.3",
"postcss-advanced-variables": "^2.3.3",
"postcss-css-variables": "^0.9.0",
diff --git a/src/core/client/stream/components/__snapshots__/App.spec.tsx.snap b/src/core/client/stream/components/__snapshots__/App.spec.tsx.snap
index 6a12e4e09..2fc77d00c 100644
--- a/src/core/client/stream/components/__snapshots__/App.spec.tsx.snap
+++ b/src/core/client/stream/components/__snapshots__/App.spec.tsx.snap
@@ -1,14 +1,14 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
-
-
+
`;
exports[`renders correctly when asset is null 1`] = `
diff --git a/src/core/client/stream/components/__snapshots__/ReplyList.spec.tsx.snap b/src/core/client/stream/components/__snapshots__/ReplyList.spec.tsx.snap
index 9fbe86dab..5707b755f 100644
--- a/src/core/client/stream/components/__snapshots__/ReplyList.spec.tsx.snap
+++ b/src/core/client/stream/components/__snapshots__/ReplyList.spec.tsx.snap
@@ -2,7 +2,7 @@
exports[`renders correctly 1`] = `
-
-
+
`;
exports[`when there is more disables load more button 1`] = `
-
+
`;
exports[`when there is more renders a load more button 1`] = `
-
+
`;
diff --git a/src/core/client/stream/components/__snapshots__/Stream.spec.tsx.snap b/src/core/client/stream/components/__snapshots__/Stream.spec.tsx.snap
index a8210fd99..441437216 100644
--- a/src/core/client/stream/components/__snapshots__/Stream.spec.tsx.snap
+++ b/src/core/client/stream/components/__snapshots__/Stream.spec.tsx.snap
@@ -10,14 +10,14 @@ exports[`renders correctly 1`] = `
-
-
+
-
-
+
+
`;
@@ -71,14 +71,14 @@ exports[`when there is more disables load more button 1`] = `
-
-
+
-
+
-
+
`;
@@ -147,14 +147,14 @@ exports[`when there is more renders a load more button 1`] = `
-
-
+
-
+
-
+
`;
diff --git a/src/core/client/ui/components/BaseButton/BaseButton.spec.tsx b/src/core/client/ui/components/BaseButton/BaseButton.spec.tsx
new file mode 100644
index 000000000..b7754c865
--- /dev/null
+++ b/src/core/client/ui/components/BaseButton/BaseButton.spec.tsx
@@ -0,0 +1,24 @@
+import React from "react";
+import TestRenderer from "react-test-renderer";
+
+import { PropTypesOf } from "talk-framework/types";
+
+import BaseButton from "./BaseButton";
+
+it("renders correctly", () => {
+ const props: PropTypesOf = {
+ className: "my-class",
+ children: "Push Me",
+ };
+ const renderer = TestRenderer.create();
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
+
+it("renders as anchor", () => {
+ const props: PropTypesOf = {
+ anchor: true,
+ children: "Push Me",
+ };
+ const renderer = TestRenderer.create();
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/BaseButton/__snapshots__/BaseButton.spec.tsx.snap b/src/core/client/ui/components/BaseButton/__snapshots__/BaseButton.spec.tsx.snap
new file mode 100644
index 000000000..c6fd97a78
--- /dev/null
+++ b/src/core/client/ui/components/BaseButton/__snapshots__/BaseButton.spec.tsx.snap
@@ -0,0 +1,29 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders as anchor 1`] = `
+
+ Push Me
+
+`;
+
+exports[`renders correctly 1`] = `
+
+`;
diff --git a/src/core/client/ui/components/Button/Button.css b/src/core/client/ui/components/Button/Button.css
index bda2d0e31..9124a859f 100644
--- a/src/core/client/ui/components/Button/Button.css
+++ b/src/core/client/ui/components/Button/Button.css
@@ -1,9 +1,20 @@
.root {
composes: button from "talk-ui/shared/typography.css";
- padding: 5px 20px;
+ padding: 5px 15px;
border-radius: var(--round-corners);
background-color: transparent;
+ position: relative;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ & > * {
+ margin: 0 calc(0.5 * var(--spacing-unit)) 0 0;
+ }
+ & > *:last-child {
+ margin: 0;
+ }
}
.root.disabled {
diff --git a/src/core/client/ui/components/Button/Button.mdx b/src/core/client/ui/components/Button/Button.mdx
index 398aff282..011e47ea5 100644
--- a/src/core/client/ui/components/Button/Button.mdx
+++ b/src/core/client/ui/components/Button/Button.mdx
@@ -5,6 +5,7 @@ menu: UI Kit
import { Playground } from 'docz'
import Button from './Button'
+import Icon from '../Icon'
import Flex from '../Flex'
# Button
@@ -28,3 +29,14 @@ import Flex from '../Flex'
+
+## Button with Icon
+
+
+
+
+
+
+
+
+
diff --git a/src/core/client/ui/components/Button/Button.tsx b/src/core/client/ui/components/Button/Button.tsx
index 8a73c0c1a..aaeaeb518 100644
--- a/src/core/client/ui/components/Button/Button.tsx
+++ b/src/core/client/ui/components/Button/Button.tsx
@@ -64,7 +64,7 @@ class Button extends React.Component {
className={rootClassName}
classes={pick(classes, "keyboardFocus", "mouseHover")}
disabled={disabled}
- ref={forwardRef}
+ forwardRef={forwardRef}
{...rest}
/>
);
diff --git a/src/core/client/ui/components/Flex/Flex.spec.tsx b/src/core/client/ui/components/Flex/Flex.spec.tsx
index b774d9961..5c68f0de0 100644
--- a/src/core/client/ui/components/Flex/Flex.spec.tsx
+++ b/src/core/client/ui/components/Flex/Flex.spec.tsx
@@ -1,5 +1,5 @@
-import { shallow } from "enzyme";
import React from "react";
+import TestRenderer from "react-test-renderer";
import { PropTypesOf } from "talk-ui/types";
@@ -11,10 +11,58 @@ it("renders correctly", () => {
alignItems: "center",
direction: "row",
};
- const wrapper = shallow(
+ const renderer = TestRenderer.create(
Hello World
);
- expect(wrapper).toMatchSnapshot();
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
+
+it("renders with wrap", () => {
+ const props: PropTypesOf = {
+ wrap: true,
+ };
+ const renderer = TestRenderer.create(
+
+ Hello World
+
+ );
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
+
+it("renders with wrap reverse", () => {
+ const props: PropTypesOf = {
+ wrap: "reverse",
+ };
+ const renderer = TestRenderer.create(
+
+ Hello World
+
+ );
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
+
+it("renders with item gutter", () => {
+ const props: PropTypesOf = {
+ itemGutter: true,
+ };
+ const renderer = TestRenderer.create(
+
+ Hello World
+
+ );
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
+
+it("renders with halfe item gutter", () => {
+ const props: PropTypesOf = {
+ itemGutter: "half",
+ };
+ const renderer = TestRenderer.create(
+
+ Hello World
+
+ );
+ expect(renderer.toJSON()).toMatchSnapshot();
});
diff --git a/src/core/client/ui/components/Flex/Flex.tsx b/src/core/client/ui/components/Flex/Flex.tsx
index 8bf770ec7..62d8ff66c 100644
--- a/src/core/client/ui/components/Flex/Flex.tsx
+++ b/src/core/client/ui/components/Flex/Flex.tsx
@@ -3,11 +3,16 @@ import React, { Ref } from "react";
import { StatelessComponent } from "react";
import { pascalCase } from "talk-common/utils";
-import { withForwardRef } from "talk-ui/hocs";
+import { withForwardRef, withStyles } from "talk-ui/hocs";
import * as styles from "./Flex.css";
interface InnerProps {
+ /**
+ * This prop can be used to add custom classnames.
+ * It is handled by the `withStyles `HOC.
+ */
+ classes: typeof styles;
id?: string;
role?: string;
justifyContent?:
@@ -32,6 +37,7 @@ interface InnerProps {
const Flex: StatelessComponent = props => {
const {
+ classes,
className,
justifyContent,
alignItems,
@@ -43,27 +49,29 @@ const Flex: StatelessComponent = props => {
} = props;
const classObject: Record = {
- [styles.itemGutter]: itemGutter === true,
- [styles.halfItemGutter]: itemGutter === "half",
- [styles.wrap]: wrap === true,
- [styles.wrapReverse]: wrap === "reverse",
+ [classes.itemGutter]: itemGutter === true,
+ [classes.halfItemGutter]: itemGutter === "half",
+ [classes.wrap]: wrap === true,
+ [classes.wrapReverse]: wrap === "reverse",
};
if (justifyContent) {
- classObject[(styles as any)[`justify${pascalCase(justifyContent)}`]] = true;
+ classObject[
+ (classes as any)[`justify${pascalCase(justifyContent)}`]
+ ] = true;
}
if (alignItems) {
- classObject[(styles as any)[`align${pascalCase(alignItems)}`]] = true;
+ classObject[(classes as any)[`align${pascalCase(alignItems)}`]] = true;
}
if (direction) {
- classObject[(styles as any)[`direction${pascalCase(direction)}`]] = true;
+ classObject[(classes as any)[`direction${pascalCase(direction)}`]] = true;
}
- const classNames: string = cn(styles.root, className, classObject);
+ const classNames: string = cn(classes.root, className, classObject);
return ;
};
-export default withForwardRef(Flex);
+export default withForwardRef(withStyles(styles)(Flex));
diff --git a/src/core/client/ui/components/Flex/__snapshots__/Flex.spec.tsx.snap b/src/core/client/ui/components/Flex/__snapshots__/Flex.spec.tsx.snap
index 90ef93c13..31f1f73c1 100644
--- a/src/core/client/ui/components/Flex/__snapshots__/Flex.spec.tsx.snap
+++ b/src/core/client/ui/components/Flex/__snapshots__/Flex.spec.tsx.snap
@@ -9,3 +9,43 @@ exports[`renders correctly 1`] = `
`;
+
+exports[`renders with halfe item gutter 1`] = `
+
+`;
+
+exports[`renders with item gutter 1`] = `
+
+`;
+
+exports[`renders with wrap 1`] = `
+
+`;
+
+exports[`renders with wrap reverse 1`] = `
+
+`;
diff --git a/src/core/client/ui/components/Icon/Icon.css b/src/core/client/ui/components/Icon/Icon.css
new file mode 100644
index 000000000..65163aa8d
--- /dev/null
+++ b/src/core/client/ui/components/Icon/Icon.css
@@ -0,0 +1,53 @@
+@font-face {
+ font-family: "Material Icons";
+ font-style: normal;
+ font-weight: 400;
+ src: local("Material Icons"), local("MaterialIcons-Regular"),
+ url(material-design-icons/iconfont/MaterialIcons-Regular.woff2)
+ format("woff2"),
+ url(material-design-icons/iconfont/MaterialIcons-Regular.woff)
+ format("woff"),
+ url(material-design-icons/iconfont/MaterialIcons-Regular.ttf)
+ format("truetype");
+}
+
+.root {
+ font-family: "Material Icons";
+ speak: none;
+ font-style: normal;
+ font-weight: normal;
+ font-variant: normal;
+ text-transform: none;
+ line-height: 1;
+ overflow: hidden;
+ vertical-align: middle;
+ display: inline-block;
+
+ /* Enable Ligatures */
+ font-feature-settings: "liga";
+ font-variant-ligatures: "discretionary-ligatures";
+
+ /* Support for Safari and Chrome. */
+ text-rendering: optimizeLegibility;
+
+ /* Better Font Rendering */
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+.sm {
+ font-size: 18px;
+ width: 18px;
+}
+.md {
+ font-size: 24px;
+ width: 24px;
+}
+.lg {
+ font-size: 36px;
+ width: 36px;
+}
+.xl {
+ font-size: 48px;
+ width: 48px;
+}
diff --git a/src/core/client/ui/components/Icon/Icon.mdx b/src/core/client/ui/components/Icon/Icon.mdx
new file mode 100644
index 000000000..83428c28b
--- /dev/null
+++ b/src/core/client/ui/components/Icon/Icon.mdx
@@ -0,0 +1,21 @@
+---
+name: Icon
+menu: UI Kit
+---
+
+import { Playground, PropsTable } from 'docz'
+import Icon from './Icon'
+
+# Icon
+
+Renders an icon.
+
+Checkout available icons https://material.io/tools/icons/
+
+## Basic usage
+
+ face
+ face
+ face
+ face
+
diff --git a/src/core/client/ui/components/Icon/Icon.spec.tsx b/src/core/client/ui/components/Icon/Icon.spec.tsx
new file mode 100644
index 000000000..93cf68a66
--- /dev/null
+++ b/src/core/client/ui/components/Icon/Icon.spec.tsx
@@ -0,0 +1,23 @@
+import React from "react";
+import TestRenderer from "react-test-renderer";
+
+import { PropTypesOf } from "talk-framework/types";
+
+import Icon from "./Icon";
+
+it("renders correctly", () => {
+ const props: PropTypesOf = {
+ children: "face",
+ };
+ const renderer = TestRenderer.create();
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
+
+it("renders correctly with specified size", () => {
+ const props: PropTypesOf = {
+ size: "lg",
+ children: "bookmark",
+ };
+ const renderer = TestRenderer.create();
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/Icon/Icon.tsx b/src/core/client/ui/components/Icon/Icon.tsx
new file mode 100644
index 000000000..4f920f2e5
--- /dev/null
+++ b/src/core/client/ui/components/Icon/Icon.tsx
@@ -0,0 +1,37 @@
+import cn from "classnames";
+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";
+
+interface InnerProps extends HTMLAttributes {
+ /**
+ * This prop can be used to add custom classnames.
+ * It is handled by the `withStyles `HOC.
+ */
+ classes: typeof styles;
+
+ size?: "sm" | "md" | "lg" | "xl";
+
+ /** ref to the HTMLIconElement */
+ ref?: Ref;
+
+ /** Internal: Forwarded Ref */
+ forwardRef?: Ref;
+}
+
+const Icon: StatelessComponent = props => {
+ const { classes, className, size, forwardRef, ...rest } = props;
+ const rootClassName = cn(classes.root, className, classes[size!]);
+ return ;
+};
+
+Icon.defaultProps = {
+ size: "sm",
+};
+
+const enhanced = withForwardRef(withStyles(styles)(Icon));
+export type IconProps = PropTypesOf;
+export default enhanced;
diff --git a/src/core/client/ui/components/Icon/__snapshots__/Icon.spec.tsx.snap b/src/core/client/ui/components/Icon/__snapshots__/Icon.spec.tsx.snap
new file mode 100644
index 000000000..5e5a8c969
--- /dev/null
+++ b/src/core/client/ui/components/Icon/__snapshots__/Icon.spec.tsx.snap
@@ -0,0 +1,17 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+
+ face
+
+`;
+
+exports[`renders correctly with specified size 1`] = `
+
+ bookmark
+
+`;
diff --git a/src/core/client/ui/components/Icon/index.ts b/src/core/client/ui/components/Icon/index.ts
new file mode 100644
index 000000000..3e8146f8b
--- /dev/null
+++ b/src/core/client/ui/components/Icon/index.ts
@@ -0,0 +1,2 @@
+export * from "./Icon";
+export { default } from "./Icon";