From 4252e7feb2decf4f4757e160b0e0eb91b784363e Mon Sep 17 00:00:00 2001 From: Flavia Moraes Date: Wed, 30 Aug 2023 10:00:26 -0300 Subject: [PATCH 1/5] feat: add accessibility elements to icon --- packages/yoga/src/Icon/Icon.jsx | 59 +++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/packages/yoga/src/Icon/Icon.jsx b/packages/yoga/src/Icon/Icon.jsx index e70ef3c8b7..11222affa4 100644 --- a/packages/yoga/src/Icon/Icon.jsx +++ b/packages/yoga/src/Icon/Icon.jsx @@ -20,17 +20,43 @@ const Icon = ({ fill, stroke, theme, + title, + description, + ariaLabel, ...props -}) => ( - -); +}) => { + const withTitle = propsTitle => { + const defaultProps = { + width: '12', + height: '12', + viewBox: '0 0 12 12', + role: 'img', + }; + const titleElement = {title}; + const descElement = {description}; + + const newSvg = React.createElement( + 'svg', + { ...propsTitle, ...defaultProps }, + titleElement, + descElement, + Component().props.children, + ); + + return newSvg; + }; + + return ( + + ); +}; const commonSizes = [ 'xxxsmall', @@ -55,6 +81,14 @@ Icon.propTypes = { /** Stroke color. Use it as one of theme.colors * tokens (vibin, neutral, stamina...) */ stroke: string, + /** Text that will be displayed in the title element, used for accessibility */ + title: string, + /** Text used as element description, used for accessibility. + * A title must be given in order to use description corretly. + */ + description: string, + /** Text used as identifier for aria-describedby, title and description */ + ariaLabel: string, /** Horizontal size of the SVG. Use it as one of * theme.spacing tokens (xxsmall, small, medium...) */ width: oneOfType([oneOf(commonSizes), string, number]), @@ -88,7 +122,10 @@ Icon.propTypes = { Icon.defaultProps = { fill: undefined, stroke: undefined, - width: undefined, + title: 'teste', + description: 'teste description', + ariaLabel: 'label test', + width: 30, height: undefined, size: undefined, }; From 55ad2e551349df616620df3f582c0fad2ad2c792 Mon Sep 17 00:00:00 2001 From: Flavia Moraes Date: Fri, 1 Sep 2023 11:58:43 -0300 Subject: [PATCH 2/5] feat: description adjustments --- packages/yoga/src/Icon/Icon.jsx | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/packages/yoga/src/Icon/Icon.jsx b/packages/yoga/src/Icon/Icon.jsx index 11222affa4..eee5db08ba 100644 --- a/packages/yoga/src/Icon/Icon.jsx +++ b/packages/yoga/src/Icon/Icon.jsx @@ -26,20 +26,30 @@ const Icon = ({ ...props }) => { const withTitle = propsTitle => { + const titleId = `${ariaLabel}-titleId`; + let ariaDescribedBy = titleId; + const titleElement = {title}; + let svgChildren = [titleElement]; + + if (description) { + const descId = `${ariaLabel}-descId`; + const descElement = {description}; + + ariaDescribedBy += ` ${descId}`; + + svgChildren = [...svgChildren, descElement]; + } + const defaultProps = { - width: '12', - height: '12', viewBox: '0 0 12 12', role: 'img', + 'aria-describedby': ariaDescribedBy, }; - const titleElement = {title}; - const descElement = {description}; const newSvg = React.createElement( 'svg', { ...propsTitle, ...defaultProps }, - titleElement, - descElement, + svgChildren, Component().props.children, ); @@ -54,6 +64,7 @@ const Icon = ({ {...(fill && { fill: get(theme.yoga.colors, fill, fill) })} {...(stroke && { stroke: get(theme.yoga.colors, stroke, stroke) })} {...props} + aria-hidden={title ? undefined : true} /> ); }; @@ -122,12 +133,12 @@ Icon.propTypes = { Icon.defaultProps = { fill: undefined, stroke: undefined, - title: 'teste', - description: 'teste description', - ariaLabel: 'label test', - width: 30, + title: undefined, + description: undefined, + ariaLabel: undefined, + width: undefined, height: undefined, - size: undefined, + size: 12, }; export default withTheme(Icon); From 97518b170ac991bc1f127e20c18bed22185b712d Mon Sep 17 00:00:00 2001 From: Flavia Moraes Date: Tue, 5 Sep 2023 10:15:53 -0300 Subject: [PATCH 3/5] test: add tests --- packages/yoga/src/Icon/Icon.jsx | 4 +- packages/yoga/src/Icon/native/Icon.test.jsx | 17 +++++++++ .../native/__snapshots__/Icon.test.jsx.snap | 38 +++++++++++++++++++ packages/yoga/src/Icon/web/Icon.test.jsx | 17 +++++++++ .../Icon/web/__snapshots__/Icon.test.jsx.snap | 38 +++++++++++++++++++ 5 files changed, 112 insertions(+), 2 deletions(-) diff --git a/packages/yoga/src/Icon/Icon.jsx b/packages/yoga/src/Icon/Icon.jsx index eee5db08ba..4c26522b7a 100644 --- a/packages/yoga/src/Icon/Icon.jsx +++ b/packages/yoga/src/Icon/Icon.jsx @@ -25,7 +25,7 @@ const Icon = ({ ariaLabel, ...props }) => { - const withTitle = propsTitle => { + const componentWithTitle = propsTitle => { const titleId = `${ariaLabel}-titleId`; let ariaDescribedBy = titleId; const titleElement = {title}; @@ -58,7 +58,7 @@ const Icon = ({ return ( { expect(toJSON()).toMatchSnapshot(); }); + + it('should match snapshot with accessible props', () => { + const { toJSON } = render( + + + , + ); + + expect(toJSON()).toMatchSnapshot(); + }); }); diff --git a/packages/yoga/src/Icon/native/__snapshots__/Icon.test.jsx.snap b/packages/yoga/src/Icon/native/__snapshots__/Icon.test.jsx.snap index c4a71e9005..6917a5536d 100644 --- a/packages/yoga/src/Icon/native/__snapshots__/Icon.test.jsx.snap +++ b/packages/yoga/src/Icon/native/__snapshots__/Icon.test.jsx.snap @@ -2,6 +2,7 @@ exports[`Snapshots should match snapshot 1`] = ` `; +exports[`Snapshots should match snapshot whit acessible props 1`] = ` + + + Circle icon + + + This is a circular icon + + + +`; + exports[`Snapshots should match snapshot with size prop 1`] = ` { expect(container).toMatchSnapshot(); }); + + it('should match snapshot with acessible props', () => { + const { container } = render( + + + , + ); + + expect(container).toMatchSnapshot(); + }); }); diff --git a/packages/yoga/src/Icon/web/__snapshots__/Icon.test.jsx.snap b/packages/yoga/src/Icon/web/__snapshots__/Icon.test.jsx.snap index 585cef42c9..d9e503ed27 100644 --- a/packages/yoga/src/Icon/web/__snapshots__/Icon.test.jsx.snap +++ b/packages/yoga/src/Icon/web/__snapshots__/Icon.test.jsx.snap @@ -8,6 +8,7 @@ exports[`Snapshots should match snapshot 1`] = `
+ + + Circle icon + + + This is a circular icon + + + +
+`; + exports[`Snapshots should match snapshot with size prop 1`] = ` .c0 { width: 16px; @@ -30,6 +66,7 @@ exports[`Snapshots should match snapshot with size prop 1`] = `
+ + + Circle icon + + + This is a circular icon + + + +
+`; + exports[`Snapshots should match snapshot with size prop 1`] = ` .c0 { width: 16px; From 5ee9d86675139d7751d45e0e39b635e5f170bb5c Mon Sep 17 00:00:00 2001 From: Flavia Moraes Date: Wed, 6 Sep 2023 15:28:11 -0300 Subject: [PATCH 5/5] test: update snapshots --- .../native/__snapshots__/Avatar.test.jsx.snap | 4 ++ .../web/__snapshots__/Avatar.test.jsx.snap | 4 ++ .../native/__snapshots__/Banner.test.jsx.snap | 1 + .../web/__snapshots__/Banner.test.jsx.snap | 1 + .../native/__snapshots__/Button.test.jsx.snap | 6 +++ .../web/__snapshots__/Button.test.jsx.snap | 8 ++++ .../__snapshots__/PlanCard.test.jsx.snap | 2 + .../__snapshots__/PlanCard.test.jsx.snap | 2 + .../web/__snapshots__/Dialog.test.jsx.snap | 1 + .../web/__snapshots__/Feedback.test.jsx.snap | 4 ++ .../web/__snapshots__/Heading.test.jsx.snap | 6 +++ packages/yoga/src/Icon/Icon.jsx | 45 +++++++++++-------- .../native/__snapshots__/Icon.test.jsx.snap | 35 --------------- .../Icon/web/__snapshots__/Icon.test.jsx.snap | 35 --------------- .../Menu/web/__snapshots__/Menu.test.jsx.snap | 9 ++++ .../native/__snapshots__/Result.test.jsx.snap | 9 ++++ .../__snapshots__/Snackbar.test.jsx.snap | 2 + .../web/__snapshots__/Snackbar.test.jsx.snap | 2 + .../native/__snapshots__/Tag.test.jsx.snap | 2 + .../Tag/web/__snapshots__/Tag.test.jsx.snap | 1 + 20 files changed, 91 insertions(+), 88 deletions(-) diff --git a/packages/yoga/src/Avatar/native/__snapshots__/Avatar.test.jsx.snap b/packages/yoga/src/Avatar/native/__snapshots__/Avatar.test.jsx.snap index 791a46baff..be43db2bef 100644 --- a/packages/yoga/src/Avatar/native/__snapshots__/Avatar.test.jsx.snap +++ b/packages/yoga/src/Avatar/native/__snapshots__/Avatar.test.jsx.snap @@ -88,6 +88,7 @@ exports[` should match snapshot in circle avatar 1`] = ` width={48} > should match snapshot in circle avatar with placeholder prop width={48} > should match snapshot in default avatar 1`] = ` width={78} > should match snapshot in default avatar with placeholder pro width={48} > should match snapshot in circle avatar 1`] = ` width="48" > should match snapshot in circle avatar with placeholder prop width="48" > should match snapshot in default avatar 1`] = ` width="78" > should match snapshot in default avatar with placeholder pro width="48" > should match snapshot with icon 1`] = ` } > should match snapshot with icon 1`] = ` display="flex" > Snapshots disabled buttons With disabled prop should match s } > Snapshots primary buttons With inverted prop should match sn } > Snapshots primary buttons With large prop should match snaps } > Snapshots secondary buttons With inverted prop should match } > Snapshots secondary buttons With large prop should match sna } > Snapshots secondary buttons Without props should match snaps } > Snapshots disabled buttons With disabled prop should match s disabled="" > Snapshots primary buttons With disabled prop should match sn disabled="" > Snapshots primary buttons With inverted prop should match sn class="c0" > Snapshots primary buttons With small prop should match snaps class="c0" > Snapshots primary buttons Without props should match snapsho class="c0" > Snapshots secondary buttons With inverted prop should match class="c0" > Snapshots secondary buttons With small prop should match sna class="c0" > Snapshots secondary buttons Without props should match snaps class="c0" > Snapshots should match snapshot with default PlanCard 1`] } > Snapshots should match snapshot with default PlanCard 1`] } > Snapshots should match snapshot with default PlanCard 1`] class="c15" > Snapshots should render list item content as button 1`] = class="c15" > should match snapshot with close button 1`] = ` class="c4" > should render correctly when not centered vertically 1`] = class="c1" > should render the icon for attention variant 1`] = ` } should render the icon for informative variant 1`] = ` } should render the icon for success variant 1`] = ` } should match snapshot no padding 1`] = ` class="c1 c2" > should match snapshot no padding 1`] = ` class="c1 c7" > should match snapshot with all components 1`] = ` class="c1 c2" > should match snapshot with all components 1`] = ` class="c1 c7" > should match snapshot with back button 1`] = ` class="c1 c2" > should match snapshot with title and back button 1`] = ` class="c1 c2" > `; -exports[`Snapshots should match snapshot whit acessible props 1`] = ` - - - Circle icon - - - This is a circular icon - - - -`; - exports[`Snapshots should match snapshot with accessible props 1`] = ` `; -exports[`Snapshots should match snapshot when acessible props is passed 1`] = ` -.c0 { - width: 16px; - height: 16px; -} - -
- - - Circle icon - - - This is a circular icon - - - -
-`; - exports[`Snapshots should match snapshot with acessible props 1`] = ` .c0 { width: 16px; diff --git a/packages/yoga/src/Menu/web/__snapshots__/Menu.test.jsx.snap b/packages/yoga/src/Menu/web/__snapshots__/Menu.test.jsx.snap index ef8f92be4b..21a8f5c92a 100644 --- a/packages/yoga/src/Menu/web/__snapshots__/Menu.test.jsx.snap +++ b/packages/yoga/src/Menu/web/__snapshots__/Menu.test.jsx.snap @@ -88,6 +88,7 @@ exports[` should match snapshot Menu with a onMouseHover props false 1`] type="button" > should match snapshot Menu with an align props end 1`] = ` type="button" > should match snapshot Menu with an align props start 1`] = ` type="button" > should match snapshot Menu.Item with active 1`] = ` type="button" > should match snapshot Menu.Item with disabled 1`] = ` type="button" > should match snapshot Menu.Item with disabled and icon 1`] = ` type="button" > should match snapshot Menu.Item with icon 1`] = ` type="button" > should match snapshot Menu.Item with link 1`] = ` type="button" > should match snapshot in default Menu 1`] = ` type="button" > should match snapshot 1`] = ` width={48} > should match snapshot 1`] = ` width="xsmall" > should match snapshot 1`] = ` width="xsmall" > should match snapshot 1`] = ` } > should match snapshot without attendence 1`] = ` width={48} > should match snapshot without limitLabel prop 1`] = ` width={48} > should match snapshot without limitLabel prop 1`] = ` width="xsmall" > should match snapshot without limitLabel prop 1`] = ` width="xsmall" > should match snapshot without limitLabel prop 1`] = ` } > should match snapshot when have a long text 1`] = ` variant="success" > should match snapshot when have an icon and action 1`] = ` variant="success" > should match snapshot 1`] = ` role="img" > should match snapshot 1`] = ` role="button" > should match snapshot with custom icon and informative type 1`] } > should match snapshot with custom icon and informative type 1`] } > should match snapshot with custom icon and informative type 1`] class="c0 c1" >