diff --git a/packages/website/docs/components/display/avatar.mdx b/packages/website/docs/components/display/avatar.mdx index 9ffa1509100..49bc44db09e 100644 --- a/packages/website/docs/components/display/avatar.mdx +++ b/packages/website/docs/components/display/avatar.mdx @@ -109,19 +109,13 @@ If your icon has multiples or custom colors like a logo, you can keep the defaul ```tsx interactive import React, { useContext } from 'react'; -import { EuiAvatar, EuiSpacer, EuiTitle } from '@elastic/eui'; -import { ThemeContext } from '../../components'; +import { EuiAvatar, EuiSpacer, EuiTitle, useEuiTheme } from '@elastic/eui'; export default () => { - const themeContext = useContext(ThemeContext); - - /** - * Setup theme based on current light/dark theme - */ - const isDarkTheme = themeContext.theme.includes('dark'); + const isDarkTheme = useEuiTheme().colorMode === 'DARK'; return ( -
+ <>

Avatar colors and sizes

@@ -166,7 +160,7 @@ export default () => {     -
+ ); }; ``` diff --git a/packages/website/docs/components/display/callout.mdx b/packages/website/docs/components/display/callout.mdx index 5d6521f81f5..f062b526061 100644 --- a/packages/website/docs/components/display/callout.mdx +++ b/packages/website/docs/components/display/callout.mdx @@ -90,7 +90,7 @@ export default () => ( Here be dragons. Don’t wanna mess with no dragons. And{' '} here’s a link.

- + Link button diff --git a/packages/website/docs/components/display/drag_and_drop.mdx b/packages/website/docs/components/display/drag_and_drop.mdx index 6db879aaff8..eea70e93d6e 100644 --- a/packages/website/docs/components/display/drag_and_drop.mdx +++ b/packages/website/docs/components/display/drag_and_drop.mdx @@ -727,7 +727,192 @@ export default () => { ); }; +``` + +## Portalled items + +**EuiDraggables** use fixed positioning to render and animate the item being dragged. This positioning logic does not work as expected when used inside of containers that have their own [stacking context](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_positioned_layout/Understanding_z-index/Stacking_context). + +To ensure dragging works as expected inside e.g. **EuiFlyout**, **EuiModal** or **EuiPopover**, use the prop `usePortal` on **EuiDraggable** components. This will render the currently dragged element inside a portal appended to the document body (or wherever **EuiPortal** is configured to `insert` to by default). + +:::warning Style inheritance +If the styling of the draggable content is scoped to a parent component, the styling won't be applied while dragging it when using `usePortal`. This is due to the portalled position in the DOM, which changes previous hierarchical relations to other ancestor elements. To prevent this from happening, we recommend applying styling from within the **EuiDraggable** scope without any parent selectors. +::: + +```tsx interactive +import React, { FunctionComponent, ReactElement, useState } from 'react'; +import { + EuiButton, + EuiDragDropContext, + EuiDraggable, + EuiDroppable, + EuiFlyout, + EuiFlyoutBody, + EuiFlyoutHeader, + EuiModal, + EuiModalBody, + EuiModalHeader, + EuiPanel, + EuiPopover, + EuiSpacer, + EuiTitle, + euiDragDropReorder, + htmlIdGenerator, +} from '@elastic/eui'; +import { DroppableProps, OnDragEndResponder } from '@hello-pangea/dnd'; + +const makeId = htmlIdGenerator(); + +const makeList = (number: number, start = 1) => + Array.from({ length: number }, (v, k) => k + start).map((el) => { + return { + content: `Item ${el}`, + id: makeId(), + }; + }); + +const DragContainer: FunctionComponent<{ + children: ReactElement | ReactElement[] | DroppableProps['children']; + onDragEnd: OnDragEndResponder; +}> = ({ children, onDragEnd }) => ( + + + {children} + + +); +export default () => { + const [isFlyoutOpen, setFlyoutOpen] = useState(false); + const [isModalOpen, setModalOpen] = useState(false); + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + + const [list, setList] = useState(makeList(3)); + const onDragEnd: OnDragEndResponder = ({ source, destination }) => { + if (source && destination) { + const items = euiDragDropReorder(list, source.index, destination.index); + + setList(items); + } + }; + + return ( + <> + setFlyoutOpen(!isFlyoutOpen)}> + Toggle flyout + + + setModalOpen(!isModalOpen)}> + Toggle modal + + + {isFlyoutOpen && ( + setFlyoutOpen(false)}> + + +

+ Portalled EuiDraggable items +

+
+
+ + + {list.map(({ content, id }, idx) => ( + + {(provided, state) => ( + + {content} + {state.isDragging && ' ✨'} + + )} + + ))} + + +
+ )} + + {isModalOpen && ( + setModalOpen(false)}> + + +

+ Portalled EuiDraggable items +

+
+
+ + + {list.map(({ content, id }, idx) => ( + + {(provided, state) => ( + + {content} + {state.isDragging && ' ✨'} + + )} + + ))} + + +
+ )} + + + + setIsPopoverOpen(false)} + button={ + setIsPopoverOpen(!isPopoverOpen)}> + Toggle popover + + } + panelPaddingSize="none" + panelProps={{ css: { inlineSize: 200 } }} + > + { + if (source && destination) { + const items = euiDragDropReorder( + list, + source.index, + destination.index + ); + setList(items); + } + }} + > + {list.map(({ content, id }, idx) => ( + + {(provided, state) => ( + {content} + )} + + ))} + + + + ); +}; ``` ## Kitchen sink @@ -853,78 +1038,6 @@ export default () => { ``` -## Using drag and drop in popovers - -**EuiDraggables** use fixed positioning to render and animate the item being dragged. This positioning logic does not work as expected when used inside of containers that have their own [stacking context](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_positioned_layout/Understanding_z-index/Stacking_context). - -This behavior particularly affects [**EuiPopover**](/docs/layout/popover). If using drag and drop UX within a popover, you **must** include the `` prop for items to properly render while being dragged. - -```tsx interactive -import React, { useState } from 'react'; -import { - EuiPopover, - EuiButton, - EuiPanel, - EuiDragDropContext, - EuiDraggable, - EuiDroppable, - euiDragDropReorder, - htmlIdGenerator, -} from '@elastic/eui'; - -const makeId = htmlIdGenerator(); -const makeList = (number: number, start = 1) => - Array.from({ length: number }, (v, k) => k + start).map((el) => { - return { - content: `Item ${el}`, - id: makeId(), - }; - }); - -export default () => { - const [isPopoverOpen, setIsPopoverOpen] = useState(false); - const [list, setList] = useState(makeList(3)); - - return ( - setIsPopoverOpen(false)} - button={ - setIsPopoverOpen(!isPopoverOpen)}> - Toggle popover with drag and drop content - - } - panelPaddingSize="none" - panelProps={{ css: { inlineSize: 200 } }} - > - { - if (source && destination) { - const items = euiDragDropReorder( - list, - source.index, - destination.index - ); - setList(items); - } - }} - > - - {list.map(({ content, id }, idx) => ( - - {(provided, state) => ( - {content} - )} - - ))} - - - - ); -}; -``` - ## Props import docgen from '@elastic/eui-docgen/dist/components/drag_and_drop'; diff --git a/packages/website/docs/components/display/empty_prompt/accessDenied--dark.png b/packages/website/docs/components/display/empty_prompt/accessDenied--dark.png new file mode 100644 index 00000000000..1c82304251a Binary files /dev/null and b/packages/website/docs/components/display/empty_prompt/accessDenied--dark.png differ diff --git a/packages/website/docs/components/display/empty_prompt/accessDenied--light.png b/packages/website/docs/components/display/empty_prompt/accessDenied--light.png new file mode 100644 index 00000000000..decaca9466c Binary files /dev/null and b/packages/website/docs/components/display/empty_prompt/accessDenied--light.png differ diff --git a/packages/website/docs/components/display/empty_prompt/multiple_types.tsx b/packages/website/docs/components/display/empty_prompt/multiple_types.tsx new file mode 100644 index 00000000000..56cdef30448 --- /dev/null +++ b/packages/website/docs/components/display/empty_prompt/multiple_types.tsx @@ -0,0 +1,146 @@ +import React, { useState } from 'react'; + +import { EuiSelect, useEuiTheme } from '@elastic/eui'; + +// @ts-expect-error Docusaurus theme is missing types for this component +import { Demo } from '@elastic/eui-docusaurus-theme/lib/components/demo'; + +// @ts-ignore - not typed +import pageNotFoundDark from './pageNotFound--dark.png'; +// @ts-ignore - not typed +import pageNotFoundLight from './pageNotFound--light.png'; +// @ts-ignore - not typed +import accessDeniedDark from './accessDenied--dark.png'; +// @ts-ignore - not typed +import accessDeniedLight from './accessDenied--light.png'; + +const types: Array<{ + value: string; + text: string; + code: (colorMode: 'DARK' | 'LIGHT') => string; +}> = [ + { + value: 'errorPages', + text: 'Page not found', + code: (colorMode) => ` + } + title={

