diff --git a/CHANGELOG.md b/CHANGELOG.md index 076553b8035e..04cf5d166fb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ ## [`master`](https://github.com/elastic/eui/tree/master) - Fixed color of `html` scrollbar in dark mode ([#4969](https://github.com/elastic/eui/pull/4969)) +- Updated `EuiMarkdownFormat` to use `EuiHorizontalRule` and better render tables, code blocks and blockquotes ([#4663](https://github.com/elastic/eui/pull/4947)) +- Updated the `EuiMarkdownFormat` to use `EuiText` as a wrapper to handle all the CSS styling ([#4663](https://github.com/elastic/eui/pull/4947)) +- Updated `EuiText`s `color` prop to accept `inherit` and custom colors. Updated the `size` prop to accept `relative` ([#4663](https://github.com/elastic/eui/pull/4947)) +- Updated `EuiText`s `blockquote` font-size/line-height to match the base font-size/line-height which is the same as paragraphs ([#4663](https://github.com/elastic/eui/pull/4947)) +- Added `markdownFormatProps` prop to `EuiMarkdownEditor` to extend the props passed to the rendered `EuiMarkdownFormat` ([#4663](https://github.com/elastic/eui/pull/4947)) ## [`36.0.0`](https://github.com/elastic/eui/tree/v36.0.0) diff --git a/src-docs/src/components/guide_markdown_format/guide_markdown_format.tsx b/src-docs/src/components/guide_markdown_format/guide_markdown_format.tsx index c7f2b98e9ad6..05355c203e43 100644 --- a/src-docs/src/components/guide_markdown_format/guide_markdown_format.tsx +++ b/src-docs/src/components/guide_markdown_format/guide_markdown_format.tsx @@ -1,18 +1,14 @@ import React, { FunctionComponent } from 'react'; import { EuiMarkdownFormat, + EuiMarkdownFormatProps, getDefaultEuiMarkdownProcessingPlugins, } from '../../../../src/components/markdown_editor'; -import { EuiText } from '../../../../src/components/text'; -import { EuiTitle } from '../../../../src/components/title'; import { slugify } from '../../../../src/services'; -export type GuideMarkdownFormatProps = { - children: any; -}; - -export const GuideMarkdownFormat: FunctionComponent = ({ +export const GuideMarkdownFormat: FunctionComponent = ({ children, + ...rest }) => { const processingPlugins = getDefaultEuiMarkdownProcessingPlugins(); const rehype2reactConfig = processingPlugins[1][1]; @@ -20,33 +16,15 @@ export const GuideMarkdownFormat: FunctionComponent = rehype2reactConfig.components.h2 = ({ children }) => { const id = slugify(children[0]); - return ( - -

{children}

-
- ); + return

{children}

; }; - rehype2reactConfig.components.p = ({ children }) => ( - -

{children}

-
- ); - - rehype2reactConfig.components.ul = ({ children }) => ( - -
    {children}
-
- ); - - rehype2reactConfig.components.ol = ({ children }) => ( - -
    {children}
-
- ); - return ( - + {children} ); diff --git a/src-docs/src/routes.js b/src-docs/src/routes.js index 3de50564bb0b..2ac4de376be6 100644 --- a/src-docs/src/routes.js +++ b/src-docs/src/routes.js @@ -3,14 +3,14 @@ import { slugify } from '../../src/services'; import { createHashHistory } from 'history'; -import { GuidePage, GuideSection } from './components'; +import { GuidePage, GuideSection, GuideMarkdownFormat } from './components'; import { EuiErrorBoundary } from '../../src/components'; import { playgroundCreator } from './services/playground'; // Guidelines -// const GettingStarted = require('!!raw-loader!./views/guidelines/getting_started.md'); +const GettingStarted = require('!!raw-loader!./views/guidelines/getting_started.md'); import AccessibilityGuidelines from './views/guidelines/accessibility'; @@ -293,34 +293,33 @@ const createExample = (example, customTitle) => { }; }; -// const createMarkdownExample = (example, title) => { -// const headings = example.default.match(/^(##) (.*)/gm); +const createMarkdownExample = (example, title) => { + const headings = example.default.match(/^(##) (.*)/gm); -// const sections = headings.map((heading) => { -// const title = heading.replace('## ', ''); + const sections = headings.map((heading) => { + const title = heading.replace('## ', ''); -// return { id: slugify(title), title: title }; -// }); + return { id: slugify(title), title: title }; + }); -// return { -// name: title, -// component: () => ( -// -// -// {example.default} -// -// -// ), -// sections: sections, -// }; -// }; + return { + name: title, + component: () => ( + + + {example.default} + + + ), + sections: sections, + }; +}; const navigation = [ { name: 'Guidelines', items: [ - // TODO uncomment when EuiMarkdownFormat has a better text formatting - // createMarkdownExample(GettingStarted, 'Getting started'), + createMarkdownExample(GettingStarted, 'Getting started'), createExample(AccessibilityGuidelines, 'Accessibility'), { name: 'Colors', diff --git a/src-docs/src/views/guidelines/getting_started.md b/src-docs/src/views/guidelines/getting_started.md index 9835b5235cc1..85ea02c4d0ee 100644 --- a/src-docs/src/views/guidelines/getting_started.md +++ b/src-docs/src/views/guidelines/getting_started.md @@ -2,11 +2,11 @@ To install the Elastic UI Framework into an existing project, use the `yarn` CLI (`npm` is not supported). -```js +``` yarn add @elastic/eui ``` -Note that EUI has [several `peerDependencies` requirements](package.json) that will also need to be installed if starting with a blank project. You can read more about other ways to [consume EUI][consuming]. +Note that EUI has [several `peerDependencies` requirements](https://github.com/elastic/eui/package.json) that will also need to be installed if starting with a blank project. You can read more about other ways to [consume EUI](https://github.com/elastic/eui/blob/master/wiki/consuming.md). ```js yarn add @elastic/eui @elastic/datemath moment prop-types @@ -17,7 +17,7 @@ yarn add @elastic/eui @elastic/datemath moment prop-types ### Node -We depend upon the version of node defined in [.nvmrc](.nvmrc). +We depend upon the version of node defined in [.nvmrc](https://github.com/elastic/eui/.nvmrc). You will probably want to install a node version manager. [nvm](https://github.com/creationix/nvm) is recommended. @@ -29,7 +29,7 @@ nvm install ### Documentation -You can run the documentation locally at [http://localhost:8030/](http://localhost:8030/) by running the following. +You can run the documentation locally at `http://localhost:8030/` by running the following. ```js yarn diff --git a/src-docs/src/views/home/home_view.js b/src-docs/src/views/home/home_view.js index d54b12c33cf5..3eeaf9105445 100644 --- a/src-docs/src/views/home/home_view.js +++ b/src-docs/src/views/home/home_view.js @@ -58,9 +58,9 @@ export const HomeView = () => (

