From e441fe89b65777bdae0bffeeef196e568cd73aa8 Mon Sep 17 00:00:00 2001 From: Lene Gadewoll Date: Mon, 29 Apr 2024 11:27:16 +0200 Subject: [PATCH] [Storybook] Add stories for more components (letters R-S) - Part 1 (#7687) --- .../page_template/page_template.stories.tsx | 3 - .../resizable_container.stories.tsx | 209 ++++++++++++++++++ .../resizable_panel.stories.tsx | 101 +++++++++ .../responsive/show_for.stories.tsx | 27 +++ .../search_bar/search_bar.stories.tsx | 157 +++++++++++++ .../search_bar/search_bar_filters.stories.tsx | 96 ++++++++ src/components/search_bar/search_filters.tsx | 2 +- src/components/side_nav/side_nav.stories.tsx | 2 + src/components/spacer/spacer.stories.tsx | 41 ++++ src/components/stat/stat.stories.tsx | 38 ++++ 10 files changed, 672 insertions(+), 4 deletions(-) create mode 100644 src/components/resizable_container/resizable_container.stories.tsx create mode 100644 src/components/resizable_container/resizable_panel.stories.tsx create mode 100644 src/components/responsive/show_for.stories.tsx create mode 100644 src/components/search_bar/search_bar.stories.tsx create mode 100644 src/components/search_bar/search_bar_filters.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/page_template/page_template.stories.tsx b/src/components/page_template/page_template.stories.tsx index b97f43be46ba..c53344e18cac 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/resizable_container/resizable_container.stories.tsx b/src/components/resizable_container/resizable_container.stories.tsx new file mode 100644 index 000000000000..9162db19b464 --- /dev/null +++ b/src/components/resizable_container/resizable_container.stories.tsx @@ -0,0 +1,209 @@ +/* + * 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 { faker } from '@faker-js/faker'; + +import { enableFunctionToggleControls } from '../../../.storybook/utils'; +import { EuiText } from '../text'; +import { + EuiResizableContainer, + EuiResizableContainerProps, +} from './resizable_container'; + +faker.seed(42); + +const placeholderText = ( + <> +

{faker.lorem.sentences(5)}

+

{faker.lorem.sentences(5)}

+

{faker.lorem.sentences(5)}

+ +); + +const TwoColumns: EuiResizableContainerProps['children'] = ( + EuiResizablePanel, + EuiResizableButton +) => ( + <> + + {placeholderText} + + + + + + {placeholderText} + + +); + +const ThreeColumns: EuiResizableContainerProps['children'] = ( + EuiResizablePanel, + EuiResizableButton +) => ( + <> + + {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/resizable_panel.stories.tsx b/src/components/resizable_container/resizable_panel.stories.tsx new file mode 100644 index 000000000000..a6525c374472 --- /dev/null +++ b/src/components/resizable_container/resizable_panel.stories.tsx @@ -0,0 +1,101 @@ +/* + * 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 { css } from '@emotion/react'; +import { faker } from '@faker-js/faker'; + +import { + disableStorybookControls, + moveStorybookControlsToCategory, +} from '../../../.storybook/utils'; +import { EuiResizableContainer } from './resizable_container'; +import { EuiResizablePanel, EuiResizablePanelProps } from './resizable_panel'; + +faker.seed(42); + +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: faker.lorem.sentences(5), + initialSize: 50, + }, + 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} + + + )} + + ); + }, +}; diff --git a/src/components/responsive/show_for.stories.tsx b/src/components/responsive/show_for.stories.tsx new file mode 100644 index 000000000000..a96b276e7f3d --- /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: ['m', 'l', 'xl'], + children: + 'Try changing the Storybook viewport, or add or remove additional sizes, to see how it affects the visibility of this text.', + }, +}; 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 000000000000..cdce9bc461eb --- /dev/null +++ b/src/components/search_bar/search_bar.stories.tsx @@ -0,0 +1,157 @@ +/* + * 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 { EuiButton } from '../button'; +import { 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 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(',')})` + ); + } + }, + }, + }, + }, + }, + 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, + }, +}; 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 000000000000..e4897b9e2239 --- /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 242624379e46..3b66d4228c23 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[]; diff --git a/src/components/side_nav/side_nav.stories.tsx b/src/components/side_nav/side_nav.stories.tsx index 75e800ee4f97..d473c74c7fe2 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; diff --git a/src/components/spacer/spacer.stories.tsx b/src/components/spacer/spacer.stories.tsx new file mode 100644 index 000000000000..3d8a18fd918c --- /dev/null +++ b/src/components/spacer/spacer.stories.tsx @@ -0,0 +1,41 @@ +/* + * 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.

+
+ + +

+ 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 000000000000..ad0d37cbe747 --- /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', + }, +};