diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..b0b9a96 --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "stage": 0 +} diff --git a/.eslintrc b/.eslintrc index 22537cf..0233e9e 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,12 +1,30 @@ --- +# babel support more syntax stuff than eslint for now +parser: babel-eslint + ecmaFeatures: modules: true + jsx: true env: es6: true browser: true node: true +globals: + # for docs + __DEV__: true + __PROD__: true + __SERVER_PROTOCOL__: true + __SERVER_HOSTNAME__: true + __SERVER_PORT__: true + __SERVER_HOST__: true + __SERVER_URL__: true + __LR_SERVER_PORT__: true + +plugins: + - react + # 0: off, 1: warning, 2: error rules: # max 80 chars per line @@ -50,3 +68,16 @@ rules: # enforce comma at eol (never before) comma-style: [2, "last"] + + # see globals + no-underscore-dangle: 0 + + # eslint-plugin-react rules + react/no-multi-comp: 2 + react/prop-types: 2 + react/wrap-multilines: 2 + react/self-closing-comp: 2 + react/no-did-mount-set-state: 2 + react/no-did-update-set-state: 2 + react/jsx-uses-react: 2 + react/jsx-uses-vars: 2 diff --git a/.gitignore b/.gitignore index d2eef5e..4da1288 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ node_modules # standalone build dist +docs/dist # fixtures test/**/*.actual.css diff --git a/.travis.yml b/.travis.yml index ec26778..d712cdd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,3 +14,8 @@ notifications: on_failure: always use_notice: true skip_join: true + +script: + - npm run test + # travis take is weird, disabled for now + #- if [[ $(node --version) != v0.* ]]; then; npm run docs-test; fi diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..9446f6e --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,29 @@ +## Contributing + +_cssnext uses a lot of [postcss](https://github.com/postcss) plugins, +so you might need to take a look at them if you find an issue or want to create +or enhance a feature._ + +Otherwise, fork, work on a branch, install dev-dependencies, +respect coding style & run tests before submitting a bug fix or a feature. + +```console +$ git clone https://github.com/YOU/cssnext.git +$ npm install +$ npm test +$ git checkout -b fix.bug423 +``` + +### Add a feature + +1. Add test files (input + expected output) in [`test/fixtures/features`](test/features) +- If the feature can affect some others, update [`test/fixtures/cases/example.css`](test/cases/example.css) to test integration with other features +- Run test, & check tests are broken (otherwise feature is useless) +- Choose a pretty simple and clear name (that match the specs) +- Add the feature in the [README features list](#features) (title, link to spec, link of the plugin, short desc) +- Add the feature in the [README node.js options list](#features-default-all-features) (camelCaseName) +- Add the dependency in the [`package.json`](package.json) +- Add the feature in the source (in [`index.js`](index.js)), in the appropriate place (order matter) +- Run test and be happy +- Add feature in [the docs](docs/content) +- Add feature on [the playground](https://github.com/cssnext/playground) example diff --git a/README.md b/README.md index 04c86dc..5c1276f 100644 --- a/README.md +++ b/README.md @@ -1,414 +1,33 @@ -# cssnext [![NPM version](http://img.shields.io/npm/v/cssnext.svg?style=flat)](https://www.npmjs.org/package/cssnext) [![Travis Build Status](https://img.shields.io/travis/cssnext/cssnext.svg?label=unix build)](https://travis-ci.org/cssnext/cssnext) [![AppVeyor Build Status](https://img.shields.io/appveyor/ci/MoOx/cssnext.svg?label=windows build)](https://ci.appveyor.com/project/MoOx/cssnext) [![Join the chat at https://gitter.im/cssnext/cssnext](https://img.shields.io/badge/gitter%20-join%20chat%20%E2%9E%9E-1dce73.svg)](https://gitter.im/cssnext/cssnext) +# cssnext +[![NPM version](http://img.shields.io/npm/v/cssnext.svg?style=flat)](https://www.npmjs.org/package/cssnext) +[![Travis Build Status](https://img.shields.io/travis/cssnext/cssnext.svg?label=unix build)](https://travis-ci.org/cssnext/cssnext) +[![AppVeyor Build Status](https://img.shields.io/appveyor/ci/MoOx/cssnext.svg?label=windows build)](https://ci.appveyor.com/project/MoOx/cssnext) +[![Join the chat at https://gitter.im/cssnext/cssnext](https://img.shields.io/badge/gitter%20-join%20chat%20%E2%9E%9E-1dce73.svg)](https://gitter.im/cssnext/cssnext) -> Use tomorrow's CSS syntax, today. +> Use tomorrow's CSS syntax, today. This is a CSS transpiler (CSS4+ to CSS3) that allows you to use tomorrow's CSS syntax today. It transforms CSS specs that are not already implemented in popular browsers into more compatible CSS. -_This is not a classic CSS preprocessor, but can totally replace one._ - -Check out [the website](https://cssnext.github.io/) or [try cssnext](https://cssnext.github.io/cssnext-playground) in your browser. - -**Is it cssnext or CSSNext or CSSnext?** -The official name is **cssnext**, which should never be capitalized, especially not at the start of a sentence, unless it is being displayed in a location that is customarily all-caps (such as the title of man pages). +## Check out [cssnext website](https://cssnext.io/) ---- +- [Features](https://cssnext.io/features/) +- [Setup](https://cssnext.io/setup/) +- [Usage](https://cssnext.io/usage/) +- [Playground](https://cssnext.io/playground/) -[Why](#why) | [Features](#features) | [Limitations](#limitations) | [Installation](#installation)| [CLI Usage](#cli) | [Node.js API](#nodejs-api) | [Contribute](#contributing) ---- | --- | --- | --- | --- | --- | --- +For questions and support please visit the +[gitter room](https://gitter.im/cssnext/cssnext). --- -## Why - -Prior 2015, CSS was frustrating by not having any specification for features we were looking for. No variables, no math, no color manipulation & no customization. Things are going to change soon since a lot of work has been made by the W3C to write new specs to make our life easier. - -**This project aims to allow you to use future CSS syntax, today.** - -It is similar to [Myth](http://myth.io/) or [SUIT CSS preprocessor](https://github.com/suitcss/preprocessor) but pushes the concept to the next level by supporting more features. It works great with [cssrecipes](https://cssrecipes.github.io/) or [SUIT CSS](https://suitcss.github.io/). - -_It's not planned for now to provide polyfills for future CSS APIs that depend on the client browser._ - -Follow [@cssnext on Twitter](https://twitter.com/cssnext) to get the latest news & join [#cssnext on irc.freenode.net](http://webchat.freenode.net/?channels=cssnext) if you have any questions. - -## Features - -You can safely use the following features: - -* automatic vendor prefixes -(via [autoprefixer](https://github.com/postcss/autoprefixer)), -* [custom properties & `var()`](http://www.w3.org/TR/css-variables/) -limited to `:root` -([⇗](https://github.com/postcss/postcss-custom-properties)), -* [reduced `calc()`](https://github.com/MoOx/reduce-css-calc#readme) -to optimize previously parsed `var()` references -([⇗](https://github.com/postcss/postcss-calc)), -* [custom media queries](http://dev.w3.org/csswg/mediaqueries/#custom-mq) -a nice way to have semantic media queries -([⇗](https://github.com/postcss/postcss-custom-media)), -* [media queries ranges](http://dev.w3.org/csswg/mediaqueries/#mq-ranges) -that allows to replace min-/max- with `<=` & `>=` (syntax easier to read) -([⇗](https://github.com/postcss/postcss-media-minmax)), -* [custom selectors](http://dev.w3.org/csswg/css-extensions/#custom-selectors) -to create your own selectors -([⇗](https://github.com/postcss/postcss-custom-selector)), -* [`color()`](http://dev.w3.org/csswg/css-color/#modifying-colors) -a color function to modify colors -(transpiled to: `rgba()`) -([⇗](https://github.com/postcss/postcss-color-function)), -* [`hwb()`](http://dev.w3.org/csswg/css-color/#the-hwb-notation) -similar to `hsl()` but easier for humans to work with -(transpiled to: `rgba()`) -([⇗](https://github.com/postcss/postcss-color-hwb)) , -* [`gray()`](http://dev.w3.org/csswg/css-color/#grays) -(transpiled to: `rgba()`) -([⇗](https://github.com/postcss/postcss-color-gray)), -* [#rrggbbaa](http://dev.w3.org/csswg/css-color/#hex-notation) -(transpiled to: `rgba()`) -([⇗](https://github.com/postcss/postcss-color-hex-alpha)), -* [`rebeccapurple`](http://dev.w3.org/csswg/css-color/#valdef-color-rebeccapurple) -([⇗](https://github.com/postcss/postcss-color-rebeccapurple)), -* [font-variant](http://dev.w3.org/csswg/css-fonts/#propdef-font-variant) -properties (fallback: `font-feature-settings`) -([⇗](https://github.com/postcss/postcss-font-variant)), -* [filter](http://www.w3.org/TR/filter-effects/) -properties (fallback: inlined `` filter) -([⇗](https://github.com/iamvdo/pleeease-filters)) -* [`rem` units](http://www.w3.org/TR/css3-values/#rem-unit) -(fallback: `px`) -([⇗](https://github.com/robwierzbowski/node-pixrem)) -* [pseudo-elements](http://www.w3.org/TR/css3-selectors/#pseudo-elements) -(adjust `::` to `:`) -([⇗](https://github.com/axa-ch/postcss-pseudoelements)) -* [`:matches` pseudo-class](http://dev.w3.org/csswg/selectors-4/#matches) -([⇗](https://github.com/postcss/postcss-selector-matches)) -* [`:not` pseudo-class](http://dev.w3.org/csswg/selectors-4/#negation) -([⇗](https://github.com/postcss/postcss-selector-NOT)) -* alpha colors for browser that don't understand [css 3 colors](http://www.w3.org/TR/css3-color/) -(fallback: solid hexa colors) -([⇗](https://github.com/postcss/postcss-color-rgba-fallback)) - -_Note that according to your [browser scope](#nodejs-options) some might be not transpiled to avoid extra useless output._ - -### Bonus features - -_The features below are considered as bonus since it's totally not related to CSS specs._ - -* `@import` inline local files and modules - `node_modules` or `web_modules` ([⇗](https://github.com/postcss/postcss-import)) to output a bundled CSS file. `url()` referenced are also rebased. -* minification is available ([⇗](https://github.com/hail2u/node-csswring)) if you want to compress the output for production. - - -### @todo - -Any omissions of the CSS specifications (even in draft) that are subject to be handled by cssnext are not intentional. -You can take a look at the [list of features that are waiting to be implemented](https://github.com/cssnext/cssnext/issues?q=is%3Aopen+is%3Aissue+label%3Afeature+label%3Aready). -Feel free to work on a feature ready to be added, or [open a new issue](https://github.com/cssnext/cssnext/issues/new) if you find something that should be handled. -Keep in mind that, as of right now, this project is intended to support new CSS *syntax* only. - -## Limitations - -### Custom properties - -The current transformation for custom properties just aims to provide a future-proof way of using a **limited subset (to top-level `:root` selector)** of the features provided by native CSS custom properties. -The transformation is not complete and can't be properly. By injecting selectors with new computed rules, we will break original cascade & unexpected results might happen. - -### Font variant - -`font-variant` are transformed to `font-feature-settings`. You might take a look at the support of [font feature settings](http://caniuse.com/#feat=font-feature). - -### Filter - -The W3C filters are only transformed as svg filter using the `url(data:*)` trick for Firefox < 35. +_The [issue tracker](https://github.com/cssnext/cssnext/issues) is exclusively for bug reports and feature requests._ --- -## Installation - -```console -$ npm install cssnext -``` - -You can install it - -- locally (`--save` or `--save-dev`), to use it through [npm scripts](https://www.npmjs.org/doc/misc/npm-scripts.html) (`npm run`) or via `.node_modules/.bin/cssnext` -- globally (`-g`), to use it through the [CLI](cli) (not recommanded) -- by using [other plugins & tools](#usage-with-other-tools) like [gulp-cssnext](https://github.com/cssnext/gulp-cssnext) - -## Usage - -You can use cssnext using [CLI](#cli), -as [a JavaScript library](#nodejs-api), -as a [PostCSS](https://github.com/postcss/postcss) plugin -or through [others tools](#usage-with-other-tools). - -### CLI - -cssnext offers a command-line interface. -Here's how to compile a file and print it to stdout: - -```console -$ cssnext index.css -``` - -To create an output file, you can just add a second argument - -```console -$ cssnext index.css output.css -``` - -Or use CLI std(in|out) redirection(s) - -```console -$ cat input.css | cssnext > output.css -``` - -### CLI options - -If you don't care about a certain feature, such as custom media queries, you can omit support for them like so: - -```console -$ cssnext --no-custom-media index.css -``` - -To enable source maps for these files, add the `--sourcemap` flag. - -**To see all CLI options** - -```console -$ cssnext --help -``` - -### Node.js API - -cssnext can be used with its own API or as a PostCSS plugin. - -#### `var string = cssnext(string, options)` - -cssnext accepts 2 arguments: a css string and an object of options. - -```js -var fs = require("fs") -var cssnext = require("cssnext") - -var input = fs.readFileSync("index.css", "utf8") - -var output = cssnext(input) -fs.writeFileSync("dist/index.css", output) -``` - -**`/!\` Note: if you are using non inlined sourcemaps, cssnext will return an object: `{css: string, map: sourcemap}`** - -See [sourcemap](#sourcemap-default-false) & [map](#map-default-depends-on-sourcemap) options for more informations. - -#### `var postcssPlugin = cssnext(options)` - -cssnext can be used as a postcss plugin: - -```js -var fs = require("fs") -var postcss = require("postcss") -var cssnext = require("cssnext") - -var input = fs.readFileSync("index.css", "utf8") - -var output = postcss() - .use(cssnext()) - .use(/* your other postcss plugin */) - .process(input) -fs.writeFileSync("dist/index.css", output) -``` - -#### Node.js options - -##### `browsers` (default: [browserslist default](https://github.com/ai/browserslist#readme) - `> 1%, last 2 versions, Firefox ESR, Opera 12.1`) - -Allows you to specify your browser scope. -**This option enables or disables `features` according to [caniuse](http://caniuse.com/) database.** -This is the exact same option that you might know from Autoprefixer. -Since cssnext includes Autoprefixer, the option is propagated. - -See [Browserslist](https://github.com/ai/browserslist#queries) queries syntax to adjust this option to your needs. - -_Note: if you don't specify this option, Browserslist will automatically try to find a `browserslist` -config file or use its default value._ - -##### `features` (default: all features) - -**You should probably use `browsers` option instead of this one.** - -Object containing key of features to enable/disable. -_Features are enabled by default: no key means feature is enabled_. - -```js -//eg: disable custom properties support -var output = cssnext(input, { - features: { - customProperties: false - } -}) -``` - -Each feature is based on PostCSS plugins & can get its own options. -To pass options to a feature, you can just pass an object to the feature: - -```js -//eg: preserve custom properties -var output = cssnext(input, { - features: { - customProperties: { - preserve: true - } - } -}) -``` - -To know all available options, please check the [available features](#available) list where you will find references to all the plugins used. - -Here are all the available features: - -- `customProperties` -- `calc` -- `customMedia` -- `mediaQueriesRange` -- `customSelectors` -- `colorFunction` -- `colorHexAlpha` -- `colorHwb` -- `colorRebeccapurple` -- `fontVariant` -- `filter` -- `rem` -- `pseudoElements` -- `pseudoClassMatches` -- `pseudoClassNot` -- `colorRgba` -- `autoprefixer` - -_Note: order is important to get everything working correctly._ - -##### `import` (default: `true`) - -Allows you to inline local `@import` files (thanks to [postcss-import](https://github.com/postcss/postcss-import#readme)): - -* you can refer to `node_modules` and `web_modules` packages -* you can omit .css extension - -_Note: you can pass [postcss-import options](https://github.com/postcss/postcss-import#readme) directly._ - -##### `url` (default: `true`) - -By default, `url()` are rebased according to `from` (and `to`) option(s). This is convenient especially for `@import`ed files. - -_Note: you can pass [postcss-url options](https://github.com/postcss/postcss-url#options) directly in order to inline or have more control over urls._ - -##### `compress` (default: `false`) - -Allows you to compress the output (using [cssnano](https://github.com/ben-eb/cssnano)). -You can enable minification by passing `true` or by providing an object containing [cssnano options](https://github.com/ben-eb/cssnano#options). - -##### `sourcemap` (default: `false`) - -This option is a shortcut to enable inlined sourcemap in the output. -Just pass `true` to get the sourcemap at the end of the output. - -- _If you want an accurate sourcemap, please also use the `from` option._ -- _If you want more control on the sourcemap, please use the `map` option instead._ - -##### `map` (default: _depends on `sourcemap`_) - -_(default: `undefined` if `sourcemap` is `false`, `inline` if `sourcemap` it true)_ - -If you want better control on sourcemap, you are at the right place. -This is the [postcss `map` option](https://github.com/postcss/postcss#source-map-1), so checkout the related documentation directly. - -_If you specify this option, `sourcemap` value will be ignored._ - -**`/!\` Using this option might change the return value of `cssnext()` (`object` instead of css `string` if map is not inlined. The object will be like {css: "{css string}", map: {sourcemap object}})** - -##### `from` (default: `null`) - -Source of the file. Required for accurate sourcemap. - -```js -var cssnext = require("cssnext") -var fs = require("fs") - -var source = "./index.css" -var output = cssnext( - fs.readFileSync(source, "utf8"), - {from: source} -) -fs.writeFileSync("dist/index.css", output) -``` - -### Usage with other tools - -Here are some tools that will help you use cssnext in your current workflow: - -* [gulp-cssnext](https://github.com/cssnext/gulp-cssnext) -* [grunt-cssnext](https://github.com/cssnext/grunt-cssnext) -* [cssnext-loader (webpack)](https://github.com/cssnext/cssnext-loader) -* [duo-cssnext](https://github.com/cssnext/duo-cssnext) -* [cssnext-brunch](https://github.com/cssnext/cssnext-brunch) -* [broccoli-cssnext](https://github.com/cssnext/broccoli-cssnext) -* [Prepros 5](https://prepros.io/) (_More options_ (dropdown) > _Project options_ (item) > _Compilers_ (tab) > _Enable cssnext_ (checkbox at the bottom)) -* @todo component-builder package -* @todo meteor package - -_Note that you can also use cssnext as a PostCSS plugin._ - ---- - -## Contributing - -_cssnext uses a lot of [postcss](https://github.com/postcss) plugins, so you might need to take a look at them if you find an issue or want to create or enhance a feature._ - -Otherwise, work on a branch, install dev-dependencies, respect coding style & run tests before submitting a bug fix or a feature. - -```console -$ git clone https://github.com/cssnext/cssnext.git -$ git checkout -b patch-1 -$ npm install -$ npm test -``` - -### Add a feature - -1. Add test files (input + expected output) in [`test/fixtures/features`](test/features) -- If the feature can affect some others, update [`test/fixtures/cases/example.css`](test/cases/example.css) to test integration with other features -- Run test, & check tests are broken (otherwise feature is useless) -- Choose a pretty simple and clear name (that match the specs) -- Add the feature in the [README features list](#features) (title, link to spec, link of the plugin, short desc) -- Add the feature in the [README node.js options list](#features-default-all-features) (camelCaseName) -- Add the dependency in the [`package.json`](package.json) -- Add the feature in the source (in [`index.js`](index.js)), in the appropriate place (order matter) -- Run test and be happy -- Add feature on [the playground](https://github.com/cssnext/cssnext-playground) example -- Add feature on [the website](https://github.com/cssnext/cssnext.github.io) - ## [Changelog](CHANGELOG.md) ## [License](LICENSE) - ---- - -## People - -The current lead maintainer is [Maxime Thirouin](http://moox.io/). [![MoOx' Gratipay](https://img.shields.io/gratipay/MoOx.svg)](https://gratipay.com/MoOx/) - -See [all contributors](https://github.com/cssnext/cssnext/graphs/contributors). - -## Acknowledgements - -Huge thanks to all the people that where involved in: - -- [rework](https://github.com/reworkcss/rework/graphs/contributors) -- [rework css parser](https://github.com/reworkcss/css/graphs/contributors) -- [myth](https://github.com/segmentio/myth/graphs/contributors) -- [autoprefixer](https://github.com/postcss/autoprefixer/graphs/contributors) -- [postcss](https://github.com/postcss/postcss/graphs/contributors) - -Without all those people, this project would not exist. diff --git a/docs/content/CNAME b/docs/content/CNAME new file mode 100644 index 0000000..3f8074d --- /dev/null +++ b/docs/content/CNAME @@ -0,0 +1 @@ +cssnext.io diff --git a/docs/content/credits.md b/docs/content/credits.md new file mode 100644 index 0000000..1291a2b --- /dev/null +++ b/docs/content/credits.md @@ -0,0 +1,9 @@ +--- +title: Credits +footer: false +--- + +* [delorean back](https://www.flickr.com/photos/jasoncipriani/11866004734) +* [delorean with blue trails](https://www.flickr.com/photos/wizzer/9295055565) +* [bttf legos](https://www.flickr.com/photos/brianneudorff/10047726604) +* [delorean side](https://www.flickr.com/photos/mooshuu/5963681346) diff --git a/docs/content/features.md b/docs/content/features.md new file mode 100644 index 0000000..4fe35bc --- /dev/null +++ b/docs/content/features.md @@ -0,0 +1,126 @@ +--- +title: Discover cssnext features +backgroundModifier: darkRoad +incomplete: true +--- + +## automatic vendor prefixes + +(via [autoprefixer](https://github.com/postcss/autoprefixer)), + + +## [custom properties & `var()`](http://www.w3.org/TR/css-variables/) + +limited to `:root` +([⇗](https://github.com/postcss/postcss-custom-properties)), + +## [reduced `calc()`](https://github.com/MoOx/reduce-css-calc#readme) + +to optimize previously parsed `var()` references +([⇗](https://github.com/postcss/postcss-calc)), + +## [custom media queries](http://dev.w3.org/csswg/mediaqueries/#custom-mq) + +a nice way to have semantic media queries +([⇗](https://github.com/postcss/postcss-custom-media)), + +## [media queries ranges](http://dev.w3.org/csswg/mediaqueries/#mq-ranges) + +that allows to replace min-/max- with `<=` & `>=` (syntax easier to read) +([⇗](https://github.com/postcss/postcss-media-minmax)), + +## [custom selectors](http://dev.w3.org/csswg/css-extensions/#custom-selectors) + +to create your own selectors +([⇗](https://github.com/postcss/postcss-custom-selector)), + +## [`color()`](http://dev.w3.org/csswg/css-color/#modifying-colors) + +a color function to modify colors (transpiled to: `rgba()`) +([⇗](https://github.com/postcss/postcss-color-function)), + +## [`hwb()`](http://dev.w3.org/csswg/css-color/#the-hwb-notation) + +similar to `hsl()` but easier for humans to work with (transpiled to: `rgba()`) +([⇗](https://github.com/postcss/postcss-color-hwb)) , + +## [`gray()`](http://dev.w3.org/csswg/css-color/#grays) + +(transpiled to: `rgba()`) +([⇗](https://github.com/postcss/postcss-color-gray)), + +## [#rrggbbaa](http://dev.w3.org/csswg/css-color/#hex-notation) + +(transpiled to: `rgba()`) +([⇗](https://github.com/postcss/postcss-color-hex-alpha)), + +## [`rebeccapurple`](http://dev.w3.org/csswg/css-color/#valdef-color-rebeccapurple) + +([⇗](https://github.com/postcss/postcss-color-rebeccapurple)), + + +## [font-variant](http://dev.w3.org/csswg/css-fonts/#propdef-font-variant) + +properties (fallback: `font-feature-settings`) +([⇗](https://github.com/postcss/postcss-font-variant)), + +## [filter](http://www.w3.org/TR/filter-effects/) + +properties (fallback: inlined `` filter) +([⇗](https://github.com/iamvdo/pleeease-filters)) + +## [`rem` units](http://www.w3.org/TR/css3-values/#rem-unit) + +(fallback: `px`) +([⇗](https://github.com/robwierzbowski/node-pixrem)) + +## [pseudo-elements](http://www.w3.org/TR/css3-selectors/#pseudo-elements) + +(adjust `::` to `:`) +([⇗](https://github.com/axa-ch/postcss-pseudoelements)) + +## [`:matches` pseudo-class](http://dev.w3.org/csswg/selectors-4/#matches) + +([⇗](https://github.com/postcss/postcss-selector-matches)) + + +## [`:not` pseudo-class](http://dev.w3.org/csswg/selectors-4/#negation) + +([⇗](https://github.com/postcss/postcss-selector-NOT)) + + +## alpha colors for browser that don't understand [css 3 colors](http://www.w3.org/TR/css3-color/) + (fallback: solid hexa colors) +([⇗](https://github.com/postcss/postcss-color-rgba-fallback)) + +_Note that according to your [browser scope](#nodejs-options) some might be not transpiled to avoid extra useless output._ + +## Bonus features + +_The features below are considered as bonus since it's totally not related to CSS specs._ + +* `@import` inline local files and modules - `node_modules` or `web_modules` ([⇗](https://github.com/postcss/postcss-import)) to output a bundled CSS file. `url()` referenced are also rebased. +* minification is available ([⇗](https://github.com/hail2u/node-csswring)) if you want to compress the output for production. + + +## @todo + +Any omissions of the CSS specifications (even in draft) that are subject to be handled by cssnext are not intentional. +You can take a look at the [list of features that are waiting to be implemented](https://github.com/cssnext/cssnext/issues?q=is%3Aopen+is%3Aissue+label%3Afeature+label%3Aready). +Feel free to work on a feature ready to be added, or [open a new issue](https://github.com/cssnext/cssnext/issues/new) if you find something that should be handled. +Keep in mind that, as of right now, this project is intended to support new CSS *syntax* only. + +## Limitations + +### Custom properties + +The current transformation for custom properties just aims to provide a future-proof way of using a **limited subset (to top-level `:root` selector)** of the features provided by native CSS custom properties. +The transformation is not complete and can't be properly. By injecting selectors with new computed rules, we will break original cascade & unexpected results might happen. + +### Font variant + +`font-variant` are transformed to `font-feature-settings`. You might take a look at the support of [font feature settings](http://caniuse.com/#feat=font-feature). + +### Filter + +The W3C filters are only transformed as svg filter using the `url(data:*)` trick for Firefox < 35. diff --git a/docs/content/index.md b/docs/content/index.md new file mode 100644 index 0000000..306f389 --- /dev/null +++ b/docs/content/index.md @@ -0,0 +1,249 @@ +--- +template: Simple +title: cssnext +--- +
+
+
+ Use tomorrow's CSS syntax, today. +

