Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Emotion] Convert EuiCollapsibleNav and EuiCollapsibleNavGroup #6865

Merged
merged 13 commits into from
Jun 23, 2023
302 changes: 302 additions & 0 deletions src/components/collapsible_nav/collapsible_nav.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,305 @@ export const Playground: Story = {
size: 240,
},
};

/**
* Full pattern demo - this was copied from src-docs examples,
* and is meant to be an imitation of Kibana's production nav
*/
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I'm a super huge fan of this story. It feels like it has too much overlap with our docs and I'm not sure if the gain is worth it. Its useful for QA but I'm 50/50 on reverting the commit once QA is over.

Thoughts? Should I go ahead and revert this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree this might be too close to what's in the docs. I responded to your other comment that maybe removing this one and adding a bit to the primary EuiCollapsibleNav example might be a good middle ground.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 thanks Trevor! I'll go ahead and revert. My only thought is that long-term, we should think about what we're going to do with all our existing docs once we're on EUI+ and Storybook combined. It might make sense then to move everything to Storybook, but right now a duplicated example is not all that helpful.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a time deciding how I thought about this one. I like your suggestion Cee, to long-term move things to Storybook and EUI+

import { css } from '@emotion/react';
import find from 'lodash/find';
import findIndex from 'lodash/findIndex';

import { logicalCSSWithFallback } from '../../global_styling';
import {
EuiButtonIcon,
EuiIcon,
EuiText,
EuiLink,
EuiHeaderSectionItemButton,
EuiHeaderLogo,
EuiHeader,
EuiPageTemplate,
EuiPinnableListGroup,
EuiPinnableListGroupItemProps,
EuiFlexItem,
EuiHorizontalRule,
EuiSkeletonText,
EuiListGroup,
} from '../../components';

import { EuiCollapsibleNavGroup } from './collapsible_nav_group';

const TopLinks: EuiPinnableListGroupItemProps[] = [
{
label: 'Home',
iconType: 'home',
isActive: true,
'aria-current': true,
onClick: () => {},
pinnable: false,
},
];
const KibanaLinks: EuiPinnableListGroupItemProps[] = [
{ label: 'Discover', onClick: () => {} },
{ label: 'Visualize', onClick: () => {} },
{ label: 'Dashboards', onClick: () => {} },
{ label: 'Canvas', onClick: () => {} },
{ label: 'Maps', onClick: () => {} },
{ label: 'Machine Learning', onClick: () => {} },
{ label: 'Graph', onClick: () => {} },
];

const LearnLinks: EuiPinnableListGroupItemProps[] = [
{ label: 'Docs', onClick: () => {} },
{ label: 'Blogs', onClick: () => {} },
{ label: 'Webinars', onClick: () => {} },
{ label: 'Elastic.co', href: 'https://elastic.co' },
];

