From 89102dd391a096814c682d092b0caa9b59524678 Mon Sep 17 00:00:00 2001 From: Lene Gadewoll Date: Wed, 20 Mar 2024 12:22:02 +0100 Subject: [PATCH 1/7] docs(storybook): add stories for EuiMark and EuiMarkdown components --- src/components/mark/mark.stories.tsx | 29 ++++++++ .../markdown_editor.stories.tsx | 72 +++++++++++++++++++ .../markdown_format.stories.tsx | 71 ++++++++++++++++++ 3 files changed, 172 insertions(+) create mode 100644 src/components/mark/mark.stories.tsx create mode 100644 src/components/markdown_editor/markdown_editor.stories.tsx create mode 100644 src/components/markdown_editor/markdown_format.stories.tsx diff --git a/src/components/mark/mark.stories.tsx b/src/components/mark/mark.stories.tsx new file mode 100644 index 00000000000..65edfe8b197 --- /dev/null +++ b/src/components/mark/mark.stories.tsx @@ -0,0 +1,29 @@ +/* + * 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 type { Meta, StoryObj } from '@storybook/react'; + +import { EuiMark, EuiMarkProps } from './mark'; + +const meta: Meta = { + title: 'Utilities/EuiMark', + component: EuiMark, + // Component defaults + args: { + hasScreenReaderHelpText: true, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Playground: Story = { + args: { + children: 'Marked text', + }, +}; diff --git a/src/components/markdown_editor/markdown_editor.stories.tsx b/src/components/markdown_editor/markdown_editor.stories.tsx new file mode 100644 index 00000000000..32add3e8f3d --- /dev/null +++ b/src/components/markdown_editor/markdown_editor.stories.tsx @@ -0,0 +1,72 @@ +/* + * 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 type { Meta, StoryObj } from '@storybook/react'; + +import { EuiMarkdownEditor, EuiMarkdownEditorProps } from './markdown_editor'; +import { + defaultParsingPlugins, + defaultProcessingPlugins, + defaultUiPlugins, +} from './plugins/markdown_default_plugins'; +import { MODE_EDITING, MODE_VIEWING } from './markdown_modes'; + +const initialContent = `## Hello world! + +Basic "GitHub flavored" markdown will work as you'd expect. + +The editor also ships with some built in plugins. For example it can handle checkboxes. Notice how they toggle state even in the preview mode. + +- [ ] Checkboxes +- [x] Can be filled +- [ ] Or empty + +It can also handle emojis! :smile: + +And it can render !{tooltip[tooltips like this](Look! I'm a very helpful tooltip content!)} +`; + +const meta: Meta = { + title: 'Editors & Syntax/EuiMarkdownEditor/EuiMarkdownEditor', + component: EuiMarkdownEditor, + // Component defaults + args: { + height: 250, + maxHeight: 500, + autoExpandPreview: true, + parsingPluginList: defaultParsingPlugins, + processingPluginList: defaultProcessingPlugins, + uiPlugins: defaultUiPlugins, + errors: [], + initialViewMode: MODE_EDITING, + dropHandlers: [], + }, +}; + +export default meta; +type Story = StoryObj; + +export const Playground: Story = { + args: { + value: initialContent, + }, +}; + +export const ViewMode: Story = { + args: { + value: initialContent, + initialViewMode: MODE_VIEWING, + }, +}; + +export const Errors: Story = { + args: { + value: initialContent, + errors: ['An error happened.', 'Woops, another error happened.'], + }, +}; diff --git a/src/components/markdown_editor/markdown_format.stories.tsx b/src/components/markdown_editor/markdown_format.stories.tsx new file mode 100644 index 00000000000..ab1dc710b5a --- /dev/null +++ b/src/components/markdown_editor/markdown_format.stories.tsx @@ -0,0 +1,71 @@ +/* + * 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 type { Meta, StoryObj } from '@storybook/react'; + +import { + hideStorybookControls, + moveStorybookControlsToCategory, +} from '../../../.storybook/utils'; +import { EuiMarkdownFormat, EuiMarkdownFormatProps } from './markdown_format'; +import { + defaultParsingPlugins, + defaultProcessingPlugins, +} from './plugins/markdown_default_plugins'; +import { ALIGNMENTS } from '../text/text_align'; + +const initialContent = `## Hello world! + +Basic "GitHub flavored" markdown will work as you'd expect. + +The editor also ships with some built in plugins. For example it can handle checkboxes. Notice how they toggle state even in the preview mode. + +- [ ] Checkboxes +- [x] Can be filled +- [ ] Or empty + +It can also handle emojis! :smile: + +And it can render !{tooltip[tooltips like this](Look! I'm a very helpful tooltip content!)} +`; + +const meta: Meta = { + title: 'Editors & Syntax/EuiMarkdownEditor/EuiMarkdownFormat', + component: EuiMarkdownFormat, + argTypes: { + color: { control: { type: 'text' } }, + grow: { control: { type: 'boolean' } }, + textAlign: { + control: { type: 'radio' }, + options: [undefined, ...ALIGNMENTS], + }, + }, + // Component defaults + args: { + textSize: 'm', + parsingPluginList: defaultParsingPlugins, + processingPluginList: defaultProcessingPlugins, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Playground: Story = { + // TODO: move this to the component level once utils are updated to fully support merged configs (#7583) + argTypes: { + ...moveStorybookControlsToCategory( + ['textAlign', 'color', 'grow'], + 'EuiText props' + ), + ...hideStorybookControls(['aria-label']), + }, + args: { + children: initialContent, + }, +}; From aee8eb9785a283bae7712f26188f49c5b42ca4f5 Mon Sep 17 00:00:00 2001 From: Lene Gadewoll Date: Wed, 20 Mar 2024 12:22:56 +0100 Subject: [PATCH 2/7] docs(storybook): add stories for EuiMutationObserver - renaming of component file to ensure props are read by Storybook --- .../mutation_observer.stories.tsx | 96 +++++++++++++++++++ ...tion_observer.ts => mutation_observer.tsx} | 0 2 files changed, 96 insertions(+) create mode 100644 src/components/observer/mutation_observer/mutation_observer.stories.tsx rename src/components/observer/mutation_observer/{mutation_observer.ts => mutation_observer.tsx} (100%) diff --git a/src/components/observer/mutation_observer/mutation_observer.stories.tsx b/src/components/observer/mutation_observer/mutation_observer.stories.tsx new file mode 100644 index 00000000000..224ae201a06 --- /dev/null +++ b/src/components/observer/mutation_observer/mutation_observer.stories.tsx @@ -0,0 +1,96 @@ +/* + * 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 React, { useState } from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; + +import { _EuiButtonColor } from '../../../themes/amsterdam/global_styling/mixins'; +import { EuiFlexGroup, EuiFlexItem } from '../../flex'; +import { EuiSpacer } from '../../spacer'; +import { EuiButton, EuiButtonEmpty } from '../../button'; +import { EuiPanel } from '../../panel'; +import { + EuiMutationObserver, + EuiMutationObserverProps, +} from './mutation_observer'; + +const meta: Meta = { + title: 'Utilities/EuiMutationObserver', + component: EuiMutationObserver, +}; + +export default meta; +type Story = StoryObj; + +const StatefulPlayground = ( + props: Omit +) => { + const [lastMutation, setLastMutation] = useState('no changes detected'); + const [buttonColor, setButtonColor] = useState<_EuiButtonColor>('primary'); + const [items, setItems] = useState(['Item 1', 'Item 2', 'Item 3']); + + const toggleButtonColor = () => { + setButtonColor(buttonColor === 'primary' ? 'warning' : 'primary'); + }; + + const addItem = () => { + setItems([...items, `Item ${items.length + 1}`]); + }; + + const handleOnMutation = ([{ type }]: MutationRecord[]) => { + setLastMutation( + type === 'attributes' ? 'button class name changed' : 'DOM tree changed' + ); + }; + + return ( + <> +

{lastMutation}

+ + + + + {(mutationRef) => ( +
+ + Toggle button color + + + + + + + +
    + {items.map((item) => ( +
  • {item}
  • + ))} +
+ + add item +
+
+
+
+ )} +
+ + ); +}; + +export const Playground: Story = { + render: ({ ...args }) => , +}; diff --git a/src/components/observer/mutation_observer/mutation_observer.ts b/src/components/observer/mutation_observer/mutation_observer.tsx similarity index 100% rename from src/components/observer/mutation_observer/mutation_observer.ts rename to src/components/observer/mutation_observer/mutation_observer.tsx From bbe232e2d4f5ad35c0a70b8d4eb33f429dc85d87 Mon Sep 17 00:00:00 2001 From: Lene Gadewoll Date: Wed, 20 Mar 2024 12:24:47 +0100 Subject: [PATCH 3/7] docs(storybook): add stories for EuiResizeObserver --- .../resize_observer.stories.tsx | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 src/components/observer/resize_observer/resize_observer.stories.tsx diff --git a/src/components/observer/resize_observer/resize_observer.stories.tsx b/src/components/observer/resize_observer/resize_observer.stories.tsx new file mode 100644 index 00000000000..a7b84780c5d --- /dev/null +++ b/src/components/observer/resize_observer/resize_observer.stories.tsx @@ -0,0 +1,94 @@ +/* + * 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 React, { useState } from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; + +import { EuiPaddingSize } from '../../../global_styling'; +import { EuiText } from '../../text'; +import { EuiCode } from '../../code'; +import { EuiSpacer } from '../../spacer'; +import { EuiButton, EuiButtonEmpty } from '../../button'; +import { EuiPanel } from '../../panel'; +import { EuiResizeObserver, EuiResizeObserverProps } from './resize_observer'; + +const meta: Meta = { + title: 'Utilities/EuiResizeObserver', + component: EuiResizeObserver, +}; + +export default meta; +type Story = StoryObj; + +const StatefulPlayground = (props: EuiResizeObserverProps) => { + const { onResize, ...rest } = props; + const [paddingSize, setPaddingSize] = useState('s'); + const [items, setItems] = useState(['Item 1', 'Item 2', 'Item 3']); + const [height, setHeight] = useState(0); + const [width, setWidth] = useState(0); + + const togglePaddingSize = () => { + setPaddingSize((paddingSize) => (paddingSize === 's' ? 'l' : 's')); + }; + + const addItem = () => { + setItems((items) => [...items, `Item ${items.length + 1}`]); + }; + + const handleOnResize = ({ + height, + width, + }: { + height: number; + width: number; + }) => { + setHeight(height); + setWidth(width); + onResize({ height, width }); + }; + + return ( + <> + +

+ + height: {height}; width: {width} + +

+
+ + + + + Toggle container padding + + + + + + {(resizeRef) => ( +
+ +
    + {items.map((item) => ( +
  • {item}
  • + ))} +
+ + add item +
+
+ )} +
+ + ); +}; + +export const Playground: Story = { + render: ({ ...args }) => , +}; From 82a4d168e2c85d7696291218c254ceec405760ab Mon Sep 17 00:00:00 2001 From: Lene Gadewoll Date: Wed, 20 Mar 2024 12:25:44 +0100 Subject: [PATCH 4/7] docs(storybook): add stories for EuiOutsideClickDetector - renaming of component file to ensure props are read by Storybook --- .../outside_click_detector.stories.tsx | 38 +++++++++++++++++++ ...detector.ts => outside_click_detector.tsx} | 0 2 files changed, 38 insertions(+) create mode 100644 src/components/outside_click_detector/outside_click_detector.stories.tsx rename src/components/outside_click_detector/{outside_click_detector.ts => outside_click_detector.tsx} (100%) diff --git a/src/components/outside_click_detector/outside_click_detector.stories.tsx b/src/components/outside_click_detector/outside_click_detector.stories.tsx new file mode 100644 index 00000000000..45cd6f005de --- /dev/null +++ b/src/components/outside_click_detector/outside_click_detector.stories.tsx @@ -0,0 +1,38 @@ +/* + * 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 React from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; + +import { EuiText } from '../text'; +import { + EuiOutsideClickDetector, + EuiOutsideClickDetectorProps, +} from './outside_click_detector'; + +const meta: Meta = { + title: 'Utilities/EuiOutsideClickDetector', + component: EuiOutsideClickDetector, +}; + +export default meta; +type Story = StoryObj; + +export const Playground: Story = { + args: { + children: ( + +

Click anywhere outside of this text to trigger an alert

+
+ ), + onOutsideClick: () => { + window.alert('Clicked outside'); + }, + }, + render: (args) => , +}; diff --git a/src/components/outside_click_detector/outside_click_detector.ts b/src/components/outside_click_detector/outside_click_detector.tsx similarity index 100% rename from src/components/outside_click_detector/outside_click_detector.ts rename to src/components/outside_click_detector/outside_click_detector.tsx From a181db16e8d59fbf4714ee731cd5e4466ec6ef1f Mon Sep 17 00:00:00 2001 From: Lene Gadewoll Date: Wed, 20 Mar 2024 16:51:58 +0100 Subject: [PATCH 5/7] chore(storybook): update usage of ...args to just args --- .../observer/mutation_observer/mutation_observer.stories.tsx | 2 +- .../observer/resize_observer/resize_observer.stories.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/observer/mutation_observer/mutation_observer.stories.tsx b/src/components/observer/mutation_observer/mutation_observer.stories.tsx index 224ae201a06..96794764fc1 100644 --- a/src/components/observer/mutation_observer/mutation_observer.stories.tsx +++ b/src/components/observer/mutation_observer/mutation_observer.stories.tsx @@ -92,5 +92,5 @@ const StatefulPlayground = ( }; export const Playground: Story = { - render: ({ ...args }) => , + render: (args) => , }; diff --git a/src/components/observer/resize_observer/resize_observer.stories.tsx b/src/components/observer/resize_observer/resize_observer.stories.tsx index a7b84780c5d..885e4ff114c 100644 --- a/src/components/observer/resize_observer/resize_observer.stories.tsx +++ b/src/components/observer/resize_observer/resize_observer.stories.tsx @@ -90,5 +90,5 @@ const StatefulPlayground = (props: EuiResizeObserverProps) => { }; export const Playground: Story = { - render: ({ ...args }) => , + render: (args) => , }; From 7b0896abc4d32423f3083456186aebc77f2dc01a Mon Sep 17 00:00:00 2001 From: Lene Gadewoll Date: Fri, 22 Mar 2024 11:05:01 +0100 Subject: [PATCH 6/7] docs(storybook): PR feedback -fix EuiMutationObserver playground to properly show mutations update EuiOutsideClickDetector playground story to use text input for children and ensure onOutsideClick triggers an action --- .../mutation_observer.stories.tsx | 16 +++++++---- .../outside_click_detector.stories.tsx | 27 ++++++++++++++----- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/components/observer/mutation_observer/mutation_observer.stories.tsx b/src/components/observer/mutation_observer/mutation_observer.stories.tsx index 96794764fc1..51f7394b875 100644 --- a/src/components/observer/mutation_observer/mutation_observer.stories.tsx +++ b/src/components/observer/mutation_observer/mutation_observer.stories.tsx @@ -27,9 +27,10 @@ const meta: Meta = { export default meta; type Story = StoryObj; -const StatefulPlayground = ( - props: Omit -) => { +const StatefulPlayground = ({ + onMutation, + ...rest +}: EuiMutationObserverProps) => { const [lastMutation, setLastMutation] = useState('no changes detected'); const [buttonColor, setButtonColor] = useState<_EuiButtonColor>('primary'); const [items, setItems] = useState(['Item 1', 'Item 2', 'Item 3']); @@ -42,10 +43,15 @@ const StatefulPlayground = ( setItems([...items, `Item ${items.length + 1}`]); }; - const handleOnMutation = ([{ type }]: MutationRecord[]) => { + const handleOnMutation = ( + mutationRecords: MutationRecord[], + mutationObserver: MutationObserver + ) => { + const [{ type }] = mutationRecords; setLastMutation( type === 'attributes' ? 'button class name changed' : 'DOM tree changed' ); + onMutation(mutationRecords, mutationObserver); }; return ( @@ -57,7 +63,7 @@ const StatefulPlayground = ( {(mutationRef) => (
diff --git a/src/components/outside_click_detector/outside_click_detector.stories.tsx b/src/components/outside_click_detector/outside_click_detector.stories.tsx index 45cd6f005de..4dbded25f6e 100644 --- a/src/components/outside_click_detector/outside_click_detector.stories.tsx +++ b/src/components/outside_click_detector/outside_click_detector.stories.tsx @@ -8,6 +8,7 @@ import React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; +import { action } from '@storybook/addon-actions'; import { EuiText } from '../text'; import { @@ -18,6 +19,9 @@ import { const meta: Meta = { title: 'Utilities/EuiOutsideClickDetector', component: EuiOutsideClickDetector, + argTypes: { + children: { control: { type: 'text' } }, + }, }; export default meta; @@ -25,14 +29,23 @@ type Story = StoryObj; export const Playground: Story = { args: { - children: ( - -

Click anywhere outside of this text to trigger an alert

-
- ), - onOutsideClick: () => { + children: + // cast type here to ensure the control table and output are connected and useful + // TODO: remove once the control table can handle more complex types + 'Click anywhere outside of this text to trigger an alert' as unknown as any, + onOutsideClick: (e: Event) => { + action('onOutsideClick')(e); window.alert('Clicked outside'); }, }, - render: (args) => , + render: ({ children, ...rest }: EuiOutsideClickDetectorProps) => { + const content = ( + +

{children}

+
+ ); + return ( + {content} + ); + }, }; From 76ab339ba1617dd3abb2f01dca3ba20a83a9c777 Mon Sep 17 00:00:00 2001 From: Lene Gadewoll Date: Fri, 22 Mar 2024 11:05:30 +0100 Subject: [PATCH 7/7] docs(storybook): PR feedback & cleanup --- src/components/markdown_editor/markdown_format.stories.tsx | 2 +- .../observer/resize_observer/resize_observer.stories.tsx | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/markdown_editor/markdown_format.stories.tsx b/src/components/markdown_editor/markdown_format.stories.tsx index ab1dc710b5a..1092ffba1a7 100644 --- a/src/components/markdown_editor/markdown_format.stories.tsx +++ b/src/components/markdown_editor/markdown_format.stories.tsx @@ -44,6 +44,7 @@ const meta: Meta = { control: { type: 'radio' }, options: [undefined, ...ALIGNMENTS], }, + ...hideStorybookControls(['aria-label']), }, // Component defaults args: { @@ -63,7 +64,6 @@ export const Playground: Story = { ['textAlign', 'color', 'grow'], 'EuiText props' ), - ...hideStorybookControls(['aria-label']), }, args: { children: initialContent, diff --git a/src/components/observer/resize_observer/resize_observer.stories.tsx b/src/components/observer/resize_observer/resize_observer.stories.tsx index 885e4ff114c..f2baa73e127 100644 --- a/src/components/observer/resize_observer/resize_observer.stories.tsx +++ b/src/components/observer/resize_observer/resize_observer.stories.tsx @@ -25,8 +25,7 @@ const meta: Meta = { export default meta; type Story = StoryObj; -const StatefulPlayground = (props: EuiResizeObserverProps) => { - const { onResize, ...rest } = props; +const StatefulPlayground = ({ onResize, ...rest }: EuiResizeObserverProps) => { const [paddingSize, setPaddingSize] = useState('s'); const [items, setItems] = useState(['Item 1', 'Item 2', 'Item 3']); const [height, setHeight] = useState(0);