+ + Check out cssnext on GitHub + + or + + try it in your browser + +

+ +
+
+
+ +
+
+

What is cssnext?

+

+ cssnext is a CSS transpiler that allows you to use + the latest CSS syntax today. + It transforms CSS specs into more compatible CSS + so you don't need to wait for browser support. + + + You can literally write future-proof CSS + and forget old preprocessor specific syntax. + +

+
+
+

Features

+ + + + _l.* are level of the specification (when information is relevant)_ + + +
+
+ +
+
+
+

Why cssnext?

+

+ Prior to 2015, CSS was frustrating by not having any specification for features we were looking for. + No variables, no math, no color manipulation & no customization. + Things are going to change soon since a lot of work has been made by the W3C to write new specs to make our life easier. + With cssnext, you can start using some new features today! +

+
+
+
+ +
+
+
+

Future-proof code

+

+ In a near future, browsers will implement new CSS specifications. As time passes, cssnext will remove some transformations that won't be necessary anymore. + And maybe one day, you will be able to completely remove cssnext from your workflow without touching your CSS. +

+
+
+
+ +
+
+
+
+

It's fast. Lightning fast.

+

+ cssnext uses PostCSS + which has + a way faster CSS parser. +
+ It's a good competitor to libsass, a bit faster than LESS and Stylecow, + and way faster than Myth or original Ruby Sass. +

