├── .babelrc
├── .editorconfig
├── .eslintrc.js
├── .gitattributes
├── .gitignore
├── .npmignore
├── .prettierignore
├── .prettierrc
├── .storybook
├── addons.js
├── config.js
└── preview-head.html
├── .travis.yml
├── CODE_OF_CONDUCT.md
├── LICENSE.md
├── README.md
├── jest.config.js
├── package.json
├── scripts
└── demos2Stories.js
├── src
├── components
│ ├── Theme
│ │ └── index.js
│ ├── badges
│ │ ├── Badge.js
│ │ ├── Badge.style.js
│ │ ├── demos
│ │ │ ├── IconOverIcon.js
│ │ │ ├── IconOverText.js
│ │ │ ├── NumberOverIcon.js
│ │ │ ├── NumberOverText.js
│ │ │ └── TextOverButton.js
│ │ └── index.js
│ ├── buttons
│ │ ├── Button.js
│ │ ├── Button.style.js
│ │ ├── demos
│ │ │ ├── Fab.js
│ │ │ ├── FabAccent.js
│ │ │ ├── FabDisabled.js
│ │ │ ├── FabMini.js
│ │ │ ├── FabPrimary.js
│ │ │ ├── Flat.js
│ │ │ ├── FlatAccent.js
│ │ │ ├── FlatDisabled.js
│ │ │ ├── FlatPrimary.js
│ │ │ ├── Icon.js
│ │ │ ├── IconAccent.js
│ │ │ ├── IconDisabled.js
│ │ │ ├── IconMini.js
│ │ │ ├── IconPrimary.js
│ │ │ ├── Raised.js
│ │ │ ├── RaisedAccent.js
│ │ │ ├── RaisedDisabled.js
│ │ │ └── RaisedPrimary.js
│ │ └── index.js
│ ├── cards
│ │ ├── Card.style.js
│ │ ├── CardActions.style.js
│ │ ├── CardMedia.style.js
│ │ ├── CardMenu.style.js
│ │ ├── CardSubtitleText.style.js
│ │ ├── CardSupportingText.style.js
│ │ ├── CardTitle.style.js
│ │ ├── CardTitleText.style.js
│ │ ├── demos
│ │ │ ├── Event.js
│ │ │ ├── Image.js
│ │ │ ├── Square.js
│ │ │ └── Wide.js
│ │ └── index.js
│ ├── checkbox
│ │ ├── Checkbox.js
│ │ ├── Checkbox.style.js
│ │ ├── demos
│ │ │ └── Checkbox.js
│ │ ├── images.js
│ │ └── index.js
│ ├── chips
│ │ ├── ButtonChip.js
│ │ ├── Chip.js
│ │ ├── Chip.style.js
│ │ ├── ChipContact.js
│ │ ├── demos
│ │ │ ├── Basic.js
│ │ │ ├── Button.js
│ │ │ ├── Contact.js
│ │ │ ├── Deletable.js
│ │ │ └── DeletableContact.js
│ │ └── index.js
│ ├── dialog
│ │ ├── Dialog.js
│ │ ├── Dialog.style.js
│ │ ├── demos
│ │ │ ├── Basic.js
│ │ │ └── FullWidthActions.js
│ │ └── index.js
│ ├── fonts
│ │ ├── MaterialIcons.js
│ │ ├── Roboto.js
│ │ └── index.js
│ ├── icons
│ │ ├── Icon.js
│ │ ├── Icon.style.js
│ │ └── index.js
│ ├── layout
│ │ ├── Spacer.style.js
│ │ └── index.js
│ ├── list
│ │ ├── List.style.js
│ │ ├── demos
│ │ │ ├── AvatarsAndActions.js
│ │ │ ├── AvatarsAndControls.js
│ │ │ ├── Icons.js
│ │ │ ├── Simple.js
│ │ │ ├── ThreeLine.js
│ │ │ └── TwoLine.js
│ │ └── index.js
│ ├── menu
│ │ ├── Menu.js
│ │ ├── Menu.style.js
│ │ ├── MenuDivider.js
│ │ ├── MenuItem.js
│ │ ├── demos
│ │ │ ├── LowerLeft.js
│ │ │ ├── LowerRight.js
│ │ │ ├── UpperLeft.js
│ │ │ ├── UpperRight.js
│ │ │ └── _shared.js
│ │ ├── getRelativePosition.js
│ │ └── index.js
│ ├── progress
│ │ ├── Progress.js
│ │ ├── Progress.style.js
│ │ ├── demos
│ │ │ ├── Progress.js
│ │ │ └── ProgressIndeterminate.js
│ │ └── index.js
│ ├── radio
│ │ ├── Radio.js
│ │ ├── Radio.style.js
│ │ ├── demos
│ │ │ └── Radio.js
│ │ └── index.js
│ ├── ripple
│ │ ├── Ripple.js
│ │ ├── Ripple.style.js
│ │ ├── helpers.js
│ │ └── index.js
│ ├── slider
│ │ ├── Slider.js
│ │ ├── Slider.style.js
│ │ ├── demos
│ │ │ ├── default.js
│ │ │ ├── disabled.js
│ │ │ └── startingValue.js
│ │ └── index.js
│ ├── snackbar
│ │ ├── Action.style.js
│ │ ├── Message.style.js
│ │ ├── Snackbar.js
│ │ ├── Snackbar.style.js
│ │ ├── demos
│ │ │ ├── Snackbar.js
│ │ │ └── SnackbarWithAction.js
│ │ └── index.js
│ ├── spinner
│ │ ├── Spinner.js
│ │ ├── Spinner.style.js
│ │ ├── demos
│ │ │ ├── Spinner.js
│ │ │ └── SpinnerSingleColor.js
│ │ └── index.js
│ ├── switch
│ │ ├── Switch.js
│ │ ├── Switch.style.js
│ │ ├── demos
│ │ │ └── Switch.js
│ │ └── index.js
│ ├── tables
│ │ ├── Table.style.js
│ │ ├── demos
│ │ │ └── DataTable.js
│ │ └── index.js
│ ├── textfield
│ │ ├── Textfield.js
│ │ ├── Textfield.style.js
│ │ ├── demos
│ │ │ ├── Error.js
│ │ │ ├── HelperText.js
│ │ │ ├── MultiLine.js
│ │ │ └── SingleLine.js
│ │ └── index.js
│ ├── toast
│ │ ├── Toast.js
│ │ ├── Toast.style.js
│ │ └── index.js
│ └── tooltips
│ │ ├── Tooltip.js
│ │ ├── Tooltip.style.js
│ │ ├── demos
│ │ ├── Above.js
│ │ ├── Below.js
│ │ ├── Large.js
│ │ ├── Left.js
│ │ ├── MultiLine.js
│ │ └── Right.js
│ │ └── index.js
├── hocs
│ ├── index.js
│ └── proxyStyledStatics.js
├── index.js
├── initGlobals.js
├── input
│ ├── Input.js
│ └── index.js
├── mixins
│ ├── animations.style.js
│ ├── arrow.style.js
│ ├── index.js
│ ├── shadows.style.js
│ └── type.style.js
├── theme
│ ├── animation
│ │ ├── defaults.js
│ │ └── index.js
│ ├── badge
│ │ ├── defaults.js
│ │ └── index.js
│ ├── button
│ │ ├── defaults.js
│ │ └── index.js
│ ├── card
│ │ ├── defaults.js
│ │ └── index.js
│ ├── chip
│ │ ├── defaults.js
│ │ └── index.js
│ ├── colorDefinitions.js
│ ├── colors
│ │ ├── defaults.js
│ │ └── index.js
│ ├── createTheme.js
│ ├── createThemer.js
│ ├── dataTable
│ │ ├── defaults.js
│ │ └── index.js
│ ├── defaultTheme.js
│ ├── dialog
│ │ └── index.js
│ ├── footer
│ │ ├── defaults.js
│ │ └── index.js
│ ├── grid
│ │ ├── defaults.js
│ │ └── index.js
│ ├── iconToggle
│ │ ├── defaults.js
│ │ └── index.js
│ ├── index.js
│ ├── layout
│ │ ├── defaults.js
│ │ └── index.js
│ ├── list
│ │ ├── defaults.js
│ │ └── index.js
│ ├── menu
│ │ ├── defaults.js
│ │ └── index.js
│ ├── progress
│ │ ├── defaults.js
│ │ └── index.js
│ ├── radio
│ │ ├── defaults.js
│ │ └── index.js
│ ├── shadows
│ │ ├── defaults.js
│ │ └── index.js
│ ├── snackbar
│ │ └── index.js
│ ├── spinner
│ │ ├── defaults.js
│ │ └── index.js
│ ├── switch
│ │ ├── defaults.js
│ │ └── index.js
│ ├── textField
│ │ ├── defaults.js
│ │ └── index.js
│ ├── tooltip
│ │ ├── defaults.js
│ │ └── index.js
│ └── typography
│ │ ├── defaults.js
│ │ └── index.js
└── util
│ ├── colors.js
│ ├── getters.js
│ ├── index.js
│ ├── math.js
│ └── units.js
├── stories
├── badges.stories.js
├── buttons.stories.js
├── cards.stories.js
├── checkbox.stories.js
├── chips.stories.js
├── decorators
│ └── wrapStory.js
├── dialog.stories.js
├── list.stories.js
├── menu.stories.js
├── progress.stories.js
├── radio.stories.js
├── slider.stories.js
├── snackbar.stories.js
├── spinner.stories.js
├── switch.stories.js
├── tables.stories.js
├── textfield.stories.js
└── tooltips.stories.js
├── tests
├── _setup
│ ├── test-bundler.js
│ ├── textOnly.js
│ └── until.js
├── badges
│ └── Badge.spec.js
├── buttons
│ └── index.spec.js
├── checkbox
│ └── Checkbox.spec.js
├── chips
│ ├── ButtonChip.spec.js
│ ├── Chip.spec.js
│ └── ChipContact.spec.js
├── input
│ └── Input.spec.js
├── menu
│ ├── Divider.spec.js
│ ├── Menu.spec.js
│ ├── MenuItem.spec.js
│ └── getRelativePosition.spec.js
├── progress
│ └── Progress.spec.js
├── radio
│ └── Radio.spec.js
├── ripple
│ └── index.spec.js
├── slider
│ └── Slider.spec.js
├── snackbar
│ └── Snackbar.spec.js
├── spinner
│ └── Spinner.spec.js
├── switch
│ └── Switch.spec.js
├── textfield
│ └── Textfield.spec.js
├── tooltips
│ └── Tooltip.spec.js
└── util
│ ├── colors.spec.js
│ ├── getters.spec.js
│ ├── math.spec.js
│ └── units.spec.js
└── yarn.lock
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["env", "react", "stage-0"],
3 | "env": {
4 | "production": {
5 | "only": ["app"],
6 | "plugins": [
7 | "transform-react-remove-prop-types",
8 | "transform-react-constant-elements",
9 | "transform-react-inline-elements"
10 | ]
11 | },
12 | "test": {
13 | "presets": ["env", "react", "stage-0"],
14 | "plugins": ["dynamic-import-node"]
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 |
3 | root = true
4 |
5 | [*]
6 | charset = utf-8
7 | end_of_line = lf
8 | insert_final_newline = true
9 | indent_style = space
10 | indent_size = 2
11 | trim_trailing_whitespace = true
12 |
13 | [*.md]
14 | trim_trailing_whitespace = false
15 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | parser: 'babel-eslint',
3 | extends: 'airbnb',
4 | env: {
5 | browser: true,
6 | node: true,
7 | jest: true,
8 | es6: true,
9 | },
10 | plugins: ['react', 'jsx-a11y'],
11 | parserOptions: {
12 | ecmaVersion: 6,
13 | sourceType: 'module',
14 | ecmaFeatures: {
15 | jsx: true,
16 | },
17 | },
18 | rules: {
19 | semi: ['error', 'never'],
20 | 'arrow-parens': ['error', 'always'],
21 | 'arrow-body-style': [2, 'as-needed'],
22 | 'comma-dangle': [2, 'always-multiline'],
23 | 'function-paren-newline': 0,
24 | 'space-in-parens': 0,
25 | 'import/imports-first': 0,
26 | 'import/newline-after-import': 0,
27 | 'import/no-dynamic-require': 0,
28 | 'import/no-extraneous-dependencies': 0,
29 | 'import/no-named-as-default': 0,
30 | 'import/prefer-default-export': 0,
31 | 'import/extensions': 0,
32 | 'object-curly-newline': 0,
33 | indent: 0,
34 | 'jsx-a11y/aria-props': 2,
35 | 'jsx-a11y/heading-has-content': 0,
36 | 'jsx-a11y/label-has-for': 0,
37 | 'jsx-a11y/mouse-events-have-key-events': 2,
38 | 'jsx-a11y/role-has-required-aria-props': 2,
39 | 'jsx-a11y/role-supports-aria-props': 2,
40 | 'max-len': 0,
41 | 'newline-per-chained-call': 0,
42 | 'no-confusing-arrow': 0,
43 | 'no-console': 1,
44 | 'no-mixed-operators': 0,
45 | 'no-use-before-define': 0,
46 | 'prefer-template': 2,
47 | 'class-methods-use-this': 0,
48 | 'react/forbid-prop-types': 0,
49 | 'react/prop-types': 0,
50 | 'react/jsx-first-prop-new-line': [2, 'multiline'],
51 | 'react/jsx-filename-extension': 0,
52 | 'react/jsx-no-target-blank': 0,
53 | 'react/no-unescaped-entities': 0,
54 | 'react/jsx-uses-react': 2,
55 | 'react/react-in-jsx-scope': 2,
56 | 'react/require-extension': 0,
57 | 'react/self-closing-comp': 0,
58 | 'react/require-default-props': 0,
59 | 'require-yield': 0,
60 | 'import/no-webpack-loader-syntax': 0,
61 | },
62 | globals: {
63 | shallowComponent: true,
64 | mountComponent: true,
65 | },
66 | settings: {
67 | 'import/core-modules': ['material-components'],
68 | 'import/resolver': {
69 | webpack: {
70 | config: './internals/webpack/webpack.prod.babel.js',
71 | },
72 | },
73 | },
74 | }
75 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # From https://github.com/Danimoth/gitattributes/blob/master/Web.gitattributes
2 |
3 | # Handle line endings automatically for files detected as text
4 | # and leave all files detected as binary untouched.
5 | * text=auto
6 |
7 | #
8 | # The above will handle all files NOT found below
9 | #
10 |
11 | #
12 | ## These files are text and should be normalized (Convert crlf => lf)
13 | #
14 |
15 | # source code
16 | *.php text
17 | *.css text
18 | *.sass text
19 | *.scss text
20 | *.less text
21 | *.styl text
22 | *.js text eol=lf
23 | *.coffee text
24 | *.json text
25 | *.htm text
26 | *.html text
27 | *.xml text
28 | *.svg text
29 | *.txt text
30 | *.ini text
31 | *.inc text
32 | *.pl text
33 | *.rb text
34 | *.py text
35 | *.scm text
36 | *.sql text
37 | *.sh text
38 | *.bat text
39 |
40 | # templates
41 | *.ejs text
42 | *.hbt text
43 | *.jade text
44 | *.haml text
45 | *.hbs text
46 | *.dot text
47 | *.tmpl text
48 | *.phtml text
49 |
50 | # server config
51 | .htaccess text
52 | .nginx.conf text
53 |
54 | # git config
55 | .gitattributes text
56 | .gitignore text
57 | .gitconfig text
58 |
59 | # code analysis config
60 | .jshintrc text
61 | .jscsrc text
62 | .jshintignore text
63 | .csslintrc text
64 |
65 | # misc config
66 | *.yaml text
67 | *.yml text
68 | .editorconfig text
69 |
70 | # build config
71 | *.npmignore text
72 | *.bowerrc text
73 |
74 | # Heroku
75 | Procfile text
76 | .slugignore text
77 |
78 | # Documentation
79 | *.md text
80 | LICENSE text
81 | AUTHORS text
82 |
83 |
84 | #
85 | ## These files are binary and should be left untouched
86 | #
87 |
88 | # (binary is a macro for -text -diff)
89 | *.png binary
90 | *.jpg binary
91 | *.jpeg binary
92 | *.gif binary
93 | *.ico binary
94 | *.mov binary
95 | *.mp4 binary
96 | *.mp3 binary
97 | *.flv binary
98 | *.fla binary
99 | *.swf binary
100 | *.gz binary
101 | *.zip binary
102 | *.7z binary
103 | *.ttf binary
104 | *.eot binary
105 | *.woff binary
106 | *.pyc binary
107 | *.pdf binary
108 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Don't check auto-generated stuff into git
2 | coverage
3 | build
4 | lib
5 | node_modules
6 | stats.json
7 |
8 | # Cruft
9 | .DS_Store
10 | npm-debug.log
11 | .idea
12 | yarn-error.log
13 |
14 | # Local scripts
15 | copy-local.sh
16 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .storybook
2 | coverage
3 | src
4 | stories
5 | tests
6 | .babelrc
7 | .editorconfig
8 | .eslintrc.js
9 | .prettierrc
10 | .travis.yml
11 | jest.config.js
12 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | src/**/*.style.js
2 | scripts/**/*.js
3 | .storybook/**/*.js
4 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | ---
2 | semi: false
3 | singleQuote: true
4 | trailingComma: all
5 | arrowParens: always
6 |
--------------------------------------------------------------------------------
/.storybook/addons.js:
--------------------------------------------------------------------------------
1 | import '@storybook/addon-actions/register';
2 | import '@storybook/addon-links/register';
3 |
--------------------------------------------------------------------------------
/.storybook/config.js:
--------------------------------------------------------------------------------
1 | import { configure } from '@storybook/react';
2 |
3 | // automatically import all files ending in *.stories.js
4 | const req = require.context('../stories', true, /.stories.js$/);
5 | function loadStories() {
6 | req.keys().forEach((filename) => req(filename));
7 | }
8 |
9 | configure(loadStories, module);
10 |
--------------------------------------------------------------------------------
/.storybook/preview-head.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - '6'
4 | before_install:
5 | - npm install -g npm@^4
6 | cache: yarn
7 | before_deploy:
8 | - yarn manualPrepublish
9 | deploy:
10 | skip_cleanup: true
11 | provider: npm
12 | email: kegan+isogon@keganmyers.com
13 | api_key:
14 | secure: OtRyB1Eovxs4ahZlVR0jEzmfutSHA0ldhpwE/1F1Ed2ZmBBzouqdSSxnY9urcb1QlM7D/RUXvMnDosUfHVesXkGpp+j3Oar/QmrBGhf2pKiwIvGqY23YKI1NKW8llYuWVgLyCKYF+vCw5lT2OoqRTEUqEV45T3BU3myU/greOzF7Q8M1Wl9DYXlGoIinYJl9Y9gW3YKFvAACaWye8QeCeSzVWDgPkx3EfUvZbhxq/sB3plm5yvNxLckIw9j1+PHjjjl9CVmihjFpleBX+Z9zUUltqBewrV8qappdA7DoXVbkwa69Y+npv+d52JqW2uZgRzi1RxKQK7r+wL7EAZxYq2XCFQUyvb8gAIpJW/1d9Y+W4N+WjuJNCz8dwsFNXOBvcElC+RNor6keBsdsYwIQvRanvBuoHf/oE6LjWerQ/jO+CLHZJ+WXdvSwAE9zxGUbpVz9ZfuAh5YVZkfHptVZgDoF4Ze8Gmjr/nLf7ISbuDL6X9oFAIqrtdaovoeyQddA+AR3tjjLdyJ7OQN8R3AIxVKmjA8xeYSQlW/7hBM3CZS/Wk1ruoXOGsUIb1CPqQdxEr028bn8JIFuqoh6U0rdb5coZaxixFZJT+1fjuz9np9xfUNbsq65i5xFUOu2dsyKgGTgAif1TaNeX2XF3SZPjN7dXRTQDv94Q3IJO73QTmo=
15 | on:
16 | tags: true
17 | repo: isogon/styled-mdl
18 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Code of Conduct
2 |
3 | As contributors and maintainers of this project, and in the interest of
4 | fostering an open and welcoming community, we pledge to respect all people who
5 | contribute through reporting issues, posting feature requests, updating
6 | documentation, submitting pull requests or patches, and other activities.
7 |
8 | We are committed to making participation in this project a harassment-free
9 | experience for everyone, regardless of level of experience, gender, gender
10 | identity and expression, sexual orientation, disability, personal appearance,
11 | body size, race, ethnicity, age, religion, or nationality.
12 |
13 | Examples of unacceptable behavior by participants include:
14 |
15 | * The use of sexualized language or imagery
16 | * Personal attacks
17 | * Trolling or insulting/derogatory comments
18 | * Public or private harassment
19 | * Publishing other's private information, such as physical or electronic
20 | addresses, without explicit permission
21 | * Other unethical or unprofessional conduct
22 |
23 | Project maintainers have the right and responsibility to remove, edit, or
24 | reject comments, commits, code, wiki edits, issues, and other contributions
25 | that are not aligned to this Code of Conduct, or to ban temporarily or
26 | permanently any contributor for other behaviors that they deem inappropriate,
27 | threatening, offensive, or harmful.
28 |
29 | By adopting this Code of Conduct, project maintainers commit themselves to
30 | fairly and consistently applying these principles to every aspect of managing
31 | this project. Project maintainers who do not follow or enforce the Code of
32 | Conduct may be permanently removed from the project team.
33 |
34 | This Code of Conduct applies both within project spaces and in public spaces
35 | when an individual is representing the project or its community.
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
38 | reported by contacting the project maintainer at contact@mxstbr.com. All
39 | complaints will be reviewed and investigated and will result in a response that
40 | is deemed necessary and appropriate to the circumstances. Maintainers are
41 | obligated to maintain confidentiality with regard to the reporter of an
42 | incident.
43 |
44 |
45 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
46 | version 1.3.0, available at
47 | [http://contributor-covenant.org/version/1/3/0/][version]
48 |
49 | [homepage]: http://contributor-covenant.org
50 | [version]: http://contributor-covenant.org/version/1/3/0/
51 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 Maximilian Stoiber
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://www.npmjs.com/package/styled-mdl)
2 | [](https://travis-ci.org/isogon/styled-mdl)
3 |
4 | To get started with development
5 |
6 | 1. clone this repo,
7 | 2. `yarn setup`
8 | 3. `yarn start`
9 |
10 | To use in your project
11 |
12 | 1. `yarn add styled-mdl`
13 | 2. `import { Button } from 'styled-mdl'`
14 | 3. read all the code to figure out how to use it because the scrub developers haven't bothered to write/publish any docs yet.
15 | 4. actually you can clone this repo down
16 | 5. `yarn setup`
17 | 6. `yarn start`
18 | 7. `localhost:3000`
19 | 8. and look at all the demonstrations
20 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | collectCoverageFrom: [
3 | 'src/**/*.js',
4 | '!src/**/*.style.js',
5 | '!src/theme/**/*.js',
6 | '!src/globals/**/*.js',
7 | '!src/index.js',
8 | '!src/*/index.js',
9 | ],
10 | coverageThreshold: {
11 | global: {
12 | statements: 80,
13 | branches: 80,
14 | functions: 90,
15 | lines: 90,
16 | },
17 | },
18 | moduleDirectories: ['node_modules'],
19 | setupTestFrameworkScriptFile: '/tests/_setup/test-bundler.js',
20 | testRegex: 'tests/.*\\.spec\\.js$',
21 | }
22 |
--------------------------------------------------------------------------------
/scripts/demos2Stories.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /* eslint-disable no-console */
4 |
5 | const fs = require('fs');
6 | const path = require('path');
7 | const glob = require('glob');
8 | const startCase = require('lodash/startCase');
9 | const dest = path.resolve(__dirname, '../stories');
10 | const source = path.resolve(__dirname, '../src');
11 |
12 | const components = glob.sync('/components/*', { root: source });
13 |
14 | const createContents = (component, demos) =>
15 | `import React from 'react';
16 | import { storiesOf } from '@storybook/react';
17 | import wrapStory from './decorators/wrapStory';
18 |
19 | ${demos.map((demo) => `import ${demo.component} from '${demo.path}';`).join('\n')}
20 |
21 | storiesOf('${component}', module)
22 | .addDecorator(wrapStory)
23 | ${demos.map(
24 | (demo) => `.add('${demo.name}', () => <${demo.component} />)`
25 | ).join('\n ')};
26 | `;
27 |
28 | const writeStoryForDemos = (demoDir) => {
29 | const componentName = path.basename(demoDir);
30 | const storyFileName = path.resolve(dest, `${componentName}.stories.js`);
31 | const demos = glob
32 | .sync(`/components/${componentName}/demos/*.js`, { root: source })
33 | .filter((file) => !file.endsWith('_shared.js'))
34 | .map((demo) => ({
35 | path: path.relative(dest, demo),
36 | component: startCase(path.basename(demo).replace(/.js$/, '')).replace(/\s/g, ''),
37 | name: startCase(path.basename(demo).replace(/.js$/, '')),
38 | }));
39 |
40 | if (demos.length) {
41 | fs.writeFileSync(storyFileName, createContents(startCase(componentName), demos));
42 | }
43 | };
44 |
45 | console.log(`====================
46 | watching demos
47 | ====================`);
48 |
49 | components.forEach((component) => {
50 | writeStoryForDemos(component);
51 |
52 | if (fs.existsSync(`${component}/demos`)) {
53 | fs.watch(`${component}/demos`, (type) => {
54 | if (type === 'rename') {
55 | console.log('updating stories for', path.basename(component));
56 | writeStoryForDemos(component);
57 | }
58 | });
59 | }
60 | });
61 |
--------------------------------------------------------------------------------
/src/components/Theme/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { ThemeProvider } from 'styled-components'
4 |
5 | import defaultTheme from '../../theme/defaultTheme'
6 |
7 | export function Theme({ children, theme = defaultTheme }) {
8 | return {children}
9 | }
10 |
11 | Theme.propTypes = {
12 | children: PropTypes.node,
13 | theme: PropTypes.object,
14 | }
15 |
--------------------------------------------------------------------------------
/src/components/badges/Badge.js:
--------------------------------------------------------------------------------
1 | import { setPropTypes, setDisplayName, defaultProps, compose } from 'recompose'
2 | import PropTypes from 'prop-types'
3 | import React from 'react'
4 |
5 | import { BadgeWrap, BadgeText } from './Badge.style'
6 | import { proxyStyledStatics } from '../../hocs'
7 |
8 | export const BadgeBase = ({
9 | text,
10 | children,
11 | __StyledComponent__: Styled,
12 | ...props
13 | }) => (
14 |
15 | {children}
16 | {text}
17 |
18 | )
19 |
20 | const enhance = compose(
21 | proxyStyledStatics(BadgeWrap),
22 | setDisplayName('Badge'),
23 | setPropTypes({
24 | text: PropTypes.node,
25 | children: PropTypes.node,
26 | className: PropTypes.string,
27 | }),
28 | defaultProps({
29 | background: true,
30 | }),
31 | )
32 |
33 | export default enhance(BadgeBase)
34 |
--------------------------------------------------------------------------------
/src/components/badges/Badge.style.js:
--------------------------------------------------------------------------------
1 | import { add, divide, subtract, cond, T, always, compose } from 'lodash/fp'
2 | import { call, prop, ifProp } from 'styled-tools'
3 | import { setDisplayName } from 'recompose'
4 | import styled from 'styled-components'
5 |
6 | const negate = (n) => -n
7 | const overlap = prop('overlap')
8 | const forButton = prop('forButton')
9 | const badgeSize = prop('theme.badgeSize')
10 | const badgeFontSize = prop('theme.badgeFontSize')
11 | const badgeOverlap = prop('theme.badgeOverlap')
12 | const badgePadding = prop('theme.badgePadding')
13 | const preferredFont = prop('theme.preferredFont')
14 | const badgeBackground = prop('theme.badgeBackground')
15 | const badgeColor = prop('theme.badgeColor')
16 | const badgeColorInverse = prop('theme.badgeColorInverse')
17 | const badgeBackgroundInverse = prop('theme.badgeBackgroundInverse')
18 |
19 | export const BadgeWrap = setDisplayName('BadgeWrap')(styled.div`
20 | position: relative;
21 | white-space: nowrap;
22 | display: inline-block;
23 | margin-right: ${cond([
24 | [overlap, call(subtract, badgeSize, badgeOverlap)],
25 | [forButton, call(subtract, badgeSize, always(14))],
26 | [T, call(add, badgeSize, badgePadding)],
27 | ])}px;
28 | `)
29 |
30 | export const BadgeText = setDisplayName('BadgeText')(styled.div`
31 | display: flex;
32 | flex-direction: row;
33 | flex-wrap: wrap;
34 | justify-content: center;
35 | align-content: center;
36 | align-items: center;
37 | position: absolute;
38 | top: ${ifProp('forButton', -10, call(divide, badgeSize, always(-2)))}px;
39 | right: ${cond([
40 | [forButton, always(-10)],
41 | [overlap, call(compose(negate, subtract), badgeSize, badgeOverlap)],
42 | [T, call(compose(negate, add), badgeSize, badgePadding)],
43 | ])}px;
44 | font-family: ${preferredFont};
45 | font-weight: 600;
46 | font-size: ${badgeFontSize}px;
47 | width: ${badgeSize}px;
48 | height: ${badgeSize}px;
49 | border-radius: 50%;
50 | color: ${ifProp('background', badgeColor, badgeColorInverse)};
51 | background: ${ifProp('background', badgeBackground, badgeBackgroundInverse)};
52 | box-shadow: ${ifProp('background', 'none', '0 0 1px gray')};
53 | `)
54 |
--------------------------------------------------------------------------------
/src/components/badges/demos/IconOverIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Badge, Icon } from '../../../'
3 |
4 | export default () => (
5 | }>
6 |
7 |
8 | )
9 |
--------------------------------------------------------------------------------
/src/components/badges/demos/IconOverText.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Badge, Icon } from '../../../'
3 |
4 | export default () => }>Walk the dog
5 |
--------------------------------------------------------------------------------
/src/components/badges/demos/NumberOverIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Badge, Icon } from '../../../'
3 |
4 | export default () => (
5 |
6 |
7 |
8 | )
9 |
--------------------------------------------------------------------------------
/src/components/badges/demos/NumberOverText.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Badge } from '../../../'
3 |
4 | export default () => Inbox
5 |
--------------------------------------------------------------------------------
/src/components/badges/demos/TextOverButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Badge, Button } from '../../../'
3 |
4 | export default () => (
5 |
6 |
7 |
8 | )
9 |
--------------------------------------------------------------------------------
/src/components/badges/index.js:
--------------------------------------------------------------------------------
1 | export Badge from './Badge'
2 |
--------------------------------------------------------------------------------
/src/components/buttons/Button.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import {
4 | compose,
5 | setPropTypes,
6 | setDisplayName,
7 | defaultProps,
8 | withProps,
9 | } from 'recompose'
10 |
11 | import { Ripple } from '../ripple'
12 |
13 | import { StyledButton, ButtonInner } from './Button.style'
14 | import { proxyStyledStatics } from '../../hocs'
15 |
16 | export const ButtonBase = ({
17 | children,
18 | text,
19 | shouldShowRipple,
20 | isDark,
21 | isRound,
22 | __StyledComponent__: Button,
23 | ...props
24 | }) => (
25 |
31 | )
32 |
33 | const enhance = compose(
34 | proxyStyledStatics(StyledButton),
35 | setDisplayName('Button'),
36 | setPropTypes({
37 | text: PropTypes.string,
38 | children: PropTypes.node,
39 | ripple: PropTypes.bool,
40 | fab: PropTypes.bool,
41 | icon: PropTypes.bool,
42 | href: PropTypes.string,
43 | to: PropTypes.string,
44 | disabled: PropTypes.bool,
45 | }),
46 | defaultProps({
47 | ripple: true,
48 | }),
49 | withProps((props) => ({
50 | shouldShowRipple: props.ripple && !props.disabled && !props.icon,
51 | isDark:
52 | (props.raised || props.fab) &&
53 | !(props.colored || props.accent || props.primary),
54 | isRound: props.fab || props.icon,
55 | })),
56 | )
57 |
58 | export default enhance(ButtonBase)
59 |
--------------------------------------------------------------------------------
/src/components/buttons/demos/Fab.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Button, Icon } from '../../../'
3 |
4 | export default () => (
5 |
8 | )
9 |
--------------------------------------------------------------------------------
/src/components/buttons/demos/FabAccent.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Button, Icon } from '../../../'
3 |
4 | export default () => (
5 |
8 | )
9 |
--------------------------------------------------------------------------------
/src/components/buttons/demos/FabDisabled.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Button, Icon } from '../../../'
3 |
4 | export default () => (
5 |
8 | )
9 |
--------------------------------------------------------------------------------
/src/components/buttons/demos/FabMini.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Button, Icon } from '../../../'
3 |
4 | export default () => (
5 |
8 | )
9 |
--------------------------------------------------------------------------------
/src/components/buttons/demos/FabPrimary.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Button, Icon } from '../../../'
3 |
4 | export default () => (
5 |
8 | )
9 |
--------------------------------------------------------------------------------
/src/components/buttons/demos/Flat.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Button } from '../../../'
3 |
4 | export default () =>
5 |
--------------------------------------------------------------------------------
/src/components/buttons/demos/FlatAccent.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Button } from '../../../'
3 |
4 | export default () =>
5 |
--------------------------------------------------------------------------------
/src/components/buttons/demos/FlatDisabled.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Button } from '../../../'
3 |
4 | export default () =>
5 |
--------------------------------------------------------------------------------
/src/components/buttons/demos/FlatPrimary.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Button } from '../../../'
3 |
4 | export default () =>
5 |
--------------------------------------------------------------------------------
/src/components/buttons/demos/Icon.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Button, Icon } from '../../../'
3 |
4 | export default () => (
5 |
8 | )
9 |
--------------------------------------------------------------------------------
/src/components/buttons/demos/IconAccent.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Button, Icon } from '../../../'
3 |
4 | export default () => (
5 |
8 | )
9 |
--------------------------------------------------------------------------------
/src/components/buttons/demos/IconDisabled.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Button, Icon } from '../../../'
3 |
4 | export default () => (
5 |
8 | )
9 |
--------------------------------------------------------------------------------
/src/components/buttons/demos/IconMini.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Button, Icon } from '../../../'
3 |
4 | export default () => (
5 |
8 | )
9 |
--------------------------------------------------------------------------------
/src/components/buttons/demos/IconPrimary.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Button, Icon } from '../../../'
3 |
4 | export default () => (
5 |
8 | )
9 |
--------------------------------------------------------------------------------
/src/components/buttons/demos/Raised.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Button } from '../../../'
3 |
4 | export default () =>
5 |
--------------------------------------------------------------------------------
/src/components/buttons/demos/RaisedAccent.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Button } from '../../../'
3 |
4 | export default () => (
5 |
8 | )
9 |
--------------------------------------------------------------------------------
/src/components/buttons/demos/RaisedDisabled.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Button } from '../../../'
3 |
4 | export default () => (
5 |
8 | )
9 |
--------------------------------------------------------------------------------
/src/components/buttons/demos/RaisedPrimary.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Button } from '../../../'
3 |
4 | export default () => (
5 |
8 | )
9 |
--------------------------------------------------------------------------------
/src/components/buttons/index.js:
--------------------------------------------------------------------------------
1 | export Button from './Button'
2 |
--------------------------------------------------------------------------------
/src/components/cards/Card.style.js:
--------------------------------------------------------------------------------
1 | import styled, { css } from 'styled-components'
2 | import { setDisplayName } from 'recompose'
3 | import { getters as g } from '../../util'
4 |
5 | export const Card = setDisplayName('Card')(styled.div`
6 | display: flex;
7 | flex-direction: column;
8 | font-size: ${g.cardFontSize}px;
9 | font-weight: 400;
10 | min-height: ${g.cardHeight}px;
11 | overflow: hidden;
12 | width: ${g.cardWidth}px;
13 | z-index: ${g.cardZIndex};
14 | position: relative;
15 | background: ${g.cardBackgroundColor};
16 | border-radius: 2px;
17 | box-sizing: border-box;
18 | ${({ expand }) => expand && css`
19 | flex-grow: 1;
20 | `}
21 | `)
22 |
--------------------------------------------------------------------------------
/src/components/cards/CardActions.style.js:
--------------------------------------------------------------------------------
1 | import styled, { css } from 'styled-components'
2 | import { setDisplayName } from 'recompose'
3 | import { getters as g } from '../../util'
4 |
5 | export const CardActions = setDisplayName('CardActions')(styled.div`
6 | font-size: ${g.cardActionsFontSize}px;
7 | line-height: normal;
8 | width: 100%;
9 | background-color: rgba(0,0,0,0);
10 | padding: 8px;
11 | box-sizing: border-box;
12 | ${({ border }) => border && css`
13 | border-top: 1px solid ${g.cardBorderColor};
14 | `}
15 | `)
16 |
--------------------------------------------------------------------------------
/src/components/cards/CardMedia.style.js:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components'
2 | import { setDisplayName } from 'recompose'
3 | import { getters as g } from '../../util'
4 |
5 | export const CardMedia = setDisplayName('CardMedia')(styled.div`
6 | background-color: ${g.cardImagePlaceholderColor};
7 | background-repeat: repeat;
8 | background-position: 50% 50%;
9 | background-size: cover;
10 | background-origin: padding-box;
11 | background-attachment: scroll;
12 | box-sizing: border-box;
13 | `)
14 |
--------------------------------------------------------------------------------
/src/components/cards/CardMenu.style.js:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components'
2 | import { setDisplayName } from 'recompose'
3 |
4 | export const CardMenu = setDisplayName('CardMenu')(styled.div`
5 | position: absolute;
6 | right: 16px;
7 | top: 16px;
8 | `)
9 |
--------------------------------------------------------------------------------
/src/components/cards/CardSubtitleText.style.js:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components'
2 | import { setDisplayName } from 'recompose'
3 | import { getters as g } from '../../util'
4 |
5 | export const CardSubtitleText = setDisplayName('CardSubtitleText')(styled.h4`
6 | font-size: ${g.cardSubtitleFontSize}px;
7 | color: ${g.cardSubtitleColor}px;
8 | margin: 0;
9 | `)
10 |
--------------------------------------------------------------------------------
/src/components/cards/CardSupportingText.style.js:
--------------------------------------------------------------------------------
1 | import styled, { css } from 'styled-components'
2 | import { setDisplayName } from 'recompose'
3 | import { getters as g } from '../../util'
4 |
5 | export const CardSupportingText = setDisplayName('CardSupportingText')(styled.div`
6 | color: ${g.cardSupportingTextTextColor};
7 | font-size: ${g.cardSupportingTextFontSize}px;
8 | line-height: ${g.cardSupportingTextLineHeight}px;
9 | overflow: hidden;
10 | padding: ${g.cardVerticalPadding}px ${g.cardHorizontalPadding}px;
11 | width: 90%;
12 | ${({ border }) => border && css`
13 | border-bottom: 1px solid ${g.cardBorderColor};
14 | `}
15 | `)
16 |
--------------------------------------------------------------------------------
/src/components/cards/CardTitle.style.js:
--------------------------------------------------------------------------------
1 | import styled, { css } from 'styled-components'
2 | import { setDisplayName } from 'recompose'
3 | import { getters as g } from '../../util'
4 |
5 | export const CardTitle = setDisplayName('CardTitle')(styled.header`
6 | align-items: center;
7 | color: ${g.cardTextColor};
8 | display: block;
9 | display: flex;
10 | line-height: normal;
11 | padding: ${g.cardVerticalPadding}px ${g.cardHorizontalPadding}px;
12 | perspective-origin: ${g.cardTitlePerspectiveOriginX}px ${g.cardTitlePerspectiveOriginY}px;
13 | transform-origin: ${g.cardTitleTransformOriginX}px ${g.cardTitleTransformOriginY}px;
14 | box-sizing: border-box;
15 | ${({ border }) => border && css`
16 | border-bottom: 1px solid ${g.cardBorderColor};
17 | `}
18 | ${({ expand }) => expand && css`
19 | flex-grow: 1;
20 | `}
21 | `)
22 |
--------------------------------------------------------------------------------
/src/components/cards/CardTitleText.style.js:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components'
2 | import { setDisplayName } from 'recompose'
3 | import { getters as g } from '../../util'
4 |
5 | export const CardTitleText = setDisplayName('CardTitleText')(styled.h1`
6 | align-self: flex-end;
7 | color: inherit;
8 | display: block;
9 | display: flex;
10 | font-size: ${g.cardTitleFontSize}px;
11 | font-weight: ${g.cardTitleTextFontWeight};
12 | line-height: normal;
13 | overflow: hidden;
14 | transform-origin: ${g.cardTitleTextTransformOriginX}px ${g.cardTitleTextTransformOriginY}px;
15 | margin: 0;
16 | `)
17 |
--------------------------------------------------------------------------------
/src/components/cards/demos/Event.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | import {
4 | Card,
5 | CardActions,
6 | CardTitle,
7 | CardTitleText,
8 | shadow2dp,
9 | Button,
10 | Spacer,
11 | Icon,
12 | } from '../../../'
13 |
14 | const EventCard = Card.extend`
15 | ${shadow2dp()} width: 256px;
16 | height: 256px;
17 | background: #3e4eb8;
18 | align-self: flex-start;
19 | `
20 |
21 | const EventInfo = CardTitleText.extend`
22 | margin-top: 0;
23 | align-self: flex-start;
24 | color: #fff;
25 | font-weight: normal;
26 | font-size: 24px;
27 | line-height: 32px;
28 | `
29 |
30 | const EventActions = CardActions.extend`
31 | border-color: rgba(255, 255, 255, 0.2);
32 | display: flex;
33 | box-sizing: border-box;
34 | align-items: center;
35 | `
36 |
37 | const EventIcon = Icon.extend`
38 | padding-right: 10px;
39 | color: #fff;
40 | `
41 |
42 | const WhiteButton = Button.extend`
43 | color: #fff;
44 | `
45 |
46 | export default () => (
47 |
48 |
49 |
50 | Featured event:
51 | May 24, 2016
52 | 7-11pm
53 |
54 |
55 |
56 | Add to calenar
57 |
58 |
59 |
60 |
61 | )
62 |
--------------------------------------------------------------------------------
/src/components/cards/demos/Image.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from 'styled-components'
3 |
4 | import { Card, CardActions, CardTitle, shadow2dp } from '../../../'
5 |
6 | const ImageCard = Card.extend`
7 | ${shadow2dp()} width: 256px;
8 | height: 256px;
9 | background: url('https://getmdl.io/assets/demos/image_card.jpg') center /
10 | cover;
11 | `
12 |
13 | const Footer = CardActions.extend`
14 | height: 52px;
15 | padding: 16px;
16 | background: rgba(0, 0, 0, 0.2);
17 | `
18 |
19 | const Filename = styled.span`
20 | color: #fff;
21 | font-size: 14px;
22 | font-weight: 500;
23 | `
24 |
25 | export default () => (
26 |
27 |
28 |
31 |
32 | )
33 |
--------------------------------------------------------------------------------
/src/components/cards/demos/Square.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | import {
4 | Button,
5 | Card,
6 | CardActions,
7 | CardSupportingText,
8 | CardTitle,
9 | CardTitleText,
10 | shadow2dp,
11 | } from '../../../'
12 |
13 | export const DemoCardSquare = Card.extend`
14 | ${shadow2dp()} width: 320px;
15 | height: 320px;
16 | `
17 |
18 | export const DemoCardTitle = CardTitle.extend`
19 | color: #fff;
20 | height: 176px;
21 | background: url('https://getmdl.io/assets/demos/dog.png') bottom right 15%
22 | no-repeat #46b6ac;
23 | `
24 |
25 | export default () => (
26 |
27 |
28 | Update
29 |
30 |
31 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenan convallis.
32 |
33 |
34 |
35 |
36 |
37 | )
38 |
--------------------------------------------------------------------------------
/src/components/cards/demos/Wide.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { MdShare } from 'react-icons/lib/md'
3 |
4 | import {
5 | Button,
6 | Card,
7 | CardActions,
8 | CardMenu,
9 | CardSupportingText,
10 | CardTitle,
11 | CardTitleText,
12 | shadow2dp,
13 | } from '../../../'
14 |
15 | export const DemoCardWide = Card.extend`
16 | ${shadow2dp()} width: 512px;
17 | `
18 |
19 | export const DemoCardTitle = CardTitle.extend`
20 | color: #fff;
21 | height: 176px;
22 | background: url('https://getmdl.io/assets/demos/welcome_card.jpg') center /
23 | cover;
24 | `
25 |
26 | export const DemoCardMenu = CardMenu.extend`
27 | color: #fff;
28 | `
29 |
30 | export default () => (
31 |
32 |
33 | Welcome
34 |
35 |
36 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris sagittis
37 | pellentesque lacus eleifend lacinia...
38 |
39 |
40 |
41 |
42 |
43 |
46 |
47 |
48 | )
49 |
--------------------------------------------------------------------------------
/src/components/cards/index.js:
--------------------------------------------------------------------------------
1 | export { Card } from './Card.style'
2 | export { CardActions } from './CardActions.style'
3 | export { CardMedia } from './CardMedia.style'
4 | export { CardMenu } from './CardMenu.style'
5 | export { CardSubtitleText } from './CardSubtitleText.style'
6 | export { CardSupportingText } from './CardSupportingText.style'
7 | export { CardTitle } from './CardTitle.style'
8 | export { CardTitleText } from './CardTitleText.style'
9 |
--------------------------------------------------------------------------------
/src/components/checkbox/Checkbox.js:
--------------------------------------------------------------------------------
1 | import { compose, setDisplayName, setPropTypes } from 'recompose'
2 | import PropTypes from 'prop-types'
3 | import React from 'react'
4 |
5 | import {
6 | CheckboxWrap,
7 | CheckboxButton,
8 | CheckboxLabel,
9 | BoxOutline,
10 | TickOutline,
11 | } from './Checkbox.style'
12 | import { proxyStyledStatics } from '../../hocs'
13 |
14 | export const CheckboxBase = ({
15 | label,
16 | __StyledComponent__: Styled,
17 | ...props
18 | }) => (
19 |
20 |
21 | {label && {label}}
22 |
23 |
24 |
25 |
26 | )
27 |
28 | const enhance = compose(
29 | proxyStyledStatics(CheckboxWrap),
30 | setDisplayName('Checkbox'),
31 | setPropTypes({
32 | label: PropTypes.string,
33 | disabled: PropTypes.bool,
34 | }),
35 | )
36 |
37 | export default enhance(CheckboxBase)
38 |
--------------------------------------------------------------------------------
/src/components/checkbox/Checkbox.style.js:
--------------------------------------------------------------------------------
1 | import { setDisplayName } from 'recompose'
2 | import styled, { css } from 'styled-components'
3 |
4 | import { getters as g } from '../../util'
5 | import { mask, bg } from './images'
6 | import { materialAnimationDefault } from '../../mixins'
7 |
8 | export const CheckboxWrap = setDisplayName('CheckboxWrap')(styled.label`
9 | position: relative;
10 | font-size: ${g.radioLabelFontSize}px;
11 | line-height: ${g.radioLabelHeight}px;
12 | display: inline-block;
13 | vertical-align: middle;
14 | box-sizing: border-box;
15 | height: ${g.radioLabelHeight}px;
16 | margin: 0;
17 | padding-left: ${({ theme }) => theme.radioButtonSize + theme.radioPadding}px;
18 | `)
19 |
20 | export const CheckboxButton = setDisplayName('CheckboxButton')(styled.input`
21 | line-height: ${g.radioLabelHeight}px;
22 | position: absolute;
23 | width: 0;
24 | height: 0;
25 | margin: 0;
26 | padding: 0;
27 | opacity: 0;
28 | -ms-appearance: none;
29 | -moz-appearance: none;
30 | -webkit-appearance: none;
31 | appearance: none;
32 | border: none;
33 | &:checked ~ div {
34 | border: 2px solid ${g.checkboxColor};
35 | }
36 | &:checked ~ div > div {
37 | background-color: ${g.checkboxColor};
38 | background-image: url(${bg});
39 | }
40 | `)
41 |
42 | export const BoxOutline = setDisplayName('BoxOutline')(styled.div`
43 | position: absolute;
44 | top: ${g.radioTopOffset}px;
45 | left: 0;
46 | display: inline-block;
47 | box-sizing: border-box;
48 | width: ${g.radioButtonSize}px;
49 | height: ${g.radioButtonSize}px;
50 | margin: 0;
51 | cursor: pointer;
52 | overflow: hidden;
53 | border: 2px solid ${g.checkboxOffColor};
54 | border-radius: 2px;
55 | z-index: 2;
56 | ${({ disabled }) =>
57 | disabled &&
58 | css`
59 | border: 2px solid ${g.checkboxDisabledColor};
60 | cursor: auto;
61 | `};
62 | `)
63 |
64 | export const TickOutline = setDisplayName('TickOutline')(styled.div`
65 | position: absolute;
66 | top: 0;
67 | left: 0;
68 | bottom: 0;
69 | right: 0;
70 | transform: scale(1.01);
71 | mask: url(${mask});
72 | background: transparent;
73 | transition-property: background;
74 | ${materialAnimationDefault('0.28s')}
75 | ${({ disabled }) =>
76 | disabled &&
77 | css`
78 | background-color: ${g.checkboxDisabledColor};
79 | `};
80 | `)
81 |
82 | export const CheckboxLabel = setDisplayName('CheckboxLabel')(styled.span`
83 | cursor: pointer;
84 |
85 | ${({ disabled }) =>
86 | disabled &&
87 | css`
88 | color: ${g.checkboxDisabledColor};
89 | cursor: auto;
90 | `};
91 | `)
92 |
--------------------------------------------------------------------------------
/src/components/checkbox/demos/Checkbox.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Checkbox } from '../../../'
3 |
4 | export default () =>
5 |
--------------------------------------------------------------------------------
/src/components/checkbox/images.js:
--------------------------------------------------------------------------------
1 | const mask =
2 | 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgdmVyc2lvbj0iMS4xIgogICB2aWV3Qm94PSIwIDAgMSAxIgogICBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWluWU1pbiBtZWV0Ij4KICA8ZGVmcz4KICAgIDxjbGlwUGF0aCBpZD0iY2xpcCI+CiAgICAgIDxwYXRoCiAgICAgICAgIGQ9Ik0gMCwwIDAsMSAxLDEgMSwwIDAsMCB6IE0gMC44NTM0Mzc1LDAuMTY3MTg3NSAwLjk1OTY4NzUsMC4yNzMxMjUgMC40MjkzNzUsMC44MDM0Mzc1IDAuMzIzMTI1LDAuOTA5Njg3NSAwLjIxNzE4NzUsMC44MDM0Mzc1IDAuMDQwMzEyNSwwLjYyNjg3NSAwLjE0NjU2MjUsMC41MjA2MjUgMC4zMjMxMjUsMC42OTc1IDAuODUzNDM3NSwwLjE2NzE4NzUgeiIKICAgICAgICAgc3R5bGU9ImZpbGw6I2ZmZmZmZjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZSIgLz4KICAgIDwvY2xpcFBhdGg+CiAgICA8bWFzayBpZD0ibWFzayIgbWFza1VuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgbWFza0NvbnRlbnRVbml0cz0ib2JqZWN0Qm91bmRpbmdCb3giPgogICAgICA8cGF0aAogICAgICAgICBkPSJNIDAsMCAwLDEgMSwxIDEsMCAwLDAgeiBNIDAuODUzNDM3NSwwLjE2NzE4NzUgMC45NTk2ODc1LDAuMjczMTI1IDAuNDI5Mzc1LDAuODAzNDM3NSAwLjMyMzEyNSwwLjkwOTY4NzUgMC4yMTcxODc1LDAuODAzNDM3NSAwLjA0MDMxMjUsMC42MjY4NzUgMC4xNDY1NjI1LDAuNTIwNjI1IDAuMzIzMTI1LDAuNjk3NSAwLjg1MzQzNzUsMC4xNjcxODc1IHoiCiAgICAgICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmUiIC8+CiAgICA8L21hc2s+CiAgPC9kZWZzPgogIDxyZWN0CiAgICAgd2lkdGg9IjEiCiAgICAgaGVpZ2h0PSIxIgogICAgIHg9IjAiCiAgICAgeT0iMCIKICAgICBjbGlwLXBhdGg9InVybCgjY2xpcCkiCiAgICAgc3R5bGU9ImZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZSIgLz4KPC9zdmc+Cg=='
3 |
4 | const bg =
5 | 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgdmVyc2lvbj0iMS4xIgogICB2aWV3Qm94PSIwIDAgMSAxIgogICBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWluWU1pbiBtZWV0Ij4KICA8cGF0aAogICAgIGQ9Ik0gMC4wNDAzODA1OSwwLjYyNjc3NjcgMC4xNDY0NDY2MSwwLjUyMDcxMDY4IDAuNDI5Mjg5MzIsMC44MDM1NTMzOSAwLjMyMzIyMzMsMC45MDk2MTk0MSB6IE0gMC4yMTcxNTcyOSwwLjgwMzU1MzM5IDAuODUzNTUzMzksMC4xNjcxNTcyOSAwLjk1OTYxOTQxLDAuMjczMjIzMyAwLjMyMzIyMzMsMC45MDk2MTk0MSB6IgogICAgIGlkPSJyZWN0Mzc4MCIKICAgICBzdHlsZT0iZmlsbDojZmZmZmZmO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lIiAvPgo8L3N2Zz4K'
6 |
7 | export { mask, bg }
8 |
--------------------------------------------------------------------------------
/src/components/checkbox/index.js:
--------------------------------------------------------------------------------
1 | export Checkbox from './Checkbox'
2 |
--------------------------------------------------------------------------------
/src/components/chips/ButtonChip.js:
--------------------------------------------------------------------------------
1 | import { compose, setPropTypes, setDisplayName } from 'recompose'
2 | import PropTypes from 'prop-types'
3 | import React from 'react'
4 |
5 | import { ButtonChipStyle, ChipText } from './Chip.style'
6 | import { proxyStyledStatics } from '../../hocs'
7 | import ChipContact from './ChipContact'
8 |
9 | export const ButtonChipBase = ({
10 | contact,
11 | children,
12 | __StyledComponent__: Styled,
13 | ...props
14 | }) => (
15 |
16 | {contact && }
17 | {children}
18 |
19 | )
20 |
21 | const enhance = compose(
22 | proxyStyledStatics(ButtonChipStyle),
23 | setDisplayName('ButtonChip'),
24 | setPropTypes({
25 | contact: PropTypes.shape({
26 | color: PropTypes.string,
27 | textColor: PropTypes.string,
28 | text: PropTypes.string,
29 | src: PropTypes.string,
30 | }),
31 | children: PropTypes.node.isRequired,
32 | }),
33 | )
34 |
35 | export default enhance(ButtonChipBase)
36 |
--------------------------------------------------------------------------------
/src/components/chips/Chip.js:
--------------------------------------------------------------------------------
1 | import { compose, setPropTypes, setDisplayName } from 'recompose'
2 | import PropTypes from 'prop-types'
3 | import React from 'react'
4 |
5 | import { Icon } from '../icons'
6 | import { ChipStyle, ChipText, ChipAction } from './Chip.style'
7 | import { proxyStyledStatics } from '../../hocs'
8 | import ChipContact from './ChipContact'
9 |
10 | export const ChipBase = ({
11 | deletable,
12 | contact,
13 | children,
14 | onClickDelete,
15 | __StyledComponent__: Styled,
16 | }) => (
17 |
18 | {contact && }
19 | {children && {children}}
20 | {deletable && (
21 |
22 |
23 |
24 | )}
25 |
26 | )
27 |
28 | const enhance = compose(
29 | proxyStyledStatics(ChipStyle),
30 | setDisplayName('Chip'),
31 | setPropTypes({
32 | deletable: PropTypes.bool,
33 | contact: PropTypes.shape({
34 | color: PropTypes.string,
35 | textColor: PropTypes.string,
36 | text: PropTypes.string,
37 | src: PropTypes.string,
38 | }),
39 | children: PropTypes.node,
40 | onClickDelete: PropTypes.func,
41 | }),
42 | )
43 |
44 | export default enhance(ChipBase)
45 |
--------------------------------------------------------------------------------
/src/components/chips/Chip.style.js:
--------------------------------------------------------------------------------
1 | import { compose, defaultProps, setDisplayName } from 'recompose'
2 | import styled, { css } from 'styled-components'
3 |
4 | import { getters as g } from '../../util'
5 | import { shadow2dp } from '../../mixins'
6 |
7 | export const ChipStyle = setDisplayName('ChipStyle')(styled.span`
8 | height: ${g.chipHeight}px;
9 | font-family: ${g.preferredFont};
10 | line-height: ${g.chipHeight}px;
11 | padding: 0 12px;
12 | border: 0;
13 | border-radius: ${({ theme }) => theme.chipHeight / 2}px;
14 | background-color: ${g.chipBgColor};
15 | display: inline-block;
16 | color: ${g.textColorPrimary};
17 | margin: 2px 0;
18 | font-size: 0;
19 | white-space: nowrap;
20 | &:focus {
21 | outline: 0;
22 | ${shadow2dp()}
23 | }
24 | &:active {
25 | background-color: ${g.chipBgActiveColor};
26 | }
27 | ${({ deletable }) => deletable && css`
28 | padding-right: 4px;
29 | `}
30 | ${({ contact }) => contact && css`
31 | padding-left: 0px;
32 | `}
33 | `)
34 |
35 | export const ButtonChipStyle = ChipStyle.withComponent('button')
36 |
37 |
38 | export const ChipText = setDisplayName('ChipText')(styled.span`
39 | font-size: ${g.chipFontSize}px;
40 | vertical-align: middle;
41 | display: inline-block;
42 | `)
43 |
44 | export const ChipAction = compose(
45 | defaultProps({
46 | type: 'button',
47 | }),
48 | setDisplayName('ChipAction'),
49 | )(styled.button`
50 | height: 24px;
51 | width: 24px;
52 | font-size: 24px;
53 | background: transparent;
54 | opacity: 0.54;
55 | display: inline-block;
56 | cursor: pointer;
57 | text-align: center;
58 | vertical-align: middle;
59 | padding: 0;
60 | margin: 0 0 0 4px;
61 | text-decoration: none;
62 | color: ${g.textColorPrimary};
63 | border: none;
64 | outline: none;
65 | overflow: hidden;
66 | `)
67 |
68 | export const ChipContactImg = setDisplayName('ChipContactImg')(styled.img`
69 | height: ${g.chipHeight}px;
70 | width: ${g.chipHeight}px;
71 | border-radius: ${({ theme }) => theme.chipHeight / 2}px;
72 | display: inline-block;
73 | vertical-align: middle;
74 | margin-right: 8px;
75 | overflow: hidden;
76 | text-align: center;
77 | font-size: 18px;
78 | line-height: 32px;
79 | background-color: ${g.rgbFromProp('color', g.colorPrimary)};
80 | color: ${({ textColor }) => textColor || '#FFF'};
81 | `)
82 |
83 | export const ChipContactSpan = setDisplayName('ChipContactSpan')(
84 | ChipContactImg.withComponent('span')
85 | )
86 |
--------------------------------------------------------------------------------
/src/components/chips/ChipContact.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 |
4 | import { ChipContactImg, ChipContactSpan } from './Chip.style'
5 |
6 | export default function ChipContact({ text, src, ...props }) {
7 | return src ? (
8 |
9 | ) : (
10 | {text}
11 | )
12 | }
13 |
14 | ChipContact.propTypes = {
15 | src: PropTypes.string,
16 | text: PropTypes.string,
17 | }
18 |
--------------------------------------------------------------------------------
/src/components/chips/demos/Basic.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Chip } from '../../../'
3 |
4 | export default () => Basic Chip
5 |
--------------------------------------------------------------------------------
/src/components/chips/demos/Button.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { ButtonChip } from '../../../'
3 |
4 | export default () => Button Chip
5 |
--------------------------------------------------------------------------------
/src/components/chips/demos/Contact.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Chip } from '../../../'
3 |
4 | /* eslint-disable no-alert */
5 | export default () => (
6 |
7 | Contact Chip
8 |
9 | )
10 |
--------------------------------------------------------------------------------
/src/components/chips/demos/Deletable.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Chip } from '../../../'
3 |
4 | /* eslint-disable no-alert */
5 | export default () => (
6 | alert('You clicked delete!')}>
7 | Basic Chip
8 |
9 | )
10 |
--------------------------------------------------------------------------------
/src/components/chips/demos/DeletableContact.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Chip } from '../../../'
3 |
4 | const avatarImg = 'https://getmdl.io/templates/dashboard/images/user.jpg'
5 |
6 | export default () => (
7 |
8 | Deletable Contact Chip
9 |
10 | )
11 |
--------------------------------------------------------------------------------
/src/components/chips/index.js:
--------------------------------------------------------------------------------
1 | export Chip from './Chip'
2 | export ButtonChip from './ButtonChip'
3 | export ChipContact from './ChipContact'
4 |
--------------------------------------------------------------------------------
/src/components/dialog/Dialog.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactModal from 'react-modal'
3 |
4 | import { DialogStyle, fadeIn } from './Dialog.style'
5 |
6 | const style = {
7 | overlay: {
8 | position: 'fixed',
9 | top: 0,
10 | left: 0,
11 | right: 0,
12 | bottom: 0,
13 | backgroundColor: 'rgba(100, 100, 100, 0.3)',
14 | zIndex: 999,
15 | display: 'flex',
16 | alignItems: 'center',
17 | justifyContent: 'center',
18 | animation: `${fadeIn} 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards`,
19 | },
20 | content: {
21 | position: 'reltive',
22 | top: 0,
23 | left: 0,
24 | right: 0,
25 | bottom: 0,
26 | height: 'auto',
27 | width: 'auto',
28 | background: 'transparent',
29 | zIndex: 1000,
30 | padding: 0,
31 | margin: 0,
32 | border: 0,
33 | overflow: 'visible',
34 | },
35 | }
36 |
37 | const DialogWrap = ({ className, children, ...props }) => (
38 |
39 | {children}
40 |
41 | )
42 |
43 | const Dialog = DialogStyle.withComponent(DialogWrap)
44 |
45 | Dialog.displayName = 'Dialog'
46 |
47 | export default Dialog
48 |
--------------------------------------------------------------------------------
/src/components/dialog/Dialog.style.js:
--------------------------------------------------------------------------------
1 | import styled, { css, keyframes } from 'styled-components'
2 |
3 | import { shadow24dp } from '../../mixins'
4 | import { getters as g } from '../../util'
5 |
6 | const flyIn = keyframes`
7 | from {
8 | transform: translate(0, 5vh);
9 | }
10 | to {
11 | transform: translate(0, 0);
12 | }
13 | `
14 |
15 | export const fadeIn = keyframes`
16 | from {
17 | opacity: 0;
18 | }
19 | to {
20 | opacity: 1;
21 | }
22 | `
23 |
24 | export const DialogStyle = styled.div.attrs({
25 | width: ({ size }) => `${parseInt(size || 5, 10) * 56}px`,
26 | })`
27 | background: white;
28 | width: ${({ width }) => width};
29 | max-width: calc(100vw - 144px);
30 | max-height: 80vh;
31 | margin-top: -15vh;
32 | border-radius: 3px;
33 | ${shadow24dp()}
34 | overflow: auto;
35 | animation: ${fadeIn} 0.3s ${g.animationCurveDefault} forwards,
36 | ${flyIn} 0.3s ${g.animationCurveLinearOutSlowIn} forwards;
37 | `
38 |
39 | export const DialogTitle = styled.h1`
40 | padding: 24px 24px 0;
41 | margin: 0;
42 | font-size: 20px;
43 | line-height: 20px;
44 | font-weight: 500;
45 | `
46 |
47 | export const DialogContent = styled.div`
48 | padding: 20px 24px 24px;
49 | font-size: 16px;
50 | line-height: 24px;
51 | color: ${g.dialogContentColor};
52 | `
53 |
54 | export const DialogActions = styled.div`
55 | position: relative;
56 | padding: 8px 0 8px 24px;
57 | display: flex;
58 | flex-direction: row-reverse;
59 | flex-wrap: wrap;
60 | > * {
61 | margin-right: 8px;
62 | height: 36px;
63 | }
64 | ${({ fullWidth }) => fullWidth && css`
65 | padding: 0 0 8px 0;
66 | right: 0;
67 | > * {
68 | height: 48px;
69 | flex: 0 0 auto;
70 | width: 100%;
71 | padding-right: 16px;
72 | margin-right: 0;
73 | text-align: right;
74 | justify-content: flex-end;
75 | border-radius: 0;
76 | }
77 | `}
78 | `
79 |
--------------------------------------------------------------------------------
/src/components/dialog/demos/Basic.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { withStateHandlers } from 'recompose'
3 | import {
4 | Dialog,
5 | DialogTitle,
6 | DialogActions,
7 | DialogContent,
8 | Button,
9 | } from '../../../'
10 |
11 | export default withStateHandlers(
12 | { isShowingDialog: false },
13 | {
14 | showDialog: () => () => ({ isShowingDialog: true }),
15 | hideDialog: () => () => ({ isShowingDialog: false }),
16 | },
17 | )(({ showDialog, hideDialog, isShowingDialog }) => (
18 |
19 |
20 |
37 |
38 | ))
39 |
--------------------------------------------------------------------------------
/src/components/dialog/demos/FullWidthActions.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { withStateHandlers } from 'recompose'
3 | import {
4 | Dialog,
5 | DialogTitle,
6 | DialogActions,
7 | DialogContent,
8 | Button,
9 | } from '../../../'
10 |
11 | const mdSpecLink =
12 | 'https://www.google.com/design/spec/components/dialogs.html#dialogs-specs'
13 |
14 | export default withStateHandlers(
15 | { isShowingDialog: false },
16 | {
17 | showDialog: () => () => ({ isShowingDialog: true }),
18 | hideDialog: () => () => ({ isShowingDialog: false }),
19 | },
20 | )(({ showDialog, hideDialog, isShowingDialog }) => (
21 |
22 |
23 |
42 |
43 | ))
44 |
--------------------------------------------------------------------------------
/src/components/dialog/index.js:
--------------------------------------------------------------------------------
1 | export { DialogTitle, DialogActions, DialogContent } from './Dialog.style'
2 |
3 | export Dialog from './Dialog'
4 |
--------------------------------------------------------------------------------
/src/components/fonts/MaterialIcons.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const MaterialIconsFont = () => (
4 |
8 | )
9 |
10 | export default MaterialIconsFont
11 |
--------------------------------------------------------------------------------
/src/components/fonts/Roboto.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 |
4 | const RobotoFont = ({ variants = '300,400,400i,700' }) => (
5 |
9 | )
10 |
11 | RobotoFont.propTypes = {
12 | variants: PropTypes.string,
13 | }
14 |
15 | export default RobotoFont
16 |
--------------------------------------------------------------------------------
/src/components/fonts/index.js:
--------------------------------------------------------------------------------
1 | export MaterialIcons from './MaterialIcons'
2 | export Roboto from './Roboto'
3 |
--------------------------------------------------------------------------------
/src/components/icons/Icon.js:
--------------------------------------------------------------------------------
1 | import { compose, setDisplayName, setPropTypes, withProps } from 'recompose'
2 | import { prop, always, cond } from 'lodash/fp'
3 | import PropTypes from 'prop-types'
4 | import React from 'react'
5 |
6 | import { IconStyle } from './Icon.style'
7 | import { proxyStyledStatics } from '../../hocs'
8 |
9 | const Icon = ({ name, __StyledComponent__: Styled, ...props }) => (
10 | {name}
11 | )
12 |
13 | const enhance = compose(
14 | proxyStyledStatics(IconStyle),
15 | setDisplayName('Icon'),
16 | setPropTypes({
17 | xs: PropTypes.bool,
18 | sm: PropTypes.bool,
19 | lg: PropTypes.bool,
20 | xl: PropTypes.bool,
21 | size: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
22 | name: PropTypes.string.isRequired,
23 | __StyledComponent__: PropTypes.func.isRequired,
24 | }),
25 | withProps((p) => ({
26 | size: cond([
27 | [prop('size'), prop('size')],
28 | [prop('xs'), always('12')],
29 | [prop('sm'), always('16')],
30 | [prop('lg'), always('32')],
31 | [prop('xl'), always('64')],
32 | ])(p),
33 | })),
34 | )
35 |
36 | export default enhance(Icon)
37 |
--------------------------------------------------------------------------------
/src/components/icons/Icon.style.js:
--------------------------------------------------------------------------------
1 | import { setDisplayName } from 'recompose'
2 | import styled from 'styled-components'
3 | import { ifProp } from 'styled-tools'
4 |
5 | import { typoIcon } from '../../mixins'
6 |
7 | export const IconStyle = setDisplayName('IconStyle')(styled.i`
8 | ${typoIcon()}
9 | font-size: ${ifProp('size', (p) => `${p.size}px`, 'inherit')};
10 | line-height: ${ifProp('size', (p) => `${p.size}px`, 'inherit')};;
11 | `)
12 |
--------------------------------------------------------------------------------
/src/components/icons/index.js:
--------------------------------------------------------------------------------
1 | export Icon from './Icon'
2 |
--------------------------------------------------------------------------------
/src/components/layout/Spacer.style.js:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components'
2 |
3 | export default styled.div`
4 | flex-grow: 1;
5 | `
6 |
--------------------------------------------------------------------------------
/src/components/layout/index.js:
--------------------------------------------------------------------------------
1 | export Spacer from './Spacer.style'
2 |
--------------------------------------------------------------------------------
/src/components/list/demos/AvatarsAndActions.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {
3 | List,
4 | ListItem,
5 | LiPrimary,
6 | LiAction,
7 | LiSecondary,
8 | LiAvatar,
9 | Button,
10 | Icon,
11 | } from '../../../'
12 |
13 | export default () => (
14 |
15 |
16 |
17 |
18 | Bryan Cranston
19 |
20 |
21 |
22 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | Aaron Paul
32 |
33 |
34 |
35 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | Bob Odenkirk
45 |
46 |
47 |
48 |
51 |
52 |
53 |
54 |
55 | )
56 |
--------------------------------------------------------------------------------
/src/components/list/demos/AvatarsAndControls.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {
3 | List,
4 | ListItem,
5 | LiAction,
6 | LiSecondary,
7 | LiPrimary,
8 | LiAvatar,
9 | Checkbox,
10 | Radio,
11 | Switch,
12 | Icon,
13 | } from '../../../'
14 |
15 | export default () => (
16 |
17 |
18 |
19 |
20 |
21 |
22 | Bryan Cranston
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | Aaron Paul
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | Bob Odenkirk
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | )
58 |
--------------------------------------------------------------------------------
/src/components/list/demos/Icons.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { List, ListItem, LiIcon, Icon } from '../../../'
3 |
4 | export default () => (
5 |
6 |
7 |
8 |
9 |
10 | Bryan Cranston
11 |
12 |
13 |
14 |
15 |
16 | Aaron Paul
17 |
18 |
19 |
20 |
21 |
22 | Bob Odenkirk
23 |
24 |
25 | )
26 |
--------------------------------------------------------------------------------
/src/components/list/demos/Simple.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { List, ListItem } from '../../../'
3 |
4 | export default () => (
5 |
6 | Bryan Cranston
7 | Aaron Paul
8 | Bob Odenkirk
9 |
10 | )
11 |
--------------------------------------------------------------------------------
/src/components/list/demos/ThreeLine.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {
3 | List,
4 | ListItem,
5 | LiPrimary,
6 | LiSecondary,
7 | LiAvatar,
8 | LiAction,
9 | LiTextBody,
10 | Button,
11 | Icon,
12 | } from '../../../'
13 |
14 | export default () => (
15 |
16 |
17 |
18 |
19 |
20 |
21 | Bryan Cranston
22 |
23 | Bryan Cranston played the role of Walter in Breaking Bad. He is also
24 | known for playing Hal in Malcom in the Middle.
25 |
26 |
27 |
28 |
29 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | Aaron Paul
41 |
42 | Aaron Paul played the role of Jesse in Breaking Bad. He also featured
43 | in the "Need For Speed" Movie.
44 |
45 |
46 |
47 |
48 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | Bob Odenkirk
60 |
61 | Bob Odinkrik played the role of Saul in Breaking Bad. Due to public
62 | fondness for the character, Bob stars in his own show now, called
63 | "Better Call Saul".
64 |
65 |
66 |
67 |
68 |
71 |
72 |
73 |
74 |
75 | )
76 |
--------------------------------------------------------------------------------
/src/components/list/demos/TwoLine.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {
3 | List,
4 | ListItem,
5 | LiPrimary,
6 | LiSecondary,
7 | LiAction,
8 | LiAvatar,
9 | LiSubTitle,
10 | LiInfo,
11 | Button,
12 | Icon,
13 | } from '../../../'
14 |
15 | export default () => (
16 |
17 |
18 |
19 |
20 |
21 |
22 | Bryan Cranston
23 | 62 Episodes
24 |
25 |
26 | Actor
27 |
28 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | Aaron Paul
40 | 62 Episodes
41 |
42 |
43 |
44 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | Bob Odenkirk
56 | 62 Episodes
57 |
58 |
59 |
60 |
63 |
64 |
65 |
66 |
67 | )
68 |
--------------------------------------------------------------------------------
/src/components/list/index.js:
--------------------------------------------------------------------------------
1 | export {
2 | List,
3 | ListItem,
4 | LiAction,
5 | LiIcon,
6 | LiAvatar,
7 | LiInfo,
8 | LiPrimary,
9 | LiSecondary,
10 | LiSubTitle,
11 | LiTextBody,
12 | LiTitle,
13 | } from './List.style'
14 |
--------------------------------------------------------------------------------
/src/components/menu/MenuDivider.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | import MenuItem from './MenuItem'
4 | import { MenuDivider as MenuDividerBase } from './Menu.style'
5 |
6 | export default class MenuDivider extends MenuItem {
7 | render() {
8 | return (
9 | {
13 | this.menuItem = menuItem
14 | }}
15 | />
16 | )
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/components/menu/MenuItem.js:
--------------------------------------------------------------------------------
1 | import { compose, setDisplayName, setPropTypes } from 'recompose'
2 | import PropTypes from 'prop-types'
3 | import React, { Component } from 'react'
4 |
5 | import { MenuItem as MenuItemBase } from './Menu.style'
6 | import { Ripple } from '../ripple'
7 | import { proxyStyledStatics } from '../../hocs'
8 |
9 | export class MenuItem extends Component {
10 | state = {
11 | getTransitionDelay: () => 0,
12 | }
13 |
14 | componentWillReceiveProps(nextProps) {
15 | if (!this.props.isVisible && nextProps.isVisible) {
16 | const {
17 | height,
18 | } = this.menuItem.parentNode.parentNode.getBoundingClientRect()
19 | const { offsetTop } = this.menuItem
20 | const { height: itemHeight } = this.menuItem.getBoundingClientRect()
21 | const getTransitionDelay = nextProps.fadeDown
22 | ? (duration) => offsetTop / height * duration
23 | : (duration) => -(offsetTop + itemHeight - height) / height * duration
24 |
25 | this.setState({ getTransitionDelay })
26 | }
27 | }
28 |
29 | render() {
30 | const { __StyledComponent__: Styled, ...props } = this.props
31 |
32 | return (
33 | {
37 | this.menuItem = menuItem
38 | }}
39 | >
40 | {props.children}
41 |
42 |
43 | )
44 | }
45 | }
46 |
47 | const enhance = compose(
48 | proxyStyledStatics(MenuItemBase),
49 | setPropTypes({
50 | isVisible: PropTypes.bool,
51 | children: PropTypes.node,
52 | }),
53 | setDisplayName('MenuItem'),
54 | )
55 |
56 | export default enhance(MenuItem)
57 |
--------------------------------------------------------------------------------
/src/components/menu/demos/LowerLeft.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Menu, MenuItem, MenuDivider, Button, Icon } from '../../../'
3 |
4 | import { Container, Bar, Bg } from './_shared'
5 |
6 | export default () => (
7 |
8 |
9 |
22 |
23 |
24 |
25 | )
26 |
--------------------------------------------------------------------------------
/src/components/menu/demos/LowerRight.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Menu, MenuItem, MenuDivider, Button, Icon } from '../../../'
3 |
4 | import { Container, Bar, Bg } from './_shared'
5 |
6 | export default () => (
7 |
8 |
9 |
23 |
24 |
25 |
26 | )
27 |
--------------------------------------------------------------------------------
/src/components/menu/demos/UpperLeft.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Menu, MenuItem, MenuDivider, Button, Icon } from '../../../'
3 |
4 | import { Container, Bar, Bg } from './_shared'
5 |
6 | export default () => (
7 |
8 |
9 |
10 |
24 |
25 |
26 | )
27 |
--------------------------------------------------------------------------------
/src/components/menu/demos/UpperRight.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Menu, MenuItem, MenuDivider, Button, Icon } from '../../../'
3 |
4 | import { Container, Bar, Bg } from './_shared'
5 |
6 | export default () => (
7 |
8 |
9 |
10 |
24 |
25 |
26 | )
27 |
--------------------------------------------------------------------------------
/src/components/menu/demos/_shared.js:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components'
2 | import { shadow2dp } from '../../../'
3 |
4 | export const Bar = styled.div`
5 | box-sizing: border-box;
6 | background: #3f51b5;
7 | color: white;
8 | width: 100%;
9 | padding: 16px;
10 | `
11 |
12 | export const Bg = styled.div`
13 | background: white;
14 | height: 148px;
15 | width: 100%;
16 | `
17 |
18 | export const Container = styled.div`
19 | position: relative;
20 | width: 200px;
21 | text-align: ${({ align }) => align};
22 | ${shadow2dp()};
23 | `
24 |
--------------------------------------------------------------------------------
/src/components/menu/getRelativePosition.js:
--------------------------------------------------------------------------------
1 | export default function getRelativePosition(element) {
2 | const rect = element.getBoundingClientRect()
3 | const sx = window.scrollX || window.pageXOffset
4 | const sy = window.scrollY || window.pageYOffset
5 |
6 | return {
7 | height: rect.height,
8 | width: rect.width,
9 | top: rect.top + sy,
10 | left: rect.left + sx,
11 | bottom: rect.bottom + sy,
12 | right: rect.right + sx,
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/components/menu/index.js:
--------------------------------------------------------------------------------
1 | export Menu from './Menu'
2 | export MenuItem from './MenuItem'
3 | export MenuDivider from './MenuDivider'
4 |
--------------------------------------------------------------------------------
/src/components/progress/Progress.js:
--------------------------------------------------------------------------------
1 | import { compose, setDisplayName } from 'recompose'
2 | import React from 'react'
3 |
4 | import {
5 | ProgressBaseStyle,
6 | ProgressBar,
7 | BufferBar,
8 | AuxBar,
9 | } from './Progress.style'
10 | import { proxyStyledStatics } from '../../hocs'
11 |
12 | export const ProgressBase = ({
13 | indeterminate,
14 | percent,
15 | width,
16 | __StyledComponent__: Styled,
17 | }) => (
18 |
19 |
20 |
21 |
22 |
23 | )
24 |
25 | const enhance = compose(
26 | proxyStyledStatics(ProgressBaseStyle),
27 | setDisplayName('Progress'),
28 | )
29 |
30 | export default enhance(ProgressBase)
31 |
--------------------------------------------------------------------------------
/src/components/progress/Progress.style.js:
--------------------------------------------------------------------------------
1 | import { setDisplayName } from 'recompose'
2 | import styled, { css, keyframes } from 'styled-components'
3 |
4 | import { getters as g } from '../../util'
5 |
6 | const indeterminate1 = keyframes`
7 | 0% {
8 | left: 0%;
9 | width: 0%;
10 | }
11 | 50% {
12 | left: 25%;
13 | width: 75%;
14 | }
15 | 75% {
16 | left: 100%;
17 | width: 0%;
18 | }
19 | `
20 |
21 | const indeterminate2 = keyframes`
22 | 0% {
23 | left: 0%;
24 | width: 0%;
25 | }
26 | 50% {
27 | left: 0%;
28 | width: 0%;
29 | }
30 | 75% {
31 | left: 0%;
32 | width: 25%;
33 | }
34 | 100% {
35 | left: 100%;
36 | width: 0%;
37 | }
38 | `
39 |
40 | export const ProgressBaseStyle = setDisplayName('ProgressBaseStyle')(styled.div`
41 | display: block;
42 | position: relative;
43 | height: ${g.barHeight}px;
44 | max-width: 100%;
45 | width: ${({ width }) => width || '500px'};
46 | `)
47 |
48 | const Bar = styled.div`
49 | display: block;
50 | position: absolute;
51 | top: 0;
52 | bottom: 0;
53 | width: 0%;
54 | transition: width 0.2s ${g.animationCurveDefault};
55 | `
56 |
57 | export const ProgressBar = setDisplayName('ProgressBar')(Bar.extend`
58 | background-color: ${g.progressMainColor};
59 | z-index: 1;
60 | left: 0;
61 | ${({ indeterminate }) => indeterminate && css`
62 | background-color: ${g.progressMainColor};
63 | animation-name: ${indeterminate1};
64 | animation-duration: 2s;
65 | animation-iteration-count: infinite;
66 | animation-timing-function: linear;
67 | `}
68 | ${({ percent }) => percent && css`
69 | width: ${percent};
70 | `}
71 | `)
72 |
73 | export const BufferBar = setDisplayName('BufferBar')(Bar.extend`
74 | background-image:
75 | linear-gradient(to right, ${g.progressSecondaryColor}, ${g.progressSecondaryColor}),
76 | linear-gradient(to right, ${g.progressMainColor}, ${g.progressMainColor});
77 | z-index: 0;
78 | left: 0;
79 | width: 100%;
80 | `)
81 |
82 | export const AuxBar = setDisplayName('AuxBar')(Bar.extend`
83 | right: 0;
84 | ${({ indeterminate }) => indeterminate && css`
85 | background-image:
86 | linear-gradient(to right, ${g.progressSecondaryColor}, ${g.progressSecondaryColor}),
87 | linear-gradient(to right,${g.progressMainColor}, ${g.progressMainColor});
88 | animation-name: ${indeterminate2};
89 | animation-duration: 2s;
90 | animation-iteration-count: infinite;
91 | animation-timing-function: linear;
92 | `}
93 | `)
94 |
--------------------------------------------------------------------------------
/src/components/progress/demos/Progress.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Progress } from '../../../'
3 |
4 | export default () =>
5 |
--------------------------------------------------------------------------------
/src/components/progress/demos/ProgressIndeterminate.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Progress } from '../../../'
3 |
4 | export default () =>
5 |
--------------------------------------------------------------------------------
/src/components/progress/index.js:
--------------------------------------------------------------------------------
1 | export Progress from './Progress'
2 |
--------------------------------------------------------------------------------
/src/components/radio/Radio.js:
--------------------------------------------------------------------------------
1 | import { compose, setDisplayName, setPropTypes } from 'recompose'
2 | import PropTypes from 'prop-types'
3 | import React from 'react'
4 |
5 | import {
6 | InnerCircle,
7 | OuterCircle,
8 | RadioButton,
9 | RadioLabel,
10 | RadioStyle,
11 | } from './Radio.style'
12 | import { proxyStyledStatics } from '../../hocs'
13 |
14 | export const RadioBase = ({
15 | label,
16 | disabled,
17 | __StyledComponent__: Styled,
18 | ...props
19 | }) => (
20 |
21 |
22 | {label && {label}}
23 |
24 |
25 |
26 | )
27 |
28 | const enhance = compose(
29 | proxyStyledStatics(RadioStyle),
30 | setDisplayName('Radio'),
31 | setPropTypes({
32 | label: PropTypes.string,
33 | disabled: PropTypes.bool,
34 | }),
35 | )
36 |
37 | export default enhance(RadioBase)
38 |
--------------------------------------------------------------------------------
/src/components/radio/Radio.style.js:
--------------------------------------------------------------------------------
1 | import { setDisplayName } from 'recompose'
2 | import styled, { css } from 'styled-components'
3 |
4 | import { getters as g } from '../../util'
5 | import { materialAnimationDefault } from '../../mixins'
6 |
7 | export const RadioStyle = setDisplayName('RadioStyle')(styled.label`
8 | position: relative;
9 | font-size: ${g.radioLabelFontSize}px;
10 | line-height: ${g.radioLabelHeight}px;
11 | display: inline-block;
12 | vertical-align: middle;
13 | box-sizing: border-box;
14 | min-height: ${g.radioLabelHeight}px;
15 | margin: 0;
16 | padding-left: ${({ theme }) => theme.radioButtonSize + theme.radioPadding}px;
17 | `)
18 |
19 | export const RadioButton = setDisplayName('RadioButton')(styled.input`
20 | line-height: ${g.radioLabelHeight}px;
21 | position: absolute;
22 | width: 0;
23 | height: 0;
24 | margin: 0;
25 | padding: 0;
26 | opacity: 0;
27 | -ms-appearance: none;
28 | -moz-appearance: none;
29 | -webkit-appearance: none;
30 | appearance: none;
31 | border: none;
32 | &:checked ~ div:first-of-type {
33 | border: 2px solid ${g.radioColor};
34 | }
35 | &:checked ~ div:nth-of-type(2) {
36 | transform: scale(1, 1);
37 | }
38 | `)
39 |
40 | export const OuterCircle = setDisplayName('OuterCircle')(styled.div`
41 | position: absolute;
42 | top: ${g.radioTopOffset}px;
43 | left: 0;
44 | display: inline-block;
45 | box-sizing: border-box;
46 | width: ${g.radioButtonSize}px;
47 | height: ${g.radioButtonSize}px;
48 | margin: 0;
49 | cursor: pointer;
50 | border: 2px solid ${g.radioOffColor};
51 | border-radius: 50%;
52 | z-index: 2;
53 |
54 | ${({ disabled }) => disabled && css`
55 | border: 2px solid ${g.radioDisabledColor};
56 | cursor: auto;
57 | `}
58 | `)
59 |
60 | export const InnerCircle = setDisplayName('InnerCircle')(styled.div`
61 | position: absolute;
62 | z-index: 1;
63 | margin: 0;
64 | top: ${({ theme }) => theme.radioTopOffset + theme.radioInnerMargin}px;
65 | left: ${g.radioInnerMargin}px;
66 | box-sizing: border-box;
67 | width: ${({ theme }) => theme.radioButtonSize - theme.radioInnerMargin * 2}px;
68 | height: ${({ theme }) => theme.radioButtonSize - theme.radioInnerMargin * 2}px;
69 | cursor: pointer;
70 | ${materialAnimationDefault('0.28s')}
71 | transition-property: transform;
72 | transform: scale(0, 0);
73 | border-radius: 50%;
74 | background: ${g.radioColor};
75 |
76 | ${({ disabled }) => disabled && css`
77 | background: ${g.radioDisabledColor};
78 | cursor: auto;
79 | `}
80 |
81 | ${({ focused }) => focused && css`
82 | box-shadow: 0 0 0px 10px rgba(0, 0, 0, 0.1);
83 | `}
84 | `)
85 |
86 | export const RadioLabel = setDisplayName('RadioLabel')(styled.span`
87 | cursor: pointer;
88 |
89 | ${({ disabled }) => disabled && css`
90 | color: ${g.radioDisabledColor};
91 | cursor: auto;
92 | `}
93 | `)
94 |
--------------------------------------------------------------------------------
/src/components/radio/demos/Radio.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Radio } from '../../../'
3 |
4 | export default () => (
5 |
6 |
7 |
8 |
9 | )
10 |
--------------------------------------------------------------------------------
/src/components/radio/index.js:
--------------------------------------------------------------------------------
1 | export Radio from './Radio'
2 |
--------------------------------------------------------------------------------
/src/components/ripple/Ripple.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { compose, setDisplayName } from 'recompose'
3 |
4 | import { proxyStyledStatics } from '../../hocs'
5 | import { getRippleSize, getRippleCoords } from './helpers'
6 | import { RippleEffect, RippleWrap } from './Ripple.style'
7 |
8 | export class RippleBase extends Component {
9 | state = {
10 | opacity: 0,
11 | }
12 |
13 | componentDidMount() {
14 | this.size = getRippleSize(this.wrapper)
15 | }
16 |
17 | handleMouseDown = (e) => {
18 | const coords = getRippleCoords(e)
19 | const translate = `translate(-50%, -50%) translate(${coords})`
20 | const initalScale = ' scale3d(0.0001, 0.0001, 1)'
21 | const finalScale = ' scale3d(1, 1, 1)'
22 | this.setState({
23 | size: this.size,
24 | shouldAnimate: false,
25 | transform: translate + initalScale,
26 | opacity: 0.3,
27 | })
28 | requestAnimationFrame(() => {
29 | this.setState({
30 | shouldAnimate: true,
31 | transform: translate + finalScale,
32 | })
33 | })
34 | }
35 |
36 | handleMouseUp = () => {
37 | this.setState({ opacity: 0 })
38 | }
39 |
40 | render() {
41 | const { __StyledComponent__: Styled } = this.props
42 |
43 | return (
44 | {
46 | this.wrapper = wrapper
47 | }}
48 | onMouseDown={this.handleMouseDown}
49 | onMouseUp={this.handleMouseUp}
50 | onMouseOut={this.handleMouseUp}
51 | onFocus={this.handleMouseDown}
52 | onBlur={this.handleMouseUp}
53 | className={this.props.className}
54 | >
55 |
67 |
68 | )
69 | }
70 | }
71 |
72 | const enhance = compose(
73 | proxyStyledStatics(RippleWrap),
74 | setDisplayName('Ripple'),
75 | )
76 |
77 | export default enhance(RippleBase)
78 |
--------------------------------------------------------------------------------
/src/components/ripple/Ripple.style.js:
--------------------------------------------------------------------------------
1 | import { cond, prop, always, T } from 'lodash/fp'
2 | import { setDisplayName } from 'recompose'
3 | import styled, { css } from 'styled-components'
4 |
5 | import { getters as g, rgba } from '../../util'
6 |
7 | export const RippleEffect = setDisplayName('RippleEffect')(styled.div.attrs({
8 | color: cond([
9 | [prop('dark'), always('rgba(0,0,0,.3)')],
10 | [prop('colored'), ({ theme }) => rgba(theme.colorPrimary, 0.5)],
11 | [prop('accent'), ({ theme }) => rgba(theme.colorAccent, 0.5)],
12 | [T, always('white')],
13 | ]),
14 | })`
15 | background-color: ${prop('color')};
16 | border-radius: 50%;
17 | transform: 'none';
18 | pointer-events: none;
19 | position: absolute;
20 | top: 0;
21 | left: 0;
22 | overflow: hidden;
23 | transition-duration: 0.6s, 0.6s, 0.6s, 1.2s;
24 | transition-timing-function: ${g.animationCurveLinearOutSlowIn};
25 | `)
26 |
27 | export const RippleWrap = setDisplayName('RippleWrap')(styled.div`
28 | display: block;
29 | position: absolute;
30 | top: 0;
31 | bottom: 0;
32 | left: 0;
33 | right: 0;
34 | z-index: 4;
35 | overflow: hidden;
36 | ${({ toggle }) => toggle && css`
37 | top: -6px;
38 | left: -10px;
39 | right: auto;
40 | bottom: auto;
41 | height: 36px;
42 | width: 36px;
43 | `}
44 | ${({ round }) => round && css`
45 | border-radius: 50%;
46 | -webkit-mask-image: -webkit-radial-gradient(circle, white, black);
47 | `}
48 | `)
49 |
--------------------------------------------------------------------------------
/src/components/ripple/helpers.js:
--------------------------------------------------------------------------------
1 | import { round } from 'lodash'
2 | import { half, double, diagonalLength, px } from '../../util'
3 |
4 | function isKeyboardClick({ clientX, clientY }) {
5 | if (clientX === 0 && clientY === 0) {
6 | return true
7 | }
8 | return false
9 | }
10 |
11 | function getX({ clientX, touches }) {
12 | return clientX !== undefined ? clientX : touches[0].clientX
13 | }
14 |
15 | function getY({ clientY, touches }) {
16 | return clientY !== undefined ? clientY : touches[0].clientY
17 | }
18 |
19 | export function getRippleSize(e) {
20 | if (!e) {
21 | return '0px'
22 | }
23 |
24 | const { width, height } = e.getBoundingClientRect()
25 | return px(double(diagonalLength(width, height)) + 2)
26 | }
27 |
28 | export function getRippleCoords(e) {
29 | const rect = e.currentTarget.getBoundingClientRect()
30 | const { height, width, left, top } = rect
31 | const coords = isKeyboardClick(e)
32 | ? [width, height].map(half)
33 | : [getX(e) - left, getY(e) - top]
34 |
35 | return coords
36 | .map(round)
37 | .map(px)
38 | .join(', ')
39 | }
40 |
--------------------------------------------------------------------------------
/src/components/ripple/index.js:
--------------------------------------------------------------------------------
1 | export Ripple from './Ripple'
2 |
--------------------------------------------------------------------------------
/src/components/slider/Slider.js:
--------------------------------------------------------------------------------
1 | import { compose, setDisplayName, setPropTypes } from 'recompose'
2 | import PropTypes from 'prop-types'
3 | import React from 'react'
4 |
5 | import { Input } from '../../input'
6 | import { SliderInput, SliderContainer, SliderBackground } from './Slider.style'
7 | import { proxyStyledStatics } from '../../hocs'
8 |
9 | export class SliderBase extends Input {
10 | state = {
11 | ...this.state,
12 | value: this.props.value || this.props.defaultValue || this.props.min,
13 | active: this.props.active,
14 | }
15 |
16 | handleMouseDown = () => {
17 | this.setState({ active: true })
18 | }
19 |
20 | handleMouseUp = (e) => {
21 | this.setState({ active: false })
22 | this.handleBlur(e)
23 | }
24 |
25 | render() {
26 | const { disabled, max, min, __StyledComponent__: Styled } = this.props
27 | const { active, value, focused } = this.state
28 |
29 | const percent = (value - min) / (max - min)
30 |
31 | return (
32 |
33 |
49 |
55 |
56 | )
57 | }
58 | }
59 |
60 | const enhance = compose(
61 | proxyStyledStatics(SliderContainer),
62 | setDisplayName('Slider'),
63 | setPropTypes({
64 | focused: PropTypes.bool,
65 | autoFocus: PropTypes.bool,
66 | active: PropTypes.bool,
67 | value: PropTypes.number,
68 | defaultValue: PropTypes.number,
69 | disabled: PropTypes.bool,
70 | min: PropTypes.number,
71 | max: PropTypes.number,
72 | onChange: PropTypes.func,
73 | onBlur: PropTypes.func,
74 | onFocus: PropTypes.func,
75 | }),
76 | )
77 |
78 | export default enhance(SliderBase)
79 |
--------------------------------------------------------------------------------
/src/components/slider/demos/default.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Slider } from '../../../'
3 |
4 | export default () =>
5 |
--------------------------------------------------------------------------------
/src/components/slider/demos/disabled.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Slider } from '../../../'
3 |
4 | export default () =>
5 |
--------------------------------------------------------------------------------
/src/components/slider/demos/startingValue.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Slider } from '../../../'
3 |
4 | export default () =>
5 |
--------------------------------------------------------------------------------
/src/components/slider/index.js:
--------------------------------------------------------------------------------
1 | export Slider from './Slider'
2 |
--------------------------------------------------------------------------------
/src/components/snackbar/Action.style.js:
--------------------------------------------------------------------------------
1 | import { setDisplayName } from 'recompose'
2 | import styled from 'styled-components'
3 |
4 | import { getters as g } from '../../util'
5 | import { typoButton } from '../../mixins'
6 |
7 | export const SnackbarAction = setDisplayName('SnackbarAction')(styled.button`
8 | background: transparent;
9 | border: none;
10 | color: ${g.snackbarActionColor};
11 | float: right;
12 | text-transform: uppercase;
13 | padding: 14px 24px 14px 12px;
14 | ${typoButton()}
15 | overflow: hidden;
16 | outline: none;
17 | opacity: 0;
18 | pointer-events: none;
19 | cursor: pointer;
20 | text-decoration: none;
21 | text-align: center;
22 | align-self: center;
23 | flex-shrink: 0;
24 | font-weight: 600;
25 | line-height: inherit;
26 |
27 | &::-moz-focus-inner {
28 | border: 0;
29 | }
30 | &:not([aria-hidden]) {
31 | opacity: 1;
32 | pointer-events: auto;
33 | }
34 | `)
35 |
--------------------------------------------------------------------------------
/src/components/snackbar/Message.style.js:
--------------------------------------------------------------------------------
1 | import { setDisplayName } from 'recompose'
2 | import styled from 'styled-components'
3 |
4 | export const SnackbarMessage = setDisplayName('SnackbarMessage')(styled.div`
5 | padding: 14px 12px 14px 24px;
6 | vertical-align: middle;
7 | color: white;
8 | float: left;
9 | `)
10 |
--------------------------------------------------------------------------------
/src/components/snackbar/Snackbar.js:
--------------------------------------------------------------------------------
1 | import { setPropTypes, setDisplayName, compose } from 'recompose'
2 | import PropTypes from 'prop-types'
3 | import React from 'react'
4 |
5 | import { SnackbarAction } from './Action.style'
6 | import { SnackbarMessage } from './Message.style'
7 | import { proxyStyledStatics } from '../../hocs'
8 | import { SnackbarStyle } from './Snackbar.style'
9 |
10 | export const SnackbarBase = ({
11 | message,
12 | actionText,
13 | actionHandler,
14 | __StyledComponent__: Styled,
15 | ...props
16 | }) => (
17 |
18 | {message && {message}}
19 | {actionText && (
20 | {actionText}
21 | )}
22 |
23 | )
24 |
25 | const enhance = compose(
26 | proxyStyledStatics(SnackbarStyle),
27 | setDisplayName('Snackbar'),
28 | setPropTypes({
29 | message: PropTypes.node,
30 | actionText: PropTypes.string,
31 | actionHandler: PropTypes.func,
32 | }),
33 | )
34 |
35 | export default enhance(SnackbarBase)
36 |
--------------------------------------------------------------------------------
/src/components/snackbar/Snackbar.style.js:
--------------------------------------------------------------------------------
1 | import { setDisplayName } from 'recompose'
2 | import styled from 'styled-components'
3 |
4 | import { getters as g } from '../../util'
5 |
6 | export const SnackbarStyle = setDisplayName('SnacbarStyle')(styled.div`
7 | background-color: #323232;
8 | display: flex;
9 | justify-content: space-between;
10 | font-family: ${g.preferredFont};
11 | @media(max-width: ${({ theme }) => theme.snackbarTabletBreakpoint - 1}px) {
12 | width: 100%;
13 | min-height: 48px;
14 | }
15 | @media(min-width: ${g.snackbarTabletBreakpoint}px) {
16 | min-width: 288px;
17 | max-width: 568px;
18 | border-radius: 2px;
19 | margin: 0 16px 16px 16px;
20 | }
21 | `)
22 |
--------------------------------------------------------------------------------
/src/components/snackbar/demos/Snackbar.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { Toast, Snackbar, Button } from '../../../'
3 |
4 | export default class Demo extends Component {
5 | state = {
6 | messages: [],
7 | showMessage: false,
8 | }
9 |
10 | componentWillUpdate(nextProps, nextState) {
11 | if (
12 | nextState.messages[0] &&
13 | nextState.messages[0] !== this.state.messages[0]
14 | ) {
15 | requestAnimationFrame(() => this.setState({ showMessage: true }))
16 | this.timeout = setTimeout(() => {
17 | this.setState({ showMessage: false })
18 | this.timeout = setTimeout(() => {
19 | this.setState({ messages: this.state.messages.slice(1) })
20 | }, 300)
21 | }, 2000)
22 | }
23 | }
24 |
25 | componentWillUnmount() {
26 | clearTimeout(this.timeout)
27 | }
28 |
29 | counter = 0
30 |
31 | increment = () => {
32 | this.counter += 1
33 | this.setState({
34 | messages: [
35 | ...this.state.messages,
36 | { message: `Example message ${this.counter}` },
37 | ],
38 | })
39 | }
40 |
41 | render() {
42 | return (
43 |
44 |
45 |
46 |
47 |
48 |
49 | )
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/components/snackbar/demos/SnackbarWithAction.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { Toast, Snackbar, Button } from '../../../'
3 |
4 | export default class Demo extends Component {
5 | state = {
6 | messages: [],
7 | showMessage: false,
8 | buttonColor: null,
9 | }
10 |
11 | componentWillUpdate(nextProps, nextState) {
12 | if (
13 | nextState.messages[0] &&
14 | nextState.messages[0] !== this.state.messages[0]
15 | ) {
16 | requestAnimationFrame(() => this.setState({ showMessage: true }))
17 | this.timeout = setTimeout(() => {
18 | this.setState({ showMessage: false })
19 | this.timeout = setTimeout(() => {
20 | this.setState({ messages: this.state.messages.slice(1) })
21 | }, 300)
22 | }, 2000)
23 | }
24 | }
25 |
26 | componentWillUnmount() {
27 | clearTimeout(this.timeout)
28 | }
29 |
30 | changeButtonColor = () => {
31 | this.counter += 1
32 | this.setState({
33 | buttonColor: `#${Math.floor(Math.random() * 0xffffff).toString(16)}`,
34 | messages: [
35 | ...this.state.messages,
36 | {
37 | message: 'Button color changed',
38 | actionText: 'Undo',
39 | actionHandler: () => this.setState({ buttonColor: null }),
40 | },
41 | ],
42 | })
43 | }
44 |
45 | render() {
46 | return (
47 |
48 |
54 |
55 |
56 |
57 |
58 | )
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/components/snackbar/index.js:
--------------------------------------------------------------------------------
1 | export Snackbar from './Snackbar'
2 |
--------------------------------------------------------------------------------
/src/components/spinner/Spinner.js:
--------------------------------------------------------------------------------
1 | import { compose, setPropTypes, setDisplayName } from 'recompose'
2 | import PropTypes from 'prop-types'
3 | import React from 'react'
4 |
5 | import {
6 | SpinnerStyle,
7 | LayerOne,
8 | LayerTwo,
9 | LayerThree,
10 | LayerFour,
11 | GapPatch,
12 | CircleClipper,
13 | Circle,
14 | } from './Spinner.style'
15 | import { proxyStyledStatics } from '../../hocs'
16 |
17 | const layers = [LayerOne, LayerTwo, LayerThree, LayerFour]
18 |
19 | export const SpinnerBase = ({ __StyledComponent__: Styled, ...props }) => (
20 |
21 | {layers.map((Layer) => (
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | ))}
34 |
35 | )
36 |
37 | const enhance = compose(
38 | proxyStyledStatics(SpinnerStyle),
39 | setDisplayName('Spinner'),
40 | setPropTypes({
41 | active: PropTypes.bool,
42 | singleColor: PropTypes.bool,
43 | }),
44 | )
45 |
46 | export default enhance(SpinnerBase)
47 |
--------------------------------------------------------------------------------
/src/components/spinner/demos/Spinner.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Spinner } from '../../../'
3 |
4 | export default () =>
5 |
--------------------------------------------------------------------------------
/src/components/spinner/demos/SpinnerSingleColor.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Spinner } from '../../../'
3 |
4 | export default () =>
5 |
--------------------------------------------------------------------------------
/src/components/spinner/index.js:
--------------------------------------------------------------------------------
1 | export Spinner from './Spinner'
2 |
--------------------------------------------------------------------------------
/src/components/switch/Switch.js:
--------------------------------------------------------------------------------
1 | import { compose, setDisplayName, setPropTypes } from 'recompose'
2 | import PropTypes from 'prop-types'
3 | import React from 'react'
4 |
5 | import { proxyStyledStatics } from '../../hocs'
6 | import {
7 | SwitchWrapStyle,
8 | SwitchStyle,
9 | SwitchButton,
10 | SwitchLabel,
11 | Track,
12 | Thumb,
13 | } from './Switch.style'
14 |
15 | export const SwitchBase = ({
16 | label,
17 | disabled,
18 | __StyledComponent__: Styled,
19 | ...props
20 | }) => (
21 |
22 |
23 |
24 | {label && {label}}
25 |
26 |
27 |
28 |
29 | )
30 |
31 | const enhance = compose(
32 | proxyStyledStatics(SwitchWrapStyle),
33 | setDisplayName('Switch'),
34 | setPropTypes({
35 | label: PropTypes.string,
36 | disabled: PropTypes.bool,
37 | }),
38 | )
39 |
40 | export default enhance(SwitchBase)
41 |
--------------------------------------------------------------------------------
/src/components/switch/Switch.style.js:
--------------------------------------------------------------------------------
1 | import { setDisplayName } from 'recompose'
2 | import styled, { css } from 'styled-components'
3 |
4 | import { getters as g } from '../../util'
5 | import { materialAnimationDefault, shadow2dp, shadow3dp } from '../../mixins'
6 |
7 | export const SwitchWrapStyle = setDisplayName('SwitchWrapStyle')(styled.div`
8 | display: inline-block;
9 | `)
10 |
11 | export const SwitchStyle = setDisplayName('SwitchStyle')(styled.label`
12 | position: relative;
13 | z-index: 1;
14 | vertical-align: middle;
15 | display: inline-block;
16 | box-sizing: border-box;
17 | width: 100%;
18 | height: ${g.switchLabelHeight}px;
19 | margin: 0;
20 | padding: 0;
21 | overflow: visible;
22 | padding-left: ${({ theme }) => theme.switchTrackLength}px;
23 | -webkit-touch-callout: none;
24 | user-select: none;
25 | `)
26 |
27 | export const SwitchButton = setDisplayName('SwitchButton')(styled.input`
28 | line-height: ${g.switchLabelHeight}px;
29 | position: absolute;
30 | width: 0;
31 | height: 0;
32 | margin: 0;
33 | padding: 0;
34 | opacity: 0;
35 | -ms-appearance: none;
36 | -moz-appearance: none;
37 | -webkit-appearance: none;
38 | appearance: none;
39 | border: none;
40 | &:checked ~ div:first-of-type {
41 | background: ${g.switchTrackColor};
42 | }
43 | &:checked ~ div:nth-of-type(2) {
44 | background: ${g.switchThumbColor};
45 | left: ${({ theme }) => theme.switchTrackLength - theme.switchThumbSize}px;
46 | ${shadow3dp()};
47 | }
48 | `)
49 |
50 | export const Track = setDisplayName('Track')(styled.div`
51 | background: ${g.switchOffTrackColor};
52 | position: absolute;
53 | left: 0;
54 | top: ${g.switchTrackTop}px;
55 | height: ${g.switchTrackHeight}px;
56 | width: ${g.switchTrackLength}px;
57 | border-radius: ${g.switchTrackHeight}px;
58 | cursor: pointer;
59 | ${({ disabled }) =>
60 | disabled &&
61 | css`
62 | border: 2px solid ${g.switchDisabledTrackColor};
63 | cursor: auto;
64 | `};
65 | `)
66 |
67 | export const Thumb = setDisplayName('Thumb')(styled.div`
68 | background: ${g.switchOffThumbColor};
69 | position: absolute;
70 | left: 0;
71 | top: ${g.switchThumbTop}px;
72 | height: ${g.switchThumbSize}px;
73 | width: ${g.switchThumbSize}px;
74 | border-radius: 50%;
75 | cursor: pointer;
76 | ${shadow2dp()} ${materialAnimationDefault('0.28s')} transition-property: left;
77 | `)
78 |
79 | export const SwitchLabel = setDisplayName('SwitchLabel')(styled.span`
80 | position: relative;
81 | cursor: pointer;
82 | font-size: ${g.switchLabelFontSize}px;
83 | line-height: ${g.switchLabelHeight}px;
84 | margin: 0;
85 | left: 24px;
86 | ${({ disabled }) =>
87 | disabled &&
88 | css`
89 | color: ${g.switchDisabledTumbColor};
90 | cursor: auto;
91 | `};
92 | `)
93 |
--------------------------------------------------------------------------------
/src/components/switch/demos/Switch.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Switch } from '../../../'
3 |
4 | export default () =>
5 |
--------------------------------------------------------------------------------
/src/components/switch/index.js:
--------------------------------------------------------------------------------
1 | export Switch from './Switch'
2 |
--------------------------------------------------------------------------------
/src/components/tables/Table.style.js:
--------------------------------------------------------------------------------
1 | import styled, { css } from 'styled-components'
2 |
3 | import { getters as g } from '../../util'
4 | import { Icon } from '../icons'
5 | import { materialAnimationDefault, typoBody2 } from '../../mixins'
6 |
7 | export const Table = styled.table`
8 | position: relative;
9 | border: ${g.dataTableDividers};
10 | border-collapse: collapse;
11 | white-space: nowrap;
12 | font-size: ${g.dataTableFontSize}px;
13 | background-color: #fff;
14 | `
15 |
16 | export const TableHeader = styled.thead`
17 | padding-bottom: 3px;
18 |
19 | `
20 |
21 | export const TableBody = styled.tbody`
22 | tr:hover {
23 | background-color: ${g.dataTableHoverColor};
24 | }
25 | `
26 |
27 | export const Row = styled.tr`
28 | position: relative;
29 | height: ${g.dataTableRowHeight}px;
30 | ${materialAnimationDefault('0.28s')};
31 | transition-property: background-color;
32 | ${({ isSelected }) => isSelected && css`
33 | background-color: ${g.dataTableSelectionColor};
34 | `}
35 | `
36 |
37 | const CellBase = styled.td`
38 | padding: 0 ${g.dataTableColumnPadding}px 12px ${g.dataTableColumnPadding}px;
39 | text-align: right;
40 |
41 | &:first-of-type {
42 | padding-left: 24px;
43 | }
44 |
45 | &:last-of-type {
46 | padding-right: 24px;
47 | }
48 |
49 | ${({ nonNumeric }) => nonNumeric && css`
50 | text-align: left;
51 | `}
52 | `
53 |
54 | export const Cell = CellBase.extend`
55 | position: relative;
56 | vertical-align: middle;
57 | height: ${g.dataTableRowHeight}px;
58 | border-top: ${g.dataTableDividers};
59 | border-bottom: ${g.dataTableDividers};
60 | padding-top: ${g.dataTableCellTop}px;
61 | box-sizing: border-box;
62 | `
63 |
64 | export const HeaderCell = CellBase.withComponent('th').extend`
65 | position: relative;
66 | vertical-align: bottom;
67 | text-overflow: ellipsis;
68 | ${typoBody2()}
69 | height: ${g.dataTableRowHeight}px;
70 | font-size: ${g.dataTableHeaderFontSize}px;
71 | color: ${g.dataTableHeaderColor};
72 | padding-bottom: 8px;
73 | box-sizing: border-box;
74 | `
75 |
76 | export const TableIcon = Icon.extend`
77 | font-size: ${g.dataTableHeaderSortIconSize}px;
78 | margin-right: 5px;
79 | vertical-align: bottom;
80 | `
81 |
--------------------------------------------------------------------------------
/src/components/tables/demos/DataTable.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { css } from 'styled-components'
3 |
4 | import {
5 | Table,
6 | TableHeader,
7 | TableBody,
8 | Row,
9 | HeaderCell,
10 | TableIcon,
11 | Cell,
12 | shadow2dp,
13 | Checkbox,
14 | theme,
15 | } from '../../../'
16 |
17 | export const DemoTable = Table.extend`
18 | ${shadow2dp()};
19 | `
20 |
21 | export const DemoTh = HeaderCell.extend`
22 | ${({ sorted }) =>
23 | sorted &&
24 | css`
25 | color: ${theme.textColorPrimary};
26 | `};
27 | `
28 |
29 | export default () => (
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | Material
39 |
40 | Quantity
41 | Unit price
42 |
43 |
44 |
45 |
46 |
47 |
48 | |
49 | Acrylic (Transparent) |
50 | 25 |
51 | $2.90 |
52 |
53 |
54 |
55 |
56 | |
57 | Laminate (Gold on Blue) |
58 | 10 |
59 | $2.35 |
60 |
61 |
62 |
63 |
64 | |
65 | Plywood (Birch) |
66 | 50 |
67 | $1.25 |
68 |
69 |
70 |
71 | )
72 |
--------------------------------------------------------------------------------
/src/components/tables/index.js:
--------------------------------------------------------------------------------
1 | export * from './Table.style'
2 |
--------------------------------------------------------------------------------
/src/components/textfield/Textfield.js:
--------------------------------------------------------------------------------
1 | import { compose, setPropTypes, setDisplayName, defaultProps } from 'recompose'
2 | import PropTypes from 'prop-types'
3 | import React from 'react'
4 | import omit from 'lodash/omit'
5 |
6 | import { Input as BaseInput } from '../../input'
7 | import {
8 | ErrorMessage,
9 | HelperText,
10 | Input,
11 | Label,
12 | Textarea,
13 | TextfieldStyle,
14 | } from './Textfield.style'
15 | import { proxyStyledStatics } from '../../hocs'
16 |
17 | export class TextfieldBase extends BaseInput {
18 | render() {
19 | const { __StyledComponent__: Styled, ...props } = this.props
20 | const Component = props.multiLine ? Textarea : Input
21 | return (
22 |
23 |
26 |
33 | {props.error && {props.error}}
34 | {props.helperText && {props.helperText}}
35 |
36 | )
37 | }
38 | }
39 |
40 | const enhance = compose(
41 | proxyStyledStatics(TextfieldStyle),
42 | setDisplayName('Textfield'),
43 | setPropTypes({
44 | error: PropTypes.string,
45 | autoFocus: PropTypes.bool,
46 | value: PropTypes.string,
47 | label: PropTypes.string,
48 | multiLine: PropTypes.bool,
49 | }),
50 | defaultProps({
51 | type: 'text',
52 | }),
53 | )
54 |
55 | export default enhance(TextfieldBase)
56 |
--------------------------------------------------------------------------------
/src/components/textfield/demos/Error.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Textfield } from '../../../'
3 |
4 | export default () => (
5 |
6 | )
7 |
--------------------------------------------------------------------------------
/src/components/textfield/demos/HelperText.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Textfield } from '../../../'
3 |
4 | export default () => (
5 |
10 | )
11 |
--------------------------------------------------------------------------------
/src/components/textfield/demos/MultiLine.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Textfield } from '../../../'
3 |
4 | export default () =>
5 |
--------------------------------------------------------------------------------
/src/components/textfield/demos/SingleLine.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Textfield } from '../../../'
3 |
4 | export default () =>
5 |
--------------------------------------------------------------------------------
/src/components/textfield/index.js:
--------------------------------------------------------------------------------
1 | export Textfield from './Textfield'
2 |
--------------------------------------------------------------------------------
/src/components/toast/Toast.js:
--------------------------------------------------------------------------------
1 | import { setDisplayName, setPropTypes, defaultProps, compose } from 'recompose'
2 | import Portal from 'react-portal'
3 | import PropTypes from 'prop-types'
4 | import React, { Component } from 'react'
5 |
6 | import { ToastAnimation } from './Toast.style'
7 | import { proxyStyledStatics } from '../../hocs'
8 |
9 | export class ToastBase extends Component {
10 | constructor(props) {
11 | super(props)
12 |
13 | this.state = {
14 | isOpened: props.isActive,
15 | isActive: props.isActive,
16 | }
17 | }
18 |
19 | componentWillReceiveProps(nextProps) {
20 | if (!this.state.isActive && nextProps.isActive && !this.isAnimating) {
21 | this.setState({ isOpened: true })
22 | this.animateIn = setTimeout(() => this.setState({ isActive: true }))
23 | }
24 |
25 | if (this.state.isActive && !nextProps.isActive) {
26 | this.setState({ isActive: false })
27 | this.isAnimating = true
28 |
29 | this.animateOut = setTimeout(() => {
30 | this.isAnimating = false
31 | if (this.props.isActive) {
32 | this.setState({ isActive: true })
33 | } else {
34 | this.setState({ isOpened: false })
35 | }
36 | }, 300)
37 | }
38 | }
39 |
40 | componentWillUnmount() {
41 | clearTimeout(this.animateOut)
42 | clearTimeout(this.animateIn)
43 | }
44 |
45 | render() {
46 | const { __StyledComponent__: Styled, ...props } = this.props
47 | return (
48 |
49 |
50 | {props.children}
51 |
52 |
53 | )
54 | }
55 | }
56 |
57 | const enhance = compose(
58 | proxyStyledStatics(ToastAnimation),
59 | setDisplayName('Toast'),
60 | defaultProps({
61 | position: 'left',
62 | }),
63 | setPropTypes({
64 | isActive: PropTypes.bool,
65 | position: PropTypes.string,
66 | children: PropTypes.node,
67 | }),
68 | )
69 |
70 | export default enhance(ToastBase)
71 |
--------------------------------------------------------------------------------
/src/components/toast/Toast.style.js:
--------------------------------------------------------------------------------
1 | import { setDisplayName } from 'recompose'
2 | import styled, { css } from 'styled-components'
3 |
4 | import { getters as g } from '../../util'
5 |
6 | export const ToastAnimation = setDisplayName('ToastAnimation')(styled.div`
7 | position: fixed;
8 | bottom: 0;
9 | z-index: 3;
10 | display: block;
11 | will-change: transform;
12 | transform: translate(0, 100%);
13 | transition: transform 0.25s ${g.animationCurveFastOutLinearIn};
14 | @media(max-width: ${({ theme }) => theme.snackbarTabletBreakpoint - 1}px) {
15 | width: 100%;
16 | left: 0;
17 | }
18 |
19 | @media(min-width: ${g.snackbarTabletBreakpoint}px) {
20 | ${({ position }) => {
21 | switch (position) {
22 | case 'left':
23 | return css`
24 | bottom: 0;
25 | left: 0;
26 | transform: translate(0, 100%);
27 | `
28 | case 'right':
29 | return css`
30 | bottom: 0;
31 | right: 0;
32 | transform: translate(0, 100%);
33 | `
34 | default:
35 | return css`
36 | left: 50%;
37 | bottom: 0;
38 | transform: translate(-50%, 100%);
39 | `
40 | }
41 | }}
42 | }
43 |
44 | ${({ isActive }) => isActive && css`
45 | transform: translate(0, 0);
46 | transition: transform 0.25s ${g.animationCurveLinearOutSlowIn};
47 | @media(min-width: ${g.snackbarTabletBreakpoint}px) {
48 | ${({ position }) => {
49 | switch (position) {
50 | case 'left':
51 | case 'right':
52 | return css`
53 | transform: translate(0, 0);
54 | `
55 | default:
56 | return css`
57 | left: 50%;
58 | transform: translate(-50%, 0);
59 | `
60 | }
61 | }}
62 | }
63 | `}
64 | `)
65 |
--------------------------------------------------------------------------------
/src/components/toast/index.js:
--------------------------------------------------------------------------------
1 | export Toast from './Toast'
2 |
--------------------------------------------------------------------------------
/src/components/tooltips/Tooltip.js:
--------------------------------------------------------------------------------
1 | import { compose, setDisplayName, setPropTypes, defaultProps } from 'recompose'
2 | import Portal from 'react-portal'
3 | import PropTypes from 'prop-types'
4 | import React, { Component } from 'react'
5 |
6 | import { TooltipStyle, TooltipPosition, TooltipWrapper } from './Tooltip.style'
7 | import { proxyStyledStatics } from '../../hocs'
8 | import getRelativePosition from '../menu/getRelativePosition'
9 |
10 | export class TooltipBase extends Component {
11 | state = {
12 | isVisible: false,
13 | }
14 |
15 | componentWillUnmount() {
16 | window.removeEventListener('scroll', this.setPosition, true)
17 | clearTimeout(this.open)
18 | }
19 |
20 | getPosition() {
21 | const control = getRelativePosition(this.control)
22 | const horizontalCenter = control.left + control.width / 2
23 | const verticalCenter = control.top + control.height / 2
24 |
25 | switch (this.props.position) {
26 | case 'below':
27 | return { x: horizontalCenter, y: control.bottom }
28 | case 'left':
29 | return { x: control.left, y: verticalCenter }
30 | case 'right':
31 | return { x: control.right, y: verticalCenter }
32 | default:
33 | return { x: horizontalCenter, y: control.top }
34 | }
35 | }
36 |
37 | setPosition = () => {
38 | this.setState({ ...this.getPosition() })
39 | }
40 |
41 | setControl = (ctrl) => {
42 | this.control = ctrl
43 | }
44 |
45 | handleOpen = () => {
46 | this.setState({ isOpened: true })
47 | this.setPosition()
48 | window.addEventListener('scroll', this.setPosition, true)
49 | this.open = setTimeout(() => {
50 | this.setState({ isVisible: true })
51 | }, this.props.delay)
52 | }
53 |
54 | handleClose = () => {
55 | window.removeEventListener('scroll', this.setPosition, true)
56 | clearTimeout(this.open)
57 | this.setState({ isOpened: false, isVisible: false })
58 | }
59 |
60 | render() {
61 | const { children, __StyledComponent__: Styled, ...props } = this.props
62 |
63 | return (
64 |
70 | {children}
71 |
72 |
73 |
74 | {this.props.message}
75 |
76 |
77 |
78 |
79 | )
80 | }
81 | }
82 |
83 | const enhance = compose(
84 | proxyStyledStatics(TooltipWrapper),
85 | setDisplayName('Tooltip'),
86 | setPropTypes({
87 | message: PropTypes.node,
88 | children: PropTypes.node,
89 | position: PropTypes.string,
90 | delay: PropTypes.number,
91 | }),
92 | defaultProps({
93 | position: 'above',
94 | delay: 0,
95 | }),
96 | )
97 |
98 | export default enhance(TooltipBase)
99 |
--------------------------------------------------------------------------------
/src/components/tooltips/Tooltip.style.js:
--------------------------------------------------------------------------------
1 | import { call, ifProp, switchProp, prop } from 'styled-tools'
2 | import { subtract, add, always } from 'lodash/fp'
3 | import { setDisplayName } from 'recompose'
4 | import styled, { css } from 'styled-components'
5 |
6 | import { arrowTop, arrowBottom, arrowLeft, arrowRight } from '../../mixins'
7 | import { getters as g } from '../../util'
8 |
9 | export const TooltipWrapper = setDisplayName('TooltipWrapper')(styled.div`
10 | display: inline-block;
11 | `)
12 |
13 | export const TooltipPosition = setDisplayName('TooltipPosition')(styled.div`
14 | position: fixed;
15 | transform: scale(0.6);
16 | opacity: 0;
17 | z-index: 999999;
18 | transition: opacity 0.2s ${g.animationCurveLinearOutSlowIn},
19 | transform 0.2s ${g.animationCurveLinearOutSlowIn};
20 | ${ifProp('isVisible', css`
21 | opacity: 1;
22 | transform: none;
23 | `)}
24 | ${switchProp('position', {
25 | above: css`
26 | top: ${call(subtract, prop('y'), always(7))}px;
27 | left: ${prop('x')}px;
28 | transform-origin: bottom center;
29 | `,
30 | below: css`
31 | top: ${call(add, prop('y'), always(7))}px;
32 | left: ${prop('x')}px;
33 | transform-origin: top center;
34 | `,
35 | left: css`
36 | top: ${prop('y')}px;
37 | left: ${call(subtract, prop('x'), always(7))}px;
38 | transform-origin: center right;
39 | `,
40 | right: css`
41 | top: ${prop('y')}px;
42 | left: ${call(add, prop('x'), always(7))}px;
43 | transform-origin: center left;
44 | `,
45 | })}
46 | `)
47 |
48 | export const TooltipStyle = setDisplayName('TooltipBase')(styled.div`
49 | display: block;
50 | background: ${g.tooltipBackgroundColor};
51 | color: ${g.tooltipTextColor};
52 | font-size: ${g.tooltipFontSize}px;
53 | line-height: 14px;
54 | padding: 8px;
55 | border-radius: 2px;
56 | user-select: none;
57 | pointer-events: none;
58 | position: absolute;
59 | white-space: nowrap;
60 | text-align: center;
61 | ${ifProp('large', css`
62 | font-size: ${g.tooltipFontSizeLarge}px;
63 | padding: 16px;
64 | `)}
65 | ${switchProp('position', {
66 | above: css`
67 | transform: translate(-50%, -100%);
68 | ${call(arrowBottom('5px'), g.tooltipBackgroundColor)}
69 | `,
70 | below: css`
71 | transform: translate(-50%, 0);
72 | ${call(arrowTop('5px'), g.tooltipBackgroundColor)}
73 | `,
74 | left: css`
75 | transform: translate(-100%, -50%);
76 | ${call(arrowRight('5px'), g.tooltipBackgroundColor)}
77 | `,
78 | right: css`
79 | transform: translate(0%, -50%);
80 | ${call(arrowLeft('5px'), g.tooltipBackgroundColor)}
81 | `,
82 | })}
83 | `)
84 |
--------------------------------------------------------------------------------
/src/components/tooltips/demos/Above.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | import { Tooltip, Button, Icon } from '../../../'
4 |
5 | export default () => (
6 |
7 |
10 |
11 | )
12 |
--------------------------------------------------------------------------------
/src/components/tooltips/demos/Below.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | import { Tooltip, Button, Icon } from '../../../'
4 |
5 | export default () => (
6 |
7 |
10 |
11 | )
12 |
--------------------------------------------------------------------------------
/src/components/tooltips/demos/Large.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | import { Tooltip, Button, Icon } from '../../../'
4 |
5 | export default () => (
6 |
7 |
10 |
11 | )
12 |
--------------------------------------------------------------------------------
/src/components/tooltips/demos/Left.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | import { Tooltip, Button, Icon } from '../../../'
4 |
5 | export default () => (
6 |
7 |
10 |
11 | )
12 |
--------------------------------------------------------------------------------
/src/components/tooltips/demos/MultiLine.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | import { Tooltip, Button, Icon } from '../../../'
4 |
5 | export default () => (
6 |
9 | Share content on
social media
10 |
11 | }
12 | >
13 |
16 |
17 | )
18 |
--------------------------------------------------------------------------------
/src/components/tooltips/demos/Right.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | import { Tooltip, Button, Icon } from '../../../'
4 |
5 | export default () => (
6 |
7 |
10 |
11 | )
12 |
--------------------------------------------------------------------------------
/src/components/tooltips/index.js:
--------------------------------------------------------------------------------
1 | export Tooltip from './Tooltip'
2 |
--------------------------------------------------------------------------------
/src/hocs/index.js:
--------------------------------------------------------------------------------
1 | export proxyStyledStatics from './proxyStyledStatics'
2 |
--------------------------------------------------------------------------------
/src/hocs/proxyStyledStatics.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-param-reassign, no-underscore-dangle */
2 | import { assignIn } from 'lodash'
3 | import { compose } from 'recompose'
4 |
5 | const cloneComponent = (component) => {
6 | const cloned = component.__clonedFrom || component
7 |
8 | function temp(...args) {
9 | return cloned.apply(this, args)
10 | }
11 |
12 | assignIn(temp, component)
13 |
14 | temp.__clonedFrom = cloned
15 |
16 | return temp
17 | }
18 |
19 | const proxyPropStatic = (propName, fnKey) => (Component) => {
20 | Component[fnKey] = function staticFn(...args) {
21 | const Cloned = cloneComponent(this)
22 | const NextStyledComponent = this.defaultProps[propName][fnKey](...args)
23 | Cloned.defaultProps = {
24 | ...this.defaultProps,
25 | [propName]: NextStyledComponent,
26 | }
27 |
28 | return Cloned
29 | }
30 |
31 | return Component
32 | }
33 |
34 | const passComponentAsProp = (propName, childComponent) => (Component) => {
35 | Component.defaultProps = {
36 | ...Component.defaultProps,
37 | [propName]: childComponent,
38 | }
39 |
40 | return Component
41 | }
42 |
43 | const proxyStyledStatics = (
44 | StyledComponent,
45 | propName = '__StyledComponent__',
46 | ) =>
47 | compose(
48 | proxyPropStatic(propName, 'withComponent'),
49 | proxyPropStatic(propName, 'extend'),
50 | passComponentAsProp(propName, StyledComponent),
51 | )
52 |
53 | export default proxyStyledStatics
54 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | export * from './components/badges'
2 | export * from './components/buttons'
3 | export * from './components/cards'
4 | export * from './components/checkbox'
5 | export * from './components/chips'
6 | export * from './components/dialog'
7 | export * from './components/fonts'
8 | export * from './components/icons'
9 | export * from './components/layout'
10 | export * from './components/list'
11 | export * from './components/menu'
12 | export * from './components/progress'
13 | export * from './components/radio'
14 | export * from './components/ripple'
15 | export * from './components/slider'
16 | export * from './components/snackbar'
17 | export * from './components/spinner'
18 | export * from './components/switch'
19 | export * from './components/tables'
20 | export * from './components/textfield'
21 | export * from './components/toast'
22 | export * from './components/tooltips'
23 | export * from './components/Theme'
24 | export * from './theme'
25 | export * from './mixins'
26 | export * from './hocs'
27 | export * as util from './util'
28 | export initGlobals from './initGlobals'
29 | export theme from './util/getters'
30 |
--------------------------------------------------------------------------------
/src/initGlobals.js:
--------------------------------------------------------------------------------
1 | import FontFaceObserver from 'fontfaceobserver'
2 | import { injectGlobal } from 'styled-components'
3 |
4 | const isBrowser =
5 | Object.prototype.toString.call(
6 | typeof process !== 'undefined' ? process : 0,
7 | ) !== '[object process]'
8 |
9 | export default ({ defaultFont: fontObserver = 'Roboto' } = {}) => {
10 | if (isBrowser && fontObserver) {
11 | const fontLoaded = () => document.body.classList.add('fontLoaded')
12 | const fontNotLoaded = () => document.body.classList.remove('fontLoaded')
13 |
14 | const observer = new FontFaceObserver(fontObserver, {})
15 | observer.load().then(fontLoaded, fontNotLoaded)
16 | }
17 |
18 | // eslint-disable-next-line no-unused-expressions
19 | injectGlobal`
20 | *, *:before, *:after {
21 | box-sizing: border-box;
22 | }
23 |
24 | body {
25 | font-family: Helvetica, Arial, sans-serif;
26 | }
27 |
28 | body.fontLoaded {
29 | font-family: '${fontObserver}', Helvetica, Arial, sans-serif;
30 | }
31 |
32 | html {
33 | width: 100%;
34 | height: 100%;
35 | margin: 0;
36 | font-size: 14px;
37 | line-height: 1.4;
38 | -ms-touch-action: manipulation;
39 | touch-action: manipulation;
40 | }
41 |
42 | body {
43 | width: 100%;
44 | min-height: 100%;
45 | margin: 0;
46 | }
47 | `
48 | }
49 |
--------------------------------------------------------------------------------
/src/input/Input.js:
--------------------------------------------------------------------------------
1 | import { Component } from 'react'
2 | import PropTypes from 'prop-types'
3 | import warning from 'warning'
4 |
5 | import isUndefined from 'lodash/isUndefined'
6 |
7 | const MESSAGE =
8 | 'You provided a `value` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultValue`. Otherwise, set either `onChange` or `readOnly`.'
9 |
10 | const warnIfReadOnly = (props) => {
11 | const isImmutable = props.value && !props.onChange && !props.readOnly
12 | warning(!isImmutable, MESSAGE)
13 | }
14 |
15 | export default class Input extends Component {
16 | constructor(props) {
17 | super(props)
18 |
19 | this.state = {
20 | value: props.value || props.defaultValue || '',
21 | focused: props.focused || props.autoFocus || false,
22 | }
23 |
24 | warnIfReadOnly(props)
25 | }
26 |
27 | componentWillReceiveProps(nextProps) {
28 | if (!isUndefined(nextProps.value) && nextProps.value !== this.state.value) {
29 | this.setState({ value: nextProps.value })
30 | }
31 |
32 | if (
33 | !isUndefined(nextProps.focused) &&
34 | nextProps.focused !== this.state.focused
35 | ) {
36 | this.setState({ focused: nextProps.focused })
37 | }
38 | }
39 |
40 | handleChange = (e) => {
41 | if (isUndefined(this.props.value)) {
42 | this.setState({ value: e.target.value })
43 | }
44 |
45 | if (this.props.onChange) {
46 | this.props.onChange(e)
47 | }
48 | }
49 |
50 | handleFocus = (e) => {
51 | if (isUndefined(this.props.focused)) {
52 | this.setState({ focused: true })
53 | }
54 |
55 | if (this.props.onFocus) {
56 | this.props.onFocus(e)
57 | }
58 | }
59 |
60 | handleBlur = (e) => {
61 | if (isUndefined(this.props.focused)) {
62 | this.setState({ focused: false })
63 | }
64 |
65 | if (this.props.onBlur) {
66 | this.props.onBlur(e)
67 | }
68 | }
69 |
70 | render() {
71 | return null
72 | }
73 | }
74 |
75 | Input.propTypes = {
76 | focused: PropTypes.bool,
77 | autoFocus: PropTypes.bool,
78 | value: PropTypes.any,
79 | onChange: PropTypes.func,
80 | onBlur: PropTypes.func,
81 | onFocus: PropTypes.func,
82 | }
83 |
--------------------------------------------------------------------------------
/src/input/index.js:
--------------------------------------------------------------------------------
1 | export Input from './Input'
2 |
--------------------------------------------------------------------------------
/src/mixins/animations.style.js:
--------------------------------------------------------------------------------
1 | import { css } from 'styled-components'
2 | import { getters as g } from '../util'
3 |
4 | export function materialAnimationFastOutSlowIn(duration = '0.2s') {
5 | return css`
6 | transition-duration: ${duration};
7 | transition-timing-function: ${g.animationCurveFastOutSlowIn};
8 | `
9 | }
10 |
11 | export function materialAnimationLinearOutSlowIn(duration = '0.2s') {
12 | return css`
13 | transition-duration: ${duration};
14 | transition-timing-function: ${g.animationCurveLinearOutSlowIn};
15 | `
16 | }
17 |
18 | export function materialAnimationFastOutLinearIn(duration = '0.2s') {
19 | return css`
20 | transition-duration: ${duration};
21 | transition-timing-function: ${g.animationCurveFastOutLinearIn};
22 | `
23 | }
24 |
25 | export function materialAnimationDefault(duration = '0.2s') {
26 | return css`
27 | transition-duration: ${duration};
28 | transition-timing-function: ${g.animationCurveDefault};
29 | `
30 | }
31 |
--------------------------------------------------------------------------------
/src/mixins/arrow.style.js:
--------------------------------------------------------------------------------
1 | import { css } from 'styled-components'
2 | import { curry } from 'lodash/fp'
3 |
4 | export const arrowTop = curry((size, color) => css`
5 | &:after {
6 | bottom: 100%;
7 | left: 50%;
8 | border: solid transparent;
9 | content: " ";
10 | height: 0;
11 | width: 0;
12 | position: absolute;
13 | pointer-events: none;
14 | border-color: rgba(0, 0, 0, 0);
15 | border-bottom-color: ${color};
16 | border-width: ${size};
17 | margin-left: -${size};
18 | }
19 | `)
20 |
21 | export const arrowRight = curry((size, color) => css`
22 | &:after {
23 | left: 100%;
24 | top: 50%;
25 | border: solid transparent;
26 | content: " ";
27 | height: 0;
28 | width: 0;
29 | position: absolute;
30 | pointer-events: none;
31 | border-color: rgba(0, 0, 0, 0);
32 | border-left-color: ${color};
33 | border-width: ${size};
34 | margin-top: -${size};
35 | }
36 | `)
37 |
38 | export const arrowBottom = curry((size, color) => css`
39 | &:after {
40 | top: 100%;
41 | left: 50%;
42 | border: solid transparent;
43 | content: " ";
44 | height: 0;
45 | width: 0;
46 | position: absolute;
47 | pointer-events: none;
48 | border-color: rgba(0, 0, 0, 0);
49 | border-top-color: ${color};
50 | border-width: ${size};
51 | margin-left: -${size};
52 | }
53 | `)
54 |
55 | export const arrowLeft = curry((size, color) => css`
56 | &:after {
57 | right: 100%;
58 | top: 50%;
59 | border: solid transparent;
60 | content: " ";
61 | height: 0;
62 | width: 0;
63 | position: absolute;
64 | pointer-events: none;
65 | border-color: rgba(0, 0, 0, 0);
66 | border-right-color: ${color};
67 | border-width: ${size};
68 | margin-top: -${size};
69 | }
70 | `)
71 |
--------------------------------------------------------------------------------
/src/mixins/index.js:
--------------------------------------------------------------------------------
1 | export * from './type.style'
2 | export * from './shadows.style'
3 | export * from './animations.style'
4 | export * from './arrow.style'
5 |
--------------------------------------------------------------------------------
/src/mixins/shadows.style.js:
--------------------------------------------------------------------------------
1 | import { css } from 'styled-components'
2 | import { getters as g } from '../util'
3 |
4 | export function focusShadow() {
5 | return css`
6 | box-shadow: 0 0 8px rgba(0,0,0,.18),0 8px 16px rgba(0,0,0,.36);
7 | `
8 | }
9 | export function shadow2dp() {
10 | return css`
11 | box-shadow: 0 2px 2px 0 rgba(0, 0, 0, ${g.shadowKeyPenumbraOpacity}),
12 | 0 3px 1px -2px rgba(0, 0, 0, ${g.shadowKeyUmbraOpacity}),
13 | 0 1px 5px 0 rgba(0, 0, 0, ${g.shadowAmbientShadowOpacity});
14 | `
15 | }
16 | export function shadow3dp() {
17 | return css`
18 | box-shadow: 0 3px 4px 0 rgba(0, 0, 0, ${g.shadowKeyPenumbraOpacity}),
19 | 0 3px 3px -2px rgba(0, 0, 0, ${g.shadowKeyUmbraOpacity}),
20 | 0 1px 8px 0 rgba(0, 0, 0, ${g.shadowAmbientShadowOpacity});
21 | `
22 | }
23 | export function shadow4dp() {
24 | return css`
25 | box-shadow: 0 4px 5px 0 rgba(0, 0, 0, ${g.shadowKeyPenumbraOpacity}),
26 | 0 1px 10px 0 rgba(0, 0, 0, ${g.shadowAmbientShadowOpacity}),
27 | 0 2px 4px -1px rgba(0, 0, 0, ${g.shadowKeyUmbraOpacity});
28 | `
29 | }
30 | export function shadow6dp() {
31 | return css`
32 | box-shadow: 0 6px 10px 0 rgba(0, 0, 0, ${g.shadowKeyPenumbraOpacity}),
33 | 0 1px 18px 0 rgba(0, 0, 0, ${g.shadowAmbientShadowOpacity}),
34 | 0 3px 5px -1px rgba(0, 0, 0, ${g.shadowKeyUmbraOpacity});
35 | `
36 | }
37 | export function shadow8dp() {
38 | return css`
39 | box-shadow: 0 8px 10px 1px rgba(0, 0, 0, ${g.shadowKeyPenumbraOpacity}),
40 | 0 3px 14px 2px rgba(0, 0, 0, ${g.shadowAmbientShadowOpacity}),
41 | 0 5px 5px -3px rgba(0, 0, 0, ${g.shadowKeyUmbraOpacity});
42 | `
43 | }
44 | export function shadow16dp() {
45 | return css`
46 | box-shadow: 0 16px 24px 2px rgba(0, 0, 0, ${g.shadowKeyPenumbraOpacity}),
47 | 0 6px 30px 5px rgba(0, 0, 0, ${g.shadowAmbientShadowOpacity}),
48 | 0 8px 10px -5px rgba(0, 0, 0, ${g.shadowKeyUmbraOpacity});
49 | `
50 | }
51 | export function shadow24dp() {
52 | return css`
53 | box-shadow: 0 9px 46px 8px rgba(0, 0, 0, ${g.shadowKeyPenumbraOpacity}),
54 | 0 11px 15px -7px rgba(0, 0, 0, ${g.shadowAmbientShadowOpacity}),
55 | 0 24px 38px 3px rgba(0, 0, 0, ${g.shadowKeyUmbraOpacity});
56 | `
57 | }
58 |
--------------------------------------------------------------------------------
/src/theme/animation/defaults.js:
--------------------------------------------------------------------------------
1 | export const animationCurveFastOutSlowIn = 'cubic-bezier(0.4, 0, 0.2, 1)'
2 | export const animationCurveLinearOutSlowIn = 'cubic-bezier(0, 0, 0.2, 1)'
3 | export const animationCurveFastOutLinearIn = 'cubic-bezier(0.4, 0, 1, 1)'
4 | export const animationCurveDefault = 'cubic-bezier(0.4, 0, 0.2, 1)'
5 |
--------------------------------------------------------------------------------
/src/theme/animation/index.js:
--------------------------------------------------------------------------------
1 | import * as defaults from './defaults'
2 | import createThemer from '../createThemer'
3 |
4 | export default createThemer(defaults)
5 |
--------------------------------------------------------------------------------
/src/theme/badge/defaults.js:
--------------------------------------------------------------------------------
1 | export const badgeFontSize = 12
2 | export const badgeSize = 22
3 | export const badgePadding = 2
4 | export const badgeOverlap = 12
5 |
--------------------------------------------------------------------------------
/src/theme/badge/index.js:
--------------------------------------------------------------------------------
1 | import * as defaults from './defaults'
2 | import { colorAccentContrast, colorAccent } from '../colors/defaults'
3 | import createThemer from '../createThemer'
4 | import { rgba, rgb } from '../../util/colors'
5 |
6 | export default createThemer(
7 | { colorAccentContrast, colorAccent, ...defaults },
8 | (theme) => ({
9 | badgeColor: rgb(theme.colorAccentContrast),
10 | badgeColorInverse: rgb(theme.colorAccent),
11 | badgeBackground: rgb(theme.colorAccent),
12 | badgeBackgroundInverse: rgba(theme.colorAccentContrast, 0.2),
13 | }),
14 | )
15 |
--------------------------------------------------------------------------------
/src/theme/button/defaults.js:
--------------------------------------------------------------------------------
1 | export const buttonMinWidth = 64
2 | export const buttonHeight = 36
3 | export const buttonPadding = 16
4 | export const buttonMargin = 4
5 | export const buttonBorderRadius = 2
6 |
7 | export const buttonFabSize = 56
8 | export const buttonFabSizeMini = 40
9 | export const buttonFabFontSize = 24
10 |
11 | export const buttonIconSize = 32
12 | export const buttonIconSizeMini = 24
13 |
--------------------------------------------------------------------------------
/src/theme/button/index.js:
--------------------------------------------------------------------------------
1 | import * as defaults from './defaults'
2 | import createThemer from '../createThemer'
3 |
4 | export default createThemer(defaults)
5 |
--------------------------------------------------------------------------------
/src/theme/card/defaults.js:
--------------------------------------------------------------------------------
1 | /* Dimensions */
2 | export const cardWidth = 330
3 | export const cardHeight = 200
4 | export const cardFontSize = 16
5 | export const cardTitleFontSize = 24
6 | export const cardSubtitleFontSize = 14
7 | export const cardHorizontalPadding = 16
8 | export const cardVerticalPadding = 16
9 |
10 | export const cardTitlePerspectiveOriginX = 165
11 | export const cardTitlePerspectiveOriginY = 56
12 |
13 | export const cardTitleTransformOriginX = 165
14 | export const cardTitleTransformOriginY = 56
15 |
16 | export const cardTitleTextTransformOriginX = 149
17 | export const cardTitleTextTransformOriginY = 48
18 |
19 | export const cardSupportingTextFontSize = 14
20 | export const cardSupportingTextLineHeight = 18
21 |
22 | export const cardActionsFontSize = 16
23 |
24 | export const cardTitleTextFontWeight = 300
25 | export const cardZIndex = 1
26 |
27 | /* Cover image */
28 | export const cardCoverImageHeight = 186
29 | export const cardBackgroundImageUrl = ''
30 |
--------------------------------------------------------------------------------
/src/theme/card/index.js:
--------------------------------------------------------------------------------
1 | import * as defaults from './defaults'
2 | import createThemer from '../createThemer'
3 |
4 | export default createThemer(defaults)
5 |
--------------------------------------------------------------------------------
/src/theme/chip/defaults.js:
--------------------------------------------------------------------------------
1 | export const chipBgColor = 'rgb(222, 222, 222)'
2 | export const chipBgActiveColor = 'rgb(214, 214, 214)'
3 | export const chipHeight = 32
4 | export const chipFontSize = 13
5 |
--------------------------------------------------------------------------------
/src/theme/chip/index.js:
--------------------------------------------------------------------------------
1 | import * as defaults from './defaults'
2 | import createThemer from '../createThemer'
3 |
4 | export default createThemer(defaults)
5 |
--------------------------------------------------------------------------------
/src/theme/colors/index.js:
--------------------------------------------------------------------------------
1 | import * as defaults from './defaults'
2 | import createThemer from '../createThemer'
3 | import { rgba, rgb } from '../../util/colors'
4 |
5 | export default createThemer(defaults, (theme) => ({
6 | /* ========== Buttons ========== */
7 |
8 | // Default button colors.
9 | buttonHoverColor: theme.buttonPrimaryColor,
10 |
11 | // Colored button colors.
12 | buttonPrimaryColorAlt: rgb(theme.colorPrimary),
13 | buttonSecondaryColorAlt: rgb(theme.colorPrimaryContrast),
14 | buttonHoverColorAlt: rgb(theme.colorPrimary),
15 | buttonActiveColorAlt: rgb(theme.colorPrimary),
16 | buttonFocusColorAlt: theme.buttonFocusColor,
17 |
18 | // Ripple color for colored raised buttons.
19 | buttonRippleColorAlt: rgb(theme.colorPrimaryContrast),
20 |
21 | // FAB colors and sizes.
22 | buttonFabColorAlt: rgb(theme.colorAccent),
23 | buttonFabHoverColorAlt: rgb(theme.colorAccent),
24 | buttonFabActiveColorAlt: rgb(theme.colorAccent),
25 | buttonFabTextColorAlt: rgb(theme.colorAccentContrast),
26 | buttonFabRippleColorAlt: rgb(theme.colorAccentContrast),
27 |
28 | // Icon button colors and sizes.
29 | buttonIconFocusColor: theme.buttonFocusColor,
30 |
31 | /* ========== Icon Toggles ========== */
32 | iconToggleFocusColor: theme.buttonFocusColor,
33 | iconToggleCheckedColor: rgb(theme.colorPrimary),
34 | iconToggleCheckedFocusColor: rgba(theme.colorPrimary, 0.26),
35 |
36 | /* ========== Radio Buttons ========== */
37 | radioColor: rgb(theme.colorPrimary),
38 |
39 | /* ========== Header ========== */
40 | layoutHeaderBgColor: rgb(theme.colorPrimary),
41 | layoutHeaderTextColor: rgb(theme.colorPrimaryContrast),
42 | layoutHeaderTabTextColor: rgba(theme.colorPrimaryContrast, 0.6),
43 |
44 | /* ========== Tabs ========== */
45 | layoutHeaderTabHighlight: rgb(theme.colorAccent),
46 | tabHighlightColor: rgb(theme.colorPrimary),
47 |
48 | /* ========== Checkboxes ========== */
49 | checkboxColor: rgb(theme.colorPrimary),
50 | checkboxFocusColor: rgba(theme.colorPrimary, 0.26),
51 |
52 | /* ========== Switches ========== */
53 | switchColor: rgb(theme.colorPrimary),
54 | switchFadedColor: rgba(theme.colorPrimary, 0.26),
55 | switchThumbColor: rgb(theme.colorPrimary) || theme.switchColor,
56 | switchTrackColor: rgba(theme.colorPrimary, 0.5),
57 |
58 | /* ========== Spinner ========== */
59 | spinnerSingleColor: rgb(theme.colorPrimary),
60 |
61 | /* ========== Text fields ========== */
62 | inputTextHighlightColor: rgb(theme.colorPrimary),
63 | inputTextDisabledColor: theme.inputTextBottomBorderColor,
64 | inputTextDisabledTextColor: theme.inputTextLabelColor,
65 |
66 | /* ========== Card ========== */
67 | cardImagePlaceholderColor: rgb(theme.colorAccent),
68 |
69 | /* ========== Sliders ========== */
70 | rangeColor: rgb(theme.colorPrimary),
71 | rangeFadedColor: rgba(theme.colorPrimary, 0.26),
72 |
73 | /* ========== Progress ========== */
74 | progressMainColor: rgb(theme.colorPrimary),
75 | progressSecondaryColor: rgba(theme.colorPrimaryContrast, 0.7),
76 | progressFallbackBufferColor: rgba(theme.colorPrimaryContrast, 0.9),
77 |
78 | /* ========== Footer ========== */
79 | footerButtonFillColor: theme.footerColor,
80 | footerUnderlineColor: theme.footerColor,
81 | }))
82 |
--------------------------------------------------------------------------------
/src/theme/createTheme.js:
--------------------------------------------------------------------------------
1 | import reduce from 'lodash/reduce'
2 | import assign from 'lodash/assign'
3 |
4 | import animation from './animation'
5 | import badge from './badge'
6 | import button from './button'
7 | import card from './card'
8 | import chip from './chip'
9 | import * as colorDefinitions from './colorDefinitions'
10 | import colors from './colors'
11 | import dataTable from './dataTable'
12 | import dialog from './dialog'
13 | import footer from './footer'
14 | import grid from './grid'
15 | import iconToggle from './iconToggle'
16 | import layout from './layout'
17 | import list from './list'
18 | import menu from './menu'
19 | import progress from './progress'
20 | import radio from './radio'
21 | import shadows from './shadows'
22 | import snackbar from './snackbar'
23 | import spinner from './spinner'
24 | import switcher from './switch'
25 | import textField from './textField'
26 | import tooltip from './tooltip'
27 | import typography from './typography'
28 |
29 | const themers = [
30 | animation,
31 | badge,
32 | button,
33 | card,
34 | chip,
35 | colors,
36 | dataTable,
37 | dialog,
38 | footer,
39 | grid,
40 | iconToggle,
41 | layout,
42 | list,
43 | menu,
44 | progress,
45 | radio,
46 | shadows,
47 | snackbar,
48 | spinner,
49 | switcher,
50 | textField,
51 | tooltip,
52 | typography,
53 | ]
54 |
55 | export default function createTheme(overrides = {}) {
56 | const compiled = reduce(
57 | themers,
58 | (theme, themer) => assign({}, theme, themer(overrides)),
59 | {},
60 | )
61 |
62 | return assign({}, colorDefinitions, compiled, overrides)
63 | }
64 |
--------------------------------------------------------------------------------
/src/theme/createThemer.js:
--------------------------------------------------------------------------------
1 | import mapValues from 'lodash/mapValues'
2 |
3 | export default (defaults, compute) => (overrides) => {
4 | const base = mapValues(defaults, (value, key) => overrides[key] || value)
5 |
6 | return compute ? { ...compute(base), ...base } : base
7 | }
8 |
--------------------------------------------------------------------------------
/src/theme/dataTable/defaults.js:
--------------------------------------------------------------------------------
1 | export const dataTableFontSize = 13
2 | export const dataTableHeaderFontSize = 12
3 | export const dataTableHeaderSortIconSize = 16
4 |
5 | export const dataTableHeaderColor = 'rgba(0, 0, 0, 0.54)'
6 | export const dataTableHeaderSortedColor = 'rgba(0, 0, 0, 0.87)'
7 | export const dataTableHeaderSortedIconHoverColor = 'rgba(0, 0, 0, 0.26)'
8 | export const dataTableDividerColor = 'rgba(0, 0, 0, 0.12)'
9 |
10 | export const dataTableHoverColor = '#eeeeee'
11 | export const dataTableSelectionColor = '#e0e0e0'
12 |
13 | export const dataTableRowHeight = 48
14 | export const dataTableLastRowHeight = 56
15 | export const dataTableHeaderHeight = 56
16 |
17 | export const dataTableColumnSpacing = 36
18 |
19 | export const dataTableCardHeaderHeight = 64
20 | export const dataTableCardTitleTop = 20
21 | export const dataTableCardPadding = 24
22 | export const dataTableButtonPaddingRight = 16
23 |
--------------------------------------------------------------------------------
/src/theme/dataTable/index.js:
--------------------------------------------------------------------------------
1 | import * as defaults from './defaults'
2 | import createThemer from '../createThemer'
3 |
4 | export default createThemer(defaults, (theme) => ({
5 | dataTableDividers: `1px solid ${theme.dataTableDividerColor}`,
6 | dataTableColumnPadding: theme.dataTableColumnSpacing / 2,
7 | dataTableCellTop: theme.dataTableCardPadding / 2,
8 | }))
9 |
--------------------------------------------------------------------------------
/src/theme/defaultTheme.js:
--------------------------------------------------------------------------------
1 | import createTheme from './createTheme'
2 |
3 | const defaultTheme = createTheme()
4 |
5 | export default defaultTheme
6 |
--------------------------------------------------------------------------------
/src/theme/dialog/index.js:
--------------------------------------------------------------------------------
1 | import createThemer from '../createThemer'
2 |
3 | export default createThemer({}, (theme) => ({
4 | dialogContentColor: theme.cardSupportingTextColor,
5 | }))
6 |
--------------------------------------------------------------------------------
/src/theme/footer/defaults.js:
--------------------------------------------------------------------------------
1 | /* megaFooter */
2 | export const footerMinPadding = 16
3 | export const footerPaddingSides = 40
4 | export const footerHeadingFontSize = 14
5 | export const footerBtnSize = 36
6 |
7 | /* miniFooter */
8 | export const miniFooterPadding = 16
9 | export const miniFooterHeadingFontSize = 24
10 | export const miniFooterBtnSize = 36
11 |
--------------------------------------------------------------------------------
/src/theme/footer/index.js:
--------------------------------------------------------------------------------
1 | import * as defaults from './defaults'
2 | import createThemer from '../createThemer'
3 |
4 | export default createThemer(defaults, (theme) => ({
5 | footerHeadingLineHeight: 1.7 * theme.footerHeadingFontSize,
6 | miniFooterHeadingLineHeight: 1.5 * theme.miniFooterHeadingFontSize,
7 | }))
8 |
--------------------------------------------------------------------------------
/src/theme/grid/defaults.js:
--------------------------------------------------------------------------------
1 | export const gridDesktopColumns = 12
2 | export const gridDesktopGutter = 16
3 | export const gridDesktopMargin = 16
4 |
5 | export const gridDesktopBreakpoint = 840
6 |
7 | export const gridTabletColumns = 8
8 |
9 | export const gridTabletBreakpoint = 480
10 |
11 | export const gridPhoneColumns = 4
12 |
--------------------------------------------------------------------------------
/src/theme/grid/index.js:
--------------------------------------------------------------------------------
1 | import * as defaults from './defaults'
2 | import createThemer from '../createThemer'
3 |
4 | export default createThemer(defaults, (theme) => ({
5 | gridTabletGutter: theme.gridDesktopGutter,
6 | gridTabletMargin: theme.gridDesktopMargin,
7 | gridPhoneGutter: theme.gridDesktopGutter,
8 | gridPhoneMargin: theme.gridDesktopMargin,
9 | gridCellDefaultColumns: theme.gridPhoneColumns,
10 | gridMaxColumns: theme.gridDesktopColumns,
11 | }))
12 |
--------------------------------------------------------------------------------
/src/theme/iconToggle/defaults.js:
--------------------------------------------------------------------------------
1 | export const iconToggleSize = 32
2 | export const iconToggleFontSize = 24
3 | export const iconToggleRippleSize = 36
4 |
--------------------------------------------------------------------------------
/src/theme/iconToggle/index.js:
--------------------------------------------------------------------------------
1 | import * as defaults from './defaults'
2 | import createThemer from '../createThemer'
3 |
4 | export default createThemer(defaults)
5 |
--------------------------------------------------------------------------------
/src/theme/index.js:
--------------------------------------------------------------------------------
1 | export defaultTheme from './defaultTheme'
2 | export createTheme from './createTheme'
3 | export * as colors from './colorDefinitions'
4 |
--------------------------------------------------------------------------------
/src/theme/layout/defaults.js:
--------------------------------------------------------------------------------
1 | export const layoutDrawerNarrow = 240
2 | export const layoutDrawerWide = 456
3 |
4 | export const layoutHeaderIconSize = 32
5 | export const layoutScreenSizeThreshold = 1024
6 | export const layoutHeaderIconMargin = 24
7 | export const layoutDrawerButtonMobileSize = 32
8 | export const layoutDrawerButtonDesktopSize = 48
9 |
10 | export const layoutHeaderMobileRowHeight = 56
11 | export const layoutHeaderDesktopRowHeight = 64
12 |
13 | export const layoutHeaderDesktopBaseline = 80
14 | export const layoutHeaderMobileBaseline = 72
15 | export const layoutHeaderMobileIndent = 16
16 | export const layoutHeaderDesktopIndent = 40
17 |
18 | export const layoutTabFontSize = 14
19 | export const layoutTabBarHeight = 48
20 | export const layoutTabMobilePadding = 12
21 | export const layoutTabDesktopPadding = 24
22 | export const layoutTabHighlightThickness = 2
23 |
--------------------------------------------------------------------------------
/src/theme/layout/index.js:
--------------------------------------------------------------------------------
1 | import * as defaults from './defaults'
2 | import createThemer from '../createThemer'
3 |
4 | export default createThemer(defaults, (theme) => ({
5 | layoutDrawerWidth: theme.layoutDrawerNarrow,
6 | layoutMobileHeaderHeight: theme.layoutHeaderMobileRowHeight,
7 | layoutDesktopHeaderHeight: theme.layoutHeaderDesktopRowHeight,
8 | }))
9 |
--------------------------------------------------------------------------------
/src/theme/list/defaults.js:
--------------------------------------------------------------------------------
1 | export const listBorder = 8
2 | export const listMinHeight = 48
3 | export const listMinPadding = 16
4 | export const listBottomPadding = 20
5 | export const listAvatarTextLeftDistance = 72
6 | export const listIconTextLeftDistance = 72
7 |
8 | export const listAvatarSize = 40
9 | export const listIconSize = 24
10 |
11 | export const listTwoLineHeight = 72
12 | export const listThreeLineHeight = 88
13 |
--------------------------------------------------------------------------------
/src/theme/list/index.js:
--------------------------------------------------------------------------------
1 | import * as defaults from './defaults'
2 | import createThemer from '../createThemer'
3 |
4 | export default createThemer(defaults)
5 |
--------------------------------------------------------------------------------
/src/theme/menu/defaults.js:
--------------------------------------------------------------------------------
1 | export const menuExpandDuration = 0.3
2 | export const menuFadeDuration = 0.2
3 |
--------------------------------------------------------------------------------
/src/theme/menu/index.js:
--------------------------------------------------------------------------------
1 | import * as defaults from './defaults'
2 | import createThemer from '../createThemer'
3 |
4 | export default createThemer(defaults)
5 |
--------------------------------------------------------------------------------
/src/theme/progress/defaults.js:
--------------------------------------------------------------------------------
1 | export const barHeight = 4
2 |
--------------------------------------------------------------------------------
/src/theme/progress/index.js:
--------------------------------------------------------------------------------
1 | import * as defaults from './defaults'
2 | import createThemer from '../createThemer'
3 |
4 | export default createThemer(defaults)
5 |
--------------------------------------------------------------------------------
/src/theme/radio/defaults.js:
--------------------------------------------------------------------------------
1 | export const radioLabelFontSize = 16
2 | export const radioLabelHeight = 24
3 | export const radioButtonSize = 16
4 | export const radioPadding = 8
5 | export const radioRippleSize = 42
6 |
--------------------------------------------------------------------------------
/src/theme/radio/index.js:
--------------------------------------------------------------------------------
1 | import * as defaults from './defaults'
2 | import createThemer from '../createThemer'
3 |
4 | export default createThemer(defaults, (theme) => ({
5 | radioInnerMargin: theme.radioButtonSize / 4,
6 | radioTopOffset: (theme.radioLabelHeight - theme.radioButtonSize) / 2,
7 | }))
8 |
--------------------------------------------------------------------------------
/src/theme/shadows/defaults.js:
--------------------------------------------------------------------------------
1 | export const shadowKeyUmbraOpacity = 0.2
2 | export const shadowKeyPenumbraOpacity = 0.14
3 | export const shadowAmbientShadowOpacity = 0.12
4 |
--------------------------------------------------------------------------------
/src/theme/shadows/index.js:
--------------------------------------------------------------------------------
1 | import * as defaults from './defaults'
2 | import createThemer from '../createThemer'
3 |
4 | export default createThemer(defaults)
5 |
--------------------------------------------------------------------------------
/src/theme/snackbar/index.js:
--------------------------------------------------------------------------------
1 | import createThemer from '../createThemer'
2 | import { colorAccent } from '../colors/defaults'
3 | import { gridTabletBreakpoint } from '../grid/defaults'
4 | import { rgb } from '../../util/colors'
5 |
6 | export default createThemer({ colorAccent, gridTabletBreakpoint }, (theme) => ({
7 | snackbarTabletBreakpoint: theme.gridTabletBreakpoint,
8 | snackbarActionColor: rgb(theme.colorAccent),
9 | }))
10 |
--------------------------------------------------------------------------------
/src/theme/spinner/defaults.js:
--------------------------------------------------------------------------------
1 | export const spinnerSize = 28
2 | export const spinnerStrokeWidth = 3
3 |
4 | // Amount of circle the arc takes up.
5 | export const spinnerArcSize = 270
6 | // Time it takes to expand and contract arc.
7 | export const spinnerArcTime = 1333
8 | // How much the start location of the arc should rotate each time.
9 | export const spinnerArcStartRot = 216
10 |
--------------------------------------------------------------------------------
/src/theme/spinner/index.js:
--------------------------------------------------------------------------------
1 | import * as defaults from './defaults'
2 | import createThemer from '../createThemer'
3 |
4 | export default createThemer(defaults, (theme) => ({
5 | spinnerDuration:
6 | 360 * (theme.spinnerArcTime / theme.spinnerArcStartRot) +
7 | (360 - theme.spinnerArcSize),
8 | }))
9 |
--------------------------------------------------------------------------------
/src/theme/switch/defaults.js:
--------------------------------------------------------------------------------
1 | export const switchLabelFontSize = 16
2 | export const switchLabelHeight = 24
3 | export const switchTrackHeight = 14
4 | export const switchTrackLength = 36
5 | export const switchThumbSize = 20
6 | export const switchHelperSize = 8
7 |
--------------------------------------------------------------------------------
/src/theme/switch/index.js:
--------------------------------------------------------------------------------
1 | import * as defaults from './defaults'
2 | import createThemer from '../createThemer'
3 |
4 | export default createThemer(defaults, (theme) => ({
5 | switchTrackTop: (theme.switchLabelHeight - theme.switchTrackHeight) / 2,
6 | switchThumbTop: (theme.switchLabelHeight - theme.switchThumbSize) / 2,
7 | switchRippleSize: theme.switchLabelHeight * 2,
8 | }))
9 |
--------------------------------------------------------------------------------
/src/theme/textField/defaults.js:
--------------------------------------------------------------------------------
1 | export const inputTextFontSize = 16
2 | export const inputTextWidth = '100%'
3 | export const inputTextPadding = 4
4 | export const inputTextVerticalSpacing = 20
5 |
6 | export const inputTextButtonSize = 32
7 | export const inputTextFloatingLabelFontsize = 12
8 | export const inputTextExpandableIconTop = 16
9 |
--------------------------------------------------------------------------------
/src/theme/textField/index.js:
--------------------------------------------------------------------------------
1 | import * as defaults from './defaults'
2 | import createThemer from '../createThemer'
3 |
4 | export default createThemer(defaults)
5 |
--------------------------------------------------------------------------------
/src/theme/tooltip/defaults.js:
--------------------------------------------------------------------------------
1 | export const tooltipFontSize = 10
2 | export const tooltipFontSizeLarge = 14
3 |
--------------------------------------------------------------------------------
/src/theme/tooltip/index.js:
--------------------------------------------------------------------------------
1 | import * as defaults from './defaults'
2 | import createThemer from '../createThemer'
3 |
4 | export default createThemer(defaults)
5 |
--------------------------------------------------------------------------------
/src/theme/typography/defaults.js:
--------------------------------------------------------------------------------
1 | export const preferredFont = "'Roboto', 'Helvetica', 'Arial', sansSerif"
2 | export const performanceFont = "'Helvetica', 'Arial', sansSerif"
3 |
--------------------------------------------------------------------------------
/src/theme/typography/index.js:
--------------------------------------------------------------------------------
1 | import * as defaults from './defaults'
2 | import createThemer from '../createThemer'
3 |
4 | export default createThemer(defaults)
5 |
--------------------------------------------------------------------------------
/src/util/colors.js:
--------------------------------------------------------------------------------
1 | export const rgb = (values) => `rgb(${values})`
2 | export const rgba = (values, alpha) => `rgba(${values},${alpha})`
3 |
--------------------------------------------------------------------------------
/src/util/getters.js:
--------------------------------------------------------------------------------
1 | import { mapValues } from 'lodash'
2 | import { defaultTheme } from '../theme'
3 | import { rgb, rgba } from './colors'
4 |
5 | const getters = mapValues(defaultTheme, (v, k) => (p) => p.theme[k])
6 |
7 | getters.fg = (p) => p.theme.fg || p.theme.textColorPrimary
8 | getters.bg = (p) => p.theme.bg || `rgb(${p.theme.white})`
9 |
10 | getters.rgb = (base, value) => (p) => rgb(p.theme[base][value])
11 | getters.rgba = (base, value, alpha) => (p) => rgba(p.theme[base][value], alpha)
12 | getters.rgbFromProp = (prop, fallback) => (p) => {
13 | const color = p[prop]
14 |
15 | if (!color) {
16 | return fallback ? fallback(p) : 'none'
17 | }
18 |
19 | const [base, value = 500] = color.split('|')
20 |
21 | return rgb(p.theme[base][parseInt(value, 10)])
22 | }
23 |
24 | export default getters
25 |
--------------------------------------------------------------------------------
/src/util/index.js:
--------------------------------------------------------------------------------
1 | export getters from './getters'
2 | export * from './colors'
3 | export * from './math'
4 | export * from './units'
5 |
--------------------------------------------------------------------------------
/src/util/math.js:
--------------------------------------------------------------------------------
1 | import { round } from 'lodash'
2 |
3 | export const half = (n) => round(n / 2)
4 | export const double = (n) => n * 2
5 | export const diagonalLength = (width, height) =>
6 | Math.sqrt(width * width + height * height)
7 |
--------------------------------------------------------------------------------
/src/util/units.js:
--------------------------------------------------------------------------------
1 | export const px = (n) => `${n}px`
2 |
--------------------------------------------------------------------------------
/stories/badges.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import wrapStory from './decorators/wrapStory'
4 |
5 | import IconOverIcon from '../src/components/badges/demos/IconOverIcon.js'
6 | import IconOverText from '../src/components/badges/demos/IconOverText.js'
7 | import NumberOverIcon from '../src/components/badges/demos/NumberOverIcon.js'
8 | import NumberOverText from '../src/components/badges/demos/NumberOverText.js'
9 | import TextOverButton from '../src/components/badges/demos/TextOverButton.js'
10 |
11 | storiesOf('Badges', module)
12 | .addDecorator(wrapStory)
13 | .add('Icon Over Icon', () => )
14 | .add('Icon Over Text', () => )
15 | .add('Number Over Icon', () => )
16 | .add('Number Over Text', () => )
17 | .add('Text Over Button', () => )
18 |
--------------------------------------------------------------------------------
/stories/buttons.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import wrapStory from './decorators/wrapStory'
4 |
5 | import Fab from '../src/components/buttons/demos/Fab.js'
6 | import FabAccent from '../src/components/buttons/demos/FabAccent.js'
7 | import FabDisabled from '../src/components/buttons/demos/FabDisabled.js'
8 | import FabMini from '../src/components/buttons/demos/FabMini.js'
9 | import FabPrimary from '../src/components/buttons/demos/FabPrimary.js'
10 | import Flat from '../src/components/buttons/demos/Flat.js'
11 | import FlatAccent from '../src/components/buttons/demos/FlatAccent.js'
12 | import FlatDisabled from '../src/components/buttons/demos/FlatDisabled.js'
13 | import FlatPrimary from '../src/components/buttons/demos/FlatPrimary.js'
14 | import Icon from '../src/components/buttons/demos/Icon.js'
15 | import IconAccent from '../src/components/buttons/demos/IconAccent.js'
16 | import IconDisabled from '../src/components/buttons/demos/IconDisabled.js'
17 | import IconMini from '../src/components/buttons/demos/IconMini.js'
18 | import IconPrimary from '../src/components/buttons/demos/IconPrimary.js'
19 | import Raised from '../src/components/buttons/demos/Raised.js'
20 | import RaisedAccent from '../src/components/buttons/demos/RaisedAccent.js'
21 | import RaisedDisabled from '../src/components/buttons/demos/RaisedDisabled.js'
22 | import RaisedPrimary from '../src/components/buttons/demos/RaisedPrimary.js'
23 |
24 | storiesOf('Buttons', module)
25 | .addDecorator(wrapStory)
26 | .add('Fab', () => )
27 | .add('Fab Accent', () => )
28 | .add('Fab Disabled', () => )
29 | .add('Fab Mini', () => )
30 | .add('Fab Primary', () => )
31 | .add('Flat', () => )
32 | .add('Flat Accent', () => )
33 | .add('Flat Disabled', () => )
34 | .add('Flat Primary', () => )
35 | .add('Icon', () => )
36 | .add('Icon Accent', () => )
37 | .add('Icon Disabled', () => )
38 | .add('Icon Mini', () => )
39 | .add('Icon Primary', () => )
40 | .add('Raised', () => )
41 | .add('Raised Accent', () => )
42 | .add('Raised Disabled', () => )
43 | .add('Raised Primary', () => )
44 |
--------------------------------------------------------------------------------
/stories/cards.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import wrapStory from './decorators/wrapStory'
4 |
5 | import Event from '../src/components/cards/demos/Event.js'
6 | import Image from '../src/components/cards/demos/Image.js'
7 | import Square from '../src/components/cards/demos/Square.js'
8 | import Wide from '../src/components/cards/demos/Wide.js'
9 |
10 | storiesOf('Cards', module)
11 | .addDecorator(wrapStory)
12 | .add('Event', () => )
13 | .add('Image', () => )
14 | .add('Square', () => )
15 | .add('Wide', () => )
16 |
--------------------------------------------------------------------------------
/stories/checkbox.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import wrapStory from './decorators/wrapStory'
4 |
5 | import Checkbox from '../src/components/checkbox/demos/Checkbox.js'
6 |
7 | storiesOf('Checkbox', module)
8 | .addDecorator(wrapStory)
9 | .add('Checkbox', () => )
10 |
--------------------------------------------------------------------------------
/stories/chips.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import wrapStory from './decorators/wrapStory'
4 |
5 | import Basic from '../src/components/chips/demos/Basic.js'
6 | import Button from '../src/components/chips/demos/Button.js'
7 | import Contact from '../src/components/chips/demos/Contact.js'
8 | import Deletable from '../src/components/chips/demos/Deletable.js'
9 | import DeletableContact from '../src/components/chips/demos/DeletableContact.js'
10 |
11 | storiesOf('Chips', module)
12 | .addDecorator(wrapStory)
13 | .add('Basic', () => )
14 | .add('Button', () => )
15 | .add('Contact', () => )
16 | .add('Deletable', () => )
17 | .add('Deletable Contact', () => )
18 |
--------------------------------------------------------------------------------
/stories/decorators/wrapStory.js:
--------------------------------------------------------------------------------
1 | import styled, { injectGlobal } from 'styled-components'
2 | import React from 'react'
3 |
4 | import { Theme, initGlobals, createTheme, colors } from '../../src'
5 |
6 | initGlobals({ fontObserver: 'Roboto' })
7 |
8 | const theme = createTheme({
9 | colorPrimary: colors.indigo[500],
10 | colorPirmaryDark: colors.indigo[700],
11 | colorAccent: colors.pink[500],
12 | })
13 |
14 | // eslint-disable-next-line no-unused-expressions
15 | injectGlobal`
16 | html, body, #root {
17 | height: 100%;
18 | }
19 | body {
20 | height: calc(100% - 16px);
21 | }
22 | `
23 |
24 | const Wrap = styled.div`
25 | height: 100%;
26 | width: 100%;
27 | display: flex;
28 | align-items: center;
29 | justify-content: center;
30 | position: relative;
31 | `
32 |
33 | const StoryWrap = (props) => (
34 |
35 | {props.children}
36 |
37 | )
38 |
39 | export default (fn) => {fn()}
40 |
--------------------------------------------------------------------------------
/stories/dialog.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import wrapStory from './decorators/wrapStory'
4 |
5 | import Basic from '../src/components/dialog/demos/Basic.js'
6 | import FullWidthActions from '../src/components/dialog/demos/FullWidthActions.js'
7 |
8 | storiesOf('Dialog', module)
9 | .addDecorator(wrapStory)
10 | .add('Basic', () => )
11 | .add('Full Width Actions', () => )
12 |
--------------------------------------------------------------------------------
/stories/list.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import wrapStory from './decorators/wrapStory'
4 |
5 | import AvatarsAndActions from '../src/components/list/demos/AvatarsAndActions.js'
6 | import AvatarsAndControls from '../src/components/list/demos/AvatarsAndControls.js'
7 | import Icons from '../src/components/list/demos/Icons.js'
8 | import Simple from '../src/components/list/demos/Simple.js'
9 | import ThreeLine from '../src/components/list/demos/ThreeLine.js'
10 | import TwoLine from '../src/components/list/demos/TwoLine.js'
11 |
12 | storiesOf('List', module)
13 | .addDecorator(wrapStory)
14 | .add('Avatars And Actions', () => )
15 | .add('Avatars And Controls', () => )
16 | .add('Icons', () => )
17 | .add('Simple', () => )
18 | .add('Three Line', () => )
19 | .add('Two Line', () => )
20 |
--------------------------------------------------------------------------------
/stories/menu.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import wrapStory from './decorators/wrapStory'
4 |
5 | import LowerLeft from '../src/components/menu/demos/LowerLeft.js'
6 | import LowerRight from '../src/components/menu/demos/LowerRight.js'
7 | import UpperLeft from '../src/components/menu/demos/UpperLeft.js'
8 | import UpperRight from '../src/components/menu/demos/UpperRight.js'
9 |
10 | storiesOf('Menu', module)
11 | .addDecorator(wrapStory)
12 | .add('Lower Left', () => )
13 | .add('Lower Right', () => )
14 | .add('Upper Left', () => )
15 | .add('Upper Right', () => )
16 |
--------------------------------------------------------------------------------
/stories/progress.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import wrapStory from './decorators/wrapStory'
4 |
5 | import Progress from '../src/components/progress/demos/Progress.js'
6 | import ProgressIndeterminate from '../src/components/progress/demos/ProgressIndeterminate.js'
7 |
8 | storiesOf('Progress', module)
9 | .addDecorator(wrapStory)
10 | .add('Progress', () => )
11 | .add('Progress Indeterminate', () => )
12 |
--------------------------------------------------------------------------------
/stories/radio.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import wrapStory from './decorators/wrapStory'
4 |
5 | import Radio from '../src/components/radio/demos/Radio.js'
6 |
7 | storiesOf('Radio', module)
8 | .addDecorator(wrapStory)
9 | .add('Radio', () => )
10 |
--------------------------------------------------------------------------------
/stories/slider.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import wrapStory from './decorators/wrapStory'
4 |
5 | import Default from '../src/components/slider/demos/default.js'
6 | import Disabled from '../src/components/slider/demos/disabled.js'
7 | import StartingValue from '../src/components/slider/demos/startingValue.js'
8 |
9 | storiesOf('Slider', module)
10 | .addDecorator(wrapStory)
11 | .add('Default', () => )
12 | .add('Disabled', () => )
13 | .add('Starting Value', () => )
14 |
--------------------------------------------------------------------------------
/stories/snackbar.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import wrapStory from './decorators/wrapStory'
4 |
5 | import Snackbar from '../src/components/snackbar/demos/Snackbar.js'
6 | import SnackbarWithAction from '../src/components/snackbar/demos/SnackbarWithAction.js'
7 |
8 | storiesOf('Snackbar', module)
9 | .addDecorator(wrapStory)
10 | .add('Snackbar', () => )
11 | .add('Snackbar With Action', () => )
12 |
--------------------------------------------------------------------------------
/stories/spinner.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import wrapStory from './decorators/wrapStory'
4 |
5 | import Spinner from '../src/components/spinner/demos/Spinner.js'
6 | import SpinnerSingleColor from '../src/components/spinner/demos/SpinnerSingleColor.js'
7 |
8 | storiesOf('Spinner', module)
9 | .addDecorator(wrapStory)
10 | .add('Spinner', () => )
11 | .add('Spinner Single Color', () => )
12 |
--------------------------------------------------------------------------------
/stories/switch.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import wrapStory from './decorators/wrapStory'
4 |
5 | import Switch from '../src/components/switch/demos/Switch.js'
6 |
7 | storiesOf('Switch', module)
8 | .addDecorator(wrapStory)
9 | .add('Switch', () => )
10 |
--------------------------------------------------------------------------------
/stories/tables.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import wrapStory from './decorators/wrapStory'
4 |
5 | import DataTable from '../src/components/tables/demos/DataTable.js'
6 |
7 | storiesOf('Tables', module)
8 | .addDecorator(wrapStory)
9 | .add('Data Table', () => )
10 |
--------------------------------------------------------------------------------
/stories/textfield.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import wrapStory from './decorators/wrapStory'
4 |
5 | import Error from '../src/components/textfield/demos/Error.js'
6 | import HelperText from '../src/components/textfield/demos/HelperText.js'
7 | import MultiLine from '../src/components/textfield/demos/MultiLine.js'
8 | import SingleLine from '../src/components/textfield/demos/SingleLine.js'
9 |
10 | storiesOf('Textfield', module)
11 | .addDecorator(wrapStory)
12 | .add('Error', () => )
13 | .add('Helper Text', () => )
14 | .add('Multi Line', () => )
15 | .add('Single Line', () => )
16 |
--------------------------------------------------------------------------------
/stories/tooltips.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import wrapStory from './decorators/wrapStory'
4 |
5 | import Above from '../src/components/tooltips/demos/Above.js'
6 | import Below from '../src/components/tooltips/demos/Below.js'
7 | import Large from '../src/components/tooltips/demos/Large.js'
8 | import Left from '../src/components/tooltips/demos/Left.js'
9 | import MultiLine from '../src/components/tooltips/demos/MultiLine.js'
10 | import Right from '../src/components/tooltips/demos/Right.js'
11 |
12 | storiesOf('Tooltips', module)
13 | .addDecorator(wrapStory)
14 | .add('Above', () => )
15 | .add('Below', () => )
16 | .add('Large', () => )
17 | .add('Left', () => )
18 | .add('Multi Line', () => )
19 | .add('Right', () => )
20 |
--------------------------------------------------------------------------------
/tests/_setup/test-bundler.js:
--------------------------------------------------------------------------------
1 | import 'jest-enzyme'
2 | import React from 'react'
3 | import Enzyme, { mount, shallow } from 'enzyme'
4 | import Adapter from 'enzyme-adapter-react-16'
5 | import './until'
6 | import './textOnly'
7 |
8 | Enzyme.configure({ adapter: new Adapter() })
9 |
10 | global.shallowComponent = (component, defaultProps = {}, children) => (
11 | props = {},
12 | ) =>
13 | shallow(
14 | React.createElement(component, { ...defaultProps, ...props }, children),
15 | )
16 |
17 | global.mountComponent = (component, defaultProps = {}, children) => (
18 | props = {},
19 | ) =>
20 | mount(React.createElement(component, { ...defaultProps, ...props }, children))
21 |
22 | const matchers = {
23 | toHaveInnerText() {
24 | return {
25 | compare(actual, expected) {
26 | const actualText = actual.textOnly()
27 | const pass = actualText === expected
28 | const expectation = pass ? 'Expected not to have text' : 'Expected text'
29 | return {
30 | pass,
31 | message: () =>
32 | `${expectation} "${expected}", but got "${actualText}"`,
33 | }
34 | },
35 | }
36 | },
37 | }
38 |
39 | beforeEach(() => {
40 | jest.addMatchers({ ...matchers })
41 | jest
42 | .spyOn(window, 'requestAnimationFrame')
43 | .mockImplementation((cb) => setTimeout(cb))
44 | jest
45 | .spyOn(window, 'cancelAnimationFrame')
46 | .mockImplementation((timeout) => clearTimeout(timeout))
47 | })
48 |
49 | afterEach(() => {
50 | window.requestAnimationFrame.mockRestore()
51 | window.cancelAnimationFrame.mockRestore()
52 | })
53 |
--------------------------------------------------------------------------------
/tests/_setup/textOnly.js:
--------------------------------------------------------------------------------
1 | import ShallowWrapper from 'enzyme/ShallowWrapper'
2 |
3 | function textRecursively(wrapper) {
4 | return wrapper
5 | .children()
6 | .map((child) => {
7 | if (!child.children().length) {
8 | if (child.getElement()) {
9 | return '' // empty element with no children
10 | }
11 | return child.text() // text content
12 | }
13 | return textRecursively(child) // element has child nodes
14 | })
15 | .join('')
16 | }
17 |
18 | function textOnly() {
19 | return this.single('textOnly', () => textRecursively(this))
20 | }
21 |
22 | ShallowWrapper.prototype.textOnly = textOnly
23 |
--------------------------------------------------------------------------------
/tests/_setup/until.js:
--------------------------------------------------------------------------------
1 | import ShallowWrapper from 'enzyme/ShallowWrapper'
2 |
3 | /* eslint-disable no-param-reassign */
4 | // Copied from gist
5 | // https://gist.github.com/matthieuprat/5fd37abbd4a4002e6cfe0c73ae54cda8
6 | function shallowRecursively(wrapper, selector) {
7 | // Do not try to shallow render empty nodes and host elements
8 | // (a.k.a primitives). Simply return the wrapper in that case.
9 | if (
10 | wrapper.isEmptyRender() ||
11 | typeof wrapper.getElement().type === 'string'
12 | ) {
13 | return wrapper
14 | }
15 | //
16 | // console.log(wrapper.getElement().type);
17 | // console.log(selector);
18 |
19 | return selector && wrapper.is(selector)
20 | ? wrapper.dive()
21 | : shallowRecursively(wrapper.dive(), selector)
22 | }
23 |
24 | function until(selector) {
25 | return this.single('until', () => shallowRecursively(this, selector))
26 | }
27 |
28 | ShallowWrapper.prototype.until = until
29 |
--------------------------------------------------------------------------------
/tests/badges/Badge.spec.js:
--------------------------------------------------------------------------------
1 | import Badge, { BadgeBase } from '../../src/components/badges/Badge'
2 |
3 | const render = shallowComponent(Badge, { text: 'foo' }, 'Hello World')
4 |
5 | describe('', () => {
6 | let badge
7 |
8 | beforeEach(() => {
9 | badge = render().until(BadgeBase)
10 | })
11 |
12 | it('has the right displayName', () => {
13 | expect(Badge.displayName).toEqual('Badge')
14 | })
15 |
16 | it('is deeply extendable', () => {
17 | expect(typeof Badge.extend).toEqual('function')
18 | expect(typeof Badge.extend``.extend).toEqual('function')
19 | })
20 |
21 | it('renders a BadgeWrap with className', () => {
22 | expect(badge.find('BadgeWrap')).toBePresent()
23 | })
24 |
25 | it('renders a BadgeText with [prop] text', () => {
26 | expect(badge.find('BadgeText')).toBePresent()
27 | expect(badge.find('BadgeText')).toHaveInnerText('foo')
28 | })
29 |
30 | it('renders its children', () => {
31 | expect(
32 | badge
33 | .find('BadgeWrap')
34 | .children()
35 | .at(0)
36 | .text(),
37 | ).toEqual('Hello World')
38 | })
39 | })
40 |
--------------------------------------------------------------------------------
/tests/buttons/index.spec.js:
--------------------------------------------------------------------------------
1 | import Button, { ButtonBase } from '../../src/components/buttons/Button'
2 |
3 | const render = shallowComponent(Button)
4 |
5 | describe('', () => {
6 | it('is has the right displayName', () => {
7 | expect(Button.displayName).toEqual('Button')
8 | })
9 |
10 | it('is deeply extendable', () => {
11 | expect(typeof Button.extend).toEqual('function')
12 | expect(typeof Button.extend``.extend).toEqual('function')
13 | })
14 |
15 | describe('when the [prop] text is defined and there are not children', () => {
16 | it('renders text inside