diff --git a/src-docs/src/views/app_context.js b/src-docs/src/views/app_context.js
index c414339d756..18f4416850f 100644
--- a/src-docs/src/views/app_context.js
+++ b/src-docs/src/views/app_context.js
@@ -17,11 +17,15 @@ import favicon16Dev from '../images/favicon/dev/favicon-16x16.png';
import favicon32Dev from '../images/favicon/dev/favicon-32x32.png';
import favicon96Dev from '../images/favicon/dev/favicon-96x96.png';
-const emotionCache = createCache({
- key: 'eui-docs',
+const generalEmotionCache = createCache({
+ key: 'css',
container: document.querySelector('meta[name="emotion-styles"]'),
});
-emotionCache.compat = true;
+generalEmotionCache.compat = true;
+const utilityCache = createCache({
+ key: 'util',
+ container: document.querySelector('meta[name="emotion-styles-utility"]'),
+});
export const AppContext = ({ children }) => {
const { theme } = useContext(ThemeContext);
@@ -41,7 +45,10 @@ export const AppContext = ({ children }) => {
return (
t.value === theme)?.provider}
colorMode={theme.includes('light') ? 'light' : 'dark'}
>
diff --git a/src-docs/src/views/provider/provider_example.js b/src-docs/src/views/provider/provider_example.js
index 3ac7aebd13a..c7c0e555d4a 100644
--- a/src-docs/src/views/provider/provider_example.js
+++ b/src-docs/src/views/provider/provider_example.js
@@ -95,12 +95,25 @@ export const ProviderExample = {
The @emotion/cache library
{' '}
provides configuration options that help with specifying the
- injection location. We recommend using a{' '}
- {''} tag to achieve this.
+ injection location. We recommend using {''}{' '}
+ tags to achieve this.
+
+ For most applications, the above configuration will be enough to
+ have styles ordered correctly. In advanced more cases, you may use
+ the default,global, and{' '}
+ utility properties on the{' '}
+ cache prop to further define where specific
+ styles should be inserted. See{' '}
+
+ the props documentation
+ {' '}
+ for details.
+
+
Any other options available with{' '}
{
My App
-
+
+
@@ -28,13 +29,15 @@ export default () => {
import { EuiProvider } from '@elastic/eui'
import createCache from '@emotion/cache';
-const cache = createCache({
- key: 'myApp',
- container: document.querySelector('meta[name="emotion-style-insert"]'),
+const euiCache = createCache({
+ key: 'eui',
+ container: document.querySelector('meta[name="eui-style-insert"]'),
});
cache.compat = true;
-
+
{/* Content */}
`}
diff --git a/src-docs/webpack.config.js b/src-docs/webpack.config.js
index 9d831994b92..16cab69d2b8 100644
--- a/src-docs/webpack.config.js
+++ b/src-docs/webpack.config.js
@@ -82,7 +82,10 @@ const webpackConfig = {
loaders: employCache([
{
loader: 'style-loader',
- options: { injectType: 'lazySingletonStyleTag' },
+ options: {
+ injectType: 'lazySingletonStyleTag',
+ insert: 'meta[name="sass-styles-compiled"]',
+ },
},
'css-loader',
'postcss-loader',
diff --git a/src/components/provider/__snapshots__/provider.test.tsx.snap b/src/components/provider/__snapshots__/provider.test.tsx.snap
index 41d40612911..dc576bb68b3 100644
--- a/src/components/provider/__snapshots__/provider.test.tsx.snap
+++ b/src/components/provider/__snapshots__/provider.test.tsx.snap
@@ -1,1301 +1,2413 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`EuiProvider applying modifications propagates \`modify\` 1`] = `
-
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`EuiProvider changing color modes propagates \`colorMode\` 1`] = `
+
+
-
-
-`;
-
-exports[`EuiProvider changing color modes propagates \`colorMode\` 1`] = `
-
+
+
+
+
+
+
+
+
+`;
+
+exports[`EuiProvider is rendered 1`] = `
+
+
-
-
+ >
+
+
+
+
+
+
+
+
`;
-exports[`EuiProvider is rendered 1`] = `
-,
+ "ctr": 0,
+ "insertionPoint": undefined,
+ "isSpeedy": false,
+ "key": "default",
+ "nonce": undefined,
+ "prepend": undefined,
+ "tags": Array [],
},
- "base": 16,
- "border": Object {
- "color": Computed {
- "computer": [Function],
- "dependencies": Array [
- "colors.lightShade",
- ],
- },
- "editable": Computed {
- "computer": [Function],
- "dependencies": Array [
- "border.width",
- "border.color",
- ],
- },
- "radius": Object {
- "medium": Computed {
+ }
+ }
+>
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`EuiProvider providing an @emotion cache config applies the cache to each location separately 1`] = `
+,
+ "ctr": 0,
+ "insertionPoint": undefined,
+ "isSpeedy": false,
+ "key": "default",
+ "nonce": undefined,
+ "prepend": undefined,
+ "tags": Array [],
+ },
+ }
+ }
+>
+
-
-
+ >
+ ,
+ "ctr": 0,
+ "insertionPoint": undefined,
+ "isSpeedy": false,
+ "key": "global",
+ "nonce": undefined,
+ "prepend": undefined,
+ "tags": Array [],
+ },
+ }
+ }
+ >
+
+
+ ,
+ "ctr": 0,
+ "insertionPoint": undefined,
+ "isSpeedy": false,
+ "key": "utility",
+ "nonce": undefined,
+ "prepend": undefined,
+ "tags": Array [],
+ },
+ }
+ }
+ >
+
+
+
+
`;
exports[`EuiProvider providing an @emotion cache config applies the cache to global styles 1`] = `
-,
- "ctr": 0,
- "insertionPoint": undefined,
- "isSpeedy": false,
- "key": "testing",
- "nonce": undefined,
- "prepend": undefined,
- "tags": Array [],
- },
- }
- }
- theme={
- Object {
- "animation": Object {
- "bounce": "cubic-bezier(.34, 1.61, .7, 1)",
- "extraFast": "90ms",
- "extraSlow": "500ms",
- "fast": "150ms",
- "normal": "250ms",
- "resistance": "cubic-bezier(.694, .0482, .335, 1)",
- "slow": "350ms",
- },
- "base": 16,
- "border": Object {
- "color": Computed {
- "computer": [Function],
- "dependencies": Array [
- "colors.lightShade",
- ],
- },
- "editable": Computed {
- "computer": [Function],
- "dependencies": Array [
- "border.width",
- "border.color",
- ],
- },
- "radius": Object {
- "medium": Computed {
+
+
+ ,
+ "ctr": 0,
+ "insertionPoint": undefined,
+ "isSpeedy": false,
+ "key": "global",
+ "nonce": undefined,
+ "prepend": undefined,
+ "tags": Array [],
+ },
+ }
+ }
+ >
+
+
+
+
+
+
+
+`;
+
+exports[`EuiProvider providing an @emotion cache config applies the cache to utility styles 1`] = `
+
+
-
-
+ >
+
+
+
+ ,
+ "ctr": 0,
+ "insertionPoint": undefined,
+ "isSpeedy": false,
+ "key": "utility",
+ "nonce": undefined,
+ "prepend": undefined,
+ "tags": Array [],
+ },
+ }
+ }
+ >
+
+
+
+
`;
-exports[`EuiProvider using \`null\` theme option does not add global styles 1`] = ``;
+exports[`EuiProvider using \`null\` theme option does not add global styles 1`] = `
+
+
+
+`;
diff --git a/src/components/provider/cache/__snapshots__/cache_provider.test.tsx.snap b/src/components/provider/cache/__snapshots__/cache_provider.test.tsx.snap
new file mode 100644
index 00000000000..ced846ba2e7
--- /dev/null
+++ b/src/components/provider/cache/__snapshots__/cache_provider.test.tsx.snap
@@ -0,0 +1,37 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`EuiProvider adds CacheProvider from Emotion when configured with a cache 1`] = `
+,
+ "ctr": 0,
+ "insertionPoint": undefined,
+ "isSpeedy": false,
+ "key": "testing",
+ "nonce": undefined,
+ "prepend": undefined,
+ "tags": Array [],
+ },
+ }
+ }
+>
+
+
+`;
+
+exports[`EuiProvider does not add CacheProvider from Emotion when configured without a cache 1`] = `
+
+
+
+`;
+
+exports[`EuiProvider renders a Fragment when no children are provided 1`] = ``;
diff --git a/src/components/provider/cache/cache_provider.test.tsx b/src/components/provider/cache/cache_provider.test.tsx
new file mode 100644
index 00000000000..d1fa6729211
--- /dev/null
+++ b/src/components/provider/cache/cache_provider.test.tsx
@@ -0,0 +1,44 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import React from 'react';
+import { shallow } from 'enzyme';
+import createCache from '@emotion/cache';
+
+import { EuiCacheProvider } from './cache_provider';
+
+describe('EuiProvider', () => {
+ const cache = createCache({
+ key: 'testing',
+ });
+ it('adds CacheProvider from Emotion when configured with a cache', () => {
+ const component = shallow(
+
+
+
+ );
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('does not add CacheProvider from Emotion when configured without a cache', () => {
+ const component = shallow(
+
+
+
+ );
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('renders a Fragment when no children are provided', () => {
+ const component = shallow();
+
+ expect(component).toMatchSnapshot();
+ });
+});
diff --git a/src/components/provider/cache/cache_provider.tsx b/src/components/provider/cache/cache_provider.tsx
new file mode 100644
index 00000000000..7c0bd618ce8
--- /dev/null
+++ b/src/components/provider/cache/cache_provider.tsx
@@ -0,0 +1,26 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import React, { PropsWithChildren } from 'react';
+import { EmotionCache } from '@emotion/cache';
+import { CacheProvider } from '@emotion/react';
+
+export interface EuiCacheProviderProps {
+ cache?: false | EmotionCache;
+}
+
+export const EuiCacheProvider = ({
+ cache,
+ children,
+}: PropsWithChildren) => {
+ return children && cache ? (
+ {children}
+ ) : (
+ <>{children}>
+ );
+};
diff --git a/src/components/provider/cache/index.ts b/src/components/provider/cache/index.ts
new file mode 100644
index 00000000000..ce66007af02
--- /dev/null
+++ b/src/components/provider/cache/index.ts
@@ -0,0 +1,9 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+export * from './cache_provider';
diff --git a/src/components/provider/provider.test.tsx b/src/components/provider/provider.test.tsx
index f908e9d59eb..edcafcc5b39 100644
--- a/src/components/provider/provider.test.tsx
+++ b/src/components/provider/provider.test.tsx
@@ -28,11 +28,47 @@ describe('EuiProvider', () => {
});
describe('providing an @emotion cache config', () => {
- const emotionCache = createCache({
- key: 'testing',
+ const defaultCache = createCache({
+ key: 'default',
});
+ const globalCache = createCache({
+ key: 'global',
+ });
+ const utilityCache = createCache({
+ key: 'utility',
+ });
+ it('applies the cache to all styles', () => {
+ const component = shallow();
+
+ expect(component).toMatchSnapshot();
+ });
+
it('applies the cache to global styles', () => {
- const component = shallow();
+ const component = shallow(
+
+ );
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('applies the cache to utility styles', () => {
+ const component = shallow(
+
+ );
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('applies the cache to each location separately', () => {
+ const component = shallow(
+
+ );
expect(component).toMatchSnapshot();
});
diff --git a/src/components/provider/provider.tsx b/src/components/provider/provider.tsx
index feba9435be9..748da28aba0 100644
--- a/src/components/provider/provider.tsx
+++ b/src/components/provider/provider.tsx
@@ -13,12 +13,18 @@ import {
EuiGlobalStyles,
EuiGlobalStylesProps,
} from '../../global_styling/reset/global_styles';
+import { EuiUtilityClasses } from '../../global_styling/utility/utility';
import {
EuiThemeProvider,
EuiThemeProviderProps,
EuiThemeSystem,
} from '../../services';
import { EuiThemeAmsterdam } from '../../themes';
+import { EuiCacheProvider } from './cache';
+
+const isEmotionCacheObject = (
+ obj: EmotionCache | Object
+): obj is EmotionCache => obj.hasOwnProperty('key');
export interface EuiProviderProps
extends Omit, 'children' | 'theme'>,
@@ -34,26 +40,70 @@ export interface EuiProviderProps
*/
globalStyles?: false | ((params: any) => JSX.Element | null);
/**
- * Provide a cache configuration from `@emotion/cache`
+ * Provide utility classes.
+ * Pass `false` to remove the default EUI utility classes.
+ */
+ utilityClasses?: false | ((params: any) => JSX.Element | null);
+ /**
+ * Provide a cache configuration(s) from `@emotion/cache`.
+ *
+ * - `default` will encompass all Emotion styles, including consumer defined appliction styles, not handled by nested cache instances.
+ * - `global` will scope all EUI global and reset styles.
+ * - `utility` will scope all EUI utility class styles.
+ *
+ * A cache instance provided as the sole value will function the same as the `default` cache.
*/
- cache?: EmotionCache;
+ cache?:
+ | EmotionCache
+ | {
+ default?: EmotionCache;
+ global?: EmotionCache;
+ utility?: EmotionCache;
+ };
}
export const EuiProvider = ({
cache,
theme = EuiThemeAmsterdam,
- globalStyles: GlobalStyles = EuiGlobalStyles,
+ globalStyles: Globals = EuiGlobalStyles,
+ utilityClasses: Utilities = EuiUtilityClasses,
colorMode,
modify,
children,
-}: PropsWithChildren>) => (
-
- {theme !== null && GlobalStyles !== false ? : null}
- {children}
-
-);
+}: PropsWithChildren>) => {
+ let defaultCache;
+ let globalCache;
+ let utilityCache;
+ if (cache) {
+ if (isEmotionCacheObject(cache)) {
+ defaultCache = cache;
+ } else {
+ defaultCache = cache.default;
+ globalCache = cache.global;
+ utilityCache = cache.utility;
+ }
+ }
+ return (
+
+
+ {theme && (
+ <>
+ }
+ />
+ }
+ />
+ >
+ )}
+ {children}
+
+
+ );
+};
diff --git a/src/global_styling/utility/utility.tsx b/src/global_styling/utility/utility.tsx
new file mode 100644
index 00000000000..9c590485f66
--- /dev/null
+++ b/src/global_styling/utility/utility.tsx
@@ -0,0 +1,12 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import React from 'react';
+import { Global, css } from '@emotion/react';
+
+export const EuiUtilityClasses = () => ;
diff --git a/src/services/theme/hooks.tsx b/src/services/theme/hooks.tsx
index 4873ae612ae..b34e80c49b5 100644
--- a/src/services/theme/hooks.tsx
+++ b/src/services/theme/hooks.tsx
@@ -43,7 +43,8 @@ export interface WithEuiThemeProps