├── .eslintignore
├── .babelrc
├── src
├── utils.js
├── index.js
├── BaseView.js
├── View.js
├── css.js
└── __tests__
│ ├── css.test.js
│ └── View.test.js
├── .npmignore
├── .eslintrc
├── .vscode
└── settings.json
├── .prettierrc.js
├── .prettierignore
├── .gitignore
├── .storybook
├── addons.js
└── config.js
├── jest.config.js
├── .travis.yml
├── stories
├── css.stories.js
├── View.stories.js
├── ThemeProvider.stories.js
└── Mixins.stories.js
├── LICENSE
├── package.json
└── README.md
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | coverage
3 | dist
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | { "presets": ["@itsjonq/zero/babel"] }
2 |
--------------------------------------------------------------------------------
/src/utils.js:
--------------------------------------------------------------------------------
1 | export { is } from '@itsjonq/is';
2 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | __fixtures__
2 | __mocks__
3 | __tests__
4 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | { "extends": "./node_modules/@itsjonq/zero/eslint.js" }
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.formatOnSave": true
3 | }
4 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = require('@itsjonq/zero/prettier');
2 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | package.json
2 | package-lock.json
3 | node_modules
4 | dist
5 | coverage
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .cache
3 | .eslintcache
4 | .opt-in
5 | .opt-out
6 | coverage
7 | dist
8 | node_modules
9 |
--------------------------------------------------------------------------------
/.storybook/addons.js:
--------------------------------------------------------------------------------
1 | import '@storybook/addon-actions/register';
2 | import '@storybook/addon-links/register';
3 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | const jestConfig = require('@itsjonq/zero/jest');
2 |
3 | module.exports = Object.assign(jestConfig, {
4 | // your overrides here
5 | });
6 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import { View } from './View';
2 |
3 | export { css, cx } from './css';
4 | export { BaseView } from './BaseView';
5 | export { View } from './View';
6 |
7 | export default View;
8 |
--------------------------------------------------------------------------------
/.storybook/config.js:
--------------------------------------------------------------------------------
1 | import { configure } from '@storybook/react';
2 |
3 | // automatically import all files ending in *.stories.js
4 | configure(require.context('../stories', true, /\.stories\.js$/), module);
5 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "lts/*"
4 |
5 | cache:
6 | directories:
7 | - node_modules
8 |
9 | install:
10 | - npm install
11 |
12 | script:
13 | - npm run validate
14 |
15 | after_success:
16 | - npm run coverage
17 |
18 | branches:
19 | only:
20 | - master
21 |
--------------------------------------------------------------------------------
/stories/css.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { css, View } from '../src/index';
3 |
4 | export default {
5 | title: 'css',
6 | };
7 |
8 | export const _default = () => {
9 | const styles = css`
10 | ${({ clr }) => `color: ${clr}`};
11 | padding: 20px;
12 | `;
13 |
14 | return (
15 |
16 | Hello
17 |
18 | );
19 | };
20 |
--------------------------------------------------------------------------------
/stories/View.stories.js:
--------------------------------------------------------------------------------
1 | import React, { useRef } from 'react';
2 | import { View } from '../src/View';
3 |
4 | export default {
5 | title: 'View',
6 | };
7 |
8 | export const _default = () => (
9 | <>
10 |
11 | Hello
12 |
13 | >
14 | );
15 |
16 | const Example = () => {
17 | const ref = useRef();
18 | console.log(ref);
19 | return Hello;
20 | };
21 |
22 | export const ref = () => ;
23 |
--------------------------------------------------------------------------------
/stories/ThemeProvider.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ThemeProvider } from 'emotion-theming';
3 | import { View } from '../src/index';
4 |
5 | const theme = {
6 | fontFamily: 'arial',
7 | };
8 |
9 | export default {
10 | title: 'ThemeProvider',
11 | };
12 |
13 | export const _default = () => {
14 | return (
15 |
16 | Hello
17 |
18 | );
19 | };
20 |
21 | export const themeOverride = () => {
22 | return (
23 |
24 | Hello
25 |
26 | );
27 | };
28 |
--------------------------------------------------------------------------------
/src/BaseView.js:
--------------------------------------------------------------------------------
1 | import styled from '@emotion/styled';
2 | import { sanitizeStyleProps } from 'is-style-prop-valid';
3 | import { is } from './utils';
4 |
5 | const defaultProps = {
6 | boxSizing: 'border-box',
7 | };
8 |
9 | export const BaseView = styled('div')(props => {
10 | const mergedProps = { ...defaultProps, ...props };
11 | const { theme, sx, ...restProps } = mergedProps;
12 |
13 | // Theme support
14 | const themeProps = is.plainObject(theme) ? theme : {};
15 | // Style prop (Override)
16 | const styleProps = is.plainObject(sx) ? sx : {};
17 |
18 | return sanitizeStyleProps({
19 | ...themeProps,
20 | ...restProps,
21 | ...styleProps,
22 | });
23 | });
24 |
25 | export default BaseView;
26 |
--------------------------------------------------------------------------------
/src/View.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { compileToClassName } from './css';
3 | import BaseView from './BaseView';
4 |
5 | /**
6 | * UI Primitive with built-in styled CSS support.
7 | *
8 | * @param {object} props Component props.
9 | * @returns React.Component A React component, enhanced with generated styles.
10 | * @example
11 | * Hello
12 | */
13 | export const View = React.forwardRef((props, ref) => {
14 | const { className, css: cssProp, ...restProps } = props;
15 | const nextClassName = compileToClassName(props);
16 |
17 | return ;
18 | });
19 |
20 | export default View;
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2019 Jon Quach
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
13 | all 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
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/stories/Mixins.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { space, layout, typography, color } from 'styled-system';
3 | import { View, css } from '../src/index';
4 |
5 | export default {
6 | title: 'StyledSystem',
7 | };
8 |
9 | export const _default = () => {
10 | const customMixin = props => {
11 | const { variant } = props;
12 |
13 | switch (variant) {
14 | case 'primary':
15 | return {
16 | background: '#05f',
17 | color: 'white',
18 | };
19 | default:
20 | return `background: #ddd;`;
21 | }
22 | };
23 |
24 | const Box = props => {
25 | return (
26 |
32 | );
33 | };
34 |
35 | return (
36 | <>
37 | Hello
38 | Hello
39 | >
40 | );
41 | };
42 |
43 | export const styledSystem = () => {
44 | // Add styled-system functions to your component
45 | const Box = props => {
46 | return (
47 |
56 | );
57 | };
58 |
59 | return (
60 |
61 | Hello
62 |
63 | );
64 | };
65 |
--------------------------------------------------------------------------------
/src/css.js:
--------------------------------------------------------------------------------
1 | import { css as emotionCss, cx as emotionCx } from 'emotion';
2 | import { is } from './utils';
3 |
4 | export { cx } from 'emotion';
5 |
6 | export const INTERNAL_COMPILE_KEY = '__SECRET_STYLED_VIEW_TO_COMPILE__';
7 |
8 | export function css(...args) {
9 | const [firstArg, ...fns] = args;
10 |
11 | if (!fns.length) {
12 | if (is.array(firstArg)) {
13 | return css.apply(css, firstArg);
14 | }
15 | if (is.string(firstArg)) {
16 | return emotionCss`${firstArg}`;
17 | }
18 | if (is.plainObject(firstArg)) {
19 | return emotionCss(firstArg);
20 | }
21 | return '';
22 | }
23 |
24 | return {
25 | args,
26 | [INTERNAL_COMPILE_KEY]: true,
27 | };
28 | }
29 |
30 | export function cxx(...args) {
31 | return props => {
32 | const [strings, ...fns] = args;
33 | const results = [];
34 |
35 | strings.forEach((string, index) => {
36 | results.push(string);
37 | const fn = fns[index];
38 |
39 | if (is.function(fn)) {
40 | try {
41 | const rx = emotionCss`
42 | ${fn(props)};
43 | `;
44 | results.push(rx);
45 | } catch (err) {
46 | console.warn(
47 | 'styled-view: Error when parsing css',
48 | '\n',
49 | '\n',
50 | err,
51 | );
52 | results.push('');
53 | }
54 | }
55 | });
56 |
57 | return emotionCss`
58 | ${results}
59 | `;
60 | };
61 | }
62 |
63 | export function compileToClassName(props) {
64 | const { className, css } = props;
65 | let result = '';
66 |
67 | if (is.plainObject(css)) {
68 | if (css[INTERNAL_COMPILE_KEY]) {
69 | result = cxx.apply(cxx, [...css.args])(props);
70 | } else {
71 | result = emotionCss(css);
72 | }
73 | }
74 |
75 | if (is.array(css)) {
76 | result = emotionCss(css);
77 | }
78 |
79 | if (is.string(css)) {
80 | result = css;
81 | }
82 |
83 | return emotionCx(className, result);
84 | }
85 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "styled-view",
3 | "version": "0.0.10",
4 | "description": "UI Primitive for React, with CSS-in-JS support",
5 | "main": "dist/cjs/index.js",
6 | "module": "dist/es/index.js",
7 | "sideEffects": false,
8 | "private": false,
9 | "scripts": {
10 | "prestart": "zero prestart",
11 | "build:es": "BUILD_FORMAT=es zero build -d dist/es",
12 | "build:cjs": "BUILD_FORMAT=cjs zero build -d dist/cjs",
13 | "build": "npm run build:cjs && npm run build:es -- --no-clean",
14 | "coverage": "nyc report --temp-directory=coverage --reporter=text-lcov | coveralls",
15 | "open:coverage": "open ./coverage/lcov-report/index.html",
16 | "lint": "zero lint",
17 | "dev": "zero test",
18 | "start": "npm run storybook",
19 | "test": "zero test --coverage",
20 | "test:coverage": "npm run test",
21 | "format": "zero format",
22 | "validate": "zero validate",
23 | "release": "zero release",
24 | "version": "npm run build",
25 | "precommit": "zero pre-commit",
26 | "storybook": "start-storybook -p 6006",
27 | "build-storybook": "build-storybook"
28 | },
29 | "files": [
30 | "dist",
31 | "README.md",
32 | "LICENSE"
33 | ],
34 | "author": "Jon Quach (https://jonquach.com)",
35 | "repository": {
36 | "type": "git",
37 | "url": "git+https://github.com/itsjonq/styled-view.git"
38 | },
39 | "bugs": {
40 | "url": "https://github.com/itsjonq/styled-view/issues"
41 | },
42 | "homepage": "https://github.com/itsjonq/styled-view#readme",
43 | "keywords": [
44 | "styled",
45 | "components",
46 | "styled-components",
47 | "emotion",
48 | "view",
49 | "styled-view",
50 | "css-in-js",
51 | "css",
52 | "react"
53 | ],
54 | "license": "MIT",
55 | "publishConfig": {
56 | "access": "public"
57 | },
58 | "peerDependencies": {
59 | "react": "^16"
60 | },
61 | "devDependencies": {
62 | "@babel/core": "7.7.4",
63 | "@itsjonq/cyan": "^0.15.1",
64 | "@itsjonq/zero": "^4.1.7",
65 | "@storybook/addon-actions": "5.2.6",
66 | "@storybook/addon-links": "5.2.6",
67 | "@storybook/addons": "5.2.6",
68 | "@storybook/react": "5.2.6",
69 | "@styled-system/css": "5.0.23",
70 | "babel-loader": "8.0.6",
71 | "coveralls": "3.0.9",
72 | "emotion-theming": "10.0.19",
73 | "nyc": "14.1.1",
74 | "react": "16.12.0",
75 | "react-dom": "16.12.0",
76 | "styled-system": "5.1.2"
77 | },
78 | "dependencies": {
79 | "@emotion/core": "^10.x",
80 | "@emotion/styled": "^10.x",
81 | "@itsjonq/is": "^0.0.2",
82 | "emotion": "^10.x",
83 | "is-style-prop-valid": "^0.0.7"
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/__tests__/css.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { cy } from '@itsjonq/cyan';
3 | import { css, View } from '../index';
4 | import { space, layout, typography, color } from 'styled-system';
5 |
6 | describe('css', () => {
7 | test('should return string for invalid type', () => {
8 | expect(css(true)).toBe('');
9 | });
10 |
11 | test('should render string styles', () => {
12 | cy.render(
13 | ,
18 | );
19 |
20 | const el = cy.get('div');
21 |
22 | expect(el.style().background).toBe('red');
23 | });
24 |
25 | test('should render array styles', () => {
26 | cy.render();
27 |
28 | const el = cy.get('div');
29 |
30 | expect(el.style().background).toBe('red');
31 | });
32 |
33 | test('should render object styles', () => {
34 | cy.render(
35 | ,
40 | );
41 |
42 | const el = cy.get('div');
43 |
44 | expect(el.style().background).toBe('red');
45 | });
46 |
47 | test('should render function styles', () => {
48 | const bg = ({ bg }) => `background: ${bg};`;
49 |
50 | cy.render(
51 | ,
57 | );
58 |
59 | const el = cy.get('div');
60 |
61 | expect(el.style().background).toBe('red');
62 | });
63 |
64 | test('should render string + function styles', () => {
65 | const bg = ({ bg }) => `background: ${bg};`;
66 |
67 | cy.render(
68 | ,
76 | );
77 |
78 | const el = cy.get('div');
79 |
80 | expect(el.style().background).toBe('red');
81 | expect(el.style().padding).toBe('20px');
82 | expect(el.style().margin).toBe('10px');
83 | });
84 |
85 | test('should handle mixins from 3rd party libraries', () => {
86 | cy.render(
87 | ,
98 | );
99 |
100 | const el = cy.get('div');
101 |
102 | expect(el.style().background).toBe('red');
103 | expect(el.style().padding).toBe('32px');
104 | expect(el.style().margin).toBe('8px');
105 | });
106 |
107 | test('should handle invalid type', () => {
108 | cy.render(
109 | ,
115 | );
116 |
117 | const el = cy.get('div');
118 |
119 | expect(el.style().background).toBe('red');
120 | });
121 |
122 | test('should handle invalid function return', () => {
123 | const spy = jest.fn();
124 | console.warn = spy;
125 |
126 | const errorMixin = () => {
127 | throw new Error('Nope');
128 | };
129 |
130 | cy.render(
131 | ,
137 | );
138 |
139 | const el = cy.get('div');
140 |
141 | expect(el.style().background).toBe('red');
142 | /* eslint-disable jest/prefer-called-with */
143 | expect(spy).toHaveBeenCalled();
144 | /* eslint-enable jest/prefer-called-with */
145 | });
146 | });
147 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ✌️ Styled View
2 |
3 | [](https://travis-ci.org/ItsJonQ/styled-view)
4 | [](https://coveralls.io/github/ItsJonQ/styled-view?branch=master)
5 | [](https://bundlephobia.com/result?p=styled-view)
6 |
7 | > UI Primitive for React, with CSS-in-JS support
8 |
9 | ## Table of contents
10 |
11 |
12 |
13 |
14 | - [Installation](#installation)
15 | - [Usage](#usage)
16 | - [`css` function](#css-function)
17 | - [`css` prop](#css-prop)
18 | - [`sx` prop](#sx-prop)
19 | - [Mixins](#mixins)
20 | - [Theming](#theming)
21 |
22 |
23 |
24 | ## Installation
25 |
26 | ```
27 | npm install styled-view
28 | ```
29 |
30 | ## Usage
31 |
32 | The `` component supports all of the default [CSSProperties](https://github.com/ItsJonQ/is-style-prop-valid/blob/master/src/CSSProperty.js#L47) as props. The styles transformed and handled by [Emotion](https://emotion.sh/docs/introduction).
33 |
34 | ```jsx
35 | import React from 'react';
36 | import { View } from 'styled-view';
37 |
38 | function Example() {
39 | return (
40 |
41 | Hello
42 |
43 | );
44 | }
45 | ```
46 |
47 | ### `css` function
48 |
49 | `css` is a utility function that works with the `` `css` prop. The API is similar to the [Emotion's css prop](https://emotion.sh/docs/css-prop#string-styles). Unlike the `css` prop, the [tagged template literal](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) allows for functions, which is handy for mixins.
50 |
51 | ```jsx
52 | import React from 'react';
53 | import { css, View } from 'styled-view';
54 |
55 | function Example() {
56 | const variant = ({ variant }) => {
57 | switch (variant) {
58 | case 'primary':
59 | return `
60 | background-color: blue;
61 | color: white;
62 | `;
63 | default:
64 | return `
65 | background-color: yellow;
66 | `;
67 | }
68 | };
69 |
70 | return (
71 |
81 | Hello
82 |
83 | );
84 | }
85 | ```
86 |
87 | ### `css` prop
88 |
89 | `` accepts a special `css` prop, which allows you to write styles, just like the [css prop](https://emotion.sh/docs/css-prop#string-styles) or [styled component](https://emotion.sh/docs/styled#styling-elements-and-components) from Emotion.
90 |
91 | ```jsx
92 | import React from 'react';
93 | import { View } from 'styled-view';
94 |
95 | function Example() {
96 | const css = `
97 | &:hover {
98 | background-color: blue;
99 | color: white;
100 | }
101 |
102 | @media (min-width: 768px) {
103 | padding: 40px;
104 | }
105 | `;
106 |
107 | return (
108 |
109 | Hello
110 |
111 | );
112 | }
113 | ```
114 |
115 | ### `sx` prop
116 |
117 | `` accepts a special `sx` prop, which allows you to write style objects.
118 |
119 | ```jsx
120 | import React from 'react';
121 | import { View } from 'styled-view';
122 |
123 | function Example() {
124 | return Hello;
125 | }
126 | ```
127 |
128 | ### Mixins
129 |
130 | `` can render mixins (`function`) when passed into the `css` function. This enables integration with libraries like [Styled Systems](https://github.com/styled-system/styled-system). It also enable you to add your very own custom mixins!
131 |
132 | ```jsx
133 | import React from 'react';
134 | import { space, layout, typography, color } from 'styled-system';
135 | import { css, View } from 'styled-view';
136 |
137 | // Add styled-system functions to your component
138 | function Box(props) {
139 | return (
140 |
149 | );
150 | }
151 |
152 | function Example() {
153 | return (
154 |
155 | Hello
156 |
157 | );
158 | }
159 | ```
160 |
161 | This concepts was inspired by [James Newell](https://github.com/jameslnewell) ❤️!
162 |
163 | ### Theming
164 |
165 | Theming `` works as specified by [Emotion Theming](https://emotion.sh/docs/theming).
166 |
167 | ```jsx
168 | import React from 'react';
169 | import { ThemeProvider } from 'emotion-theming';
170 | import { View } from 'styled-view';
171 |
172 | const theme = {
173 | fontFamily: 'arial',
174 | };
175 |
176 | function Example() {
177 | return (
178 |
179 | Hello
180 |
181 | );
182 | }
183 | ```
184 |
--------------------------------------------------------------------------------
/src/__tests__/View.test.js:
--------------------------------------------------------------------------------
1 | import React, { useRef } from 'react';
2 | import { cy } from '@itsjonq/cyan';
3 | import { css as emotionCss } from 'emotion';
4 | import { ThemeProvider } from 'emotion-theming';
5 | import { View, css } from '../index';
6 |
7 | describe('View', () => {
8 | describe('rendering', () => {
9 | test('should render a div, by default', () => {
10 | cy.render();
11 |
12 | const el = cy.get('div');
13 |
14 | expect(el.exists()).toBeTruthy();
15 | });
16 |
17 | test('should render as another component, using `as` prop', () => {
18 | cy.render(Hello);
19 |
20 | const el = cy.get('button');
21 |
22 | expect(el.exists()).toBeTruthy();
23 | expect(el.text()).toBe('Hello');
24 |
25 | expect(cy.get('div').exists()).toBe(false);
26 | });
27 | });
28 |
29 | describe('styles', () => {
30 | test('should render styles', () => {
31 | cy.render(
32 |
33 | Hello
34 | ,
35 | );
36 |
37 | const el = cy.get('div');
38 |
39 | expect(el.style().background).toBe('pink');
40 | expect(el.style().color).toBe('white');
41 | });
42 |
43 | test('should render styles using css prop', () => {
44 | cy.render(
45 |
51 | Hello
52 | ,
53 | );
54 |
55 | const el = cy.get('div');
56 |
57 | expect(el.style().background).toBe('purple');
58 | expect(el.style().color).toBe('white');
59 | });
60 |
61 | test('should render object styles using css prop', () => {
62 | cy.render(
63 |
70 | Hello
71 | ,
72 | );
73 |
74 | const el = cy.get('div');
75 |
76 | expect(el.style().background).toBe('red');
77 | expect(el.style().color).toBe('black');
78 | expect(el.style().padding).toBe('21px');
79 | });
80 |
81 | test('should render styles using sx prop', () => {
82 | cy.render(
83 |
90 | Hello
91 | ,
92 | );
93 |
94 | const el = cy.get('div');
95 |
96 | expect(el.style().background).toBe('red');
97 | expect(el.style().color).toBe('black');
98 | expect(el.style().padding).toBe('21px');
99 | });
100 |
101 | test('should handle invalid sx prop', () => {
102 | cy.render(Hello);
103 |
104 | const el = cy.get('div');
105 |
106 | expect(el.style().zIndex).not.toBe(100);
107 | });
108 |
109 | test('should handle css prop functions', () => {
110 | const Example = props => {
111 | const mixin = ({ p }) => `padding: ${p * 4}px`;
112 | return (
113 |
119 | );
120 | };
121 |
122 | const customCss = css`
123 | background: pink;
124 | `;
125 |
126 | cy.render();
127 |
128 | expect(cy.get('div').style().background).toBe('pink');
129 | expect(cy.get('div').style().padding).toBe('8px');
130 | });
131 | });
132 |
133 | describe('theming', () => {
134 | test('should enable theming', () => {
135 | const theme = {
136 | fontFamily: 'arial',
137 | };
138 |
139 | cy.render(
140 |
141 | Hello
142 | ,
143 | );
144 |
145 | expect(cy.get('div').style().fontFamily).toBe('arial');
146 | });
147 |
148 | test('should recognize own themed props', () => {
149 | const theme = {
150 | fontFamily: 'arial',
151 | };
152 |
153 | cy.render(
154 |
155 | Hello
156 | ,
157 | );
158 |
159 | expect(cy.get('div').style().fontFamily).toBe('georgia');
160 | });
161 |
162 | test('should handle invalid theme prop', () => {
163 | cy.render(Hello);
164 |
165 | expect(cy.get('div').exists()).toBe(true);
166 | });
167 |
168 | test('should override theming if props are defined', () => {
169 | const theme = {
170 | fontFamily: 'arial',
171 | };
172 |
173 | cy.render(
174 |
175 | Title
176 |
177 | Hello
178 |
179 | There
180 | Click
181 |
182 | Subtitle
183 |
184 |
185 |
186 | ,
187 | );
188 |
189 | expect(cy.get('h1').style().fontFamily).toBe('arial');
190 | expect(cy.get('div').style().fontFamily).toBe('georgia');
191 | expect(cy.get('span').style().fontFamily).toBe('monospace');
192 | expect(cy.get('button').style().fontFamily).toBe('arial');
193 | expect(cy.get('h2').style().fontFamily).toBe('serif');
194 | });
195 | });
196 | });
197 |
--------------------------------------------------------------------------------