const CollapsibleNavAll = () => {
const [navIsOpen, setNavIsOpen] = useState(true);

/**
* Accordion toggling
*/
const [openGroups, setOpenGroups] = useState(['Kibana', 'Learn']);

const toggleAccordion = (isOpen: boolean, title?: string) => {
if (!title) return;
const itExists = openGroups.includes(title);
if (isOpen) {
if (itExists) return;
openGroups.push(title);
} else {
const index = openGroups.indexOf(title);
if (index > -1) {
openGroups.splice(index, 1);
}
}
setOpenGroups([...openGroups]);
};

/**
* Pinning
*/
const [pinnedItems, setPinnedItems] = useState<
EuiPinnableListGroupItemProps[]
>([]);

const addPin = (item: any) => {
if (!item || find(pinnedItems, { label: item.label })) {
return;
}
item.pinned = true;
const newPinnedItems = pinnedItems ? pinnedItems.concat(item) : [item];
setPinnedItems(newPinnedItems);
};

const removePin = (item: any) => {
const pinIndex = findIndex(pinnedItems, { label: item.label });
if (pinIndex > -1) {
item.pinned = false;
const newPinnedItems = pinnedItems;
newPinnedItems.splice(pinIndex, 1);
setPinnedItems([...newPinnedItems]);
}
};

const collapsibleNav = (
<EuiCollapsibleNav
aria-label="Main navigation"
isOpen={navIsOpen}
button={
<EuiHeaderSectionItemButton
aria-label="Toggle main navigation"
onClick={() => setNavIsOpen(!navIsOpen)}
>
<EuiIcon type={'menu'} size="m" aria-hidden="true" />
</EuiHeaderSectionItemButton>
}
onClose={() => setNavIsOpen(false)}
// Accessibility - Add scroll to nav on very small screens
css={css`
@media (max-height: 15em) {
${logicalCSSWithFallback('overflow-y', 'auto')}
}
`}
>
{/* Dark deployments section */}
<EuiFlexItem grow={false} style={{ flexShrink: 0 }}>
<EuiCollapsibleNavGroup isCollapsible={false} background="dark">
<EuiListGroup
maxWidth="none"
gutterSize="none"
size="s"
listItems={[
{
label: 'Manage deployment',
href: '#',
iconType: 'logoCloud',
iconProps: {
color: 'ghost',
},
},
]}
/>
</EuiCollapsibleNavGroup>
</EuiFlexItem>

{/* Shaded pinned section always with a home item */}
<EuiFlexItem grow={false} style={{ flexShrink: 0 }}>
<EuiCollapsibleNavGroup
background="light"
style={{ maxHeight: '40vh' }}
className="eui-yScroll"
>
<EuiPinnableListGroup
aria-label="Pinned links" // A11y : Since this group doesn't have a visible `title` it should be provided an accessible description
listItems={TopLinks.concat(pinnedItems)}
unpinTitle={({ label }) => `Unpin ${label}`}
onPinClick={removePin}
maxWidth="none"
color="text"
gutterSize="none"
size="s"
/>
</EuiCollapsibleNavGroup>
</EuiFlexItem>

<EuiHorizontalRule margin="none" />

{/* BOTTOM */}
<EuiFlexItem
className="eui-yScroll"
// Accessibility - Allows nav items to be seen and interacted with on very small screen sizes
css={css`
@media (max-height: 15em) {
flex: 1 0 auto;
}
`}
>
{/* Kibana section */}
<EuiCollapsibleNavGroup
title={
<a
className="eui-textInheritColor"
href="#/navigation/collapsible-nav"
onClick={(e) => e.stopPropagation()}
>
Kibana
</a>
}
buttonElement="div"
iconType="logoKibana"
isCollapsible={true}
initialIsOpen={openGroups.includes('Kibana')}
onToggle={(isOpen: boolean) => toggleAccordion(isOpen, 'Kibana')}
>
<EuiPinnableListGroup
aria-label="Kibana" // A11y : EuiCollapsibleNavGroup can't correctly pass the `title` as the `aria-label` to the right HTML element, so it must be added manually
listItems={KibanaLinks}
pinTitle={({ label }) => `Pin ${label}`}
onPinClick={addPin}
maxWidth="none"
color="subdued"
gutterSize="none"
size="s"
/>
</EuiCollapsibleNavGroup>

{/* Security callout */}
<EuiCollapsibleNavGroup
background="light"
iconType="logoSecurity"
title="Elastic Security"
isCollapsible={true}
initialIsOpen={true}
arrowDisplay="none"
extraAction={
<EuiButtonIcon
aria-label="Hide and never show again"
title="Hide and never show again"
iconType="cross"
/>
}
>
<EuiText size="s" color="subdued" style={{ padding: '0 8px 8px' }}>
<p>
Threat prevention, detection, and response with SIEM and endpoint
security.
<br />
<EuiLink>Learn more</EuiLink>
</p>
</EuiText>
</EuiCollapsibleNavGroup>

{/* Learn section */}
<EuiCollapsibleNavGroup
title={
<a
className="eui-textInheritColor"
href="#/navigation/collapsible-nav"
onClick={(e) => e.stopPropagation()}
>
Training
</a>
}
buttonElement="div"
iconType="training"
isCollapsible={true}
initialIsOpen={openGroups.includes('Learn')}
onToggle={(isOpen: boolean) => toggleAccordion(isOpen, 'Learn')}
>
<EuiPinnableListGroup
aria-label="Learn" // A11y : EuiCollapsibleNavGroup can't correctly pass the `title` as the `aria-label` to the right HTML element, so it must be added manually
listItems={LearnLinks}
pinTitle={({ label }) => `Pin ${label}`}
onPinClick={addPin}
maxWidth="none"
color="subdued"
gutterSize="none"
size="s"
/>
</EuiCollapsibleNavGroup>
</EuiFlexItem>

<EuiFlexItem grow={false}>
{/* Span fakes the nav group into not being the first item and therefore adding a top border */}
<span />
<EuiCollapsibleNavGroup>
<EuiButton fill fullWidth iconType="plusInCircleFilled">
Add data
</EuiButton>
</EuiCollapsibleNavGroup>
</EuiFlexItem>
</EuiCollapsibleNav>
);

return (
<>
<EuiHeader
position="fixed"
sections={[
{
items: [
collapsibleNav,
<EuiHeaderLogo iconType="logoElastic">Elastic</EuiHeaderLogo>,
],
borders: 'right',
},
]}
/>

<EuiPageTemplate>
<EuiPageTemplate.EmptyPrompt>
<EuiSkeletonText />
</EuiPageTemplate.EmptyPrompt>
</EuiPageTemplate>
</>
);
};

export const FullPattern: Story = {
render: () => <CollapsibleNavAll />,
};