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"