From a7bf2ef91684ba89aeb991e0d6473af0a6d8ce5f Mon Sep 17 00:00:00 2001 From: Lene Gadewoll Date: Tue, 16 Apr 2024 11:53:16 +0200 Subject: [PATCH 01/12] docs(storybook): add stories for EuiResizableContainer and Panel --- .../resizeable_container.stories.tsx | 229 ++++++++++++++++++ .../resizeable_panel.stories.tsx | 99 ++++++++ 2 files changed, 328 insertions(+) create mode 100644 src/components/resizable_container/resizeable_container.stories.tsx create mode 100644 src/components/resizable_container/resizeable_panel.stories.tsx diff --git a/src/components/resizable_container/resizeable_container.stories.tsx b/src/components/resizable_container/resizeable_container.stories.tsx new file mode 100644 index 00000000000..eced7b903a2 --- /dev/null +++ b/src/components/resizable_container/resizeable_container.stories.tsx @@ -0,0 +1,229 @@ +/* + * 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 { enableFunctionToggleControls } from '../../../.storybook/utils'; +import { EuiText } from '../text'; +import { + EuiResizableContainer, + EuiResizableContainerProps, +} from './resizable_container'; + +// using static text over '@faker-js/faker' to ensure same output in regards to VRT +const placeholderText = ( +

+ Autem vitae quibusdam iure aspernatur nobis. Illo dicta debitis aperiam. + Assumenda dicta saepe corrupti tempora. Nobis nihil ipsum esse eius + perspiciatis velit maiores architecto earum. Minus ipsam dignissimos + voluptatem eos ipsa. Laudantium eius porro autem impedit voluptatibus + accusamus qui adipisci. +

+); + +const TwoColumns: EuiResizableContainerProps['children'] = ( + EuiResizablePanel, + EuiResizableButton +) => ( + <> + + + {placeholderText} + {placeholderText} + {placeholderText} + + + + + + + + {placeholderText} + {placeholderText} + {placeholderText} + + + +); + +const ThreeColumns: EuiResizableContainerProps['children'] = ( + EuiResizablePanel, + EuiResizableButton +) => ( + <> + + + {placeholderText} + {placeholderText} + {placeholderText} + + + + + + + + {placeholderText} + {placeholderText} + {placeholderText} + + + + + + + + {placeholderText} + {placeholderText} + {placeholderText} + + + +); + +const WithMinSize: EuiResizableContainerProps['children'] = ( + EuiResizablePanel, + EuiResizableButton +) => ( + <> + + + {placeholderText} + {placeholderText} + {placeholderText} + + + + + + + + {placeholderText} + {placeholderText} + {placeholderText} + + + +); + +const SingleCollapsible: EuiResizableContainerProps['children'] = ( + EuiResizablePanel, + EuiResizableButton +) => ( + <> + + + {placeholderText} + {placeholderText} + {placeholderText} + + + + + + + + {placeholderText} + {placeholderText} + {placeholderText} + + + +); + +const MultiCollapsible: EuiResizableContainerProps['children'] = ( + EuiResizablePanel, + EuiResizableButton +) => ( + <> + + + {placeholderText} + {placeholderText} + {placeholderText} + + + + + + + + {placeholderText} + {placeholderText} + {placeholderText} + + + + + + + + {placeholderText} + {placeholderText} + {placeholderText} + + + +); + +const meta: Meta = { + title: 'Layout/EuiResizableContainer/EuiResizableContainer', + component: EuiResizableContainer, + args: { + direction: 'horizontal', + }, +}; +enableFunctionToggleControls(meta, [ + 'onPanelWidthChange', + 'onToggleCollapsed', + 'onResizeStart', + 'onResizeEnd', +]); + +export default meta; +type Story = StoryObj; + +export const Playground: Story = { + argTypes: { + children: { + control: 'select', + options: ['2 columns', '3 columns', 'With MinSize'], + description: + 'Select an option to show examples using EuiResizablePanel and EuiResizableButton', + mapping: { + '2 columns': TwoColumns, + '3 columns': ThreeColumns, + 'With MinSize': WithMinSize, + }, + }, + }, + args: { + children: '2 columns' as unknown as any, // overwriting expected type to use children select control instead of function + style: { height: '50vh' }, + }, +}; + +export const CollapsiblePanels: Story = { + argTypes: { + children: { + control: 'radio', + options: ['Single', 'Multiple'], + description: + 'Select an option to show examples of EuiResizablePanel with mode={"collapsible" | "main"}. Click the resizable button element to collapse a column.', + mapping: { + Single: SingleCollapsible, + Multiple: MultiCollapsible, + }, + }, + }, + args: { + children: 'Single' as unknown as any, + style: { height: '50vh' }, + }, +}; diff --git a/src/components/resizable_container/resizeable_panel.stories.tsx b/src/components/resizable_container/resizeable_panel.stories.tsx new file mode 100644 index 00000000000..d48360f72ad --- /dev/null +++ b/src/components/resizable_container/resizeable_panel.stories.tsx @@ -0,0 +1,99 @@ +/* + * 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 { + disableStorybookControls, + moveStorybookControlsToCategory, +} from '../../../.storybook/utils'; +import { EuiResizableContainer } from './resizable_container'; +import { EuiResizablePanel, EuiResizablePanelProps } from './resizable_panel'; +import { css } from '@emotion/react'; + +const meta: Meta = { + title: 'Layout/EuiResizableContainer/EuiResizablePanel', + component: EuiResizablePanel, + argTypes: { + mode: { + control: 'radio', + description: + 'For use with collapsible panels. Will only be applied when used within EuiResizableContainer. View EuiResizableContainer stories for an example.', + options: [undefined, 'collapsible', 'main', 'custom'], + }, + }, + args: { + minSize: '0px', + scrollable: true, + hasShadow: false, + borderRadius: 'none', + color: 'transparent', + paddingSize: 'm', + wrapperPadding: 'none', + // for quicker/easier QA + grow: false, + hasBorder: false, + }, +}; +disableStorybookControls(meta, ['panelRef']); +moveStorybookControlsToCategory( + meta, + [ + 'color', + 'borderRadius', + 'grow', + 'hasBorder', + 'hasShadow', + 'paddingSize', + 'panelRef', + ], + 'EuiPanel props' +); + +export default meta; +type Story = StoryObj; + +export const Playground: Story = { + args: { + children: + 'Autem vitae quibusdam iure aspernatur nobis. Illo dicta debitis aperiam. Assumenda dicta saepe corrupti tempora.', + initialSize: 100, + }, + render: ({ mode, children, ...rest }) => { + const placeholderMode = + mode === 'collapsible' + ? 'main' + : mode === 'main' + ? 'collapsible' + : 'custom'; + return ( + + {(EuiResizablePanel, EuiResizableButton) => ( + <> + + {children} + + + {/* NOTE: using the second panel only to ensure functionality, visually not required */} + + {children} + + + )} + + ); + }, +}; From d550554112e50b3d37eed17cf34e8629f0be7c75 Mon Sep 17 00:00:00 2001 From: Lene Gadewoll Date: Tue, 16 Apr 2024 11:54:21 +0200 Subject: [PATCH 02/12] refactor(EuiFieldSearch): add onClear prop --- src/components/form/field_search/field_search.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/form/field_search/field_search.tsx b/src/components/form/field_search/field_search.tsx index b3c9bc595ef..edc0fea0e65 100644 --- a/src/components/form/field_search/field_search.tsx +++ b/src/components/form/field_search/field_search.tsx @@ -55,6 +55,10 @@ export interface EuiFieldSearchProps * Shows a button that quickly clears any input */ isClearable?: boolean; + /** + * Called when the onClear button is pressed. + */ + onClear?: () => void; /** * Creates an input group with element(s) coming before input * `string` | `ReactElement` or an array of these @@ -161,11 +165,13 @@ export class EuiFieldSearch extends Component< } this.setState({ value: '' }); - const { incremental, onSearch } = this.props; + const { incremental, onSearch, onClear } = this.props; if (onSearch && incremental) { onSearch(''); } + + onClear?.(); }; componentWillUnmount() { @@ -217,6 +223,7 @@ export class EuiFieldSearch extends Component< compressed, onSearch, isClearable: _isClearable, + onClear, append, prepend, ...rest From a0973120f66ae5c7400d2baaef79ec4c99c99811 Mon Sep 17 00:00:00 2001 From: Lene Gadewoll Date: Tue, 16 Apr 2024 11:55:20 +0200 Subject: [PATCH 03/12] docs(storybook): add EuiSearchBar and EuiSearchBarFilters stories --- .../search_bar/search_bar.stories.tsx | 343 ++++++++++++++++++ .../search_bar/search_bar_filters.stories.tsx | 96 +++++ src/components/search_bar/search_filters.tsx | 2 +- 3 files changed, 440 insertions(+), 1 deletion(-) create mode 100644 src/components/search_bar/search_bar.stories.tsx create mode 100644 src/components/search_bar/search_bar_filters.stories.tsx diff --git a/src/components/search_bar/search_bar.stories.tsx b/src/components/search_bar/search_bar.stories.tsx new file mode 100644 index 00000000000..d57734cf541 --- /dev/null +++ b/src/components/search_bar/search_bar.stories.tsx @@ -0,0 +1,343 @@ +/* + * 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 { enableFunctionToggleControls } from '../../../.storybook/utils'; +import { EuiBasicTable } from '../basic_table'; +import { EuiButton } from '../button'; +import { EuiCallOut } from '../call_out'; +import { EuiHealth } from '../health'; +import { EuiSpacer } from '../spacer'; +import { EuiText } from '../text'; +import { + EuiSearchBarOnChangeArgs, + EuiSearchBar, + EuiSearchBarProps, +} from './search_bar'; + +const tags = [ + { name: 'marketing', color: 'danger' }, + { name: 'finance', color: 'success' }, + { name: 'eng', color: 'success' }, + { name: 'sales', color: 'warning' }, + { name: 'ga', color: 'success' }, +]; + +const items = [ + { + type: 'watch', + status: 'open', + active: false, + tag: ['finance'], + owner: 'wanda', + stars: 2, + followers: 10, + comments: 3, + }, + { + type: 'visualization', + status: 'closed', + active: true, + tag: ['ga', 'marketing', 'eng'], + owner: 'carrie', + stars: 2, + followers: 7, + comments: 2, + }, + { + type: 'watch', + open: 'open', + active: true, + tag: [], + owner: 'carrie', + stars: 4, + followers: 2, + comments: 10, + }, + { + type: 'visualization', + open: 'open', + active: false, + tag: ['eng'], + owner: 'dewey', + stars: 5, + followers: 2, + comments: 8, + }, + { + type: 'dashboard', + open: 'closed', + active: false, + tag: ['sales', 'marketing', 'ga'], + owner: 'gabic', + stars: 1, + followers: 13, + comments: 1, + }, +]; + +const meta: Meta = { + title: 'Forms/EuiSearchBar/EuiSearchBar', + component: EuiSearchBar, + argTypes: { + toolsLeft: { + control: 'boolean', + description: 'Toogle the control to display an example for left tools', + mapping: { + true: Left tools button, + false: undefined, + }, + }, + toolsRight: { + control: 'boolean', + description: 'Toogle the control to display an example for right tools', + mapping: { + true: Right tools button, + false: undefined, + }, + }, + }, +}; +enableFunctionToggleControls(meta, ['onChange']); + +export default meta; +type Story = StoryObj; + +export const Playground: Story = { + args: { + // setting up props for easier testing/QA + dateFormat: {}, + defaultQuery: '', + query: '', + box: { + placeholder: 'Enter a search term or query...', + incremental: false, + schema: { + strict: true, + fields: { + type: { + type: 'string', + }, + active: { + type: 'boolean', + }, + status: { + type: 'string', + }, + followers: { + type: 'number', + }, + comments: { + type: 'number', + }, + stars: { + type: 'number', + }, + owner: { + type: 'string', + }, + tag: { + type: 'string', + validate: (value: string) => { + if (value !== '' && !tags.some((tag) => tag.name === value)) { + throw new Error( + `unknown tag (possible values: ${tags + .map((tag) => tag.name) + .join(',')})` + ); + } + }, + }, + }, + }, + }, + hint: { + content: '', + popoverProps: {}, + }, + filters: [ + { + type: 'field_value_toggle_group', + field: 'status', + items: [ + { + value: 'open', + name: 'Open', + }, + { + value: 'closed', + name: 'Closed', + }, + ], + }, + { + type: 'is', + field: 'active', + name: 'Active', + negatedName: 'Inactive', + }, + { + type: 'field_value_toggle', + name: 'Mine', + field: 'owner', + value: 'dewey', + }, + { + type: 'field_value_toggle', + name: 'Popular', + field: 'followers', + value: 5, + operator: 'gt', + }, + { + type: 'field_value_selection', + field: 'tag', + name: 'Tag', + multiSelect: 'or', + operator: 'exact', + cache: 10000, // will cache the loaded tags for 10 sec + options: () => + new Promise((resolve) => { + setTimeout(() => { + resolve( + tags.map((tag) => ({ + value: tag.name, + view: {tag.name}, + })) + ); + }, 2000); + }), + }, + ], + // casting to any to allow for easier teasting/QA via toggle switch + toolsLeft: false as any, + toolsRight: false as any, + }, + render: (args) => , +}; + +const StatefulSearchBar = (args: EuiSearchBarProps) => { + const { query, defaultQuery, box, hint } = args; + + const [_query, setQuery] = useState( + query ?? defaultQuery ?? EuiSearchBar.Query.MATCH_ALL + ); + const [error, setError] = useState(null); + const showHint = !!hint?.content; + + const onChange = ({ query, error }: EuiSearchBarOnChangeArgs) => { + if (error) { + setError(error); + } else { + setError(null); + setQuery(query); + } + }; + + const handleOnClear = () => { + setQuery(EuiSearchBar.Query.MATCH_ALL); + }; + + const renderSearch = () => { + return ( + {hint.content}, + popoverProps: hint.popoverProps ?? {}, + } + : undefined + } + /> + ); + }; + + const renderError = () => { + if (!error) { + return; + } + return ( + <> + + + + ); + }; + + const renderTable = () => { + const columns = [ + { + name: 'Type', + field: 'type', + }, + { + name: 'Open', + field: 'status', + render: (status: string) => (status === 'open' ? 'Yes' : 'No'), + }, + { + name: 'Active', + field: 'active', + }, + { + name: 'Tags', + field: 'tag', + }, + { + name: 'Owner', + field: 'owner', + }, + { + name: 'Stats', + width: '150px', + render: (item: (typeof items)[0]) => { + return ( +
+
{`${item.stars} Stars`}
+
{`${item.followers} Followers`}
+
{`${item.comments} Comments`}
+
+ ); + }, + }, + ]; + + const queriedItems = EuiSearchBar.Query.execute(_query, items, { + defaultFields: ['owner', 'tag', 'type'], + }); + + return ; + }; + return ( + renderError() || ( + <> + {renderSearch()} + + +

Example data output

+
+ + {renderTable()} + + ) + ); +}; diff --git a/src/components/search_bar/search_bar_filters.stories.tsx b/src/components/search_bar/search_bar_filters.stories.tsx new file mode 100644 index 00000000000..e4897b9e223 --- /dev/null +++ b/src/components/search_bar/search_bar_filters.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 from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; + +import { enableFunctionToggleControls } from '../../../.storybook/utils'; +import { EuiHealth } from '../health'; +import { + EuiSearchBarFilters, + EuiSearchBarFiltersProps, +} from './search_filters'; +import { Query } from './query'; + +const tags = [ + { name: 'marketing', color: 'danger' }, + { name: 'finance', color: 'success' }, + { name: 'eng', color: 'success' }, + { name: 'sales', color: 'warning' }, + { name: 'ga', color: 'success' }, +]; + +const meta: Meta = { + title: 'Forms/EuiSearchBar/EuiSearchBarFilters', + component: EuiSearchBarFilters, +}; +enableFunctionToggleControls(meta, ['onChange']); + +export default meta; +type Story = StoryObj; + +export const Playground: Story = { + args: { + filters: [ + { + type: 'field_value_toggle_group', + field: 'status', + items: [ + { + value: 'open', + name: 'Open', + }, + { + value: 'closed', + name: 'Closed', + }, + ], + }, + { + type: 'is', + field: 'active', + name: 'Active', + negatedName: 'Inactive', + }, + { + type: 'field_value_toggle', + name: 'Mine', + field: 'owner', + value: 'dewey', + }, + { + type: 'field_value_toggle', + name: 'Popular', + field: 'followers', + value: 5, + operator: 'gt', + }, + { + type: 'field_value_selection', + field: 'tag', + name: 'Tag', + multiSelect: 'or', + operator: 'exact', + cache: 10000, // will cache the loaded tags for 10 sec + options: () => + new Promise((resolve) => { + setTimeout(() => { + resolve( + tags.map((tag) => ({ + value: tag.name, + view: {tag.name}, + })) + ); + }, 2000); + }), + }, + ], + // setting up props for easier testing/QA + query: Query.parse(''), + }, +}; diff --git a/src/components/search_bar/search_filters.tsx b/src/components/search_bar/search_filters.tsx index 242624379e4..3b66d4228c2 100644 --- a/src/components/search_bar/search_filters.tsx +++ b/src/components/search_bar/search_filters.tsx @@ -13,7 +13,7 @@ import { EuiFilterGroup } from '../filter_group'; export type { SearchFilterConfig } from './filters'; -interface EuiSearchBarFiltersProps { +export interface EuiSearchBarFiltersProps { query: Query; onChange: (query: Query) => void; filters: SearchFilterConfig[]; From 922b382f96402627a83b0cf7e322d54c0ec700bd Mon Sep 17 00:00:00 2001 From: Lene Gadewoll Date: Tue, 16 Apr 2024 11:56:05 +0200 Subject: [PATCH 04/12] docs(storybook): add stories for EuiShowFor, EuiSpacer and EuiStat --- .../responsive/show_for.stories.tsx | 27 +++++++++++ src/components/spacer/spacer.stories.tsx | 47 +++++++++++++++++++ src/components/stat/stat.stories.tsx | 38 +++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 src/components/responsive/show_for.stories.tsx create mode 100644 src/components/spacer/spacer.stories.tsx create mode 100644 src/components/stat/stat.stories.tsx diff --git a/src/components/responsive/show_for.stories.tsx b/src/components/responsive/show_for.stories.tsx new file mode 100644 index 00000000000..925af7b8b93 --- /dev/null +++ b/src/components/responsive/show_for.stories.tsx @@ -0,0 +1,27 @@ +/* + * 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 { EuiShowFor, EuiShowForProps } from './show_for'; + +const meta: Meta = { + title: 'Utilities/EuiShowFor', + component: EuiShowFor, +}; + +export default meta; +type Story = StoryObj; + +export const Playground: Story = { + args: { + sizes: ['l'], + children: + 'Try changing the Storybook viewport, or adding the `s` size, to see how it affects the visibility of this text.', + }, +}; diff --git a/src/components/spacer/spacer.stories.tsx b/src/components/spacer/spacer.stories.tsx new file mode 100644 index 00000000000..094aa00b582 --- /dev/null +++ b/src/components/spacer/spacer.stories.tsx @@ -0,0 +1,47 @@ +/* + * 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 { EuiSpacer, EuiSpacerProps } from './spacer'; + +const meta: Meta = { + title: 'Layout/EuiSpacer', + component: EuiSpacer, + decorators: [ + (Story) => ( + <> + +

Observe the space created between this and the next text block.

+
+
({ + backgroundColor: euiTheme.colors.lightShade, + })} + > + +
+ +

+ Observe the space created between this and the previous text block. +

+
+ + ), + ], + args: { + size: 'l', + }, +}; + +export default meta; +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/src/components/stat/stat.stories.tsx b/src/components/stat/stat.stories.tsx new file mode 100644 index 00000000000..ad0d37cbe74 --- /dev/null +++ b/src/components/stat/stat.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 type { Meta, StoryObj } from '@storybook/react'; + +import { EuiStat, EuiStatProps } from './stat'; + +const meta: Meta = { + title: 'Display/EuiStat', + component: EuiStat, + argTypes: { + title: { control: 'text' }, + }, + args: { + textAlign: 'left', + titleColor: 'default', + titleSize: 'l', + titleElement: 'p', + descriptionElement: 'p', + isLoading: false, + reverse: false, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Playground: Story = { + args: { + title: '999,999', + description: 'description', + }, +}; From 04724930191b7fd43b942bceff980068f1c4dd83 Mon Sep 17 00:00:00 2001 From: Lene Gadewoll Date: Tue, 16 Apr 2024 11:56:37 +0200 Subject: [PATCH 05/12] docs(storybook): cleanup and improvements --- src/components/page_template/page_template.stories.tsx | 3 --- src/components/side_nav/side_nav.stories.tsx | 2 ++ 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/page_template/page_template.stories.tsx b/src/components/page_template/page_template.stories.tsx index b97f43be46b..c53344e18ca 100644 --- a/src/components/page_template/page_template.stories.tsx +++ b/src/components/page_template/page_template.stories.tsx @@ -148,7 +148,4 @@ export const Playground: Story = { }, }, }, - // using render() over args to ensure dynamic update on prop changes - // Cee TODO: This doesn't appear to work for the `paddingSize` and `bottomBorder` props - // render: ({ ...args }) => , }; diff --git a/src/components/side_nav/side_nav.stories.tsx b/src/components/side_nav/side_nav.stories.tsx index 75e800ee4f9..d473c74c7fe 100644 --- a/src/components/side_nav/side_nav.stories.tsx +++ b/src/components/side_nav/side_nav.stories.tsx @@ -11,6 +11,7 @@ import type { Meta, StoryObj } from '@storybook/react'; import { hideStorybookControls, disableStorybookControls, + enableFunctionToggleControls, } from '../../../.storybook/utils'; import { EuiIcon } from '../icon'; @@ -37,6 +38,7 @@ const meta: Meta = { ], }; disableStorybookControls(meta, ['children']); +enableFunctionToggleControls(meta, ['toggleOpenOnMobile']); export default meta; type Story = StoryObj; From abddb1a7b1ba4fbe0aa37e4339ec361112100949 Mon Sep 17 00:00:00 2001 From: Lene Gadewoll Date: Tue, 16 Apr 2024 12:08:03 +0200 Subject: [PATCH 06/12] docs(storybook): ensure proper Query types are passed as state --- src/components/search_bar/search_bar.stories.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/search_bar/search_bar.stories.tsx b/src/components/search_bar/search_bar.stories.tsx index d57734cf541..c7295c31c87 100644 --- a/src/components/search_bar/search_bar.stories.tsx +++ b/src/components/search_bar/search_bar.stories.tsx @@ -20,6 +20,7 @@ import { EuiSearchBarOnChangeArgs, EuiSearchBar, EuiSearchBarProps, + QueryType, } from './search_bar'; const tags = [ @@ -226,7 +227,7 @@ export const Playground: Story = { const StatefulSearchBar = (args: EuiSearchBarProps) => { const { query, defaultQuery, box, hint } = args; - const [_query, setQuery] = useState( + const [_query, setQuery] = useState( query ?? defaultQuery ?? EuiSearchBar.Query.MATCH_ALL ); const [error, setError] = useState(null); @@ -237,7 +238,7 @@ const StatefulSearchBar = (args: EuiSearchBarProps) => { setError(error); } else { setError(null); - setQuery(query); + setQuery(query ?? EuiSearchBar.Query.MATCH_ALL); } }; From 07972e74a5fb407c38afab172159b15f8824f7a5 Mon Sep 17 00:00:00 2001 From: Lene Gadewoll Date: Tue, 16 Apr 2024 16:32:30 +0200 Subject: [PATCH 07/12] docs(storybook): rename files to match directory name --- ...able_container.stories.tsx => resizable_container.stories.tsx} | 0 .../{resizeable_panel.stories.tsx => resizable_panel.stories.tsx} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/components/resizable_container/{resizeable_container.stories.tsx => resizable_container.stories.tsx} (100%) rename src/components/resizable_container/{resizeable_panel.stories.tsx => resizable_panel.stories.tsx} (100%) diff --git a/src/components/resizable_container/resizeable_container.stories.tsx b/src/components/resizable_container/resizable_container.stories.tsx similarity index 100% rename from src/components/resizable_container/resizeable_container.stories.tsx rename to src/components/resizable_container/resizable_container.stories.tsx diff --git a/src/components/resizable_container/resizeable_panel.stories.tsx b/src/components/resizable_container/resizable_panel.stories.tsx similarity index 100% rename from src/components/resizable_container/resizeable_panel.stories.tsx rename to src/components/resizable_container/resizable_panel.stories.tsx From ed69f23b10263e76e340e5a5ddefa4a6ad10ce27 Mon Sep 17 00:00:00 2001 From: Lene Gadewoll Date: Tue, 16 Apr 2024 16:33:18 +0200 Subject: [PATCH 08/12] docs(storybook): add additional sizes as default to ensure more visibility in the preview --- src/components/responsive/show_for.stories.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/responsive/show_for.stories.tsx b/src/components/responsive/show_for.stories.tsx index 925af7b8b93..a96b276e7f3 100644 --- a/src/components/responsive/show_for.stories.tsx +++ b/src/components/responsive/show_for.stories.tsx @@ -20,8 +20,8 @@ type Story = StoryObj; export const Playground: Story = { args: { - sizes: ['l'], + sizes: ['m', 'l', 'xl'], children: - 'Try changing the Storybook viewport, or adding the `s` size, to see how it affects the visibility of this text.', + 'Try changing the Storybook viewport, or add or remove additional sizes, to see how it affects the visibility of this text.', }, }; From 9a3644515fa94e6e06d5fdbcab0ee9f3f3d332bf Mon Sep 17 00:00:00 2001 From: Lene Gadewoll Date: Tue, 16 Apr 2024 16:52:01 +0200 Subject: [PATCH 09/12] docs(storybook): use faker.seed to generate stable data --- .../resizable_container.stories.tsx | 46 ++++-------- .../resizable_panel.stories.tsx | 8 ++- .../search_bar/search_bar.stories.tsx | 71 +++++-------------- 3 files changed, 37 insertions(+), 88 deletions(-) diff --git a/src/components/resizable_container/resizable_container.stories.tsx b/src/components/resizable_container/resizable_container.stories.tsx index eced7b903a2..9162db19b46 100644 --- a/src/components/resizable_container/resizable_container.stories.tsx +++ b/src/components/resizable_container/resizable_container.stories.tsx @@ -8,6 +8,7 @@ import React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; +import { faker } from '@faker-js/faker'; import { enableFunctionToggleControls } from '../../../.storybook/utils'; import { EuiText } from '../text'; @@ -16,15 +17,14 @@ import { EuiResizableContainerProps, } from './resizable_container'; -// using static text over '@faker-js/faker' to ensure same output in regards to VRT +faker.seed(42); + const placeholderText = ( -

- Autem vitae quibusdam iure aspernatur nobis. Illo dicta debitis aperiam. - Assumenda dicta saepe corrupti tempora. Nobis nihil ipsum esse eius - perspiciatis velit maiores architecto earum. Minus ipsam dignissimos - voluptatem eos ipsa. Laudantium eius porro autem impedit voluptatibus - accusamus qui adipisci. -

+ <> +

{faker.lorem.sentences(5)}

+

{faker.lorem.sentences(5)}

+

{faker.lorem.sentences(5)}

+ ); const TwoColumns: EuiResizableContainerProps['children'] = ( @@ -33,21 +33,13 @@ const TwoColumns: EuiResizableContainerProps['children'] = ( ) => ( <> - - {placeholderText} - {placeholderText} - {placeholderText} - + {placeholderText} - - {placeholderText} - {placeholderText} - {placeholderText} - + {placeholderText} ); @@ -58,31 +50,19 @@ const ThreeColumns: EuiResizableContainerProps['children'] = ( ) => ( <> - - {placeholderText} - {placeholderText} - {placeholderText} - + {placeholderText} - - {placeholderText} - {placeholderText} - {placeholderText} - + {placeholderText} - - {placeholderText} - {placeholderText} - {placeholderText} - + {placeholderText} ); diff --git a/src/components/resizable_container/resizable_panel.stories.tsx b/src/components/resizable_container/resizable_panel.stories.tsx index d48360f72ad..4a7a8a9778c 100644 --- a/src/components/resizable_container/resizable_panel.stories.tsx +++ b/src/components/resizable_container/resizable_panel.stories.tsx @@ -8,6 +8,8 @@ import React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; +import { css } from '@emotion/react'; +import { faker } from '@faker-js/faker'; import { disableStorybookControls, @@ -15,7 +17,8 @@ import { } from '../../../.storybook/utils'; import { EuiResizableContainer } from './resizable_container'; import { EuiResizablePanel, EuiResizablePanelProps } from './resizable_panel'; -import { css } from '@emotion/react'; + +faker.seed(42); const meta: Meta = { title: 'Layout/EuiResizableContainer/EuiResizablePanel', @@ -61,8 +64,7 @@ type Story = StoryObj; export const Playground: Story = { args: { - children: - 'Autem vitae quibusdam iure aspernatur nobis. Illo dicta debitis aperiam. Assumenda dicta saepe corrupti tempora.', + children: faker.lorem.sentences(5), initialSize: 100, }, render: ({ mode, children, ...rest }) => { diff --git a/src/components/search_bar/search_bar.stories.tsx b/src/components/search_bar/search_bar.stories.tsx index c7295c31c87..4848ed7165b 100644 --- a/src/components/search_bar/search_bar.stories.tsx +++ b/src/components/search_bar/search_bar.stories.tsx @@ -8,6 +8,7 @@ import React, { useState } from 'react'; import type { Meta, StoryObj } from '@storybook/react'; +import { faker } from '@faker-js/faker'; import { enableFunctionToggleControls } from '../../../.storybook/utils'; import { EuiBasicTable } from '../basic_table'; @@ -23,6 +24,8 @@ import { QueryType, } from './search_bar'; +faker.seed(42); + const tags = [ { name: 'marketing', color: 'danger' }, { name: 'finance', color: 'success' }, @@ -31,58 +34,22 @@ const tags = [ { name: 'ga', color: 'success' }, ]; -const items = [ - { - type: 'watch', - status: 'open', - active: false, - tag: ['finance'], - owner: 'wanda', - stars: 2, - followers: 10, - comments: 3, - }, - { - type: 'visualization', - status: 'closed', - active: true, - tag: ['ga', 'marketing', 'eng'], - owner: 'carrie', - stars: 2, - followers: 7, - comments: 2, - }, - { - type: 'watch', - open: 'open', - active: true, - tag: [], - owner: 'carrie', - stars: 4, - followers: 2, - comments: 10, - }, - { - type: 'visualization', - open: 'open', - active: false, - tag: ['eng'], - owner: 'dewey', - stars: 5, - followers: 2, - comments: 8, - }, - { - type: 'dashboard', - open: 'closed', - active: false, - tag: ['sales', 'marketing', 'ga'], - owner: 'gabic', - stars: 1, - followers: 13, - comments: 1, - }, -]; +const items = [...Array(5).keys()].map((id) => { + return { + id, + status: faker.helpers.arrayElement(['open', 'closed']), + type: faker.helpers.arrayElement(['dashboard', 'visualization', 'watch']), + tag: faker.helpers.arrayElements( + tags.map((tag) => tag.name), + { min: 0, max: 3 } + ), + active: faker.datatype.boolean(), + owner: faker.helpers.arrayElement(['dewey', 'wanda', 'carrie', 'gabic']), + followers: faker.number.int({ min: 0, max: 20 }), + comments: faker.number.int({ min: 0, max: 10 }), + stars: faker.number.int({ min: 0, max: 5 }), + }; +}); const meta: Meta = { title: 'Forms/EuiSearchBar/EuiSearchBar', From 99ea78378f2bedd64d12ddd15d51cc0bf430229f Mon Sep 17 00:00:00 2001 From: Lene Gadewoll Date: Fri, 26 Apr 2024 14:05:05 +0200 Subject: [PATCH 10/12] docs(storybook): PR feeback - update initialSize of EuiResizablePanel story - remove background-color for spacer story element --- .../resizable_container/resizable_panel.stories.tsx | 2 +- src/components/spacer/spacer.stories.tsx | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/components/resizable_container/resizable_panel.stories.tsx b/src/components/resizable_container/resizable_panel.stories.tsx index 4a7a8a9778c..a6525c37447 100644 --- a/src/components/resizable_container/resizable_panel.stories.tsx +++ b/src/components/resizable_container/resizable_panel.stories.tsx @@ -65,7 +65,7 @@ type Story = StoryObj; export const Playground: Story = { args: { children: faker.lorem.sentences(5), - initialSize: 100, + initialSize: 50, }, render: ({ mode, children, ...rest }) => { const placeholderMode = diff --git a/src/components/spacer/spacer.stories.tsx b/src/components/spacer/spacer.stories.tsx index 094aa00b582..3d8a18fd918 100644 --- a/src/components/spacer/spacer.stories.tsx +++ b/src/components/spacer/spacer.stories.tsx @@ -21,13 +21,7 @@ const meta: Meta = {

Observe the space created between this and the next text block.

-
({ - backgroundColor: euiTheme.colors.lightShade, - })} - > - -
+

Observe the space created between this and the previous text block. From 48ef4f76bfea0ff94abed696248f9e9333140b86 Mon Sep 17 00:00:00 2001 From: Lene Gadewoll Date: Fri, 26 Apr 2024 14:05:30 +0200 Subject: [PATCH 11/12] docs(storybook): simplify EuiSearchBar story --- .../search_bar/search_bar.stories.tsx | 160 +----------------- 1 file changed, 3 insertions(+), 157 deletions(-) diff --git a/src/components/search_bar/search_bar.stories.tsx b/src/components/search_bar/search_bar.stories.tsx index 4848ed7165b..cdce9bc461e 100644 --- a/src/components/search_bar/search_bar.stories.tsx +++ b/src/components/search_bar/search_bar.stories.tsx @@ -6,25 +6,12 @@ * Side Public License, v 1. */ -import React, { useState } from 'react'; +import React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; -import { faker } from '@faker-js/faker'; import { enableFunctionToggleControls } from '../../../.storybook/utils'; -import { EuiBasicTable } from '../basic_table'; import { EuiButton } from '../button'; -import { EuiCallOut } from '../call_out'; -import { EuiHealth } from '../health'; -import { EuiSpacer } from '../spacer'; -import { EuiText } from '../text'; -import { - EuiSearchBarOnChangeArgs, - EuiSearchBar, - EuiSearchBarProps, - QueryType, -} from './search_bar'; - -faker.seed(42); +import { EuiSearchBar, EuiSearchBarProps } from './search_bar'; const tags = [ { name: 'marketing', color: 'danger' }, @@ -34,23 +21,6 @@ const tags = [ { name: 'ga', color: 'success' }, ]; -const items = [...Array(5).keys()].map((id) => { - return { - id, - status: faker.helpers.arrayElement(['open', 'closed']), - type: faker.helpers.arrayElement(['dashboard', 'visualization', 'watch']), - tag: faker.helpers.arrayElements( - tags.map((tag) => tag.name), - { min: 0, max: 3 } - ), - active: faker.datatype.boolean(), - owner: faker.helpers.arrayElement(['dewey', 'wanda', 'carrie', 'gabic']), - followers: faker.number.int({ min: 0, max: 20 }), - comments: faker.number.int({ min: 0, max: 10 }), - stars: faker.number.int({ min: 0, max: 5 }), - }; -}); - const meta: Meta = { title: 'Forms/EuiSearchBar/EuiSearchBar', component: EuiSearchBar, @@ -126,10 +96,6 @@ export const Playground: Story = { }, }, }, - hint: { - content: '', - popoverProps: {}, - }, filters: [ { type: 'field_value_toggle_group', @@ -177,7 +143,7 @@ export const Playground: Story = { resolve( tags.map((tag) => ({ value: tag.name, - view: {tag.name}, + view: tag.name, })) ); }, 2000); @@ -188,124 +154,4 @@ export const Playground: Story = { toolsLeft: false as any, toolsRight: false as any, }, - render: (args) => , -}; - -const StatefulSearchBar = (args: EuiSearchBarProps) => { - const { query, defaultQuery, box, hint } = args; - - const [_query, setQuery] = useState( - query ?? defaultQuery ?? EuiSearchBar.Query.MATCH_ALL - ); - const [error, setError] = useState(null); - const showHint = !!hint?.content; - - const onChange = ({ query, error }: EuiSearchBarOnChangeArgs) => { - if (error) { - setError(error); - } else { - setError(null); - setQuery(query ?? EuiSearchBar.Query.MATCH_ALL); - } - }; - - const handleOnClear = () => { - setQuery(EuiSearchBar.Query.MATCH_ALL); - }; - - const renderSearch = () => { - return ( - {hint.content}, - popoverProps: hint.popoverProps ?? {}, - } - : undefined - } - /> - ); - }; - - const renderError = () => { - if (!error) { - return; - } - return ( - <> - - - - ); - }; - - const renderTable = () => { - const columns = [ - { - name: 'Type', - field: 'type', - }, - { - name: 'Open', - field: 'status', - render: (status: string) => (status === 'open' ? 'Yes' : 'No'), - }, - { - name: 'Active', - field: 'active', - }, - { - name: 'Tags', - field: 'tag', - }, - { - name: 'Owner', - field: 'owner', - }, - { - name: 'Stats', - width: '150px', - render: (item: (typeof items)[0]) => { - return ( -

-
{`${item.stars} Stars`}
-
{`${item.followers} Followers`}
-
{`${item.comments} Comments`}
-
- ); - }, - }, - ]; - - const queriedItems = EuiSearchBar.Query.execute(_query, items, { - defaultFields: ['owner', 'tag', 'type'], - }); - - return ; - }; - return ( - renderError() || ( - <> - {renderSearch()} - - -

Example data output

-
- - {renderTable()} - - ) - ); }; From 14b423b5ec0cf2a72e7f8606e0423d757eabe6b0 Mon Sep 17 00:00:00 2001 From: Lene Gadewoll Date: Fri, 26 Apr 2024 19:52:54 +0200 Subject: [PATCH 12/12] refactor: remove added onClear prop --- src/components/form/field_search/field_search.tsx | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/components/form/field_search/field_search.tsx b/src/components/form/field_search/field_search.tsx index edc0fea0e65..b3c9bc595ef 100644 --- a/src/components/form/field_search/field_search.tsx +++ b/src/components/form/field_search/field_search.tsx @@ -55,10 +55,6 @@ export interface EuiFieldSearchProps * Shows a button that quickly clears any input */ isClearable?: boolean; - /** - * Called when the onClear button is pressed. - */ - onClear?: () => void; /** * Creates an input group with element(s) coming before input * `string` | `ReactElement` or an array of these @@ -165,13 +161,11 @@ export class EuiFieldSearch extends Component< } this.setState({ value: '' }); - const { incremental, onSearch, onClear } = this.props; + const { incremental, onSearch } = this.props; if (onSearch && incremental) { onSearch(''); } - - onClear?.(); }; componentWillUnmount() { @@ -223,7 +217,6 @@ export class EuiFieldSearch extends Component< compressed, onSearch, isClearable: _isClearable, - onClear, append, prepend, ...rest