((source: DemoSourceMeta) => {
+ setSources((sources) => ([...sources, source]));
+ }, []);
+
+ const onClickCopyToClipboard = useCallback(() => {
+ copyToClipboard(activeSource?.code || '');
+ }, [activeSource]);
+
+ const onClickReloadExample = useCallback(() => {
+ setLiveProviderKey((liveProviderKey) => liveProviderKey + 1);
+ }, []);
+
+ const onClickOpenInCodeSandbox = useCallback(() => {
+ // TODO: implement
+ console.error('Open in CodeSandbox action is not implemented yet');
+ }, []);
+
+ return (
+
+
+
+
+
+ {isSourceOpen && }
+
+
+ {Children.map(children, (child, index) => {
+ if (isElement(child) && child.type === DemoSource) {
+ return child;
+ }
+
+ return {child};
+ })}
+
+
+ );
+};
diff --git a/packages/docusaurus-theme/src/components/demo/editor/editor.tsx b/packages/docusaurus-theme/src/components/demo/editor/editor.tsx
new file mode 100644
index 00000000000..4a5394025f3
--- /dev/null
+++ b/packages/docusaurus-theme/src/components/demo/editor/editor.tsx
@@ -0,0 +1,49 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { LiveEditor, LiveError } from 'react-live';
+import { css } from '@emotion/react';
+import { useEuiMemoizedStyles, useEuiTheme } from '@elastic/eui';
+
+const getEditorStyles = () => ({
+ editor: css`
+ font-family: var(--ifm-font-family-monospace);
+ border-radius: 0 0 var(--docs-demo-border-radius) var(--docs-demo-border-radius);
+
+ & .prism-code {
+ border-radius: 0 0 calc(var(--docs-demo-border-radius) - 1px) calc(var(--docs-demo-border-radius) - 1px);
+ }
+ `,
+ error: css`
+ // docusaurus overrides the default pre styles
+ // forcing us to use higher specificity here
+ && > pre {
+ font-size: var(--eui-font-size-s);
+ background: var(--eui-background-color-danger);
+ color: var(--eui-color-danger-text);
+ padding: var(--eui-size-xs) var(--eui-size-s);
+ margin: 0;
+ border-radius: 0;
+ }
+ `,
+});
+
+export const DemoEditor = () => {
+ const styles = useEuiMemoizedStyles(getEditorStyles);
+
+ return (
+
+ );
+}
diff --git a/packages/docusaurus-theme/src/components/demo/editor/index.ts b/packages/docusaurus-theme/src/components/demo/editor/index.ts
new file mode 100644
index 00000000000..cf7d0a1eb5b
--- /dev/null
+++ b/packages/docusaurus-theme/src/components/demo/editor/index.ts
@@ -0,0 +1 @@
+export { DemoEditor } from './editor';
diff --git a/packages/docusaurus-theme/src/components/demo/index.ts b/packages/docusaurus-theme/src/components/demo/index.ts
new file mode 100644
index 00000000000..349ce0aab1b
--- /dev/null
+++ b/packages/docusaurus-theme/src/components/demo/index.ts
@@ -0,0 +1,2 @@
+export { Demo, type DemoProps } from './demo';
+export { DemoSource } from './source';
diff --git a/packages/docusaurus-theme/src/components/demo/preview/index.ts b/packages/docusaurus-theme/src/components/demo/preview/index.ts
new file mode 100644
index 00000000000..ed761d6cdc7
--- /dev/null
+++ b/packages/docusaurus-theme/src/components/demo/preview/index.ts
@@ -0,0 +1 @@
+export { DemoPreview } from './preview';
diff --git a/packages/docusaurus-theme/src/components/demo/preview/preview.tsx b/packages/docusaurus-theme/src/components/demo/preview/preview.tsx
new file mode 100644
index 00000000000..c9dfab45f56
--- /dev/null
+++ b/packages/docusaurus-theme/src/components/demo/preview/preview.tsx
@@ -0,0 +1,41 @@
+import { css } from '@emotion/react';
+import { LiveError, LivePreview } from 'react-live';
+import BrowserOnly from '@docusaurus/BrowserOnly';
+import ErrorBoundary from '@docusaurus/ErrorBoundary';
+import { ErrorBoundaryErrorMessageFallback } from '@docusaurus/theme-common';
+import { UseEuiTheme, EuiFlexGroup, useEuiTheme } from '@elastic/eui';
+
+const getPreviewStyles = (euiTheme: UseEuiTheme) => ({
+ previewWrapper: css`
+ padding: ${euiTheme.euiTheme.size.l};
+ border-radius: var(--docs-demo-border-radius);
+ `,
+});
+
+/**
+ * PreviewLoader provides a fallback content for the server-side render
+ * of the live component preview component.
+ * Due to the limitations of react-live the demo is only rendered client-side.
+ */
+const PreviewLoader = () => (
+ Loading...
+);
+
+export const DemoPreview = () => {
+ const euiTheme = useEuiTheme();
+ const styles = getPreviewStyles(euiTheme);
+
+ return (
+ }>
+ {() => (
+ <>
+ }>
+
+
+
+
+ >
+ )}
+
+ );
+};
diff --git a/packages/docusaurus-theme/src/components/demo/scope.ts b/packages/docusaurus-theme/src/components/demo/scope.ts
new file mode 100644
index 00000000000..f9809471ea6
--- /dev/null
+++ b/packages/docusaurus-theme/src/components/demo/scope.ts
@@ -0,0 +1,8 @@
+import React from 'react';
+import * as EUI from '@elastic/eui';
+
+export const demoScope: Record = {
+ React,
+ ...React,
+ ...EUI,
+};
diff --git a/packages/docusaurus-theme/src/components/demo/source/get_source_from_children.ts b/packages/docusaurus-theme/src/components/demo/source/get_source_from_children.ts
new file mode 100644
index 00000000000..6dff6b4da38
--- /dev/null
+++ b/packages/docusaurus-theme/src/components/demo/source/get_source_from_children.ts
@@ -0,0 +1,46 @@
+import { Children, ReactElement, ReactNode } from 'react';
+import { isElement } from 'react-is';
+
+export interface SourceMeta {
+ /**
+ * The source code
+ */
+ code: string;
+}
+
+/**
+ * Get source string from given children.
+ */
+export const getSourceFromChildren = (children: ReactNode): string | null => {
+ if (Children.count(children) !== 1 || !isElement(children)) {
+ // This should never happen
+ return null;
+ }
+
+ const element = children as ReactElement;
+ const functionName = (element.type as Function).name;
+ // The code block content could render in either MDXPre (development builds)
+ // or pre (optimized production builds)
+ if (
+ typeof element.type !== 'function' ||
+ (functionName !== 'MDXPre' && functionName !== 'pre')
+ ) {
+ return null;
+ }
+
+ if (!isElement(element.props.children)) {
+ return null;
+ }
+
+ const codeElement = element.props.children as ReactElement;
+ if (!codeElement || !codeElement.props.children) {
+ return null;
+ }
+
+ const code = codeElement.props.children;
+ if (typeof code !== 'string') {
+ return null;
+ }
+
+ return code;
+};
diff --git a/packages/docusaurus-theme/src/components/demo/source/index.ts b/packages/docusaurus-theme/src/components/demo/source/index.ts
new file mode 100644
index 00000000000..1773a43a356
--- /dev/null
+++ b/packages/docusaurus-theme/src/components/demo/source/index.ts
@@ -0,0 +1 @@
+export { DemoSource, type DemoSourceProps } from './source';
diff --git a/packages/docusaurus-theme/src/components/demo/source/source.tsx b/packages/docusaurus-theme/src/components/demo/source/source.tsx
new file mode 100644
index 00000000000..a8f4eafe34e
--- /dev/null
+++ b/packages/docusaurus-theme/src/components/demo/source/source.tsx
@@ -0,0 +1,28 @@
+import { PropsWithChildren, useEffect } from 'react';
+import { useDemoContext } from '../context';
+import { getSourceFromChildren } from './get_source_from_children';
+
+export interface DemoSourceProps extends PropsWithChildren {
+ filename?: string;
+ isActive?: boolean;
+}
+
+export const DemoSource = ({ children, filename, isActive = false }: DemoSourceProps) => {
+ const demoContext = useDemoContext();
+
+ useEffect(() => {
+ const source = getSourceFromChildren(children);
+
+ if (source) {
+ const transformedSource = source.replace(/\n$/, '');
+
+ demoContext.addSource({
+ code: transformedSource,
+ isActive,
+ filename,
+ });
+ }
+ }, [children]);
+
+ return null;
+}
diff --git a/packages/docusaurus-theme/src/theme/MDXComponents/index.ts b/packages/docusaurus-theme/src/theme/MDXComponents/index.ts
index 3db17981ea2..86a179cf731 100644
--- a/packages/docusaurus-theme/src/theme/MDXComponents/index.ts
+++ b/packages/docusaurus-theme/src/theme/MDXComponents/index.ts
@@ -10,12 +10,15 @@ import OriginalMDXComponents from '@theme-init/MDXComponents';
import { Badge } from '../../components/badge';
import { Icon } from '../../components/icon';
import { FigmaEmbed } from '../../components/figma_embed';
+import { Demo, DemoSource } from '../../components/demo';
const MDXComponents = {
...OriginalMDXComponents,
Badge,
FigmaEmbed,
Icon,
+ Demo,
+ DemoSource,
};
export default MDXComponents;
diff --git a/packages/docusaurus-theme/src/theme/Root.styles.ts b/packages/docusaurus-theme/src/theme/Root.styles.ts
index 94883648bda..f1af0c84e44 100644
--- a/packages/docusaurus-theme/src/theme/Root.styles.ts
+++ b/packages/docusaurus-theme/src/theme/Root.styles.ts
@@ -1,4 +1,13 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
import {
+ euiBorderColor,
euiFontSizeFromScale,
euiLineHeightFromBaseline,
useEuiBackgroundColor,
@@ -8,7 +17,8 @@ import {
// override docusaurus variables as needed
// NOTE: we use define variables with style calculations here
// on the global level to reduce how often they are called
-export const getGlobalStyles = ({ euiTheme }: UseEuiTheme) => {
+export const getGlobalStyles = (theme: UseEuiTheme) => {
+ const { euiTheme } = theme;
const { font, base, colors, size } = euiTheme;
const fontBodyScale = font.scale[font.body.scale];
const fontBase = {
@@ -39,10 +49,13 @@ export const getGlobalStyles = ({ euiTheme }: UseEuiTheme) => {
[data-theme='dark']:root {
/* EUI theme variables */
--eui-background-color-primary: ${useEuiBackgroundColor('primary')};
+ --eui-background-color-primary-opaque: ${useEuiBackgroundColor('primary', { method: 'opaque' })};
--eui-background-color-success: ${useEuiBackgroundColor('success')};
--eui-background-color-danger: ${useEuiBackgroundColor('danger')};
--eui-background-color-warning: ${useEuiBackgroundColor('warning')};
-
+
+ --eui-color-danger-text: ${euiTheme.colors.dangerText};
+
/* Docusaurus theme variables */
--ifm-background-color: ${colors.body};
--ifm-font-color-base: ${colors.text};
@@ -68,6 +81,11 @@ export const getGlobalStyles = ({ euiTheme }: UseEuiTheme) => {
--eui-line-height-s: ${lineHeightS};
--eui-line-height-xs: ${lineHeightXS};
+ --eui-size-xs: ${euiTheme.size.xs};
+ --eui-size-s: ${euiTheme.size.s};
+
+ --eui-border-color-primary: ${euiBorderColor(theme, 'primary')};
+
/* Docusaurus theme variables */
--ifm-font-family-base: ${fontBase.fontFamily};
--ifm-font-size-base: var(--eui-font-size-base);
@@ -80,7 +98,7 @@ export const getGlobalStyles = ({ euiTheme }: UseEuiTheme) => {
h1, h2, h3, h4, h5, h6 {
margin-block-start: ${size.l};
margin-block-end: ${size.m};
-
+
font-weight: ${font.weight.bold};
}
diff --git a/packages/website/docs/02_components/navigation/button/overview.mdx b/packages/website/docs/02_components/navigation/button/overview.mdx
index 848b5b310bb..82a27177142 100644
--- a/packages/website/docs/02_components/navigation/button/overview.mdx
+++ b/packages/website/docs/02_components/navigation/button/overview.mdx
@@ -20,10 +20,22 @@ The most standard button component is **EuiButton** which comes in two styles an
When using colors other than `primary`, be sure that either the words or an icon also represents the status. For instance, don't rely on color alone to represent dangerous actions but use words like "Delete" not "Confirm". The `text` and `accent` colors should be used sparingly as they can easily be confused with other states like disabled and danger.
+
+ ```tsx
+ Button
+ ```
+
+
## Empty button
Use **EuiButtonEmpty** when you want to reduce the importance of the button, but still want to align it to the rest of the buttons. It is also the only button component that supports down to size `xs`.
+
+ ```tsx
+ ButtonEmpty
+ ```
+
+
## Flush empty button
When aligning **EuiButtonEmpty** components to the left or the right, you should make sure they’re flush with the edge of their container, so that they’re horizontally aligned with the other content in the container.
diff --git a/yarn.lock b/yarn.lock
index b1a9174af36..7839ce05ceb 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5698,9 +5698,12 @@ __metadata:
"@elastic/eui": "npm:94.5.0"
"@emotion/css": "npm:^11.11.2"
"@emotion/react": "npm:^11.11.4"
- "@types/react": "npm:^18"
- "@types/react-dom": "npm:^18"
+ "@types/react-is": "npm:^18"
+ clsx: "npm:^2.1.1"
moment: "npm:^2.30.1"
+ prism-react-renderer: "npm:^2.3.1"
+ react-is: "npm:^18.3.1"
+ react-live: "npm:^4.1.7"
typescript: "npm:~5.4.5"
peerDependencies:
react: ^18.0.0
@@ -10022,15 +10025,6 @@ __metadata:
languageName: node
linkType: hard
-"@types/react-dom@npm:^18":
- version: 18.3.0
- resolution: "@types/react-dom@npm:18.3.0"
- dependencies:
- "@types/react": "npm:*"
- checksum: 10c0/6c90d2ed72c5a0e440d2c75d99287e4b5df3e7b011838cdc03ae5cd518ab52164d86990e73246b9d812eaf02ec351d74e3b4f5bd325bf341e13bf980392fd53b
- languageName: node
- linkType: hard
-
"@types/react-dom@npm:^18.0.0, @types/react-dom@npm:^18.2.6":
version: 18.2.6
resolution: "@types/react-dom@npm:18.2.6"
@@ -10049,6 +10043,15 @@ __metadata:
languageName: node
linkType: hard
+"@types/react-is@npm:^18":
+ version: 18.3.0
+ resolution: "@types/react-is@npm:18.3.0"
+ dependencies:
+ "@types/react": "npm:*"
+ checksum: 10c0/0fdc950981c36100cc3c1692081d62538671c8e4a431b64f80c452c6f67b7bcd569542dffeb6b4a4b13565a2037bc963b6bf64c4ae5623c64ffa2935b6ecfb21
+ languageName: node
+ linkType: hard
+
"@types/react-redux@npm:^7.1.20":
version: 7.1.22
resolution: "@types/react-redux@npm:7.1.22"
@@ -11695,6 +11698,13 @@ __metadata:
languageName: node
linkType: hard
+"any-promise@npm:^1.0.0":
+ version: 1.3.0
+ resolution: "any-promise@npm:1.3.0"
+ checksum: 10c0/60f0298ed34c74fef50daab88e8dab786036ed5a7fad02e012ab57e376e0a0b4b29e83b95ea9b5e7d89df762f5f25119b83e00706ecaccb22cfbacee98d74889
+ languageName: node
+ linkType: hard
+
"anymatch@npm:^3.0.3, anymatch@npm:~3.1.2":
version: 3.1.3
resolution: "anymatch@npm:3.1.3"
@@ -14259,7 +14269,7 @@ __metadata:
languageName: node
linkType: hard
-"clsx@npm:^2.0.0":
+"clsx@npm:^2.0.0, clsx@npm:^2.1.1":
version: 2.1.1
resolution: "clsx@npm:2.1.1"
checksum: 10c0/c4c8eb865f8c82baab07e71bfa8897c73454881c4f99d6bc81585aecd7c441746c1399d08363dc096c550cceaf97bd4ce1e8854e1771e9998d9f94c4fe075839
@@ -14596,6 +14606,13 @@ __metadata:
languageName: node
linkType: hard
+"commander@npm:^4.0.0":
+ version: 4.1.1
+ resolution: "commander@npm:4.1.1"
+ checksum: 10c0/84a76c08fe6cc08c9c93f62ac573d2907d8e79138999312c92d4155bc2325d487d64d13f669b2000c9f8caf70493c1be2dac74fec3c51d5a04f8bc3ae1830bab
+ languageName: node
+ linkType: hard
+
"commander@npm:^5.1.0":
version: 5.1.0
resolution: "commander@npm:5.1.0"
@@ -27030,6 +27047,17 @@ __metadata:
languageName: node
linkType: hard
+"mz@npm:^2.7.0":
+ version: 2.7.0
+ resolution: "mz@npm:2.7.0"
+ dependencies:
+ any-promise: "npm:^1.0.0"
+ object-assign: "npm:^4.0.1"
+ thenify-all: "npm:^1.0.0"
+ checksum: 10c0/103114e93f87362f0b56ab5b2e7245051ad0276b646e3902c98397d18bb8f4a77f2ea4a2c9d3ad516034ea3a56553b60d3f5f78220001ca4c404bd711bd0af39
+ languageName: node
+ linkType: hard
+
"n-readlines@npm:1.0.0":
version: 1.0.0
resolution: "n-readlines@npm:1.0.0"
@@ -29064,7 +29092,7 @@ __metadata:
languageName: node
linkType: hard
-"pirates@npm:^4.0.4, pirates@npm:^4.0.6":
+"pirates@npm:^4.0.1, pirates@npm:^4.0.4, pirates@npm:^4.0.6":
version: 4.0.6
resolution: "pirates@npm:4.0.6"
checksum: 10c0/00d5fa51f8dded94d7429700fb91a0c1ead00ae2c7fd27089f0c5b63e6eca36197fe46384631872690a66f390c5e27198e99006ab77ae472692ab9c2ca903f36
@@ -30328,7 +30356,7 @@ __metadata:
languageName: node
linkType: hard
-"prism-react-renderer@npm:^2.3.0":
+"prism-react-renderer@npm:^2.0.6, prism-react-renderer@npm:^2.3.0, prism-react-renderer@npm:^2.3.1":
version: 2.3.1
resolution: "prism-react-renderer@npm:2.3.1"
dependencies:
@@ -31223,6 +31251,13 @@ __metadata:
languageName: node
linkType: hard
+"react-is@npm:^18.3.1":
+ version: 18.3.1
+ resolution: "react-is@npm:18.3.1"
+ checksum: 10c0/f2f1e60010c683479e74c63f96b09fb41603527cd131a9959e2aee1e5a8b0caf270b365e5ca77d4a6b18aae659b60a86150bb3979073528877029b35aecd2072
+ languageName: node
+ linkType: hard
+
"react-json-view-lite@npm:^1.2.0":
version: 1.4.0
resolution: "react-json-view-lite@npm:1.4.0"
@@ -31232,6 +31267,20 @@ __metadata:
languageName: node
linkType: hard
+"react-live@npm:^4.1.7":
+ version: 4.1.7
+ resolution: "react-live@npm:4.1.7"
+ dependencies:
+ prism-react-renderer: "npm:^2.0.6"
+ sucrase: "npm:^3.31.0"
+ use-editable: "npm:^2.3.3"
+ peerDependencies:
+ react: ">=18.0.0"
+ react-dom: ">=18.0.0"
+ checksum: 10c0/728a51cb0b92774076e4592f9b3cbc2af4afac1da549dbb55723728324bdc1968d3f7b268b5dd92929dcc9d3aa1fd1265f7e912b5ee6fd4fe9b5b77898b50237
+ languageName: node
+ linkType: hard
+
"react-loadable-ssr-addon-v5-slorber@npm:^1.0.1":
version: 1.0.1
resolution: "react-loadable-ssr-addon-v5-slorber@npm:1.0.1"
@@ -34938,6 +34987,24 @@ __metadata:
languageName: node
linkType: hard
+"sucrase@npm:^3.31.0":
+ version: 3.35.0
+ resolution: "sucrase@npm:3.35.0"
+ dependencies:
+ "@jridgewell/gen-mapping": "npm:^0.3.2"
+ commander: "npm:^4.0.0"
+ glob: "npm:^10.3.10"
+ lines-and-columns: "npm:^1.1.6"
+ mz: "npm:^2.7.0"
+ pirates: "npm:^4.0.1"
+ ts-interface-checker: "npm:^0.1.9"
+ bin:
+ sucrase: bin/sucrase
+ sucrase-node: bin/sucrase-node
+ checksum: 10c0/ac85f3359d2c2ecbf5febca6a24ae9bf96c931f05fde533c22a94f59c6a74895e5d5f0e871878dfd59c2697a75ebb04e4b2224ef0bfc24ca1210735c2ec191ef
+ languageName: node
+ linkType: hard
+
"sudo-block@npm:^1.1.0":
version: 1.2.0
resolution: "sudo-block@npm:1.2.0"
@@ -35484,6 +35551,24 @@ __metadata:
languageName: node
linkType: hard
+"thenify-all@npm:^1.0.0":
+ version: 1.6.0
+ resolution: "thenify-all@npm:1.6.0"
+ dependencies:
+ thenify: "npm:>= 3.1.0 < 4"
+ checksum: 10c0/9b896a22735e8122754fe70f1d65f7ee691c1d70b1f116fda04fea103d0f9b356e3676cb789506e3909ae0486a79a476e4914b0f92472c2e093d206aed4b7d6b
+ languageName: node
+ linkType: hard
+
+"thenify@npm:>= 3.1.0 < 4":
+ version: 3.3.1
+ resolution: "thenify@npm:3.3.1"
+ dependencies:
+ any-promise: "npm:^1.0.0"
+ checksum: 10c0/f375aeb2b05c100a456a30bc3ed07ef03a39cbdefe02e0403fb714b8c7e57eeaad1a2f5c4ecfb9ce554ce3db9c2b024eba144843cd9e344566d9fcee73b04767
+ languageName: node
+ linkType: hard
+
"throttleit@npm:^1.0.0":
version: 1.0.0
resolution: "throttleit@npm:1.0.0"
@@ -35851,6 +35936,13 @@ __metadata:
languageName: node
linkType: hard
+"ts-interface-checker@npm:^0.1.9":
+ version: 0.1.13
+ resolution: "ts-interface-checker@npm:0.1.13"
+ checksum: 10c0/232509f1b84192d07b81d1e9b9677088e590ac1303436da1e92b296e9be8e31ea042e3e1fd3d29b1742ad2c959e95afe30f63117b8f1bc3a3850070a5142fea7
+ languageName: node
+ linkType: hard
+
"tsconfig-paths@npm:^3.14.1":
version: 3.14.2
resolution: "tsconfig-paths@npm:3.14.2"
@@ -36968,6 +37060,15 @@ __metadata:
languageName: node
linkType: hard
+"use-editable@npm:^2.3.3":
+ version: 2.3.3
+ resolution: "use-editable@npm:2.3.3"
+ peerDependencies:
+ react: ">= 16.8.0"
+ checksum: 10c0/6e8ae63ed0b9ad9a79d1f88992c6a594da0ad3dd1c67da7c12b73722b2a41f787c611dbe9e640f9cee5738168028219ca3c7b4cf739f096cee8069e82968a7b9
+ languageName: node
+ linkType: hard
+
"use-memo-one@npm:^1.1.3":
version: 1.1.3
resolution: "use-memo-one@npm:1.1.3"