[SharedUX] SCSS migration of kibana_react plugin (#216450)

## Summary

This PR is a part of SCSS migration of SharedUX team code.
Here is a [meta](https://github.com/elastic/kibana-team/issues/1417)
issue for it.
This commit is contained in:
Paulina Shakirova 2025-04-07 17:06:16 +02:00 committed by GitHub
parent bb748eea70
commit bc415d6d48
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 334 additions and 351 deletions

View file

@ -1,328 +0,0 @@
// Default styles for Markdown element
//
// 1. Links
// 2. Headings
// 3. Images
// 4. Blockquotes
// 5. Horizontal rules
// 6. Lists
// 7. Tables
// 8. Code blocks
// Functions
// Note: The inlined base font size is set in common/functions/font.js. It should match $kbnMdFontSize.
$kbnDefaultFontSize: 14px;
@function canvasToEm($size) {
@return #{calc($size / $kbnDefaultFontSize)}em;
}
.kbnMarkdown__body {
// Font size variables
$kbnMarkdownFontSizeS: canvasToEm(12px);
$kbnMarkdownFontSize: canvasToEm(14px);
$kbnMarkdownFontSizeL: canvasToEm(20px);
$kbnMarkdownFontSizeXL: canvasToEm(28px);
$kbnMarkdownFontSizeXXL: canvasToEm(36px);
// Spacing variables
$kbnMarkdownSizeL: canvasToEm(24px);
$kbnMarkdownSize: canvasToEm(16px);
$kbnMarkdownSizeS: canvasToEm(12px);
$kbnMarkdownSizeXS: canvasToEm(8px);
$kbnMarkdownSizeXXS: canvasToEm(4px);
// Grayscale variables
$kbnMarkdownAlphaLightestShade: rgba($euiColorFullShade, .05);
$kbnMarkdownAlphaLightShade: rgba($euiColorFullShade, .15);
$kbnMarkdownAlphaDarkShade: rgba($euiColorFullShade, .65);
// Reverse grayscale for opposite of theme
$kbnMarkdownAlphaLightestShadeReversed: rgba($euiColorEmptyShade, .05);
$kbnMarkdownAlphaLightShadeReversed: rgba($euiColorEmptyShade, .15);
$kbnMarkdownAlphaDarkShadeReversed: rgba($euiColorEmptyShade, .65);
&--reversed {
color: $euiColorLightestShade;
}
> *:first-child {
margin-top: 0 !important;
}
> *:last-child {
margin-bottom: 0 !important;
}
p,
blockquote,
ul,
ol,
dl,
table,
pre {
margin-top: 0;
margin-bottom: $kbnMarkdownSize;
line-height: 1.5em;
}
strong {
font-weight: 600;
}
// 1. Links
a {
color: inherit;
text-decoration: underline;
}
a:hover {
text-decoration: underline dotted;
}
a:active,
a:hover {
outline-width: 0;
}
a:not([href]) {
color: inherit;
text-decoration: none;
}
// 2. Headings
h1,
h2,
h3,
h4,
h5,
h6 {
margin-top: 0;
margin-bottom: $kbnMarkdownSizeXS;
}
h1 {
font-size: $kbnMarkdownFontSizeXXL;
line-height: 1.333333em;
font-weight: 300;
}
h2 {
font-size: $kbnMarkdownFontSizeXL;
line-height: 1.428571em;
font-weight: 300;
}
h3 {
font-size: $kbnMarkdownFontSizeL;
line-height: 1.6em;
font-weight: 600;
}
h4 {
font-size: $kbnMarkdownSize;
line-height: 1.5em;
font-weight: 600;
}
h5 {
font-size: $kbnMarkdownFontSize;
line-height: 1.142857em;
font-weight: 700;
}
h6 {
font-size: $kbnMarkdownFontSizeS;
line-height: 1.333333em;
font-weight: 700;
text-transform: uppercase;
}
// 3. Images
img {
max-width: 100%;
box-sizing: content-box;
border-style: none;
pointer-events: auto;
}
// 4. Blockquotes
blockquote {
padding: 0 1em;
border-left: $kbnMarkdownSizeXXS solid $kbnMarkdownAlphaLightShade;
}
&--reversed blockquote {
border-left-color: $kbnMarkdownAlphaLightShadeReversed;
}
// 5. Horizontal rules
hr {
overflow: hidden;
background: transparent;
height: 2px;
padding: 0;
margin: $kbnMarkdownSizeL 0;
background-color: $kbnMarkdownAlphaLightShade;
border: 0;
}
&--reversed hr {
background-color: $kbnMarkdownAlphaLightShadeReversed;
}
hr::before {
display: table;
content: '';
}
hr::after {
display: table;
clear: both;
content: '';
}
// 6. Lists
ul,
ol {
padding-left: $kbnMarkdownSizeL;
margin-top: 0;
margin-bottom: $kbnMarkdownSize;
}
ul {
list-style-type: disc;
}
ol {
list-style-type: decimal;
}
ul ul {
list-style-type: circle;
}
ol ol,
ul ol {
list-style-type: lower-roman;
}
ul ul ol,
ul ol ol,
ol ul ol,
ol ol ol {
list-style-type: lower-alpha;
}
dd {
margin-left: 0;
}
ul ul,
ul ol,
ol ol,
ol ul {
margin-top: 0;
margin-bottom: 0;
}
li > p {
margin-bottom: $kbnMarkdownSizeXS;
}
li + li {
margin-top: $kbnMarkdownSizeXXS;
}
// 7. Tables
table {
display: block;
width: 100%;
overflow: auto;
border-left: 1px solid $kbnMarkdownAlphaLightShade;
border-spacing: 0;
border-collapse: collapse;
}
&--reversed table {
border-left-color: $kbnMarkdownAlphaLightShadeReversed;
}
td,
th {
padding: 0;
}
table th,
table td {
padding: $kbnMarkdownSizeXXS $kbnMarkdownSizeS;
border-top: 1px solid $kbnMarkdownAlphaLightShade;
border-bottom: 1px solid $kbnMarkdownAlphaLightShade;
&:last-child {
border-right: 1px solid $kbnMarkdownAlphaLightShade;
}
}
&--reversed table th,
&--reversed table td {
border-color: $kbnMarkdownAlphaLightShadeReversed;
}
table tr {
background-color: transparent;
border-top: 1px solid $kbnMarkdownAlphaLightShade;
}
&--reversed table tr {
border-top-color: $kbnMarkdownAlphaLightShadeReversed;
}
// 8. Code blocks
code,
pre {
margin-bottom: $kbnMarkdownSizeXS;
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;
font-size: $kbnMarkdownFontSizeS;
}
code {
padding: $kbnMarkdownSizeXXS 0;
margin: 0;
background-color: $kbnMarkdownAlphaLightestShade;
border-radius: $kbnMarkdownSizeXXS;
}
&--reversed code {
background-color: $kbnMarkdownAlphaLightestShadeReversed;
}
code::before,
code::after {
letter-spacing: -.2em;
content: '\00a0';
}
pre {
padding: $kbnMarkdownSize;
overflow: auto;
font-size: $kbnMarkdownFontSizeS;
line-height: 1.333333em;
background-color: $kbnMarkdownAlphaLightestShade;
border-radius: $kbnMarkdownSizeXXS;
word-wrap: normal;
}
&--reversed pre {
background-color: $kbnMarkdownAlphaLightestShadeReversed;
}
pre code {
display: inline;
max-width: auto;
padding: 0;
overflow: visible;
line-height: inherit;
word-wrap: normal;
white-space: pre;
background-color: transparent;
border: 0;
}
pre code::before,
pre code::after {
content: normal;
}
}

View file

@ -1 +0,0 @@
@import './markdown';

View file

@ -11,9 +11,9 @@ import classNames from 'classnames';
import React, { useEffect } from 'react';
import MarkdownIt from 'markdown-it';
import { memoize } from 'lodash';
import { getSecureRelForTarget } from '@elastic/eui';
import { getSecureRelForTarget, useEuiTheme } from '@elastic/eui';
import { markdownStyles } from './markdownStyles';
import './index.scss';
/**
* Return a memoized markdown rendering function that use the specified
* whiteListedRules and openLinksInNewTab configurations.
@ -80,6 +80,7 @@ export interface MarkdownProps extends React.HTMLAttributes<HTMLDivElement> {
openLinksInNewTab?: boolean;
whiteListedRules?: string[];
onRender?: () => void;
isReversed?: boolean;
}
export const Markdown = (props: MarkdownProps) => {
@ -87,14 +88,27 @@ export const Markdown = (props: MarkdownProps) => {
props.onRender?.();
}, [props]);
const { className, markdown = '', openLinksInNewTab, whiteListedRules, ...rest } = props;
const classes = classNames('kbnMarkdown__body', className);
const {
className,
markdown = '',
openLinksInNewTab,
whiteListedRules,
isReversed = false,
...rest
} = props;
const { euiTheme } = useEuiTheme();
const classes = classNames(
'kbnMarkdown__body',
{ 'kbnMarkdown__body--reversed': isReversed },
className
);
const markdownRenderer = markdownFactory(whiteListedRules, openLinksInNewTab);
const renderedMarkdown = markdownRenderer(markdown);
return (
<div
{...rest}
className={classes}
css={markdownStyles(euiTheme, isReversed)}
/*
* Justification for dangerouslySetInnerHTML:
* The Markdown Visualization is, believe it or not, responsible for rendering Markdown.

View file

@ -0,0 +1,287 @@
/*
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { css } from '@emotion/react';
import { UseEuiTheme, transparentize } from '@elastic/eui';
// Default styles for Markdown element
//
// 1. Links
// 2. Headings
// 3. Images
// 4. Blockquotes
// 5. Horizontal rules
// 6. Lists
// 7. Tables
// 8. Code blocks
export const markdownStyles = (euiTheme: UseEuiTheme['euiTheme'], isReversed: boolean) => {
// Note: The inlined base font size is set in common/functions/font.js. It should match $kbnMdFontSize.
const kbnDefaultFontSize = 14;
// Function to convert px to em
const canvasToEm = (size: number): string => `${size / kbnDefaultFontSize}em`;
// Font size variables
const kbnMarkdownFontSizeS = canvasToEm(12);
const kbnMarkdownFontSize = canvasToEm(14);
const kbnMarkdownFontSizeL = canvasToEm(20);
const kbnMarkdownFontSizeXL = canvasToEm(28);
const kbnMarkdownFontSizeXXL = canvasToEm(36);
// Spacing variables
const kbnMarkdownSizeL = canvasToEm(24);
const kbnMarkdownSize = canvasToEm(16);
const kbnMarkdownSizeS = canvasToEm(12);
const kbnMarkdownSizeXS = canvasToEm(8);
const kbnMarkdownSizeXXS = canvasToEm(4);
// Grayscale variables
const kbnMarkdownAlphaLightestShade = transparentize(`${euiTheme.colors.fullShade}`, 0.05);
const kbnMarkdownAlphaLightShade = transparentize(`${euiTheme.colors.fullShade}`, 0.15);
// Reverse grayscale for opposite of theme
const kbnMarkdownAlphaLightestShadeReversed = transparentize(
`${euiTheme.colors.emptyShade}`,
0.05
);
const kbnMarkdownAlphaLightShadeReversed = transparentize(`${euiTheme.colors.emptyShade}`, 0.15);
return css({
...(isReversed && {
color: `${euiTheme.colors.lightestShade}`,
}),
'> *:first-child': {
marginTop: '0 !important',
},
'> *:last-child': {
marginBottom: '0 !important',
},
'p, blockquote, ul, ol, dl, table, pre': {
marginTop: 0,
marginBottom: kbnMarkdownSize,
lineHeight: '1.5em',
},
strong: {
fontWeight: 600,
},
// Links
a: {
color: 'inherit',
textDecoration: 'underline',
'&:hover': {
textDecoration: 'underline dotted',
},
'&:active, &:hover': {
outlineWidth: 0,
},
'&:not([href])': {
color: 'inherit',
textDecoration: 'none',
},
},
// Headings
'h1, h2, h3, h4, h5, h6': {
marginTop: 0,
marginBottom: kbnMarkdownSizeXS,
},
h1: {
fontSize: kbnMarkdownFontSizeXXL,
lineHeight: '1.333333em',
fontWeight: 300,
},
h2: {
fontSize: kbnMarkdownFontSizeXL,
lineHeight: '1.428571em',
fontWeight: 300,
},
h3: {
fontSize: kbnMarkdownFontSizeL,
lineHeight: '1.6em',
fontWeight: 600,
},
h4: {
fontSize: kbnMarkdownSize,
lineHeight: '1.5em',
fontWeight: 600,
},
h5: {
fontSize: kbnMarkdownFontSize,
lineHeight: '1.142857em',
fontWeight: 700,
},
h6: {
fontSize: kbnMarkdownFontSizeS,
lineHeight: '1.333333em',
fontWeight: 700,
textTransform: 'uppercase',
},
// Images
img: {
maxWidth: '100%',
boxSizing: 'content-box',
borderStyle: 'none',
pointerEvents: 'auto',
},
// Blockquotes
blockquote: {
padding: '0 1em',
borderLeft: `${kbnMarkdownSizeXXS} solid ${kbnMarkdownAlphaLightShade}`,
...(isReversed && {
borderLeftColor: `${kbnMarkdownAlphaLightShadeReversed}`,
}),
},
// Horizontal rules
hr: {
overflow: 'hidden',
background: 'transparent',
height: '2px',
padding: 0,
margin: `${kbnMarkdownSizeL} 0`,
backgroundColor: `${kbnMarkdownAlphaLightShade}`,
border: 0,
'::before': {
display: 'table',
content: '"',
},
'::after': {
display: 'table',
clear: 'both',
content: '"',
},
...(isReversed && {
backgroundColor: kbnMarkdownAlphaLightShadeReversed,
}),
},
// Lists
'ul, ol': {
paddingLeft: `${kbnMarkdownSizeL}`,
marginTop: 0,
marginBottom: `${kbnMarkdownSize}`,
},
ul: {
listStyleType: 'disc',
},
ol: {
listStyleType: 'decimal',
},
'ul ul': {
listStyleType: 'circle',
},
'ol ol, ul ol': {
listStyleType: 'lower-roman',
},
'ul ul ol, ul ol ol, ol ul ol, ol ol ol': {
listStyleType: 'lower-alpha',
},
dd: {
marginLeft: 0,
},
// Nested lists with no margin
'ul ul, ul ol, ol ol, ol ul': {
marginTop: 0,
marginBottom: 0,
},
'li > p': {
marginBottom: `${kbnMarkdownSizeXS}`,
},
'li + li': {
marginTop: `${kbnMarkdownSizeXXS}`,
},
// Tables
table: {
display: 'block',
width: '100%',
overflow: 'auto',
borderLeft: `1px solid ${kbnMarkdownAlphaLightShade}`,
borderSpacing: 0,
borderCollapse: 'collapse',
...(isReversed && {
borderLeftColor: `${kbnMarkdownAlphaLightShadeReversed}`,
}),
},
'table th, table td': {
padding: `${kbnMarkdownSizeXXS} ${kbnMarkdownSizeS}`,
borderTop: `1px solid ${kbnMarkdownAlphaLightShade}`,
borderBottom: `1px solid ${kbnMarkdownAlphaLightShade}`,
'&:last-child': {
borderRight: `1px solid ${kbnMarkdownAlphaLightShade}`,
},
...(isReversed && {
borderColor: `${kbnMarkdownAlphaLightShadeReversed}`,
}),
},
'table tr': {
backgroundColor: 'transparent',
borderTop: `1px solid ${kbnMarkdownAlphaLightShade}`,
...(isReversed && {
borderTopColor: `${kbnMarkdownAlphaLightShadeReversed}`,
}),
},
// Code blocks
'code, pre': {
marginBottom: `${kbnMarkdownSizeXS}`,
fontFamily: `'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace`,
fontSize: `${kbnMarkdownFontSizeS}`,
},
code: {
padding: `${kbnMarkdownSizeXXS} 0`,
margin: 0,
backgroundColor: `${kbnMarkdownAlphaLightestShade}`,
borderRadius: `${kbnMarkdownSizeXXS}`,
'&::before, &::after': {
letterSpacing: '-.2em',
content: '"\xa0"',
},
...(isReversed && {
backgroundColor: `${kbnMarkdownAlphaLightestShadeReversed}`,
}),
},
pre: {
padding: `${kbnMarkdownSize}`,
overflow: 'auto',
fontSize: `${kbnMarkdownFontSizeS}`,
lineHeight: '1.333333em',
backgroundColor: `${kbnMarkdownAlphaLightestShade}`,
borderRadius: `${kbnMarkdownSizeXXS}`,
wordWrap: 'normal',
...(isReversed && {
backgroundColor: `${kbnMarkdownAlphaLightestShadeReversed}`,
}),
},
'pre code': {
display: 'inline',
maxWidth: 'auto',
padding: 0,
overflow: 'visible',
lineHeight: 'inherit',
wordWrap: 'normal',
whiteSpace: 'pre',
backgroundColor: 'transparent',
border: 0,
'&::before, &::after': {
content: 'normal',
},
},
});
};

View file

@ -1,7 +0,0 @@
.kbnNoDataPageContents__item:only-child {
min-width: ($euiSize * 22.5);
@include euiBreakpoint('xs', 's') {
min-width: auto;
}
}

View file

@ -7,9 +7,14 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import './action_cards.scss';
import { EuiFlexGrid, EuiFlexItem } from '@elastic/eui';
import {
EuiFlexGrid,
EuiFlexItem,
mathWithUnits,
useEuiTheme,
useEuiMaxBreakpoint,
} from '@elastic/eui';
import { css } from '@emotion/react';
import React, { ReactElement } from 'react';
import { ElasticAgentCard, NoDataCard } from '../no_data_card';
@ -17,13 +22,25 @@ interface ActionCardsProps {
actionCards: Array<ReactElement<typeof NoDataCard> | ReactElement<typeof ElasticAgentCard>>;
}
export const ActionCards = ({ actionCards }: ActionCardsProps) => {
const { euiTheme } = useEuiTheme();
const cards = actionCards.map((card) => (
<EuiFlexItem key={card.key || ''} className="kbnNoDataPageContents__item">
{card}
</EuiFlexItem>
));
return (
<EuiFlexGrid columns={2} css={{ justifyContent: 'space-around' }}>
<EuiFlexGrid
columns={2}
css={css({
justifyContent: 'space-around',
'.kbnNoDataPageContents__item:only-child': {
minWidth: mathWithUnits(euiTheme.size.base, (x) => x * 22.5),
},
[useEuiMaxBreakpoint('m')]: {
minWidth: 'auto',
},
})}
>
{cards}
</EuiFlexGrid>
);

View file

@ -8,7 +8,7 @@
*/
import PropTypes from 'prop-types';
import React from 'react';
import React, { useMemo } from 'react';
import classNames from 'classnames';
import { get } from 'lodash';
import { ClassNames } from '@emotion/react';
@ -37,6 +37,11 @@ function MarkdownVisualization(props) {
const panelBackgroundColor = model.background_color || backgroundColor;
const style = { backgroundColor: panelBackgroundColor };
const isReversed = useMemo(
() => isBackgroundInverted(panelBackgroundColor),
[panelBackgroundColor]
);
let markdown;
if (model.markdown) {
@ -49,15 +54,10 @@ function MarkdownVisualization(props) {
}
);
const markdownClasses = classNames('kbnMarkdown__body', {
'kbnMarkdown__body--reversed': isBackgroundInverted(panelBackgroundColor),
});
const contentClasses = classNames(
'tvbMarkdown__content',
`tvbMarkdown__content--${model.markdown_vertical_align}`,
{ 'tvbMarkdown__content-isScrolling': model.markdown_scrollbars },
markdownClasses
{ 'tvbMarkdown__content-isScrolling': model.markdown_scrollbars }
);
const markdownError = markdownSource instanceof Error ? markdownSource : null;
@ -79,6 +79,7 @@ function MarkdownVisualization(props) {
<div>
{!markdownError && (
<Markdown
isReversed={isReversed}
onRender={initialRender}
markdown={markdownSource}
openLinksInNewTab={model.markdown_openLinksInNewTab}