- + Getting started - + diff --git a/src-docs/src/views/markdown_editor/mardown_format_example.js b/src-docs/src/views/markdown_editor/mardown_format_example.js index 01fb77106ac3..dce19cfe9223 100644 --- a/src-docs/src/views/markdown_editor/mardown_format_example.js +++ b/src-docs/src/views/markdown_editor/mardown_format_example.js @@ -1,24 +1,23 @@ import React, { Fragment } from 'react'; - -import { renderToHtml } from '../../services'; - import { GuideSectionTypes } from '../../components'; import { EuiLink, EuiMarkdownFormat, EuiText, + EuiCode, } from '../../../../src/components'; import { Link } from 'react-router-dom'; import MarkdownFormat from './markdown_format'; const markdownFormatSource = require('!!raw-loader!./markdown_format'); -const markdownFormatHtml = renderToHtml(MarkdownFormat); + +import MarkdownFormatStyles from './markdown_format_styles'; +const markdownFormatStylesSource = require('!!raw-loader!./markdown_format_styles'); import MarkdownFormatSink from './markdown_format_sink'; const markdownFormatSinkSource = require('!!raw-loader!./markdown_format_sink'); -const markdownFormatSinkHtml = renderToHtml(MarkdownFormatSink); export const MarkdownFormatExample = { title: 'Markdown format', @@ -45,10 +44,6 @@ export const MarkdownFormatExample = { type: GuideSectionTypes.JS, code: markdownFormatSource, }, - { - type: GuideSectionTypes.HTML, - code: markdownFormatHtml, - }, ], title: 'Built in plugins', text: ( @@ -59,8 +54,9 @@ export const MarkdownFormatExample = { Remark {' '} by default. The translation layer automatically substitutes raw HTML - output with their EUI equivalent. This means anchor and code blocks - will become EuiLink and EuiCodeBlock{' '} + output with their EUI equivalent. This means anchor, code blocks and + horizontal rules will become EuiLink,{' '} + EuiCodeBlock and EuiHorizontalRule{' '} components respectively.

), @@ -73,11 +69,29 @@ export const MarkdownFormatExample = { source: [ { type: GuideSectionTypes.JS, - code: markdownFormatSinkSource, + code: markdownFormatStylesSource, }, + ], + title: 'Text sizing and coloring', + text: ( +

+ EuiMarkdownFormat uses{' '} + EuiText as a wrapper to handle all + the CSS styling when rendering the HTML. It also gives the ability to + control the text size and color with the textSize{' '} + and color props, respectively. +

+ ), + props: { + EuiMarkdownFormat, + }, + demo: , + }, + { + source: [ { - type: GuideSectionTypes.HTML, - code: markdownFormatSinkHtml, + type: GuideSectionTypes.JS, + code: markdownFormatSinkSource, }, ], title: 'Kitchen sink', diff --git a/src-docs/src/views/markdown_editor/markdown_format_sink.js b/src-docs/src/views/markdown_editor/markdown_format_sink.js index 9cb5d06af7f5..87e8b6425146 100644 --- a/src-docs/src/views/markdown_editor/markdown_format_sink.js +++ b/src-docs/src/views/markdown_editor/markdown_format_sink.js @@ -1,6 +1,19 @@ -import React from 'react'; - -import { EuiMarkdownFormat } from '../../../../src'; +import React, { useState } from 'react'; +import classNames from 'classnames'; +import { + EuiMarkdownFormat, + EuiPanel, + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, + EuiFormRow, + EuiSelect, + EuiRange, + EuiColorPicker, + useColorPickerState, + EuiButton, + EuiPopover, +} from '../../../../src'; const markdownContent = `# h1 Heading ## h2 Heading @@ -146,5 +159,132 @@ Autoconverted link https://github.com/nodeca/pica (enable linkify to see) `; export default () => { - return {markdownContent}; + const textSizeArray = ['xs', 's', 'm', 'relative']; + + const textSizeOptions = textSizeArray.map((name) => { + return { + value: name, + text: name, + }; + }); + + const textColorsArray = [ + 'default', + 'subdued', + 'success', + 'accent', + 'danger', + 'warning', + 'ghost', + 'inherit', + 'custom', + ]; + + const textColorsOptions = textColorsArray.map((name) => { + return { + value: name, + text: name, + }; + }); + + const [textSize, setTextSize] = useState(textSizeOptions[2].value); + const [fontSizeScale, setFontSizeScale] = useState(16); + const [textColor, setTextColor] = useState(textColorsOptions[0].value); + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + + const onChangeTextSize = (e) => { + setTextSize(e.target.value); + }; + + const onChangeFontSizeScale = (e) => { + console.log(fontSizeScale); + setFontSizeScale(e.target.value); + }; + + const onChangeTextColor = (e) => { + setTextColor(e.target.value); + }; + + const panelClasses = classNames({ + guideDemo__ghostBackground: textColor === 'ghost', + }); + + const [color, setColor, colorErrors] = useColorPickerState('#c561dc'); + + const onButtonClick = () => + setIsPopoverOpen((isPopoverOpen) => !isPopoverOpen); + const closePopover = () => setIsPopoverOpen(false); + + const button = ( + + Customize props + + ); + + return ( + <> + + + + + onChangeTextColor(e)} + /> + + + + + + + + onChangeTextSize(e)} + /> + + + + + + + + + + + + + + {markdownContent} + + + + ); }; diff --git a/src-docs/src/views/markdown_editor/markdown_format_styles.js b/src-docs/src/views/markdown_editor/markdown_format_styles.js new file mode 100644 index 000000000000..3e5651f2e4c1 --- /dev/null +++ b/src-docs/src/views/markdown_editor/markdown_format_styles.js @@ -0,0 +1,22 @@ +import React from 'react'; + +import { EuiMarkdownFormat } from '../../../../src'; + +const markdownContent = `This text has the \`textSize\` prop set to \`"s"\`. + +The color prop is set to \`"danger"\` and that's why all the text is red! :smile: + +| Emoji | Color | +| ------ | ----------- | +| :rose: | Red | +| :apple: | Red | +| :green_heart: | Green | +`; + +export default () => { + return ( + + {markdownContent} + + ); +}; diff --git a/src-docs/src/views/text/text_color.js b/src-docs/src/views/text/text_color.js index aef31b7db256..c38283010894 100644 --- a/src-docs/src/views/text/text_color.js +++ b/src-docs/src/views/text/text_color.js @@ -40,6 +40,9 @@ export default () => (

Danger text color

+

+ Custom text color +

diff --git a/src/components/form/described_form_group/__snapshots__/described_form_group.test.tsx.snap b/src/components/form/described_form_group/__snapshots__/described_form_group.test.tsx.snap index f561a443b399..c81174129223 100644 --- a/src/components/form/described_form_group/__snapshots__/described_form_group.test.tsx.snap +++ b/src/components/form/described_form_group/__snapshots__/described_form_group.test.tsx.snap @@ -52,6 +52,7 @@ exports[`EuiDescribedFormGroup is rendered 1`] = ` >

Test description
@@ -226,6 +227,7 @@ exports[`EuiDescribedFormGroup props fullWidth is rendered 1`] = ` >
Test description
@@ -324,6 +326,7 @@ exports[`EuiDescribedFormGroup props gutterSize is rendered 1`] = ` >
Test description
@@ -433,6 +436,7 @@ exports[`EuiDescribedFormGroup props props for the flex item containers are pass >
Test description
@@ -532,6 +536,7 @@ exports[`EuiDescribedFormGroup props titleSize is rendered 1`] = ` >
Test description
@@ -629,6 +634,7 @@ exports[`EuiDescribedFormGroup ties together parts for accessibility 1`] = ` >
Test description
diff --git a/src/components/markdown_editor/_markdown_format.scss b/src/components/markdown_editor/_markdown_format.scss index 8aecdb7d956a..ba33c62326e4 100644 --- a/src/components/markdown_editor/_markdown_format.scss +++ b/src/components/markdown_editor/_markdown_format.scss @@ -1,276 +1,81 @@ -// Default styles for Markdown Format -// 1. Headings -// 2. Images -// 3. Blockquotes -// 4. Horizontal rules -// 5. Lists -// 6. Tables -// 7. Code +// The Markdown Format uses by default a few EUI components. +// It uses the EuiText to wrap all the content so all the styles related with scaling based on the font-size live inside `_text.scss` -// The Markdown Format uses by default a few EUI components -// to render elements: EuiLink and EuiCode. - -$browserDefaultFontSize: 16px; - -// We're setting a function o transform px in em -// because it's easier to think in px -@function em($pixels, $context: $browserDefaultFontSize) { - @return #{$pixels/$context}em; -} - -.euiMarkdownFormat { - @include euiFont; - @include euiText; - - // We're using `em` values to support apps where consumers might adjust sizes - // and consequently the markdown needs to adjust to these changes - - // Font size variables - $euiMarkdownFontSizeXS: em(12px); - $euiMarkdownFontSizeS: em(14px); - $euiMarkdownFontSize: em(16px); - $euiMarkdownFontSizeM: em(18px); - $euiMarkdownFontSizeL: em(20px); - $euiMarkdownFontSizeXL: em(28px); - $euiMarkdownFontSizeXXL: em(36px); - - // Spacing variables - $euiMarkdownSizeXXS: em(4px); - $euiMarkdownSizeXS: em(8px); - $euiMarkdownSizeS: em(12px); - $euiMarkdownSize: em(16px); - $euiMarkdownSizeL: em(24px); - - // We're using alpha values to support apps that - // display markdown on backgrounds of various colors - - // Grayscale variables - $euiMarkdownAlphaLightestShade: rgba($euiColorFullShade, .05); - $euiMarkdownAlphaLightShade: rgba($euiColorFullShade, .15); - $euiMarkdownAlphaDarkShade: rgba($euiColorFullShade, .65); - - // Reverse grayscale for opposite of theme - $euiMarkdownAlphaLightestShadeReversed: rgba($euiColorEmptyShade, .05); - $euiMarkdownAlphaLightShadeReversed: rgba($euiColorEmptyShade, .15); - $euiMarkdownAlphaDarkShadeReversed: rgba($euiColorEmptyShade, .65); - - &--reversed { - color: $euiColorLightestShade; - } - - > div > *:first-child { - // sass-lint:disable-block no-important - margin-top: 0 !important; - } - - > div > * { - margin-top: 0; - margin-bottom: $euiMarkdownSize; - } - - > div > *:last-child, - .euiCheckbox { - // sass-lint:disable-block no-important - margin-bottom: 0 !important; - } - - .euiCheckbox + *:not(.euiCheckbox) { - margin-top: $euiMarkdownSize; - } - - p, - blockquote, - ul, - ol, - dl, - pre, - table { - margin-top: 0; - margin-bottom: $euiMarkdownSize; - line-height: 1.5em; - } - - strong { - font-weight: 600; - } - - // 2. Headings - h1, - h2, - h3, - h4, - h5, - h6 { - margin-top: 0; - margin-bottom: $euiMarkdownSizeXS; - } - - h1 { - font-size: $euiMarkdownFontSizeXXL; - line-height: 1.333333em; - font-weight: 300; - } - - h2 { - font-size: $euiMarkdownFontSizeXL; - line-height: 1.428571em; - font-weight: 300; - } - - h3 { - font-size: $euiMarkdownFontSizeL; - line-height: 1.6em; - font-weight: 600; - } - - h4 { - font-size: $euiMarkdownSize; - line-height: 1.5em; - font-weight: 600; - } - - h5 { - font-size: $euiMarkdownFontSizeS; - line-height: 1.142857em; - font-weight: 700; +// This should only be used for .euiMarkdownFormat, therefore it's not included in a separate mixin file +@mixin euiMarkdownAdjustBorderColors($color) { + .euiMarkdownFormat__blockquote { + border-left-color: $color; } - h6 { - font-size: $euiMarkdownFontSizeXS; - line-height: 1.333333em; - font-weight: 700; - text-transform: uppercase; + .euiHorizontalRule { + background-color: $color; + color: $color; // ensure that firefox gets the `currentColor` } - // 3. Images - img { - max-width: 100%; - box-sizing: content-box; - border-style: none; + .euiMarkdownFormat__table { + border-left: 1px solid $color; } - // 4. Blockquotes - blockquote { - padding: 0 1em; - border-left: $euiMarkdownSizeXXS solid $euiMarkdownAlphaLightShade; - } - - &--reversed blockquote { - border-left-color: $euiMarkdownAlphaLightShadeReversed; - } - - // 5. Horizontal rules - hr { - border: none; - height: 1px; - background-color: $euiMarkdownAlphaLightShade; - margin: $euiMarkdownSizeL 0; - } - - hr::before { - display: table; - content: ''; - } - - hr::after { - display: table; - clear: both; - content: ''; - } - - // 6. Lists - ul, - ol { - padding-left: $euiMarkdownSizeL; - margin-top: 0; - margin-bottom: $euiMarkdownSize; - } - - 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; - } + .euiMarkdownFormat__table th, + .euiMarkdownFormat__table td { + border-top: 1px solid $color; + border-bottom: 1px solid $color; - ul ul, - ul ol, - ol ol, - ol ul { - margin-top: 0; - margin-bottom: 0; + &:last-child { + border-right: 1px solid $color; + } } - li > p { - margin-bottom: $euiMarkdownSizeXS; + .euiMarkdownFormat__table tr { + border-top: 1px solid $color; } +} - li + li { - margin-top: $euiMarkdownSizeXXS; +.euiMarkdownFormat { + $euiMarkdownAlphaShade: rgba($euiColorFullShade, .15); + + $euiMarkdownBorderColors: ( + default: $euiMarkdownAlphaShade, + subdued: $euiTextSubduedColor, + secondary: $euiColorSecondary, + success: $euiColorSuccess, + accent: $euiColorAccent, + warning: $euiColorWarning, + danger: $euiColorDanger, + ghost: $euiColorGhost, + inherit: currentColor, + custom: currentColor, + ); + + // We're adjusting the borders of the elements by passing a color defined in $euiMarkdownBorderColors. + // For the `custom` and `inherit` colors we're assigning the `currentColor` so we can get the current or computed value of the `color` property + @each $name, $color in $euiMarkdownBorderColors { + .euiTextColor--#{$name} { + @include euiMarkdownAdjustBorderColors($color); + } } - .task-list-item { - list-style-type: none; + .euiMarkdownFormat__blockquote { + border-left-style: solid; } - .task-list-item + .task-list-item { - margin-top: $euiMarkdownSizeXXS; + .euiCheckbox { + // sass-lint:disable-block no-important + margin-bottom: 0 !important; } - .task-list-item input { - margin: 0 .2em .25em -1.6em; - vertical-align: middle; + // We're adjusting the position of the checkboxes so that when the text size is `relative` the checkboxes get better positioned + .euiCheckbox .euiCheckbox__input + .euiCheckbox__square { + top: 50%; + transform: translateY(-50%); } - // 7. Tables - table { + // Tables + .euiMarkdownFormat__table { display: block; width: 100%; overflow: auto; - border-left: 1px solid $euiMarkdownAlphaLightShade; border-spacing: 0; border-collapse: collapse; } - - td, - th { - padding: 0; - } - - table th, - table td { - padding: $euiMarkdownSizeXXS $euiMarkdownSizeXS; - border-top: 1px solid $euiMarkdownAlphaLightShade; - border-bottom: 1px solid $euiMarkdownAlphaLightShade; - - &:last-child { - border-right: 1px solid $euiMarkdownAlphaLightShade; - } - } - - table tr { - background-color: transparent; - border-top: 1px solid $euiMarkdownAlphaLightShade; - } } diff --git a/src/components/markdown_editor/markdown_editor.test.tsx b/src/components/markdown_editor/markdown_editor.test.tsx index dfe0fc4622c7..1cc8a0065a7f 100644 --- a/src/components/markdown_editor/markdown_editor.test.tsx +++ b/src/components/markdown_editor/markdown_editor.test.tsx @@ -103,13 +103,13 @@ describe('EuiMarkdownEditor', () => { component.find('EuiButtonEmpty').simulate('click'); expect( component - .find('.euiMarkdownFormat') + .find('EuiText.euiMarkdownFormat') .childAt(0) .childAt(0) .matchesElement(

Hello world

) ); expect( - component.find('.euiMarkdownFormat').childAt(0).childAt(0).text() + component.find('EuiText.euiMarkdownFormat').childAt(0).childAt(0).text() ).toBe('Hello world'); }); diff --git a/src/components/markdown_editor/markdown_editor.tsx b/src/components/markdown_editor/markdown_editor.tsx index 32df65d1640f..f3f41f905630 100644 --- a/src/components/markdown_editor/markdown_editor.tsx +++ b/src/components/markdown_editor/markdown_editor.tsx @@ -26,7 +26,7 @@ import { CommonProps, OneOf } from '../common'; import MarkdownActions, { insertText } from './markdown_actions'; import { EuiMarkdownEditorToolbar } from './markdown_editor_toolbar'; import { EuiMarkdownEditorTextArea } from './markdown_editor_text_area'; -import { EuiMarkdownFormat } from './markdown_format'; +import { EuiMarkdownFormat, EuiMarkdownFormatProps } from './markdown_format'; import { EuiMarkdownEditorDropZone } from './markdown_editor_drop_zone'; import { htmlIdGenerator } from '../../services/'; @@ -118,6 +118,14 @@ type CommonMarkdownEditorProps = Omit< /** array defining any drag&drop handlers */ dropHandlers?: EuiMarkdownDropHandler[]; + + /** + * Further extend the props applied to EuiMarkdownFormat + */ + markdownFormatProps?: Omit< + EuiMarkdownFormatProps, + 'parsingPluginList' | 'processingPluginList' | 'children' + >; }; export type EuiMarkdownEditorProps = OneOf< @@ -191,6 +199,7 @@ export const EuiMarkdownEditor = forwardRef< 'aria-describedby': ariaDescribedBy, initialViewMode = MODE_EDITING, dropHandlers = [], + markdownFormatProps, ...rest }, ref @@ -411,7 +420,8 @@ export const EuiMarkdownEditor = forwardRef< style={{ height: previewHeight }}> + processingPluginList={processingPluginList} + {...markdownFormatProps}> {value} diff --git a/src/components/markdown_editor/markdown_format.tsx b/src/components/markdown_editor/markdown_format.tsx index bdc8439ce51b..f4c4a30d5b58 100644 --- a/src/components/markdown_editor/markdown_format.tsx +++ b/src/components/markdown_editor/markdown_format.tsx @@ -9,23 +9,34 @@ import React, { FunctionComponent, useMemo } from 'react'; import unified, { PluggableList } from 'unified'; import { VFileContents } from 'vfile'; +import classNames from 'classnames'; +import { CommonProps } from '../common'; +import { EuiText, EuiTextProps } from '../text/text'; import { defaultProcessingPlugins, defaultParsingPlugins, } from './plugins/markdown_default_plugins'; -export interface EuiMarkdownFormatProps { - children: string; - /** array of unified plugins to parse content into an AST */ - parsingPluginList?: PluggableList; - /** array of unified plugins to convert the AST into a ReactNode */ - processingPluginList?: PluggableList; -} +export type EuiMarkdownFormatProps = CommonProps & + Omit & { + children: string; + /** array of unified plugins to parse content into an AST */ + parsingPluginList?: PluggableList; + /** array of unified plugins to convert the AST into a ReactNode */ + processingPluginList?: PluggableList; + /** + * Determines the text size. Choose `relative` to control the `font-size` based on the value of a parent container. + */ + textSize?: EuiTextProps['size']; + }; export const EuiMarkdownFormat: FunctionComponent = ({ children, + className, parsingPluginList = defaultParsingPlugins, processingPluginList = defaultProcessingPlugins, + textSize = 'm', + ...rest }) => { const processor = useMemo( () => unified().use(parsingPluginList).use(processingPluginList), @@ -41,5 +52,12 @@ export const EuiMarkdownFormat: FunctionComponent = ({ return children; } }, [children, processor]); - return
{result}
; + + const classes = classNames('euiMarkdownFormat', className); + + return ( + + {result} + + ); }; diff --git a/src/components/markdown_editor/plugins/markdown_default_plugins/processing_plugins.tsx b/src/components/markdown_editor/plugins/markdown_default_plugins/processing_plugins.tsx index 0b9d35d2d5d3..901886af57c2 100644 --- a/src/components/markdown_editor/plugins/markdown_default_plugins/processing_plugins.tsx +++ b/src/components/markdown_editor/plugins/markdown_default_plugins/processing_plugins.tsx @@ -30,8 +30,10 @@ import rehype2react from 'rehype-react'; import remark2rehype from 'remark-rehype'; import * as MarkdownTooltip from '../markdown_tooltip'; import * as MarkdownCheckbox from '../markdown_checkbox'; +import { FENCED_CLASS } from '../remark/remark_prismjs'; import { EuiLink } from '../../../link'; import { EuiCodeBlock, EuiCode } from '../../../code'; +import { EuiHorizontalRule } from '../../../horizontal_rule'; const unknownHandler: Handler = (h, node) => { return h(node, node.type, node, all(h, node)); @@ -63,11 +65,25 @@ export const getDefaultEuiMarkdownProcessingPlugins = (): [ a: EuiLink, code: (props: any) => // If there are linebreaks use codeblock, otherwise code - /\r|\n/.exec(props.children) ? ( + /\r|\n/.exec(props.children) || + (props.className && props.className.indexOf(FENCED_CLASS) > -1) ? ( ) : ( ), + // When we use block code "fences" the code tag is replaced by the `EuiCodeBlock`. + // But there's a `pre` tag wrapping all the `EuiCodeBlock`. + // We want to replace this `pre` tag with a `div` because the `EuiCodeBlock` has its own children `pre` tag. + pre: (props) => ( +
+ ), + blockquote: (props) => ( +
+ ), + table: (props) => ( + + ), + hr: (props) => , tooltipPlugin: MarkdownTooltip.renderer, checkboxPlugin: MarkdownCheckbox.renderer, }, diff --git a/src/components/markdown_editor/plugins/remark/remark_prismjs.ts b/src/components/markdown_editor/plugins/remark/remark_prismjs.ts index 9f43cc1f16ef..ad62e6c9c64a 100644 --- a/src/components/markdown_editor/plugins/remark/remark_prismjs.ts +++ b/src/components/markdown_editor/plugins/remark/remark_prismjs.ts @@ -10,6 +10,8 @@ import refractor from 'refractor'; import visit from 'unist-util-visit'; import { Plugin } from 'unified'; +export const FENCED_CLASS = 'remark-prismjs--fenced'; + const attacher: Plugin = () => { return (ast) => visit(ast, 'code', visitor); @@ -29,6 +31,7 @@ const attacher: Plugin = () => { 'prismjs', ...(data.hProperties?.className || []), `language-${language}`, + FENCED_CLASS, ], }; } diff --git a/src/components/text/__snapshots__/text_color.test.tsx.snap b/src/components/text/__snapshots__/text_color.test.tsx.snap index 6ecc8bc17b27..0696df004585 100644 --- a/src/components/text/__snapshots__/text_color.test.tsx.snap +++ b/src/components/text/__snapshots__/text_color.test.tsx.snap @@ -7,3 +7,24 @@ exports[`EuiTextColor is rendered 1`] = ` data-test-subj="test subject string" /> `; + +exports[`EuiTextColor props color is rendered with custom color 1`] = ` + +

+ Content +

+
+`; + +exports[`EuiTextColor props color is rendered with named color 1`] = ` + +

+ Content +

+
+`; diff --git a/src/components/text/_text.scss b/src/components/text/_text.scss index 6440d88540e2..49107c0f9cd4 100644 --- a/src/components/text/_text.scss +++ b/src/components/text/_text.scss @@ -1,8 +1,9 @@ // This should only be used for .euiText, therefore it's not included in a separate mixin file +@mixin euiScaleText($baseFontSize, $sizingMethod: 'rem') { + @include fontSize($baseFontSize, $sizingMethod); -@mixin euiScaleText($baseFontSize) { $baseLineHeightMultiplier: $baseFontSize / 2; - line-height: convertToRem($baseLineHeightMultiplier * 3); + line-height: ($baseLineHeightMultiplier * 3) / $baseFontSize; p, ul, @@ -11,95 +12,156 @@ blockquote, img, pre { - margin-bottom: convertToRem($baseLineHeightMultiplier * 3); + margin-bottom: marginToRemOrEm(($baseLineHeightMultiplier * 3), $baseFontSize, $sizingMethod); } ul, ol { - margin-left: convertToRem($baseLineHeightMultiplier * 3); + margin-left: marginToRemOrEm(($baseLineHeightMultiplier * 3), $baseFontSize, $sizingMethod); } blockquote { - padding: convertToRem($baseFontSize * 1.5); - font-size: convertToRem($baseFontSize * nth($euiTextScale, 4)); + font-size: fontSizeToRemOrEm($baseFontSize, $sizingMethod); + padding: marginToRemOrEm(($baseLineHeightMultiplier * 3), $baseFontSize, $sizingMethod); + } + + // headings + $fontSizeH1: $baseFontSize * nth($euiTextScale, 1); + $fontSizeH2: $baseFontSize * nth($euiTextScale, 2); + $fontSizeH3: $baseFontSize * nth($euiTextScale, 3); + $fontSizeH4: $baseFontSize * nth($euiTextScale, 5); // skip level 4 on purpose + $fontSizeH5: $baseFontSize * nth($euiTextScale, 6); + $fontSizeH6: $baseFontSize * nth($euiTextScale, 7); + + $headingMarginBottom: $baseLineHeightMultiplier * 1; + $headingMarginTop: $baseLineHeightMultiplier * 4; + + h1 { + font-size: fontSizeToRemOrEm($fontSizeH1, $sizingMethod); + line-height: ($baseLineHeightMultiplier * 6) / $fontSizeH1; + margin-bottom: marginToRemOrEm($headingMarginBottom, $fontSizeH1, $sizingMethod); + } + + h2 { + font-size: fontSizeToRemOrEm($fontSizeH2, $sizingMethod); + line-height: ($baseLineHeightMultiplier * 5) / $fontSizeH2; + margin-bottom: marginToRemOrEm($headingMarginBottom, $fontSizeH2, $sizingMethod); + } + + h3 { + font-size: fontSizeToRemOrEm($fontSizeH3, $sizingMethod); + line-height: ($baseLineHeightMultiplier * 4) / $fontSizeH3; + margin-bottom: marginToRemOrEm($headingMarginBottom, $fontSizeH3, $sizingMethod); + } + + h4 { + font-size: fontSizeToRemOrEm($fontSizeH4, $sizingMethod); + line-height: ($baseLineHeightMultiplier * 3) / $fontSizeH4; + margin-bottom: marginToRemOrEm($headingMarginBottom, $fontSizeH4, $sizingMethod); + } + + h5 { + font-size: fontSizeToRemOrEm($fontSizeH5, $sizingMethod); + line-height: ($baseLineHeightMultiplier * 2) / $fontSizeH5; + margin-bottom: marginToRemOrEm($headingMarginBottom, $fontSizeH5, $sizingMethod); } - h1, - h2, - h3, - h4, - h5, h6 { - margin-bottom: convertToRem($baseLineHeightMultiplier * 1); + font-size: fontSizeToRemOrEm($fontSizeH6, $sizingMethod); + line-height: ($baseLineHeightMultiplier * 2) / $fontSizeH6; + margin-bottom: marginToRemOrEm($headingMarginBottom, $fontSizeH6, $sizingMethod); } - dd + dt { - margin-top: convertToRem($baseLineHeightMultiplier * 2); + * + h2 { + margin-top: marginToRemOrEm($headingMarginTop, $fontSizeH2, $sizingMethod); } - * + h2, - * + h3, - * + h4, - * + h5, - * + h6 { - margin-top: convertToRem($baseLineHeightMultiplier * 4); + * + h3 { + margin-top: marginToRemOrEm($headingMarginTop, $fontSizeH3, $sizingMethod); } - h1 { - font-size: convertToRem($baseFontSize * nth($euiTextScale, 1)); - line-height: convertToRem($baseLineHeightMultiplier * 6); + * + h4 { + margin-top: marginToRemOrEm($headingMarginTop, $fontSizeH4, $sizingMethod); } - h2 { - font-size: convertToRem($baseFontSize * nth($euiTextScale, 2)); - line-height: convertToRem($baseLineHeightMultiplier * 5); + * + h5 { + margin-top: marginToRemOrEm($headingMarginTop, $fontSizeH5, $sizingMethod); } - h3 { - font-size: convertToRem($baseFontSize * nth($euiTextScale, 3)); - line-height: convertToRem($baseLineHeightMultiplier * 4); + * + h6 { + margin-top: marginToRemOrEm($headingMarginTop, $fontSizeH6, $sizingMethod); + } + + dd + dt { + $marginTop: $baseLineHeightMultiplier * 2; + + margin-top: marginToRemOrEm($marginTop, $marginTop/$baseFontSize, $sizingMethod); } - h4, dt, .eui-definitionListReverse dd { - font-size: convertToRem($baseFontSize * nth($euiTextScale, 5)); // skip level 4 on purpose - line-height: convertToRem($baseLineHeightMultiplier * 3); + font-size: fontSizeToRemOrEm(($baseFontSize * nth($euiTextScale, 5)), $sizingMethod); // skip level 4 on purpose + line-height: ($baseLineHeightMultiplier * 3) / ($baseFontSize * nth($euiTextScale, 5)); } .eui-definitionListReverse dt { - font-size: convertToRem($baseFontSize * nth($euiTextScale, 7)); + font-size: fontSizeToRemOrEm(($baseFontSize * nth($euiTextScale, 7)), $sizingMethod); color: $euiTextColor; } - h5 { - font-size: convertToRem($baseFontSize * nth($euiTextScale, 6)); - line-height: convertToRem($baseLineHeightMultiplier * 2); - } - - h6 { - font-size: convertToRem($baseFontSize * nth($euiTextScale, 7)); - line-height: convertToRem($baseLineHeightMultiplier * 2); - } - small { - font-size: convertToRem($baseFontSize * nth($euiTextScale, 6)); + font-size: fontSizeToRemOrEm(($baseFontSize * nth($euiTextScale, 6)), $sizingMethod); } pre { - padding: $baseLineHeightMultiplier * 2; + padding: fontSizeToRemOrEm(($baseLineHeightMultiplier * 2), $sizingMethod); } code { // Setting the font size in rem's ensure it doesn't compound // the 90% set by euiCodeBlock - font-size: convertToRem($baseFontSize * .9); + font-size: fontSizeToRemOrEm(($baseFontSize * .9), $sizingMethod); + } + + // specific markdown format components that need to scale + &.euiMarkdownFormat { + .euiMarkdownFormat__blockquote { + padding: 0 marginToRemOrEm($baseLineHeightMultiplier * 2, $baseFontSize, $sizingMethod); + border-left-width: marginToRemOrEm($baseLineHeightMultiplier / 2, $baseFontSize, $sizingMethod); + margin-bottom: marginToRemOrEm($baseLineHeightMultiplier * 2, $baseFontSize, $sizingMethod); + } + + .euiCheckbox + *:not(.euiCheckbox) { + margin-top: marginToRemOrEm($baseLineHeightMultiplier * 2, $baseFontSize, $sizingMethod); + } + + .euiCheckbox__label { + font-size: fontSizeToRemOrEm($baseFontSize, $sizingMethod); + padding-left: marginToRemOrEm($baseLineHeightMultiplier * 3, $baseFontSize, $sizingMethod); + line-height: $baseLineHeightMultiplier * 3 / $baseFontSize; + } + + .euiCheckbox + *:not(.euiCheckbox) { + margin-top: marginToRemOrEm($baseLineHeightMultiplier * 2, $baseFontSize, $sizingMethod); + } + + .euiMarkdownFormat__codeblockWrapper { + margin-bottom: marginToRemOrEm($baseLineHeightMultiplier * 2, $baseFontSize, $sizingMethod); + } + + .euiMarkdownFormat__table { + margin-bottom: marginToRemOrEm($baseLineHeightMultiplier * 2, $baseFontSize, $sizingMethod); + } + + .euiMarkdownFormat__table th, + .euiMarkdownFormat__table td { + padding: marginToRemOrEm($baseLineHeightMultiplier / 2, $baseFontSize, $sizingMethod) marginToRemOrEm($baseLineHeightMultiplier * 1, $baseFontSize, $sizingMethod); + } } } .euiText { @include euiText; - @include euiFontSize; // The euiText mixin forces a color. Since euiText is usually a child // of other styling concerns, we should inherit their coloring. The default // coloring will likely coming from the reset.scss anyway. @@ -137,7 +199,7 @@ list-style: decimal; } - blockquote { + blockquote:not(.euiMarkdownFormat__blockquote) { position: relative; text-align: center; margin-left: auto; @@ -196,6 +258,16 @@ text-transform: uppercase; } + h1, + h2, + h3, + h4, + h5, + h6, + dt { + color: inherit; + } + pre { white-space: pre-wrap; background: $euiCodeBlockBackgroundColor; @@ -208,15 +280,12 @@ } // unset font-size from euiCodeBlock so it doesn't doubly add 90% - code { @include euiCodeFont; display: inline-block; // ensures background stretches the full line-height font-weight: $euiFontWeightRegular; } - @include euiScaleText($euiFontSize); - &.euiText--constrainedWidth { max-width: $euiTextConstrainedMaxWidth; // If the max-width is way too short of the width of the container, @@ -230,12 +299,18 @@ } } +.euiText--medium { + @include euiScaleText($euiFontSize, 'rem'); +} + .euiText--small { - @include fontSize($euiFontSizeS); - @include euiScaleText($euiFontSizeS); + @include euiScaleText($euiFontSizeS, 'rem'); } .euiText--extraSmall { - @include fontSize($euiFontSizeXS); - @include euiScaleText($euiFontSizeXS); + @include euiScaleText($euiFontSizeXS, 'rem'); +} + +.euiText--relative { + @include euiScaleText($euiFontSize, 'em'); } diff --git a/src/components/text/_text_color.scss b/src/components/text/_text_color.scss index 79d8d9916809..7b9d8b6ec755 100644 --- a/src/components/text/_text_color.scss +++ b/src/components/text/_text_color.scss @@ -8,17 +8,24 @@ $euiTextColors: ( warning: $euiColorWarning, danger: $euiColorDanger, ghost: $euiColorGhost, + inherit: inherit, ); // Create color modifiers based on the map @each $name, $color in $euiTextColors { .euiTextColor--#{$name} { - // The below function makes sure the color is accessible on our default background. - color: makeHighContrastColor($color, $euiColorEmptyShade); + @if $name != 'inherit' { + // The below function makes sure the color is accessible on our default background. + color: makeHighContrastColor($color, $euiColorEmptyShade); + } @if $name == 'ghost' { color: $color !important; // sass-lint:disable-line no-important } + + @if $name == 'inherit' { + color: $color; + } } } diff --git a/src/components/text/text.tsx b/src/components/text/text.tsx index d420c6c713a6..cdf625a8cd27 100644 --- a/src/components/text/text.tsx +++ b/src/components/text/text.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import React, { FunctionComponent, HTMLAttributes } from 'react'; +import React, { FunctionComponent, HTMLAttributes, CSSProperties } from 'react'; import classNames from 'classnames'; import { CommonProps, keysOf } from '../common'; @@ -18,6 +18,7 @@ const textSizeToClassNameMap = { xs: 'euiText--extraSmall', s: 'euiText--small', m: 'euiText--medium', + relative: 'euiText--relative', }; export type TextSize = keyof typeof textSizeToClassNameMap; @@ -27,11 +28,15 @@ export const TEXT_SIZES = keysOf(textSizeToClassNameMap); export type EuiTextProps = CommonProps & Omit, 'color'> & { textAlign?: TextAlignment; + /** + * Determines the text size. Choose `relative` to control the `font-size` based on the value of a parent container. + */ size?: TextSize; /** * **`secondary` color is DEPRECATED, use `success` instead** + * Any of our named colors or a `hex`, `rgb` or `rgba` value. */ - color?: TextColor; + color?: TextColor | CSSProperties['color']; grow?: boolean; }; diff --git a/src/components/text/text_color.test.tsx b/src/components/text/text_color.test.tsx index 624cc7476ddc..cc637a80c0fe 100644 --- a/src/components/text/text_color.test.tsx +++ b/src/components/text/text_color.test.tsx @@ -18,4 +18,28 @@ describe('EuiTextColor', () => { expect(component).toMatchSnapshot(); }); + + describe('props', () => { + describe('color', () => { + test('is rendered with named color', () => { + const component = render( + +

