diff --git a/src/components/side_nav/side_nav.stories.tsx b/src/components/side_nav/side_nav.stories.tsx new file mode 100644 index 00000000000..a75d1b0cf7c --- /dev/null +++ b/src/components/side_nav/side_nav.stories.tsx @@ -0,0 +1,163 @@ +/* + * 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 { + EuiSideNav, + EuiSideNavProps, + EuiSideNavHeadingProps, +} from './side_nav'; +import { EuiIcon } from '../icon'; + +const meta: Meta = { + title: 'EuiSideNav', + component: EuiSideNav, +}; + +export default meta; +type Story = StoryObj; + +const componentDefaults: EuiSideNavProps = { + mobileBreakpoints: ['xs', 's'], + items: [], + // Aria-label and mobileTitle do not have defaults; they are being set here as they are shared between examples + 'aria-label': 'Side navigation example', + mobileTitle: 'Mobile navigation header', +}; + +// Heading props shared across examples +const _sharedHeadingProps: EuiSideNavHeadingProps = { + element: 'h1', + screenReaderOnly: false, +}; + +export const Playground: Story = { + args: { + ...componentDefaults, + heading: 'Elastic', + headingProps: _sharedHeadingProps, + isOpenOnMobile: false, + truncate: false, + }, + render: ({ ...args }) => , +}; + +export const SideNavHeader: Story = { + args: { + ...componentDefaults, + items: [ + { + name: 'Root item', + id: 'rootItem', + items: [ + { + name: 'Child item', + id: 'childItem', + onClick: () => {}, + }, + ], + }, + ], + heading: 'Navigation header', + headingProps: _sharedHeadingProps, + }, + argTypes: { + // This story demos the header props; removing other props to prevent confusion + toggleOpenOnMobile: { table: { disable: true } }, + isOpenOnMobile: { table: { disable: true } }, + mobileBreakpoints: { table: { disable: true } }, + items: { table: { disable: true } }, + renderItem: { table: { disable: true } }, + truncate: { table: { disable: true } }, + }, + render: ({ ...args }) => , +}; + +const StatefulSideNav = (props: Partial) => { + const [isSideNavOpenOnMobile, setIsSideNavOpenOnMobile] = useState(false); + const [selectedItemName, setSelectedItem] = useState('Time stuff'); + + const toggleOpenOnMobile = () => { + setIsSideNavOpenOnMobile(!isSideNavOpenOnMobile); + }; + + const sideNav = [ + { + name: 'Kibana', + id: 'kibana', + onClick: undefined, + icon: , + items: [ + { + name: 'Has nested children', + id: 'normal_children', + isSelected: selectedItemName === 'Has nested children', + onClick: () => setSelectedItem('Has nested children'), + items: [ + { + name: 'Child 1', + id: 'child_1', + isSelected: selectedItemName === 'Child 1', + onClick: () => setSelectedItem('Child 1'), + items: [ + { + name: 'Child 2', + id: 'child_2', + isSelected: selectedItemName === 'Child 2', + onClick: () => setSelectedItem('Child 2'), + items: [], + }, + ], + }, + ], + }, + { + name: 'Has forceOpen: true', + id: 'force_open', + isSelected: selectedItemName === 'Has forceOpen: true', + onClick: () => setSelectedItem('Has forceOpen: true'), + forceOpen: true, + items: [ + { + name: 'Child 3', + id: 'child_3', + isSelected: selectedItemName === 'Child 3', + onClick: () => setSelectedItem('Child 3'), + }, + ], + }, + { + name: 'Children only without link', + id: 'children_only', + isSelected: selectedItemName === 'Children only without link', + onClick: undefined, + items: [ + { + name: 'Child 4', + id: 'child_4', + isSelected: selectedItemName === 'Child 4', + onClick: () => setSelectedItem('Child 4'), + }, + ], + }, + ], + }, + ]; + + return ( + + ); +};