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

feat(VisuallyHidden): Add VisuallyHidden component #1246

Merged
merged 1 commit into from
Feb 7, 2022
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
title: 'VisuallyHidden'
description: 'VisuallyHidden has all the styles necessary to hide it from visual clients, but keep it for screen readers.'
status: 'new'
showTabs: true
---

import VisuallyHiddenInfo from 'Docs/uilib/components/visually-hidden/info'
import VisuallyHiddenDemos from 'Docs/uilib/components/visually-hidden/demos'

<VisuallyHiddenInfo />
<VisuallyHiddenDemos />
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* UI lib Component Example
*
*/

import ComponentBox from 'dnb-design-system-portal/src/shared/tags/ComponentBox'


export const VisuallyHiddenDefault = () => (
<ComponentBox data-visual-test="visually-hidden-default">
{() => /* jsx */ `
<VisuallyHidden>Hidden content</VisuallyHidden>
`}
</ComponentBox>
)

export const VisuallyHiddenFocusable = () => (
<ComponentBox data-visual-test="visually-hidden-focusable">
{() => /* jsx */ `
<VisuallyHidden focusable>
<Anchor href="/">Hidden, but focusable content</Anchor>
</VisuallyHidden>
`}
</ComponentBox>
)

export const VisuallyHiddenUseCase = () => (
<ComponentBox data-visual-test="visually-hidden-use-case">
{() => /* jsx */ `
<Anchor href="/">Read more <VisuallyHidden element="span">about Eufemia</VisuallyHidden></Anchor>
`}
</ComponentBox>
)