Content

+
+ ); + + expect(component).toMatchSnapshot(); + }); + + test('is rendered with custom color', () => { + const component = render( + +

Content

+
+ ); + + expect(component).toMatchSnapshot(); + }); + }); + }); }); diff --git a/src/components/text/text_color.tsx b/src/components/text/text_color.tsx index 27faa683b566..96f9391afc5b 100644 --- a/src/components/text/text_color.tsx +++ b/src/components/text/text_color.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import React, { FunctionComponent, HTMLAttributes } from 'react'; +import React, { FunctionComponent, HTMLAttributes, CSSProperties } from 'react'; import classNames from 'classnames'; import { CommonProps, keysOf } from '../common'; @@ -19,6 +19,7 @@ const colorsToClassNameMap = { danger: 'euiTextColor--danger', warning: 'euiTextColor--warning', ghost: 'euiTextColor--ghost', + inherit: 'euiTextColor--inherit', }; export type TextColor = keyof typeof colorsToClassNameMap; @@ -32,8 +33,9 @@ export type EuiTextColorProps = CommonProps & > & { /** * **`secondary` color is DEPRECATED, use `success` instead** + * Any of our named colors or a `hex`, `rgb` or `rgba` value. */ - color?: TextColor; + color?: TextColor | CSSProperties['color']; /** * Determines the root element */ @@ -45,17 +47,31 @@ export const EuiTextColor: FunctionComponent = ({ color = 'default', className, component = 'span', + style, ...rest }) => { + const isNamedColor = COLORS.includes(color as TextColor); + const classes = classNames( 'euiTextColor', - colorsToClassNameMap[color], + { 'euiTextColor--custom': !isNamedColor }, + isNamedColor && colorsToClassNameMap[color as TextColor], className ); const Component = component; + // We're checking if is a custom color. + // If it is a custom color we set the `color` of the `.euiTextColor` div to that custom color. + // This way the children text elements can `inherit` that color and border and backgrounds can get that `currentColor`. + const euiTextStyle = !isNamedColor + ? { + color: color, + ...style, + } + : { ...style }; + return ( - + {children} ); diff --git a/src/global_styling/mixins/_typography.scss b/src/global_styling/mixins/_typography.scss index 0905e5476cbf..5d76e9fc4275 100644 --- a/src/global_styling/mixins/_typography.scss +++ b/src/global_styling/mixins/_typography.scss @@ -1,6 +1,41 @@ // sass-lint:disable no-vendor-prefixes // sass-lint:disable no-important +@function fontSizeToRemOrEm($size, $sizingMethod: 'rem') { + @if ($sizingMethod == 'rem') { + @return #{$size / $euiFontSize}rem; + } @else if ($sizingMethod == 'em') { + @return #{$size / $euiFontSize}em; + } +} + +// It can also be applied to calculate paddings +@function marginToRemOrEm($elementSize, $elementFontSize, $sizingMethod: 'rem') { + @if ($sizingMethod == 'rem') { + @return #{$elementSize / $euiFontSize}rem; + } @else if ($sizingMethod == 'em') { + @return #{$elementSize / $elementFontSize}em; + } +} + +// Spit out rem and px +@mixin fontSize($size: $euiFontSize, $sizingMethod: 'rem') { + @if ($sizingMethod == 'rem') { + font-size: $size; + font-size: fontSizeToRemOrEm($size, 'rem'); + } @else if ($sizingMethod == 'em') { + font-size: fontSizeToRemOrEm($size, 'em'); + } +} + +@mixin lineHeightFromBaseline($multiplier: 3) { + line-height: lineHeightFromBaseline($multiplier); +} + +// Some mixins that help us deal with browser scaling of text more consistently. +// Essentially, fonts across eui should scale against the root html element, not +// against parent inheritance. + // Our base fonts @mixin euiFont { diff --git a/src/global_styling/variables/_typography.scss b/src/global_styling/variables/_typography.scss index a135b93101b4..6bb7ec9c1996 100644 --- a/src/global_styling/variables/_typography.scss +++ b/src/global_styling/variables/_typography.scss @@ -1,30 +1,3 @@ -// Some mixins that help us deal with browser scaling of text more consistently. -// Essentially, fonts across eui should scale against the root html element, not -// against parent inheritance. - -// Typography mixins - -@function convertToRem($size) { - @return #{$size / $euiFontSize}rem; -} - -// Spit out rem and px -@mixin fontSize($size: $euiFontSize) { - font-size: $size; - font-size: convertToRem($size); -} - -// Our base gridline is at 1/2 the font-size, ensure line-heights stay on that gridline. -// EX: A proper line-height for text is 1.5 times the font-size. -// If our base font size (euiFontSize) is 16, our baseline is 8 (16*1.5 / 3). To ensure the -// text stays on the baseline, we pass a multiplier to calculate a line-height in rems. -@function lineHeightFromBaseline($multiplier: 3) { - @return convertToRem(($euiFontSize/2)*$multiplier); -} -@mixin lineHeightFromBaseline($multiplier: 3) { - line-height: lineHeightFromBaseline($multiplier); -} - // Families $euiFontFamily: 'Inter UI', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol' !default; $euiCodeFontFamily: 'Roboto Mono', Consolas, Menlo, Courier, monospace !default; @@ -56,6 +29,22 @@ $euiFontWeightBold: 700 !default; $euiCodeFontWeightRegular: 400 !default; $euiCodeFontWeightBold: 700 !default; + +// Normally functions are imported before variables in `_index.scss` files +// But because they need to consume some typography variables they need to live here +@function convertToRem($size) { + @return #{$size / $euiFontSize}rem; +} + +// Our base gridline is at 1/2 the font-size, ensure line-heights stay on that gridline. +// EX: A proper line-height for text is 1.5 times the font-size. +// If our base font size (euiFontSize) is 16, our baseline is 8 (16*1.5 / 3). To ensure the +// text stays on the baseline, we pass a multiplier to calculate a line-height in rems. +@function lineHeightFromBaseline($multiplier: 3) { + @return convertToRem(($euiFontSize/2)*$multiplier); +} + + // Titles map // Lists all the properties per EuiTitle size that then gets looped through to create the selectors. // The map allows for tokenization and easier customization per theme, otherwise you'd have to override the selectors themselves diff --git a/src/themes/eui-amsterdam/global_styling/mixins/_typography.scss b/src/themes/eui-amsterdam/global_styling/mixins/_typography.scss index f33cc6d97743..f78e7763479f 100644 --- a/src/themes/eui-amsterdam/global_styling/mixins/_typography.scss +++ b/src/themes/eui-amsterdam/global_styling/mixins/_typography.scss @@ -2,6 +2,41 @@ // All line-heights are aligned to baseline grid // sass-lint:disable no-vendor-prefixes + +@function fontSizeToRemOrEm($size, $sizingMethod: 'rem') { + @if ($sizingMethod == 'rem') { + @return #{$size / $euiFontSize}rem; + } @else if ($sizingMethod == 'em') { + @return #{$size / $euiFontSize}em; + } +} + +@function marginToRemOrEm($elementSize, $elementFontSize, $sizingMethod: 'rem') { + @if ($sizingMethod == 'rem') { + @return #{$elementSize / $euiFontSize}rem; + } @else if ($sizingMethod == 'em') { + @return #{$elementSize / $elementFontSize}em; + } +} + +// Spit out rem and px +@mixin fontSize($size: $euiFontSize, $sizingMethod: 'rem') { + @if ($sizingMethod == 'rem') { + font-size: $size; + font-size: fontSizeToRemOrEm($size, 'rem'); + } @else if ($sizingMethod == 'em') { + font-size: fontSizeToRemOrEm($size, 'em'); + } +} + +@mixin lineHeightFromBaseline($multiplier: 3) { + line-height: lineHeightFromBaseline($multiplier); +} + +// Some mixins that help us deal with browser scaling of text more consistently. +// Essentially, fonts across eui should scale against the root html element, not +// against parent inheritance. + // Redoing this mixin mainly to remove the letter-spacing @mixin euiFont { font-family: $euiFontFamily; diff --git a/src/themes/eui-amsterdam/global_styling/variables/_typography.scss b/src/themes/eui-amsterdam/global_styling/variables/_typography.scss index 765e81bc80d8..84f7d3651a93 100644 --- a/src/themes/eui-amsterdam/global_styling/variables/_typography.scss +++ b/src/themes/eui-amsterdam/global_styling/variables/_typography.scss @@ -19,13 +19,17 @@ $euiBodyLineHeight: 1.142857143; // 16px from a 14px base font size to ensure it $euiCodeFontWeightRegular: 400; $euiCodeFontWeightBold: 700; + +// Normally functions are imported before variables in `_index.scss` files +// But because they need to consume some typography variables they need to live here +@function convertToRem($size) { + @return #{$size / $euiFontSize}rem; +} + // Use 8px increments for base gridline @function lineHeightFromBaseline($multiplier: 3) { @return convertToRem(($euiSize/2)*$multiplier); } -@mixin lineHeightFromBaseline($multiplier: 3) { - line-height: lineHeightFromBaseline($multiplier); -} $euiTitles: ( 'xxxs': ( diff --git a/src/themes/eui-amsterdam/overrides/_text.scss b/src/themes/eui-amsterdam/overrides/_text.scss index ffda9eff4baf..9fb169f3bd6c 100644 --- a/src/themes/eui-amsterdam/overrides/_text.scss +++ b/src/themes/eui-amsterdam/overrides/_text.scss @@ -1,5 +1,3 @@ -// Increase the medium (currently default) size of EuiText to original 16px .euiText--medium { - @include fontSize($euiFontSizeM); - @include euiScaleText($euiFontSizeM); + @include euiScaleText($euiFontSizeM, 'rem'); }