diff --git a/CHANGELOG.md b/CHANGELOG.md index 3058fd992ba..16eccf6b8ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # [`master`](https://github.com/elastic/eui/tree/master) - Add disabled prop to `EuiComboBoxOption` ([#650](https://github.com/elastic/eui/pull/650)) +- Added export of sass theme variables in json format during compilation ([#642](https://github.com/elastic/eui/pull/642)) # [`0.0.40`](https://github.com/elastic/eui/tree/v0.0.40) diff --git a/package.json b/package.json index 7f9fa27996f..107eef669f3 100644 --- a/package.json +++ b/package.json @@ -105,6 +105,8 @@ "redux": "^3.7.2", "redux-thunk": "^2.2.0", "rimraf": "^2.6.2", + "sass-extract": "^2.1.0", + "sass-extract-js": "^0.3.0", "sass-loader": "^6.0.6", "sass-vars-to-js-loader": "^2.0.2", "shelljs": "^0.8.1", diff --git a/scripts/compile-scss.js b/scripts/compile-scss.js index 73fe1dff894..d1a217ad1b8 100755 --- a/scripts/compile-scss.js +++ b/scripts/compile-scss.js @@ -1,16 +1,75 @@ -const { execSync } = require('child_process'); -const shell = require('shelljs'); -const glob = require('glob'); - -shell.mkdir('dist'); - -glob('./src/theme_*.scss', undefined, (error, files) => { - files.forEach(file => { - const splitPath = file.split('/'); - const fileName = splitPath[splitPath.length - 1]; - const splitFileName = fileName.split('.'); - const baseFileName = splitFileName[0]; - execSync(`node-sass ${file} > "dist/eui_${baseFileName}.css"`); - execSync(`postcss --replace --config src-docs/postcss.config.js "dist/eui_${baseFileName}.css"`); +const path = require('path'); +const util = require('util'); +const fs = require('fs'); +const globModule = require('glob'); + +const chalk = require('chalk'); +const postcss = require('postcss'); +const sassExtract = require('sass-extract'); + +const postcssConfiguration = require('../src-docs/postcss.config.js'); + +const writeFile = util.promisify(fs.writeFile); +const mkdir = util.promisify(fs.mkdir); +const glob = util.promisify(globModule); + +async function compileScssFiles(sourcePattern, destinationDirectory) { + try { + await mkdir(destinationDirectory); + } catch (err) { + if (err.code !== 'EEXIST') { + throw err; + } + } + + const inputFilenames = await glob(sourcePattern, undefined); + + await Promise.all( + inputFilenames.map(async inputFilename => { + console.log(chalk`{cyan …} Compiling {gray ${inputFilename}}`); + + try { + const { name } = path.parse(inputFilename); + const outputFilenames = await compileScssFile( + inputFilename, + path.join(destinationDirectory, `eui_${name}.css`), + path.join(destinationDirectory, `eui_${name}.json`) + ); + + console.log( + chalk`{green ✔} Finished compiling {gray ${inputFilename}} to ${outputFilenames + .map(filename => chalk.gray(filename)) + .join(', ')}` + ); + } catch (error) { + console.log(chalk`{red ✗} Failed to compile {gray ${inputFilename}} with ${error.stack}`); + } + }) + ); +} + +async function compileScssFile(inputFilename, outputCssFilename, outputVarsFilename) { + const { css: renderedCss, vars: extractedVars } = await sassExtract.render( + { + file: inputFilename, + outFile: outputCssFilename, + }, + { + plugins: [{ plugin: 'sass-extract-js' }], + } + ); + + const { css: postprocessedCss } = await postcss(postcssConfiguration).process(renderedCss, { + from: outputCssFilename, + to: outputCssFilename, }); -}); + + await Promise.all([ + writeFile(outputCssFilename, postprocessedCss), + writeFile(outputVarsFilename, JSON.stringify(extractedVars, undefined, 2)), + ]); + + return [outputCssFilename, outputVarsFilename]; +} + +compileScssFiles(path.join('src', 'theme_*.scss'), 'dist'); diff --git a/src/components/key_pad_menu/_index.scss b/src/components/key_pad_menu/_index.scss index 4e5eeabf111..fa4d726dbce 100644 --- a/src/components/key_pad_menu/_index.scss +++ b/src/components/key_pad_menu/_index.scss @@ -2,4 +2,4 @@ $euiKeyPadMenuSize: $euiSize * 6; -@import 'key_pad_menu' +@import 'key_pad_menu'; diff --git a/src/index.d.ts b/src/index.d.ts index 7acdb9091d4..4355a412ee7 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -1,2 +1,3 @@ /// /// +/// diff --git a/src/themes/index.d.ts b/src/themes/index.d.ts new file mode 100644 index 00000000000..dbebe469845 --- /dev/null +++ b/src/themes/index.d.ts @@ -0,0 +1,4 @@ +declare module "@elastic/eui/dist/eui_theme_*.json" { + const value: any; + export default value; +} diff --git a/wiki/consuming.md b/wiki/consuming.md index 85d40d51899..d5b2e9d7472 100644 --- a/wiki/consuming.md +++ b/wiki/consuming.md @@ -56,6 +56,28 @@ If you want access to the Sass variables, functions, and mixins in EUI then you' @import '../node_modules/@elastic/eui/src/theme_light.scss'; ``` +### Reusing the variables in JavaScript + +The Sass variables are also made available for consumption as json files. This enables reuse of values in css-in-js systems like [styled-components](https://www.styled-components.com). As the following example shows, it can also make the downstream components theme-aware without much extra effort: + +```js +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; +import styled, { ThemeProvider } from 'styled-components'; +import * as euiVars from '@elastic/eui/dist/eui_theme_k6_light.json'; + +const CustomComponent = styled.div` + color: ${props => props.theme.euiColorPrimary}; + border: ${props => props.theme.euiBorderThin}; +`; + +ReactDOM.render( + + content + +, document.querySelector('#renderTarget')); +``` + ### "Module build failed" or "Module parse failed: Unexpected token" error If you get an error when importing a React component, you might need to configure Webpack's `resolve.mainFields` to `['webpack', 'browser', 'main']` to import the components from `lib` intead of `src`. See the [Webpack docs](https://webpack.js.org/configuration/resolve/#resolve-mainfields) for more info. diff --git a/yarn.lock b/yarn.lock index c3befe13e15..375bc03be51 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1472,7 +1472,7 @@ callsites@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" -camel-case@3.0.x: +camel-case@3.0.x, camel-case@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" dependencies: @@ -1807,6 +1807,10 @@ color-convert@^1.3.0, color-convert@^1.9.0: dependencies: color-name "^1.1.1" +color-convert@~0.5.0: + version "0.5.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-0.5.3.tgz#bdb6c69ce660fadffe0b0007cc447e1b9f7282bd" + color-name@^1.0.0, color-name@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" @@ -3680,6 +3684,12 @@ globule@^1.0.0: lodash "~4.17.4" minimatch "~3.0.2" +gonzales-pe@^4.2.2: + version "4.2.3" + resolved "https://registry.yarnpkg.com/gonzales-pe/-/gonzales-pe-4.2.3.tgz#41091703625433285e0aee3aa47829fc1fbeb6f2" + dependencies: + minimist "1.1.x" + got@^5.0.0: version "5.7.1" resolved "https://registry.yarnpkg.com/got/-/got-5.7.1.tgz#5f81635a61e4a6589f180569ea4e381680a51f35" @@ -5693,6 +5703,10 @@ minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" +minimist@1.1.x: + version "1.1.3" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.1.3.tgz#3bedfd91a92d39016fcfaa1c681e8faa1a1efda8" + minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" @@ -6401,6 +6415,12 @@ parse-asn1@^5.0.0: evp_bytestokey "^1.0.0" pbkdf2 "^3.0.3" +parse-color@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/parse-color/-/parse-color-1.0.0.tgz#7b748b95a83f03f16a94f535e52d7f3d94658619" + dependencies: + color-convert "~0.5.0" + parse-glob@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" @@ -7778,6 +7798,21 @@ sane@^2.0.0: optionalDependencies: fsevents "^1.1.1" +sass-extract-js@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/sass-extract-js/-/sass-extract-js-0.3.0.tgz#3fc5be20d84ce55c29a8b089a49254fbfb69a2a3" + dependencies: + camel-case "^3.0.0" + +sass-extract@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/sass-extract/-/sass-extract-2.1.0.tgz#c65e6ca3103cbcf2fca0dcd81b07e4e49a6cc583" + dependencies: + bluebird "^3.4.7" + gonzales-pe "^4.2.2" + parse-color "^1.0.0" + query-ast "^1.0.1" + sass-graph@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49"