Page not found

} + layout="vertical" + body={ +

+ We can't find the page you're looking for. It might have + been removed, renamed, or it didn't exist in the first place. +

+ } + actions={[ + + Home + , + + Go back + , + ]} +/>`, + }, + { + value: 'noPrivileges', + text: 'No permission', + code: (colorMode) => ` + } + title={

Access denied

} + layout="vertical" + body={ +

+ Sorry to rain on your parade, but you don't have permissions to access + this page. +

+ } + actions={[ + + Home + , + + Go back + , + ]} +/>`, + }, + { + value: 'licenseUpgrade', + text: 'License upgrade', + code: () => `Do more with Kibana!} + layout="vertical" + hasBorder + body={ +

+ Start a free trial or upgrade your license to use anomaly detection. +

+ } + actions={[ + + Upgrade + , + Start a free trial, + ]} + footer={ + <> + +

Want to learn more?

+
+ + Read the docs + + + } +/>`, + }, +]; + +export default () => { + const { colorMode } = useEuiTheme(); + + const [selectedType, setSelectedType] = useState(types[0]); + + const onChange = (e: React.ChangeEvent) => { + const type = types.find((option) => option.value === e.target.value); + if (type) { + setSelectedType(type); + } + }; + + return ( + <> + ({ + value: type.value, + text: type.text, + }))} + value={selectedType.value} + onChange={(e) => onChange(e)} + aria-label="Empty prompt examples" + /> + + + {selectedType.code(colorMode)} + + + ); +}; diff --git a/packages/website/docs/components/display/empty_prompt/overview.mdx b/packages/website/docs/components/display/empty_prompt/overview.mdx index 1213eff5476..91abe633a2e 100644 --- a/packages/website/docs/components/display/empty_prompt/overview.mdx +++ b/packages/website/docs/components/display/empty_prompt/overview.mdx @@ -231,59 +231,9 @@ import illustration from '!url-loader!./illustration.svg'; **EuiEmptyPrompt** can be used for more than just **empty** pages. The following example showcases different types of empty states that you can create with the **EuiEmptyPrompt**. For a full list see the [usage guidelines](/docs/guidelines/empty-prompt). -```tsx interactive -import React, { useContext } from 'react'; -import { - EuiEmptyPrompt, - EuiImage, - EuiButton, - EuiButtonEmpty, -} from '@elastic/eui'; -import { ThemeContext } from '../../../components/with_theme'; -import pageNotFoundDark from '../../../images/empty-prompt/pageNotFound--dark.png'; -import pageNotFoundLight from '../../../images/empty-prompt/pageNotFound--light.png'; -import pageNotFoundDark2x from '../../../images/empty-prompt/pageNotFound--dark@2x.png'; -import pageNotFoundLight2x from '../../../images/empty-prompt/pageNotFound--light@2x.png'; +import MultipleTypes from './multiple_types'; -export default () => { - const themeContext = useContext(ThemeContext); - const isDarkTheme = themeContext.theme.includes('dark'); - - const pageNotFound = isDarkTheme ? pageNotFoundDark : pageNotFoundLight; - const pageNotFound2x = isDarkTheme ? pageNotFoundDark2x : pageNotFoundLight2x; - - return ( - - } - title={

Page not found

} - layout="vertical" - body={ -

- We can't find the page you're looking for. It might have - been removed, renamed, or it didn't exist in the first place. -

- } - actions={[ - - Home - , - - Go back - , - ]} - /> - ); -}; - -``` + ## Using in a page template diff --git a/packages/website/docs/components/display/empty_prompt/pageNotFound--dark.png b/packages/website/docs/components/display/empty_prompt/pageNotFound--dark.png new file mode 100644 index 00000000000..27095016fda Binary files /dev/null and b/packages/website/docs/components/display/empty_prompt/pageNotFound--dark.png differ diff --git a/packages/website/docs/components/display/empty_prompt/pageNotFound--light.png b/packages/website/docs/components/display/empty_prompt/pageNotFound--light.png new file mode 100644 index 00000000000..0fe9eb35d04 Binary files /dev/null and b/packages/website/docs/components/display/empty_prompt/pageNotFound--light.png differ diff --git a/packages/website/docs/components/display/icons/icon_types_tokens.ts b/packages/website/docs/components/display/icons/icon_types_tokens.ts index 35cee335edd..c5d9df93902 100644 --- a/packages/website/docs/components/display/icons/icon_types_tokens.ts +++ b/packages/website/docs/components/display/icons/icon_types_tokens.ts @@ -46,6 +46,7 @@ export const iconTypesTokens: Array = [ 'tokenRankFeatures', 'tokenRepo', 'tokenSearchType', + 'tokenSemanticText', 'tokenShape', 'tokenString', 'tokenStruct', diff --git a/packages/website/docs/components/display/icons/overview.mdx b/packages/website/docs/components/display/icons/overview.mdx index cd6c2959592..48dccab5482 100644 --- a/packages/website/docs/components/display/icons/overview.mdx +++ b/packages/website/docs/components/display/icons/overview.mdx @@ -354,12 +354,17 @@ import { iconColors } from './icon_colors.ts' {iconColors.map((color) => ( - {(copy) => ( - -  {' '} - {color} - - )} + {(copy) => { + const panel = ( + +  {' '} + {color} + + ); + return color === 'ghost' + ? {panel} + : panel; + }} ))} diff --git a/packages/website/docs/components/display/text.mdx b/packages/website/docs/components/display/text.mdx index 97bf3c7a647..b0126acf318 100644 --- a/packages/website/docs/components/display/text.mdx +++ b/packages/website/docs/components/display/text.mdx @@ -220,6 +220,7 @@ Using the `size` prop on **EuiText** you can get smaller sizes of text than the ```tsx interactive import React, { useState, useContext } from 'react'; +import { css } from '@emotion/react'; import { EuiText, EuiFlexGroup, @@ -227,7 +228,6 @@ import { EuiHorizontalRule, EuiButtonGroup, } from '@elastic/eui'; -import { ThemeContext } from '../../components/with_theme'; const text = [

This is Heading One

, @@ -303,8 +303,17 @@ const text = [
This is Heading Six
, ]; +const textLinesCss = ({ euiTheme }) => css` + background-image: linear-gradient(${euiTheme.focus.backgroundColor} 1px, transparent 1px); + background-size: 100% 4px; + background-position-y: -1px; + + & > * { + background-color: ${euiTheme.colors.highlight}; + } +`; + export default () => { - const themeContext = useContext(ThemeContext); const textSizeArray = ['xs', 's', 'm']; const textSizeNamesArray = ['Extra small', 'Small', 'Medium']; @@ -352,10 +361,7 @@ export default () => { options={firstOptions} /> - + {text} @@ -374,10 +380,7 @@ export default () => { options={secondOptions} /> - + {text} @@ -385,7 +388,6 @@ export default () => { ); }; - ``` ## Coloring text diff --git a/packages/website/docs/components/display/toast/overview.mdx b/packages/website/docs/components/display/toast/overview.mdx index 21e6920600d..89f23a6f414 100644 --- a/packages/website/docs/components/display/toast/overview.mdx +++ b/packages/website/docs/components/display/toast/overview.mdx @@ -3,6 +3,8 @@ slug: /display/toast id: display_toast --- +import previewWrapper from './preview_wrapper'; + # Toast Be sure to read the full [toast usage guidelines](/docs/guidelines/toast). @@ -10,7 +12,7 @@ Be sure to read the full [toast usage guidelines](/docs/guidelines/toast). ## Toast list ```tsx interactive -import React, { useState, Fragment } from 'react'; +import React, { useState } from 'react'; import { EuiCode, EuiGlobalToastList, @@ -24,11 +26,11 @@ let addToastHandler; let removeAllToastsHandler; let toastId = 0; -export function addToast() { +const addToast = () => { addToastHandler(); } -export function removeAllToasts() { +const removeAllToasts = () => { removeAllToastsHandler(); } @@ -56,7 +58,7 @@ export default () => { title: "Check it out, here's a really long title that will wrap within a narrower browser", text: ( - + <>

Here’s some stuff that you need to know. We can make this text really long so that, when viewed within a browser @@ -66,7 +68,7 @@ export default () => { And some other stuff on another line, just for kicks. And{' '} here’s a link.

-
+ ), }, { @@ -79,13 +81,13 @@ export default () => { color: 'warning', iconType: 'user', text: ( - + <>

This is a security measure.

Please move your mouse to show that you’re still using Kibana.

-
+ ), }, { @@ -136,7 +138,6 @@ export default () => { ); }; - ``` ## Default @@ -145,121 +146,129 @@ export default () => { They should not be used for historical actions (**your report built 30 minutes ago**). This means that a user should never be greeted with toasts when starting a session. Toasts should be brief and avoid long paragraphs of text or titling. -```tsx interactive -import React from 'react'; -import { EuiToast } from '@elastic/eui'; + + ```tsx interactive + import React from 'react'; + import { EuiToast } from '@elastic/eui'; -export default () => ( -
+ export default () => ( {}}>

A good toast message is short and to the point. It should very rarely include multiple paragraphs.

-
-); -``` + ); + ``` +
## Info For informative messages use `type="info"`. -```tsx interactive -import React from 'react'; -import { EuiToast } from '@elastic/eui'; - -export default () => ( - {}}> -

- Icons should be used rarely. They are good for warnings, but when paired - with long titles they look out of place. -

-
-); -``` + + ```tsx interactive + import React from 'react'; + import { EuiToast } from '@elastic/eui'; + + export default () => ( + {}}> +

+ Icons should be used rarely. They are good for warnings, but when paired + with long titles they look out of place. +

+
+ ); + ``` +
## Success For success messages use `color="success"`. -```tsx interactive -import React from 'react'; -import { - EuiButton, - EuiLink, - EuiToast, - EuiFlexGroup, - EuiFlexItem, -} from '@elastic/eui'; + + ```tsx interactive + import React from 'react'; + import { + EuiButton, + EuiLink, + EuiToast, + EuiFlexGroup, + EuiFlexItem, + } from '@elastic/eui'; + + export default () => ( + +

+ While the layout will adjust properly for wrapping titles, they do not + look particularly good. Similarily, do not use a whole lot of text in your + body either. At a certain point people will not have enough time to read + these things. Like, you probably are not even reading this now. +

-export default () => ( - -

- While the layout will adjust properly for wrapping titles, they do not - look particularly good. Similarily, do not use a whole lot of text in your - body either. At a certain point people will not have enough time to read - these things. Like, you probably are not even reading this now. -

- -

- And some other stuff on another line, just for kicks. And{' '} - here’s a link. -

- - - - Download report - - -
-); -``` +

+ And some other stuff on another line, just for kicks. And{' '} + here’s a link. +

+ + + + Download report + + +
+ ); + ``` +
## Warning Use this callout to warn the user against decisions they might regret. Show a warning message when the program detects that **something is not behaving right, but it didn't cause any termination.** For warning messages use `color="warning"`. -```tsx interactive -import React from 'react'; -import { EuiToast } from '@elastic/eui'; - -export default () => ( - -); -``` + + ```tsx interactive + import React from 'react'; + import { EuiToast } from '@elastic/eui'; + + export default () => ( + + ); + ``` + ## Danger Use this callout to let the user know that something went wrong. For example if you want to communicate an error. You should show an error message when the issue is **terminal, this doesn't always mean that the operation stops completely, but the task is not complete**. For errors messages use `color="danger"`. -```tsx interactive -import React from 'react'; -import { EuiToast } from '@elastic/eui'; - -const esError = - 'Error: expected _scroll_id in the folling Elasticsearch response: ' + - '{"took":0,"timed_out":false,"_shards":{"total":0,"successful":0,"skipped":0,"failed":0},' + - '"hits":{"total":0,"max_score":0,"hits":[]}}'; - -export default () => ( - -

{esError}

-
-); -``` + + ```tsx interactive + import React from 'react'; + import { EuiToast } from '@elastic/eui'; + + const esError = + 'Error: expected _scroll_id in the folling Elasticsearch response: ' + + '{"took":0,"timed_out":false,"_shards":{"total":0,"successful":0,"skipped":0,"failed":0},' + + '"hits":{"total":0,"max_score":0,"hits":[]}}'; + + export default () => ( + +

{esError}

+
+ ); + ``` +
## Props diff --git a/packages/website/docs/components/display/toast/preview_wrapper.tsx b/packages/website/docs/components/display/toast/preview_wrapper.tsx new file mode 100644 index 00000000000..75c57372519 --- /dev/null +++ b/packages/website/docs/components/display/toast/preview_wrapper.tsx @@ -0,0 +1,3 @@ +export default ({ children }) => ( +
{children}
+); diff --git a/packages/website/docs/components/editors_and_syntax/markdown_format.mdx b/packages/website/docs/components/editors_and_syntax/markdown_format.mdx index bd77a80fad5..c66afed93cc 100644 --- a/packages/website/docs/components/editors_and_syntax/markdown_format.mdx +++ b/packages/website/docs/components/editors_and_syntax/markdown_format.mdx @@ -80,8 +80,8 @@ Markdown content often comes from untrusted sources like user generated content. ``` **Links starting with http:, https:, mailto:, and / are valid:** -* https://elastic.com -* http://elastic.com +* https://elastic.co +* http://elastic.co * https link to [elastic.co](https://elastic.co) * http link to [elastic.co](http://elastic.co) * relative link to [eui doc's homepage](/) @@ -97,10 +97,9 @@ Markdown content often comes from untrusted sources like user generated content. import React from 'react'; import { EuiMarkdownFormat } from '@elastic/eui'; -// eslint-disable-next-line no-restricted-globals -const locationPathname = location.pathname; +const locationPathname = window.location.pathname; -export const markdownContent = `**Links starting with http:, https:, mailto:, and / are valid:** +const markdownContent = `**Links starting with http:, https:, mailto:, and / are valid:** * https://elastic.com * http://elastic.com diff --git a/packages/website/docs/components/editors_and_syntax/markdown_plugins.mdx b/packages/website/docs/components/editors_and_syntax/markdown_plugins.mdx index e762e22097e..5f60d0ed502 100644 --- a/packages/website/docs/components/editors_and_syntax/markdown_plugins.mdx +++ b/packages/website/docs/components/editors_and_syntax/markdown_plugins.mdx @@ -16,22 +16,22 @@ EUI provides additional plugins by default, but these can be omitted or otherwis The parsing plugins, responsible for parsing markdown are: 1. [remark-parse](https://www.npmjs.com/package/remark-parse) -2. [additional pre-processing for code blocks](https://github.com/elastic/eui/blob/main/src/components/markdown_editor/plugins/remark/remark_prismjs.ts) +2. [additional pre-processing for code blocks](https://github.com/elastic/eui/blob/main/packages/eui/src/components/markdown_editor/plugins/remark/remark_prismjs.ts) 3. [remark-emoji](https://www.npmjs.com/package/remark-emoji) 4. [remark-breaks](https://www.npmjs.com/package/remark-breaks) -5. [link validation for security](https://github.com/elastic/eui/blob/main/src/components/markdown_editor/plugins/markdown_link_validator.tsx) -6. [injection of EuiCheckbox for markdown check boxes](https://github.com/elastic/eui/blob/main/src/components/markdown_editor/plugins/markdown_checkbox/parser.ts) -7. [tooltip plugin parser](https://github.com/elastic/eui/blob/main/src/components/markdown_editor/plugins/markdown_tooltip/parser.ts) +5. [link validation for security](https://github.com/elastic/eui/blob/main/packages/eui/src/components/markdown_editor/plugins/markdown_link_validator.tsx) +6. [injection of EuiCheckbox for markdown check boxes](https://github.com/elastic/eui/blob/main/packages/eui/src/components/markdown_editor/plugins/markdown_checkbox/parser.ts) +7. [tooltip plugin parser](https://github.com/elastic/eui/blob/main/packages/eui/src/components/markdown_editor/plugins/markdown_tooltip/parser.ts) The above set provides an abstract syntax tree used by the editor to provide feedback, and the renderer passes that output to the set of processing plugins to allow it to be rendered: 1. [remark-rehype](https://www.npmjs.com/package/remark-rehype) 2. [rehype-react](https://www.npmjs.com/package/rehype-react) -3. [tooltip plugin renderer](https://github.com/elastic/eui/blob/main/src/components/markdown_editor/plugins/markdown_tooltip/renderer.tsx) +3. [tooltip plugin renderer](https://github.com/elastic/eui/blob/main/packages/eui/src/components/markdown_editor/plugins/markdown_tooltip/renderer.tsx) The last set of plugin configuration - `uiPlugins` - allows toolbar buttons to be defined and how they alter or inject markdown and returns with only one plugin: -1. [tooltip plugin ui](https://github.com/elastic/eui/blob/main/src/components/markdown_editor/plugins/markdown_tooltip/plugin.tsx) +1. [tooltip plugin ui](https://github.com/elastic/eui/blob/main/packages/eui/src/components/markdown_editor/plugins/markdown_tooltip/plugin.tsx) These plugin definitions can be obtained by calling `getDefaultEuiMarkdownParsingPlugins`, `getDefaultEuiMarkdownProcessingPlugins`, and `getDefaultEuiMarkdownUiPlugins` respectively. diff --git a/packages/website/docs/components/forms/color_selection.mdx b/packages/website/docs/components/forms/color_selection.mdx index 4b452b89ae7..7ca2ddcb599 100644 --- a/packages/website/docs/components/forms/color_selection.mdx +++ b/packages/website/docs/components/forms/color_selection.mdx @@ -344,7 +344,7 @@ export default () => { Display fixed } - display="columnCompressedSwitch" + display="columnCompressed" > { onCreateOption={onCreateOption} isClearable={true} data-test-subj="demoComboBox" - autoFocus /> ); diff --git a/packages/website/docs/components/forms/compressed_forms.mdx b/packages/website/docs/components/forms/compressed_forms.mdx index cb0a9fc4111..42e8040ed25 100644 --- a/packages/website/docs/components/forms/compressed_forms.mdx +++ b/packages/website/docs/components/forms/compressed_forms.mdx @@ -11,7 +11,7 @@ Also known as **Editor-Style Controls**, compressed forms and controls were spec Do not use compressed and non-compressed form controls in the same form. ::: -To use compressed forms, pass `display="rowCompressed"` to the EuiFormRows and `compressed=true` to the form controls themselves. +To use compressed forms, pass `compressed=true` to all form controls. ```tsx interactive import React, { useState } from 'react'; @@ -91,12 +91,11 @@ export default () => { - + { /> - + - + { /> - + { /> - + { Editor-style controls can be displayed in a two column layout for even better use of limited space, just pass `display="columnCompressed"` to align the labels and inputs side by side. -**EuiSwitches** are a special case in which so you must pass `"columnCompressedSwitch"` to the EuiFormRow as the display property. - ```tsx interactive import React, { useState } from 'react'; import { @@ -255,7 +252,7 @@ export default () => { /> - + { return ( /* DisplayToggles wrapper for Docs only */ -
- + <> + { placeholder="Example of an error" /> -
+ ); }; ``` @@ -436,14 +436,16 @@ export default () => { Use `customInput` to pass a custom input to trigger your calendar. ```tsx interactive -import React, { forwardRef, useState } from 'react'; +import React, { forwardRef, useState, FunctionComponent, ReactNode } from 'react'; import { EuiDatePicker, EuiButton } from '@elastic/eui'; import PropTypes from 'prop-types'; import moment from 'moment'; // Should be a component because the date picker does some ref stuff behind the scenes -// eslint-disable-next-line -const ExampleCustomInput = forwardRef(({ onClick, value }, ref) => { +const ExampleCustomInput: FunctionComponent<{ + onClick: Function; + value: ReactNode; +}> = forwardRef(({ onClick, value }, ref) => { return ( {value} @@ -451,11 +453,6 @@ const ExampleCustomInput = forwardRef(({ onClick, value }, ref) => { ); }); -ExampleCustomInput.propTypes = { - onClick: PropTypes.func, - value: PropTypes.string, -}; - export default () => { const [startDate, setStartDate] = useState(moment()); @@ -602,66 +599,79 @@ Custom classes can be passed to various bits of the calendar and input. * `dayClassName` will pass onto specificed days. * `popperClassName` will pass onto the popover. -```tsx interactive -import React, { useState } from 'react'; -import { EuiDatePicker, EuiFormRow, EuiSpacer } from '@elastic/eui'; -import moment from 'moment'; - -export default () => { - const [startDate, setStartDate] = useState(moment()); - - const handleChange = (date) => { - setStartDate(date); - }; - - return ( -
- - - +import { css } from '@emotion/css'; + + + ```tsx interactive + import React, { useState } from 'react'; + import { EuiDatePicker, EuiFormRow, EuiSpacer } from '@elastic/eui'; + import moment from 'moment'; + import { css } from '@emotion/css'; // Generates a vanilla JS className + + const visColors = euiPaletteColorBlind(); + const backgroundCss = css` + background-color: ${visColors[3]}; + `; + const outlineCss = css` + outline: solid 2px ${visColors[3]}; + `; + + export default () => { + const [startDate, setStartDate] = useState(moment()); + + const handleChange = (date) => { + setStartDate(date); + }; + + return ( + <> + + + - + - - - + + + - + - - - date.date() < Math.random() * 31 - ? 'guideDemo__datePickerPurpleDay' - : undefined - } - /> - + + + date.date() < Math.random() * 31 + ? backgroundCss + : undefined + } + /> + - + - - - -
- ); -}; -``` + + + + + ); + }; + ``` + diff --git a/packages/website/docs/components/forms/form_controls/overview.mdx b/packages/website/docs/components/forms/form_controls/overview.mdx index 8d9c4d8935f..b89d54a1276 100644 --- a/packages/website/docs/components/forms/form_controls/overview.mdx +++ b/packages/website/docs/components/forms/form_controls/overview.mdx @@ -714,7 +714,7 @@ export default () => { ## Form control layout delimited -Building block only +Building block only Like **EuiFormControlLayout**, **EuiFormControlLayoutDelimited** is generally used internally to consistently style form controls. This component specifically lays out two form controls with center text or icon. @@ -732,7 +732,7 @@ import { export default () => (
( } endControl={ - } @@ -759,18 +757,16 @@ export default () => ( } endControl={ - } @@ -779,18 +775,16 @@ export default () => ( px} startControl={ - } endControl={ - } @@ -799,18 +793,16 @@ export default () => ( } endControl={ - } @@ -820,18 +812,16 @@ export default () => ( clear={{ onClick: () => {} }} isLoading startControl={ - } endControl={ - } @@ -840,18 +830,16 @@ export default () => ( } endControl={ - } @@ -860,18 +848,16 @@ export default () => ( } endControl={ - } @@ -880,19 +866,17 @@ export default () => ( Add} startControl={ - } delimiter="+" endControl={ - } @@ -901,19 +885,17 @@ export default () => ( Merge} startControl={ - } delimiter={} endControl={ - } @@ -923,19 +905,17 @@ export default () => ( readOnly prepend={Read only} startControl={ - } endControl={ - @@ -946,19 +926,17 @@ export default () => ( isDisabled prepend={Disabled} startControl={ - } endControl={ - diff --git a/packages/website/docs/components/forms/search_bar.mdx b/packages/website/docs/components/forms/search_bar.mdx index 7e27d264c98..6142fc56fa3 100644 --- a/packages/website/docs/components/forms/search_bar.mdx +++ b/packages/website/docs/components/forms/search_bar.mdx @@ -49,7 +49,7 @@ Formats understood by the parser * `YYYY-MM-DD` ```tsx interactive -import React, { useState, Fragment } from 'react'; +import React, { useState } from 'react'; import { EuiHealth, EuiCallOut, @@ -108,7 +108,7 @@ const loadTags = () => { const initialQuery = EuiSearchBar.Query.MATCH_ALL; -export const SearchBar = () => { +export default () => { const [query, setQuery] = useState(initialQuery); const [error, setError] = useState(null); const [incremental, setIncremental] = useState(false); @@ -251,14 +251,14 @@ export const SearchBar = () => { return; } return ( - + <> - + ); }; @@ -323,8 +323,8 @@ export const SearchBar = () => { } const content = renderError() || ( - - + +

Elasticsearch Query String

@@ -332,9 +332,8 @@ export const SearchBar = () => { {esQueryString ? esQueryString : ''} - - - +
+

Elasticsearch Query DSL

@@ -344,7 +343,7 @@ export const SearchBar = () => {
- +

JS execution

@@ -357,7 +356,7 @@ export const SearchBar = () => { ); return ( - + <> {renderSearch()} @@ -379,10 +378,9 @@ export const SearchBar = () => { {content} - + ); }; - ``` ## Controlled search bar @@ -390,7 +388,7 @@ export const SearchBar = () => { An **EuiSearchBar** can have its query controlled by a parent component by passing the `query` prop. Changes to the query will be passed back up through the `onChange` callback where the new query must be stored in state and passed back into the search bar. ```tsx interactive -import React, { useState, Fragment } from 'react'; +import React, { useState } from 'react'; import { EuiHealth, EuiCallOut, @@ -448,7 +446,7 @@ const loadTags = () => { const initialQuery = 'status:open'; -export const ControlledSearchBar = () => { +export default () => { const [query, setQuery] = useState(initialQuery); const [error, setError] = useState(null); const [incremental, setIncremental] = useState(false); @@ -468,7 +466,7 @@ export const ControlledSearchBar = () => { const renderBookmarks = () => { return ( - + <>

Enter a query, or select one from a bookmark

@@ -490,7 +488,7 @@ export const ControlledSearchBar = () => {
- + ); }; @@ -593,14 +591,14 @@ export const ControlledSearchBar = () => { return; } return ( - + <> - + ); }; @@ -657,7 +655,7 @@ export const ControlledSearchBar = () => { ); return ( - + <> {renderBookmarks()} @@ -674,7 +672,7 @@ export const ControlledSearchBar = () => {
{content} - + ); }; @@ -685,7 +683,7 @@ export const ControlledSearchBar = () => { An **EuiSearchBar** can have custom filter dropdowns that control how a user can search. ```tsx interactive -import React, { useState, Fragment } from 'react'; +import React, { useState } from 'react'; import { EuiHealth, EuiCallOut, @@ -845,7 +843,7 @@ const CustomComponent = ({ query, onChange }) => { ); }; -export const SearchBarFilters = () => { +export default () => { const [query, setQuery] = useState(initialQuery); const [error, setError] = useState(null); @@ -891,6 +889,7 @@ export const SearchBarFilters = () => { value: tag.name, view: {tag.name}, })), + autoSortOptions: false, }, { type: 'custom_component', @@ -959,14 +958,14 @@ export const SearchBarFilters = () => { return; } return ( - + <> - + ); }; @@ -1020,8 +1019,8 @@ export const SearchBarFilters = () => { const esQueryString = EuiSearchBar.Query.toESQueryString(query); const content = renderError() || ( - - + +

Elasticsearch Query String

@@ -1029,9 +1028,8 @@ export const SearchBarFilters = () => { {esQueryString ? esQueryString : ''} - - - +
+

Elasticsearch Query DSL

@@ -1041,7 +1039,7 @@ export const SearchBarFilters = () => {
- +

JS execution

@@ -1054,11 +1052,11 @@ export const SearchBarFilters = () => { ); return ( - + <> {renderSearch()} {content} - + ); }; diff --git a/packages/website/docs/components/forms/selection_controls/overview.mdx b/packages/website/docs/components/forms/selection_controls/overview.mdx index 689ed58d02f..e1808847682 100644 --- a/packages/website/docs/components/forms/selection_controls/overview.mdx +++ b/packages/website/docs/components/forms/selection_controls/overview.mdx @@ -18,7 +18,7 @@ Use the `checked` prop to handle the checked and unchecked state. You can also u Make sure to pass a `label` to ensure a larger clickable area and ensure that screen readers will read out the label when the user is focused on the input. To learn more about labels usage, go to the [guidelines tab](/docs/forms/selection-controls/guidelines). ```tsx interactive -import React, { useState, Fragment } from 'react'; +import React, { useState } from 'react'; import { EuiCheckbox, EuiSpacer, useGeneratedHtmlId } from '@elastic/eui'; export default () => { @@ -43,7 +43,7 @@ export default () => { }; return ( - + <> { id={compressedCheckboxId} label="I am a readonly checkbox" checked={checked} - onChange={(e) => onChange(e)} + onChange={() => {}} readOnly /> - + ); }; ``` @@ -168,7 +168,7 @@ When creating a list, each input should have the same `name` to ensure a group i Make sure to pass a `label` to ensure a larger clickable area and ensure that screen readers will read out the label when the user is focused on the input. To learn more about labels usage, go to the [guidelines tab](/docs/forms/selection-controls/guidelines). ```tsx interactive -import React, { useState, Fragment } from 'react'; +import React, { useState } from 'react'; import { EuiRadio, EuiSpacer, useGeneratedHtmlId } from '@elastic/eui'; export default () => { @@ -187,7 +187,7 @@ export default () => { }; return ( - + <> { onChange={(e) => onChange(e)} compressed /> - + ); }; ``` @@ -329,7 +329,7 @@ When providing the state as the label, you'll need to provide an `aria-described ::: ```tsx interactive -import React, { useState, Fragment } from 'react'; +import React, { useState } from 'react'; import { EuiSwitch, EuiFormRow, useGeneratedHtmlId } from '@elastic/eui'; export default () => { @@ -350,8 +350,8 @@ export default () => { }; return ( - - + <> + { /> Show something} > { compressed /> - + ); }; ``` diff --git a/packages/website/docs/components/guidelines/getting_started.mdx b/packages/website/docs/components/guidelines/getting_started.mdx index 1f1070eccb3..41d86fb601d 100644 --- a/packages/website/docs/components/guidelines/getting_started.mdx +++ b/packages/website/docs/components/guidelines/getting_started.mdx @@ -23,22 +23,15 @@ You can read more about other ways to [consume EUI](https://github.com/elastic/e ## Setting up your application -:::warning - -While EUI is in the process of converting from a Sass based theme to CSS-in-JS via Emotion. We require that both the [**EuiProvider**](/docs/utilities/provider) **and** the compiled CSS (or raw Sass) files be imported during this transition. - -::: - -EUI provides a general context provider to handle global aspects like light and dark theme. You can import these default themes through their respective compiled CSS files. Use the `.min.css` file extension for the minified version. +EUI uses CSS-in-JS (specifically [Emotion](https://emotion.sh/)) for its styles and theming. As such, we require an `` wrapper around your application in order for various theme-related UI & UX (such as dark/light mode switching) to work as expected. ```tsx import React from 'react'; -import '@elastic/eui/dist/eui_theme_light.css'; import { EuiProvider, EuiText } from '@elastic/eui'; const MyApp = () => ( - +

Hello World!

); @@ -46,14 +39,13 @@ const MyApp = () => ( export default MyApp; ``` -For the dark theme, you can swap the words `light` for `dark`. -For more configuration options of the provider, see the [EuiProvider documentation](/docs/utilities/provider). +For more configuration options of the provider, see the [**EuiProvider** documentation](/docs/utilities/provider). ## Styling your application -To build your custom components using EUI theme variables, functions, and mixins, you will need to consume them through one of the [Sass](/docs/theming/sass), [Emotion](/docs/theming/theme-provider), or [JSON import](https://github.com/elastic/eui/blob/main/wiki/consuming-eui/README.md#a-not-recommended-legacy-method-to-consume-theming-variables-from-sass) methods. +You can build custom components using EUI's theme tokens, consumed via `useEuiTheme()`. The below example uses Emotion's `css` prop, but any CSS-in-JS library should be able to interpolate the JS variables. -As long as you have wrapped your application with [**EuiProvider**](/docs/guidelines/getting-started#setting-up-your-application), you have access to the JS theme tokens via `useEuiTheme()` and Emotion's `css` prop. +For more ways to consume EUI's theme, see the [**EuiThemeProvider** documentation](/theming/theme-provider#consuming-with-the-react-hook). ```tsx import React from 'react'; @@ -88,19 +80,45 @@ export default () => { }; ``` -### Customizing the style tokens +### Customizing with classes + +For consumers using vanilla or preprocessed CSS, all components allow you to pass a custom `className` prop, which will be appended onto the component. + +:::warning Avoid overwriting `.eui` class names + +EUI's class names are not a guaranteed API and are prone to change, which will risk breaking your theme. Target your custom classNames instead. + +::: + +While EUI's styles are generally low in [specificity](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity) due to our usage of CSS-in-JS, you may need to ensure that your CSS is defined after ours in your ``. See [**EuiProvider's** cache customization for more style injection options](/utilities/provider#cache-customization). + +```tsx +import React from 'react'; +import { EuiButton } from '@elastic/eui'; +const myCustomCSS = ` + .myCustomButton { + background-color: pink; + } +`; +export default () => ( + <> + + Hello world! + +); +``` -EUI can be slightly customized to fit your branding needs by altering the base tokens like color and typography. Simply declare your token overrides before importing the whole EUI theme. This will re-compile all of the EUI components with your colors. +### Customizing the style tokens -For a full list of global tokens visit [Customizing theme](/docs/theming/customizing-themes). +EUI can be slightly customized to fit your branding needs by altering the base tokens like color and typography. You can pass a full or partial list of override tokens to the **EuiProvider**'s `modify` prop. -:::warning Partial component support +:::warning Touch the least amount of variables possible -EUI is transitioning to a CSS-in-JS solution for theming and requires consuming/customizing global variables in **both the Sass and CSS-in-JS** methods. To track this effort, subscribe to the [Meta ticket](https://github.com/elastic/eui/issues/3912). +By nature, EUI is very rigid. You shouldn't need much to make drastic changes to color. Most themes are less then a dozen variable overwrites in total. ::: -You can pass along a full or partial list of global `overrides` to the [**EuiProvider**](/docs/guidelines/getting-started#setting-up-your-application) which will update the EUI components that are currently using the Emotion method of theming. +For a full list of global tokens visit [Customizing theme](/docs/theming/customizing-themes). For more examples of the `modify` prop, see the [**EuiThemeProvider** docs](/theming/theme-provider#simple-instance-overrides). ```tsx import React, { FunctionComponent, ReactNode } from 'react'; @@ -142,18 +160,6 @@ export default () => { }; ``` -#### Do not use in conjunction with the compiled CSS. - -If you provide both, it will duplicate the imported styles. - -#### Touch the least amount of variables possible. - -By nature EUI is very rigid. You shouldn't need much to make drastic changes to color. Most themes are less then a dozen variable overwrites in total. - -#### Do not overwrite individual component variables or `.eui` class names. - -Although this may be possible, components are much more prone to change and you'll risk breaking your theme. All EUI components accept custom a `className` which you can use to append your custom styles. - ## Fonts By default, EUI ships with a font stack that includes some outside, open source fonts. If your system is internet available you can include these by adding the following imports to your SCSS/CSS files, otherwise you'll need to bundle the physical fonts in your build. EUI will drop to System Fonts (which you may prefer) in their absence. @@ -214,20 +220,6 @@ import { findTestSubject } from '@elastic/eui/lib/test'; // Enzyme import { findByTestSubject, render, screen } from '@elastic/eui/lib/test/rtl'; // React Testing Library ``` -## Customizing with classes - -We do not recommend customizing EUI components by applying styles directly to EUI classes, eg. `.euiButton`. All components allow you to pass a custom `className` prop directly to the component which will then append this to the class list. Utilizing the cascade feature of CSS, you can then customize by overriding styles so long as your styles are imported **after** the EUI import. - -```tsx - -``` - -Renders as: - -```html -