-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feat(web-react): Introduce Navigation #DS-1524
- Loading branch information
Showing
26 changed files
with
619 additions
and
4 deletions.
There are no files selected for viewing
22 changes: 22 additions & 0 deletions
22
packages/web-react/src/components/Navigation/Navigation.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
'use client'; | ||
|
||
import classNames from 'classnames'; | ||
import React from 'react'; | ||
import { useStyleProps } from '../../hooks'; | ||
import { SpiritNavigationProps } from '../../types'; | ||
import { useNavigationStyleProps } from './useNavigationStyleProps'; | ||
|
||
const Navigation = (props: SpiritNavigationProps): JSX.Element => { | ||
const { children, ...restProps } = props; | ||
|
||
const { classProps, props: modifiedProps } = useNavigationStyleProps(restProps); | ||
const { styleProps, props: otherProps } = useStyleProps(modifiedProps); | ||
|
||
return ( | ||
<nav {...otherProps} className={classNames(classProps, styleProps.className)} style={styleProps.style}> | ||
<ul>{children}</ul> | ||
</nav> | ||
); | ||
}; | ||
|
||
export default Navigation; |
19 changes: 19 additions & 0 deletions
19
packages/web-react/src/components/Navigation/NavigationItem.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
'use client'; | ||
|
||
import React from 'react'; | ||
import { useStyleProps } from '../../hooks'; | ||
import { SpiritNavigationItemProps } from '../../types'; | ||
|
||
const NavigationItem = (props: SpiritNavigationItemProps): JSX.Element => { | ||
const { children, ...restProps } = props; | ||
|
||
const { styleProps, props: otherProps } = useStyleProps(restProps); | ||
|
||
return ( | ||
<li {...otherProps} className={styleProps.className} style={styleProps.style}> | ||
{children} | ||
</li> | ||
); | ||
}; | ||
|
||
export default NavigationItem; |
43 changes: 43 additions & 0 deletions
43
packages/web-react/src/components/Navigation/NavigationLink.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
'use client'; | ||
|
||
import classNames from 'classnames'; | ||
import React, { ElementType, forwardRef } from 'react'; | ||
import { useStyleProps } from '../../hooks'; | ||
import { PolymorphicRef, SpiritNavigationLinkProps } from '../../types'; | ||
import { useNavigationLinkStyleProps } from './useNavigationLinkStyleProps'; | ||
|
||
const defaultProps: Partial<SpiritNavigationLinkProps> = { | ||
elementType: 'a', | ||
}; | ||
|
||
/* We need an exception for components exported with forwardRef */ | ||
/* eslint no-underscore-dangle: ['error', { allow: ['_NavigationLink'] }] */ | ||
const _NavigationLink = <E extends ElementType = 'a'>( | ||
props: SpiritNavigationLinkProps<E>, | ||
ref: PolymorphicRef<E>, | ||
): JSX.Element => { | ||
const propsWithDefaults = { ...defaultProps, ...props }; | ||
const { | ||
elementType: ElementTag = defaultProps.elementType as ElementType, | ||
children, | ||
...restProps | ||
} = propsWithDefaults; | ||
const { classProps, props: modifiedProps } = useNavigationLinkStyleProps(restProps); | ||
const { styleProps, props: otherProps } = useStyleProps(modifiedProps); | ||
|
||
return ( | ||
<ElementTag | ||
{...otherProps} | ||
{...styleProps} | ||
href={restProps.href} | ||
className={classNames(classProps, styleProps.className)} | ||
ref={ref} | ||
> | ||
{children} | ||
</ElementTag> | ||
); | ||
}; | ||
|
||
const NavigationLink = forwardRef<HTMLAnchorElement, SpiritNavigationLinkProps<ElementType>>(_NavigationLink); | ||
|
||
export default NavigationLink; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
# Navigation | ||
|
||
The `Navigation` component provides a versatile and accessible way to build navigation menus. | ||
|
||
The Navigation component consists of the following building blocks: | ||
|
||
- [Navigation](#navigation) | ||
- [NavigationItem](#navigationitem) | ||
- [NavigationLink](#navigationlink) | ||
|
||
## Navigation | ||
|
||
The `Navigation` component is a container for navigation items. | ||
|
||
### Usage | ||
|
||
```jsx | ||
import { Navigation, NavigationItem, NavigationLink } from '@lmc-eu/spirit-web-react'; | ||
|
||
<Navigation> | ||
<NavigationItem> | ||
<NavigationLink href="/" isSelected> | ||
Home | ||
</NavigationLink> | ||
</NavigationItem> | ||
<NavigationItem> | ||
<NavigationLink href="/about">About Us</NavigationLink> | ||
</NavigationItem> | ||
<NavigationItem> | ||
<NavigationLink href="/contact">Contact</NavigationLink> | ||
</NavigationItem> | ||
</Navigation>; | ||
``` | ||
|
||
### API | ||
|
||
| Name | Type | Default | Required | Description | | ||
| ---------- | ----------------------- | ------- | -------- | ------------------------- | | ||
| `children` | `string` \| `ReactNode` | `null` | ✓ | Content of the Navigation | | ||
|
||
The components accept [additional attributes][readme-additional-attributes]. | ||
If you need more control over the styling of a component, you can use [style props][readme-style-props] | ||
and [escape hatches][readme-escape-hatches]. | ||
|
||
## NavigationItem | ||
|
||
The `NavigationItem` component is a container for navigation links. | ||
|
||
### Usage | ||
|
||
```jsx | ||
import { NavigationItem, NavigationLink } from '@lmc-eu/spirit-web-react'; | ||
|
||
<NavigationItem> | ||
<NavigationLink href="/" isSelected> | ||
Home | ||
</NavigationLink> | ||
</NavigationItem>; | ||
``` | ||
|
||
### API | ||
|
||
| Name | Type | Default | Required | Description | | ||
| ---------- | ----------------------- | ------- | -------- | ----------------------------- | | ||
| `children` | `string` \| `ReactNode` | `null` | ✓ | Content of the NavigationItem | | ||
|
||
## NavigationLink | ||
|
||
The `NavigationLink` component is a link in the navigation. | ||
|
||
### Usage | ||
|
||
```jsx | ||
import { NavigationLink } from '@lmc-eu/spirit-web-react'; | ||
|
||
<NavigationLink href="/" isSelected> | ||
Home | ||
</NavigationLink>; | ||
``` | ||
|
||
### Selected | ||
|
||
The `isSelected` prop is used to indicate that the link is selected. | ||
|
||
```jsx | ||
<NavigationLink href="/" isSelected> | ||
Home | ||
</NavigationLink> | ||
``` | ||
|
||
### Disabled | ||
|
||
The `isDisabled` prop is used to indicate that the link is disabled. | ||
|
||
```jsx | ||
<NavigationLink href="/" isDisabled> | ||
Home | ||
</NavigationLink> | ||
``` | ||
|
||
### API | ||
|
||
| Name | Type | Default | Required | Description | | ||
| ------------- | --------------------------------- | ------- | -------- | ----------------------------- | | ||
| `children` | `string` \| `ReactNode` | `null` | ✓ | Content of the NavigationLink | | ||
| `elementType` | `ElementType` | `a` | ✕ | Type of element used as | | ||
| `href` | `string` | - | ✕ | URL of the link | | ||
| `isSelected` | `boolean` | `false` | ✕ | Whether the link is selected | | ||
| `isDisabled` | `boolean` | `false` | ✕ | Whether the link is disabled | | ||
| `ref` | `ForwardedRef<HTMLAnchorElement>` | — | ✕ | Anchor element reference | | ||
| `target` | `string` | `null` | ✕ | Link target | | ||
|
||
[readme-additional-attributes]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web-react/README.md#additional-attributes | ||
[readme-escape-hatches]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web-react/README.md#escape-hatches | ||
[readme-style-props]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web-react/README.md#style-props |
28 changes: 28 additions & 0 deletions
28
packages/web-react/src/components/Navigation/__tests__/Navigation.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import '@testing-library/jest-dom'; | ||
import { render, screen } from '@testing-library/react'; | ||
import React from 'react'; | ||
import { classNamePrefixProviderTest } from '../../../../tests/providerTests/classNamePrefixProviderTest'; | ||
import { restPropsTest } from '../../../../tests/providerTests/restPropsTest'; | ||
import { stylePropsTest } from '../../../../tests/providerTests/stylePropsTest'; | ||
import Navigation from '../Navigation'; | ||
|
||
describe('Navigation', () => { | ||
classNamePrefixProviderTest(Navigation, 'Navigation'); | ||
|
||
stylePropsTest(Navigation); | ||
|
||
restPropsTest(Navigation, 'nav'); | ||
|
||
it('should have default classname', () => { | ||
render(<Navigation>Content</Navigation>); | ||
|
||
expect(screen.getByRole('navigation')).toHaveClass('Navigation'); | ||
}); | ||
|
||
it('should render list and children', () => { | ||
render(<Navigation>Content</Navigation>); | ||
|
||
expect(screen.getByRole('list')).toBeInTheDocument(); | ||
expect(screen.getByText('Content')).toBeInTheDocument(); | ||
}); | ||
}); |
24 changes: 24 additions & 0 deletions
24
packages/web-react/src/components/Navigation/__tests__/NavigationItem.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import '@testing-library/jest-dom'; | ||
import { render, screen } from '@testing-library/react'; | ||
import React from 'react'; | ||
import { restPropsTest } from '../../../../tests/providerTests/restPropsTest'; | ||
import { stylePropsTest } from '../../../../tests/providerTests/stylePropsTest'; | ||
import NavigationItem from '../NavigationItem'; | ||
|
||
describe('NavigationItem', () => { | ||
stylePropsTest(NavigationItem); | ||
|
||
restPropsTest(NavigationItem, 'li'); | ||
|
||
it('should have correct role', () => { | ||
render(<NavigationItem>Content</NavigationItem>); | ||
|
||
expect(screen.getByRole('listitem')).toBeInTheDocument(); | ||
}); | ||
|
||
it('should render children', () => { | ||
render(<NavigationItem>Content</NavigationItem>); | ||
|
||
expect(screen.getByRole('listitem')).toHaveTextContent('Content'); | ||
}); | ||
}); |
47 changes: 47 additions & 0 deletions
47
packages/web-react/src/components/Navigation/__tests__/NavigationLink.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import '@testing-library/jest-dom'; | ||
import { render, screen } from '@testing-library/react'; | ||
import React from 'react'; | ||
import { classNamePrefixProviderTest } from '../../../../tests/providerTests/classNamePrefixProviderTest'; | ||
import { restPropsTest } from '../../../../tests/providerTests/restPropsTest'; | ||
import { stylePropsTest } from '../../../../tests/providerTests/stylePropsTest'; | ||
import NavigationLink from '../NavigationLink'; | ||
|
||
describe('NavigationLink', () => { | ||
classNamePrefixProviderTest(NavigationLink, 'NavigationLink'); | ||
|
||
stylePropsTest(NavigationLink); | ||
|
||
restPropsTest(NavigationLink, 'a'); | ||
|
||
it('should have default classname', () => { | ||
render(<NavigationLink href="/">Content</NavigationLink>); | ||
|
||
expect(screen.getByRole('link')).toHaveClass('NavigationLink'); | ||
}); | ||
|
||
it('should have selected classname', () => { | ||
render( | ||
<NavigationLink href="/" isSelected> | ||
Content | ||
</NavigationLink>, | ||
); | ||
|
||
expect(screen.getByRole('link')).toHaveClass('NavigationLink NavigationLink--selected'); | ||
}); | ||
|
||
it('should have disabled classname', () => { | ||
render( | ||
<NavigationLink href="/" isDisabled> | ||
Content | ||
</NavigationLink>, | ||
); | ||
|
||
expect(screen.getByRole('link')).toHaveClass('NavigationLink NavigationLink--disabled'); | ||
}); | ||
|
||
it('should render children', () => { | ||
render(<NavigationLink href="/">Content</NavigationLink>); | ||
|
||
expect(screen.getByText('Content')).toBeInTheDocument(); | ||
}); | ||
}); |
26 changes: 26 additions & 0 deletions
26
packages/web-react/src/components/Navigation/__tests__/useNavigationLinkStyleProps.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { renderHook } from '@testing-library/react'; | ||
import { SpiritNavigationLinkProps } from '../../../types'; | ||
import { useNavigationLinkStyleProps } from '../useNavigationLinkStyleProps'; | ||
|
||
describe('useNavigationLinkStyleProps', () => { | ||
it('should return defaults', () => { | ||
const props = {}; | ||
const { result } = renderHook(() => useNavigationLinkStyleProps(props)); | ||
|
||
expect(result.current.classProps).toBe('NavigationLink'); | ||
}); | ||
|
||
it('should return disabled class', () => { | ||
const props: SpiritNavigationLinkProps = { isDisabled: true }; | ||
const { result } = renderHook(() => useNavigationLinkStyleProps(props)); | ||
|
||
expect(result.current.classProps).toBe('NavigationLink NavigationLink--disabled'); | ||
}); | ||
|
||
it('should return selected class', () => { | ||
const props = { isSelected: true }; | ||
const { result } = renderHook(() => useNavigationLinkStyleProps(props)); | ||
|
||
expect(result.current.classProps).toBe('NavigationLink NavigationLink--selected'); | ||
}); | ||
}); |
11 changes: 11 additions & 0 deletions
11
packages/web-react/src/components/Navigation/__tests__/useNavigationStyleProps.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { renderHook } from '@testing-library/react'; | ||
import { useNavigationStyleProps } from '../useNavigationStyleProps'; | ||
|
||
describe('useNavigationStyleProps', () => { | ||
it('should return defaults', () => { | ||
const props = {}; | ||
const { result } = renderHook(() => useNavigationStyleProps(props)); | ||
|
||
expect(result.current.classProps).toBe('Navigation'); | ||
}); | ||
}); |
24 changes: 24 additions & 0 deletions
24
packages/web-react/src/components/Navigation/demo/NavigationButtons.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import React from 'react'; | ||
import { Button } from '../../Button'; | ||
import Navigation from '../Navigation'; | ||
import NavigationItem from '../NavigationItem'; | ||
|
||
const NavigationDefault = () => { | ||
return ( | ||
<div style={{ '--spirit-header-height': '72px' } as React.CSSProperties}> | ||
<Navigation> | ||
<NavigationItem> | ||
<Button elementType="a" href="#"> | ||
Button | ||
</Button> | ||
</NavigationItem> | ||
<NavigationItem> | ||
<Button elementType="a" href="#" color="secondary"> | ||
Button | ||
</Button> | ||
</NavigationItem> | ||
</Navigation> | ||
</div> | ||
); | ||
}; | ||
export default NavigationDefault; |
12 changes: 12 additions & 0 deletions
12
packages/web-react/src/components/Navigation/demo/NavigationDefault.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import React from 'react'; | ||
import Navigation from '../Navigation'; | ||
import NavigationItem from '../NavigationItem'; | ||
|
||
const NavigationDefault = () => { | ||
return ( | ||
<Navigation> | ||
<NavigationItem>Item</NavigationItem> | ||
</Navigation> | ||
); | ||
}; | ||
export default NavigationDefault; |
Oops, something went wrong.