Skip to content

Commit d55f01f

Browse files
author
John Persson
committed
Merge branch 'develop'
2 parents de9ba4b + 1000dfc commit d55f01f

2 files changed

Lines changed: 84 additions & 100 deletions

File tree

README.md

Lines changed: 68 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
[![Travis](https://img.shields.io/travis/rust-lang/rust.svg)]()
55

66
## Styled Components Breakpoint 💅
7-
This package provides a friendly API for working with breakpoints in [Styled Components](https://www.styled-components.com/). It allows you to set up any number of breakpoints with a naming convention of your choice.
8-
Once set up you'll have three main ways of interacting with your breakpoints `up` (min-width), `down` (max-width), and `only` (a range between two breakpoints).
7+
This library provides utility functions for dealing with media queries, to make them reusable and easier to read. It can be used as an alternative to SASS/LESS mixins.
8+
9+
More on mixins and [Styled Components](https://www.styled-components.com/) in [this article](https://github.com/styled-components/styled-components/blob/master/docs/tips-and-tricks.md).
910

1011
---
1112

@@ -17,25 +18,14 @@ npm install @humblebee/styled-components-breakpoint
1718
```
1819
---
1920

20-
### Usage and example
21-
22-
The default export of `styled-components-breakpoint` is a function that accepts a config object with your breakpoints. This will return an instance with utility functions for each breakpoint.
23-
I'd recommend that you store this instance in a separate file that can later be imported and used by any component.
21+
### Usage and setup
2422

25-
Coming from form SASS I like to think of these kind of utility functions for `styled-components` in terms of `mixins`. I also think it makes seance to keep these "mixins" close to our projects themes (if any exist), to make them easier to discover when working on other styles. With this in mind the folder structure could look something like this:
23+
The default export of `styled-components-breakpoint` is a function that accepts a `config` object of breakpoints. This will return an object with three main utility methods/mixins: `up` (min-width), `down` (max-width) and `only` (a range between two media queries), all described in detail below.
2624

27-
.
28-
+--componsnts
29-
| +--Button.js
30-
+--themes
31-
| +--mixins.js
32-
33-
34-
`themes/mixins.js`
3525
```javascript
3626
import styledBreakpoint from '@humblebee/styled-components-breakpoint';
3727

38-
// Create an instance of styled-components-breakpoint and pass it an object of breakpoints.
28+
// Creates an object with breakpoint utility methods.
3929
export const breakpoint = styledBreakpoint({
4030
xs: 320,
4131
s: 576,
@@ -45,104 +35,96 @@ export const breakpoint = styledBreakpoint({
4535
});
4636
```
4737

48-
`components/Button.js`
38+
#### Up
4939
```javascript
50-
// Styled Components
51-
import styled from 'styled-components';
52-
// Our breakpoint instance/mixin
53-
import { breakpoint } from '../../theme/mixins';
40+
breakpoint.up('m')
41+
// Will return a media query with a min-width of 768
42+
// @media only screen and (min-width: 768px)
43+
```
5444

55-
const Button = styled.button`
56-
background: white;
57-
${breakpoint.m}`
58-
background: palevioletred;
59-
`
60-
`
61-
});
45+
#### Down
46+
```javascript
47+
breakpoint.down('m')
48+
// Will return a media query with a max-width of 768
49+
// @media only screen and (max-width: 768px)
50+
```
51+
52+
#### Only
53+
```javascript
54+
breakpoint.only('m')
55+
// Will return a range media query between "m" and the next upper breakpoint "l"
56+
// @media only screen and (min-width: 768px) and (max-width: 1200px)
6257
```
6358

64-
In the above example we create an instance of `styled-components-breakpoint` in a file called `themes/mixins.js` and export it with the name `breakpoint`.
65-
We then import `breakpoint` in a separate file called `components/Button.js` and use it inside the styling of our `styled-component` button.
66-
The function `breakpoint.m` will result in the following media query: `'@media only screen and (min-width: 768px)'`, giving our button component a `background-color` of `palevioletred` when the viewport is wider than 768px.
59+
```javascript
60+
breakpoint.only('m', 'xl')
61+
// Will return a range media query between "m" and the breakpoint passed as the second argument, "xl"
62+
// @media only screen and (min-width: 768px) and (max-width: 1200px)
63+
```
6764

68-
## API
65+
#### Shorthand
6966

70-
Continuing on the above example, you have access to all the other breakpoints in the same manner, in our case: `breakpoint.xs`, `breakpoint.s`, `breakpoint.m`, `breakpoint.l`, `breakpoint.xl`. As mentioned in the intro you can add as many breakpoints as you like with any naming convention you prefer. If you prefer the naming convention used in Twitter Bootstrap, your config object would look like this.
67+
There is also a shorthand for mobile first media queries (min-width). Calling `breakpoint.m` is the same as `breakppoint.up('m')`.
7168

7269
```javascript
73-
export const breakpoint = styledBreakpoint({
74-
xs: 320,
75-
sm: 576,
76-
md: 768,
77-
lq: 992,
78-
xl: 1200,
79-
});
70+
`breakpoint.m'`
71+
// Will return a media query with a min-width of 768
72+
// @media only screen and (min-width: 768px)
8073
```
81-
8274
---
8375

84-
#### breakpoint.up.m
76+
### Usage with styled components
77+
In the following example we create a styled button component.
8578

86-
In the "Usage and example" section we made use of the function `breakpoint.m`, this is a shorthand for writing `breakpoint.up.m`. The reason for this shorthand is to encourage the usage of mobile-first breakpoints, i.e. `min-width` media queries.
87-
88-
The functions `breakpoint.m` and `breakpoint.up.m` are the same.
79+
This is the folder structure we'll be working with.
80+
```
81+
.
82+
+--components
83+
| +--Button.js
84+
+--themes
85+
| +--mixins.js
86+
```
8987

88+
`themes/mixins.js`
9089
```javascript
91-
const Button = styled.button`
92-
background: white;
93-
${breakpoint.up.m}`
94-
background: palevioletred;
95-
`
96-
`
90+
import styledBreakpoint from '@humblebee/styled-components-breakpoint';
91+
92+
// Create an instance of styled-components-breakpoint and pass it an object of breakpoints.
93+
export const breakpoint = styledBreakpoint({
94+
xs: 320,
95+
s: 576,
96+
m: 768,
97+
l: 992,
98+
xl: 1200,
9799
});
98100
```
99101

100-
#### breakpoint.down.m
101-
102-
In contrast to `breakpoint.up`, `breakpoint.down` goes the opposite direction and returns a `max-width` media query. The example below would return the media query `@media only screen and (min-width: 768px)`.
103-
102+
`components/Button.js`
104103
```javascript
104+
// Styled Components
105+
import styled from 'styled-components';
106+
// Our breakpoint instance/mixin
107+
import { breakpoint } from '../../theme/mixins';
108+
105109
const Button = styled.button`
106110
background: white;
107-
${breakpoint.down.m}`
111+
font-size: 18px;
112+
${breakpoint.down(s)}`
113+
font-size: 12px;
114+
`
115+
${breakpoint.m}`
108116
background: palevioletred;
109117
`
110118
`
111119
});
112120
```
113121

114-
#### breakpoint.only.m(breakpoint?)
115-
116-
Unlike `up` and `down`, the `only` function accepts an optional breakpoint argument in the form of a string. This argument is used to return a range media query, between the breakpoint used in the executing function and the passed argument.
117-
For example, executing `breakpoint.only.m('xl')`, will return a range between the `m` and `xl` breakpoints.
118-
```javascript
119-
`breakpoint.only.m('xl')`
120-
// Will return:
121-
// @media only screen and (min-width: 768px) and (max-width: 1200px)
122-
```
123-
124-
It works just as well to pass a smaller breakpoint than the executing function. For example starting at breakpoint `m` and going down to `s`.
125-
```javascript
126-
`breakpoint.only.m('s')`
127-
// Will return:
128-
// @media only screen and (max-width: 768px) and (min-width: 576px)
129-
```
130-
131-
If no argument is passed the next upper breakpoint will be used implicitly. For example, executing `breakpoint.only.m()`, will return a range between the `m` and `l` breakpoints.
132-
133-
```javascript
134-
`breakpoint.only.m()`
135-
// Will return:
136-
// @media only screen and (min-width: 768px) and (max-width: 992px)
137-
```
138-
139-
**Important! Even if no breakpoint argument is passed to `only`, it is still necessary to actually execute the function. If not no media query will be returned.**
122+
The first mixin `breakpoint.down(s)`, will give the styled button component a font size of 12px, at a breakpoint lower than "s", i.e. max-width(320px).
140123

141-
**Correct: breakpoint.only.m()**
142-
143-
**Wrong: breakpoint.only.m**
124+
The second mixin `breakpoint.m`, uses the short hand version of `breakpoint.up.('m')`, and will give the button a background of `palevioletred`, at a breakpoint higher than "m", i.e. min-width(768).
144125

145126
---
146127

147128
Happy coding!
148-
/The bees at [Humblebee](http://humblebee.se) 🐝
129+
130+
/ The bees at [Humblebee](http://humblebee.se) 🐝

src/index.js

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export const getNextMedia = (breakpoints: Breakpoints, width: number): number =>
4646
};
4747

4848
export const mediaRules =
49-
(breakpoints: Breakpoints, widthKey: string, rule: Rule, boundKey: string) => {
49+
(breakpoints: Breakpoints, widthKey: string, rule: Rule, boundKey?: string) => {
5050
const width = breakpoints[widthKey];
5151
const bound = breakpoints[boundKey];
5252
let baseWidthRule = mediaWidthRule(rule);
@@ -74,16 +74,18 @@ export const mediaRules =
7474
return [].concat([baseRule], boundRule ? [boundRule] : []).join(' and ');
7575
};
7676

77-
export const getMedias = (breakpoints: Breakpoints, rule: Rule, method: boolean = false) => (
78-
Object.keys(breakpoints).reduce((acc, key) => {
77+
export const getMixin = (breakpoints: Breakpoints, key: string, rule: Rule = 'up') => (bound: string) => (
78+
(...args) => css`
79+
${mediaTemplate(mediaRules(breakpoints, key, rule, bound))}{
80+
${css(...args)}
81+
}
82+
`
83+
);
84+
85+
export const getMediaShorthands = (breakpoints, rule, method: boolean = false) => (
86+
Object.keys(breakpoints).reduce((acc: Object, key: string) => {
7987
// Create a method that accepts a bound media
80-
const boundMethod = bound => (
81-
(...args) => css`
82-
${mediaTemplate(mediaRules(breakpoints, key, rule, bound))}{
83-
${css(...args)}
84-
}
85-
`
86-
);
88+
const boundMethod = getMixin(breakpoints, key, rule);
8789

8890
return ({
8991
...acc,
@@ -94,13 +96,13 @@ export const getMedias = (breakpoints: Breakpoints, rule: Rule, method: boolean
9496
);
9597

9698
export const getMedia = (breakpoints: Breakpoints) => {
97-
const mediasUp = getMedias(breakpoints, 'up');
99+
const mediasUp = getMediaShorthands(breakpoints, 'up');
98100

99101
return ({
100102
...mediasUp,
101-
up: { ...mediasUp },
102-
down: { ...getMedias(breakpoints, 'down') },
103-
only: { ...getMedias(breakpoints, 'only', true) },
103+
up: (widthKey: string) => getMixin(breakpoints, widthKey, 'up'),
104+
down: (widthKey: string) => getMixin(breakpoints, widthKey, 'down'),
105+
only: (widthKey: string, boundKey: string) => getMixin(breakpoints, widthKey, 'only')(boundKey),
104106
});
105107
};
106108

0 commit comments

Comments
 (0)