- Custom tokens
By default, an iconType with the token prefix
(i.e. those listed above) will have predefined styles. However,
diff --git a/src-docs/src/views/icon/tokens.js b/src-docs/src/views/icon/tokens.tsx
similarity index 94%
rename from src-docs/src/views/icon/tokens.js
rename to src-docs/src/views/icon/tokens.tsx
index 184c5c3a626..039c4cfa261 100644
--- a/src-docs/src/views/icon/tokens.js
+++ b/src-docs/src/views/icon/tokens.tsx
@@ -10,7 +10,9 @@ import {
EuiSpacer,
} from '../../../../src/components';
-const tokens = [
+import type { EuiTokenMapType } from '../../../../src/components/token/token_map';
+
+const tokens: EuiTokenMapType[] = [
'tokenAlias',
'tokenAnnotation',
'tokenArray',
diff --git a/src-docs/src/views/theme/_json/eui_theme_dark.json b/src-docs/src/views/theme/_json/eui_theme_dark.json
index 978804edb50..b62e2064b34 100644
--- a/src-docs/src/views/theme/_json/eui_theme_dark.json
+++ b/src-docs/src/views/theme/_json/eui_theme_dark.json
@@ -249,54 +249,6 @@
"warning": "#f3d371",
"danger": "#f86b63"
},
- "euiTokenGrayColor": "#535966",
- "euiTokenTypes": {
- "euiColorVis0": {
- "graphic": "#54b399",
- "behindText": "#6dccb1"
- },
- "euiColorVis1": {
- "graphic": "#6092c0",
- "behindText": "#79aad9"
- },
- "euiColorVis2": {
- "graphic": "#d36086",
- "behindText": "#ee789d"
- },
- "euiColorVis3": {
- "graphic": "#9170b8",
- "behindText": "#a987d1"
- },
- "euiColorVis4": {
- "graphic": "#ca8eae",
- "behindText": "#e4a6c7"
- },
- "euiColorVis5": {
- "graphic": "#d6bf57",
- "behindText": "#f1d86f"
- },
- "euiColorVis6": {
- "graphic": "#b9a888",
- "behindText": "#d2c0a0"
- },
- "euiColorVis7": {
- "graphic": "#da8b45",
- "behindText": "#f5a35c"
- },
- "euiColorVis8": {
- "graphic": "#aa6556",
- "behindText": "#c47c6c"
- },
- "euiColorVis9": {
- "graphic": "#e7664c",
- "behindText": "#ff7e62"
- },
- "gray": {
- "graphic": "#535966",
- "behindText": "#535966"
- }
- },
- "euiTokenTypeKeys": "'euiColorVis0', 'euiColorVis1', 'euiColorVis2', 'euiColorVis3', 'euiColorVis4', 'euiColorVis5', 'euiColorVis6', 'euiColorVis7', 'euiColorVis8', 'euiColorVis9', 'gray'",
"euiPopoverArrowSize": "12px",
"euiContrastRatioText": 4.5,
"euiContrastRatioGraphic": 3,
diff --git a/src-docs/src/views/theme/_json/eui_theme_light.json b/src-docs/src/views/theme/_json/eui_theme_light.json
index acaa0f3983a..609edb604a6 100644
--- a/src-docs/src/views/theme/_json/eui_theme_light.json
+++ b/src-docs/src/views/theme/_json/eui_theme_light.json
@@ -249,54 +249,6 @@
"warning": "#fec514",
"danger": "#bd271e"
},
- "euiTokenGrayColor": "#69707d",
- "euiTokenTypes": {
- "euiColorVis0": {
- "graphic": "#54b399",
- "behindText": "#6dccb1"
- },
- "euiColorVis1": {
- "graphic": "#6092c0",
- "behindText": "#79aad9"
- },
- "euiColorVis2": {
- "graphic": "#d36086",
- "behindText": "#ee789d"
- },
- "euiColorVis3": {
- "graphic": "#9170b8",
- "behindText": "#a987d1"
- },
- "euiColorVis4": {
- "graphic": "#ca8eae",
- "behindText": "#e4a6c7"
- },
- "euiColorVis5": {
- "graphic": "#d6bf57",
- "behindText": "#f1d86f"
- },
- "euiColorVis6": {
- "graphic": "#b9a888",
- "behindText": "#d2c0a0"
- },
- "euiColorVis7": {
- "graphic": "#da8b45",
- "behindText": "#f5a35c"
- },
- "euiColorVis8": {
- "graphic": "#aa6556",
- "behindText": "#c47c6c"
- },
- "euiColorVis9": {
- "graphic": "#e7664c",
- "behindText": "#ff7e62"
- },
- "gray": {
- "graphic": "#69707d",
- "behindText": "#69707d"
- }
- },
- "euiTokenTypeKeys": "'euiColorVis0', 'euiColorVis1', 'euiColorVis2', 'euiColorVis3', 'euiColorVis4', 'euiColorVis5', 'euiColorVis6', 'euiColorVis7', 'euiColorVis8', 'euiColorVis9', 'gray'",
"euiPopoverArrowSize": "12px",
"euiContrastRatioText": 4.5,
"euiContrastRatioGraphic": 3,
diff --git a/src/components/datagrid/controls/__snapshots__/column_sorting.test.tsx.snap b/src/components/datagrid/controls/__snapshots__/column_sorting.test.tsx.snap
index 28edd0fec5f..cd88127432b 100644
--- a/src/components/datagrid/controls/__snapshots__/column_sorting.test.tsx.snap
+++ b/src/components/datagrid/controls/__snapshots__/column_sorting.test.tsx.snap
@@ -111,7 +111,7 @@ exports[`useDataGridColumnSorting columnSorting renders a toolbar button/popover
class="euiFlexItem euiFlexItem--flexGrowZero"
>
diff --git a/src/components/icon/assets/tokenStruct.tsx b/src/components/icon/assets/tokenStruct.tsx
index 24e3070f5e3..1e13ab1672b 100644
--- a/src/components/icon/assets/tokenStruct.tsx
+++ b/src/components/icon/assets/tokenStruct.tsx
@@ -30,7 +30,7 @@ const EuiIconTokenStruct = ({
{title ? {title} : null}
);
diff --git a/src/components/icon/svgs/tokens/tokenStruct.svg b/src/components/icon/svgs/tokens/tokenStruct.svg
index 3eae7a65f6f..93265ccfaf9 100644
--- a/src/components/icon/svgs/tokens/tokenStruct.svg
+++ b/src/components/icon/svgs/tokens/tokenStruct.svg
@@ -1,3 +1,3 @@
diff --git a/src/components/index.scss b/src/components/index.scss
index 845b1ae6a3f..f4bb1d5ce59 100644
--- a/src/components/index.scss
+++ b/src/components/index.scss
@@ -39,6 +39,5 @@
@import 'suggest/index';
@import 'table/index';
@import 'tabs/index';
-@import 'token/index';
@import 'tool_tip/index';
@import 'tour/index';
diff --git a/src/components/token/__snapshots__/token.test.tsx.snap b/src/components/token/__snapshots__/token.test.tsx.snap
index 50627a08a4e..5d9500135b0 100644
--- a/src/components/token/__snapshots__/token.test.tsx.snap
+++ b/src/components/token/__snapshots__/token.test.tsx.snap
@@ -2,7 +2,7 @@
exports[`EuiToken is rendered 1`] = `
{
+ const isVizColor = typeof color === 'number';
+
+ const iconColor = isVizColor ? visColors[color] : euiTheme.colors.darkShade;
+
+ const isDarkMode = colorMode === 'DARK';
+
+ const backgroundDarkColor = isVizColor
+ ? visColorsBehindText[color]
+ : euiTheme.colors.darkShade;
+
+ const backgroundLightColor = isDarkMode
+ ? shade(iconColor, 0.7)
+ : tint(iconColor, 0.9);
+
+ const lightColor = makeHighContrastColor(iconColor)(backgroundLightColor);
+
+ const boxShadowColor = isDarkMode
+ ? shade(iconColor, 0.6)
+ : tint(iconColor, 0.7);
+
+ const darkColor = isColorDark(...chroma(backgroundDarkColor).rgb())
+ ? euiTheme.colors.ghost
+ : euiTheme.colors.ink;
+
+ switch (fill) {
+ case 'none':
+ return `
+ // Without a background, the fill color should be the graphic color
+ color: ${iconColor};
+ `;
+ case 'light':
+ return `
+ color: ${lightColor};
+ background-color: ${backgroundLightColor};
+ box-shadow: inset 0 0 0 1px ${boxShadowColor};
+ `;
+ case 'dark':
+ return `
+ color: ${darkColor};
+ background-color: ${backgroundDarkColor};
+ `;
+ }
+};
+
+export const euiTokenStyles = (
+ { euiTheme, colorMode }: UseEuiTheme,
+ fill: TokenFill
+) => ({
+ // Base
+ euiToken: css`
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+
+ svg {
+ ${logicalCSS('height', '100%')}
+ margin: auto;
+ }
+ `,
+ // Shapes
+ circle: css`
+ border-radius: 50%;
+ `,
+ square: css`
+ border-radius: ${euiTheme.border.radius.small};
+ `,
+ rectangle: css`
+ box-sizing: content-box;
+ border-radius: ${euiTheme.border.radius.small};
+ `,
+ // Sizes
+ xs: css`
+ ${logicalSizeCSS(euiTheme.size.s, euiTheme.size.s)};
+
+ &[class*='-square'] {
+ border-radius: calc(${euiTheme.border.radius.small} / 2);
+ }
+
+ &[class*='-rectangle'] {
+ ${logicalCSS(
+ 'padding-vertical',
+ '1px'
+ )}; // adds a small padding so that the icon is not touching the border
+ ${logicalCSS('padding-horizontal', euiTheme.size.xs)};
+ border-radius: calc(${euiTheme.border.radius.small} / 2);
+ }
+ `,
+ s: css`
+ ${logicalSizeCSS(euiTheme.size.base, euiTheme.size.base)};
+
+ &[class*='-rectangle'] {
+ ${logicalCSS('padding-horizontal', euiTheme.size.xs)};
+ }
+ `,
+ m: css`
+ ${logicalSizeCSS(euiTheme.size.l, euiTheme.size.l)};
+
+ &[class*='-rectangle'] {
+ ${logicalCSS('padding-horizontal', euiTheme.size.s)};
+ }
+ `,
+ l: css`
+ ${logicalSizeCSS(euiTheme.size.xl, euiTheme.size.xl)};
+
+ &[class*='-rectangle'] {
+ ${logicalCSS('padding-horizontal', euiTheme.size.s)};
+ }
+ `,
+ // Colors
+ euiColorVis0: css(getTokenColor(euiTheme, colorMode, fill, 0)),
+ euiColorVis1: css(getTokenColor(euiTheme, colorMode, fill, 1)),
+ euiColorVis2: css(getTokenColor(euiTheme, colorMode, fill, 2)),
+ euiColorVis3: css(getTokenColor(euiTheme, colorMode, fill, 3)),
+ euiColorVis4: css(getTokenColor(euiTheme, colorMode, fill, 4)),
+ euiColorVis5: css(getTokenColor(euiTheme, colorMode, fill, 5)),
+ euiColorVis6: css(getTokenColor(euiTheme, colorMode, fill, 6)),
+ euiColorVis7: css(getTokenColor(euiTheme, colorMode, fill, 7)),
+ euiColorVis8: css(getTokenColor(euiTheme, colorMode, fill, 8)),
+ euiColorVis9: css(getTokenColor(euiTheme, colorMode, fill, 9)),
+ gray: css(getTokenColor(euiTheme, colorMode, fill, 'gray')),
+ customColor: css``,
+ // Fills
+ light: css``,
+ dark: css``,
+ none: css``,
+});
diff --git a/src/components/token/token.test.tsx b/src/components/token/token.test.tsx
index 4c44c912cf5..7d117991f05 100644
--- a/src/components/token/token.test.tsx
+++ b/src/components/token/token.test.tsx
@@ -9,8 +9,10 @@
import React from 'react';
import { render } from 'enzyme';
import { requiredProps } from '../../test';
+import { shouldRenderCustomStyles } from '../../test/internal';
-import { EuiToken, COLORS, SHAPES, SIZES, FILLS } from './token';
+import { EuiToken } from './token';
+import { COLORS, SHAPES, SIZES, FILLS } from './token_types';
import { TOKEN_MAP } from './token_map';
import { keysOf } from '../common';
@@ -18,6 +20,8 @@ const tokenTypes = keysOf(TOKEN_MAP);
const tokenColors = COLORS;
describe('EuiToken', () => {
+ shouldRenderCustomStyles();
+
test('is rendered', () => {
const component = render();
diff --git a/src/components/token/token.tsx b/src/components/token/token.tsx
index e4a2ddbbbe5..95ce82eba31 100644
--- a/src/components/token/token.tsx
+++ b/src/components/token/token.tsx
@@ -6,109 +6,24 @@
* Side Public License, v 1.
*/
-import React, { FunctionComponent, HTMLAttributes } from 'react';
-import defaults from 'lodash/defaults';
+import React, { FunctionComponent } from 'react';
import classNames from 'classnames';
-import { CommonProps, keysOf } from '../common';
-import { isColorDark, hexToRgb } from '../../services';
+import { useEuiTheme, isColorDark, hexToRgb } from '../../services';
-import { IconType, EuiIcon, IconSize } from '../icon';
+import { EuiIcon, IconSize } from '../icon';
import { EuiTokenMapType, TOKEN_MAP } from './token_map';
-
-type TokenSize = 'xs' | 's' | 'm' | 'l';
-type TokenShape = 'circle' | 'square' | 'rectangle';
-type TokenFill = 'dark' | 'light' | 'none';
-type TokenColor =
- | 'euiColorVis0'
- | 'euiColorVis1'
- | 'euiColorVis2'
- | 'euiColorVis3'
- | 'euiColorVis4'
- | 'euiColorVis5'
- | 'euiColorVis6'
- | 'euiColorVis7'
- | 'euiColorVis8'
- | 'euiColorVis9'
- | 'gray';
-
-const sizeToClassMap: { [size in TokenSize]: string } = {
- xs: 'euiToken--xsmall',
- s: 'euiToken--small',
- m: 'euiToken--medium',
- l: 'euiToken--large',
-};
-
-export const SIZES = keysOf(sizeToClassMap);
-
-const shapeToClassMap: { [shape in TokenShape]: string } = {
- circle: 'euiToken--circle',
- square: 'euiToken--square',
- rectangle: 'euiToken--rectangle',
-};
-
-export const SHAPES = keysOf(shapeToClassMap);
-
-const fillToClassMap: { [fill in TokenFill]: string | null } = {
- none: null,
- light: 'euiToken--light',
- dark: 'euiToken--dark',
-};
-
-export const FILLS = keysOf(fillToClassMap);
-
-const colorToClassMap: { [color in TokenColor]: string } = {
- euiColorVis0: 'euiToken--euiColorVis0',
- euiColorVis1: 'euiToken--euiColorVis1',
- euiColorVis2: 'euiToken--euiColorVis2',
- euiColorVis3: 'euiToken--euiColorVis3',
- euiColorVis4: 'euiToken--euiColorVis4',
- euiColorVis5: 'euiToken--euiColorVis5',
- euiColorVis6: 'euiToken--euiColorVis6',
- euiColorVis7: 'euiToken--euiColorVis7',
- euiColorVis8: 'euiToken--euiColorVis8',
- euiColorVis9: 'euiToken--euiColorVis9',
- gray: 'euiToken--gray',
-};
-
-export const COLORS = keysOf(colorToClassMap);
-
-export interface TokenProps {
- /**
- * An EUI icon type
- */
- iconType: IconType;
- /**
- * For best results use one of the vis color names (or 'gray').
- * Or supply your own color (can be used with dark or no fill only).
- * Default: `gray`
- */
- color?: TokenColor | string;
- /**
- * Outer shape surrounding the icon
- * Default: `circle`
- */
- shape?: TokenShape;
- /**
- * `light` for lightened color with border, `dark` for solid, or `none`
- * Default: `light`
- */
- fill?: TokenFill;
- /**
- * Size of the token
- */
- size?: TokenSize;
- /**
- * The icon's title. Required for accessibility
- */
- title?: string;
- 'aria-label'?: string;
- 'aria-labelledby'?: string;
- 'aria-describedby'?: string;
-}
-
-export type EuiTokenProps = CommonProps &
- TokenProps &
- Omit, 'title'>;
+import { COLORS } from './token_types';
+import type {
+ EuiTokenProps,
+ TokenColor,
+ TokenSize,
+ TokenShape,
+ TokenFill,
+} from './token_types';
+import { euiTokenStyles } from './token.styles';
+
+const isTokenColor = (color: string): color is TokenColor =>
+ COLORS.includes(color as TokenColor);
export const EuiToken: FunctionComponent = ({
iconType,
@@ -138,58 +53,58 @@ export const EuiToken: FunctionComponent = ({
finalSize = 'm';
}
- const currentDisplay = {
- color,
- fill,
- shape,
- };
- let finalDisplay;
-
// If the iconType passed is one of the prefab token types,
// grab its properties
- if (typeof iconType === 'string' && iconType in TOKEN_MAP) {
- const tokenDisplay = TOKEN_MAP[iconType as EuiTokenMapType];
- finalDisplay = defaults(currentDisplay, tokenDisplay);
+ const tokenDefaults =
+ typeof iconType === 'string' && iconType in TOKEN_MAP
+ ? TOKEN_MAP[iconType as EuiTokenMapType]
+ : {};
+
+ const finalColor = color || tokenDefaults.color || 'gray';
+ const finalShape = shape || tokenDefaults.shape || 'circle';
+ let finalFill = fill || 'light';
+
+ const euiTheme = useEuiTheme();
+ const styles = euiTokenStyles(euiTheme, finalFill);
+
+ let cssStyles = [
+ styles.euiToken,
+ styles[finalShape as TokenShape],
+ styles[finalFill as TokenFill],
+ styles[size as TokenSize],
+ ];
+
+ let finalStyle = style;
+
+ if (isTokenColor(finalColor)) {
+ cssStyles = [...cssStyles, styles[finalColor as TokenColor]];
+ } else if (finalFill === 'none') {
+ // When a custom HEX color is passed and the token doesn't have any fill (no background),
+ // the icon gets that passed color
+ cssStyles = [...cssStyles, styles.customColor];
+ finalStyle = { color: finalColor, ...style };
} else {
- finalDisplay = currentDisplay;
+ // When a custom HEX color is passed and the token has a fill (light or dark),
+ // the background gets the custom color and the icon gets white or black based on the passed color
+ // The fill='light' (lightened background) will always be overridden by fill='dark' (opaque background)
+ // to better handle custom colors
+ const isFinalColorDark = isColorDark(...hexToRgb(finalColor));
+ const lightOrDarkColor = isFinalColorDark ? '#FFFFFF' : '#000000';
+
+ cssStyles = [...cssStyles, styles.customColor];
+
+ finalFill = 'dark';
+ finalStyle = {
+ color: lightOrDarkColor,
+ backgroundColor: finalColor,
+ ...style,
+ };
}
- const finalColor = finalDisplay.color || 'gray';
- const finalShape = finalDisplay.shape || 'circle';
- let finalFill = finalDisplay.fill || 'light';
-
- // Color can be a named space via euiColorVis
- let colorClass;
- if (finalColor in colorToClassMap) {
- colorClass = colorToClassMap[finalColor as TokenColor];
- }
- // Or it can be a string which adds inline styles for the
- else {
- // text color if fill='none' or
- if (finalFill === 'none') {
- style.color = finalColor;
- }
- // full background color if fill='dark' and overrides fill='light' with dark
- else {
- finalFill = 'dark';
- style.backgroundColor = finalColor;
- style.color = isColorDark(...hexToRgb(finalColor))
- ? '#FFFFFF'
- : '#000000';
- }
- }
-
- const classes = classNames(
- 'euiToken',
- colorClass,
- shapeToClassMap[finalShape],
- fillToClassMap[finalFill],
- sizeToClassMap[size],
- className
- );
+ const classes = classNames('euiToken', className);
return (
-
+
, 'title'>;
diff --git a/src/themes/amsterdam/overrides/_index.scss b/src/themes/amsterdam/overrides/_index.scss
index 134807ca3c5..37642e4d7db 100644
--- a/src/themes/amsterdam/overrides/_index.scss
+++ b/src/themes/amsterdam/overrides/_index.scss
@@ -33,5 +33,4 @@
@import 'side_nav';
@import 'steps';
@import 'tabs';
-@import 'token';
@import 'tooltip';
diff --git a/src/themes/amsterdam/overrides/_token.scss b/src/themes/amsterdam/overrides/_token.scss
deleted file mode 100644
index 7302be7663c..00000000000
--- a/src/themes/amsterdam/overrides/_token.scss
+++ /dev/null
@@ -1,4 +0,0 @@
-.euiToken--square {
- // Same border radius as the legacy theme
- border-radius: $euiBorderRadiusSmall - 1px;
-}
diff --git a/upcoming_changelogs/6067.md b/upcoming_changelogs/6067.md
new file mode 100644
index 00000000000..8f2ed2f53a1
--- /dev/null
+++ b/upcoming_changelogs/6067.md
@@ -0,0 +1,5 @@
+- Updated `tokenFile`, `tokenSymbol` and `tokenRepo` default shapes to `square` instead of `rectangle`
+
+**CSS-in-JS conversions**
+
+- Converted `EuiToken` to Emotion