+
+
+
+ +
+
+
+

Active development

+

+ No longer wait for releases. + A fixed bug will be released ASAP. +
+ Minor features will never be idle for long. +
+ See that by yourself on + cssnext + & + PostCSS. + activities graphs. + +
+ cssnext uses lots of PostCSS plugins, + so check them out too. +

+
+
+
+ +
+
+
+
+

Based on NPM ecosystem

+

+ cssnext uses npm packages that should respect semver. +
+ Bugfixes are pushed often. + Minor changes won't break your code. + Major releases are, well, major and are not supposed to happen a lot. +
+ Codebase is exploded into smart and standalone packages so it's easier to work on something or fix a bug. +

+
+
+
+ +
+
+ +
+
+ +
+
+
+ Follow + @cssnext + to get the latest news + or + join the chat on gitter + if you have any questions. +
+
+
+ +
+
+
+ + + You can also check + suitcss + or + basscss + +
+
+
diff --git a/docs/content/it-s-cssnext-not-CSSNext.md b/docs/content/it-s-cssnext-not-CSSNext.md new file mode 100644 index 0000000..5ded767 --- /dev/null +++ b/docs/content/it-s-cssnext-not-CSSNext.md @@ -0,0 +1,28 @@ +--- +title: "It's cssnext, not CSSNext" +footer: false +--- + +## Is it cssnext or CSSNext or CSSnext? + +The official name is **cssnext**, which should never be capitalized, especially not at the start of a sentence, unless it is being displayed in a location that is customarily all-caps (such as the title of man pages). + +### Why ? + +```js +function nameify(string) { + return string + .replace(" ", "") + .toLowerCase() +} + +nameify("CSS Next") +nameify("CSSNext") +nameify("CSSnext") +nameify("CSS next") +nameify("css next") +nameify("cssnext") + +// all the results above are just the same +// -> "cssnext" ! +``` diff --git a/docs/content/playground.html b/docs/content/playground.html new file mode 100644 index 0000000..a647ebc --- /dev/null +++ b/docs/content/playground.html @@ -0,0 +1,70 @@ +--- +template: Simple +title: Playground +className: js-cssnext-Playground cssnext-Playground +footer: false +scripts: + - /playground.js +--- +
+
+ +
+
+ +
diff --git a/docs/content/setup.md b/docs/content/setup.md new file mode 100644 index 0000000..485d76f --- /dev/null +++ b/docs/content/setup.md @@ -0,0 +1,130 @@ +--- +title: Install & setup cssnext +backgroundModifier: darkTeam +incomplete: true +--- + +## Installation + +cssnext is available on +[github](https://github.com/cssnext/cssnext) +and [npm](https://www.npmjs.org/package/cssnext). + +You can install it: + +- locally (`--save` or `--save-dev`), to use it through [npm scripts](https://www.npmjs.org/doc/misc/npm-scripts.html) (`npm run`) or via `.node_modules/.bin/cssnext` +- globally (`-g`), to use it through the [CLI](cli) _(not recommanded)_ +- by using [other plugins & tools](#usage) like [gulp-cssnext](https://github.com/cssnext/gulp-cssnext) + +The main package offers +[a CLI](https://github.com/cssnext/cssnext#cli) and +[a Node.js/io.js API](https://github.com/cssnext/cssnext#nodejs-api"). + +