export const VisuallyHiddenSpan = () => (
<ComponentBox data-visual-test="visually-hidden-span">
{() => /* jsx */ `
<VisuallyHidden element="span">Hidden, with custom HTML element</VisuallyHidden>
`}
</ComponentBox>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
showTabs: true
---

import {
VisuallyHiddenDefault,
VisuallyHiddenFocusable,
VisuallyHiddenSpan,
VisuallyHiddenUseCase,
} from 'Docs/uilib/components/visually-hidden/Examples'

## Demos

#### VisuallyHidden

<VisuallyHiddenDefault />

#### VisuallyHidden with focusable content


Use `VisuallyHidden` with `focusable={true}` to visually hide an element by default, but to display it when it’s focused (e.g. by a keyboard-only user). The container will be displayed when any child element of the container receives focus.

<VisuallyHiddenFocusable />

#### VisuallyHidden with example of use case

<VisuallyHiddenUseCase />

#### VisuallyHidden with custom element

<VisuallyHiddenSpan />
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
showTabs: true
---

## Events

No events are supported at the moment.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
showTabs: true
---

## Description

`VisuallyHidden` is a utility component that can be used to hide its children visually, while keeping them visible to screen readers and other assistive technology.

NOTE: Many semantic elements, such as button elements, have meaning to assistive devices and browsers that provide context for the user and, in many cases, provide or restrict interactive behaviors. Use caution when overriding our defaults and make sure that the element you choose to render provides the same experience for all users. In short: The component shouldn’t be used to hide interactive content.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
showTabs: true
---

## Properties

### `VisuallyHidden` properties

| Properties | Description |
| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `children` | _(optional)_ The content you want to be visually hidden.It can be a `string` or a `React Element`. |
| `className` | _(optional)_ Custom className for the component root. |
| `element` | _(optional)_ Custom root HTML element for the component. Defaults to `<div>` |
| `focusable` | _(optional)_ Set to `true` to hide an element by default, but to display it when it’s focused (e.g. by a keyboard-only user) root. Defaults to false |
53 changes: 53 additions & 0 deletions packages/dnb-eufemia-sandbox/stories/components/VisuallyHidden.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* @dnb/eufemia Component Story
*
*/

import React from 'react'
import { VisuallyHidden } from '@dnb/eufemia/src/components'
import { Provider } from '@dnb/eufemia/src/shared'
import { Box, Wrapper } from '../helpers'

export default {
title: 'Eufemia/Components/VisuallyHidden',
}

export const Default = () => {
return (
<Provider>
<VisuallyHidden>Default</VisuallyHidden>
</Provider>
)
}

export const VisuallyHiddenSandbox = () => {
return (
<Wrapper>
<Box>
<Default />
</Box>
<Box>
<VisuallyHidden />
</Box>
</Wrapper>
)
}

export const VisuallyHiddenMultiple = () => {
return (
<Wrapper>
<Box>
<VisuallyHidden />
<VisuallyHidden />
</Box>
</Wrapper>
)
}

export const VisuallyHiddenWithProvider = () => {
return (
<Provider>
<VisuallyHidden />
</Provider>
)
}
14 changes: 14 additions & 0 deletions packages/dnb-eufemia/src/components/VisuallyHidden.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* ATTENTION: This file is auto generated by using "prepareTemplates".
* Do not change the content!
*
*/

/**
* Library Index visually-hidden to autogenerate all the components and extensions
* Used by "prepareVisuallyHiddens"
*/

import VisuallyHidden from './visually-hidden/VisuallyHidden'
export * from './visually-hidden/VisuallyHidden'
export default VisuallyHidden
2 changes: 2 additions & 0 deletions packages/dnb-eufemia/src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import Textarea from './textarea/Textarea'
import Timeline from './timeline/Timeline'
import ToggleButton from './toggle-button/ToggleButton'
import Tooltip from './tooltip/Tooltip'
import VisuallyHidden from './visually-hidden/VisuallyHidden'

// define / export all the available components
export {
Expand Down Expand Up @@ -91,4 +92,5 @@ export {
Timeline,
ToggleButton,
Tooltip,
VisuallyHidden,
}
3 changes: 3 additions & 0 deletions packages/dnb-eufemia/src/components/lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import Textarea from './textarea/Textarea'
import Timeline from './timeline/Timeline'
import ToggleButton from './toggle-button/ToggleButton'
import Tooltip from './tooltip/Tooltip'
import VisuallyHidden from './visually-hidden/VisuallyHidden'

// define / export all the available components
export {
Expand Down Expand Up @@ -93,6 +94,7 @@ export {
Timeline,
ToggleButton,
Tooltip,
VisuallyHidden,
}

export const getComponents = () => {
Expand Down Expand Up @@ -136,6 +138,7 @@ export const getComponents = () => {
Timeline,
ToggleButton,
Tooltip,
VisuallyHidden,
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React from 'react'
import classnames from 'classnames'

// Shared
import Context from '../../shared/Context'
import { extendPropsWithContext } from '../../shared/component-helper'

export interface VisuallyHiddenProps {
/**
* The content of the visually hidden element, can be a string or a React Element
* Default: null
*/
children?: string | React.ReactNode // ReactNode allows multiple elements, strings, numbers, fragments, portals...

/**
* Custom className on the component root
* Default: null
*/
className?: string

/**
* Hide an element by default, but to display it when it’s focused (e.g. by a keyboard-only user)
* Default: false
*/
focusable?: boolean

/**
* Root element of the component
* Default: div
*/
element?: string | React.ReactNode
}

export const defaultProps = {
className: null,
children: null,
focusable: false,
element: 'div',
}

const VisuallyHidden = (localProps: VisuallyHiddenProps) => {
// Every component should have a context
const context = React.useContext(Context)

// Extract additional props from global context
const { element, children, className, focusable, ...props } =
extendPropsWithContext(
{ ...defaultProps, ...localProps },
defaultProps,
context?.translation?.VisuallyHidden,
context?.VisuallyHidden
)

const visuallyHiddenClassNames = classnames(
'dnb-visually-hidden',
focusable
? 'dnb-visually-hidden--focusable'
: 'dnb-visually-hidden--default',
className
)
const Element = element

return (
<Element
data-testid="visually-hidden"
className={visuallyHiddenClassNames}
{...props}
>
{children}
</Element>
)
}

export default VisuallyHidden
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* Screenshot Test
* This file will not run on "test:staged" because we don't require any related files
*/

import {
testPageScreenshot,
setupPageScreenshot,
} from '../../../core/jest/jestSetupScreenshots'

describe('VisuallyHidden screenshot', () => {
setupPageScreenshot({ url: '/uilib/components/visually-hidden/demos' })

it('have to match VisuallyHidden default', async () => {
const screenshot = await testPageScreenshot({
selector: '[data-visual-test="visually-hidden-default"] .dnb-visually-hidden',
})
expect(screenshot).toMatchImageSnapshot()
})

it('have to match VisuallyHidden focusable', async () => {
const screenshot = await testPageScreenshot({
selector: '[data-visual-test="visually-hidden-focusable"] .dnb-visually-hidden',
})
expect(screenshot).toMatchImageSnapshot()
})

it('have to match VisuallyHidden use case', async () => {
const screenshot = await testPageScreenshot({
selector: '[data-visual-test="visually-hidden-use-case"] .dnb-visually-hidden',
})
expect(screenshot).toMatchImageSnapshot()
})

it('have to match VisuallyHidden span element', async () => {
const screenshot = await testPageScreenshot({
selector: '[data-visual-test="visually-hidden-span"] .dnb-visually-hidden',
})
expect(screenshot).toMatchImageSnapshot()
})
})
Loading