├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .gitignore
├── README.md
├── index.js
└── package.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_size = 2
6 | end_of_line = lf
7 | indent_style = space
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | src/decls/**/*.js
2 | src/vendor/**/*.js
3 | src/test/utils.js
4 | *.test.js
5 | example/
6 | flow-typed/**/*.js
7 | lib/
8 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extends": "airbnb",
4 | "rules": {
5 | "semi": [2, "never"],
6 | "arrow-parens": 0,
7 | "class-methods-use-this": 0,
8 | "comma-dangle": ["error", {
9 | "arrays": "never",
10 | "objects": "never",
11 | "imports": "never",
12 | "exports": "never",
13 | "functions": "ignore"
14 | }],
15 | "symbol-description": 0,
16 | "no-unused-vars": [2, { "varsIgnorePattern": "^_+$" }],
17 | "import/no-extraneous-dependencies": 0,
18 | "import/prefer-default-export": 0,
19 | "no-confusing-arrow": 0,
20 | "no-else-return": 0,
21 | "react/sort-comp": 0,
22 | "react/jsx-filename-extension": 0,
23 | "no-prototype-builtins": 0,
24 | "no-duplicate-imports": 0
25 | },
26 | "env": {
27 | "mocha": true,
28 | "browser": "true"
29 | },
30 | "parserOptions": {
31 | "ecmaVersion": 7,
32 | "sourceType": "module",
33 | "ecmaFeatures": {
34 | "impliedStrict": true,
35 | "jsx": true,
36 | "experimentalObjectRestSpread": true
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .idea
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Styled Media Queries:
media queries for `styled-components` 💅
2 |
3 | The `mediaQuery` function provided by this module extends [Styled Components](https://www.styled-components.com), giving it **a helper for managing media queries**.
4 |
5 | ## How does it work?
6 |
7 | Here's a quick example:
8 |
9 | 1. Start by defining your globally-shared media queries. We'll use a static JavaScript object to do this and we will use variable names of our own choosing.
10 | ```JS
11 | // sharedFile.js
12 |
13 | /* You could also name this object "respondTo", "atMedia", "nomNoms", etc. */
14 | export const media = {
15 | smallOnly: "",
16 | medium: "",
17 | large: "",
18 | wide: "",
19 | extraWide: ""
20 | };
21 | ```
22 | 2. Then import the `styled-media-queries` module and use it define the media query "features" we want for each name.
23 | ```JS
24 | // sharedFile.js
25 | import { mediaQuery } from 'styled-media-queries';
26 |
27 | // Totally optional: define some re-usable breakpoint numbers.
28 | export const breakpoint = {
29 | medium: 666,
30 | large: 888,
31 | wide: 999,
32 | extraWide: 1111,
33 | };
34 |
35 | export const media = {
36 | smallOnly: mediaQuery`(max-width: ${(breakpoint.medium - 1) / 16}em)`,
37 | medium: mediaQuery`(min-width: ${breakpoint.medium / 16}em)`,
38 | large: mediaQuery`(min-width: ${breakpoint.large / 16}em)`,
39 | wide: mediaQuery`(min-width: ${breakpoint.wide / 16}em)`,
40 | extraWide: mediaQuery`(min-width: ${breakpoint.extraWide / 16}em)`,
41 | print: mediaQuery`print`,
42 | };
43 | ```
44 | 3. Once we've defined our re-usable media queries, `media.smallOnly` and its siblings are now functions that can handle tagged template literals. Use them in any styled component that needs it.
45 | ```JS
46 | import styled from 'styled-components';
47 | import { media } from './sharedFile.js';
48 |
49 | const Button = styled.button`
50 | width: 100%;
51 |
52 | ${media.medium`
53 | width: auto;
54 | `}
55 |
56 | ${media.extraWide`
57 | font-size: 1.5rem;
58 | `}
59 | `;
60 | ```
61 |
62 | ## TLDR; if you already know what a tag function is.
63 |
64 | ```JavaScript
65 | const mediaQuery = (...queryFeatures) => (...rules) => css`
66 | @media ${css(...queryFeatures)} {
67 | ${css(...rules)}
68 | }`
69 | ```
70 |
71 | The `mediaQuery` method is a tag function that takes the given media query features in a tagged template literal; it returns a new tag function. This new tag function can be used in `styled-components` to take the CSS in a tagged template literal and returns the same CSS but wrapped in the pre-defined media query.
72 |
73 | ## Why does this exist?
74 |
75 | The `css` method of Styled Components is very powerful and allows you to create media query helpers like this:
76 |
77 | ```JS
78 | // style-utils.js
79 | import { css } from 'styled-components'
80 |
81 | export const media = {
82 | handheld: (...args) => css`@media (max-width: 420px) { ${ css(...args) } }`,
83 | tablet: (...args) => css`@media (min-width: 421px) { ${ css(...args) } }`,
84 | }
85 | ```
86 |
87 | The above file creates two "tag functions", `media.handheld` and `media.tablet`, that can be used to handle tagged template literals like this:
88 |
89 | ```JS
90 | import { media } from './style-utils';
91 |
92 | const Box = styled.div`
93 | font-size: 16px;
94 |
95 | ${media.handheld`
96 | font-size: 14px;
97 | `}
98 | `;
99 | ```
100 |
101 | The CSS generated from this will look something like this:
102 |
103 | ```CSS
104 | .examp {
105 | font-size: 16px;
106 | }
107 |
108 | @media (max-width: 420px) {
109 | .examp {
110 | font-size: 14px;
111 | }
112 | }
113 | ```
114 |
115 | Pretty neat. The best part of this method is that it allows the developer to pick whatever name they want when defining the static object that holds all the media query helpers (e.g. `media`, `respondTo`, `atMedia`, …). And, since it is a static object, IDEs will offer auto-complete suggestions when you type the name of the object. I.e. typing `media.` in your IDE will offer `media.handheld`, `media.tablet` and all other media queries defined in your object.
116 |
117 | The only problem with the above method is that there is a lot of boilerplate. ``(...args) => css`@media (query goes here) { ${ css(...args) } }`,`` and it is not possible (for mere mortals) to memorize that.
118 |
119 | So we wrote a simple helper method to make things easier.
120 |
121 | ## API
122 |
123 | `mediaQuery`: A helper method to manage media queries.
124 |
125 | The `mediaQuery` method is a tag function that takes the given media query features in a tagged template literal; it returns a new tag function. This new tag function can be used in styled components to take a CSS rulesets in a tagged template literal and returns the same CSS but wrapped in the pre-defined media query.
126 |
127 | ### Arguments
128 |
129 | 1. `TaggedTemplateLiteral`: A tagged template literal containing the query features of a media query. e.g. `` `(min-width: 48em)` `` or `` `(min-width: 700px), handheld and (orientation: landscape)` ``
130 |
131 | ### Returns
132 |
133 | A new tag function.
134 |
135 | ### Example
136 |
137 | ```JS
138 | // An example mediaQueries.js file.
139 | import { mediaQuery } from 'styled-media-queries';
140 |
141 | // Define commonly used media queries and use them in all of your components.
142 | export const media = {
143 | mobileOnly: mediaQuery`(max-width: ${767 / 16}em)`,
144 | tablet: mediaQuery`(min-width: ${768 / 16}em)`,
145 | print: mediaQuery`print`,
146 | };
147 | ```
148 |
149 | ```JS
150 | // An example component file.
151 | import styled from 'styled-components';
152 | import { media } from './mediaQueries';
153 |
154 | const Button = styled.button`
155 | width: 100%;
156 |
157 | ${media.tablet`
158 | width: auto;
159 | `}
160 |
161 | ${media.print`
162 | color: black;
163 | `}
164 | `;
165 | ```
166 |
167 | This will generate CSS like the following:
168 | ```CSS
169 | .examp {
170 | width: 100%;
171 | }
172 |
173 | @media (min-width: 48em) {
174 | .examp {
175 | width: auto;
176 | }
177 | }
178 |
179 | @media print {
180 | .examp {
181 | color: black;
182 | }
183 | }
184 | ```
185 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import { css } from 'styled-components'
2 |
3 | /**
4 | * For the specified media query, returns a tag function that can be used to
5 | * automatically wrap the tagged template literal in its media query.
6 | *
7 | * @param {string} query The string or template literal containing the media
8 | * query features.
9 | */
10 |
11 | const mediaQuery = (...query) => (...rules) => css`@media ${css(...query)} { ${css(...rules)} }`
12 |
13 | export { mediaQuery }
14 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "styled-media-queries",
3 | "version": "1.0.1",
4 | "description": "Allows easy re-usable media queries with styled-components. 💅",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "eslint index.js"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/JohnAlbin/styled-media-queries.git"
12 | },
13 | "keywords": [
14 | "react",
15 | "css",
16 | "css-in-js",
17 | "styled-components"
18 | ],
19 | "author": "John Albin Wilkins (http://john.albin.net/)",
20 | "license": "(MIT OR GPL-2.0)",
21 | "bugs": {
22 | "url": "https://github.com/JohnAlbin/styled-media-queries/issues"
23 | },
24 | "homepage": "https://github.com/JohnAlbin/styled-media-queries#readme",
25 | "devDependencies": {
26 | "eslint": "^3.18.0",
27 | "eslint-config-airbnb": "^13.0.0"
28 | },
29 | "peerDependencies": {
30 | "react": "^0.14.0 || ^15.0.0-0",
31 | "styled-components": "^1.0.0 || ^2.0.0"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------