Merge branch 'next' of github.com:coralproject/talk into permalink

* 'next' of github.com:coralproject/talk: (36 commits)
  [next] Implement AriaInfo (#1756)
  e render props for TrapFocus (#1755)
  [ToggleShow] Fix typo and better description (#1753)
  Fix wrong hour pluralization
  Implement button active state
  Styling fixes
  Fix Playground
  Commit snapshots
  Harmonize typography
  Fix Flex margin bug and add examples
  Update package-lock.json
  Use explicit export
  Implement ButtonIcon component
  Remove wrong ref prop
  Implement new button api
  Read env in watchers.ts
  updated tests
  Update ToggleShow.spec.tsx
  ToggleShow Component
  Fix CI thanks to wyatt
  ...
This commit is contained in:
Belén Curcio
2018-07-23 16:00:08 -03:00
88 changed files with 1972 additions and 386 deletions
+17 -1
View File
@@ -21,6 +21,12 @@ jobs:
at: ~/coralproject/talk
- restore_cache:
key: dependency-cache-{{ checksum "package-lock.json" }}
- run:
name: Update NPM
command: sudo npm update -g npm
- run:
name: Audit dependencies
command: npm audit
- run:
name: Install dependencies
command: npm install
@@ -46,6 +52,10 @@ jobs:
# unit_tests will run the unit tests.
unit_tests:
<<: *job_defaults
environment:
<<: *job_environment
CI: true
JEST_JUNIT_OUTPUT: "reports/junit/js-test-results.xml"
steps:
- checkout
- attach_workspace:
@@ -55,7 +65,13 @@ jobs:
command: npm run compile
- run:
name: Perform testing
command: npm run test
# We're running these tests in band to avoid errors where the circleci
# test runner runs out of RAM trying to run them all in parallel.
command: npm run test -- --ci --runInBand --testResultsProcessor="jest-junit"
- store_test_results:
path: reports/junit
- store_artifacts:
path: reports/junit
# build will build the static assets and server typescript files.
build:
+2
View File
@@ -4,6 +4,8 @@ import {
Config,
LongRunningExecutor,
} from "../scripts/watcher";
// Ensure environment variables are read.
import "./env";
const config: Config = {
rootDir: path.resolve(__dirname, "../src"),
+4
View File
@@ -25,6 +25,10 @@ export default {
options: {
modules: true,
importLoaders: 1,
localIdentName:
process.env.NODE_ENV === "production"
? "[hash:base64]"
: "[name]-[local]-[hash:base64:5]",
},
},
{
+53
View File
@@ -12553,6 +12553,35 @@
"pretty-format": "^23.2.0"
}
},
"jest-junit": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/jest-junit/-/jest-junit-5.1.0.tgz",
"integrity": "sha512-3EVf1puv2ox5wybQDfLX3AEn3IKOgDV4E76y4pO2hBu46DEtAFZZAm//X1pzPQpqKji0zqgMIzqzF/K+uGAX9A==",
"dev": true,
"requires": {
"jest-validate": "^23.0.1",
"mkdirp": "^0.5.1",
"strip-ansi": "^4.0.0",
"xml": "^1.0.1"
},
"dependencies": {
"ansi-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
"dev": true
},
"strip-ansi": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
"dev": true,
"requires": {
"ansi-regex": "^3.0.0"
}
}
}
},
"jest-leak-detector": {
"version": "23.2.0",
"resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-23.2.0.tgz",
@@ -14421,6 +14450,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",
@@ -21956,6 +21991,18 @@
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
"dev": true
},
"typeface-manuale": {
"version": "0.0.54",
"resolved": "https://registry.npmjs.org/typeface-manuale/-/typeface-manuale-0.0.54.tgz",
"integrity": "sha512-wWgWFPSvoxEDdm8Dmq0cZzgmBfRXho5WhxU6x4dKBk7WIBsyvRgcjT+j7cQ3ah/9VYp1+nJzQWhCue+TiqA7FA==",
"dev": true
},
"typeface-source-sans-pro": {
"version": "0.0.54",
"resolved": "https://registry.npmjs.org/typeface-source-sans-pro/-/typeface-source-sans-pro-0.0.54.tgz",
"integrity": "sha512-4nsvldyZsOBuvR4oEuUMTquJFVssP4iIVnMEIU4paCWo2940b6r/t95sk7KwDpCablS8DprM/YlhpgqnS7gpKg==",
"dev": true
},
"typescript": {
"version": "2.9.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz",
@@ -23331,6 +23378,12 @@
"integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=",
"dev": true
},
"xml": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz",
"integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=",
"dev": true
},
"xml-name-validator": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
+4
View File
@@ -115,8 +115,10 @@
"graphql-playground-middleware-express": "^1.7.2",
"html-webpack-plugin": "^3.2.0",
"jest": "^23.4.1",
"jest-junit": "^5.1.0",
"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",
@@ -161,6 +163,8 @@
"tslint-plugin-prettier": "^1.3.0",
"tslint-react": "^3.6.0",
"typed-css-modules": "^0.3.4",
"typeface-manuale": "0.0.54",
"typeface-source-sans-pro": "0.0.54",
"typescript": "^2.9.2",
"uglifyjs-webpack-plugin": "^1.2.5",
"webpack": "4.12.0",
+5 -1
View File
@@ -22,7 +22,11 @@ let argv = process.argv.slice(2);
argv.push("--config", paths.appJestConfig);
// Watch unless on CI or in coverage mode
if (!process.env.CI && argv.indexOf("--coverage") < 0) {
if (
!process.env.CI && // ensure that the ci env var is not set.
argv.indexOf("--ci") < 0 && // ensure that the ci flag is not passed
argv.indexOf("--coverage") < 0 // ensure that the coverage flag is not passed
) {
argv.push("--watch");
}
@@ -22,10 +22,10 @@ function createMutationContainer<T extends string, I, R>(
): InferableComponentEnhancer<{ [P in T]: (input: I) => Promise<R> }> {
return compose(
withContext(({ relayEnvironment }) => ({ relayEnvironment })),
hoistStatics((WrappedComponent: React.ComponentType<any>) => {
hoistStatics((BaseComponent: React.ComponentType<any>) => {
class CreateMutationContainer extends React.Component<any> {
public static displayName = wrapDisplayName(
WrappedComponent,
BaseComponent,
"createMutationContainer"
);
@@ -38,7 +38,7 @@ function createMutationContainer<T extends string, I, R>(
const inject = {
[propName]: this.commit,
};
return <WrappedComponent {...rest} {...inject} />;
return <BaseComponent {...rest} {...inject} />;
}
}
return CreateMutationContainer as React.ComponentType<any>;
@@ -34,7 +34,7 @@ function withLocalStateContainer<T>(
): InferableComponentEnhancer<{ local: T }> {
return compose(
withContext(({ relayEnvironment }) => ({ relayEnvironment })),
hoistStatics((WrappedComponent: React.ComponentType<any>) => {
hoistStatics((BaseComponent: React.ComponentType<any>) => {
class LocalStateContainer extends React.Component<Props, any> {
constructor(props: Props) {
super(props);
@@ -65,7 +65,7 @@ function withLocalStateContainer<T>(
public render() {
const { relayEnvironment: _, ...rest } = this.props;
return <WrappedComponent {...rest} local={this.state.data} />;
return <BaseComponent {...rest} local={this.state.data} />;
}
}
return LocalStateContainer as React.ComponentType<any>;
+1 -1
View File
@@ -1,2 +1,2 @@
// TODO: (@cvle) Extract useful common types into its own package.
export { Diff, Omit, Overwrite, PropTypesOf } from "talk-ui/types";
export { Omit, Overwrite, PropTypesOf } from "talk-ui/types";
@@ -2,7 +2,7 @@
exports[`renders correctly on big screens 1`] = `
<span
className="Typography-root Typography-heading2 Username-root"
className="Typography-root Typography-heading2 Typography-colorTextPrimary Username-root"
>
Marvin
</span>
@@ -10,7 +10,7 @@ exports[`renders correctly on big screens 1`] = `
exports[`renders correctly on small screens 1`] = `
<span
className="Typography-root Typography-heading3 Username-root"
className="Typography-root Typography-heading3 Typography-colorTextPrimary Username-root"
>
Marvin
</span>
+1 -1
View File
@@ -4,5 +4,5 @@
}
.level0 {
border-color: var(--palette-secondary-darkest);
border-color: var(--palette-grey-darkest);
}
@@ -1,5 +1,5 @@
.textarea {
composes: body1 from "talk-ui/shared/typography.css";
composes: bodyCopy from "talk-ui/shared/typography.css";
display: block;
height: 100px;
@@ -41,7 +41,7 @@ const PostCommentForm: StatelessComponent<PostCommentFormProps> = props => (
</Field>
<div className={styles.postButtonContainer}>
<Localized id="comments-postCommentForm-post">
<Button disabled={submitting} primary>
<Button color="primary" variant="filled" disabled={submitting}>
Post
</Button>
</Localized>
@@ -39,4 +39,11 @@ describe("when there is more", () => {
.simulate("click");
expect((props.onShowAll as SinonSpy).calledOnce).toBe(true);
});
const wrapperDisabledButton = shallow(
<ReplyList {...props} disableShowAll />
);
it("disables load more button", () => {
expect(wrapperDisabledButton).toMatchSnapshot();
});
});
@@ -34,8 +34,7 @@ const ReplyList: StatelessComponent<ReplyListProps> = props => {
aria-controls={`talk-comments-replyList-log--${props.commentID}`}
onClick={props.onShowAll}
disabled={props.disableShowAll}
secondary
invert
variant="outlined"
fullWidth
>
Show All Replies
+1 -2
View File
@@ -42,8 +42,7 @@ const Stream: StatelessComponent<StreamProps> = props => {
<Button
id={"talk-comments-stream-loadMore"}
onClick={props.onLoadMore}
secondary
invert
variant="outlined"
fullWidth
disabled={props.disableLoadMore}
aria-controls="talk-comments-stream-log"
@@ -1,14 +1,14 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<Flex
<withPropsOnChange(Flex)
className="App-root"
justifyContent="center"
>
<Relay(StreamContainer)
asset={Object {}}
/>
</Flex>
</withPropsOnChange(Flex)>
`;
exports[`renders correctly when asset is null 1`] = `
@@ -2,7 +2,7 @@
exports[`renders correctly 1`] = `
<Indent>
<Flex
<withPropsOnChange(Flex)
direction="column"
id="talk-comments-replyList-log--comment-id"
itemGutter={true}
@@ -24,13 +24,55 @@ exports[`renders correctly 1`] = `
}
key="comment-2"
/>
</Flex>
</withPropsOnChange(Flex)>
</Indent>
`;
exports[`when there is more disables load more button 1`] = `
<Indent>
<withPropsOnChange(Flex)
direction="column"
id="talk-comments-replyList-log--comment-id"
itemGutter={true}
role="log"
>
<Relay(CommentContainer)
data={
Object {
"id": "comment-1",
}
}
key="comment-1"
/>
<Relay(CommentContainer)
data={
Object {
"id": "comment-2",
}
}
key="comment-2"
/>
<Localized
id="comments-replyList-showAll"
>
<withPropsOnChange(Button)
aria-controls="talk-comments-replyList-log--comment-id"
disabled={true}
fullWidth={true}
id="talk-comments-replyList-showAll--comment-id"
onClick={[Function]}
variant="outlined"
>
Show All Replies
</withPropsOnChange(Button)>
</Localized>
</withPropsOnChange(Flex)>
</Indent>
`;
exports[`when there is more renders a load more button 1`] = `
<Indent>
<Flex
<withPropsOnChange(Flex)
direction="column"
id="talk-comments-replyList-log--comment-id"
itemGutter={true}
@@ -60,13 +102,12 @@ exports[`when there is more renders a load more button 1`] = `
disabled={false}
fullWidth={true}
id="talk-comments-replyList-showAll--comment-id"
invert={true}
onClick={[Function]}
secondary={true}
variant="outlined"
>
Show All Replies
</withPropsOnChange(Button)>
</Localized>
</Flex>
</withPropsOnChange(Flex)>
</Indent>
`;
@@ -10,14 +10,14 @@ exports[`renders correctly 1`] = `
<withContext(createMutationContainer(PostCommentFormContainer))
assetID="asset-id"
/>
<Flex
<withPropsOnChange(Flex)
aria-live="polite"
direction="column"
id="talk-comments-stream-log"
itemGutter={true}
role="log"
>
<Flex
<withPropsOnChange(Flex)
direction="column"
itemGutter={true}
key="comment-1"
@@ -36,8 +36,8 @@ exports[`renders correctly 1`] = `
}
}
/>
</Flex>
<Flex
</withPropsOnChange(Flex)>
<withPropsOnChange(Flex)
direction="column"
itemGutter={true}
key="comment-2"
@@ -56,8 +56,8 @@ exports[`renders correctly 1`] = `
}
}
/>
</Flex>
</Flex>
</withPropsOnChange(Flex)>
</withPropsOnChange(Flex)>
</div>
`;
@@ -71,14 +71,14 @@ exports[`when there is more disables load more button 1`] = `
<withContext(createMutationContainer(PostCommentFormContainer))
assetID="asset-id"
/>
<Flex
<withPropsOnChange(Flex)
aria-live="polite"
direction="column"
id="talk-comments-stream-log"
itemGutter={true}
role="log"
>
<Flex
<withPropsOnChange(Flex)
direction="column"
itemGutter={true}
key="comment-1"
@@ -97,8 +97,8 @@ exports[`when there is more disables load more button 1`] = `
}
}
/>
</Flex>
<Flex
</withPropsOnChange(Flex)>
<withPropsOnChange(Flex)
direction="column"
itemGutter={true}
key="comment-2"
@@ -117,7 +117,7 @@ exports[`when there is more disables load more button 1`] = `
}
}
/>
</Flex>
</withPropsOnChange(Flex)>
<Localized
id="comments-stream-loadMore"
>
@@ -126,14 +126,13 @@ exports[`when there is more disables load more button 1`] = `
disabled={true}
fullWidth={true}
id="talk-comments-stream-loadMore"
invert={true}
onClick={[Function]}
secondary={true}
variant="outlined"
>
Load More
</withPropsOnChange(Button)>
</Localized>
</Flex>
</withPropsOnChange(Flex)>
</div>
`;
@@ -147,14 +146,14 @@ exports[`when there is more renders a load more button 1`] = `
<withContext(createMutationContainer(PostCommentFormContainer))
assetID="asset-id"
/>
<Flex
<withPropsOnChange(Flex)
aria-live="polite"
direction="column"
id="talk-comments-stream-log"
itemGutter={true}
role="log"
>
<Flex
<withPropsOnChange(Flex)
direction="column"
itemGutter={true}
key="comment-1"
@@ -173,8 +172,8 @@ exports[`when there is more renders a load more button 1`] = `
}
}
/>
</Flex>
<Flex
</withPropsOnChange(Flex)>
<withPropsOnChange(Flex)
direction="column"
itemGutter={true}
key="comment-2"
@@ -193,7 +192,7 @@ exports[`when there is more renders a load more button 1`] = `
}
}
/>
</Flex>
</withPropsOnChange(Flex)>
<Localized
id="comments-stream-loadMore"
>
@@ -202,13 +201,12 @@ exports[`when there is more renders a load more button 1`] = `
disabled={false}
fullWidth={true}
id="talk-comments-stream-loadMore"
invert={true}
onClick={[Function]}
secondary={true}
variant="outlined"
>
Load More
</withPropsOnChange(Button)>
</Localized>
</Flex>
</withPropsOnChange(Flex)>
</div>
`;
@@ -2,13 +2,13 @@
exports[`loads more comments 1`] = `
<div
className="Flex-root App-root Flex-justifyCenter"
className="Flex-root App-root Flex-justifyCenter Flex-alignCenter"
>
<div
className="Stream-root"
>
<h1
className="Typography-root Typography-heading1 Typography-gutterBottom"
className="Typography-root Typography-heading1 Typography-colorTextPrimary Typography-gutterBottom"
>
Talk NEO
</h1>
@@ -28,11 +28,14 @@ exports[`loads more comments 1`] = `
className="PostCommentForm-postButtonContainer"
>
<button
className="BaseButton-root Button-root Button-primary"
className="BaseButton-root Button-root Button-sizeRegular Button-colorPrimary Button-variantFilled"
disabled={false}
onBlur={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
>
Post
</button>
@@ -40,12 +43,12 @@ exports[`loads more comments 1`] = `
</form>
<div
aria-live="polite"
className="Flex-root Flex-itemGutter Flex-directionColumn"
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
id="talk-comments-stream-log"
role="log"
>
<div
className="Flex-root Flex-itemGutter Flex-directionColumn"
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
>
<div
role="article"
@@ -54,7 +57,7 @@ exports[`loads more comments 1`] = `
className="Flex-root TopBar-root Flex-halfItemGutter Flex-alignBaseline Flex-directionColumn"
>
<span
className="Typography-root Typography-heading3 Username-root"
className="Typography-root Typography-heading3 Typography-colorTextPrimary Username-root"
>
Markus
</span>
@@ -67,14 +70,14 @@ exports[`loads more comments 1`] = `
</time>
</div>
<p
className="Typography-root Typography-body1"
className="Typography-root Typography-bodyCopy Typography-colorTextPrimary"
>
Joining Too
</p>
</div>
</div>
<div
className="Flex-root Flex-itemGutter Flex-directionColumn"
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
>
<div
role="article"
@@ -83,7 +86,7 @@ exports[`loads more comments 1`] = `
className="Flex-root TopBar-root Flex-halfItemGutter Flex-alignBaseline Flex-directionColumn"
>
<span
className="Typography-root Typography-heading3 Username-root"
className="Typography-root Typography-heading3 Typography-colorTextPrimary Username-root"
>
Lukas
</span>
@@ -96,14 +99,14 @@ exports[`loads more comments 1`] = `
</time>
</div>
<p
className="Typography-root Typography-body1"
className="Typography-root Typography-bodyCopy Typography-colorTextPrimary"
>
What's up?
</p>
</div>
</div>
<div
className="Flex-root Flex-itemGutter Flex-directionColumn"
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
>
<div
role="article"
@@ -112,7 +115,7 @@ exports[`loads more comments 1`] = `
className="Flex-root TopBar-root Flex-halfItemGutter Flex-alignBaseline Flex-directionColumn"
>
<span
className="Typography-root Typography-heading3 Username-root"
className="Typography-root Typography-heading3 Typography-colorTextPrimary Username-root"
>
Isabelle
</span>
@@ -125,7 +128,7 @@ exports[`loads more comments 1`] = `
</time>
</div>
<p
className="Typography-root Typography-body1"
className="Typography-root Typography-bodyCopy Typography-colorTextPrimary"
>
Hey!
</p>
@@ -138,13 +141,13 @@ exports[`loads more comments 1`] = `
exports[`renders comment stream 1`] = `
<div
className="Flex-root App-root Flex-justifyCenter"
className="Flex-root App-root Flex-justifyCenter Flex-alignCenter"
>
<div
className="Stream-root"
>
<h1
className="Typography-root Typography-heading1 Typography-gutterBottom"
className="Typography-root Typography-heading1 Typography-colorTextPrimary Typography-gutterBottom"
>
Talk NEO
</h1>
@@ -164,11 +167,14 @@ exports[`renders comment stream 1`] = `
className="PostCommentForm-postButtonContainer"
>
<button
className="BaseButton-root Button-root Button-primary"
className="BaseButton-root Button-root Button-sizeRegular Button-colorPrimary Button-variantFilled"
disabled={false}
onBlur={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
>
Post
</button>
@@ -176,12 +182,12 @@ exports[`renders comment stream 1`] = `
</form>
<div
aria-live="polite"
className="Flex-root Flex-itemGutter Flex-directionColumn"
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
id="talk-comments-stream-log"
role="log"
>
<div
className="Flex-root Flex-itemGutter Flex-directionColumn"
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
>
<div
role="article"
@@ -190,7 +196,7 @@ exports[`renders comment stream 1`] = `
className="Flex-root TopBar-root Flex-halfItemGutter Flex-alignBaseline Flex-directionColumn"
>
<span
className="Typography-root Typography-heading3 Username-root"
className="Typography-root Typography-heading3 Typography-colorTextPrimary Username-root"
>
Markus
</span>
@@ -203,14 +209,14 @@ exports[`renders comment stream 1`] = `
</time>
</div>
<p
className="Typography-root Typography-body1"
className="Typography-root Typography-bodyCopy Typography-colorTextPrimary"
>
Joining Too
</p>
</div>
</div>
<div
className="Flex-root Flex-itemGutter Flex-directionColumn"
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
>
<div
role="article"
@@ -219,7 +225,7 @@ exports[`renders comment stream 1`] = `
className="Flex-root TopBar-root Flex-halfItemGutter Flex-alignBaseline Flex-directionColumn"
>
<span
className="Typography-root Typography-heading3 Username-root"
className="Typography-root Typography-heading3 Typography-colorTextPrimary Username-root"
>
Lukas
</span>
@@ -232,7 +238,7 @@ exports[`renders comment stream 1`] = `
</time>
</div>
<p
className="Typography-root Typography-body1"
className="Typography-root Typography-bodyCopy Typography-colorTextPrimary"
>
What's up?
</p>
@@ -240,13 +246,16 @@ exports[`renders comment stream 1`] = `
</div>
<button
aria-controls="talk-comments-stream-log"
className="BaseButton-root Button-root Button-invert Button-fullWidth Button-secondary"
className="BaseButton-root Button-root Button-sizeRegular Button-colorRegular Button-variantOutlined Button-fullWidth"
disabled={false}
id="talk-comments-stream-loadMore"
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
>
Load More
</button>
@@ -2,13 +2,13 @@
exports[`renders comment stream 1`] = `
<div
className="Flex-root App-root Flex-justifyCenter"
className="Flex-root App-root Flex-justifyCenter Flex-alignCenter"
>
<div
className="Stream-root"
>
<h1
className="Typography-root Typography-heading1 Typography-gutterBottom"
className="Typography-root Typography-heading1 Typography-colorTextPrimary Typography-gutterBottom"
>
Talk NEO
</h1>
@@ -28,11 +28,14 @@ exports[`renders comment stream 1`] = `
className="PostCommentForm-postButtonContainer"
>
<button
className="BaseButton-root Button-root Button-primary"
className="BaseButton-root Button-root Button-sizeRegular Button-colorPrimary Button-variantFilled"
disabled={false}
onBlur={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
>
Post
</button>
@@ -40,12 +43,12 @@ exports[`renders comment stream 1`] = `
</form>
<div
aria-live="polite"
className="Flex-root Flex-itemGutter Flex-directionColumn"
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
id="talk-comments-stream-log"
role="log"
>
<div
className="Flex-root Flex-itemGutter Flex-directionColumn"
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
>
<div
role="article"
@@ -54,7 +57,7 @@ exports[`renders comment stream 1`] = `
className="Flex-root TopBar-root Flex-halfItemGutter Flex-alignBaseline Flex-directionColumn"
>
<span
className="Typography-root Typography-heading3 Username-root"
className="Typography-root Typography-heading3 Typography-colorTextPrimary Username-root"
>
Markus
</span>
@@ -67,14 +70,14 @@ exports[`renders comment stream 1`] = `
</time>
</div>
<p
className="Typography-root Typography-body1"
className="Typography-root Typography-bodyCopy Typography-colorTextPrimary"
>
Joining Too
</p>
</div>
</div>
<div
className="Flex-root Flex-itemGutter Flex-directionColumn"
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
>
<div
role="article"
@@ -83,7 +86,7 @@ exports[`renders comment stream 1`] = `
className="Flex-root TopBar-root Flex-halfItemGutter Flex-alignBaseline Flex-directionColumn"
>
<span
className="Typography-root Typography-heading3 Username-root"
className="Typography-root Typography-heading3 Typography-colorTextPrimary Username-root"
>
Markus
</span>
@@ -96,7 +99,7 @@ exports[`renders comment stream 1`] = `
</time>
</div>
<p
className="Typography-root Typography-body1"
className="Typography-root Typography-bodyCopy Typography-colorTextPrimary"
>
I like yoghurt
</p>
@@ -105,7 +108,7 @@ exports[`renders comment stream 1`] = `
className="Indent-root Indent-level0"
>
<div
className="Flex-root Flex-itemGutter Flex-directionColumn"
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
id="talk-comments-replyList-log--comment-with-replies"
role="log"
>
@@ -116,7 +119,7 @@ exports[`renders comment stream 1`] = `
className="Flex-root TopBar-root Flex-halfItemGutter Flex-alignBaseline Flex-directionColumn"
>
<span
className="Typography-root Typography-heading3 Username-root"
className="Typography-root Typography-heading3 Typography-colorTextPrimary Username-root"
>
Markus
</span>
@@ -129,7 +132,7 @@ exports[`renders comment stream 1`] = `
</time>
</div>
<p
className="Typography-root Typography-body1"
className="Typography-root Typography-bodyCopy Typography-colorTextPrimary"
>
Joining Too
</p>
@@ -141,7 +144,7 @@ exports[`renders comment stream 1`] = `
className="Flex-root TopBar-root Flex-halfItemGutter Flex-alignBaseline Flex-directionColumn"
>
<span
className="Typography-root Typography-heading3 Username-root"
className="Typography-root Typography-heading3 Typography-colorTextPrimary Username-root"
>
Lukas
</span>
@@ -154,7 +157,7 @@ exports[`renders comment stream 1`] = `
</time>
</div>
<p
className="Typography-root Typography-body1"
className="Typography-root Typography-bodyCopy Typography-colorTextPrimary"
>
What's up?
</p>
@@ -2,13 +2,13 @@
exports[`renders comment stream 1`] = `
<div
className="Flex-root App-root Flex-justifyCenter"
className="Flex-root App-root Flex-justifyCenter Flex-alignCenter"
>
<div
className="Stream-root"
>
<h1
className="Typography-root Typography-heading1 Typography-gutterBottom"
className="Typography-root Typography-heading1 Typography-colorTextPrimary Typography-gutterBottom"
>
Talk NEO
</h1>
@@ -28,11 +28,14 @@ exports[`renders comment stream 1`] = `
className="PostCommentForm-postButtonContainer"
>
<button
className="BaseButton-root Button-root Button-primary"
className="BaseButton-root Button-root Button-sizeRegular Button-colorPrimary Button-variantFilled"
disabled={false}
onBlur={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
>
Post
</button>
@@ -40,12 +43,12 @@ exports[`renders comment stream 1`] = `
</form>
<div
aria-live="polite"
className="Flex-root Flex-itemGutter Flex-directionColumn"
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
id="talk-comments-stream-log"
role="log"
>
<div
className="Flex-root Flex-itemGutter Flex-directionColumn"
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
>
<div
role="article"
@@ -54,7 +57,7 @@ exports[`renders comment stream 1`] = `
className="Flex-root TopBar-root Flex-halfItemGutter Flex-alignBaseline Flex-directionColumn"
>
<span
className="Typography-root Typography-heading3 Username-root"
className="Typography-root Typography-heading3 Typography-colorTextPrimary Username-root"
>
Markus
</span>
@@ -67,14 +70,14 @@ exports[`renders comment stream 1`] = `
</time>
</div>
<p
className="Typography-root Typography-body1"
className="Typography-root Typography-bodyCopy Typography-colorTextPrimary"
>
Joining Too
</p>
</div>
</div>
<div
className="Flex-root Flex-itemGutter Flex-directionColumn"
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
>
<div
role="article"
@@ -83,7 +86,7 @@ exports[`renders comment stream 1`] = `
className="Flex-root TopBar-root Flex-halfItemGutter Flex-alignBaseline Flex-directionColumn"
>
<span
className="Typography-root Typography-heading3 Username-root"
className="Typography-root Typography-heading3 Typography-colorTextPrimary Username-root"
>
Lukas
</span>
@@ -96,7 +99,7 @@ exports[`renders comment stream 1`] = `
</time>
</div>
<p
className="Typography-root Typography-body1"
className="Typography-root Typography-bodyCopy Typography-colorTextPrimary"
>
What's up?
</p>
@@ -2,13 +2,13 @@
exports[`renders comment stream 1`] = `
<div
className="Flex-root App-root Flex-justifyCenter"
className="Flex-root App-root Flex-justifyCenter Flex-alignCenter"
>
<div
className="Stream-root"
>
<h1
className="Typography-root Typography-heading1 Typography-gutterBottom"
className="Typography-root Typography-heading1 Typography-colorTextPrimary Typography-gutterBottom"
>
Talk NEO
</h1>
@@ -28,11 +28,14 @@ exports[`renders comment stream 1`] = `
className="PostCommentForm-postButtonContainer"
>
<button
className="BaseButton-root Button-root Button-primary"
className="BaseButton-root Button-root Button-sizeRegular Button-colorPrimary Button-variantFilled"
disabled={false}
onBlur={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
>
Post
</button>
@@ -40,12 +43,12 @@ exports[`renders comment stream 1`] = `
</form>
<div
aria-live="polite"
className="Flex-root Flex-itemGutter Flex-directionColumn"
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
id="talk-comments-stream-log"
role="log"
>
<div
className="Flex-root Flex-itemGutter Flex-directionColumn"
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
>
<div
role="article"
@@ -54,7 +57,7 @@ exports[`renders comment stream 1`] = `
className="Flex-root TopBar-root Flex-halfItemGutter Flex-alignBaseline Flex-directionColumn"
>
<span
className="Typography-root Typography-heading3 Username-root"
className="Typography-root Typography-heading3 Typography-colorTextPrimary Username-root"
>
Markus
</span>
@@ -67,7 +70,7 @@ exports[`renders comment stream 1`] = `
</time>
</div>
<p
className="Typography-root Typography-body1"
className="Typography-root Typography-bodyCopy Typography-colorTextPrimary"
>
Joining Too
</p>
@@ -76,7 +79,7 @@ exports[`renders comment stream 1`] = `
className="Indent-root Indent-level0"
>
<div
className="Flex-root Flex-itemGutter Flex-directionColumn"
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
id="talk-comments-replyList-log--comment-0"
role="log"
>
@@ -87,7 +90,7 @@ exports[`renders comment stream 1`] = `
className="Flex-root TopBar-root Flex-halfItemGutter Flex-alignBaseline Flex-directionColumn"
>
<span
className="Typography-root Typography-heading3 Username-root"
className="Typography-root Typography-heading3 Typography-colorTextPrimary Username-root"
>
Lukas
</span>
@@ -100,20 +103,23 @@ exports[`renders comment stream 1`] = `
</time>
</div>
<p
className="Typography-root Typography-body1"
className="Typography-root Typography-bodyCopy Typography-colorTextPrimary"
>
What's up?
</p>
</div>
<button
aria-controls="talk-comments-replyList-log--comment-0"
className="BaseButton-root Button-root Button-invert Button-fullWidth Button-secondary"
className="BaseButton-root Button-root Button-sizeRegular Button-colorRegular Button-variantOutlined Button-fullWidth"
disabled={false}
id="talk-comments-replyList-showAll--comment-0"
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
>
Show All Replies
</button>
@@ -127,13 +133,13 @@ exports[`renders comment stream 1`] = `
exports[`show all replies 1`] = `
<div
className="Flex-root App-root Flex-justifyCenter"
className="Flex-root App-root Flex-justifyCenter Flex-alignCenter"
>
<div
className="Stream-root"
>
<h1
className="Typography-root Typography-heading1 Typography-gutterBottom"
className="Typography-root Typography-heading1 Typography-colorTextPrimary Typography-gutterBottom"
>
Talk NEO
</h1>
@@ -153,11 +159,14 @@ exports[`show all replies 1`] = `
className="PostCommentForm-postButtonContainer"
>
<button
className="BaseButton-root Button-root Button-primary"
className="BaseButton-root Button-root Button-sizeRegular Button-colorPrimary Button-variantFilled"
disabled={false}
onBlur={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
>
Post
</button>
@@ -165,12 +174,12 @@ exports[`show all replies 1`] = `
</form>
<div
aria-live="polite"
className="Flex-root Flex-itemGutter Flex-directionColumn"
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
id="talk-comments-stream-log"
role="log"
>
<div
className="Flex-root Flex-itemGutter Flex-directionColumn"
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
>
<div
role="article"
@@ -179,7 +188,7 @@ exports[`show all replies 1`] = `
className="Flex-root TopBar-root Flex-halfItemGutter Flex-alignBaseline Flex-directionColumn"
>
<span
className="Typography-root Typography-heading3 Username-root"
className="Typography-root Typography-heading3 Typography-colorTextPrimary Username-root"
>
Markus
</span>
@@ -192,7 +201,7 @@ exports[`show all replies 1`] = `
</time>
</div>
<p
className="Typography-root Typography-body1"
className="Typography-root Typography-bodyCopy Typography-colorTextPrimary"
>
Joining Too
</p>
@@ -201,7 +210,7 @@ exports[`show all replies 1`] = `
className="Indent-root Indent-level0"
>
<div
className="Flex-root Flex-itemGutter Flex-directionColumn"
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
id="talk-comments-replyList-log--comment-0"
role="log"
>
@@ -212,7 +221,7 @@ exports[`show all replies 1`] = `
className="Flex-root TopBar-root Flex-halfItemGutter Flex-alignBaseline Flex-directionColumn"
>
<span
className="Typography-root Typography-heading3 Username-root"
className="Typography-root Typography-heading3 Typography-colorTextPrimary Username-root"
>
Lukas
</span>
@@ -225,7 +234,7 @@ exports[`show all replies 1`] = `
</time>
</div>
<p
className="Typography-root Typography-body1"
className="Typography-root Typography-bodyCopy Typography-colorTextPrimary"
>
What's up?
</p>
@@ -237,7 +246,7 @@ exports[`show all replies 1`] = `
className="Flex-root TopBar-root Flex-halfItemGutter Flex-alignBaseline Flex-directionColumn"
>
<span
className="Typography-root Typography-heading3 Username-root"
className="Typography-root Typography-heading3 Typography-colorTextPrimary Username-root"
>
Isabelle
</span>
@@ -250,7 +259,7 @@ exports[`show all replies 1`] = `
</time>
</div>
<p
className="Typography-root Typography-body1"
className="Typography-root Typography-bodyCopy Typography-colorTextPrimary"
>
Hey!
</p>
@@ -0,0 +1,17 @@
---
name: AriaInfo
menu: UI Kit
---
import { Playground, PropsTable } from 'docz'
import AriaInfo from './AriaInfo'
# AriaInfo
Renders Text that is only seen by screen readers.
## Basic usage
<Playground>
<AriaInfo>This can only be seen by screen readers</AriaInfo>
<div>Above this line is a hidden text that you can't see</div>
</Playground>
@@ -0,0 +1,10 @@
.root {
position: absolute !important;
width: 1px;
height: 1px;
padding: 0;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
@@ -0,0 +1,14 @@
import React from "react";
import TestRenderer from "react-test-renderer";
import { PropTypesOf } from "talk-framework/types";
import AriaInfo from "./AriaInfo";
it("renders correctly", () => {
const props: PropTypesOf<typeof AriaInfo> = {
children: "This text is only for screen readers",
};
const renderer = TestRenderer.create(<AriaInfo {...props} />);
expect(renderer.toJSON()).toMatchSnapshot();
});
@@ -0,0 +1,32 @@
import cn from "classnames";
import React, { HTMLAttributes, StatelessComponent } from "react";
import { withForwardRef, withStyles } from "talk-ui/hocs";
import { PropTypesOf } from "talk-ui/types";
import * as styles from "./AriaInfo.css";
interface InnerProps extends HTMLAttributes<HTMLElement> {
/**
* This prop can be used to add custom classnames.
* It is handled by the `withStyles `HOC.
*/
classes: typeof styles;
component?: string;
children: React.ReactNode;
}
const AriaInfo: StatelessComponent<InnerProps> = props => {
const { component, className, classes, ...rest } = props;
const Component = component!;
const rootClassName = cn(classes.root, className);
return <Component className={rootClassName} {...rest} />;
};
AriaInfo.defaultProps = {
component: "div",
};
const enhanced = withForwardRef(withStyles(styles)(AriaInfo));
export type AriaInfoProps = PropTypesOf<typeof enhanced>;
export default enhanced;
@@ -0,0 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<div
className="AriaInfo-root"
>
This text is only for screen readers
</div>
`;
@@ -0,0 +1 @@
export { default, AriaInfoProps } from "./AriaInfo";
@@ -8,3 +8,6 @@
outline-color: -webkit-focus-ring-color;
outline-style: auto;
}
.mouseHover {
}
@@ -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<typeof BaseButton> = {
className: "my-class",
children: "Push Me",
};
const renderer = TestRenderer.create(<BaseButton {...props} />);
expect(renderer.toJSON()).toMatchSnapshot();
});
it("renders as anchor", () => {
const props: PropTypesOf<typeof BaseButton> = {
anchor: true,
children: "Push Me",
};
const renderer = TestRenderer.create(<BaseButton {...props} />);
expect(renderer.toJSON()).toMatchSnapshot();
});
@@ -1,8 +1,13 @@
import cn from "classnames";
import React from "react";
import React, { Ref } from "react";
import { ButtonHTMLAttributes, StatelessComponent } from "react";
import { withKeyboardFocus, withStyles } from "talk-ui/hocs";
import {
withForwardRef,
withKeyboardFocus,
withMouseHover,
withStyles,
} from "talk-ui/hocs";
import { PropTypesOf } from "talk-ui/types";
import * as styles from "./BaseButton.css";
@@ -10,7 +15,6 @@ import * as styles from "./BaseButton.css";
interface InnerProps extends ButtonHTMLAttributes<HTMLButtonElement> {
/** If set renders an anchor tag instead */
anchor?: boolean;
/**
* This prop can be used to add custom classnames.
* It is handled by the `withStyles `HOC.
@@ -18,9 +22,13 @@ interface InnerProps extends ButtonHTMLAttributes<HTMLButtonElement> {
classes: typeof styles;
/** This is passed by the `withKeyboardFocus` HOC */
keyboardFocus: boolean;
keyboardFocus?: boolean;
innerRef?: React.RefObject<HTMLDivElement> | any;
/** This is passed by the `withMouseHover` HOC */
mouseHover?: boolean;
/** Internal: Forwarded Ref */
forwardRef?: Ref<HTMLButtonElement>;
}
/**
@@ -32,8 +40,9 @@ const BaseButton: StatelessComponent<InnerProps> = ({
className,
classes,
keyboardFocus,
mouseHover,
forwardRef,
type: typeProp,
innerRef,
...rest
}) => {
let Element = "button";
@@ -54,11 +63,14 @@ const BaseButton: StatelessComponent<InnerProps> = ({
const rootClassName = cn(classes.root, className, {
[classes.keyboardFocus]: keyboardFocus,
[classes.mouseHover]: mouseHover,
});
return <Element {...rest} className={rootClassName} ref={innerRef} />;
return <Element {...rest} className={rootClassName} ref={forwardRef} />;
};
const enhanced = withStyles(styles)(withKeyboardFocus(BaseButton));
const enhanced = withForwardRef(
withStyles(styles)(withMouseHover(withKeyboardFocus(BaseButton)))
);
export type BaseButtonProps = PropTypesOf<typeof enhanced>;
export default enhanced;
@@ -0,0 +1,29 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders as anchor 1`] = `
<a
className="BaseButton-root"
onBlur={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
>
Push Me
</a>
`;
exports[`renders correctly 1`] = `
<button
className="BaseButton-root my-class"
onBlur={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
>
Push Me
</button>
`;
@@ -1,2 +1 @@
export * from "./BaseButton";
export { default } from "./BaseButton";
export { default, BaseButtonProps } from "./BaseButton";
+248 -65
View File
@@ -1,99 +1,282 @@
.root {
composes: button from "talk-ui/shared/typography.css";
border-radius: var(--round-corners);
background-color: transparent;
position: relative;
display: inline-flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
border: 1px solid transparent;
&:enabled,
&:disabled {
padding: 5px 20px;
border-radius: var(--round-corners);
background-color: transparent;
/* TODO: hover styles for the default button */
& > * {
margin: 0 calc(0.5 * var(--spacing-unit)) 0 0;
/* convince safari */
align-self: center;
}
& > *:last-child {
margin: 0;
}
}
.root:disabled {
.root.disabled {
opacity: 0.4;
cursor: default;
}
.fullWidth:enabled,
.fullWidth:disabled {
.fullWidth {
display: block;
width: 100%;
box-sizing: border-box;
}
.primary:enabled,
.primary:disabled {
background-color: var(--palette-primary-main);
color: #fff;
.sizeSmall {
composes: button from "talk-ui/shared/typography.css";
padding: 4px 10px;
}
.primary:enabled {
&:hover {
background-color: var(--palette-primary-light);
.sizeRegular {
composes: button from "talk-ui/shared/typography.css";
padding: 8px 15px;
}
.sizeLarge {
composes: buttonLarge from "talk-ui/shared/typography.css";
padding: 10px 15px;
}
.variantRegular {
&.colorRegular {
color: var(--palette-grey-main);
}
&.colorPrimary {
color: var(--palette-primary-main);
}
&.colorError {
color: var(--palette-error-main);
}
&.colorSuccess {
color: var(--palette-success-main);
}
&:active {
background-color: var(--palette-primary-lighter);
&:not(.disabled) {
&.colorRegular {
&.mouseHover {
color: var(--palette-grey-light);
}
&:active,
&.active {
color: var(--palette-grey-lighter);
}
}
&.colorPrimary {
&.mouseHover {
color: var(--palette-primary-light);
}
&:active,
&.active {
color: var(--palette-primary-lighter);
}
}
&.colorError {
&.mouseHover {
color: var(--palette-error-light);
}
&:active,
&.active {
color: var(--palette-error-lighter);
}
}
&.colorSuccess {
&.mouseHover {
color: var(--palette-success-light);
}
&:active,
&.active {
color: var(--palette-success-lighter);
}
}
}
}
.primary:enabled.invert,
.primary:disabled.invert {
background-color: transparent;
border: 1px solid var(--palette-primary-main);
color: var(--palette-primary-main);
}
.primary:enabled.invert {
&:hover {
border-color: var(--palette-primary-light);
color: var(--palette-primary-light);
.variantFilled {
color: var(--palette-common-white);
&.colorRegular {
background-color: var(--palette-grey-main);
}
&.colorPrimary {
background-color: var(--palette-primary-main);
}
&.colorError {
background-color: var(--palette-error-main);
}
&.colorSuccess {
background-color: var(--palette-success-main);
}
&:active {
border-color: var(--palette-primary-lighter);
color: var(--palette-primary-lighter);
&:not(.disabled) {
&.colorRegular {
&.mouseHover {
background-color: var(--palette-grey-light);
}
&:active,
&.active {
background-color: var(--palette-grey-lighter);
}
}
&.colorPrimary {
&.mouseHover {
background-color: var(--palette-primary-light);
}
&:active,
&.active {
background-color: var(--palette-primary-lighter);
}
}
&.colorError {
&.mouseHover {
background-color: var(--palette-error-light);
}
&:active,
&.active {
background-color: var(--palette-error-lighter);
}
}
&.colorSuccess {
&.mouseHover {
background-color: var(--palette-success-light);
}
&:active,
&.active {
background-color: var(--palette-success-lighter);
}
}
}
}
.secondary:enabled,
.secondary:disabled {
background-color: var(--palette-secondary-main);
color: #fff;
}
.secondary:enabled {
&:hover {
background-color: var(--palette-secondary-light);
.variantOutlined {
&.colorRegular {
color: var(--palette-grey-main);
border: 1px solid currentColor;
}
&:active {
background-color: var(--palette-secondary-lighter);
&.colorPrimary {
color: var(--palette-primary-main);
border: 1px solid currentColor;
}
&.colorError {
color: var(--palette-error-main);
border: 1px solid currentColor;
}
&.colorSuccess {
color: var(--palette-success-main);
border: 1px solid currentColor;
}
&:not(.disabled) {
&.colorRegular {
&.mouseHover {
color: var(--palette-grey-light);
border: 1px solid currentColor;
}
&:active,
&.active {
color: var(--palette-grey-lighter);
border: 1px solid currentColor;
}
}
&.colorPrimary {
&.mouseHover {
color: var(--palette-primary-light);
border: 1px solid currentColor;
}
&:active,
&.active {
color: var(--palette-primary-lighter);
border: 1px solid currentColor;
}
}
&.colorError {
&.mouseHover {
color: var(--palette-error-light);
border: 1px solid currentColor;
}
&:active,
&.active {
color: var(--palette-error-lighter);
border: 1px solid currentColor;
}
}
&.colorSuccess {
&.mouseHover {
color: var(--palette-success-light);
border: 1px solid currentColor;
}
&:active,
&.active {
color: var(--palette-success-lighter);
border: 1px solid currentColor;
}
}
}
}
.secondary:enabled.invert,
.secondary:disabled.invert {
background-color: transparent;
border: 1px solid var(--palette-secondary-main);
color: var(--palette-secondary-main);
}
.secondary:enabled.invert {
&:hover {
border-color: var(--palette-secondary-light);
color: var(--palette-secondary-light);
.variantGhost {
&.colorRegular {
color: var(--palette-grey-main);
}
&.colorPrimary {
color: var(--palette-primary-main);
}
&.colorError {
color: var(--palette-error-main);
}
&.colorSuccess {
color: var(--palette-success-main);
}
&:active {
border-color: var(--palette-secondary-lighter);
color: var(--palette-secondary-lighter);
&:not(.disabled) {
&.colorRegular {
&.mouseHover {
border: 1px solid currentColor;
}
&:active,
&.active {
border: 1px solid currentColor;
color: var(--palette-common-white);
background-color: var(--palette-grey-main);
}
}
&.colorPrimary {
&.mouseHover {
border: 1px solid currentColor;
}
&:active,
&.active {
border: 1px solid currentColor;
color: var(--palette-common-white);
background-color: var(--palette-primary-main);
}
}
&.colorError {
&.mouseHover {
border: 1px solid currentColor;
}
&:active,
&.active {
border: 1px solid currentColor;
color: var(--palette-common-white);
background-color: var(--palette-error-main);
}
}
&.colorSuccess {
&.mouseHover {
border: 1px solid currentColor;
}
&:active,
&.active {
border: 1px solid currentColor;
color: var(--palette-common-white);
background-color: var(--palette-success-main);
}
}
}
}
/**
* This seems to be the best way to target modern touch device browsers.
*/
@media (-moz-touch-enabled: 1), (pointer: coarse) {
/* TODO: Remove hover styles */
}
+63 -14
View File
@@ -5,23 +5,72 @@ menu: UI Kit
import { Playground } from 'docz'
import Button from './Button'
import ButtonIcon from './ButtonIcon'
import Icon from '../Icon'
import Flex from '../Flex'
# Button
## Basic usage
## Regular Button
<Playground>
<Button style={{margin: "0 10px 10px 0"}}>Push Me</Button>
<Button style={{margin: "0 10px 10px 0"}} disabled>Push Me</Button>
<Button style={{margin: "0 10px 10px 0"}} anchor>I'm an Anchor Tag</Button>
<Button style={{margin: "0 10px 10px 0"}} primary>Primary</Button>
<Button style={{margin: "0 10px 10px 0"}} primary disabled>Primary</Button>
<Button style={{margin: "0 10px 10px 0"}} secondary>Secondary</Button>
<Button style={{margin: "0 10px 10px 0"}} secondary disabled>Secondary</Button>
<Button style={{margin: "0 10px 10px 0"}} primary invert>Primary</Button>
<Button style={{margin: "0 10px 10px 0"}} primary invert disabled>Primary</Button>
<Button style={{margin: "0 10px 10px 0"}} secondary invert>Secondary</Button>
<Button style={{margin: "0 10px 10px 0"}} secondary invert disabled>Secondary</Button>
<Button style={{marginBottom: "10px"}} primary fullWidth>Full Width</Button>
<Button style={{marginBottom: "10px"}} primary invert fullWidth>Full Width Invert</Button>
<Flex itemGutter wrap>
<Button>Push Me</Button>
<Button size="small">Push Me</Button>
<Button size="large">Push Me</Button>
<Button color="primary">Push Me</Button>
<Button color="error">Push Me</Button>
<Button color="success">Push Me</Button>
<Button disabled>Push Me</Button>
<Button active>Push Me</Button>
<Button><ButtonIcon>face</ButtonIcon><span>Push Me</span></Button>
<Button fullWidth>Push Me</Button>
</Flex>
</Playground>
## Filled Button
<Playground>
<Flex itemGutter wrap>
<Button variant="filled">Push Me</Button>
<Button variant="filled" size="small">Push Me</Button>
<Button variant="filled" size="large">Push Me</Button>
<Button variant="filled" color="primary">Push Me</Button>
<Button variant="filled" color="error">Push Me</Button>
<Button variant="filled" color="success">Push Me</Button>
<Button variant="filled" disabled>Push Me</Button>
<Button variant="filled" active>Push Me</Button>
<Button variant="filled"><ButtonIcon>face</ButtonIcon><span>Push Me</span></Button>
<Button variant="filled" fullWidth>Push Me</Button>
</Flex>
</Playground>
## Outlined Button
<Playground>
<Flex itemGutter wrap>
<Button variant="outlined">Push Me</Button>
<Button variant="outlined" size="small">Push Me</Button>
<Button variant="outlined" size="large">Push Me</Button>
<Button variant="outlined" color="primary">Push Me</Button>
<Button variant="outlined" color="error">Push Me</Button>
<Button variant="outlined" color="success">Push Me</Button>
<Button variant="outlined" disabled>Push Me</Button>
<Button variant="outlined" active>Push Me</Button>
<Button variant="outlined"><ButtonIcon>face</ButtonIcon><span>Push Me</span></Button>
<Button variant="outlined" fullWidth>Push Me</Button>
</Flex>
</Playground>
## Ghost Button
<Playground>
<Flex itemGutter wrap>
<Button variant="ghost">Push Me</Button>
<Button variant="ghost" size="small">Push Me</Button>
<Button variant="ghost" size="large">Push Me</Button>
<Button variant="ghost" color="primary">Push Me</Button>
<Button variant="ghost" color="error">Push Me</Button>
<Button variant="ghost" color="success">Push Me</Button>
<Button variant="ghost" disabled>Push Me</Button>
<Button variant="ghost" active>Push Me</Button>
<Button variant="ghost"><ButtonIcon>face</ButtonIcon><span>Push Me</span></Button>
<Button variant="ghost" fullWidth>Push Me</Button>
</Flex>
</Playground>
@@ -0,0 +1,62 @@
import React from "react";
import ShallowRenderer from "react-test-renderer/shallow";
import { PropTypesOf } from "talk-framework/types";
import { Button } from "./Button";
it("renders correctly", () => {
const props: PropTypesOf<typeof Button> = {
classes: {
mouseHover: "mouseHover",
keyboardFocus: "keyboardFocus",
} as any,
children: "Push me",
};
const renderer = ShallowRenderer.createRenderer();
renderer.render(<Button {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
it("forwards ref", () => {
const props: PropTypesOf<typeof Button> = {
// tslint:disable-next-line:no-empty
forwardRef: () => {},
classes: {} as any,
children: "Push me",
};
const renderer = ShallowRenderer.createRenderer();
renderer.render(<Button {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
it("renders a regular sized, primary colored ghost button with fullWidth", () => {
const props: PropTypesOf<typeof Button> = {
color: "primary",
variant: "ghost",
fullWidth: true,
classes: {
colorPrimary: "colorPrimary",
variantGhost: "variantGhost",
sizeRegular: "sizeRegular",
fullWidth: "fullWidth",
} as any,
children: "Push me",
};
const renderer = ShallowRenderer.createRenderer();
renderer.render(<Button {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
it("renders active state", () => {
const props: PropTypesOf<typeof Button> = {
active: true,
classes: {
active: "active",
} as any,
children: "Push me",
};
const renderer = ShallowRenderer.createRenderer();
renderer.render(<Button {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
+45 -23
View File
@@ -1,8 +1,8 @@
import cn from "classnames";
import { pick } from "lodash";
import React, { ButtonHTMLAttributes } from "react";
import React, { ButtonHTMLAttributes, Ref } from "react";
import { withStyles } from "talk-ui/hocs";
import { withForwardRef, withStyles } from "talk-ui/hocs";
import { PropTypesOf } from "talk-ui/types";
import BaseButton, { BaseButtonProps } from "../BaseButton";
@@ -15,54 +15,76 @@ interface InnerProps extends ButtonHTMLAttributes<HTMLButtonElement> {
* This prop can be used to add custom classnames.
* It is handled by the `withStyles `HOC.
*/
classes: typeof styles & Partial<BaseButtonProps["classes"]>;
classes: typeof styles & BaseButtonProps["classes"];
/** Size of the button */
size?: "small" | "regular" | "large";
/** Color of the button */
color?: "regular" | "primary" | "error" | "success";
/** Variant of the button */
variant?: "regular" | "filled" | "outlined" | "ghost";
/** If set renders a full width button */
fullWidth?: boolean;
/** If set renders a button with inverted borders */
invert?: boolean;
/** If set renders active state e.g. to implement toggle buttons */
active?: boolean;
/** If set renders a button with primary colors */
primary?: boolean;
/** If set renders a button with secondary colors */
secondary?: boolean;
innerRef?: React.RefObject<HTMLDivElement> | any;
/** Internal: Forwarded Ref */
forwardRef?: Ref<HTMLButtonElement>;
}
class Button extends React.Component<InnerProps> {
export class Button extends React.Component<InnerProps> {
public static defaultProps: Partial<InnerProps> = {
size: "regular",
variant: "regular",
color: "regular",
};
public render() {
const {
active,
classes,
color,
className,
size,
fullWidth,
invert,
primary,
secondary,
innerRef,
disabled,
forwardRef,
variant,
...rest
} = this.props;
const rootClassName = cn(classes.root, className, {
[classes.invert]: invert,
[classes.sizeRegular]: size === "regular",
[classes.sizeSmall]: size === "small",
[classes.sizeLarge]: size === "large",
[classes.colorRegular]: color === "regular",
[classes.colorPrimary]: color === "primary",
[classes.colorError]: color === "error",
[classes.colorSuccess]: color === "success",
[classes.variantRegular]: variant === "regular",
[classes.variantFilled]: variant === "filled",
[classes.variantOutlined]: variant === "outlined",
[classes.variantGhost]: variant === "ghost",
[classes.fullWidth]: fullWidth,
[classes.primary]: primary,
[classes.secondary]: secondary,
[classes.active]: active,
[classes.disabled]: disabled,
});
return (
<BaseButton
className={rootClassName}
classes={pick(classes, "keyboardFocus")}
innerRef={innerRef}
classes={pick(classes, "keyboardFocus", "mouseHover")}
disabled={disabled}
forwardRef={forwardRef}
{...rest}
/>
);
}
}
const enhanced = withStyles(styles)(Button);
const enhanced = withForwardRef(withStyles(styles)(Button));
export type ButtonProps = PropTypesOf<typeof enhanced>;
export default enhanced;
@@ -0,0 +1,8 @@
.root {
&:first-child {
margin-left: -4px;
}
&:last-child {
margin-right: -4px;
}
}
@@ -0,0 +1,30 @@
import React from "react";
import ShallowRenderer from "react-test-renderer/shallow";
import { PropTypesOf } from "talk-framework/types";
import { ButtonIcon } from "./ButtonIcon";
it("renders correctly", () => {
const props: PropTypesOf<typeof ButtonIcon> = {
classes: {
root: "root",
} as any,
children: "Push me",
};
const renderer = ShallowRenderer.createRenderer();
renderer.render(<ButtonIcon {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
it("forwards ref", () => {
const props: PropTypesOf<typeof ButtonIcon> = {
// tslint:disable-next-line:no-empty
forwardRef: () => {},
classes: {} as any,
children: "Push me",
};
const renderer = ShallowRenderer.createRenderer();
renderer.render(<ButtonIcon {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -0,0 +1,38 @@
import cn from "classnames";
import React, { HTMLAttributes, Ref, StatelessComponent } from "react";
import Icon, { IconProps } from "talk-ui/components/Icon";
import { withForwardRef, withStyles } from "talk-ui/hocs";
import { PropTypesOf } from "talk-ui/types";
import * as styles from "./ButtonIcon.css";
interface InnerProps extends HTMLAttributes<HTMLSpanElement> {
/**
* This prop can be used to add custom classnames.
* It is handled by the `withStyles `HOC.
*/
classes: typeof styles & IconProps["classes"];
size?: IconProps["size"];
/** The name of the icon to render */
children: string;
/** Internal: Forwarded Ref */
forwardRef?: Ref<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} />;
};
ButtonIcon.defaultProps = {
size: "sm",
};
const enhanced = withForwardRef(withStyles(styles)(ButtonIcon));
export type ButtonIconProps = PropTypesOf<typeof enhanced>;
export default enhanced;
@@ -0,0 +1,43 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`forwards ref 1`] = `
<withPropsOnChange(WithMouseHover)
className=""
classes={Object {}}
forwardRef={[Function]}
>
Push me
</withPropsOnChange(WithMouseHover)>
`;
exports[`renders a regular sized, primary colored ghost button with fullWidth 1`] = `
<withPropsOnChange(WithMouseHover)
className="sizeRegular colorPrimary variantGhost fullWidth"
classes={Object {}}
>
Push me
</withPropsOnChange(WithMouseHover)>
`;
exports[`renders active state 1`] = `
<withPropsOnChange(WithMouseHover)
className="active"
classes={Object {}}
>
Push me
</withPropsOnChange(WithMouseHover)>
`;
exports[`renders correctly 1`] = `
<withPropsOnChange(WithMouseHover)
className=""
classes={
Object {
"keyboardFocus": "keyboardFocus",
"mouseHover": "mouseHover",
}
}
>
Push me
</withPropsOnChange(WithMouseHover)>
`;
@@ -0,0 +1,20 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`forwards ref 1`] = `
<withPropsOnChange(Icon)
className=""
forwardRef={[Function]}
size="sm"
>
Push me
</withPropsOnChange(Icon)>
`;
exports[`renders correctly 1`] = `
<withPropsOnChange(Icon)
className="root"
size="sm"
>
Push me
</withPropsOnChange(Icon)>
`;
@@ -1,2 +1,2 @@
export * from "./Button";
export { default } from "./Button";
export { default, default as Button, ButtonProps } from "./Button";
export { default as ButtonIcon, ButtonIconProps } from "./ButtonIcon";
+58 -10
View File
@@ -1,52 +1,100 @@
.root {
display: flex;
& > * {
flex-shrink: 0;
}
}
.halfItemGutter {
& > * {
margin: 0 calc(0.5 * var(--spacing-unit)) 0 0;
margin: 0 calc(0.5 * var(--spacing-unit)) 0 0 !important;
}
&.directionRowReverse {
& > * {
margin: 0 0 0 calc(0.5 * var(--spacing-unit));
margin: 0 0 0 calc(0.5 * var(--spacing-unit)) !important;
}
}
&.directionColumn {
& > * {
margin: 0 0 calc(0.5 * var(--spacing-unit)) 0;
margin: 0 0 calc(0.5 * var(--spacing-unit)) 0 !important;
}
}
&.directionColumnReverese {
& > * {
margin: calc(0.5 * var(--spacing-unit)) 0 0 0;
margin: calc(0.5 * var(--spacing-unit)) 0 0 0 !important;
}
}
& > *:last-child {
margin: 0;
margin: 0 !important;
}
}
.itemGutter {
& > * {
margin: 0 var(--spacing-unit) 0 0;
margin: 0 var(--spacing-unit) 0 0 !important;
}
&.directionRowReverse {
& > * {
margin: 0 0 0 var(--spacing-unit);
margin: 0 0 0 var(--spacing-unit) !important;
}
}
&.directionColumn {
& > * {
margin: 0 0 var(--spacing-unit) 0;
margin: 0 0 var(--spacing-unit) 0 !important;
}
}
&.directionColumnReverese {
& > * {
margin: var(--spacing-unit) 0 0 0;
margin: var(--spacing-unit) 0 0 0 !important;
}
}
& > *:last-child {
margin: 0;
margin: 0 !important;
}
}
.wrap {
flex-wrap: wrap;
}
.wrapReverse {
flex-wrap: wrap-reverse;
}
.wrap,
.wrapReverse {
&.itemGutter {
&:not(:empty) {
margin-top: calc(-1 * var(--spacing-unit)) !important;
}
& > * {
margin-top: var(--spacing-unit) !important;
}
}
&.directionColumn.itemGutter {
&:not(:empty) {
margin-left: calc(-1 * var(--spacing-unit)) !important;
}
&.itemGutter > * {
margin-left: var(--spacing-unit) !important;
}
}
&.halfItemGutter {
&:not(:empty) {
margin-top: calc(-0.5 * var(--spacing-unit)) !important;
}
& > * {
margin-top: calc(0.5 * var(--spacing-unit)) !important;
}
}
&.directionColumn.halfItemGutter {
&:not(:empty) {
margin-left: calc(-0.5 * var(--spacing-unit)) !important;
}
&.halfItemGutter > * {
margin-left: calc(0.5 * var(--spacing-unit)) !important;
}
}
}
+20 -1
View File
@@ -5,12 +5,31 @@ menu: UI Kit
import { Playground, PropsTable } from 'docz'
import Flex from './Flex'
import Button from '../Button'
# Flex
`Flex` is a wrapper around `flexbox`.
## Basic usage
## Justify content
<Playground>
<Flex justifyContent="center">I'm centered</Flex>
</Playground>
## Align items
<Playground>
<Flex alignItems="center" itemGutter>
<Button variant="filled">Push Me</Button>
<Button variant="filled" size="small">Push Me</Button>
<Button variant="filled" size="large">Push Me</Button>
</Flex>
</Playground>
## Direction
<Playground>
<Flex direction="column" itemGutter>
<Button variant="filled">Push Me</Button>
<Button variant="filled">Push Me</Button>
<Button variant="filled">Push Me</Button>
</Flex>
</Playground>
@@ -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(
<Flex {...props}>
<div>Hello World</div>
</Flex>
);
expect(wrapper).toMatchSnapshot();
expect(renderer.toJSON()).toMatchSnapshot();
});
it("renders with wrap", () => {
const props: PropTypesOf<typeof Flex> = {
wrap: true,
};
const renderer = TestRenderer.create(
<Flex {...props}>
<div>Hello World</div>
</Flex>
);
expect(renderer.toJSON()).toMatchSnapshot();
});
it("renders with wrap reverse", () => {
const props: PropTypesOf<typeof Flex> = {
wrap: "reverse",
};
const renderer = TestRenderer.create(
<Flex {...props}>
<div>Hello World</div>
</Flex>
);
expect(renderer.toJSON()).toMatchSnapshot();
});
it("renders with item gutter", () => {
const props: PropTypesOf<typeof Flex> = {
itemGutter: true,
};
const renderer = TestRenderer.create(
<Flex {...props}>
<div>Hello World</div>
</Flex>
);
expect(renderer.toJSON()).toMatchSnapshot();
});
it("renders with halfe item gutter", () => {
const props: PropTypesOf<typeof Flex> = {
itemGutter: "half",
};
const renderer = TestRenderer.create(
<Flex {...props}>
<div>Hello World</div>
</Flex>
);
expect(renderer.toJSON()).toMatchSnapshot();
});
+38 -10
View File
@@ -1,12 +1,19 @@
import cn from "classnames";
import React from "react";
import React, { Ref } from "react";
import { StatelessComponent } from "react";
import { pascalCase } from "talk-common/utils";
import { withForwardRef, withStyles } from "talk-ui/hocs";
import { PropTypesOf } from "talk-ui/types";
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?:
@@ -20,38 +27,59 @@ interface InnerProps {
direction?: "row" | "column" | "row-reverse" | "column-reverse";
itemGutter?: boolean | "half";
className?: string;
wrap?: boolean | "reverse";
/** Internal: Forwarded Ref */
forwardRef?: Ref<HTMLDivElement>;
}
const Flex: StatelessComponent<InnerProps> = props => {
const {
classes,
className,
justifyContent,
alignItems,
direction,
itemGutter,
wrap,
forwardRef,
...rest
} = props;
let alignItemsWithDefault = alignItems;
if (!alignItems) {
alignItemsWithDefault =
direction && direction.startsWith("column") ? "flex-start" : "center";
}
const classObject: Record<string, boolean> = {
[styles.itemGutter]: itemGutter === true,
[styles.halfItemGutter]: itemGutter === "half",
[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;
if (alignItemsWithDefault) {
classObject[
(classes as any)[`align${pascalCase(alignItemsWithDefault)}`]
] = 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 <div className={classNames} {...rest} />;
return <div ref={forwardRef} className={classNames} {...rest} />;
};
export default Flex;
const enhanced = withForwardRef(withStyles(styles)(Flex));
export default enhanced;
export type FlexProps = PropTypesOf<typeof enhanced>;
@@ -9,3 +9,43 @@ exports[`renders correctly 1`] = `
</div>
</div>
`;
exports[`renders with halfe item gutter 1`] = `
<div
className="Flex-root Flex-halfItemGutter Flex-alignCenter"
>
<div>
Hello World
</div>
</div>
`;
exports[`renders with item gutter 1`] = `
<div
className="Flex-root Flex-itemGutter Flex-alignCenter"
>
<div>
Hello World
</div>
</div>
`;
exports[`renders with wrap 1`] = `
<div
className="Flex-root Flex-wrap Flex-alignCenter"
>
<div>
Hello World
</div>
</div>
`;
exports[`renders with wrap reverse 1`] = `
<div
className="Flex-root Flex-wrapReverse Flex-alignCenter"
>
<div>
Hello World
</div>
</div>
`;
+1 -2
View File
@@ -1,2 +1 @@
export * from "./Flex";
export { default } from "./Flex";
export { default, FlexProps } from "./Flex";
@@ -0,0 +1,54 @@
@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;
letter-spacing: 0;
/* 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;
}
@@ -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
<Playground>
<Icon size="sm">face</Icon>
<Icon size="md">face</Icon>
<Icon size="lg">face</Icon>
<Icon size="xl">face</Icon>
</Playground>
@@ -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<typeof Icon> = {
children: "face",
};
const renderer = TestRenderer.create(<Icon {...props} />);
expect(renderer.toJSON()).toMatchSnapshot();
});
it("renders correctly with specified size", () => {
const props: PropTypesOf<typeof Icon> = {
size: "lg",
children: "bookmark",
};
const renderer = TestRenderer.create(<Icon {...props} />);
expect(renderer.toJSON()).toMatchSnapshot();
});
@@ -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<HTMLSpanElement> {
/**
* This prop can be used to add custom classnames.
* It is handled by the `withStyles `HOC.
*/
classes: typeof styles;
size?: "sm" | "md" | "lg" | "xl";
/** The name of the icon to render */
children: string;
/** Internal: Forwarded Ref */
forwardRef?: Ref<HTMLSpanElement>;
}
const Icon: StatelessComponent<InnerProps> = props => {
const { classes, className, size, forwardRef, ...rest } = props;
const rootClassName = cn(classes.root, className, classes[size!]);
return <span className={rootClassName} {...rest} ref={forwardRef} />;
};
Icon.defaultProps = {
size: "sm",
};
const enhanced = withForwardRef(withStyles(styles)(Icon));
export type IconProps = PropTypesOf<typeof enhanced>;
export default enhanced;
@@ -0,0 +1,17 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<span
className="Icon-root Icon-sm"
>
face
</span>
`;
exports[`renders correctly with specified size 1`] = `
<span
className="Icon-root Icon-lg"
>
bookmark
</span>
`;
@@ -0,0 +1 @@
export { default, IconProps } from "./Icon";
@@ -2,6 +2,8 @@ import React from "react";
import { ReactNode, StatelessComponent } from "react";
import Responsive, { MediaQueryMatchers } from "react-responsive";
import { PropTypesOf } from "talk-ui/types";
import theme from "../../theme/variables";
import UIContext from "../UIContext";
@@ -45,3 +47,4 @@ const MatchMediaWithContext: StatelessComponent<InnerProps> = props => (
);
export default MatchMediaWithContext;
export type MatchMediaProps = PropTypesOf<typeof MatchMediaWithContext>;
@@ -1,2 +1 @@
export * from "./MatchMedia";
export { default } from "./MatchMedia";
export { default, MatchMediaProps } from "./MatchMedia";
@@ -1,4 +1,4 @@
.root {
composes: body1 from "talk-ui/shared/typography.css";
composes: bodyCopy from "talk-ui/shared/typography.css";
background-color: transparent;
}
@@ -1,9 +1,9 @@
import cn from "classnames";
import React from "react";
import React, { Ref } from "react";
import TimeAgo, { Formatter } from "react-timeago";
import { UIContext } from "talk-ui/components";
import { withStyles } from "talk-ui/hocs";
import { withForwardRef, withStyles } from "talk-ui/hocs";
import { PropTypesOf } from "talk-ui/types";
import * as styles from "./RelativeTime.css";
@@ -14,29 +14,30 @@ interface InnerProps {
classes: typeof styles;
className?: string;
formatter?: Formatter;
/** Internal: Forwarded Ref */
forwardRef?: Ref<HTMLDivElement>;
}
const defaultFormatter: Formatter = (value, unit, suffix, timestamp: string) =>
new Date(timestamp).toISOString();
class RelativeTime extends React.Component<InnerProps> {
public render() {
const { date, classes, live, className, formatter } = this.props;
return (
<UIContext.Consumer>
{({ timeagoFormatter }) => (
<TimeAgo
date={date}
className={cn(className, classes.root)}
live={live}
formatter={timeagoFormatter || formatter || defaultFormatter}
/>
)}
</UIContext.Consumer>
);
}
}
const RelativeTime: React.StatelessComponent<InnerProps> = props => {
const { date, classes, live, className, formatter } = props;
return (
<UIContext.Consumer>
{({ timeagoFormatter }) => (
<TimeAgo
date={date}
className={cn(className, classes.root)}
live={live}
formatter={timeagoFormatter || formatter || defaultFormatter}
/>
)}
</UIContext.Consumer>
);
};
const enhanced = withStyles(styles)(RelativeTime);
const enhanced = withForwardRef(withStyles(styles)(RelativeTime));
export type RelativeTimeProps = PropTypesOf<typeof enhanced>;
export default enhanced;
@@ -1,2 +1 @@
export * from "./RelativeTime";
export { default } from "./RelativeTime";
export { default, RelativeTimeProps } from "./RelativeTime";
@@ -0,0 +1,35 @@
import React from "react";
import { create } from "react-test-renderer";
import ToggleShow from "./ToggleShow";
it("renders correctly", () => {
const tree = create(
<ToggleShow>
{({ toggleShow, show }) => (
<div>
{show && <div>SHOW ME</div>}
<button onClick={toggleShow}>Click me and I disappear</button>
</div>
)}
</ToggleShow>
).toJSON();
expect(tree).toMatchSnapshot();
});
it("should hide the div", () => {
const renderer = create(
<ToggleShow>
{({ toggleShow, show }) => (
<div>
{show && <div>SHOW ME</div>}
<button onClick={toggleShow}>Click me and I disappear</button>
</div>
)}
</ToggleShow>
);
renderer.root.findByType("button").props.onClick();
expect(renderer.toJSON()).toMatchSnapshot();
});
@@ -0,0 +1,33 @@
import React, { ReactNode } from "react";
interface State {
show: boolean;
}
interface Props {
children: (props: RenderProps) => ReactNode;
}
interface RenderProps {
toggleShow: () => void;
show: boolean;
}
class ToggleShow extends React.Component<Props, State> {
public state = {
show: true,
};
public toggleShow = () => {
this.setState(state => ({ show: !state.show }));
};
public render() {
return this.props.children({
toggleShow: this.toggleShow,
show: this.state.show,
});
}
}
export default ToggleShow;
@@ -0,0 +1,26 @@
---
name: ToggleShow
menu: UI Kit
---
import { Playground } from 'docz'
import ToggleShow from './ToggleShow'
import Button from '../Button'
import Flex from '../Flex'
# ToggleShow
A render props component to manage visible state.
## Basic usage
<Playground>
<ToggleShow>
{({ toggleShow, show }) => (
<Flex itemGutter direction="column">
{show && <div>Hello World!</div>}
<Button onClick={toggleShow} variant="filled" color="primary">
Toggle Show
</Button>
</Flex>
)}
</ToggleShow>
</Playground>
@@ -0,0 +1,24 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<div>
<div>
SHOW ME
</div>
<button
onClick={[Function]}
>
Click me and I disappear
</button>
</div>
`;
exports[`should hide the div 1`] = `
<div>
<button
onClick={[Function]}
>
Click me and I disappear
</button>
</div>
`;
@@ -0,0 +1,27 @@
---
name: TrapFocus
menu: UI Kit
---
import { Playground } from 'docz'
import TrapFocus from './TrapFocus'
import Button from '../Button'
# TrapFocus
Traps focus inside component when using keyboard navigation for accessibility purposes.
## Basic usage
<Playground>
<div>
<TrapFocus>
{({firstFocusableRef, lastFocusableRef}) =>
<div>
<Button forwardRef={firstFocusableRef} autoFocus>Cancel</Button>
<Button forwardRef={lastFocusableRef}>Send</Button>
</div>
}
</TrapFocus>
</div>
</Playground>
@@ -0,0 +1,80 @@
import React from "react";
import { create } from "react-test-renderer";
import Sinon from "sinon";
import { PropTypesOf } from "talk-ui/types";
import TrapFocus from "./TrapFocus";
const FakeFocusable: any = class extends React.Component {
public focus = Sinon.spy();
public render() {
return null;
}
};
it("renders correctly", () => {
const props: PropTypesOf<TrapFocus> = {
children: () => (
<>
<span>child1</span>
<span>child2</span>
</>
),
};
const renderer = create(
<div>
<TrapFocus {...props} />
</div>
);
expect(renderer.toJSON()).toMatchSnapshot();
});
it("Change focus to `lastFocusable` when focus reaches beginning", () => {
const props: PropTypesOf<TrapFocus> = {
children: ({ firstFocusableRef, lastFocusableRef }) => (
<>
<FakeFocusable ref={firstFocusableRef} />
<span>child1</span>
<span>child2</span>
<FakeFocusable ref={lastFocusableRef} />
</>
),
};
const renderer = create(
<div>
<TrapFocus {...props} />
</div>
);
renderer.root.findAllByProps({ tabIndex: 0 })[0].props.onFocus();
expect(
renderer.root.findAllByType(FakeFocusable)[0].instance.focus.called
).toBe(false);
expect(
renderer.root.findAllByType(FakeFocusable)[1].instance.focus.called
).toBe(true);
});
it("Change focus to `firstFocusable` when focus reaches end", () => {
const props: PropTypesOf<TrapFocus> = {
children: ({ firstFocusableRef, lastFocusableRef }) => (
<>
<FakeFocusable ref={firstFocusableRef} />
<span>child1</span>
<span>child2</span>
<FakeFocusable ref={lastFocusableRef} />
</>
),
};
const renderer = create(
<div>
<TrapFocus {...props} />
</div>
);
renderer.root.findAllByProps({ tabIndex: 0 })[1].props.onFocus();
expect(
renderer.root.findAllByType(FakeFocusable)[0].instance.focus.called
).toBe(true);
expect(
renderer.root.findAllByType(FakeFocusable)[1].instance.focus.called
).toBe(false);
});
@@ -0,0 +1,36 @@
import React, { RefObject } from "react";
export interface Focusable {
focus: () => void;
}
interface RenderProps {
firstFocusableRef: RefObject<Focusable>;
lastFocusableRef: RefObject<Focusable>;
}
export interface TrapFocusProps {
children: (props: RenderProps) => React.ReactNode;
}
export default class TrapFocus extends React.Component<TrapFocusProps> {
private firstFocusableRef = React.createRef<Focusable>();
private lastFocusableRef = React.createRef<Focusable>();
// Trap keyboard focus inside the dropdown until a value has been chosen.
private focusBegin = () => this.firstFocusableRef.current!.focus();
private focusEnd = () => this.lastFocusableRef.current!.focus();
public render() {
return (
<>
<div tabIndex={0} onFocus={this.focusEnd} />
{this.props.children({
firstFocusableRef: this.firstFocusableRef,
lastFocusableRef: this.lastFocusableRef,
})}
<div tabIndex={0} onFocus={this.focusBegin} />
</>
);
}
}
@@ -0,0 +1,20 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<div>
<div
onFocus={[Function]}
tabIndex={0}
/>
<span>
child1
</span>
<span>
child2
</span>
<div
onFocus={[Function]}
tabIndex={0}
/>
</div>
`;
@@ -0,0 +1 @@
export { default, TrapFocusProps } from "./TrapFocus";
@@ -19,28 +19,16 @@
composes: heading4 from "talk-ui/shared/typography.css";
}
.subtitle1 {
composes: subtitle1 from "talk-ui/shared/typography.css";
}
.subtitle2 {
composes: subtitle2 from "talk-ui/shared/typography.css";
}
.body1 {
composes: body1 from "talk-ui/shared/typography.css";
}
.body2 {
composes: body2 from "talk-ui/shared/typography.css";
.bodyCopy {
composes: bodyCopy from "talk-ui/shared/typography.css";
}
.button {
composes: button from "talk-ui/shared/typography.css";
}
.overline {
composes: overline from "talk-ui/shared/typography.css";
.buttonLarge {
composes: buttonLarge from "talk-ui/shared/typography.css";
}
.timestamp {
@@ -85,8 +73,8 @@
color: var(--palette-primary-main);
}
.colorSecondary {
color: var(--palette-secondary-main);
.colorTextPrimary {
color: var(--palette-text-primary);
}
.colorTextSecondary {
@@ -96,3 +84,7 @@
.colorError {
color: var(--palette-error-main);
}
.colorSuccess {
color: var(--palette-success-main);
}
@@ -0,0 +1,56 @@
---
name: Typography
menu: UI Kit
---
import { Playground } from 'docz'
import Typography from './Typography'
import Flex from '../Flex'
# Typography
## Basic Use
<Playground>
<Flex itemGutter direction="column">
<Typography variant="heading1">Heading1</Typography>
<Typography variant="heading2">Heading2</Typography>
<Typography variant="heading3">Heading3</Typography>
<Typography variant="heading4">Heading4</Typography>
<Typography variant="bodyCopy">BodyCopy</Typography>
<Typography variant="timestamp">timestamp</Typography>
</Flex>
</Playground>
## Using different colors
<Playground>
<Flex itemGutter direction="column">
<Typography color="textPrimary">textPrimary</Typography>
<Typography color="textSecondary">textSecondary</Typography>
<Typography color="success">success</Typography>
<Typography color="error">error</Typography>
</Flex>
</Playground>
## Set align
<Playground>
<Flex itemGutter direction="column" alignItems="stretch" style={{width: "200px"}}>
<Typography align="left">left</Typography>
<Typography align="center">center</Typography>
<Typography align="right">right</Typography>
<Typography align="justify"> No hay nadie que ame el dolor mismo, que lo busque, lo encuentre y lo
quiera, simplemente porque es el dolor.</Typography>
</Flex>
</Playground>
## Cut off long text
<Playground>
<Typography noWrap style={{width: "200px"}}>No hay nadie que ame el dolor mismo, que lo busque, lo encuentre y lo quiera, simplemente porque es el dolor.</Typography>
</Playground>
## Gutters
<Playground>
<Typography gutterBottom>I have a bottom gutter</Typography>
<Typography paragraph>I have a paragraph gutter</Typography>
<Typography>Just a normal text</Typography>
</Playground>
@@ -0,0 +1,20 @@
import React from "react";
import TestRenderer from "react-test-renderer";
import { PropTypesOf } from "talk-ui/types";
import Typography from "./Typography";
it("renders correctly", () => {
const props: PropTypesOf<typeof Typography> = {
className: "custom",
variant: "heading1",
color: "textSecondary",
gutterBottom: true,
children: "Hello World",
noWrap: true,
align: "left",
};
const renderer = TestRenderer.create(<Typography {...props} />);
expect(renderer.toJSON()).toMatchSnapshot();
});
@@ -1,8 +1,8 @@
import cn from "classnames";
import React from "react";
import React, { Ref } from "react";
import { HTMLAttributes, ReactNode, StatelessComponent } from "react";
import { withStyles } from "talk-ui/hocs";
import { withForwardRef, withStyles } from "talk-ui/hocs";
import { PropTypesOf } from "talk-ui/types";
import * as styles from "./Typography.css";
@@ -12,11 +12,7 @@ type Variant =
| "heading2"
| "heading3"
| "heading4"
| "subtitle1"
| "subtitle2"
| "body1"
| "body2"
| "button"
| "bodyCopy"
| "timestamp";
// Based on Typography Component of Material UI.
@@ -45,10 +41,10 @@ interface InnerProps extends HTMLAttributes<any> {
color?:
| "inherit"
| "primary"
| "textPrimary"
| "textSecondary"
| "secondary"
| "error"
| "default";
| "success";
/**
* The component used for the root node.
* Either a string to use a DOM element or a component.
@@ -77,6 +73,9 @@ interface InnerProps extends HTMLAttributes<any> {
* Applies the theme typography styles.
*/
variant?: Variant;
/** Internal: Forwarded Ref */
forwardRef?: Ref<HTMLElement>;
}
const Typography: StatelessComponent<InnerProps> = props => {
@@ -91,6 +90,7 @@ const Typography: StatelessComponent<InnerProps> = props => {
noWrap,
paragraph,
variant,
forwardRef,
...rest
} = props;
@@ -98,10 +98,11 @@ const Typography: StatelessComponent<InnerProps> = props => {
classes.root,
classes[variant!],
{
[classes.colorPrimary]: color === "primary",
[classes.colorSecondary]: color === "secondary",
[classes.colorError]: color === "error",
[classes.colorTextPrimary]: color === "textPrimary",
[classes.colorTextSecondary]: color === "textSecondary",
[classes.colorPrimary]: color === "primary",
[classes.colorError]: color === "error",
[classes.colorSuccess]: color === "success",
[classes.noWrap]: noWrap,
[classes.gutterBottom]: gutterBottom,
[classes.paragraph]: paragraph,
@@ -116,29 +117,26 @@ const Typography: StatelessComponent<InnerProps> = props => {
const Component =
component || (paragraph ? "p" : headlineMapping![variant!]) || "span";
return <Component className={rootClassName} {...rest} />;
return <Component ref={forwardRef} className={rootClassName} {...rest} />;
};
Typography.defaultProps = {
align: "inherit",
color: "default",
color: "textPrimary",
gutterBottom: false,
headlineMapping: {
heading1: "h1",
heading2: "h1",
heading3: "h1",
heading4: "h1",
subtitle1: "h2",
subtitle2: "h3",
body1: "p",
body2: "aside",
bodyCopy: "p",
timestamp: "span",
},
noWrap: false,
paragraph: false,
variant: "body1",
variant: "bodyCopy",
};
const enhanced = withStyles(styles)(Typography);
export type CenterProps = PropTypesOf<typeof enhanced>;
const enhanced = withForwardRef(withStyles(styles)(Typography));
export type TypographyProps = PropTypesOf<typeof enhanced>;
export default enhanced;
@@ -0,0 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<h1
className="Typography-root Typography-heading1 Typography-colorTextSecondary Typography-noWrap Typography-gutterBottom Typography-alignLeft custom"
>
Hello World
</h1>
`;
@@ -1,2 +1 @@
export * from "./Typography";
export { default } from "./Typography";
export { default, TypographyProps } from "./Typography";
+1
View File
@@ -7,3 +7,4 @@ export { default as RelativeTime } from "./RelativeTime";
export { default as UIContext, UIContextProps } from "./UIContext";
export { default as Flex } from "./Flex";
export { default as MatchMedia } from "./MatchMedia";
export { default as TrapFocus } from "./TrapFocus";
+2
View File
@@ -1,2 +1,4 @@
export { default as withStyles } from "./withStyles";
export { default as withKeyboardFocus } from "./withKeyboardFocus";
export { default as withMouseHover } from "./withMouseHover";
export { default as withForwardRef } from "./withForwardRef";
+29 -15
View File
@@ -1,22 +1,36 @@
import React from "react";
import {
InferableComponentEnhancerWithProps,
withPropsOnChange,
} from "recompose";
import React, { Ref } from "react";
// TODO: ForwardRef API is not supported in enzymes shallow rendering
// https://github.com/airbnb/enzyme/issues/1553
// As for now we do props passing instead until full React16 support lands in
// enzyme.
/**
* withForwardRef provides a property called `forwardRef` using
* the `React.forwardRef` api.
*/
function withForwardRef<T>(): InferableComponentEnhancerWithProps<
{ forwardRef: Ref<any> },
{}
> {
return WrappedComponent => {
return React.forwardRef((props, ref) => (
<WrappedComponent forwardRef={ref} />
));
};
/*
function withForwardRef<P extends { ref?: Ref<any>; forwardRef?: Ref<any> }>(
BaseComponent: React.ComponentType<P>
): React.ComponentType<Omit<P, "forwardRef">> {
const forwardRef: RefForwardingComponent<any, P> = (props, ref) => (
<BaseComponent {...props} forwardRef={ref} />
);
return React.forwardRef<any, P>(forwardRef);
}
export default withForwardRef;
// TODO: workaround, add bug link.
export default withForwardRef as <
P extends { ref?: Ref<any>; forwardRef?: Ref<any> }
>(
BaseComponent: React.ComponentType<P>
) => React.ComponentType<P>;
*/
// Stub, currently doesn't do anything except adding types.
export default function withForwardRef<P extends { forwardRef?: Ref<any> }>(
BaseComponent: React.ComponentType<P>
): React.ComponentType<P> {
return BaseComponent;
}
+12 -7
View File
@@ -3,10 +3,10 @@ import { FocusEvent, MouseEvent } from "react";
import { hoistStatics } from "recompose";
interface InjectedProps {
onFocus?: React.EventHandler<FocusEvent<any>>;
onBlur?: React.EventHandler<FocusEvent<any>>;
onMouseDown?: React.EventHandler<MouseEvent<any>>;
keyboardFocus?: boolean;
onFocus: React.EventHandler<FocusEvent<any>>;
onBlur: React.EventHandler<FocusEvent<any>>;
onMouseDown: React.EventHandler<MouseEvent<any>>;
keyboardFocus: boolean;
}
/**
@@ -14,8 +14,8 @@ interface InjectedProps {
* to indicate a focus on the element, that wasn't triggered by mouse
* or touch.
*/
export default hoistStatics<InjectedProps>(
<T extends InjectedProps>(WrappedComponent: React.ComponentType<T>) => {
const withKeyboardFocus = hoistStatics<InjectedProps>(
<T extends InjectedProps>(BaseComponent: React.ComponentType<T>) => {
class WithKeyboardFocus extends React.Component<any> {
public state = {
keyboardFocus: false,
@@ -48,7 +48,7 @@ export default hoistStatics<InjectedProps>(
public render() {
return (
<WrappedComponent
<BaseComponent
{...this.props}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
@@ -62,3 +62,8 @@ export default hoistStatics<InjectedProps>(
return WithKeyboardFocus as React.ComponentType<any>;
}
);
// TODO: workaround, add bug link.
export default withKeyboardFocus as <P extends Partial<InjectedProps>>(
BaseComponent: React.ComponentType<P>
) => React.ComponentType<P>;
@@ -0,0 +1,69 @@
import * as React from "react";
import { MouseEvent, TouchEvent } from "react";
import { hoistStatics } from "recompose";
interface InjectedProps {
onMouseOver: React.EventHandler<MouseEvent<any>>;
onMouseOut: React.EventHandler<MouseEvent<any>>;
onTouchEnd: React.EventHandler<TouchEvent<any>>;
mouseHover: boolean;
}
/**
* withMouseHover provides a property `MouseHover: boolean`
* to indicate a focus on the element, that wasn't triggered by mouse
* or touch.
*/
const withMouseHover = hoistStatics<InjectedProps>(
<T extends InjectedProps>(BaseComponent: React.ComponentType<T>) => {
class WithMouseHover extends React.Component<any> {
public state = {
mouseHover: false,
lastTouchEndTime: 0,
};
private handleTouchEnd: React.EventHandler<TouchEvent<any>> = event => {
if (this.props.onTouchEnd) {
this.props.onTouchEnd(event);
}
this.setState({ lastTouchEndTime: new Date().getTime() });
};
private handleMouseOver: React.EventHandler<MouseEvent<any>> = event => {
if (this.props.onMouseOver) {
this.props.onMouseOver(event);
}
const now = new Date().getTime();
if (now - this.state.lastTouchEndTime > 750) {
this.setState({ mouseHover: true });
}
};
private handleMouseOut: React.EventHandler<MouseEvent<any>> = event => {
if (this.props.onMouseOut) {
this.props.onMouseOut(event);
}
this.setState({ mouseHover: false });
};
public render() {
return (
<BaseComponent
{...this.props}
onMouseOver={this.handleMouseOver}
onMouseOut={this.handleMouseOut}
onTouchEnd={this.handleTouchEnd}
mouseHover={this.state.mouseHover}
/>
);
}
}
return WithMouseHover as React.ComponentType<any>;
}
);
// TODO: workaround, add bug link.
export default withMouseHover as <P extends Partial<InjectedProps>>(
BaseComponent: React.ComponentType<P>
) => React.ComponentType<P>;
+3 -2
View File
@@ -13,17 +13,18 @@ function withStyles<T>(
): DefaultingInferableComponentEnhancer<{ classes?: Partial<T> }> {
const classes = { ...(styles as any) };
return withPropsOnChange<any, any>(["classes"], props => {
const resolvedClasses = { ...classes };
if (props.classes) {
Object.keys(props.classes).forEach(k => {
if (classes[k]) {
classes[k] += ` ${props.classes[k]}`;
resolvedClasses[k] += ` ${props.classes[k]}`;
} else if (process.env.NODE_ENV !== "production") {
// tslint:disable:next-line: no-console
console.warn("Extending non existant className", k);
}
});
}
return { classes };
return { classes: resolvedClasses };
});
}
+68 -12
View File
@@ -1,3 +1,61 @@
@font-face {
font-family: "Source Sans Pro";
font-style: normal;
font-display: swap;
font-weight: 300;
src: local("Source Sans Pro Light "), local("Source Sans Pro-Light"),
url("typeface-source-sans-pro/files/source-sans-pro-latin-300.woff2")
format("woff2"),
url("typeface-source-sans-pro/files/source-sans-pro-latin-300.woff")
format("woff");
}
@font-face {
font-family: "Source Sans Pro";
font-style: normal;
font-display: swap;
font-weight: 400;
src: local("Source Sans Pro Regular italic"),
local("Source Sans Pro-Regularitalic"),
url("typeface-source-sans-pro/files/source-sans-pro-latin-400.woff2")
format("woff2"),
url("typeface-source-sans-pro/files/source-sans-pro-latin-400.woff")
format("woff");
}
@font-face {
font-family: "Source Sans Pro";
font-style: normal;
font-display: swap;
font-weight: 600;
src: local("Source Sans Pro SemiBold italic"),
local("Source Sans Pro-SemiBolditalic"),
url("typeface-source-sans-pro/files/source-sans-pro-latin-600.woff2")
format("woff2"),
url("typeface-source-sans-pro/files/source-sans-pro-latin-600.woff")
format("woff");
}
@font-face {
font-family: "Manuale";
font-style: normal;
font-display: swap;
font-weight: 400;
src: local("Manuale Regular "), local("Manuale-Regular"),
url("typeface-manuale/files/manuale-latin-400.woff2") format("woff2"),
url("typeface-manuale/files/manuale-latin-400.woff") format("woff");
}
@font-face {
font-family: "Manuale";
font-style: normal;
font-display: swap;
font-weight: 600;
src: local("Manuale SemiBold "), local("Manuale-SemiBold"),
url("typeface-manuale/files/manuale-latin-600.woff2") format("woff2"),
url("typeface-manuale/files/manuale-latin-600.woff") format("woff");
}
.heading1 {
font-size: calc(24rem / var(--rem-base));
font-weight: var(--font-weight-medium);
@@ -33,16 +91,7 @@
color: var(--palette-text-primary);
}
.subtitle1 {
}
.subtitle2 {
}
.body2 {
}
.body1 {
.bodyCopy {
font-size: calc(16rem / var(--rem-base));
font-weight: var(--font-weight-regular);
font-family: "Source Sans Pro";
@@ -55,11 +104,18 @@
color: var(--palette-text-secondary);
font-family: "Source Sans Pro";
font-weight: var(--font-weight-medium);
font-size: 16px;
font-size: 14px;
line-height: calc(18em / 16);
letter-spacing: calc(0.57em / 16);
}
.overline {
.buttonLarge {
color: var(--palette-text-secondary);
font-family: "Source Sans Pro";
font-weight: var(--font-weight-medium);
font-size: 16px;
line-height: calc(20em / 16);
letter-spacing: calc(0.57em / 16);
}
.timestamp {
+9 -12
View File
@@ -12,14 +12,16 @@ const variables = {
main: "#3498DB",
light: "#67B2E4",
lighter: "#8DC5EB",
lightest: "#EBF5FB",
},
/* Secondary colors */
secondary: {
grey: {
darkest: "#404345",
dark: "#65696B",
main: "#787D80",
light: "#9A9DA0",
lighter: "#636E72",
lighter: "#BBBEBF",
lightest: "#F5F5F5",
},
/* Success colors */
success: {
@@ -28,21 +30,21 @@ const variables = {
main: "#00CD73",
light: "#40D996",
lighter: "#83EBBD",
lightest: "#E6FAF1",
},
/* Error colors */
error: {
darkest: "#F50F0C",
dark: "#FF1F1C",
main: "#FA4643",
light: "#F26563",
lighter: "#F26563",
light: "#FB7472",
lighter: "#FC9795",
lightest: "#FEF0EF",
},
/* Text colors */
text: {
primary: "#3B4A53",
secondary: "#787D80",
disabled: "rgba(0, 0, 0, 0.38)",
hint: "rgba(0, 0, 0, 0.38)",
},
/* Common colors */
common: {
@@ -51,11 +53,6 @@ const variables = {
},
/* Divider */
divider: "rgba(0, 0, 0, 0.12)",
/* The background colors used to style the surfaces. */
background: {
paper: "#FFF",
default: "#FAFAFA",
},
},
/* gitter and spacing */
spacingUnitSmall: 5,
@@ -68,7 +65,7 @@ const variables = {
fontSize: 16,
fontWeightLight: 300,
fontWeightRegular: 400,
fontWeightMedium: 550,
fontWeightMedium: 600,
/* Breakpoints */
breakpoints: {
xs: 320,
+2 -10
View File
@@ -2,27 +2,19 @@ import React from "react";
// TODO: Extract useful common types into its own package.
/**
* Returns literals types that are in T but not in U.
*
* E.g. Diff<"a" | "b", "a"> = "b"
*/
export type Diff<T extends keyof any, U extends keyof any> = ({ [P in T]: P } &
{ [P in U]: never } & { [x: string]: never; [x: number]: never })[T];
/**
* Overwrite properties of `T`.
*
* E.g. Omit<{a: boolean, b: boolean}, "b"> = {a: boolean}
*/
export type Omit<U, K extends keyof U> = Pick<U, Diff<keyof U, K>>;
export type Omit<U, K extends keyof U> = Pick<U, Exclude<keyof U, K>>;
/**
* Overwrite properties of `T`.
*
* E.g. Overwrite<{a: boolean}, {a: string}> = {a: string}
*/
export type Overwrite<T, U> = Pick<T, Diff<keyof T, keyof U>> & U;
export type Overwrite<T, U> = Pick<T, Exclude<keyof T, keyof U>> & U;
/**
* Returns the PropTypes from a React Component.
+1 -1
View File
@@ -22,7 +22,7 @@ framework-timeago =
*[other] Minuten
}
[hour] { $value ->
[0] Stunde
[1] Stunde
*[other] Stunden
}
[day] { $value ->
+1 -1
View File
@@ -18,7 +18,7 @@ framework-timeago-time =
*[other] minutes
}
[hour] { $value ->
[0] hour
[1] hour
*[other] hours
}
[day] { $value ->
+1 -1
View File
@@ -22,7 +22,7 @@ framework-timeago =
*[other] minutos
}
[hour] { $value ->
[0] hora
[1] hora
*[other] horas
}
[day] { $value ->