├── .npmignore ├── CNAME ├── .prettierignore ├── emotion.js ├── .eslintignore ├── styleguide ├── Image.tsx ├── Para.tsx ├── Box.tsx ├── Heading.tsx ├── Button.tsx ├── Intro.md └── styleguide.tsx ├── .eslintrc.json ├── webpack.config.js ├── .travis.yml ├── .gitignore ├── .editorconfig ├── .prettierrc ├── tsconfig.json ├── babel.config.js ├── .github └── workflows │ └── dependabot.yml ├── License.md ├── styleguide.config.js ├── Readme.md ├── src ├── __tests__ │ └── Stack.spec.tsx ├── Stack.tsx └── Stack.md └── package.json /.npmignore: -------------------------------------------------------------------------------- 1 | __tests__/ -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | stack-styled.js.org 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | lib/ 2 | styleguide-build/ -------------------------------------------------------------------------------- /emotion.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./emotion'); 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | styleguide/setup.ts 3 | styleguide-build/ 4 | lib/ 5 | esm/ 6 | emotion/ 7 | coverage/* 8 | -------------------------------------------------------------------------------- /styleguide/Image.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | const Image = styled.img` 4 | max-width: 100%; 5 | `; 6 | 7 | export default Image; 8 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tamia/react", 3 | "overrides": [ 4 | { 5 | "files": ["*.tsx"], 6 | "extends": "tamia/typescript-react" 7 | } 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | module: { 3 | rules: [ 4 | { 5 | test: /\.(js|tsx)$/, 6 | loader: 'babel-loader', 7 | exclude: /node_modules/, 8 | }, 9 | ], 10 | }, 11 | }; 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | cache: 3 | directories: 4 | - node_modules 5 | node_js: 6 | - 12 7 | - 10 8 | - 8 9 | after_success: 10 | - npx semantic-release 11 | branches: 12 | except: 13 | - /^v\d+\.\d+\.\d+$/ 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | styleguide-build/ 3 | .DS_Store 4 | Thumbs.db 5 | .idea/ 6 | .vscode/ 7 | *.sublime-project 8 | *.sublime-workspace 9 | *.log 10 | .eslintcache 11 | Changelog.md 12 | lib/ 13 | esm/ 14 | emotion/ 15 | coverage/ 16 | types/ 17 | yarn.lock 18 | -------------------------------------------------------------------------------- /styleguide/Para.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | const Para = styled.p` 4 | margin-top: 0; 5 | margin-bottom: 16px; 6 | line-height: 1.5; 7 | font-size: 1.2rem; 8 | font-family: Georgia, 'Times New Roman', Times, serif; 9 | `; 10 | 11 | export default Para; 12 | -------------------------------------------------------------------------------- /styleguide/Box.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import { width, height, space, color } from 'styled-system'; 3 | 4 | const Box = styled('div')( 5 | { 6 | boxSizing: 'border-box', 7 | }, 8 | width, 9 | height, 10 | space, 11 | color 12 | ); 13 | 14 | export default Box; 15 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = tab 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.{json,yml,md,babelrc,eslintrc,remarkrc}] 12 | indent_style = space 13 | indent_size = 2 14 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "singleQuote": true, 4 | "trailingComma": "es5", 5 | "overrides": [ 6 | { 7 | "files": "*.md", 8 | "options": { 9 | "printWidth": 70, 10 | "useTabs": false, 11 | "trailingComma": "none", 12 | "proseWrap": "never" 13 | } 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /styleguide/Heading.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | const Heading = styled.h1` 4 | margin-top: 16px; 5 | margin-bottom: 32px; 6 | line-height: 1.1; 7 | font-weight: normal; 8 | font-size: 2.7rem; 9 | font-family: Georgia, 'Times New Roman', Times, serif; 10 | `; 11 | 12 | export default Heading; 13 | -------------------------------------------------------------------------------- /styleguide/Button.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | const Button = styled.button` 4 | padding: 8px 16px; 5 | border: 0; 6 | border-radius: 2px; 7 | background: #cd009b; 8 | color: white; 9 | font-size: 1rem; 10 | cursor: pointer; 11 | 12 | &:hover, 13 | &:active, 14 | &:focus { 15 | background: #f249cc; 16 | } 17 | `; 18 | 19 | export default Button; 20 | -------------------------------------------------------------------------------- /styleguide/Intro.md: -------------------------------------------------------------------------------- 1 | # Stack Styled 2 | 3 | React component to make stack layouts easy: adds whitespace horizontal and vertical whitespace between each child element but not around the container. Based on [styled-system](https://styled-system.com/) and CSS Grid. We recommend to use this component with [Rebass Grid](https://rebassjs.org/grid/). 4 | 5 | ## Installation 6 | 7 | ```bash 8 | npm install stack-styled 9 | ``` 10 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "es2015", 5 | "jsx": "react", 6 | "moduleResolution": "node", 7 | "strict": true, 8 | "esModuleInterop": true, 9 | "allowSyntheticDefaultImports": true, 10 | "declaration": true, 11 | "declarationDir": "types", 12 | "types": [ 13 | "node", 14 | "react", 15 | "jest" 16 | ] 17 | }, 18 | "include": [ 19 | "src" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@babel/typescript', 4 | [ 5 | '@babel/env', 6 | { 7 | modules: false, 8 | }, 9 | ], 10 | '@babel/react', 11 | ], 12 | env: { 13 | test: { 14 | presets: ['@babel/typescript', '@babel/env', '@babel/react'], 15 | }, 16 | cjs: { 17 | presets: [ 18 | '@babel/typescript', 19 | [ 20 | '@babel/env', 21 | { 22 | targets: { 23 | node: '8.6', 24 | }, 25 | }, 26 | ], 27 | ], 28 | }, 29 | emotion: { 30 | plugins: [ 31 | [ 32 | 'transform-rename-import', 33 | { 34 | original: '^styled-components$', 35 | replacement: '@emotion/styled', 36 | }, 37 | ], 38 | ], 39 | }, 40 | }, 41 | }; 42 | -------------------------------------------------------------------------------- /.github/workflows/dependabot.yml: -------------------------------------------------------------------------------- 1 | name: Dependabot Automerge 2 | 'on': pull_request 3 | jobs: 4 | worker: 5 | runs-on: ubuntu-latest 6 | if: 'github.actor == "dependabot[bot]"' 7 | steps: 8 | - uses: actions/github-script@v3 9 | with: 10 | script: |- 11 | github.pulls.createReview({ 12 | owner: context.payload.repository.owner.login, 13 | repo: context.payload.repository.name, 14 | pull_number: context.payload.pull_request.number, 15 | event: 'APPROVE' 16 | }) 17 | github.pulls.merge({ 18 | owner: context.payload.repository.owner.login, 19 | repo: context.payload.repository.name, 20 | pull_number: context.payload.pull_request.number, 21 | merge_method: 'squash' 22 | }) 23 | -------------------------------------------------------------------------------- /License.md: -------------------------------------------------------------------------------- 1 | # The MIT License 2 | 3 | Copyright 2018 Artem Sapegin, contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /styleguide.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const docgenTypeScript = require('react-docgen-typescript'); 3 | 4 | module.exports = { 5 | title: 'Stack Styled: stacking layouts for React', 6 | sections: [ 7 | { 8 | content: path.join(__dirname, 'styleguide/Intro.md'), 9 | }, 10 | { 11 | components: 'src/*.tsx', 12 | }, 13 | ], 14 | require: [path.join(__dirname, 'styleguide/styleguide.tsx')], 15 | getComponentPathLine: () => `import Stack from 'stack-styled'`, 16 | ribbon: { 17 | url: 'https://github.com/sapegin/stack-styled', 18 | }, 19 | showSidebar: false, 20 | styleguideDir: path.join(__dirname, 'styleguide-build'), 21 | propsParser: docgenTypeScript.withCustomConfig( 22 | path.join(__dirname, 'tsconfig.json'), 23 | { 24 | propFilter(prop) { 25 | if (prop.parent) { 26 | return ( 27 | !prop.parent.fileName.includes('node_modules') || 28 | prop.parent.fileName.includes('@types/styled-system') 29 | ); 30 | } 31 | return true; 32 | }, 33 | componentNameResolver: (exp, source) => 34 | exp.getName() === 'StyledComponentClass' && 35 | docgenTypeScript.getDefaultExportForFile(source), 36 | } 37 | ).parse, 38 | }; 39 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Stack Styled 2 | 3 | [![Build Status](https://travis-ci.org/sapegin/stack-styled.svg)](https://travis-ci.org/sapegin/stack-styled) [![npm](https://img.shields.io/npm/v/stack-styled.svg)](https://www.npmjs.com/package/stack-styled) 4 | 5 | React component to make stack layouts easy: adds whitespace horizontal and vertical whitespace between each child element but not around the container. Based on [styled-system](https://styled-system.com/) and CSS Grid. We recommend to use this component with [Rebass Grid](https://rebassjs.org/grid/). 6 | 7 | [![Washing your code. A book on clean code for frontend developers](https://sapegin.me/images/washing-code-github.jpg)](https://sapegin.me/book/) 8 | 9 | ## Installation 10 | 11 | ```bash 12 | npm install stack-styled 13 | ``` 14 | 15 | ## Documentation & examples 16 | 17 | [See documentation & examples](https://stack-styled.js.org/). 18 | 19 | ## Change log 20 | 21 | The change log can be found on the [Releases page](https://github.com/sapegin/stack-styled/releases). 22 | 23 | ## Contributing 24 | 25 | Everyone is welcome to contribute. Please take a moment to review the [contributing guidelines](Contributing.md). 26 | 27 | ## Sponsoring 28 | 29 | This software has been developed with lots of coffee, buy me one more cup to keep it going. 30 | 31 | Buy Me A Coffee 32 | 33 | ## Authors and license 34 | 35 | [Artem Sapegin](http://sapegin.me) and [contributors](https://github.com/sapegin/stack-styled/graphs/contributors). 36 | 37 | MIT License, see the included [License.md](License.md) file. 38 | -------------------------------------------------------------------------------- /styleguide/styleguide.tsx: -------------------------------------------------------------------------------- 1 | import Box from './Box'; 2 | import Button from './Button'; 3 | import Heading from './Heading'; 4 | import Image from './Image'; 5 | import Para from './Para'; 6 | 7 | // @ts-ignore 8 | global.Box = Box; 9 | // @ts-ignore 10 | global.Button = Button; 11 | // @ts-ignore 12 | global.Heading = Heading; 13 | // @ts-ignore 14 | global.Image = Image; 15 | // @ts-ignore 16 | global.Para = Para; 17 | 18 | // @ts-ignore 19 | global.images = [ 20 | 'https://images.unsplash.com/photo-1481099218264-74ca322f4f67?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=dda119125130d5d5cef73ba28afc40b4&dpr=1&auto=format&fit=crop&w=1000&q=80&cs=tinysrgb', 21 | 'https://images.unsplash.com/photo-1481703443304-97302c668171?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=c772d02c66eb928bb45a618cf7356594&dpr=1&auto=format&fit=crop&w=1000&q=80&cs=tinysrgb', 22 | 'https://images.unsplash.com/photo-1515333308017-2c8be90ed62f?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=f70d56fe1c529833dfeddbaa3726c2bc&dpr=1&auto=format&fit=crop&w=1000&q=80&cs=tinysrgb', 23 | 'https://images.unsplash.com/photo-1490682143684-14369e18dce8?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=492b91a4a59d07bcdf43764fbb4542d6&dpr=1&auto=format&fit=crop&w=1000&q=80&cs=tinysrgb', 24 | 'https://images.unsplash.com/photo-1512300336117-ff710065ae51?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=7221b692334739eefe176fe423189320&dpr=1&auto=format&fit=crop&w=1000&q=80&cs=tinysrgb', 25 | 'https://images.unsplash.com/photo-1475737154378-501d2de7fd94?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=3dd373b55748b832e8a0decaffe280cb&dpr=1&auto=format&fit=crop&w=1000&q=80&cs=tinysrgb', 26 | 'https://images.unsplash.com/photo-1478513684736-6c48ee67c717?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=c1ceaff2610916f92c506433285d459f&dpr=1&auto=format&fit=crop&w=1000&q=80&cs=tinysrgb', 27 | 'https://images.unsplash.com/photo-1475219373687-7edb962ca1aa?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=6cf42580697fa65e4326302a80edc650&dpr=1&auto=format&fit=crop&w=1000&q=80&cs=tinysrgb', 28 | ]; 29 | -------------------------------------------------------------------------------- /src/__tests__/Stack.spec.tsx: -------------------------------------------------------------------------------- 1 | import 'jest-styled-components'; 2 | import React from 'react'; 3 | import { render } from '@testing-library/react'; 4 | import Stack from '../Stack'; 5 | 6 | test('render a div by default', () => { 7 | const { getByTestId } = render(hello); 8 | expect(getByTestId('container')).toHaveProperty('tagName', 'DIV'); 9 | }); 10 | 11 | test('render a custom tag', () => { 12 | const { getByTestId } = render( 13 | 14 | hello 15 | 16 | ); 17 | expect(getByTestId('container')).toHaveProperty('tagName', 'HEADER'); 18 | }); 19 | 20 | test('custom gap', () => { 21 | const { 22 | container: { firstChild }, 23 | } = render(hello); 24 | expect(firstChild).toHaveStyleRule('grid-gap', '32px'); 25 | }); 26 | 27 | test('custom min column width', () => { 28 | const { 29 | container: { firstChild }, 30 | } = render(hello); 31 | expect(firstChild).toHaveStyleRule( 32 | 'grid-template-columns', 33 | 'repeat(auto-fit,minmax(100px,1fr))' 34 | ); 35 | }); 36 | 37 | test('custom number of columns', () => { 38 | const { 39 | container: { firstChild }, 40 | } = render(hello); 41 | expect(firstChild).toHaveStyleRule('grid-template-columns', 'repeat(3,1fr)'); 42 | }); 43 | 44 | test('spacing props', () => { 45 | const { 46 | container: { firstChild }, 47 | } = render( 48 | 49 | hello 50 | 51 | ); 52 | expect(firstChild).toHaveStyleRule('margin-top', '32px'); 53 | expect(firstChild).toHaveStyleRule('padding-bottom', '64px'); 54 | }); 55 | 56 | test('CSS grip props', () => { 57 | const { 58 | container: { firstChild }, 59 | } = render( 60 | 61 | hello 62 | 63 | ); 64 | expect(firstChild).toHaveStyleRule('grid-template-columns', '1fr 2fr 1fr'); 65 | expect(firstChild).toHaveStyleRule('align-items', 'center'); 66 | }); 67 | 68 | test('doesn’t leak props to DOM', () => { 69 | const { container } = render( 70 | 71 | ); 72 | expect(container.innerHTML).toMatchInlineSnapshot( 73 | `"
"` 74 | ); 75 | }); 76 | -------------------------------------------------------------------------------- /src/Stack.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import { 3 | space, 4 | layout, 5 | flexbox, 6 | grid, 7 | color, 8 | border, 9 | shadow, 10 | position, 11 | system, 12 | SpaceProps, 13 | LayoutProps, 14 | FlexboxProps, 15 | GridProps, 16 | ColorProps, 17 | BorderProps, 18 | ShadowProps, 19 | PositionProps, 20 | ResponsiveValue, 21 | TLengthStyledSystem, 22 | } from 'styled-system'; 23 | // @ts-ignore 24 | import propTypes, { propType } from '@styled-system/prop-types'; 25 | 26 | type Props = SpaceProps & 27 | LayoutProps & 28 | FlexboxProps & 29 | GridProps & 30 | ColorProps & 31 | BorderProps & 32 | ShadowProps & 33 | PositionProps & { 34 | /** Minimum width of a child, will create responsive CSS Grid layout like 35 | * `grid-template-columns: repeat(auto-fit, minmax($minColumnWidth$)}, 1fr))`. 36 | * (You can use either this prop or `numColumns` but not both.) 37 | */ 38 | minColumnWidth?: ResponsiveValue; 39 | /** Number of columns, will create a responsive CSS Grid layout like 40 | * `grid-template-columns: repeat($numColumns$, 1fr))`. 41 | * (You can use either this prop or `minColumnWidth` but not both.) 42 | */ 43 | numColumns?: ResponsiveValue; 44 | }; 45 | 46 | const px = (value: TLengthStyledSystem): string => 47 | typeof value === 'number' ? `${value}px` : value; 48 | 49 | const getMinMaxValue = ( 50 | value: TLengthStyledSystem, 51 | scale: TLengthStyledSystem[] = [] 52 | ) => px(scale[value as number] || value); 53 | 54 | export const Stack = styled('div')( 55 | { 56 | boxSizing: 'border-box', 57 | display: 'grid', 58 | }, 59 | space, 60 | layout, 61 | flexbox, 62 | grid, 63 | color, 64 | border, 65 | shadow, 66 | position, 67 | system({ 68 | minColumnWidth: { 69 | property: 'gridTemplateColumns', 70 | scale: 'space', 71 | transform: (value, scale) => 72 | value 73 | ? `repeat(auto-fit, minmax(${getMinMaxValue( 74 | value, 75 | scale as TLengthStyledSystem[] 76 | )}, 1fr))` 77 | : null, 78 | }, 79 | numColumns: { 80 | property: 'gridTemplateColumns', 81 | transform: value => (value ? `repeat(${value}, 1fr)` : null), 82 | }, 83 | }) 84 | ); 85 | 86 | Stack.displayName = 'Stack'; 87 | 88 | Stack.propTypes = { 89 | minColumnWidth: propType, 90 | ...propTypes.space, 91 | ...propTypes.layout, 92 | ...propTypes.flexbox, 93 | ...propTypes.grid, 94 | ...propTypes.color, 95 | ...propTypes.border, 96 | ...propTypes.shadow, 97 | ...propTypes.position, 98 | }; 99 | 100 | export default Stack; 101 | -------------------------------------------------------------------------------- /src/Stack.md: -------------------------------------------------------------------------------- 1 | _All props except `minColumnWidth` and `numColumns` are coming from styled._ 2 | 3 | ### Default scale 4 | 5 | | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 6 | | --- | --- | --- | ---- | ---- | ---- | ----- | ----- | ----- | 7 | | 0px | 4px | 8px | 16px | 32px | 64px | 128px | 256px | 512px | 8 | 9 | ### Examples 10 | 11 | Vertical stack (default) with 8px gap: 12 | 13 | ```jsx 14 | 15 | 16 | 17 | 18 | 19 | ``` 20 | 21 | Multiline stack: 22 | 23 | ```jsx 24 | 25 | {images.map(i => ( 26 | 27 | ))} 28 | 29 | ``` 30 | 31 | Responsive gap (8px, 16px, 32px depending on the viewport width): 32 | 33 | ```jsx 34 | 35 | {images.slice(0, 3).map(i => ( 36 | 37 | ))} 38 | 39 | ``` 40 | 41 | Responsive column layout: 42 | 43 | ```jsx 44 | 45 | {images.map(i => ( 46 | 47 | ))} 48 | 49 | ``` 50 | 51 | _You can also use `gridRowGap` and `gridColumnGap` props._ 52 | 53 | Accepts styled-system [spacing props](https://styled-system.com/table#space), like `mt` or `mb`: 54 | 55 | ```jsx 56 | 57 | {images.slice(0, 3).map(i => ( 58 | 59 | ))} 60 | 61 | ``` 62 | 63 | You can also use it as a generic CSS Grid component: 64 | 65 | ```jsx 66 | 71 | {images.slice(0, 3).map(i => ( 72 | 73 | ))} 74 | 75 | ``` 76 | 77 | \_All styled-system’s [Space](https://styled-system.com/table/#space), [Layout](https://styled-system.com/table/#layout), [Flexbox](https://styled-system.com/table/#flexbox) and [Grid Layout](https://styled-system.com/table/#grid-layout) props are available. 78 | 79 | Responsive buttons (full width on small screens, horizontally stacked on larger screens): 80 | 81 | ```jsx 82 | 87 | 88 | 89 | 90 | 91 | ``` 92 | 93 | More responsive buttons (vertically stacked on small screens, 2×2 grid on larger screens): 94 | 95 | ```jsx 96 | 97 | 98 | 99 | 100 | 101 | 102 | ``` 103 | 104 | Medium-style [article layout](http://gedd.ski/post/article-grid-layout/): 105 | 106 | ```jsx 107 | 111 | 112 | 113 | 114 | 115 | Down the Rabbit Hole 116 | 117 | Alice was beginning to get very tired of sitting by her sister 118 | on the bank, and of having nothing to do: once or twice she had 119 | peeped into the book her sister was reading, but it had no 120 | pictures or conversations in it, “and what is the use of a 121 | book,” thought Alice “without pictures or conversation?” 122 | 123 | 124 | So she was considering in her own mind (as well as she could, 125 | for the hot day made her feel very sleepy and stupid), whether 126 | the pleasure of making a daisy-chain would be worth the trouble 127 | of getting up and picking the daisies, when suddenly a White 128 | Rabbit with pink eyes ran close by her. 129 | 130 | 131 | 132 | ``` 133 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stack-styled", 3 | "version": "0.0.0-development", 4 | "description": "Stacking layouts for React", 5 | "author": { 6 | "name": "Artem Sapegin", 7 | "url": "https://sapegin.me" 8 | }, 9 | "homepage": "https://github.com/sapegin/stack-styled", 10 | "repository": "sapegin/stack-styled", 11 | "license": "MIT", 12 | "engines": { 13 | "node": ">=8.6" 14 | }, 15 | "browserslist": [ 16 | ">1%", 17 | "last 1 version", 18 | "Firefox ESR", 19 | "not dead" 20 | ], 21 | "main": "lib/Stack.js", 22 | "browser": "esm/Stack.js", 23 | "types": "types/Stack.d.ts", 24 | "files": [ 25 | "lib", 26 | "esm", 27 | "emotion", 28 | "types" 29 | ], 30 | "scripts": { 31 | "pretest": "npm run lint && npm run typecheck", 32 | "test": "npm run test:jest", 33 | "posttest": "npm run format", 34 | "typecheck": "tsc --noEmit", 35 | "styleguide": "styleguidist server", 36 | "styleguide:build": "styleguidist build", 37 | "start": "styleguidist server", 38 | "build": "npm run build:esm && npm run build:cjs && npm run build:emotion && npm run build:types", 39 | "build:esm": "babel --delete-dir-on-start --ignore '**/*.spec.js' --extensions '.tsx' -d esm/ src/", 40 | "build:cjs": "babel --delete-dir-on-start --ignore '**/*.spec.js' --extensions '.tsx' --env-name cjs -d lib/ src/", 41 | "build:emotion": "babel --delete-dir-on-start --ignore '**/*.spec.js' --extensions '.tsx' --env-name emotion -d emotion/ src/", 42 | "build:types": "tsc --emitDeclarationOnly", 43 | "prepublishOnly": "npm run build", 44 | "lint": "eslint . --cache --fix --ext .js,.tsx", 45 | "test:jest": "jest", 46 | "test:watch": "jest --watch", 47 | "test:coverage": "jest --coverage", 48 | "format": "prettier --write '**/*.{js,tsx,md}'" 49 | }, 50 | "keywords": [ 51 | "white", 52 | "space", 53 | "whitespace", 54 | "margin", 55 | "padding", 56 | "grid", 57 | "stack", 58 | "layout", 59 | "react", 60 | "component", 61 | "components", 62 | "styled-system", 63 | "styled-components", 64 | "emotion", 65 | "design-system", 66 | "css-in-js" 67 | ], 68 | "dependencies": { 69 | "@styled-system/prop-types": "^5.1.5", 70 | "@types/styled-system": "^5.1.10", 71 | "styled-system": "^5.1.5" 72 | }, 73 | "devDependencies": { 74 | "@babel/cli": "^7.11.6", 75 | "@babel/core": "^7.11.6", 76 | "@babel/preset-env": "^7.11.5", 77 | "@babel/preset-react": "^7.10.4", 78 | "@babel/preset-typescript": "^7.10.4", 79 | "@emotion/core": "^10.0.35", 80 | "@emotion/styled": "^10.0.27", 81 | "@testing-library/react": "^9.5.0", 82 | "@types/jest": "^24.9.1", 83 | "@types/styled-components": "^5.1.3", 84 | "@typescript-eslint/eslint-plugin": "^2.34.0", 85 | "@typescript-eslint/parser": "^2.34.0", 86 | "babel-core": "^7.0.0-bridge.0", 87 | "babel-jest": "^24.9.0", 88 | "babel-loader": "^8.1.0", 89 | "babel-plugin-transform-rename-import": "^2.3.0", 90 | "eslint": "^6.8.0", 91 | "eslint-config-tamia": "^7.2.5", 92 | "eslint-plugin-react": "^7.20.6", 93 | "husky": "^3.1.0", 94 | "jest": "^29.3.1", 95 | "jest-styled-components": "^7.0.3", 96 | "lint-staged": "^9.5.0", 97 | "prettier": "^1.19.1", 98 | "react": "^16.13.1", 99 | "react-docgen-typescript": "^1.20.4", 100 | "react-dom": "^16.13.1", 101 | "react-styleguidist": "^13.0.0", 102 | "styled-components": "^5.2.0", 103 | "typescript": "^3.9.7", 104 | "webpack": "^5.75.0" 105 | }, 106 | "jest": { 107 | "testPathIgnorePatterns": [ 108 | "/node_modules/", 109 | "/types/", 110 | "/lib/", 111 | "/esm/", 112 | "/emotion/" 113 | ] 114 | }, 115 | "lint-staged": { 116 | "*.{js,tsx}": [ 117 | "eslint --fix", 118 | "prettier --write", 119 | "git add" 120 | ], 121 | "*.md": [ 122 | "prettier --write", 123 | "git add" 124 | ] 125 | }, 126 | "husky": { 127 | "hooks": { 128 | "pre-commit": "lint-staged" 129 | } 130 | } 131 | } 132 | --------------------------------------------------------------------------------