diff --git a/.storybook/googleFont.stories.js b/.storybook/googleFont.stories.js new file mode 100644 index 00000000..b5319078 --- /dev/null +++ b/.storybook/googleFont.stories.js @@ -0,0 +1,30 @@ +import {createElement as h} from 'react'; +import {storiesOf} from '@storybook/react'; +const {action} = require('@storybook/addon-actions'); +const {linkTo} = require('@storybook/addon-links'); +const {create} = require('../index'); +const {addon: addonRule} = require('../addon/rule'); +const {addon: addonGoogleFont} = require('../addon/googleFont'); + +const nano = create(); +addonRule(nano); +addonGoogleFont(nano); + +nano.googleFont('Roboto'); +nano.googleFont('Roboto Slab', 700); + +const className1 = nano.rule({ + fontFamily: '"Roboto"' +}, 'Roboto'); + +const className2 = nano.rule({ + fontFamily: '"Roboto Slab"' +}, 'Roboto_Slab'); + +storiesOf('Addons/googleFont', module) + .add('Roboto', () => + h('div', {className: className1}, 'Hello world') + ) + .add('Roboto Slab, bold', () => + h('div', {className: className2}, 'Hello world') + ) diff --git a/.storybook/important.stories.js b/.storybook/important.stories.js index 5a64e2e8..362d9208 100644 --- a/.storybook/important.stories.js +++ b/.storybook/important.stories.js @@ -12,10 +12,10 @@ addonImportant(renderer); const {rule} = renderer; const className1 = rule({ - border: '1px solid red' + border: '1px solid red' }, 'RedBorderImportant'); storiesOf('Addons/!important', module) - .add('Default', () => - h('div', {className: className1}, 'Hello world') - ) + .add('Default', () => + h('div', {className: className1}, 'Hello world') + ) diff --git a/README.md b/README.md index 212cb789..9499ee24 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ __Tiny [5th generation](https://github.com/streamich/freestyler/blob/ - [`animate/*`](./docs/animations.md) - [`reset/*`](./docs/resets.md) - [`reset-font`](./docs/reset-font.md) + - [`googleFont()`](./docs/googleFont.md) - [Server-side rendering](./docs/SSR.md) diff --git a/addon/googleFont.js b/addon/googleFont.js new file mode 100644 index 00000000..d2c4e82d --- /dev/null +++ b/addon/googleFont.js @@ -0,0 +1,43 @@ +'use strict'; + +function createUrl (font, weights, subsets) { + var params = '?family=' + encodeURIComponent(font); + + if (weights) { + if (!(weights instanceof Array)) + weights = [weights]; + + params += ':' + weights.join(','); + } + + if (subsets) { + if (!(subsets instanceof Array)) + subsets = [subsets]; + + params += '&subset=' + subsets.join(','); + } + + return 'https://fonts.googleapis.com/css' + params; +} + +exports.addon = function (renderer) { + if (process.env.NODE_ENV !== 'production') { + require('./__dev__/warnOnMissingDependencies')('hydrate', renderer, ['put']); + } + + if (renderer.client) { + renderer.googleFont = function (font, weights, subsets) { + var el = document.createElement('link'); + + el.href = createUrl(font, weights, subsets); + el.rel = 'stylesheet'; + el.type = 'text/css'; + + document.head.appendChild(el); + }; + } else { + renderer.googleFont = function (font, weights, subsets) { + renderer.raw = "@import url('" + createUrl(font, weights, subsets) + "');" + renderer.raw; + }; + } +}; diff --git a/addon/hydrate.js b/addon/hydrate.js index 7093cc74..caed9616 100644 --- a/addon/hydrate.js +++ b/addon/hydrate.js @@ -1,19 +1,17 @@ 'use strict'; -exports.addon = function (renderer, id) { - id = id || 'nano-css'; - +exports.addon = function (renderer) { if (process.env.NODE_ENV !== 'production') { require('./__dev__/warnOnMissingDependencies')('hydrate', renderer, ['put']); } if (renderer.client) { var hydrated = {}; - var stylesheet = document.getElementById(id); + var stylesheet = renderer.sh; if (!stylesheet) { if (process.env.NODE_ENV !== 'production') { - console.error('Hydration stylesheet with id "' + id + '" was not found.'); + console.error('Hydration style sheet was not found.'); } return; diff --git a/addon/keyframes.js b/addon/keyframes.js index 3a410c01..69bda8bd 100644 --- a/addon/keyframes.js +++ b/addon/keyframes.js @@ -10,9 +10,9 @@ exports.addon = function (renderer) { document.head.appendChild(renderer.ksh = document.createElement('style')) } - var putAtrule = renderer.putAtrule; + var putAt = renderer.putAt; - renderer.putAtrule = function (__, keyframes, prelude) { + renderer.putAt = function (__, keyframes, prelude) { // @keyframes if (prelude[1] === 'k') { var str = ''; @@ -38,14 +38,14 @@ exports.addon = function (renderer) { return; } - putAtrule(__, keyframes, prelude); + putAt(__, keyframes, prelude); }; renderer.keyframes = function (keyframes, block) { if (!block) block = renderer.hash(keyframes); block = renderer.pfx + block; - renderer.putAtrule('', keyframes, '@keyframes ' + block); + renderer.putAt('', keyframes, '@keyframes ' + block); return block; }; diff --git a/docs/Addons.md b/docs/Addons.md index ee5dff39..df6ceca3 100644 --- a/docs/Addons.md +++ b/docs/Addons.md @@ -28,7 +28,8 @@ plenty more to chose from. Below is a list of addons shipped with `nano-css`. - [`:global`](./global.md) — allows emitting global styles - [`animate/*`](./animations.md) — collection of animation styles - [`reset/*`](./resets.md) — collection of CSS resets -- [`reset-font`](./docs/reset-font.md) — global styles for better font +- [`reset-font`](./reset-font.md) — global styles for better font +- [`googleFont()`](./googleFont.md) — loads custom fonts from *Google Fonts* ## Addon Installation diff --git a/docs/SSR.md b/docs/SSR.md index 7ea979a2..4e223b05 100644 --- a/docs/SSR.md +++ b/docs/SSR.md @@ -12,8 +12,12 @@ html += ``; ## Re-hydrating `nano-css` can re-hydrate server-side generated CSS. To do that, you need to install [`hydrate` addon](hydrate.md); -and set `nano-css` id on your ``; ``` diff --git a/docs/googleFont.md b/docs/googleFont.md new file mode 100644 index 00000000..78c25197 --- /dev/null +++ b/docs/googleFont.md @@ -0,0 +1,21 @@ +# `googleFont()` Addon + +Creates `googleFont()` method that loads fonts from *Google Fonts*. Signature: + +```ts +googleFont(name: string, widths?: number | number[], subsets?: string | string[]) +``` + + +## Example + +Below example loads `Roboto Slab` font at `400` and `700` widths, including `cyrillic` characters. + +```js +nano.googleFont('Roboto Slab', [400, 700], 'cyrillic'); +``` + + +## Installation + +Simply install `googleFont` addon. Read more about the [Addon Installation](./Addons.md#addon-installation). diff --git a/docs/hydrate.md b/docs/hydrate.md index 17b79ace..b8851869 100644 --- a/docs/hydrate.md +++ b/docs/hydrate.md @@ -6,20 +6,16 @@ Re-hydrates CSS styles generated on the server. On the server add `nano-css` id html += ``; ``` -That's it! `hydrate` addon will find this stylesheet in the browser and will not emit CSS -rules that were already generated by the server. - - -## Configuration - -You can set a custom id for you style sheet. +And when creating `nano-css` instance provide that style sheet in configuration. ```js -import {addon as addonHydrate} from 'nano-css/addon/hydrate'; - -addonHydrate(nano, 'custom-id'); +const nano = create({ + sh: typeof document === 'object' ? document.getElementById('nano-css') : null +}); ``` +That's it! + ## Installation diff --git a/docs/rule.md b/docs/rule.md index 6e146612..7dfb6569 100644 --- a/docs/rule.md +++ b/docs/rule.md @@ -12,6 +12,8 @@ const css = { }, }; const className = nano.rule(css); + +
Hello world!
``` --- diff --git a/index.js b/index.js index 6d04baa5..ff815b0d 100644 --- a/index.js +++ b/index.js @@ -36,13 +36,11 @@ exports.create = function (config) { putRaw: function (rawCssRule) { renderer.raw += rawCssRule; }, - putAtrule: function (selector, decls, prelude) { - renderer.put(selector, decls, prelude); - } }, config); if (renderer.client) { - document.head.appendChild(renderer.sh = document.createElement('style')); + if (!renderer.sh) + document.head.appendChild(renderer.sh = document.createElement('style')); renderer.putRaw = function (rawCssRule) { if (process.env.NODE_ENV === 'production') { @@ -70,7 +68,7 @@ exports.create = function (config) { if ((value instanceof Object) && !(value instanceof Array)) { if (prop[0] === '@') { - renderer.putAtrule(selector, value, prop); + renderer.putAt(selector, value, prop); } else { renderer.put(renderer.selector(selector, prop), value, atrule); } @@ -85,5 +83,7 @@ exports.create = function (config) { } }; + renderer.putAt = renderer.put; + return renderer; };