Skip to content

Commit

Permalink
Merge branch 'main' into feature/521-CreateRadioButtonComponent
Browse files Browse the repository at this point in the history
  • Loading branch information
TimRoe authored Nov 5, 2024
2 parents f387776 + 56e87a2 commit 91fe719
Show file tree
Hide file tree
Showing 15 changed files with 197 additions and 85 deletions.
26 changes: 26 additions & 0 deletions documentation/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
# Changelog

## [components-v0.27.0](https://github.com/department-of-veterans-affairs/va-mobile-library/tree/components-v0.27.0) (2024-11-01)

[Full Changelog](https://github.com/department-of-veterans-affairs/va-mobile-library/compare/components-v0.26.0...components-v0.27.0)

**Closed issues:**

- DS - Typography Component - Align with VADS and publish documentation [\#557](https://github.com/department-of-veterans-affairs/va-mobile-library/issues/557)
- Assets - Add BitterRegular font family, remove BitterBold font family [\#538](https://github.com/department-of-veterans-affairs/va-mobile-library/issues/538)
- Accessibility: Add Heading Label for Screenreader Users [\#533](https://github.com/department-of-veterans-affairs/va-mobile-library/issues/533)
- Accessibility: Add Item Count to Checkbox Group for Screenreader Users [\#532](https://github.com/department-of-veterans-affairs/va-mobile-library/issues/532)
- Text Input: Prep for handoff [\#498](https://github.com/department-of-veterans-affairs/va-mobile-library/issues/498)
- \[Design Tokens\] Typography: Add tokens to tokens package [\#494](https://github.com/department-of-veterans-affairs/va-mobile-library/issues/494)
- \[Figma\] Add annotations to template [\#489](https://github.com/department-of-veterans-affairs/va-mobile-library/issues/489)
- DS - Checkbox Component Implementation [\#455](https://github.com/department-of-veterans-affairs/va-mobile-library/issues/455)
- DS - Checkbox Group Component Flagship Work Setup [\#433](https://github.com/department-of-veterans-affairs/va-mobile-library/issues/433)
- DS - Checkbox Group Component Unit Tests [\#431](https://github.com/department-of-veterans-affairs/va-mobile-library/issues/431)
- \[Design Tokens\] Typography: Prep for handoff [\#425](https://github.com/department-of-veterans-affairs/va-mobile-library/issues/425)
- \[Design Tokens\] Colors: Create divider and feedback tokens [\#419](https://github.com/department-of-veterans-affairs/va-mobile-library/issues/419)
- DS - Q3 Bug & Maintenance Mgmt [\#402](https://github.com/department-of-veterans-affairs/va-mobile-library/issues/402)
- DS - Create CheckboxGroup Component [\#69](https://github.com/department-of-veterans-affairs/va-mobile-library/issues/69)

**Merged pull requests:**

- \[Bug\] Link - Flagship crash mitigation efforts [\#573](https://github.com/department-of-veterans-affairs/va-mobile-library/pull/573) ([TimRoe](https://github.com/TimRoe))
- \[Feature\] Checkbox/CheckboxGroup: Add heading role and list position [\#545](https://github.com/department-of-veterans-affairs/va-mobile-library/pull/545) ([narin](https://github.com/narin))

## [components-v0.26.0](https://github.com/department-of-veterans-affairs/va-mobile-library/tree/components-v0.26.0) (2024-10-21)

[Full Changelog](https://github.com/department-of-veterans-affairs/va-mobile-library/compare/assets-v0.14.0...components-v0.26.0)
Expand Down
2 changes: 1 addition & 1 deletion packages/components/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@department-of-veterans-affairs/mobile-component-library",
"version": "0.26.0",
"version": "0.27.0",
"description": "VA Design System Mobile Component Library",
"main": "src/index.tsx",
"scripts": {
Expand Down
49 changes: 49 additions & 0 deletions packages/components/src/components/Checkbox/Checkbox.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ describe('Checkbox', () => {
onPress: onPressSpy,
}

const labelObject = { text: 'Label text object', a11yLabel: 'Label a11y' }
const descriptionObject = {
text: 'Description text object',
a11yLabel: 'Description a11y',
}

const errorMsg = 'Error text'

describe('Basic tests', () => {
Expand Down Expand Up @@ -75,6 +81,49 @@ describe('Checkbox', () => {
})
})

describe('Accessibility', () => {
it('should have a11y labels when label and description are strings', () => {
render(<Checkbox {...commonProps} />)
expect(
screen.getByLabelText('Label text, Description text'),
).toBeOnTheScreen()
})

it('should include required in a11y label', () => {
render(<Checkbox {...commonProps} required />)
expect(
screen.getByLabelText('Label text, Required, Description text'),
).toBeOnTheScreen()
})

it('should have a11y labels when label and description are TextWithA11y objects', () => {
render(
<Checkbox
{...commonProps}
label={labelObject}
description={descriptionObject}
required
/>,
)
expect(
screen.getByLabelText('Label a11y, Required, Description a11y'),
).toBeOnTheScreen()
})

it('should have a11y labels when label and description are objects without a11y', () => {
render(
<Checkbox
{...commonProps}
label={{ text: 'Label without a11y' }}
description={{ text: 'Description without a11y' }}
/>,
)
expect(
screen.getByLabelText('Label without a11y, Description without a11y'),
).toBeOnTheScreen()
})
})

describe('Styling', () => {
describe('Light mode', () => {
it('icon color (unchecked)', async () => {
Expand Down
15 changes: 14 additions & 1 deletion packages/components/src/components/Checkbox/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
useWindowDimensions,
} from 'react-native'
import { spacing } from '@department-of-veterans-affairs/mobile-tokens'
import { useTranslation } from 'react-i18next'
import React, { FC } from 'react'

import { CheckboxRadioProps, FormElementProps } from '../../types/forms'
Expand All @@ -20,7 +21,7 @@ import {
} from '../shared/FormText'
import { Icon, IconProps } from '../Icon/Icon'
import { Spacer } from '../Spacer/Spacer'
import { useTheme } from '../../utils'
import { getA11yLabel, useTheme } from '../../utils'

export type CheckboxProps = FormElementProps &
CheckboxRadioProps & {
Expand All @@ -31,6 +32,7 @@ export type CheckboxProps = FormElementProps &
}

export const Checkbox: FC<CheckboxProps> = ({
a11yListPosition,
checked,
label,
description,
Expand All @@ -44,6 +46,7 @@ export const Checkbox: FC<CheckboxProps> = ({
tile,
}) => {
const theme = useTheme()
const { t } = useTranslation()
const fontScale = useWindowDimensions().fontScale

/**
Expand Down Expand Up @@ -115,6 +118,14 @@ export const Checkbox: FC<CheckboxProps> = ({
</View>
)

/**
* Combined a11yLabel on Pressable required for Android Talkback
*/
const a11yLabel =
getA11yLabel(label) +
(required ? ', ' + t('required') : '') +
(description ? `, ${getA11yLabel(description)}` : '')

return (
<ComponentWrapper>
<View style={containerStyle} testID={testID}>
Expand All @@ -131,6 +142,8 @@ export const Checkbox: FC<CheckboxProps> = ({
onPress={onPress}
style={tile ? tileStyle : pressableBaseStyle}
aria-checked={indeterminate ? 'mixed' : checked}
aria-valuetext={a11yListPosition}
aria-label={a11yLabel}
role="checkbox">
{_icon}
<Spacer size="xs" horizontal />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,17 @@ describe('CheckboxGroup', () => {
expect(checkboxes[4].props.accessibilityState.checked).toBe(false)
expect(checkboxes[5].props.accessibilityState.checked).toBe(false)
})

it('should have accessibilityValues on checkboxes', () => {
render(<CheckboxGroup {...commonProps} />)
const checkboxes = screen.queryAllByRole('checkbox')
expect(checkboxes[0].props.accessibilityValue.text).toBe('1 of 6')
expect(checkboxes[1].props.accessibilityValue.text).toBe('2 of 6')
expect(checkboxes[2].props.accessibilityValue.text).toBe('3 of 6')
expect(checkboxes[3].props.accessibilityValue.text).toBe('4 of 6')
expect(checkboxes[4].props.accessibilityValue.text).toBe('5 of 6')
expect(checkboxes[5].props.accessibilityValue.text).toBe('6 of 6')
})
})

describe('onPress behavior', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { View, ViewStyle } from 'react-native'
import { spacing } from '@department-of-veterans-affairs/mobile-tokens'
import { useTranslation } from 'react-i18next'
import React, { FC, Fragment } from 'react'

import { Checkbox } from '../Checkbox/Checkbox'
Expand Down Expand Up @@ -99,6 +100,7 @@ export const CheckboxGroup: FC<CheckboxGroupProps> = ({
tile,
}) => {
const theme = useTheme()
const { t } = useTranslation()

const handleCheckboxChange = (value: string | number) => {
if (selectedItems.includes(value)) {
Expand Down Expand Up @@ -141,11 +143,16 @@ export const CheckboxGroup: FC<CheckboxGroupProps> = ({
{items.map((item, index) => {
const isObject = typeof item === 'object'
const value = isObject ? item.value || item.text : item
const a11yListPosition = t('listPosition', {
position: index + 1,
total: items.length,
})

return (
<Fragment key={`checkbox-group-item-${index}`}>
<Checkbox
label={item}
a11yListPosition={a11yListPosition}
description={isObject ? item.description : undefined}
checked={selectedItems.includes(value)}
onPress={() => handleCheckboxChange(value)}
Expand Down
35 changes: 32 additions & 3 deletions packages/components/src/components/Icon/Icon.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,29 @@
import { ColorValue, useWindowDimensions } from 'react-native'
import { ColorValue, View, ViewStyle, useWindowDimensions } from 'react-native'
import { SvgProps } from 'react-native-svg'
import React, { FC } from 'react'

import { IconMap } from './iconList'
import { useColorScheme, useTheme } from '../../utils'

type nameOrSvg =
type nameOrSvgOrNoIcon =
| {
/** Name of preset icon to use {@link IconMap} **/
name: keyof typeof IconMap
noIcon?: never
svg?: never
}
| {
name?: never
noIcon?: never
/** Custom SVG passed to display */
svg: React.FC<SvgProps>
}
| {
name?: never
/** True to render icon as a null passthrough */
noIcon: boolean
svg?: never
}

type heightAndWidth =
| {
Expand All @@ -37,8 +45,10 @@ type lightDarkModeFill = {
/**
* Props that need to be passed in to {@link Icon}
*/
export type IconProps = nameOrSvg &
export type IconProps = nameOrSvgOrNoIcon &
heightAndWidth & {
/** Wraps in View that aligns the icon with text of line height passed */
alignWithTextLineHeight?: number
/** Fill color for the icon, defaults to light/dark mode primary blue */
fill?: 'default' | 'base' | ColorValue | lightDarkModeFill
/** Optional maximum width when scaled */
Expand All @@ -60,9 +70,11 @@ export type IconProps = nameOrSvg &
*/
export const Icon: FC<IconProps> = ({
name,
noIcon,
svg,
width = 24,
height = 24,
alignWithTextLineHeight,
fill = 'default',
maxWidth,
preventScaling,
Expand All @@ -73,6 +85,8 @@ export const Icon: FC<IconProps> = ({
const fontScale = useWindowDimensions().fontScale
const fs = (val: number) => fontScale * val

if (noIcon) return null

// ! to override TS incorrectly thinking svg can be undefined after update
const _Icon: FC<SvgProps> = name ? IconMap[name] : svg!

Expand All @@ -96,5 +110,20 @@ export const Icon: FC<IconProps> = ({
iconProps = { ...iconProps, width: fs(width), height: fs(height) }
}

if (alignWithTextLineHeight) {
const viewStyle: ViewStyle = {
alignSelf: 'flex-start',
minHeight: alignWithTextLineHeight * fontScale,
alignItems: 'center',
justifyContent: 'center',
}

return (
<View style={viewStyle}>
<_Icon {...iconProps} testID={testID} />
</View>
)
}

return <_Icon {...iconProps} testID={testID} />
}
5 changes: 5 additions & 0 deletions packages/components/src/components/Link/Link.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ export const _ExternalLink: Story = {
onCancel: () => console.log('Analytics event: Canceled'),
onPress: () => console.log('Analytics event: Pressed'),
onConfirm: () => console.log('Analytics event: Confirmed'),
onOpenURLError: (e, url) => {
console.log(JSON.stringify(e))
console.log('Error: ' + e)
console.log('Error opening URL: ' + url)
},
},
},
}
Expand Down
8 changes: 6 additions & 2 deletions packages/components/src/components/Link/Link.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ describe('Link', () => {
render(<Link {...commonProps} />)
const icon = screen.UNSAFE_queryByType(Icon)

expect(icon).toBeNull()
expect(icon?.props.name).toBeUndefined()
expect(icon?.props.svg).toBeUndefined()
expect(icon?.props.noIcon).toBeDefined()
})
})

Expand Down Expand Up @@ -414,7 +416,9 @@ describe('Link', () => {
render(<Link {...iconOverrideProps} icon={'no icon'} />)
const icon = screen.UNSAFE_queryByType(Icon)

expect(icon).toBeFalsy()
expect(icon?.props.name).toBeUndefined()
expect(icon?.props.svg).toBeUndefined()
expect(icon?.props.noIcon).toBeDefined()
})
})

Expand Down
Loading

0 comments on commit 91fe719

Please sign in to comment.