Skip to content

Commit

Permalink
Merge pull request #2826 from SUI-Components/input-a11y
Browse files Browse the repository at this point in the history
a11y Atom Input
  • Loading branch information
andresin87 authored Feb 4, 2025
2 parents e1be0ab + 9b24685 commit 9bf0b75
Show file tree
Hide file tree
Showing 55 changed files with 1,236 additions and 687 deletions.
9 changes: 7 additions & 2 deletions components/atom/button/demo/articles/ArticleA11y.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import PropTypes from 'prop-types'

import {Article, Box, H2, Paragraph, ListItem, UnorderedList, Strong, Anchor} from '@s-ui/documentation-library'
import {Anchor, Article, Box, H2, ListItem, Paragraph, Strong, UnorderedList} from '@s-ui/documentation-library'

const ArticleA11y = ({className}) => {
return (
<Article className={className}>
<H2>Accessibility</H2>
<H2>
Accessibility –{' '}
<Anchor href="https://github.com/SUI-Components/sui-components/blob/master/contributor-docs/Accessibility%20Standards.md">
<Strong>Guidelines</Strong>
</Anchor>
</H2>
<Box style={{backgroundColor: 'color-mix(in srgb, #00FF00 10%, transparent)'}}>
<Paragraph>
✅ This component has been successfully tested for{' '}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import PropTypes from 'prop-types'

import {Article, H2, ListItem, UnorderedList} from '@s-ui/documentation-library'

import AtomKbd from '@s-ui/react-atom-kbd'

const ArticleKeyboardNavigation = ({className}) => {
Expand Down
2 changes: 1 addition & 1 deletion components/atom/button/demo/articles/ArticleNegative.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {Fragment} from 'react'
import usePrefersColorScheme from 'use-prefers-color-scheme'

import PropTypes from 'prop-types'
import usePrefersColorScheme from 'use-prefers-color-scheme'

import {Article, Cell, Code, Grid, H2, Label, Paragraph} from '@s-ui/documentation-library'

Expand Down
6 changes: 3 additions & 3 deletions components/atom/button/demo/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@

import {H1, Paragraph} from '@s-ui/documentation-library'

import ArticleA11y from './articles/ArticleA11y.js'
import ArticleAlignment from './articles/ArticleAlignment.js'
import ArticleColor from './articles/ArticleColor.js'
import ArticleDesign from './articles/ArticleDesign.js'
import ArticleDesignColor from './articles/ArticleDesignColor.js'
import ArticleElevation from './articles/ArticleElevation.js'
import ArticleIsFitted from './articles/ArticleIsFitted.js'
import ArticleKeyboardNavigation from './articles/ArticleKeyboardNavigation.js'
import ArticleLink from './articles/ArticleLink.js'
import ArticleNegative from './articles/ArticleNegative.js'
import ArticlePlayground from './articles/ArticlePlayground.js'
import ArticleShape from './articles/ArticleShape.js'
import ArticleSize from './articles/ArticleSize.js'
import ArticleSocialColor from './articles/ArticleSocialColor.js'
import ArticleA11y from './articles/ArticleA11y.js'
import ArticleKeyboardNavigation from './articles/ArticleKeyboardNavigation.js'
import TypeDeprecatedArticle from './TypeDeprecatedArticle.js'
import {CLASS_SECTION} from './settings.js'
import TypeDeprecatedArticle from './TypeDeprecatedArticle.js'

const Demo = () => {
return (
Expand Down
2 changes: 1 addition & 1 deletion components/atom/button/src/styles/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ $base-class: '.sui-AtomButton';
}
}

&:focus {
&:focus-visible {
box-shadow: $bxsh-atom-button-focus;
outline: 2px solid transparentize($c-primary, 0.2);
outline-offset: 2px;
Expand Down
57 changes: 57 additions & 0 deletions components/atom/input/demo/articles/ArticleA11y.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import PropTypes from 'prop-types'

import {Anchor, Article, Box, Code, H2, ListItem, Paragraph, Strong, UnorderedList} from '@s-ui/documentation-library'

const ArticleA11y = ({className}) => {
return (
<Article className={className}>
<H2>
Accessibility –{' '}
<Anchor href="https://github.com/SUI-Components/sui-components/blob/master/contributor-docs/Accessibility%20Standards.md">
<Strong>Guidelines</Strong>
</Anchor>
</H2>
<Box style={{backgroundColor: 'color-mix(in srgb, #00FF00 10%, transparent)'}}>
<Paragraph>
✅ This component has been successfully tested for{' '}
<Strong>WCAG 2.0 levels A and AA, WCAG 2.1 levels A and AA</Strong> and for common accessibility best
practices.
</Paragraph>
</Box>
<UnorderedList>
<ListItem>
<Strong>Label</Strong>: Ensure text fields are properly labeled using <Code>label</Code> elements, with the
for attribute linking to the input. This helps screen readers identify the field’s purpose.
</ListItem>
<ListItem>
<Strong>Aria Label</Strong>: Use <Code>aria-label</Code> for inputs without visible labels (e.g., search bars
with placeholder text only). This attribute provides an accessible name that describes the purpose of the
input.
</ListItem>
<ListItem>
<Strong>Descriptive Text</Strong>: When additional descriptive text is required, use{' '}
<Code>aria-describedby</Code> to associate the input field with explanatory content, such as error messages or
guidelines.
</ListItem>
<ListItem>
<Strong>Error Feedback</Strong>: Use <Code>role="alert"</Code> or <Code>aria-live="assertive"</Code> for error
messages, ensuring screen readers announce them immediately upon field validation.
</ListItem>
</UnorderedList>
<Box style={{backgroundColor: 'color-mix(in srgb, #FFFF00 10%, transparent)'}}>
<Strong>Mandatory / Required</Strong>
<UnorderedList>
<ListItem>
The asterisk * for mandatory needs to be read as <Strong>mandatory</Strong>.
</ListItem>
</UnorderedList>
</Box>
</Article>
)
}

ArticleA11y.propTypes = {
className: PropTypes.string
}

export default ArticleA11y
141 changes: 141 additions & 0 deletions components/atom/input/demo/articles/ArticleAddonAndIcon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import {useState} from 'react'

import PropTypes from 'prop-types'

import {
AntDesignIcon,
Article,
Cell,
Code,
Grid,
H2,
Input,
ListItem,
Paragraph,
RadioButton,
RadioButtonGroup,
UnorderedList
} from '@s-ui/documentation-library'
import AtomLabel from '@s-ui/react-atom-label/lib'
import PrimitiveVisuallyHidden from '@s-ui/react-primitive-visually-hidden'

import AtomInput from '../../src/index.js'

const ArticleAddonAndIcon = ({className}) => {
const [state, setState] = useState({})
const {icon, iconValue, rightAddon, leftAddon} = state
const setStatus = (newState = {}) => setState({...state, ...newState})
const valueIcon = iconValue ? <AntDesignIcon icon={iconValue} style={{color: 'currentColor'}} /> : null
return (
<Article className={className}>
<H2>Addon and Icon</H2>
<Paragraph>Input offers the possibility to add icons and contents on its left or right positions</Paragraph>
<UnorderedList>
<ListItem>
<Code>leftAddon</Code> and <Code>rightAddon</Code>: use it as a label for the input field
</ListItem>
<ListItem>
<Code>leftIcon</Code> and <Code>rightIcon</Code>: use it as a valid symbol for the field
</ListItem>
</UnorderedList>
<Paragraph>This field props can be combined all together.</Paragraph>
<Grid cols={2} gutter={[8, 8]}>
<Cell span={2}>
<PrimitiveVisuallyHidden>
<AtomLabel htmlFor="input-icons-and-addons" text="icons and addons" />
</PrimitiveVisuallyHidden>
<AtomInput
id="input-icons-and-addons"
placeholder="icons and addons"
leftIcon={icon === 'leftIcon' ? valueIcon : undefined}
rightIcon={icon === 'rightIcon' ? valueIcon : undefined}
leftAddon={leftAddon}
rightAddon={rightAddon}
/>
</Cell>
<Cell>
<RadioButtonGroup
onChange={(event, value) => {
setStatus({icon: value})
}}
fullWidth
>
<RadioButton value="leftIcon" label="leftIcon" />
<RadioButton value="rightIcon" label="rightIcon" />
</RadioButtonGroup>
</Cell>
<Cell>
<RadioButtonGroup
onChange={(event, value) =>
setStatus({
iconValue: value
})
}
fullWidth
>
<RadioButton
value="AiFillFire"
aria-label="fire"
label={<AntDesignIcon icon="AiFillFire" style={{color: 'currentColor'}} />}
/>
<RadioButton
value="AiOutlineSketch"
aria-label="sketch"
label={<AntDesignIcon icon="AiOutlineSketch" style={{color: 'currentColor'}} />}
/>
<RadioButton
value="AiOutlineInfoCircle"
aria-label="info"
label={<AntDesignIcon icon="AiOutlineInfoCircle" style={{color: 'currentColor'}} />}
/>
<RadioButton
value="AiTwotoneSkin"
aria-label="skin"
label={<AntDesignIcon icon="AiTwotoneSkin" style={{color: 'currentColor'}} />}
/>
<RadioButton
value="AiOutlineExclamationCircle"
aria-label="exclamation"
label={<AntDesignIcon icon="AiOutlineExclamationCircle" style={{color: 'currentColor'}} />}
/>
<RadioButton
value="AiOutlineCar"
aria-label="car"
label={<AntDesignIcon icon="AiOutlineCar" style={{color: 'currentColor'}} />}
/>
<RadioButton
value="AiOutlineAppstore"
aria-label="appstore"
label={<AntDesignIcon icon="AiOutlineAppstore" style={{color: 'currentColor'}} />}
/>
<RadioButton
value="AiFillTrophy"
aria-label="trophy"
label={<AntDesignIcon icon="AiFillTrophy" style={{color: 'currentColor'}} />}
/>
</RadioButtonGroup>
</Cell>
<Cell>
<Input
fullWidth
placeholder="leftAddon text"
onChange={event => setStatus({leftAddon: event.target.value})}
/>
</Cell>
<Cell>
<Input
fullWidth
placeholder="rightAddon text"
onChange={event => setStatus({rightAddon: event.target.value})}
/>
</Cell>
</Grid>
</Article>
)
}

ArticleAddonAndIcon.propTypes = {
className: PropTypes.node
}

export default ArticleAddonAndIcon
44 changes: 44 additions & 0 deletions components/atom/input/demo/articles/ArticleBorderless.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import {useState} from 'react'

import PropTypes from 'prop-types'

import {Article, Box, Cell, Code, Grid, H2, Paragraph, RadioButton} from '@s-ui/documentation-library'

import AtomInput from '../../src/index.js'

const ArticleBorderless = ({className}) => {
const [border, setBorder] = useState(true)
const [mode, setMode] = useState('light')
return (
<Article className={className}>
<H2>No border</H2>
<Paragraph>
The border of the input can be removed using the boolean prop <Code>noBorder</Code>
</Paragraph>
<Grid cols={2} gutter={[8, 8]}>
<Cell>
<RadioButton fullWidth value={border} label="hide border" onClick={(event, value) => setBorder(!value)} />
</Cell>
<Cell>
<RadioButton
fullWidth
value={mode}
label="set dark"
onClick={(event, value) => setMode(value ? 'dark' : 'light')}
/>
</Cell>
<Cell span={2}>
<Box mode={mode}>
<AtomInput placeholder="click to interact" noBorder={!border} />
</Box>
</Cell>
</Grid>
</Article>
)
}

ArticleBorderless.propTypes = {
className: PropTypes.node
}

export default ArticleBorderless
28 changes: 28 additions & 0 deletions components/atom/input/demo/articles/ArticleDefault.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import PropTypes from 'prop-types'

import {Article, H2, Paragraph} from '@s-ui/documentation-library'
import AtomLabel from '@s-ui/react-atom-label/lib'
import PrimitiveVisuallyHidden from '@s-ui/react-primitive-visually-hidden'

import AtomInput from '../../src/index.js'

const ArticleDefault = ({className}) => {
return (
<Article className={className}>
<H2>Default</H2>
<Paragraph>By default, the element gets the following look and feel.</Paragraph>
<PrimitiveVisuallyHidden>
<AtomLabel htmlFor="default" text="Label for default input" />
</PrimitiveVisuallyHidden>
<div>
<AtomInput id="default" />
</div>
</Article>
)
}

ArticleDefault.propTypes = {
className: PropTypes.node
}

export default ArticleDefault
41 changes: 41 additions & 0 deletions components/atom/input/demo/articles/ArticleDisabledReadOnly.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import PropTypes from 'prop-types'

import {Article, Cell, Code, Grid, H2, Label, Paragraph} from '@s-ui/documentation-library'

import AtomInput from '../../src/index.js'

const ArticleDisabledReadOnly = ({className}) => {
return (
<Article className={className}>
<H2>Disable and ReadOnly</H2>
<Paragraph>
Input provides two different modes that blocks the component behavior the difference between them is the
appearance.
</Paragraph>
<Paragraph>
The developer can disable the component using the <Code>disabled</Code> boolean prop. It can be blocked also
using the <Code>readOnly</Code> boolean prop, but it will look like the default input.
</Paragraph>
<Grid gutter={[8, 8]} cols={2}>
<Cell>
<Label htmlFor="input-disabled">disabled</Label>
</Cell>
<Cell>
<Label htmlFor="input-read-only">readOnly</Label>
</Cell>
<Cell>
<AtomInput id="input-disabled" value="disabled" disabled />
</Cell>
<Cell>
<AtomInput id="input-read-only" value="readOnly" readOnly />
</Cell>
</Grid>
</Article>
)
}

ArticleDisabledReadOnly.propTypes = {
className: PropTypes.node
}

export default ArticleDisabledReadOnly
Loading

0 comments on commit 9bf0b75

Please sign in to comment.