+``` +$ npm install cssnext +``` +

+ +## Usage + +You can use cssnext using [CLI](#cli), +as [a JavaScript library](#nodejs-api), +as a [PostCSS](https://github.com/postcss/postcss) plugin +or through others tools below: + +

+[webpack](https://github.com/cssnext/cssnext-loader) +, +[gulp](https://github.com/cssnext/gulp-cssnext) +, +[grunt](https://github.com/cssnext/grunt-cssnext) +, +[brunch](https://github.com/cssnext/cssnext-brunch) +, +[broccoli](https://github.com/cssnext/broccoli-cssnext) +, +[connect](https://github.com/cssnext/cssnext-connect) +, +[duo](https://github.com/cssnext/duo-cssnext) +or in +[prepros 5](https://prepros.io/) +

+ + +### CLI + +cssnext offers a command-line interface. +Here's how to compile a file and print it to stdout: + +```console +$ cssnext index.css +``` + +To create an output file, you can just add a second argument + +```console +$ cssnext index.css output.css +``` + +Or use CLI std(in|out) redirection(s) + +```console +$ cat input.css | cssnext > output.css +``` + +### CLI options + +If you don't care about a certain feature, such as custom media queries, you can omit support for them like so: + +```console +$ cssnext --no-custom-media index.css +``` + +To enable source maps for these files, add the `--sourcemap` flag. + +**To see all CLI options** + +```console +$ cssnext --help +``` + +### Node.js API + +cssnext can be used with its own API or as a PostCSS plugin. + +#### `var string = cssnext(string, options)` + +cssnext accepts 2 arguments: a css string and an object of options. + +```js +var fs = require("fs") +var cssnext = require("cssnext") + +var input = fs.readFileSync("index.css", "utf8") + +var output = cssnext(input) +fs.writeFileSync("dist/index.css", output) +``` + +**`/!\` Note: if you are using non inlined sourcemaps, cssnext will return an object: `{css: string, map: sourcemap}`** + +See [sourcemap](#sourcemap-default-false) & [map](#map-default-depends-on-sourcemap) options for more informations. + +#### `var postcssPlugin = cssnext(options)` + +cssnext can be used as a postcss plugin: + +```js +var fs = require("fs") +var postcss = require("postcss") +var cssnext = require("cssnext") + +var input = fs.readFileSync("index.css", "utf8") + +var output = postcss() + .use(cssnext()) + .use(/* your other postcss plugin */) + .process(input) +fs.writeFileSync("dist/index.css", output) +``` diff --git a/docs/content/usage.md b/docs/content/usage.md new file mode 100644 index 0000000..08cc3e4 --- /dev/null +++ b/docs/content/usage.md @@ -0,0 +1,145 @@ +--- +title: How to use cssnext ? +incomplete: true +--- + +When you have correctly [setup](/setup/) cssnext, you might want to tweak it a +little bit. You will find below all the available options. + +# Options + +## `browsers` + +(default: [browserslist default](https://github.com/ai/browserslist#readme) - `> 1%, last 2 versions, Firefox ESR, Opera 12.1`) + +Allows you to specify your browser scope. +**This option enables or disables `features` according to [caniuse](http://caniuse.com/) database.** +This is the exact same option that you might know from Autoprefixer. +Since cssnext includes Autoprefixer, the option is propagated. + +See [Browserslist](https://github.com/ai/browserslist#queries) queries syntax to adjust this option to your needs. + +_Note: if you don't specify this option, Browserslist will automatically try to find a `browserslist` +config file or use its default value._ + +## `features` + +(default: all features) + +**You should probably use `browsers` option instead of this one.** + +Object containing key of features to enable/disable. +_Features are enabled by default: no key means feature is enabled_. + +```js +//eg: disable custom properties support +var output = cssnext(input, { + features: { + customProperties: false + } +}) +``` + +Each feature is based on PostCSS plugins & can get its own options. +To pass options to a feature, you can just pass an object to the feature: + +```js +//eg: preserve custom properties +var output = cssnext(input, { + features: { + customProperties: { + preserve: true + } + } +}) +``` + +To know all available options, please check corresponding postcss plugin: + +- `customProperties` (=> postcss-custom-properties) +- `calc` (=> postcss-calc) +- `customMedia` (=> postcss-custom-media) +- `mediaQueriesRange` (=> postcss-media-minmax) +- `customSelectors` (=> postcss-custom-selectors) +- `colorRebeccapurple` (=> postcss-color-rebeccapurple) +- `colorHwb` (=> postcss-color-hwb) +- `colorGray` (=> postcss-color-gray) +- `colorHexAlpha` (=> postcss-color-hex-alpha) +- `colorFunction` (=> postcss-color-function) +- `fontVariant` (=> postcss-font-variant) +- `filter` (=> pleeease-filters) +- `rem` (=> pixrem) +- `pseudoElements` (=> postcss-pseudoelements) +- `pseudoClassMatches` (=> postcss-selector-matches) +- `pseudoClassNot` (=> postcss-selector-not) +- `colorRgba` (=> postcss-color-rgba-fallback) +- `autoprefixer` (=> autoprefixer-core) + +_Note: order is important to get everything working correctly._ + +## `import` + +(default: `true`) + +Allows you to inline local `@import` files (thanks to [postcss-import](https://github.com/postcss/postcss-import#readme)): + +* you can refer to `node_modules` and `web_modules` packages +* you can omit .css extension + +_Note: you can pass [postcss-import options](https://github.com/postcss/postcss-import#readme) directly._ + +## `url` + +(default: `true`) + +By default, `url()` are rebased according to `from` (and `to`) option(s). This is convenient especially for `@import`ed files. + +_Note: you can pass [postcss-url options](https://github.com/postcss/postcss-url#options) directly in order to inline or have more control over urls._ + +## `compress` + +(default: `false`) + +Allows you to compress the output (using [cssnano](https://github.com/ben-eb/cssnano)). +You can enable minification by passing `true` or by providing an object containing [cssnano options](https://github.com/ben-eb/cssnano#options). + +## `sourcemap` + +(default: `false`) + +This option is a shortcut to enable inlined sourcemap in the output. +Just pass `true` to get the sourcemap at the end of the output. + +- _If you want an accurate sourcemap, please also use the `from` option._ +- _If you want more control on the sourcemap, please use the `map` option instead._ + +## `map` + +(default: _depends on `sourcemap`_) + +_(default: `undefined` if `sourcemap` is `false`, `inline` if `sourcemap` it true)_ + +If you want better control on sourcemap, you are at the right place. +This is the [postcss `map` option](https://github.com/postcss/postcss#source-map-1), so checkout the related documentation directly. + +_If you specify this option, `sourcemap` value will be ignored._ + +**`/!\` Using this option might change the return value of `cssnext()` (`object` instead of css `string` if map is not inlined. The object will be like {css: "{css string}", map: {sourcemap object}})** + +## `from` + +(default: `null`) + +Source of the file. Required for accurate sourcemap. + +```js +var cssnext = require("cssnext") +var fs = require("fs") + +var source = "./index.css" +var output = cssnext( + fs.readFileSync(source, "utf8"), + {from: source} +) +fs.writeFileSync("dist/index.css", output) +``` diff --git a/docs/scripts/build.js b/docs/scripts/build.js new file mode 100644 index 0000000..0a988ca --- /dev/null +++ b/docs/scripts/build.js @@ -0,0 +1,185 @@ +import path from "path" + +import {sync as rm} from "rimraf" +import async from "async" +import color from "chalk" +import nanoLogger from "nano-logger" + +import Metalsmith from "metalsmith" +import markdown from "metalsmith-md" +import addFilenames from "metalsmith-filenames" +import url from "metalsmith-url" +import rename from "metalsmith-rename" +// import collections from "metalsmith-collections" +// import rss from "metalsmith-rss" +import react from "metalsmith-react" + +import webpack from "webpack" +import webpackConfig from "./webpack.config" + +// prod +import copyWithContentHash from "copy-with-content-hash/hash-file" + +// dev +import watch from "metalsmith-watch" +import devServer from "./webpack-dev-server" + +// customize marked +import "./marked" + +import pkg from "../../package" + +import variables, {defineGlobalVariables} from "./variables" +defineGlobalVariables() +const DEV_SERVER = process.argv.includes("--dev-server") + +const log = nanoLogger("./build") + +log(color.cyan("- Variables")) +JSON.stringify(variables, null, 2).split("\n").forEach(l => log(l)) + +const mdToHtmlReplacement = [/\.md$/, ".html"] + +// We clean ./dist by hand mainly for prod, in order to be able to build +// assets with webpack before metalsmith build. +// This allows us to get hashes in filename and pass them to the build +rm(path.join(__dirname, "..", "dist")) + +const smith = new Metalsmith(path.join(__dirname, "..")) +smith +.source("content") +.destination("dist") +// clean is made before +.clean(false) + +// convert markdown +.use( + markdown({ + baseHref: `${__SERVER_URL__}/`, + }) +) + +// useful for some homemade plugins +.use( + addFilenames() +) + +// add url meta data with some replacements +.use( + url([ + mdToHtmlReplacement, + [/index\.html?$/, ""], + ]) +) +// wrap .html into react `template:` +.use( + react({ + pattern: [ + "**/*.md", + "**/*.html", + ], + templatesPath: "src/layouts", + defaultTemplate: "Default", + before: "", + data: { + pkg: pkg, + metadata: smith.metadata(), + }, + }) +) + +.use( + rename([ + mdToHtmlReplacement, + // no .html at the end of urls + [/\.html$/, "/index.html"], + // ensure we only have index.html, no index/index + [/index\/index\.html$/, "index.html"], + ]) +) + +// for development, we build metalsmith first, then we serve via +// webpack-dev-server which build assets too (no hashes involved) +if (DEV_SERVER) { + smith.metadata().assets = { + scripts: [ + "/index.js", + `http://${__SERVER_HOSTNAME__}:${__LR_SERVER_PORT__}/livereload.js`, + ], + // css is handled by the js via webpack style-loader + } + smith + .use( + watch({ + log: nanoLogger("watcher"), + livereload: __LR_SERVER_PORT__, + paths: { + "${source}/**/*": true, + "src/layouts/**/*": "**/*.md", + "src/modules/**/*": "**/*.md", + }, + }) + ) + .build((err) => { + if (err) { + throw err + } + + devServer({ + protocol: __SERVER_PROTOCOL__, + host: __SERVER_HOSTNAME__, + port: __SERVER_PORT__, + open: process.argv.includes("--open"), + }) + }) +} + +// for production we build assets first to be able to pass some assets hashes +// to metalsmith +else { + webpack(webpackConfig, (err, stats) => { + if (err) { + throw err + } + + if (stats.hasErrors()) { + stats.compilation.errors.forEach( + item => log(...[color.red("Error:"), ...item.message.split("\n")]) + ) + throw new Error("webpack build failed with errors") + } + if (stats.hasWarnings()) { + stats.compilation.warnings.forEach( + item => log(...[color.yellow("Warning:"), ...item.message.split("\n")]) + ) + } + + console.log(color.green("\n✓ Assets build completed")) + + async.map( + [ + "index.js", + ...(__PROD__ ? ["index.css"] : []), + ], + (file, cb) => copyWithContentHash(`./docs/dist/${file}`, false, cb), + (asynErr, results) => { + if (asynErr) { + throw asynErr + } + + smith.metadata().assets = { + scripts: ["/" + results[0]], + ...(__PROD__ ? {stylesheets: ["/" + results[1]]} : {}), + } + smith + .build(buildErr => { + if (buildErr) { + throw buildErr + } + + console.log(color.green("\n✓ Static build completed")) + }) + } + ) + }) +} diff --git a/docs/scripts/deploy-to-gh-pages.sh b/docs/scripts/deploy-to-gh-pages.sh new file mode 100755 index 0000000..94950b1 --- /dev/null +++ b/docs/scripts/deploy-to-gh-pages.sh @@ -0,0 +1,133 @@ +#!/usr/bin/env bash + +set -o errexit #abort if any command fails + +# https://github.com/X1011/git-directory-deploy/pull/10 +deploy_directory=${GIT_DEPLOY_DIR:-dist} +deploy_branch=${GIT_DEPLOY_BRANCH:-gh-pages} + +#if no user identity is already set in the current git environment, use this: +default_username=${GIT_DEPLOY_USERNAME:-deploy.sh} +default_email=${GIT_DEPLOY_EMAIL:-} + +#repository to deploy to. must be readable and writable. +repo=${GIT_DEPLOY_REPO:-origin} + +# Parse arg flags +while : ; do + if [[ $1 = "-v" || $1 = "--verbose" ]]; then + verbose=true + shift + elif [[ $1 = "-s" || $1 = "--setup" ]]; then + setup=true + shift + elif [[ $1 = "-e" || $1 = "--allow-empty" ]]; then + allow_empty=true + shift + else + break + fi +done + +#echo expanded commands as they are executed (for debugging) +function enable_expanded_output { + if [ $verbose ]; then + set -o xtrace + set +o verbose + fi +} + +#this is used to avoid outputting the repo URL, which may contain a secret token +function disable_expanded_output { + if [ $verbose ]; then + set +o xtrace + set -o verbose + fi +} + +enable_expanded_output + +function set_user_id { + if [[ -z `git config user.name` ]]; then + git config user.name "$default_username" + fi + if [[ -z `git config user.email` ]]; then + git config user.email "$default_email" + fi +} + +function restore_head { + if [[ $previous_branch = "HEAD" ]]; then + #we weren't on any branch before, so just set HEAD back to the commit it was on + git update-ref --no-deref HEAD $commit_hash $deploy_branch + else + git symbolic-ref HEAD refs/heads/$previous_branch + fi + + git reset --mixed +} + +if ! git diff --exit-code --quiet --cached; then + echo Aborting due to uncommitted changes in the index >&2 + exit 1 +fi + +commit_title=`git log -n 1 --format="%s" HEAD` +commit_hash=`git log -n 1 --format="%H" HEAD` +previous_branch=`git rev-parse --abbrev-ref HEAD` + +if [ $setup ]; then + mkdir -p "$deploy_directory" + git --work-tree "$deploy_directory" checkout --orphan $deploy_branch + git --work-tree "$deploy_directory" rm -r "*" + git --work-tree "$deploy_directory" add --all + git --work-tree "$deploy_directory" commit -m "initial publish"$'\n\n'"generated from commit $commit_hash" + git push $repo $deploy_branch + restore_head + exit +fi + +if [ ! -d "$deploy_directory" ]; then + echo "Deploy directory '$deploy_directory' does not exist. Aborting." >&2 + exit 1 +fi + +if [[ -z `ls -A "$deploy_directory" 2> /dev/null` && -z $allow_empty ]]; then + echo "Deploy directory '$deploy_directory' is empty. Aborting. If you're sure you want to deploy an empty tree, use the -e flag." >&2 + exit 1 +fi + +disable_expanded_output +git fetch --force $repo $deploy_branch:$deploy_branch +enable_expanded_output + +#make deploy_branch the current branch +git symbolic-ref HEAD refs/heads/$deploy_branch + +#put the previously committed contents of deploy_branch branch into the index +git --work-tree "$deploy_directory" reset --mixed --quiet + +git --work-tree "$deploy_directory" add --all + +set +o errexit +diff=$(git --work-tree "$deploy_directory" diff --exit-code --quiet HEAD)$? +set -o errexit +case $diff in + 0) echo No changes to files in $deploy_directory. Skipping commit.;; + 1) + set_user_id + git --work-tree "$deploy_directory" commit -m \ + "publish: $commit_title"$'\n\n'"generated from commit $commit_hash" + + disable_expanded_output + #--quiet is important here to avoid outputting the repo URL, which may contain a secret token + git push --quiet $repo $deploy_branch + enable_expanded_output + ;; + *) + echo git diff exited with code $diff. Aborting. Staying on branch $deploy_branch so you can debug. To switch back to master, use: git symbolic-ref HEAD refs/heads/master && git reset --mixed >&2 + exit $diff + ;; +esac + +restore_head diff --git a/docs/scripts/marked.js b/docs/scripts/marked.js new file mode 100644 index 0000000..e768e9c --- /dev/null +++ b/docs/scripts/marked.js @@ -0,0 +1,145 @@ +/* eslint no-script-url: 0 */ +import path from "path" + +import marked from "marked" +import hljs from "highlight.js" + +// https://github.com/chjj/marked/blob/master/lib/marked.js#L1096 +function unescape(html) { + return html.replace(/&([#\w]+);/g, function(_, n) { + n = n.toLowerCase() + if (n === "colon") { + return ":" + } + if (n.charAt(0) === "#") { + return n.charAt(1) === "x" + ? String.fromCharCode(parseInt(n.substring(2), 16)) + : String.fromCharCode(+n.substring(1)) + } + return "" + }) +} + +function rebaseUrl(baseHref, currentPath, uri) { + // don't touch non relative uri + if ( + // skip absolute url + uri.indexOf("/") === 0 || + // datauris + uri.indexOf("data:") === 0 || + // internal links + // uri.indexOf("#") === 0 || + // protocol based + /^[a-z]+:\/\//.test(uri) + ) { + return uri + } + else { + // make it absolute + return baseHref + path.normalize(path.join(currentPath, uri)) + } +} + +const renderer = new marked.Renderer() +const headingIds = {} +renderer.heading = function(text, level, raw) { + const escaped = raw + // url in lower case are cool + .toLowerCase() + + // dashify + // .replace(/[^\w]+/g, "-") + .replace(/\W+/g, "-") + .replace(/^-+/, "") + .replace(/-+$/, "") + + const key = this.options.__metalsmith.__filename + "#" + escaped + if (!headingIds[key]) { + headingIds[key] = 0 + } + headingIds[key]++ + const id = escaped + ( + headingIds[key] > 1 ? `-${headingIds[key]}` : "" + ) + + return ( + ` + # + ${text} + ` + ) +} + +renderer.link = function(href, title, text) { + + // DON'T PLAY WITH US OK ? + // (this came from original marked source code and should remain I think) + if (this.options.sanitize) { + try { + var prot = decodeURIComponent(unescape(href)) + .replace(/[^\w:]/g, "") + .toLowerCase() + } + catch (e) { + return "" + } + + if ( + prot.indexOf("javascript:") === 0 || + prot.indexOf("vbscript:") === 0 + ) { + return "" + } + } + + return `${text}` +} + +renderer.image = function(href, title, text) { + return ( + `${text}" : ">"}` + ) +} + +marked.setOptions({ + + renderer: renderer, + + highlight: (code, language) => { + code = code.trim() + + // language is recognized by highlight.js + if (hljs.getLanguage(language)) { + return hljs.highlight(language, code).value + } + + // fallback to auto + return hljs.highlightAuto(code).value + }, + + gfm: true, + tables: true, + smartypants: true, +}) + +export default marked diff --git a/docs/scripts/variables.js b/docs/scripts/variables.js new file mode 100644 index 0000000..58096f8 --- /dev/null +++ b/docs/scripts/variables.js @@ -0,0 +1,39 @@ +const __PROD__ = process.argv.includes("--production") + +const variables = { + __DEV__: !__PROD__, + __PROD__, + ...__PROD__ && { + "process.env": { + NODE_ENV: JSON.stringify("production"), + }, + }, + __SERVER_PROTOCOL__: "http://", + ...( + __PROD__ ? + { + __SERVER_HOSTNAME__: "cssnext.io", + __SERVER_HOST__: "cssnext.io", + "process.env": { + NODE_ENV: JSON.stringify("production"), + }, + } + : + { + __SERVER_HOSTNAME__: "0.0.0.0", + __SERVER_PORT__: 1985, + __SERVER_HOST__: "0.0.0.0:1985", + __LR_SERVER_PORT__: 1986, + } + ), +} + +variables.__SERVER_URL__ = + `${variables.__SERVER_PROTOCOL__}${variables.__SERVER_HOST__}` + +export default variables + +// define some global var like __DEV__ +export function defineGlobalVariables() { + Object.keys(variables).forEach((k) => global[k] = variables[k]) +} diff --git a/docs/scripts/webpack-dev-server.js b/docs/scripts/webpack-dev-server.js new file mode 100644 index 0000000..456e2a1 --- /dev/null +++ b/docs/scripts/webpack-dev-server.js @@ -0,0 +1,79 @@ +import webpack from "webpack" +import webpackNanoLogs from "webpack-nano-logs" +import WebpackDevServer from "webpack-dev-server" +import opn from "opn" +import logger from "nano-logger" + +import config from "./webpack.config" + +const log = logger("webpack-dev-server") + +export default (options) => { + options = { + protocol: "http://", + host: "0.0.0.0", + port: 3000, + open: true, + ...(options || {}), + } + + const serverUrl = `${options.protocol}${options.host}:${options.port}` + + const devEntries = [ + `webpack-dev-server/client?${serverUrl}`, + `webpack/hot/only-dev-server`, + ] + + const devConfig = { + ...config, + debug: true, + watch: true, + colors: true, + progress: true, + entry: { + // add devEntries + ...Object.keys(config.entry) + .reduce( + (acc, key) => { + // entries with name that start with "test" do not need extra stuff + acc[key] = key.indexOf("tests") === 0 ? + config.entry[key] : + [ + ...devEntries, + ...config.entry[key], + ] + return acc + }, + {} + ), + }, + plugins: [ + ...(config.plugins || []), + new webpack.NoErrorsPlugin(), + new webpack.HotModuleReplacementPlugin(), + webpackNanoLogs, + ], + eslint: { + ...config.eslint, + emitWarning: true, + }, + } + + return new WebpackDevServer( + webpack(devConfig), + { + https: options.protocol === "https://", + contentBase: config.output.path, + hot: true, + stats: { + colors: true, + }, + noInfo: true, + }) + .listen(options.port, options.host, () => { + log(`Dev server started on ${serverUrl}`) + if (options.open) { + opn(`${serverUrl}`) + } + }) +} diff --git a/docs/scripts/webpack.config.js b/docs/scripts/webpack.config.js new file mode 100644 index 0000000..ec68999 --- /dev/null +++ b/docs/scripts/webpack.config.js @@ -0,0 +1,97 @@ +import path from "path" + +import webpack from "webpack" +import ExtractTextPlugin from "extract-text-webpack-plugin" + +import variables, {defineGlobalVariables} from "./variables" +defineGlobalVariables() + +const production = __PROD__ || process.argv.includes("--production") + +var config = { + entry: { + index: [ + "./docs/src/index", + ], + playground: [ + "./docs/src/modules/playground/index", + ], + }, + + output: { + path: path.join(__dirname, "..", "dist"), + filename: "[name].js", + publicPath: "/", + }, + + resolve: { + extensions: [ + "", + ".js", + ".json", + ".css", + ], + + alias: { + "caniuse-db": path.resolve(__dirname, "../../node_modules/caniuse-db"), + }, + }, + + module: { + // ! \\ note that loaders are executed from bottom to top ! + loaders: [ + { + test: /\.(jsx?|es)$/, + loaders: [ + "babel?" + JSON.stringify({ + stage: 0, + }), + "eslint", + ], + exclude: /node_modules/, + }, + { + test: /\.json$/, + loaders: [ + "json", + ], + }, + { + test: /\.css$/, + loader: ExtractTextPlugin.extract( + "style-loader", + "css-loader!cssnext-loader" + ), + }, + { + test: /\.(ico|jpe?g|png|gif|svg)$/, + loaders: [ + "file?name=[path][name].[ext]&context=./docs/src", + ], + }, + ], + }, + + plugins: [ + new webpack.DefinePlugin(variables), + new ExtractTextPlugin("[name].css", {disable: !production}), + ...(production ? + [ + new webpack.optimize.UglifyJsPlugin({ + compress: { + warnings: false, + }, + }), + ] : + [] + ), + ], + + node: { + // https://github.com/webpack/webpack/issues/451 + // run tape test with webpack + fs: "empty", + }, +} + +export default config diff --git a/docs/src/assets/cssnext.svg b/docs/src/assets/cssnext.svg new file mode 100644 index 0000000..b5202b7 --- /dev/null +++ b/docs/src/assets/cssnext.svg @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/assets/delorean-back.jpg b/docs/src/assets/delorean-back.jpg new file mode 100644 index 0000000..9da9033 Binary files /dev/null and b/docs/src/assets/delorean-back.jpg differ diff --git a/docs/src/assets/delorean-front.jpg b/docs/src/assets/delorean-front.jpg new file mode 100644 index 0000000..ecd6636 Binary files /dev/null and b/docs/src/assets/delorean-front.jpg differ diff --git a/docs/src/assets/engine.jpg b/docs/src/assets/engine.jpg new file mode 100644 index 0000000..fb4a530 Binary files /dev/null and b/docs/src/assets/engine.jpg differ diff --git a/docs/src/assets/fast.jpg b/docs/src/assets/fast.jpg new file mode 100644 index 0000000..b707eb3 Binary files /dev/null and b/docs/src/assets/fast.jpg differ diff --git a/docs/src/assets/flux.jpg b/docs/src/assets/flux.jpg new file mode 100644 index 0000000..0510614 Binary files /dev/null and b/docs/src/assets/flux.jpg differ diff --git a/docs/src/assets/github.svg b/docs/src/assets/github.svg new file mode 100644 index 0000000..193277b --- /dev/null +++ b/docs/src/assets/github.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + + diff --git a/docs/src/assets/road.jpg b/docs/src/assets/road.jpg new file mode 100644 index 0000000..ce250e8 Binary files /dev/null and b/docs/src/assets/road.jpg differ diff --git a/docs/src/assets/team.jpg b/docs/src/assets/team.jpg new file mode 100644 index 0000000..bdaf191 Binary files /dev/null and b/docs/src/assets/team.jpg differ diff --git a/docs/src/assets/twitter.svg b/docs/src/assets/twitter.svg new file mode 100644 index 0000000..acc81b7 --- /dev/null +++ b/docs/src/assets/twitter.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + diff --git a/docs/src/index.css b/docs/src/index.css new file mode 100644 index 0000000..8690692 --- /dev/null +++ b/docs/src/index.css @@ -0,0 +1,335 @@ +/* base */ +@import "normalize.css/normalize.css"; +@import "cssrecipes-defaults"; + +/* grid */ +@import "cssrecipes-custom-media-queries"; +@import "cssrecipes-grid"; +@import "cssrecipes-utils"; + +@import "cssrecipes-vertical-rhythm"; +@import "cssrecipes-vertical-rhythm/lib/ratio/minor-third.css"; + +@import "./modules/Header"; +@import "./modules/Footer"; +@import "./modules/SVGIcon"; +@import "./modules/playground"; + +:root { + --cssnext-Color-blue: #318edf; + --cssnext-Color-purple: #8053ca; + --cssnext-Color-green: #46C340; +} + +/** + * generic typography + */ + +html { + /*height: 100%;*/ + margin: 0; + padding: 0; + + background: #f1f1f1 +} + +body { + /*min-height: 100%;*/ + display: flex; + flex-direction: column; + + min-height: 100vh; + margin: 0; + padding: 0; + + font-family: Avenir Next, Calibri, Calibri Light, Segoe UI, Segoe UI Light, Myanmar Text, sans-serif; +} + +::selection { + color: #fff; + background: #428BCA; +} + +a, +a:visited { + color: inherit; + position: relative; + text-decoration: none; +} + + a::before { + content: ""; + position: absolute; + height: 1px; + left: 0; + right: 0; + bottom: 0; + + background: currentColor; + opacity: .25; + + transform: scaleX(.85) translateY(.085rem); + transition: .2s; + } + a:hover::before, + a:focus::before { + opacity: 0.75; + transform: scaleX(.95); + } + a:active::before { + opacity: .2; + } + +h1, +h2, +h3 { + font-weight: 300; +} + +/** + * customise recipes + */ + +.r-Grid { + width: auto; + margin: 0 auto; + padding: 0 1rem; +} + @media (--r-minM) { + .r-Grid { + max-width: 65rem; + padding: 0; + } + } + /*@media (--r-minM) { .r-Grid { width: 70rem } }*/ + /*@media (--r-minXL) { .r-Grid { width: 70rem } }*/ + + +/** + * cssnext stuff + */ + +.cssnext-Icon { + display: inline-block; + + width: 1.2em; /* required for IE */ + height: 1.2em; + line-height: 1; + vertical-align: middle; + + color: inherit; + fill: currentColor; + + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + transform: translate3d(0,0,0); /* fix webkit/blink poor rendering issues */ +} + +:root { + --cssnext-Header-height: calc(var(--r-lineHeight) * 2.5); +} + +.r-VerticalRhythm {font-size: .8333rem} +@media (--r-minM) { + .r-VerticalRhythm {font-size: 1rem} +} + +@media (--r-minM) { + .cssnext-Body {padding-top: var(--cssnext-Header-height)} +} + + + +.cssnext-Center { text-align: center } + +.cssnext-Light { + color: #fff; + font-weight: 300; +} + + .cssnext-Light a { color: #fff !important } + .cssnext-Light a::before { background: #f1f1f1 } + +.cssnext-Jumbotron { + overflow: auto; + padding: 6rem 0; +} + + .cssnext-Jumbotron + :not(.cssnext-Jumbotron) { margin-top: var(--r-lineHeight) } + + .cssnext-Jumbotron--default { + background: linear-gradient(160deg, + color(var(--cssnext-Color-purple) l(-5%) a(.9)), + color(var(--cssnext-Color-blue) a(.9)) + ), + url("assets/delorean-back.jpg") no-repeat 50% 50%/cover + ; + } + + .cssnext-Jumbotron--whiteRoad { + background: linear-gradient(160deg, + color(var(--cssnext-Color-purple) l(90%) a(.9)), + color(var(--cssnext-Color-blue) l(90%) a(.9)) + ), + url("assets/road.jpg") no-repeat 50% 10%/cover + ; + } + .cssnext-Jumbotron--darkRoad { + background: linear-gradient(160deg, + color(var(--cssnext-Color-blue) a(.9)), + color(var(--cssnext-Color-purple) a(.9)) + ), + url("assets/road.jpg") no-repeat 50% 10%/cover + ; + } + .cssnext-Jumbotron--darkDeloreanFront { + background: linear-gradient(160deg, + color(var(--cssnext-Color-purple) l(-10%) a(.95)), + color(var(--cssnext-Color-blue) l(-5%) a(.9)) + ), + url("assets/delorean-front.jpg") no-repeat 50% 70%/cover + ; + } + .cssnext-Jumbotron--lightFast { + background: linear-gradient(160deg, + color(var(--cssnext-Color-blue) l(90%) a(.9)), + color(var(--cssnext-Color-purple) l(90%) a(.9)) + ), + url("assets/fast.jpg") no-repeat 50% 50%/cover + ; + } + .cssnext-Jumbotron--darkFlux { + background: linear-gradient(160deg, + color(var(--cssnext-Color-blue) a(.7)), + color(var(--cssnext-Color-purple) a(.9)) + ), + url("assets/flux.jpg") no-repeat 50% 50%/cover + ; + } + .cssnext-Jumbotron--lightTeam { + background: linear-gradient(160deg, + color(var(--cssnext-Color-purple) l(90%) a(.95)), + color(var(--cssnext-Color-blue) l(90%) a(.95)) + ), + url("assets/team.jpg") no-repeat 50% 50%/cover + ; + } + .cssnext-Jumbotron--darkTeam { + background: linear-gradient(160deg, + color(var(--cssnext-Color-blue) a(.95)), + color(var(--cssnext-Color-purple) a(.95)) + ), + url("assets/team.jpg") no-repeat 50% 50%/cover + ; + } + .cssnext-Jumbotron--cssrecipes { + background: linear-gradient(160deg, + color(var(--cssnext-Color-blue) a(.85)), + color(var(--cssnext-Color-green) a(.85)) + ), + url("assets/engine.jpg") no-repeat 50% 50%/cover + ; + } + + .cssnext-Jumbotron-title { + display: block; + font-size: calc(var(--r-h1-fontSize) * 1.5); + line-height: calc(var(--r-h1-lineHeight) * 1.5); + font-weight: 400; + margin: 6rem auto; + text-shadow: 0 .1rem .1rem rgba(0, 0, 0, 0.4); + } + + .cssnext-Jumbotron-title--smaller { + font-size: var(--r-h1-fontSize); + line-height: var(--r-h1-lineHeight); + } + +.cssnext-List { + margin: 0 4rem var(--r-lineHeight) !important; + /*margin-right: 0 !important ;*/ +} + + +.cssnext-FeaturesList { +} + + .cssnext-FeaturesList li::before { + content: "〉 "; + padding-right: .4rem; + opacity: .4; + font-size: var(--r-small-fontSize); + } + + .cssnext-FeaturesList-small { + opacity: .4; + font-size: var(--r-small-fontSize); + } + +.cssnext-Section { + margin: 0 auto var(--r-lineHeight); + /*max-width: 50rem;*/ +} + + .cssnext-Section-title { text-align: center } + + .cssnext-Section-content { + + } + + .cssnext-Section-highlight { + display: block; + text-align: center; + margin: var(--r-lineHeight); + } + + .cssnext-Section-link { + text-align: center; + font-size: var(--r-small-fontSize); + color: var(--cssnext-Color-blue); + } + + .cssnext-Section-link:hover { color: var(--cssnext-Color-purple) } + +.cssnext-Tools { + text-align: center; + font-size: var(--r-h3-fontSize); + font-weight: 300; +} + +.cssnext-INeedSpace { + margin-top: calc(var(--r-lineHeight) * 2); + margin-bottom: calc(var(--r-lineHeight) * 2); +} + + +.cssnext-Callout { + font-size: var(--r-small-fontSize); + padding: 1rem 1rem 0; + margin-bottom: var(--r-lineHeight); + border: 1px solid color(#000 a(.1)); + border-left-width: .2rem; + border-radius: 3px; +} + + .cssnext-Callout--danger { border-left-color: #d9534f; } + .cssnext-Callout--danger .cssnext-Callout-title { color: #ce4844; } + + .cssnext-Callout--warning { border-left-color: #f0ad4e; } + .cssnext-Callout--warning .cssnext-Callout-title { color: #aa6708; } + + .cssnext-Callout--info { border-left-color: var(--cssnext-Color-blue); } + .cssnext-Callout--info .cssnext-Callout-title { color: color(var(--cssnext-Color-blue) b(+20%)); } + +pre { + margin: 1rem 0; + padding: 1rem; + + font-size: var(--r-small-fontSize); + font-weight: 400; + + color: color(var(--cssnext-Color-blue) l(-10%)); + border: 1px solid #DDD; + border-radius: 0.3em; + background: color(#fafafa a(.6)); +} diff --git a/docs/src/index.js b/docs/src/index.js new file mode 100644 index 0000000..feff3ff --- /dev/null +++ b/docs/src/index.js @@ -0,0 +1,6 @@ +// import "./modules/polyfills" +import "./index.css" + +if (console && console.info) { + console.info("cssnext") +} diff --git a/docs/src/layouts/Default.js b/docs/src/layouts/Default.js new file mode 100644 index 0000000..9fffc97 --- /dev/null +++ b/docs/src/layouts/Default.js @@ -0,0 +1,135 @@ +import React, {Component, PropTypes} from "react" +import cx from "classnames" + +import dashify from "../modules/dashify" + +import Html from "../modules/Html" +import Head from "../modules/Head" +import Body from "../modules/Body" + +export default class Default extends Component { + + static propTypes = { + pkg: PropTypes.object.isRequired, + metadata: PropTypes.object.isRequired, + // collections: PropTypes.object.isRequired, + file: PropTypes.object.isRequired, + } + + static childContextTypes = { + pkg: PropTypes.object.isRequired, + // collections: PropTypes.object.isRequired, + file: PropTypes.object.isRequired, + } + + getChildContext() { + return { + pkg: this.props.pkg, + // collections: this.props.collections, + file: this.props.file, + } + } + + render() { + const { + file, + } = this.props + const footer = file.footer === undefined ? true : file.footer + + if (!file.title) { + console.log(`${file.filename} doesn't have a title`) + } + return ( + + + +
+
+
+

+ {file.title} +

+
+
+
+ + { + file.incomplete && +
+
+
Incomplete
+

+ { + "This documentation is still a work in progress. " + } +
+ + Pull requests + + { + " expanding on existing or adding additional content " + + " are " + } + extremely appreciated. +

+
+
+ } + +
+
+
+ + { + footer && +
+
+ Try cssnext in your browser now. +
+
+ } + + + + ) + } +} diff --git a/docs/src/layouts/Simple.js b/docs/src/layouts/Simple.js new file mode 100644 index 0000000..30af7b9 --- /dev/null +++ b/docs/src/layouts/Simple.js @@ -0,0 +1,60 @@ +import React, {Component, PropTypes} from "react" + +import Html from "../modules/Html" +import Head from "../modules/Head" +import Body from "../modules/Body" + +export default class Simple extends Component { + + static propTypes = { + pkg: PropTypes.object.isRequired, + metadata: PropTypes.object.isRequired, + // collections: PropTypes.object.isRequired, + file: PropTypes.object.isRequired, + } + + static childContextTypes = { + pkg: PropTypes.object.isRequired, + // collections: PropTypes.object.isRequired, + file: PropTypes.object.isRequired, + } + + getChildContext() { + return { + pkg: this.props.pkg, + // collections: this.props.collections, + file: this.props.file, + } + } + + render() { + const { + file, + } = this.props + const footer = file.footer === undefined ? true : file.footer + + if (!file.title) { + console.log(`${file.filename} doesn't have a title`) + } + return ( + + + +
+ + + ) + } +} diff --git a/docs/src/modules/Analytics/index.js b/docs/src/modules/Analytics/index.js new file mode 100644 index 0000000..73bdee8 --- /dev/null +++ b/docs/src/modules/Analytics/index.js @@ -0,0 +1,25 @@ +import React, {Component} from "react" + +import isogram from "isogram" + +export default class Analytics extends Component { + + render() { + return ( + + ) + } +} diff --git a/docs/src/modules/Body/index.js b/docs/src/modules/Body/index.js new file mode 100644 index 0000000..5de0c53 --- /dev/null +++ b/docs/src/modules/Body/index.js @@ -0,0 +1,47 @@ +import React, {Component, PropTypes} from "react" + +import Header from "../Header" +import Footer from "../Footer" +import Analytics from "../Analytics" + +export default class Body extends Component { + + static defaultProps = { + scripts: [], + footer: true, + } + + static contextTypes = { + pkg: PropTypes.object.isRequired, + file: PropTypes.object.isRequired, + } + + static propTypes = { + children: PropTypes.oneOfType([ + PropTypes.array, + PropTypes.object, + ]).isRequired, + scripts: PropTypes.array, + footer: PropTypes.bool, + } + + render() { + return ( + + +
+ + {this.props.children} + +