├── .gitignore
├── demo
└── src
│ ├── index.js
│ ├── App.less
│ ├── index.html
│ ├── reset.less
│ └── App.js
├── .editorconfig
├── .babelrc
├── server.js
├── LICENSE
├── webpack.dev.config.js
├── .eslintrc
├── src
└── Baseline.js
├── README.md
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | demo/dist
4 | npm-debug.log
5 |
--------------------------------------------------------------------------------
/demo/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from 'react-dom';
3 | import App from 'App';
4 |
5 | render(
6 | ,
7 | document.getElementById('demo')
8 | );
9 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
--------------------------------------------------------------------------------
/demo/src/App.less:
--------------------------------------------------------------------------------
1 | @import "./reset.less";
2 |
3 | html {
4 | font-family: Helvetica, Arial, sans-serif;
5 | }
6 |
7 | body {
8 | margin: 0;
9 | }
10 |
11 | .root {
12 | margin: 50px auto;
13 | width: 320px;
14 | }
15 |
16 | .controls {
17 | margin-top: 27px;
18 | }
19 |
--------------------------------------------------------------------------------
/demo/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | React Baseline
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "stage-0", "react"],
3 | "env": {
4 | "development": {
5 | "plugins": [
6 | [
7 | "react-transform",
8 | {
9 | "transforms": [
10 | {
11 | "transform": "react-transform-hmr",
12 | "imports": ["react"],
13 | "locals": ["module"]
14 | },
15 | {
16 | "transform": "react-transform-catch-errors",
17 | "imports": ["react", "redbox-react"]
18 | }
19 | ]
20 | }
21 | ]
22 | ]
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var express = require('express');
3 | var webpack = require('webpack');
4 | var config = require('./webpack.dev.config');
5 | var opn = require('opn');
6 | var app = express();
7 | var compiler = webpack(config);
8 | var port = 1704;
9 |
10 | app.use(require('webpack-dev-middleware')(compiler, {
11 | noInfo: true,
12 | publicPath: config.output.publicPath
13 | }));
14 |
15 | app.use(require('webpack-hot-middleware')(compiler));
16 |
17 | app.use(express.static(path.join(__dirname, 'demo/dist')));
18 | app.get('/', function(req, res) {
19 | res.sendFile(path.join(__dirname, 'demo/dist/index.html'));
20 | });
21 |
22 | app.listen(port, 'localhost', function(err) {
23 | if (err) {
24 | console.log(err); // eslint-disable-line no-console
25 | } else {
26 | opn('http://localhost:' + port);
27 | }
28 | });
29 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright © 2016 Misha Moroshko
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the “Software”), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 | of the Software, and to permit persons to whom the Software is furnished to do
10 | 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 |
--------------------------------------------------------------------------------
/webpack.dev.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var webpack = require('webpack');
3 | var autoprefixer = require('autoprefixer');
4 |
5 | module.exports = {
6 | entry: [
7 | 'webpack-hot-middleware/client',
8 | './demo/src/index'
9 | ],
10 |
11 | output: {
12 | path: path.resolve(__dirname, 'dist'), // Must be an absolute path
13 | filename: 'index.js',
14 | publicPath: '/'
15 | },
16 |
17 | module: {
18 | loaders: [
19 | {
20 | test: /\.js$/,
21 | loaders: ['babel'],
22 | include: [
23 | path.resolve(__dirname, 'src'), // Must be an absolute path
24 | path.resolve(__dirname, 'demo', 'src') // Must be an absolute path
25 | ]
26 | },
27 | {
28 | test: /\.less$/,
29 | loader: 'style!css?modules&localIdentName=[name]__[local]___[hash:base64:5]!postcss!less',
30 | exclude: /node_modules/
31 | }
32 | ]
33 | },
34 |
35 | postcss: function() {
36 | return [autoprefixer];
37 | },
38 |
39 | resolve: {
40 | modulesDirectories: ['node_modules', 'src']
41 | },
42 |
43 | plugins: [
44 | new webpack.HotModuleReplacementPlugin()
45 | ]
46 | };
47 |
--------------------------------------------------------------------------------
/demo/src/reset.less:
--------------------------------------------------------------------------------
1 | /* http://meyerweb.com/eric/tools/css/reset/
2 | v2.0 | 20110126
3 | License: none (public domain)
4 | */
5 |
6 | html, body, div, span, applet, object, iframe,
7 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
8 | a, abbr, acronym, address, big, cite, code,
9 | del, dfn, em, img, ins, kbd, q, s, samp,
10 | small, strike, strong, sub, sup, tt, var,
11 | b, u, i, center,
12 | dl, dt, dd, ol, ul, li,
13 | fieldset, form, label, legend,
14 | table, caption, tbody, tfoot, thead, tr, th, td,
15 | article, aside, canvas, details, embed,
16 | figure, figcaption, footer, header, hgroup,
17 | menu, nav, output, ruby, section, summary,
18 | time, mark, audio, video {
19 | margin: 0;
20 | padding: 0;
21 | border: 0;
22 | font-size: 100%;
23 | font: inherit;
24 | vertical-align: baseline;
25 | }
26 | /* HTML5 display-role reset for older browsers */
27 | article, aside, details, figcaption, figure,
28 | footer, header, hgroup, menu, nav, section {
29 | display: block;
30 | }
31 | body {
32 | line-height: 1;
33 | }
34 | ol, ul {
35 | list-style: none;
36 | }
37 | blockquote, q {
38 | quotes: none;
39 | }
40 | blockquote:before, blockquote:after,
41 | q:before, q:after {
42 | content: '';
43 | content: none;
44 | }
45 | table {
46 | border-collapse: collapse;
47 | border-spacing: 0;
48 | }
49 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "es6": true,
4 | "node": true,
5 | "browser": true
6 | },
7 | "parser": "babel-eslint",
8 | "plugins": [
9 | "react"
10 | ],
11 | "extends": "plugin:react/recommended",
12 | "rules": {
13 | "array-callback-return": 2,
14 | "brace-style": [2, "1tbs"],
15 | "camelcase": [2, { "properties": "always" }],
16 | "comma-dangle": [2, "never"],
17 | "comma-style": [2, "last"],
18 | "eol-last": 2,
19 | "indent": [2, 2, { "SwitchCase": 1 }],
20 | "jsx-quotes": [2, "prefer-double"],
21 | "key-spacing": [2, { "beforeColon": false, "afterColon": true }],
22 | "keyword-spacing": 2,
23 | "linebreak-style": [2, "unix"],
24 | "no-cond-assign": [2, "always"],
25 | "no-console": 2,
26 | "no-multiple-empty-lines": [2, { "max": 1 }],
27 | "no-spaced-func": 2,
28 | "no-trailing-spaces": 2,
29 | "no-unused-vars": [2, {"vars": "all", "args": "after-used"}],
30 | "no-whitespace-before-property": 2,
31 | "newline-after-var": [2, "always"],
32 | "object-curly-spacing": [2, "always"],
33 | "prefer-rest-params": 2,
34 | "quote-props": [2, "as-needed"],
35 | "quotes": [2, "single"],
36 | "semi": [2, "always"],
37 | "space-before-blocks": [2, "always"],
38 | "space-before-function-paren": [2, "never"],
39 | "space-in-parens": [2, "never"],
40 | "template-curly-spacing": [2, "never"],
41 |
42 | "react/jsx-boolean-value": [2, "always"],
43 | "react/jsx-space-before-closing": [2, "always"]
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/Baseline.js:
--------------------------------------------------------------------------------
1 | import React, { Children, PropTypes } from 'react';
2 |
3 | function calculateBackground(type, lineHeight, color) {
4 | if (type === 'line') {
5 | const percentage = (lineHeight - 1) / lineHeight * 100;
6 |
7 | return {
8 | backgroundSize: `100% ${lineHeight}px`,
9 | backgroundImage: `linear-gradient(to bottom, transparent 0%, transparent ${percentage}%, ${color} ${percentage}%, ${color} 100%)`
10 | };
11 | }
12 |
13 | return {
14 | backgroundSize: `100% ${lineHeight * 2}px`,
15 | backgroundImage: `linear-gradient(to bottom, ${color} 50%, transparent 50%, transparent 100%)`
16 | };
17 | }
18 |
19 | function Baseline(props) {
20 | const { isVisible, type, lineHeight, color, children, style, ...restProps } = props;
21 | const baselineStyle = {
22 | position: 'absolute',
23 | top: 0,
24 | left: 0,
25 | bottom: 0,
26 | right: 0,
27 | pointerEvents: 'none',
28 | ...calculateBackground(type, lineHeight, color)
29 | };
30 | const rootProps = {
31 | ...restProps,
32 | style: { ...style, position: 'relative' }
33 | };
34 |
35 | return (
36 |
37 | { isVisible &&
}
38 | {Children.only(children)}
39 |
40 | );
41 | }
42 |
43 | Baseline.propTypes = {
44 | isVisible: PropTypes.bool,
45 | type: PropTypes.string,
46 | lineHeight: PropTypes.number,
47 | color: PropTypes.string,
48 | children: PropTypes.node.isRequired,
49 | style: PropTypes.object
50 | };
51 |
52 | Baseline.defaultProps = {
53 | isVisible: true,
54 | type: 'line',
55 | lineHeight: 9,
56 | color: 'rgba(0, 0, 0, 0.15)',
57 | style: {}
58 | };
59 |
60 | export default Baseline;
61 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
8 |
9 |
10 | # React Baseline
11 |
12 | This project provides a `` component that allows you to easily render a baseline overlay. To actually place the text on the baseline, check out basekick.
13 |
14 | ## Installation
15 |
16 | ```shell
17 | npm install react-baseline
18 | ```
19 |
20 | ## Basic Usage
21 |
22 | ```js
23 | import Baseline from 'react-baseline';
24 |
25 | // Then, just wrap some element with
26 | render() {
27 | return (
28 |
29 |
30 | Some element
31 |
32 |
33 | );
34 | }
35 | ```
36 |
37 | ## Props
38 |
39 | * [`isVisible`](#isVisibleProp)
40 | * [`type`](#typeProp)
41 | * [`lineHeight`](#lineHeightProp)
42 | * [`color`](#colorProp)
43 | * You can also pass any other props like `className`, `style`, etc.
44 |
45 |
46 | #### isVisible (optional)
47 |
48 | Controls whether the baseline overlay will be rendered or not. Default: `true`
49 |
50 |
51 | #### type (optional)
52 |
53 | Baseline overlay comes with two types: `'line'` and `'bar'`
54 |
55 | Default: `'line'`
56 |
57 |
58 | #### lineHeight (optional)
59 |
60 | The distance in `px` between two consecutive baselines.
61 |
62 | Default: `9`
63 |
64 |
65 | #### color (optional)
66 |
67 | The color of the baseline overlay.
68 |
69 | All the usual CSS color formats are suppoted: `'#123456'`, `'#555'`, `'blue'`, `'rgb(100, 200, 300)'`
70 |
71 | Default: `'rgba(0, 0, 0, 0.15)'`
72 |
73 | ## Development
74 |
75 | ```shell
76 | $ npm install
77 | $ npm start
78 | ```
79 |
80 | ## License
81 |
82 | MIT
83 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-baseline",
3 | "version": "1.0.1",
4 | "description": "Add baseline overlay to your React components",
5 | "main": "dist/Baseline.js",
6 | "repository": {
7 | "type": "git",
8 | "url": "https://github.com/moroshko/react-baseline.git"
9 | },
10 | "author": "Misha Moroshko ",
11 | "scripts": {
12 | "start": "rm -rf demo/dist && mkdir demo/dist && npm run copy-static-files && node server",
13 | "lint": "eslint demo/src src server.js webpack.dev.config.js",
14 | "copy-static-files": "cp demo/src/index.html demo/dist/",
15 | "dist": "rm -rf dist && mkdir dist && babel src/Baseline.js --out-file dist/Baseline.js",
16 | "build": "npm run lint",
17 | "preversion": "npm run build",
18 | "postversion": "git push && git push --tags",
19 | "prepublish": "npm run dist"
20 | },
21 | "peerDependencies": {
22 | "react": "^15.0.1"
23 | },
24 | "devDependencies": {
25 | "autoprefixer": "^6.3.6",
26 | "babel-cli": "^6.7.7",
27 | "babel-core": "^6.7.7",
28 | "babel-eslint": "^6.0.4",
29 | "babel-loader": "^6.2.4",
30 | "babel-plugin-react-transform": "^2.0.2",
31 | "babel-preset-es2015": "^6.6.0",
32 | "babel-preset-react": "^6.5.0",
33 | "babel-preset-stage-0": "^6.5.0",
34 | "basekick": "^2.0.0",
35 | "css-loader": "^0.23.1",
36 | "eslint": "^2.8.0",
37 | "eslint-plugin-react": "^5.0.1",
38 | "express": "^4.13.4",
39 | "less": "^2.6.1",
40 | "less-loader": "^2.2.3",
41 | "opn": "^4.0.1",
42 | "postcss-loader": "^0.8.2",
43 | "react": "^15.0.1",
44 | "react-dom": "^15.0.1",
45 | "react-transform-catch-errors": "^1.0.2",
46 | "react-transform-hmr": "^1.0.4",
47 | "redbox-react": "^1.2.3",
48 | "style-loader": "^0.13.1",
49 | "webpack": "^1.13.0",
50 | "webpack-dev-middleware": "^1.6.1",
51 | "webpack-hot-middleware": "^2.10.0"
52 | },
53 | "files": [
54 | "dist"
55 | ],
56 | "keywords": [
57 | "baseline",
58 | "vertical rhythm",
59 | "vertical-rhythm",
60 | "typography",
61 | "grid",
62 | "react baseline",
63 | "react vertical rhythm",
64 | "react vertical-rhythm",
65 | "react typography",
66 | "react grid",
67 | "react-component"
68 | ],
69 | "license": "MIT"
70 | }
71 |
--------------------------------------------------------------------------------
/demo/src/App.js:
--------------------------------------------------------------------------------
1 | import styles from './App.less';
2 |
3 | import React, { Component } from 'react';
4 | import basekick from 'basekick';
5 | import Baseline from 'Baseline';
6 |
7 | export default class App extends Component {
8 | constructor() {
9 | super();
10 |
11 | this.state = {
12 | isVisible: true,
13 | type: 'line',
14 | lineHeight: 12
15 | };
16 |
17 | this.toggleIsVisible = this.toggleIsVisible.bind(this);
18 | this.updateType = this.updateType.bind(this);
19 | this.updateLineHeight = this.updateLineHeight.bind(this);
20 | }
21 |
22 | toggleIsVisible() {
23 | const { isVisible } = this.state;
24 |
25 | this.setState({
26 | isVisible: !isVisible
27 | });
28 | }
29 |
30 | updateType(event) {
31 | this.setState({
32 | type: event.target.value
33 | });
34 | }
35 |
36 | updateLineHeight(event) {
37 | this.setState({
38 | lineHeight: parseInt(event.target.value, 10)
39 | });
40 | }
41 |
42 | render() {
43 | const { isVisible, type, lineHeight } = this.state;
44 |
45 | const headingStyle = {
46 | ...basekick({
47 | baseFontSize: 10,
48 | descenderHeightScale: 0.12,
49 | gridRowHeight: lineHeight,
50 | typeSizeModifier: 2.1,
51 | typeRowSpan: 3
52 | }),
53 | fontWeight: 600
54 | };
55 |
56 | const textStyle = basekick({
57 | baseFontSize: 10,
58 | descenderHeightScale: 0.12,
59 | gridRowHeight: lineHeight,
60 | typeSizeModifier: 1.6,
61 | typeRowSpan: 2
62 | });
63 |
64 | return (
65 |
66 |
70 |
71 |
72 | React Baseline
73 |
74 |
75 | Lorem ipsum dolor sit amet, ex duo ponderum mandamus scriptorem.
76 | Sed nonumy principes iracundia et.
77 |
78 |
79 |
80 |
81 |
84 | {
85 | isVisible &&
86 |
115 | }
116 |
117 |
118 | );
119 | }
120 | }
121 |
--------------------------------------------------------------------------------