Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ consider additional positioning prop support on a case-by-case basis.
- `CollapsibleSubNavItem` -> `SubNav.CollapsibleItem`
- `SubNavItem` -> `SubNav.Item`
- `SubNavItemText` -> `SubNav.ItemText`
- Added `Nav.List` as a semantic wrapper for `Nav.Item`. See the
[README](../packages/chrome/README.md#usages) for details.

#### @zendeskgarden/react-colorpickers

Expand Down
14 changes: 7 additions & 7 deletions packages/avatars/demo/~patterns/stories/ChromeStory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,23 @@
import React from 'react';
import { Story } from '@storybook/react';
import Icon from '@zendeskgarden/svg-icons/src/16/grid-2x2-stroke.svg';
import { Chrome, Body, Header, HeaderItem, HeaderItemIcon } from '@zendeskgarden/react-chrome';
import { Chrome, Body, Header } from '@zendeskgarden/react-chrome';
import { Avatar, IAvatarProps } from '@zendeskgarden/react-avatars';

export const ChromeStory: Story<IAvatarProps> = args => (
<Chrome isFluid style={{ height: 'auto' }}>
<Body>
<Header>
<HeaderItem aria-label="Products">
<HeaderItemIcon>
<Header.Item aria-label="Products">
<Header.ItemIcon>
<Icon />
</HeaderItemIcon>
</HeaderItem>
<HeaderItem isRound aria-label="User profile">
</Header.ItemIcon>
</Header.Item>
<Header.Item isRound aria-label="User profile">
<Avatar {...args} size="extrasmall">
<img alt="Example User" src="images/avatars/chrome.png" />
</Avatar>
</HeaderItem>
</Header.Item>
</Header>
</Body>
</Chrome>
Expand Down
15 changes: 12 additions & 3 deletions packages/chrome/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ npm install react react-dom styled-components @zendeskgarden/react-theming
import { ThemeProvider } from '@zendeskgarden/react-theming';
import { Chrome, Nav, SubNav, Body, Header, Content, Main } from '@zendeskgarden/react-chrome';
import ConnectIcon from '@zendeskgarden/icons/src/26/relationshape-connect.svg';
import BrandmarkIcon from '@zendeskgarden/svg-icons/src/26/zendesk.svg';

<ThemeProvider>
<Chrome>
Expand All @@ -27,11 +28,19 @@ import ConnectIcon from '@zendeskgarden/icons/src/26/relationshape-connect.svg';
</Nav.ItemIcon>
<NavItemText>Zendesk Connect</NavItemText>
</Nav.Item>
<Nav.Item isCurrent>
<Nav.List>
<Nav.Item isCurrent>
<Nav.ItemIcon>
<HomeIcon />
</Nav.ItemIcon>
<NavItemText>Home</NavItemText>
</Nav.Item>
</Nav.List>
<Nav.Item hasBrandmark>
<Nav.ItemIcon>
<HomeIcon />
<BrandmarkIcon />
</Nav.ItemIcon>
<NavItemText>Home</NavItemText>
<Nav.ItemText>Brandmark</Nav.ItemText>
</Nav.Item>
</Nav>
<SubNav>
Expand Down
30 changes: 16 additions & 14 deletions packages/chrome/demo/stories/ChromeStory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,20 +139,22 @@ export const ChromeStory: Story<IArgs> = ({
<Nav.ItemText>Nav Logo</Nav.ItemText>
</Nav.Item>
)}
{navItems.map((item, index) => (
<Nav.Item
key={index}
isCurrent={currentNav === index}
onClick={() => {
setCurrentNav(index);
setCurrentSubNav(0);
onNavClick({ hasSubNav: item.hasSubNav });
}}
>
<Nav.ItemIcon>{NAV_ICONS[index] || <NavIcon />}</Nav.ItemIcon>
<Nav.ItemText isWrapped={isWrapped}>{item.text}</Nav.ItemText>
</Nav.Item>
))}
<Nav.List>
{navItems.map((item, index) => (
<Nav.Item
key={index}
isCurrent={currentNav === index}
onClick={() => {
setCurrentNav(index);
setCurrentSubNav(0);
onNavClick({ hasSubNav: item.hasSubNav });
}}
>
<Nav.ItemIcon>{NAV_ICONS[index] || <NavIcon />}</Nav.ItemIcon>
<Nav.ItemText isWrapped={isWrapped}>{item.text}</Nav.ItemText>
</Nav.Item>
))}
</Nav.List>
{hasBrandmark && (
<Nav.Item hasBrandmark>
<Nav.ItemIcon>
Expand Down
3 changes: 3 additions & 0 deletions packages/chrome/src/elements/nav/Nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { StyledNav } from '../../styled';
import { NavItem } from './NavItem';
import { NavItemIcon } from './NavItemIcon';
import { NavItemText } from './NavItemText';
import { NavList } from './NavList';

export const NavComponent = React.forwardRef<HTMLElement, INavProps>((props, ref) => {
const { hue, isLight, isDark } = useChromeContext();
Expand All @@ -36,11 +37,13 @@ NavComponent.propTypes = {
* @extends HTMLAttributes<HTMLElement>
*/
export const Nav = NavComponent as typeof NavComponent & {
List: typeof NavList;
Item: typeof NavItem;
ItemIcon: typeof NavItemIcon;
ItemText: typeof NavItemText;
};

Nav.List = NavList;
Nav.Item = NavItem;
Nav.ItemIcon = NavItemIcon;
Nav.ItemText = NavItemText;
113 changes: 63 additions & 50 deletions packages/chrome/src/elements/nav/NavItem.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,42 +9,55 @@ import React from 'react';
import { render } from 'garden-test-utils';
import { PALETTE, getColorV8, DEFAULT_THEME } from '@zendeskgarden/react-theming';
import { Chrome } from '../Chrome';
import { NavItem } from './NavItem';
import { Nav } from './Nav';
import { PRODUCTS, Product } from '../../types';

describe('NavItem', () => {
it('passes ref to underlying DOM element', () => {
const ref = React.createRef<HTMLButtonElement>();
const { container } = render(<NavItem ref={ref} />);
const { getByTestId } = render(
<Nav.List>
<Nav.Item ref={ref} data-test-id="item" />
</Nav.List>
);

expect(container.firstChild).toBe(ref.current);
expect(getByTestId('item')).toBe(ref.current);
});

it('renders expanded styling', () => {
const { container } = render(
const { getByTestId } = render(
<Nav isExpanded>
<NavItem />
<Nav.List>
<Nav.Item data-test-id="item" />
</Nav.List>
</Nav>
);

expect(container.firstChild!.firstChild).toHaveStyle(`
expect(getByTestId('item')).toHaveStyle(`
justify-content: start;
text-align: inherit;
`);
});

describe('Current', () => {
it('renders state attribute when current', () => {
const { getByTestId } = render(<NavItem isCurrent data-test-id="current-nav-item" />);
const { getByTestId } = render(
<Nav.List>
<Nav.Item isCurrent data-test-id="current-nav-item" />
</Nav.List>
);

const currentNavItem = getByTestId('current-nav-item');

expect(currentNavItem).toHaveAttribute('aria-current', 'true');
});

it('does not render state attribute when not current', () => {
const { getByTestId } = render(<NavItem data-test-id="nav-item" />);
const { getByTestId } = render(
<Nav.List>
<Nav.Item data-test-id="nav-item" />
</Nav.List>
);

const navItem = getByTestId('nav-item');

Expand All @@ -54,110 +67,110 @@ describe('NavItem', () => {

describe('Order', () => {
it('renders correct order if used as brandmark', () => {
const { container } = render(<NavItem hasBrandmark />);
const { container } = render(<Nav.Item hasBrandmark />);

expect(container.firstChild).toHaveStyleRule('order', '1');
});

it('renders correct order if used as logo', () => {
const { container } = render(<NavItem hasLogo />);
const { container } = render(<Nav.Item hasLogo />);

expect(container.firstChild).toHaveStyleRule('order', '0');
expect(container.firstChild).toHaveStyleRule('order', '-1');
});
});

describe('Opacity', () => {
it('renders correct opacity if used as brandmark', () => {
const { container } = render(<NavItem hasBrandmark />);
const { container } = render(<Nav.Item hasBrandmark />);

expect(container.firstChild).toHaveStyleRule('opacity', '0.3');
});

it('renders correct opacity if used as logo', () => {
const { container } = render(<NavItem hasLogo />);
const { container } = render(<Nav.Item hasLogo />);

expect(container.firstChild).toHaveStyleRule('opacity', '1');
});

it('renders correct opacity if current', () => {
const { container } = render(<NavItem isCurrent />);
const { getByTestId } = render(
<Nav.List>
<Nav.Item isCurrent data-test-id="item" />
</Nav.List>
);

expect(container.firstChild).toHaveStyleRule('opacity', '1');
expect(getByTestId('item')).toHaveStyleRule('opacity', '1');
});
});

describe('Hover Color', () => {
it('renders correct color with dark hue', () => {
const { container } = render(
const { getByTestId } = render(
<Chrome hue="black">
<NavItem />
<Nav.List>
<Nav.Item data-test-id="item" />
</Nav.List>
</Chrome>
);

expect(container.firstChild!.firstChild).toHaveStyleRule(
'background-color',
'rgba(0,0,0,0.1)',
{
modifier: '&:hover'
}
);
expect(getByTestId('item')).toHaveStyleRule('background-color', 'rgba(0,0,0,0.1)', {
modifier: '&:hover'
});
});

it('renders correct color with light hue', () => {
const { container } = render(
const { getByTestId } = render(
<Chrome hue="white">
<NavItem />
<Nav.List>
<Nav.Item data-test-id="item" />
</Nav.List>
</Chrome>
);

expect(container.firstChild!.firstChild).toHaveStyleRule(
'background-color',
'rgba(255,255,255,0.1)',
{
modifier: '&:hover'
}
);
expect(getByTestId('item')).toHaveStyleRule('background-color', 'rgba(255,255,255,0.1)', {
modifier: '&:hover'
});
});
});

describe('Current Color', () => {
it('renders correct color by default', () => {
const { container } = render(
const { getByTestId } = render(
<Chrome>
<NavItem isCurrent />
<Nav.List>
<Nav.Item isCurrent data-test-id="item" />
</Nav.List>
</Chrome>
);

expect(container.firstChild!.firstChild).toHaveStyleRule(
expect(getByTestId('item')).toHaveStyleRule(
'background-color',
getColorV8('chromeHue', 500, DEFAULT_THEME)
);
});

it('renders correct color with dark hue', () => {
const { container } = render(
const { getByTestId } = render(
<Chrome hue="black">
<NavItem isCurrent />
<Nav.List>
<Nav.Item isCurrent data-test-id="item" />
</Nav.List>
</Chrome>
);

expect(container.firstChild!.firstChild).toHaveStyleRule(
'background-color',
'rgba(255,255,255,0.4)'
);
expect(getByTestId('item')).toHaveStyleRule('background-color', 'rgba(255,255,255,0.4)');
});

it('renders correct color with light hue', () => {
const { container } = render(
const { getByTestId } = render(
<Chrome hue="white">
<NavItem isCurrent />
<Nav.List>
<Nav.Item isCurrent data-test-id="item" />
</Nav.List>
</Chrome>
);

expect(container.firstChild!.firstChild).toHaveStyleRule(
'background-color',
'rgba(0,0,0,0.4)'
);
expect(getByTestId('item')).toHaveStyleRule('background-color', 'rgba(0,0,0,0.4)');
});
});

Expand All @@ -174,14 +187,14 @@ describe('NavItem', () => {

it('renders correct product color if provided', () => {
PRODUCTS.forEach(product => {
const { container } = render(<NavItem hasLogo product={product} />);
const { container } = render(<Nav.Item hasLogo product={product} />);

expect(container.firstChild).toHaveStyleRule('color', VALID_COLOR_MAP[product]);
});
});

it('renders correct color if no product is provided', () => {
const { container } = render(<NavItem hasLogo />);
const { container } = render(<Nav.Item hasLogo />);

expect(container.firstChild).toHaveStyleRule('color', 'inherit');
});
Expand Down
Loading