From f3aec52e82f7a95677273c330ae7818470355bd1 Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Tue, 24 Sep 2024 21:37:01 -0700 Subject: [PATCH 01/34] Create CheckboxGroup component and stories --- .../CheckboxGroup/CheckboxGroup.stories.tsx | 139 ++++++++++++ .../CheckboxGroup/CheckboxGroup.tsx | 197 ++++++++++++++++++ 2 files changed, 336 insertions(+) create mode 100644 packages/components/src/components/CheckboxGroup/CheckboxGroup.stories.tsx create mode 100644 packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx diff --git a/packages/components/src/components/CheckboxGroup/CheckboxGroup.stories.tsx b/packages/components/src/components/CheckboxGroup/CheckboxGroup.stories.tsx new file mode 100644 index 00000000..36614b6f --- /dev/null +++ b/packages/components/src/components/CheckboxGroup/CheckboxGroup.stories.tsx @@ -0,0 +1,139 @@ +import { Meta, StoryObj } from '@storybook/react' +import { View } from 'react-native' +import React, { useState } from 'react' + +import { CheckboxGroup, CheckboxGroupProps } from './CheckboxGroup' +import { generateDocs } from '../../utils/storybook' + +const meta: Meta = { + title: 'Checkbox group', + component: CheckboxGroup, + decorators: [ + (Story) => ( + + {Story()} + + ), + ], + parameters: { + design: [ + { + name: 'Figma component overview', + type: 'figma', + url: 'https://www.figma.com/design/mAMh8vyVgsevAOungfvGN6/%5BNEW%5D-Checkbox---%23427?node-id=1509-5372&t=eTj3nXLA5XBywjl0-4', + }, + { + name: 'Figma examples', + type: 'figma', + url: 'https://www.figma.com/design/mAMh8vyVgsevAOungfvGN6/%5BNEW%5D-Checkbox---%23427?node-id=1509-5373&t=bI5ocY9b39t81dX4-4', + }, + ], + docs: generateDocs({ + name: 'Checkbox group', + docUrl: + 'https://department-of-veterans-affairs.github.io/va-mobile-app/design/Components/Selection%20and%20Input/Checkbox/', + }), + }, +} + +export default meta + +type Story = StoryObj + +const statefulComponentRenderer = (props: CheckboxGroupProps) => { + const { + description, + descriptionA11y, + error, + errorA11y, + header, + headerA11y, + hint, + hintA11y, + required, + tile, + } = props + + const [selectedItems, setSelectedItems] = useState<(string | number)[]>([]) + + const items = [ + { + label: 'Option 1', + labelA11y: 'Accessibility override for option 1', + value: '1', + }, + { label: 'Option 2' }, + { label: 'Option 3' }, + { label: 'Option 4' }, + { label: 'Option 5' }, + { label: 'Option 6' }, + ] + + return ( + setSelectedItems(selected)} + required={required} + tile={tile} + /> + ) +} + +const header = 'Label Header', + headerA11y = 'Accessibility override for header', + hint = 'Hint about this checkbox group', + hintA11y = 'Accessibility override for hint', + error = 'Error text', + errorA11y = 'Accessibility override for error', + description = 'Checkbox description', + descriptionA11y = 'Accessibility override for description' + +export const _Default: Story = { + render: statefulComponentRenderer, + args: { + header, + headerA11y, + hint, + hintA11y, + description, + descriptionA11y, + required: true, + }, +} + +export const __Tile: Story = { + render: statefulComponentRenderer, + args: { + tile: true, + header, + headerA11y, + hint, + hintA11y, + description, + descriptionA11y, + }, +} + +export const ___Error: Story = { + render: statefulComponentRenderer, + args: { + error, + errorA11y, + header, + headerA11y, + hint, + hintA11y, + description, + descriptionA11y, + required: true, + }, +} diff --git a/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx b/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx new file mode 100644 index 00000000..7170822b --- /dev/null +++ b/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx @@ -0,0 +1,197 @@ +import { Text, 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' +import { ComponentWrapper } from '../../wrapper' +import { Spacer } from '../Spacer/Spacer' +import { useTheme } from '../../utils' + +export type CheckboxGroupItem = { + label: string + a11y?: string + value?: string | number +} + +export type CheckboxGroupProps = { + /** Array of checkbox options. Can be an array of strings or objects if values and/or a11y overrides are needed */ + items: CheckboxGroupItem[] | string[] + /** OnPress logic to alter `checked` state or other behavior associated with the checkbox */ + onSelectionChange: (selected: (string | number)[]) => void + /** Callback function that receives an updated array of selected values when checkboxes are pressed */ + selectedItems: (string | number)[] + /** Description that appears below label */ + description?: string + /** Accessibility override for description text */ + descriptionA11y?: string + /** Hint text. Appears below header */ + hint?: string + /** Accessibility override for hint text */ + hintA11y?: string + /** Optional error text. If present, applies error styling to checkbox */ + error?: string + /** Accessibility override for error text */ + errorA11y?: string + /** Header text */ + header?: string + /** Accessibility override for header */ + headerA11y?: string + /** True to append (*Required) suffix to label */ + required?: boolean + /** True to apply tile styling */ + tile?: boolean +} + +export const CheckboxGroup: FC = ({ + items, + selectedItems, + error, + errorA11y, + header, + headerA11y, + hint, + hintA11y, + onSelectionChange, + required, + tile, +}) => { + const { t } = useTranslation() + const theme = useTheme() + + const handleCheckboxChange = (value: string | number) => { + if (selectedItems.includes(value)) { + onSelectionChange( + selectedItems.filter((itemValue) => itemValue !== value), + ) + } else { + onSelectionChange([...selectedItems, value]) + } + } + + /** + * Fonts + */ + // TODO: Replace with typography tokens + const fontRegular = 'SourceSansPro-Regular' + const fontBold = 'SourceSansPro-Bold' + + const fontHeader = { + fontFamily: fontRegular, + color: theme.vadsColorForegroundDefault, + fontSize: 20, + lineHeight: 30, + } + + const fontHint = { + fontFamily: fontRegular, + color: theme.vadsColorForegroundSubtle, + fontSize: 16, + lineHeight: 22, + } + + const fontError = { + fontFamily: fontBold, + color: theme.vadsColorForegroundError, + fontSize: 16, + lineHeight: 22, + } + + /** + * Container styling + */ + let containerStyle: ViewStyle = { + width: '100%', + } + + if (error) { + containerStyle = { + ...containerStyle, + borderLeftWidth: spacing.vadsSpace2xs, + borderColor: theme.vadsColorFormsBorderError, + paddingLeft: spacing.vadsSpaceLg, + } + } + + /** + * Header + */ + const headerProps = { + 'aria-label': headerA11y, + style: fontHeader, + } + + const requiredStyle = { + color: theme.vadsColorForegroundError, + } + + const _header = header && ( + <> + + {header} + {required && ( + {` (*${t('required')})`} + )} + + + + ) + + /** + * Hint + */ + const hintProps = { + 'aria-label': hintA11y, + style: fontHint, + } + + const _hint = hint && ( + <> + {hint} + + + ) + + /** + * Error + */ + const errorProps = { + 'aria-label': `${t('error')}: ${errorA11y || error}`, + style: fontError, + } + + const _error = error && ( + <> + {error} + + + ) + + return ( + + + {_header} + {_hint} + {_error} + {items.map((item, index) => { + const isObject = typeof item === 'object' + const label = isObject ? item.label : item + const value = isObject ? item.value || item.label : item + + return ( + + handleCheckboxChange(value)} + tile={tile} + /> + {index < items.length - 1 && } + + ) + })} + + + ) +} From ddb80b7a288ca156128d0000a93af22b42cc60e4 Mon Sep 17 00:00:00 2001 From: VA Automation Bot Date: Wed, 25 Sep 2024 04:44:03 +0000 Subject: [PATCH 02/34] Version bump: components-v0.25.1-alpha.0 --- packages/components/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/package.json b/packages/components/package.json index fe188575..05a16b07 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@department-of-veterans-affairs/mobile-component-library", - "version": "0.25.0", + "version": "0.25.1-alpha.0", "description": "VA Design System Mobile Component Library", "main": "src/index.tsx", "scripts": { From 23b95d47503c95ac7e8c53c04ce96c69d3985505 Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Wed, 25 Sep 2024 11:45:11 -0700 Subject: [PATCH 03/34] Create AccessibleText type, common form props, form text components. Create Forms folder and restructure --- .../components/.storybook/web/preview.tsx | 3 + .../src/components/Checkbox/Checkbox.tsx | 282 ------------------ .../{ => Forms}/Checkbox/Checkbox.stories.tsx | 47 +-- .../components/Forms/Checkbox/Checkbox.tsx | 154 ++++++++++ .../CheckboxGroup/CheckboxGroup.stories.tsx | 16 +- .../CheckboxGroup/CheckboxGroup.tsx | 134 ++------- .../src/components/Forms/FormText.tsx | 163 ++++++++++ packages/components/src/index.tsx | 2 +- packages/components/src/types/common.ts | 8 + packages/components/src/types/forms.ts | 23 ++ .../components/src/utils/accessibility.ts | 18 ++ 11 files changed, 421 insertions(+), 429 deletions(-) delete mode 100644 packages/components/src/components/Checkbox/Checkbox.tsx rename packages/components/src/components/{ => Forms}/Checkbox/Checkbox.stories.tsx (71%) create mode 100644 packages/components/src/components/Forms/Checkbox/Checkbox.tsx rename packages/components/src/components/{ => Forms}/CheckboxGroup/CheckboxGroup.stories.tsx (91%) rename packages/components/src/components/{ => Forms}/CheckboxGroup/CheckboxGroup.tsx (54%) create mode 100644 packages/components/src/components/Forms/FormText.tsx create mode 100644 packages/components/src/types/common.ts create mode 100644 packages/components/src/types/forms.ts diff --git a/packages/components/.storybook/web/preview.tsx b/packages/components/.storybook/web/preview.tsx index e9842e67..08e0ecc5 100644 --- a/packages/components/.storybook/web/preview.tsx +++ b/packages/components/.storybook/web/preview.tsx @@ -21,6 +21,9 @@ export const parameters = { currentProps.theme = isDark ? themes.dark : themes.light return React.createElement(DocsContainer, currentProps) }, + controls: { + sort: 'requiredFirst', + }, }, viewport: { defaultViewport: 'mobile2', diff --git a/packages/components/src/components/Checkbox/Checkbox.tsx b/packages/components/src/components/Checkbox/Checkbox.tsx deleted file mode 100644 index d4960504..00000000 --- a/packages/components/src/components/Checkbox/Checkbox.tsx +++ /dev/null @@ -1,282 +0,0 @@ -import { - Pressable, - StyleProp, - Text, - View, - ViewStyle, - useWindowDimensions, -} from 'react-native' -import { spacing } from '@department-of-veterans-affairs/mobile-tokens' -import { useTranslation } from 'react-i18next' -import React, { FC } from 'react' - -import { ComponentWrapper } from '../../wrapper' -import { Icon, IconProps } from '../Icon/Icon' -import { Spacer } from '../Spacer/Spacer' -import { useTheme } from '../../utils' - -export type CheckboxProps = { - /** Primary text for checkbox */ - label: string - /** OnPress logic to alter `checked` state or other behavior associated with the checkbox */ - onPress: () => void - /** True to make checkbox appear as checked */ - checked?: boolean - /** Description that appears below label */ - description?: string - /** Accessibility override for description text */ - descriptionA11y?: string - /** Hint text. Appears below header */ - hint?: string - /** Accessibility override for hint text */ - hintA11y?: string - /** Optional error text. If present, applies error styling to checkbox */ - error?: string - /** Accessibility override for error text */ - errorA11y?: string - /** Header text */ - header?: string - /** Accessibility override for header */ - headerA11y?: string - /** True to apply indeterminate icon to checkbox */ - indeterminate?: boolean - /** Accessibility override for label */ - labelA11y?: string - /** True to append (*Required) suffix to label */ - required?: boolean - /** True to apply tile styling */ - tile?: boolean -} - -export const Checkbox: FC = ({ - checked, - label, - labelA11y, - description, - descriptionA11y, - error, - errorA11y, - header, - headerA11y, - hint, - hintA11y, - indeterminate, - onPress, - required, - tile, -}) => { - const { t } = useTranslation() - const theme = useTheme() - const fontScale = useWindowDimensions().fontScale - - /** - * Fonts - */ - // TODO: Replace with typography tokens - const fontRegular = 'SourceSansPro-Regular' - const fontBold = 'SourceSansPro-Bold' - - const fontHeader = { - fontFamily: fontRegular, - color: theme.vadsColorForegroundDefault, - fontSize: 20, - lineHeight: 30, - } - - const fontHint = { - fontFamily: fontRegular, - color: theme.vadsColorForegroundSubtle, - fontSize: 16, - lineHeight: 22, - } - - const fontError = { - fontFamily: fontBold, - color: theme.vadsColorForegroundError, - fontSize: 16, - lineHeight: 22, - } - - const fontLabel = { - fontFamily: error ? fontBold : fontRegular, - color: theme.vadsColorForegroundDefault, - fontSize: 20, - lineHeight: 30, - } - - const fontDescription = { - fontFamily: fontRegular, - color: theme.vadsColorForegroundDefault, - fontSize: 16, - lineHeight: 22, - } - - /** - * Container styling - */ - let containerStyle: ViewStyle = { - width: '100%', - } - - if (error) { - containerStyle = { - ...containerStyle, - borderLeftWidth: spacing.vadsSpace2xs, - borderColor: theme.vadsColorFormsBorderError, - paddingLeft: spacing.vadsSpaceLg, - } - } - - /** - * Pressable styling - */ - const pressableBaseStyle: StyleProp = { - width: '100%', - flexDirection: 'row', - alignItems: 'flex-start', - } - - const tileStyle: ViewStyle = { - ...pressableBaseStyle, - borderWidth: 2, - borderRadius: spacing.vadsSpace2xs, - padding: spacing.vadsSpaceSm, - paddingRight: spacing.vadsSpaceMd, - borderColor: checked - ? theme.vadsColorFormsBorderActive - : theme.vadsColorFormsBorderSubtle, - backgroundColor: checked - ? theme.vadsColorFormsSurfaceActive - : theme.vadsColorSurfaceDefault, - } - - /** - * Header - */ - const headerProps = { - 'aria-label': headerA11y, - style: fontHeader, - } - - const _header = header && ( - <> - {header} - - - ) - - /** - * Hint - */ - const hintProps = { - 'aria-label': hintA11y, - style: fontHint, - } - - const _hint = hint && ( - <> - {hint} - - - ) - - /** - * Error - */ - const errorProps = { - 'aria-label': `${t('error')}: ${errorA11y || error}`, - style: fontError, - } - - const _error = error && ( - <> - {error} - - - ) - - /** - * Icon - */ - const iconViewStyle: ViewStyle = { - // Below keeps icon aligned with first row of text, centered, and scalable - alignSelf: 'flex-start', - minHeight: fontLabel.lineHeight * fontScale, - alignItems: 'center', - justifyContent: 'center', - } - - const iconProps: IconProps = { - name: indeterminate - ? 'IndeterminateCheckBox' - : checked - ? 'CheckBox' - : 'CheckBoxOutlineBlank', - fill: - checked || indeterminate - ? theme.vadsColorFormsForegroundActive - : theme.vadsColorFormsBorderDefault, - } - - const _icon = ( - - - - ) - - /** - * Label - */ - const labelProps = { - 'aria-label': labelA11y, - style: fontLabel, - } - - const requiredStyle = { - color: theme.vadsColorForegroundError, - } - - const _label = ( - - {label} - {required && {` (*${t('required')})`}} - - ) - - /** - * Description - */ - const descriptionProps = { - 'aria-label': descriptionA11y, - style: fontDescription, - } - - const _description = description && ( - <> - - {description} - - ) - - return ( - - - {_header} - {_hint} - {_error} - - {_icon} - - - {_label} - {_description} - - - - - ) -} diff --git a/packages/components/src/components/Checkbox/Checkbox.stories.tsx b/packages/components/src/components/Forms/Checkbox/Checkbox.stories.tsx similarity index 71% rename from packages/components/src/components/Checkbox/Checkbox.stories.tsx rename to packages/components/src/components/Forms/Checkbox/Checkbox.stories.tsx index fd11ea67..7d7dd49a 100644 --- a/packages/components/src/components/Checkbox/Checkbox.stories.tsx +++ b/packages/components/src/components/Forms/Checkbox/Checkbox.stories.tsx @@ -3,7 +3,7 @@ import { View } from 'react-native' import React, { useState } from 'react' import { Checkbox, CheckboxProps } from './Checkbox' -import { generateDocs } from '../../utils/storybook' +import { generateDocs } from '../../../utils/storybook' const meta: Meta = { title: 'Checkbox', @@ -43,16 +43,11 @@ type Story = StoryObj const statefulComponentRenderer = (props: CheckboxProps) => { const { description, - descriptionA11y, error, - errorA11y, header, - headerA11y, hint, - hintA11y, indeterminate, label, - labelA11y, required, tile, } = props @@ -63,16 +58,11 @@ const statefulComponentRenderer = (props: CheckboxProps) => { setChecked(!checked)} required={required} tile={tile} @@ -80,28 +70,25 @@ const statefulComponentRenderer = (props: CheckboxProps) => { ) } -const header = 'Label Header', - headerA11y = 'Accessibility override for header', - hint = 'Hint text', - hintA11y = 'Accessibility override for hint', - error = 'Error text', - errorA11y = 'Accessibility override for error', - label = 'Label', - labelA11y = 'Accessibility override for label', - description = 'Checkbox description', - descriptionA11y = 'Accessibility override for description' +const header = { + text: 'Label Header', + a11y: 'Accessibility override for header', + }, + hint = { text: 'Hint text', a11y: 'Accessibility override for hint' }, + error = { text: 'Error text', a11y: 'Accessibility override for error' }, + label = { text: 'Label', a11y: 'Accessibility override for label' }, + description = { + text: 'Checkbox description', + a11y: 'Accessibility override for description', + } export const _Default: Story = { render: statefulComponentRenderer, args: { header, - headerA11y, hint, - hintA11y, label, - labelA11y, description, - descriptionA11y, required: true, }, } @@ -111,13 +98,9 @@ export const __Tile: Story = { args: { tile: true, header, - headerA11y, hint, - hintA11y, label, - labelA11y, description, - descriptionA11y, }, } @@ -125,7 +108,6 @@ export const ___CheckboxOnly: Story = { render: statefulComponentRenderer, args: { label, - labelA11y, }, } @@ -133,14 +115,9 @@ export const ____Error: Story = { render: statefulComponentRenderer, args: { header, - headerA11y, hint, - hintA11y, error, - errorA11y, label, - labelA11y, description, - descriptionA11y, }, } diff --git a/packages/components/src/components/Forms/Checkbox/Checkbox.tsx b/packages/components/src/components/Forms/Checkbox/Checkbox.tsx new file mode 100644 index 00000000..8ed6b51a --- /dev/null +++ b/packages/components/src/components/Forms/Checkbox/Checkbox.tsx @@ -0,0 +1,154 @@ +import { + Pressable, + StyleProp, + View, + ViewStyle, + useWindowDimensions, +} from 'react-native' +import { spacing } from '@department-of-veterans-affairs/mobile-tokens' +import React, { FC } from 'react' + +import { CheckboxRadioProps, FormElementProps } from '../../../types/forms' +import { ComponentWrapper } from '../../../wrapper' +import { Description, Error, Header, Hint, Label, fontLabel } from '../FormText' +import { Icon, IconProps } from '../../Icon/Icon' +import { Spacer } from '../../Spacer/Spacer' +import { useTheme } from '../../../utils' + +export type CheckboxProps = FormElementProps & + CheckboxRadioProps & { + /** True to make checkbox appear as checked */ + checked?: boolean + /** True to apply indeterminate icon to checkbox */ + indeterminate?: boolean + } + +export const Checkbox: FC = ({ + checked, + label, + description, + error, + header, + hint, + indeterminate, + onPress, + required, + tile, +}) => { + const theme = useTheme() + const fontScale = useWindowDimensions().fontScale + + /** + * Container styling + */ + let containerStyle: ViewStyle = { + width: '100%', + } + + if (error) { + containerStyle = { + ...containerStyle, + borderLeftWidth: spacing.vadsSpace2xs, + borderColor: theme.vadsColorFormsBorderError, + paddingLeft: spacing.vadsSpaceLg, + } + } + + /** + * Pressable styling + */ + const pressableBaseStyle: StyleProp = { + width: '100%', + flexDirection: 'row', + alignItems: 'flex-start', + } + + const tileStyle: ViewStyle = { + ...pressableBaseStyle, + borderWidth: 2, + borderRadius: spacing.vadsSpace2xs, + padding: spacing.vadsSpaceSm, + paddingRight: spacing.vadsSpaceMd, + borderColor: checked + ? theme.vadsColorFormsBorderActive + : theme.vadsColorFormsBorderSubtle, + backgroundColor: checked + ? theme.vadsColorFormsSurfaceActive + : theme.vadsColorSurfaceDefault, + } + + /** + * Icon + */ + const iconViewStyle: ViewStyle = { + // Below keeps icon aligned with first row of text, centered, and scalable + alignSelf: 'flex-start', + // TODO: Replace lineHeight with typography token + minHeight: fontLabel.lineHeight * fontScale, + alignItems: 'center', + justifyContent: 'center', + } + + const iconProps: IconProps = { + name: indeterminate + ? 'IndeterminateCheckBox' + : checked + ? 'CheckBox' + : 'CheckBoxOutlineBlank', + fill: + checked || indeterminate + ? theme.vadsColorFormsForegroundActive + : theme.vadsColorFormsBorderDefault, + } + + const _icon = ( + + + + ) + + return ( + + + {header && ( + <> +
+ + + )} + + {hint && ( + <> + + + + )} + + {error && ( + <> + + + + )} + + + {_icon} + + + + + + + ) +} diff --git a/packages/components/src/components/CheckboxGroup/CheckboxGroup.stories.tsx b/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.stories.tsx similarity index 91% rename from packages/components/src/components/CheckboxGroup/CheckboxGroup.stories.tsx rename to packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.stories.tsx index 36614b6f..6a204e01 100644 --- a/packages/components/src/components/CheckboxGroup/CheckboxGroup.stories.tsx +++ b/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.stories.tsx @@ -3,7 +3,7 @@ import { View } from 'react-native' import React, { useState } from 'react' import { CheckboxGroup, CheckboxGroupProps } from './CheckboxGroup' -import { generateDocs } from '../../utils/storybook' +import { generateDocs } from '../../../utils/storybook' const meta: Meta = { title: 'Checkbox group', @@ -58,15 +58,15 @@ const statefulComponentRenderer = (props: CheckboxGroupProps) => { const items = [ { - label: 'Option 1', - labelA11y: 'Accessibility override for option 1', + text: 'Option 1', + a11y: 'Accessibility override for option 1', value: '1', }, - { label: 'Option 2' }, - { label: 'Option 3' }, - { label: 'Option 4' }, - { label: 'Option 5' }, - { label: 'Option 6' }, + { text: 'Option 2' }, + { text: 'Option 3' }, + { text: 'Option 4' }, + { text: 'Option 5' }, + { text: 'Option 6' }, ] return ( diff --git a/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx b/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx similarity index 54% rename from packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx rename to packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx index 7170822b..fe5e2ec4 100644 --- a/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx +++ b/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx @@ -1,22 +1,21 @@ -import { Text, View, ViewStyle } from 'react-native' +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 { AccessibleText } from '../../../types/common' import { Checkbox } from '../Checkbox/Checkbox' -import { ComponentWrapper } from '../../wrapper' -import { Spacer } from '../Spacer/Spacer' -import { useTheme } from '../../utils' +import { ComponentWrapper } from '../../../wrapper' +import { Error, Header, Hint } from '../FormText' +import { Spacer } from '../../Spacer/Spacer' +import { useTheme } from '../../../utils' -export type CheckboxGroupItem = { - label: string - a11y?: string +export type CheckboxGroupItem = AccessibleText & { value?: string | number } export type CheckboxGroupProps = { /** Array of checkbox options. Can be an array of strings or objects if values and/or a11y overrides are needed */ - items: CheckboxGroupItem[] | string[] + items: CheckboxGroupItem[] /** OnPress logic to alter `checked` state or other behavior associated with the checkbox */ onSelectionChange: (selected: (string | number)[]) => void /** Callback function that receives an updated array of selected values when checkboxes are pressed */ @@ -47,16 +46,12 @@ export const CheckboxGroup: FC = ({ items, selectedItems, error, - errorA11y, header, - headerA11y, hint, - hintA11y, onSelectionChange, required, tile, }) => { - const { t } = useTranslation() const theme = useTheme() const handleCheckboxChange = (value: string | number) => { @@ -69,34 +64,6 @@ export const CheckboxGroup: FC = ({ } } - /** - * Fonts - */ - // TODO: Replace with typography tokens - const fontRegular = 'SourceSansPro-Regular' - const fontBold = 'SourceSansPro-Bold' - - const fontHeader = { - fontFamily: fontRegular, - color: theme.vadsColorForegroundDefault, - fontSize: 20, - lineHeight: 30, - } - - const fontHint = { - fontFamily: fontRegular, - color: theme.vadsColorForegroundSubtle, - fontSize: 16, - lineHeight: 22, - } - - const fontError = { - fontFamily: fontBold, - color: theme.vadsColorForegroundError, - fontSize: 16, - lineHeight: 22, - } - /** * Container styling */ @@ -113,76 +80,37 @@ export const CheckboxGroup: FC = ({ } } - /** - * Header - */ - const headerProps = { - 'aria-label': headerA11y, - style: fontHeader, - } - - const requiredStyle = { - color: theme.vadsColorForegroundError, - } - - const _header = header && ( - <> - - {header} - {required && ( - {` (*${t('required')})`} - )} - - - - ) - - /** - * Hint - */ - const hintProps = { - 'aria-label': hintA11y, - style: fontHint, - } - - const _hint = hint && ( - <> - {hint} - - - ) - - /** - * Error - */ - const errorProps = { - 'aria-label': `${t('error')}: ${errorA11y || error}`, - style: fontError, - } - - const _error = error && ( - <> - {error} - - - ) - return ( - {_header} - {_hint} - {_error} + {header && ( + <> +
+ + + )} + + {hint && ( + <> + + + + )} + + {error && ( + <> + + + + )} {items.map((item, index) => { - const isObject = typeof item === 'object' - const label = isObject ? item.label : item - const value = isObject ? item.value || item.label : item + const value = + typeof item === 'object' ? item.value || item.text : item return ( handleCheckboxChange(value)} tile={tile} diff --git a/packages/components/src/components/Forms/FormText.tsx b/packages/components/src/components/Forms/FormText.tsx new file mode 100644 index 00000000..6d43dfa5 --- /dev/null +++ b/packages/components/src/components/Forms/FormText.tsx @@ -0,0 +1,163 @@ +import { Text } from 'react-native' +import React, { FC } from 'react' + +import { AccessibleText } from '../../types/common' +import { getA11yText, getDisplayText } from '../../utils' +import { useTheme } from '../../utils' +import { useTranslation } from 'react-i18next' + +export type FormTextProps = { + text: AccessibleText +} + +/** + * Fonts (TODO: replace with typography tokens) + */ +const fontRegular = 'SourceSansPro-Regular' +const fontBold = 'SourceSansPro-Bold' + +const fontHeader = { + fontFamily: fontRegular, + fontSize: 20, + lineHeight: 30, +} + +const fontHint = { + fontFamily: fontRegular, + fontSize: 16, + lineHeight: 22, +} + +const fontError = { + fontFamily: fontBold, + fontSize: 16, + lineHeight: 22, +} + +export const fontLabel = { + fontSize: 20, + lineHeight: 30, +} + +const fontDescription = { + fontFamily: fontRegular, + fontSize: 16, + lineHeight: 22, +} + +/** + * Header + */ +export type HeaderProps = FormTextProps & { + required?: boolean +} + +export const Header: FC = ({ text, required }) => { + const theme = useTheme() + const { t } = useTranslation() + + const textStyle = { + ...fontHeader, + color: theme.vadsColorForegroundDefault, + } + + const requiredStyle = { + color: theme.vadsColorForegroundError, + } + + return ( + + {getDisplayText(text)} + {required && {` (*${t('required')})`}} + + ) +} + +/** + * Hint + */ +export const Hint: FC = ({ text }) => { + const theme = useTheme() + + // TODO: Replace with typography tokens + const textStyle = { + ...fontHint, + color: theme.vadsColorForegroundSubtle, + } + + return ( + + {getDisplayText(text)} + + ) +} + +/** + * Error + */ +export const Error: FC = ({ text }) => { + const { t } = useTranslation() + const theme = useTheme() + + // TODO: Replace with typography tokens + const textStyle = { + ...fontError, + color: theme.vadsColorForegroundError, + } + + return ( + + {getDisplayText(text)} + + ) +} + +/** + * Label + */ +export type LabelProps = FormTextProps & { + required?: boolean + error?: AccessibleText +} + +export const Label: FC = ({ text, error, required }) => { + const theme = useTheme() + const { t } = useTranslation() + + // TODO: Replace with typography tokens + const textStyle = { + ...fontLabel, + fontFamily: error ? fontBold : fontRegular, + color: theme.vadsColorForegroundDefault, + } + + const requiredStyle = { + color: theme.vadsColorForegroundError, + } + + return ( + + {getDisplayText(text)} + {required && {` (*${t('required')})`}} + + ) +} + +/** + * Description + */ +export const Description: FC = ({ text }) => { + const theme = useTheme() + + // TODO: Replace with typography tokens + const textStyle = { + ...fontDescription, + color: theme.vadsColorForegroundDefault, + } + + return ( + + {getDisplayText(text)} + + ) +} diff --git a/packages/components/src/index.tsx b/packages/components/src/index.tsx index 75d73586..243b226c 100644 --- a/packages/components/src/index.tsx +++ b/packages/components/src/index.tsx @@ -9,7 +9,7 @@ if (expoApp && App.initiateExpo) { // Export components here so they are exported through npm export { Alert } from './components/Alert/Alert' export { Button, ButtonVariants } from './components/Button/Button' -export { Checkbox } from './components/Checkbox/Checkbox' +export { Checkbox } from './components/Forms/Checkbox/Checkbox' export { Icon } from './components/Icon/Icon' export { Link } from './components/Link/Link' export { LoadingIndicator } from './components/LoadingIndicator/LoadingIndicator' diff --git a/packages/components/src/types/common.ts b/packages/components/src/types/common.ts new file mode 100644 index 00000000..fc95e52d --- /dev/null +++ b/packages/components/src/types/common.ts @@ -0,0 +1,8 @@ +export type AccessibleText = + | string + | { + /** Text to display */ + text: string + /** Accessibility override for text */ + a11y?: string + } diff --git a/packages/components/src/types/forms.ts b/packages/components/src/types/forms.ts new file mode 100644 index 00000000..4dd9ba2b --- /dev/null +++ b/packages/components/src/types/forms.ts @@ -0,0 +1,23 @@ +import { AccessibleText } from './common' + +export type FormElementProps = { + /** Hint text. Appears below header */ + hint?: AccessibleText + /** Optional error text. If present, applies error styling to checkbox */ + error?: AccessibleText + /** Header text */ + header?: AccessibleText + /** True to append (*Required) suffix to label */ + required?: boolean +} + +export type CheckboxRadioProps = { + /** Primary text for checkbox */ + label: AccessibleText + /** OnPress logic to alter `checked` state or other behavior associated with the checkbox */ + onPress: () => void + /** Description that appears below label */ + description?: AccessibleText + /** True to apply tile styling */ + tile?: boolean +} diff --git a/packages/components/src/utils/accessibility.ts b/packages/components/src/utils/accessibility.ts index 35578de7..f708c5a5 100644 --- a/packages/components/src/utils/accessibility.ts +++ b/packages/components/src/utils/accessibility.ts @@ -1,2 +1,20 @@ +import { AccessibleText } from '../types/common' + // Export related hooks export { useIsScreenReaderEnabled } from './hooks/useIsScreenReaderEnabled' + +export const getDisplayText = (text?: AccessibleText): string | undefined => { + if (text) { + return typeof text === 'object' ? text.text : text + } +} + +export const getA11yText = (text?: AccessibleText): string | undefined => { + if (text) { + if (typeof text === 'object') { + return text.a11y || text.text + } + + return text + } +} From ca1035277bb448fa4c16193d194bba04c169ce87 Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Wed, 25 Sep 2024 11:46:02 -0700 Subject: [PATCH 04/34] Revert default viewport --- packages/components/.storybook/web/preview.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/components/.storybook/web/preview.tsx b/packages/components/.storybook/web/preview.tsx index 08e0ecc5..5fb04de7 100644 --- a/packages/components/.storybook/web/preview.tsx +++ b/packages/components/.storybook/web/preview.tsx @@ -25,7 +25,4 @@ export const parameters = { sort: 'requiredFirst', }, }, - viewport: { - defaultViewport: 'mobile2', - }, } From 04577ceec5c69c7bf6bf552a9783f5f5c0ef593e Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Wed, 25 Sep 2024 12:45:26 -0700 Subject: [PATCH 05/34] Update types. Update CheckboxGroup to use new types. Fix CheckboxGroup stories --- .../CheckboxGroup/CheckboxGroup.stories.tsx | 77 ++++++------------- .../Forms/CheckboxGroup/CheckboxGroup.tsx | 46 +++++------ packages/components/src/types/common.ts | 16 ++-- packages/components/src/types/forms.ts | 18 +++-- 4 files changed, 64 insertions(+), 93 deletions(-) diff --git a/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.stories.tsx b/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.stories.tsx index 6a204e01..36781036 100644 --- a/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.stories.tsx +++ b/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.stories.tsx @@ -41,46 +41,17 @@ export default meta type Story = StoryObj const statefulComponentRenderer = (props: CheckboxGroupProps) => { - const { - description, - descriptionA11y, - error, - errorA11y, - header, - headerA11y, - hint, - hintA11y, - required, - tile, - } = props + const { error, header, hint, items, required, tile } = props const [selectedItems, setSelectedItems] = useState<(string | number)[]>([]) - const items = [ - { - text: 'Option 1', - a11y: 'Accessibility override for option 1', - value: '1', - }, - { text: 'Option 2' }, - { text: 'Option 3' }, - { text: 'Option 4' }, - { text: 'Option 5' }, - { text: 'Option 6' }, - ] - return ( setSelectedItems(selected)} required={required} tile={tile} @@ -88,24 +59,33 @@ const statefulComponentRenderer = (props: CheckboxGroupProps) => { ) } -const header = 'Label Header', - headerA11y = 'Accessibility override for header', - hint = 'Hint about this checkbox group', - hintA11y = 'Accessibility override for hint', - error = 'Error text', - errorA11y = 'Accessibility override for error', - description = 'Checkbox description', - descriptionA11y = 'Accessibility override for description' +const items = [ + { + text: 'Option 1', + a11y: 'Accessibility override for option 1', + value: '1', + }, + { text: 'Option 2' }, + { text: 'Option 3' }, + { text: 'Option 4' }, + { text: 'Option 5' }, + { text: 'Option 6' }, + 'Option 7', +] + +const header = { + text: 'Label Header', + a11y: 'Accessibility override for header', + }, + hint = { text: 'Hint text', a11y: 'Accessibility override for hint' }, + error = { text: 'Error text', a11y: 'Accessibility override for error' } export const _Default: Story = { render: statefulComponentRenderer, args: { header, - headerA11y, hint, - hintA11y, - description, - descriptionA11y, + items, required: true, }, } @@ -113,13 +93,10 @@ export const _Default: Story = { export const __Tile: Story = { render: statefulComponentRenderer, args: { - tile: true, header, - headerA11y, hint, - hintA11y, - description, - descriptionA11y, + items, + tile: true, }, } @@ -127,13 +104,9 @@ export const ___Error: Story = { render: statefulComponentRenderer, args: { error, - errorA11y, header, - headerA11y, hint, - hintA11y, - description, - descriptionA11y, + items, required: true, }, } diff --git a/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx b/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx index fe5e2ec4..a263eb6c 100644 --- a/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx +++ b/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx @@ -2,44 +2,25 @@ import { View, ViewStyle } from 'react-native' import { spacing } from '@department-of-veterans-affairs/mobile-tokens' import React, { FC, Fragment } from 'react' -import { AccessibleText } from '../../../types/common' import { Checkbox } from '../Checkbox/Checkbox' import { ComponentWrapper } from '../../../wrapper' import { Error, Header, Hint } from '../FormText' +import { FormElementProps } from '../../../types/forms' import { Spacer } from '../../Spacer/Spacer' +import { TextA11y } from '../../../types/common' import { useTheme } from '../../../utils' -export type CheckboxGroupItem = AccessibleText & { - value?: string | number -} +export type CheckboxGroupItem = + | string + | (TextA11y & { value?: string | number }) -export type CheckboxGroupProps = { +export type CheckboxGroupProps = FormElementProps & { /** Array of checkbox options. Can be an array of strings or objects if values and/or a11y overrides are needed */ items: CheckboxGroupItem[] /** OnPress logic to alter `checked` state or other behavior associated with the checkbox */ onSelectionChange: (selected: (string | number)[]) => void /** Callback function that receives an updated array of selected values when checkboxes are pressed */ selectedItems: (string | number)[] - /** Description that appears below label */ - description?: string - /** Accessibility override for description text */ - descriptionA11y?: string - /** Hint text. Appears below header */ - hint?: string - /** Accessibility override for hint text */ - hintA11y?: string - /** Optional error text. If present, applies error styling to checkbox */ - error?: string - /** Accessibility override for error text */ - errorA11y?: string - /** Header text */ - header?: string - /** Accessibility override for header */ - headerA11y?: string - /** True to append (*Required) suffix to label */ - required?: boolean - /** True to apply tile styling */ - tile?: boolean } export const CheckboxGroup: FC = ({ @@ -64,6 +45,18 @@ export const CheckboxGroup: FC = ({ } } + const getItemValue = (item: CheckboxGroupItem): string | number => { + if (typeof item === 'object') { + if (item.value) { + return item.value // value could be undefined or a number/string + } else { + return item.text + } + } else { + return item // Handle the case where item is a string + } + } + /** * Container styling */ @@ -104,8 +97,7 @@ export const CheckboxGroup: FC = ({ )} {items.map((item, index) => { - const value = - typeof item === 'object' ? item.value || item.text : item + const value = getItemValue(item) return ( diff --git a/packages/components/src/types/common.ts b/packages/components/src/types/common.ts index fc95e52d..b9f45406 100644 --- a/packages/components/src/types/common.ts +++ b/packages/components/src/types/common.ts @@ -1,8 +1,8 @@ -export type AccessibleText = - | string - | { - /** Text to display */ - text: string - /** Accessibility override for text */ - a11y?: string - } +export type TextA11y = { + /** Text to display */ + text: string + /** Accessibility override for text */ + a11y?: string +} + +export type AccessibleText = string | TextA11y diff --git a/packages/components/src/types/forms.ts b/packages/components/src/types/forms.ts index 4dd9ba2b..9ff73d87 100644 --- a/packages/components/src/types/forms.ts +++ b/packages/components/src/types/forms.ts @@ -1,16 +1,24 @@ import { AccessibleText } from './common' +/** + * Props that are common to most form elements + */ export type FormElementProps = { - /** Hint text. Appears below header */ - hint?: AccessibleText - /** Optional error text. If present, applies error styling to checkbox */ + /** Optional error text. If present, applies error styling to element */ error?: AccessibleText /** Header text */ header?: AccessibleText - /** True to append (*Required) suffix to label */ + /** Hint text. Appears below header */ + hint?: AccessibleText + /** True to append (*Required) suffix to element */ required?: boolean + /** True to apply tile styling */ + tile?: boolean } +/** + * Props that are common to Checkbox and Radio + */ export type CheckboxRadioProps = { /** Primary text for checkbox */ label: AccessibleText @@ -18,6 +26,4 @@ export type CheckboxRadioProps = { onPress: () => void /** Description that appears below label */ description?: AccessibleText - /** True to apply tile styling */ - tile?: boolean } From b830f316e8f2f59cab703eb6d4f7c6c3520e6557 Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Wed, 25 Sep 2024 12:51:33 -0700 Subject: [PATCH 06/34] Add comments to text utils --- .../components/src/utils/accessibility.ts | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/packages/components/src/utils/accessibility.ts b/packages/components/src/utils/accessibility.ts index f708c5a5..324e3a80 100644 --- a/packages/components/src/utils/accessibility.ts +++ b/packages/components/src/utils/accessibility.ts @@ -3,18 +3,14 @@ import { AccessibleText } from '../types/common' // Export related hooks export { useIsScreenReaderEnabled } from './hooks/useIsScreenReaderEnabled' -export const getDisplayText = (text?: AccessibleText): string | undefined => { - if (text) { - return typeof text === 'object' ? text.text : text - } -} +/** + * Returns text that should be displayed on the screen + */ +export const getDisplayText = (text: AccessibleText): string => + typeof text === 'string' ? text : text.text -export const getA11yText = (text?: AccessibleText): string | undefined => { - if (text) { - if (typeof text === 'object') { - return text.a11y || text.text - } - - return text - } -} +/** + * Returns override text to be read by screen readers + */ +export const getA11yText = (text: AccessibleText): string => + typeof text === 'string' ? text : text.a11y || text.text From ab7dca9de06499e7f2071904ff347bee046ebaab Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Wed, 25 Sep 2024 12:52:06 -0700 Subject: [PATCH 07/34] Export CheckboxGroup --- packages/components/src/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/components/src/index.tsx b/packages/components/src/index.tsx index 243b226c..0dc7b673 100644 --- a/packages/components/src/index.tsx +++ b/packages/components/src/index.tsx @@ -10,6 +10,7 @@ if (expoApp && App.initiateExpo) { export { Alert } from './components/Alert/Alert' export { Button, ButtonVariants } from './components/Button/Button' export { Checkbox } from './components/Forms/Checkbox/Checkbox' +export { CheckboxGroup } from './components/Forms/CheckboxGroup/CheckboxGroup' export { Icon } from './components/Icon/Icon' export { Link } from './components/Link/Link' export { LoadingIndicator } from './components/LoadingIndicator/LoadingIndicator' From 7118bcfdc4a9dd8946dfe2debf30dda5d8ce62d3 Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Wed, 25 Sep 2024 13:20:42 -0700 Subject: [PATCH 08/34] Cleanup story vars --- .../Forms/Checkbox/Checkbox.stories.tsx | 19 ++++++++----------- .../CheckboxGroup/CheckboxGroup.stories.tsx | 9 +++------ 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/packages/components/src/components/Forms/Checkbox/Checkbox.stories.tsx b/packages/components/src/components/Forms/Checkbox/Checkbox.stories.tsx index 7d7dd49a..7e0542de 100644 --- a/packages/components/src/components/Forms/Checkbox/Checkbox.stories.tsx +++ b/packages/components/src/components/Forms/Checkbox/Checkbox.stories.tsx @@ -70,17 +70,14 @@ const statefulComponentRenderer = (props: CheckboxProps) => { ) } -const header = { - text: 'Label Header', - a11y: 'Accessibility override for header', - }, - hint = { text: 'Hint text', a11y: 'Accessibility override for hint' }, - error = { text: 'Error text', a11y: 'Accessibility override for error' }, - label = { text: 'Label', a11y: 'Accessibility override for label' }, - description = { - text: 'Checkbox description', - a11y: 'Accessibility override for description', - } +const header = { text: 'Header', a11y: 'Accessibility override for header' } +const hint = { text: 'Hint text', a11y: 'Accessibility override for hint' } +const error = { text: 'Error text', a11y: 'Accessibility override for error' } +const label = { text: 'Label', a11y: 'Accessibility override for label' } +const description = { + text: 'Description', + a11y: 'Accessibility override for description', +} export const _Default: Story = { render: statefulComponentRenderer, diff --git a/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.stories.tsx b/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.stories.tsx index 36781036..81d78057 100644 --- a/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.stories.tsx +++ b/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.stories.tsx @@ -73,12 +73,9 @@ const items = [ 'Option 7', ] -const header = { - text: 'Label Header', - a11y: 'Accessibility override for header', - }, - hint = { text: 'Hint text', a11y: 'Accessibility override for hint' }, - error = { text: 'Error text', a11y: 'Accessibility override for error' } +const header = { text: 'Header', a11y: 'Accessibility override for header' } +const hint = { text: 'Hint text', a11y: 'Accessibility override for hint' } +const error = { text: 'Error text', a11y: 'Accessibility override for error' } export const _Default: Story = { render: statefulComponentRenderer, From d34b0301d339e32e0e7ed1baf8c55365c8efdf99 Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Wed, 25 Sep 2024 13:21:07 -0700 Subject: [PATCH 09/34] Fix a11y text to announce Required for screen readers --- packages/components/src/components/Forms/FormText.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/components/src/components/Forms/FormText.tsx b/packages/components/src/components/Forms/FormText.tsx index 6d43dfa5..70ead4af 100644 --- a/packages/components/src/components/Forms/FormText.tsx +++ b/packages/components/src/components/Forms/FormText.tsx @@ -66,7 +66,9 @@ export const Header: FC = ({ text, required }) => { } return ( - + {getDisplayText(text)} {required && {` (*${t('required')})`}} @@ -136,7 +138,9 @@ export const Label: FC = ({ text, error, required }) => { } return ( - + {getDisplayText(text)} {required && {` (*${t('required')})`}} From df54b6e2b49efd0eaf5aed2c6543cfdbdc2238cc Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Wed, 25 Sep 2024 13:27:54 -0700 Subject: [PATCH 10/34] Clean up required screenreader logic --- .../components/src/components/Forms/FormText.tsx | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/components/src/components/Forms/FormText.tsx b/packages/components/src/components/Forms/FormText.tsx index 70ead4af..09351a5f 100644 --- a/packages/components/src/components/Forms/FormText.tsx +++ b/packages/components/src/components/Forms/FormText.tsx @@ -65,10 +65,12 @@ export const Header: FC = ({ text, required }) => { color: theme.vadsColorForegroundError, } + const ariaLabel = required + ? getA11yText(text) + ', ' + t('required') + : getA11yText(text) + return ( - + {getDisplayText(text)} {required && {` (*${t('required')})`}} @@ -137,10 +139,12 @@ export const Label: FC = ({ text, error, required }) => { color: theme.vadsColorForegroundError, } + const ariaLabel = required + ? getA11yText(text) + ', ' + t('required') + : getA11yText(text) + return ( - + {getDisplayText(text)} {required && {` (*${t('required')})`}} From 2bc82e9f5ca3c8e73d7bfd0488798c8ca48c07cc Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Wed, 25 Sep 2024 14:12:57 -0700 Subject: [PATCH 11/34] Replace AccessibleText with string | TextWithA11y --- .../components/Forms/CheckboxGroup/CheckboxGroup.tsx | 4 ++-- .../components/src/components/Forms/FormText.tsx | 6 +++--- packages/components/src/types/common.ts | 4 +--- packages/components/src/types/forms.ts | 12 ++++++------ packages/components/src/utils/accessibility.ts | 6 +++--- 5 files changed, 15 insertions(+), 17 deletions(-) diff --git a/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx b/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx index a263eb6c..1681382f 100644 --- a/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx +++ b/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx @@ -7,12 +7,12 @@ import { ComponentWrapper } from '../../../wrapper' import { Error, Header, Hint } from '../FormText' import { FormElementProps } from '../../../types/forms' import { Spacer } from '../../Spacer/Spacer' -import { TextA11y } from '../../../types/common' +import { TextWithA11y } from '../../../types/common' import { useTheme } from '../../../utils' export type CheckboxGroupItem = | string - | (TextA11y & { value?: string | number }) + | (TextWithA11y & { value?: string | number }) export type CheckboxGroupProps = FormElementProps & { /** Array of checkbox options. Can be an array of strings or objects if values and/or a11y overrides are needed */ diff --git a/packages/components/src/components/Forms/FormText.tsx b/packages/components/src/components/Forms/FormText.tsx index 09351a5f..9d756f0d 100644 --- a/packages/components/src/components/Forms/FormText.tsx +++ b/packages/components/src/components/Forms/FormText.tsx @@ -1,13 +1,13 @@ import { Text } from 'react-native' import React, { FC } from 'react' -import { AccessibleText } from '../../types/common' +import { TextWithA11y } from '../../types/common' import { getA11yText, getDisplayText } from '../../utils' import { useTheme } from '../../utils' import { useTranslation } from 'react-i18next' export type FormTextProps = { - text: AccessibleText + text: string | TextWithA11y } /** @@ -121,7 +121,7 @@ export const Error: FC = ({ text }) => { */ export type LabelProps = FormTextProps & { required?: boolean - error?: AccessibleText + error?: string | TextWithA11y } export const Label: FC = ({ text, error, required }) => { diff --git a/packages/components/src/types/common.ts b/packages/components/src/types/common.ts index b9f45406..6f1fc6ea 100644 --- a/packages/components/src/types/common.ts +++ b/packages/components/src/types/common.ts @@ -1,8 +1,6 @@ -export type TextA11y = { +export type TextWithA11y = { /** Text to display */ text: string /** Accessibility override for text */ a11y?: string } - -export type AccessibleText = string | TextA11y diff --git a/packages/components/src/types/forms.ts b/packages/components/src/types/forms.ts index 9ff73d87..22e697b7 100644 --- a/packages/components/src/types/forms.ts +++ b/packages/components/src/types/forms.ts @@ -1,15 +1,15 @@ -import { AccessibleText } from './common' +import { TextWithA11y } from './common' /** * Props that are common to most form elements */ export type FormElementProps = { /** Optional error text. If present, applies error styling to element */ - error?: AccessibleText + error?: string | TextWithA11y /** Header text */ - header?: AccessibleText + header?: string | TextWithA11y /** Hint text. Appears below header */ - hint?: AccessibleText + hint?: string | TextWithA11y /** True to append (*Required) suffix to element */ required?: boolean /** True to apply tile styling */ @@ -21,9 +21,9 @@ export type FormElementProps = { */ export type CheckboxRadioProps = { /** Primary text for checkbox */ - label: AccessibleText + label: string | TextWithA11y /** OnPress logic to alter `checked` state or other behavior associated with the checkbox */ onPress: () => void /** Description that appears below label */ - description?: AccessibleText + description?: string | TextWithA11y } diff --git a/packages/components/src/utils/accessibility.ts b/packages/components/src/utils/accessibility.ts index 324e3a80..adcd78c2 100644 --- a/packages/components/src/utils/accessibility.ts +++ b/packages/components/src/utils/accessibility.ts @@ -1,4 +1,4 @@ -import { AccessibleText } from '../types/common' +import { TextWithA11y } from '../types/common' // Export related hooks export { useIsScreenReaderEnabled } from './hooks/useIsScreenReaderEnabled' @@ -6,11 +6,11 @@ export { useIsScreenReaderEnabled } from './hooks/useIsScreenReaderEnabled' /** * Returns text that should be displayed on the screen */ -export const getDisplayText = (text: AccessibleText): string => +export const getDisplayText = (text: string | TextWithA11y): string => typeof text === 'string' ? text : text.text /** * Returns override text to be read by screen readers */ -export const getA11yText = (text: AccessibleText): string => +export const getA11yText = (text: string | TextWithA11y): string => typeof text === 'string' ? text : text.a11y || text.text From e398c3d42139621fa1b85208cd00e27596683148 Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Wed, 25 Sep 2024 14:18:42 -0700 Subject: [PATCH 12/34] Remove getItemValue function --- .../Forms/CheckboxGroup/CheckboxGroup.tsx | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx b/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx index 1681382f..a3ee590b 100644 --- a/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx +++ b/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx @@ -45,18 +45,6 @@ export const CheckboxGroup: FC = ({ } } - const getItemValue = (item: CheckboxGroupItem): string | number => { - if (typeof item === 'object') { - if (item.value) { - return item.value // value could be undefined or a number/string - } else { - return item.text - } - } else { - return item // Handle the case where item is a string - } - } - /** * Container styling */ @@ -97,7 +85,8 @@ export const CheckboxGroup: FC = ({ )} {items.map((item, index) => { - const value = getItemValue(item) + const value = + typeof item === 'object' ? item.value || item.text : item return ( From ad0756ba2619ba7ee829eac0101ab8f1233f33eb Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Wed, 25 Sep 2024 14:21:58 -0700 Subject: [PATCH 13/34] Remove redundant comments --- packages/components/src/components/Forms/FormText.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/components/src/components/Forms/FormText.tsx b/packages/components/src/components/Forms/FormText.tsx index 9d756f0d..1fe9d695 100644 --- a/packages/components/src/components/Forms/FormText.tsx +++ b/packages/components/src/components/Forms/FormText.tsx @@ -83,7 +83,6 @@ export const Header: FC = ({ text, required }) => { export const Hint: FC = ({ text }) => { const theme = useTheme() - // TODO: Replace with typography tokens const textStyle = { ...fontHint, color: theme.vadsColorForegroundSubtle, @@ -103,7 +102,6 @@ export const Error: FC = ({ text }) => { const { t } = useTranslation() const theme = useTheme() - // TODO: Replace with typography tokens const textStyle = { ...fontError, color: theme.vadsColorForegroundError, @@ -128,7 +126,6 @@ export const Label: FC = ({ text, error, required }) => { const theme = useTheme() const { t } = useTranslation() - // TODO: Replace with typography tokens const textStyle = { ...fontLabel, fontFamily: error ? fontBold : fontRegular, @@ -157,7 +154,6 @@ export const Label: FC = ({ text, error, required }) => { export const Description: FC = ({ text }) => { const theme = useTheme() - // TODO: Replace with typography tokens const textStyle = { ...fontDescription, color: theme.vadsColorForegroundDefault, From 609224e7c45b3642404a3f22f8d283f89fbbc642 Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Wed, 25 Sep 2024 20:53:07 -0700 Subject: [PATCH 14/34] Add variety to stories to show different types allowed for props --- .../components/Forms/Checkbox/Checkbox.stories.tsx | 2 +- .../Forms/CheckboxGroup/CheckboxGroup.stories.tsx | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/packages/components/src/components/Forms/Checkbox/Checkbox.stories.tsx b/packages/components/src/components/Forms/Checkbox/Checkbox.stories.tsx index 7e0542de..72598a23 100644 --- a/packages/components/src/components/Forms/Checkbox/Checkbox.stories.tsx +++ b/packages/components/src/components/Forms/Checkbox/Checkbox.stories.tsx @@ -70,7 +70,7 @@ const statefulComponentRenderer = (props: CheckboxProps) => { ) } -const header = { text: 'Header', a11y: 'Accessibility override for header' } +const header = 'Header' const hint = { text: 'Hint text', a11y: 'Accessibility override for hint' } const error = { text: 'Error text', a11y: 'Accessibility override for error' } const label = { text: 'Label', a11y: 'Accessibility override for label' } diff --git a/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.stories.tsx b/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.stories.tsx index 81d78057..0859485a 100644 --- a/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.stories.tsx +++ b/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.stories.tsx @@ -60,12 +60,8 @@ const statefulComponentRenderer = (props: CheckboxGroupProps) => { } const items = [ - { - text: 'Option 1', - a11y: 'Accessibility override for option 1', - value: '1', - }, - { text: 'Option 2' }, + 'Option 1', + { text: 'Option 2', a11y: 'Accessibility override for option 2', value: '2' }, { text: 'Option 3' }, { text: 'Option 4' }, { text: 'Option 5' }, @@ -73,9 +69,9 @@ const items = [ 'Option 7', ] -const header = { text: 'Header', a11y: 'Accessibility override for header' } +const header = 'Header' const hint = { text: 'Hint text', a11y: 'Accessibility override for hint' } -const error = { text: 'Error text', a11y: 'Accessibility override for error' } +const error = { text: 'Error text' } export const _Default: Story = { render: statefulComponentRenderer, From 4ae0f500afdc0aecea12321a9b49f786bb2ed2e8 Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Wed, 25 Sep 2024 20:53:44 -0700 Subject: [PATCH 15/34] Add StringOrTextWithA11y, TextWithA11yAndVlue, and StringOrTextWithA11yAndValue types --- .../Forms/CheckboxGroup/CheckboxGroup.tsx | 14 +++++--------- .../components/src/components/Forms/FormText.tsx | 8 ++++---- packages/components/src/types/common.ts | 6 ++++++ packages/components/src/types/forms.ts | 12 ++++++------ packages/components/src/utils/accessibility.ts | 6 +++--- packages/components/tsconfig.json | 2 +- 6 files changed, 25 insertions(+), 23 deletions(-) diff --git a/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx b/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx index a3ee590b..9fa22115 100644 --- a/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx +++ b/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx @@ -7,19 +7,15 @@ import { ComponentWrapper } from '../../../wrapper' import { Error, Header, Hint } from '../FormText' import { FormElementProps } from '../../../types/forms' import { Spacer } from '../../Spacer/Spacer' -import { TextWithA11y } from '../../../types/common' +import { StringOrTextWithA11yAndValue } from '../../../types/common' import { useTheme } from '../../../utils' -export type CheckboxGroupItem = - | string - | (TextWithA11y & { value?: string | number }) - export type CheckboxGroupProps = FormElementProps & { - /** Array of checkbox options. Can be an array of strings or objects if values and/or a11y overrides are needed */ - items: CheckboxGroupItem[] - /** OnPress logic to alter `checked` state or other behavior associated with the checkbox */ - onSelectionChange: (selected: (string | number)[]) => void + /** Array of checkbox options. Can be an array containing strings or objects if values or a11y overrides are needed */ + items: StringOrTextWithA11yAndValue[] /** Callback function that receives an updated array of selected values when checkboxes are pressed */ + onSelectionChange: (selected: (string | number)[]) => void + /** Array of the labels or values (if provided) of currently selected checkboxes */ selectedItems: (string | number)[] } diff --git a/packages/components/src/components/Forms/FormText.tsx b/packages/components/src/components/Forms/FormText.tsx index 1fe9d695..574593ca 100644 --- a/packages/components/src/components/Forms/FormText.tsx +++ b/packages/components/src/components/Forms/FormText.tsx @@ -1,13 +1,13 @@ import { Text } from 'react-native' import React, { FC } from 'react' -import { TextWithA11y } from '../../types/common' +import { StringOrTextWithA11y } from '../../types/common' import { getA11yText, getDisplayText } from '../../utils' import { useTheme } from '../../utils' import { useTranslation } from 'react-i18next' export type FormTextProps = { - text: string | TextWithA11y + text: StringOrTextWithA11y } /** @@ -119,7 +119,7 @@ export const Error: FC = ({ text }) => { */ export type LabelProps = FormTextProps & { required?: boolean - error?: string | TextWithA11y + error?: StringOrTextWithA11y } export const Label: FC = ({ text, error, required }) => { @@ -160,7 +160,7 @@ export const Description: FC = ({ text }) => { } return ( - + {getDisplayText(text)} ) diff --git a/packages/components/src/types/common.ts b/packages/components/src/types/common.ts index 6f1fc6ea..b9d66bb4 100644 --- a/packages/components/src/types/common.ts +++ b/packages/components/src/types/common.ts @@ -4,3 +4,9 @@ export type TextWithA11y = { /** Accessibility override for text */ a11y?: string } + +export type TextWithA11yAndValue = TextWithA11y & { value?: string | number } + +export type StringOrTextWithA11y = string | TextWithA11y + +export type StringOrTextWithA11yAndValue = string | TextWithA11yAndValue diff --git a/packages/components/src/types/forms.ts b/packages/components/src/types/forms.ts index 22e697b7..37f0c970 100644 --- a/packages/components/src/types/forms.ts +++ b/packages/components/src/types/forms.ts @@ -1,15 +1,15 @@ -import { TextWithA11y } from './common' +import { StringOrTextWithA11y } from './common' /** * Props that are common to most form elements */ export type FormElementProps = { /** Optional error text. If present, applies error styling to element */ - error?: string | TextWithA11y + error?: StringOrTextWithA11y /** Header text */ - header?: string | TextWithA11y + header?: StringOrTextWithA11y /** Hint text. Appears below header */ - hint?: string | TextWithA11y + hint?: StringOrTextWithA11y /** True to append (*Required) suffix to element */ required?: boolean /** True to apply tile styling */ @@ -21,9 +21,9 @@ export type FormElementProps = { */ export type CheckboxRadioProps = { /** Primary text for checkbox */ - label: string | TextWithA11y + label: StringOrTextWithA11y /** OnPress logic to alter `checked` state or other behavior associated with the checkbox */ onPress: () => void /** Description that appears below label */ - description?: string | TextWithA11y + description?: StringOrTextWithA11y } diff --git a/packages/components/src/utils/accessibility.ts b/packages/components/src/utils/accessibility.ts index adcd78c2..9203945e 100644 --- a/packages/components/src/utils/accessibility.ts +++ b/packages/components/src/utils/accessibility.ts @@ -1,4 +1,4 @@ -import { TextWithA11y } from '../types/common' +import { StringOrTextWithA11y } from '../types/common' // Export related hooks export { useIsScreenReaderEnabled } from './hooks/useIsScreenReaderEnabled' @@ -6,11 +6,11 @@ export { useIsScreenReaderEnabled } from './hooks/useIsScreenReaderEnabled' /** * Returns text that should be displayed on the screen */ -export const getDisplayText = (text: string | TextWithA11y): string => +export const getDisplayText = (text: StringOrTextWithA11y): string => typeof text === 'string' ? text : text.text /** * Returns override text to be read by screen readers */ -export const getA11yText = (text: string | TextWithA11y): string => +export const getA11yText = (text: StringOrTextWithA11y): string => typeof text === 'string' ? text : text.a11y || text.text diff --git a/packages/components/tsconfig.json b/packages/components/tsconfig.json index 1b2f904a..e8f0fb9f 100644 --- a/packages/components/tsconfig.json +++ b/packages/components/tsconfig.json @@ -110,7 +110,7 @@ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ // "skipLibCheck": true /* Skip type checking all .d.ts files. */ }, - "include": ["src", "global.d.ts"], + "include": ["src/**/*", ".storybook/**/*", "global.d.ts"], "exclude": ["node_modules"], "extends": "../../tsconfig.eslint.json" } From f932043b40cafa20722afeca357f8785be36f68f Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Wed, 25 Sep 2024 21:15:42 -0700 Subject: [PATCH 16/34] Remove StringOrTextWithA11yAndValue. Update CheckboxGroup.items to not allow mixed array --- .../Forms/CheckboxGroup/CheckboxGroup.stories.tsx | 14 +++++++++++--- .../Forms/CheckboxGroup/CheckboxGroup.tsx | 4 ++-- packages/components/src/types/common.ts | 7 ++++--- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.stories.tsx b/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.stories.tsx index 0859485a..0e39b8a1 100644 --- a/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.stories.tsx +++ b/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.stories.tsx @@ -60,13 +60,21 @@ const statefulComponentRenderer = (props: CheckboxGroupProps) => { } const items = [ - 'Option 1', + { text: 'Option 1' }, { text: 'Option 2', a11y: 'Accessibility override for option 2', value: '2' }, { text: 'Option 3' }, { text: 'Option 4' }, { text: 'Option 5' }, { text: 'Option 6' }, - 'Option 7', +] + +const simpleItems = [ + 'Option 1', + 'Option 2', + 'Option 3', + 'Option 4', + 'Option 5', + 'Option 6', ] const header = 'Header' @@ -88,7 +96,7 @@ export const __Tile: Story = { args: { header, hint, - items, + items: simpleItems, tile: true, }, } diff --git a/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx b/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx index 9fa22115..7f86a162 100644 --- a/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx +++ b/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx @@ -7,12 +7,12 @@ import { ComponentWrapper } from '../../../wrapper' import { Error, Header, Hint } from '../FormText' import { FormElementProps } from '../../../types/forms' import { Spacer } from '../../Spacer/Spacer' -import { StringOrTextWithA11yAndValue } from '../../../types/common' +import { TextWithA11yAndValue } from '../../../types/common' import { useTheme } from '../../../utils' export type CheckboxGroupProps = FormElementProps & { /** Array of checkbox options. Can be an array containing strings or objects if values or a11y overrides are needed */ - items: StringOrTextWithA11yAndValue[] + items: string[] | TextWithA11yAndValue[] /** Callback function that receives an updated array of selected values when checkboxes are pressed */ onSelectionChange: (selected: (string | number)[]) => void /** Array of the labels or values (if provided) of currently selected checkboxes */ diff --git a/packages/components/src/types/common.ts b/packages/components/src/types/common.ts index b9d66bb4..8818fada 100644 --- a/packages/components/src/types/common.ts +++ b/packages/components/src/types/common.ts @@ -5,8 +5,9 @@ export type TextWithA11y = { a11y?: string } -export type TextWithA11yAndValue = TextWithA11y & { value?: string | number } +export type TextWithA11yAndValue = TextWithA11y & { + /** Value that may differ from provided text */ + value?: string | number +} export type StringOrTextWithA11y = string | TextWithA11y - -export type StringOrTextWithA11yAndValue = string | TextWithA11yAndValue From 9940b133b7525d51cfd70de7114e83c20f6fd7cb Mon Sep 17 00:00:00 2001 From: VA Automation Bot Date: Thu, 26 Sep 2024 04:16:40 +0000 Subject: [PATCH 17/34] Version bump: components-v0.25.1-alpha.1 --- packages/components/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/package.json b/packages/components/package.json index 05a16b07..32e68206 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@department-of-veterans-affairs/mobile-component-library", - "version": "0.25.1-alpha.0", + "version": "0.25.1-alpha.1", "description": "VA Design System Mobile Component Library", "main": "src/index.tsx", "scripts": { From cf0a88a2422c5e52d07f11d13ced0f2efeba9c3e Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Wed, 25 Sep 2024 21:43:31 -0700 Subject: [PATCH 18/34] Update getA11yText comment --- packages/components/src/utils/accessibility.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/utils/accessibility.ts b/packages/components/src/utils/accessibility.ts index 9203945e..360a8c4d 100644 --- a/packages/components/src/utils/accessibility.ts +++ b/packages/components/src/utils/accessibility.ts @@ -10,7 +10,7 @@ export const getDisplayText = (text: StringOrTextWithA11y): string => typeof text === 'string' ? text : text.text /** - * Returns override text to be read by screen readers + * Returns a11y override text or just text if a11y isn't provided */ export const getA11yText = (text: StringOrTextWithA11y): string => typeof text === 'string' ? text : text.a11y || text.text From 7cb7dc217ec49cc918bbbaae5b91880898b9ef92 Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Wed, 25 Sep 2024 21:47:16 -0700 Subject: [PATCH 19/34] Revert tsconfig --- packages/components/tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/tsconfig.json b/packages/components/tsconfig.json index e8f0fb9f..1b2f904a 100644 --- a/packages/components/tsconfig.json +++ b/packages/components/tsconfig.json @@ -110,7 +110,7 @@ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ // "skipLibCheck": true /* Skip type checking all .d.ts files. */ }, - "include": ["src/**/*", ".storybook/**/*", "global.d.ts"], + "include": ["src", "global.d.ts"], "exclude": ["node_modules"], "extends": "../../tsconfig.eslint.json" } From cd9c1efb7d81b2563b9373bf7131615fa347db82 Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Mon, 30 Sep 2024 19:11:45 -0700 Subject: [PATCH 20/34] Update to latest tokens and fast-xml-parser 4.4.41 --- packages/components/package.json | 4 ++-- yarn.lock | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/components/package.json b/packages/components/package.json index 32e68206..0ae567bf 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -48,7 +48,7 @@ }, "peerDependencies": { "@department-of-veterans-affairs/mobile-assets": "^0.12.0", - "@department-of-veterans-affairs/mobile-tokens": "^0.17.0", + "@department-of-veterans-affairs/mobile-tokens": "^0.17.1", "react": "^18.2.0", "react-native": ">=0.71.7", "react-native-gesture-handler": "^2.12.0", @@ -60,7 +60,7 @@ "@babel/preset-env": "^7.24.8", "@babel/preset-typescript": "^7.24.7", "@department-of-veterans-affairs/mobile-assets": "0.13.0", - "@department-of-veterans-affairs/mobile-tokens": "0.17.0", + "@department-of-veterans-affairs/mobile-tokens": "0.17.1", "@expo/metro-runtime": "~3.2.1", "@expo/webpack-config": "~19.0.1", "@react-native-async-storage/async-storage": "1.23.1", diff --git a/yarn.lock b/yarn.lock index fba48574..35fbd5e9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3128,7 +3128,7 @@ __metadata: "@babel/preset-env": "npm:^7.24.8" "@babel/preset-typescript": "npm:^7.24.7" "@department-of-veterans-affairs/mobile-assets": "npm:0.13.0" - "@department-of-veterans-affairs/mobile-tokens": "npm:0.17.0" + "@department-of-veterans-affairs/mobile-tokens": "npm:0.17.1" "@expo/metro-runtime": "npm:~3.2.1" "@expo/webpack-config": "npm:~19.0.1" "@os-team/i18next-react-native-language-detector": "npm:^1.0.34" @@ -3191,7 +3191,7 @@ __metadata: typescript: "npm:~5.3.3" peerDependencies: "@department-of-veterans-affairs/mobile-assets": ^0.12.0 - "@department-of-veterans-affairs/mobile-tokens": ^0.17.0 + "@department-of-veterans-affairs/mobile-tokens": ^0.17.1 react: ^18.2.0 react-native: ">=0.71.7" react-native-gesture-handler: ^2.12.0 @@ -3199,10 +3199,10 @@ __metadata: languageName: unknown linkType: soft -"@department-of-veterans-affairs/mobile-tokens@npm:0.17.0": - version: 0.17.0 - resolution: "@department-of-veterans-affairs/mobile-tokens@npm:0.17.0" - checksum: b043f9962f07b14a28d85ae9dab0a954da025b7c9fb948ed1711c861837f299fa70a4f25902bba20857f45d49f8b588f5f33275b5ddb62fdbac96db9de23d516 +"@department-of-veterans-affairs/mobile-tokens@npm:0.17.1": + version: 0.17.1 + resolution: "@department-of-veterans-affairs/mobile-tokens@npm:0.17.1" + checksum: c2e789b0ea6d8b94df0d1490abd3bb480fc6ca87335d806979912873f698d7c6a9dd40d2ca52cbc973c1f4615dd2a3e02bd289456d99d3ff5d5201a3360fefff languageName: node linkType: hard @@ -12375,13 +12375,13 @@ __metadata: linkType: hard "fast-xml-parser@npm:^4.0.12, fast-xml-parser@npm:^4.2.4": - version: 4.3.4 - resolution: "fast-xml-parser@npm:4.3.4" + version: 4.4.1 + resolution: "fast-xml-parser@npm:4.4.1" dependencies: strnum: "npm:^1.0.5" bin: fxparser: src/cli/cli.js - checksum: 1e44cad5f14efa9971fe2df6246e6656c22bccf8e8c1d3545a63c446e67ab23e9f615ecba0c4b103ea1126ee4344d9cc9672bd6409f728330131c3ba76827715 + checksum: 7f334841fe41bfb0bf5d920904ccad09cefc4b5e61eaf4c225bf1e1bb69ee77ef2147d8942f783ee8249e154d1ca8a858e10bda78a5d78b8bed3f48dcee9bf33 languageName: node linkType: hard From b62a7215f15da38bb3e5b6db742b0702732f4da9 Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Mon, 30 Sep 2024 19:23:45 -0700 Subject: [PATCH 21/34] Fix mixed imports. Make FormTextProps local type --- packages/components/src/components/Forms/FormText.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/src/components/Forms/FormText.tsx b/packages/components/src/components/Forms/FormText.tsx index 574593ca..a641b7e1 100644 --- a/packages/components/src/components/Forms/FormText.tsx +++ b/packages/components/src/components/Forms/FormText.tsx @@ -1,12 +1,12 @@ import { Text } from 'react-native' +import { useTranslation } from 'react-i18next' import React, { FC } from 'react' import { StringOrTextWithA11y } from '../../types/common' import { getA11yText, getDisplayText } from '../../utils' import { useTheme } from '../../utils' -import { useTranslation } from 'react-i18next' -export type FormTextProps = { +type FormTextProps = { text: StringOrTextWithA11y } From 2215ade7b65d57673c9997622db869bb6b95fa4e Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Mon, 30 Sep 2024 19:24:23 -0700 Subject: [PATCH 22/34] Move tile to CheckboxRadioProps. Add tile to CheckboxGroupProps --- .../src/components/Forms/CheckboxGroup/CheckboxGroup.tsx | 2 ++ packages/components/src/types/forms.ts | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx b/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx index 7f86a162..6533b29e 100644 --- a/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx +++ b/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx @@ -17,6 +17,8 @@ export type CheckboxGroupProps = FormElementProps & { onSelectionChange: (selected: (string | number)[]) => void /** Array of the labels or values (if provided) of currently selected checkboxes */ selectedItems: (string | number)[] + /** True to apply tile styling */ + tile?: boolean } export const CheckboxGroup: FC = ({ diff --git a/packages/components/src/types/forms.ts b/packages/components/src/types/forms.ts index 37f0c970..bf8f5fef 100644 --- a/packages/components/src/types/forms.ts +++ b/packages/components/src/types/forms.ts @@ -12,8 +12,6 @@ export type FormElementProps = { hint?: StringOrTextWithA11y /** True to append (*Required) suffix to element */ required?: boolean - /** True to apply tile styling */ - tile?: boolean } /** @@ -26,4 +24,6 @@ export type CheckboxRadioProps = { onPress: () => void /** Description that appears below label */ description?: StringOrTextWithA11y + /** True to apply tile styling */ + tile?: boolean } From a1284727dd5f8eab81c2eb4a79ac5a52bb790e0a Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Mon, 30 Sep 2024 19:24:34 -0700 Subject: [PATCH 23/34] Add index for type files --- packages/components/src/types/index.ts | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 packages/components/src/types/index.ts diff --git a/packages/components/src/types/index.ts b/packages/components/src/types/index.ts new file mode 100644 index 00000000..46a1335a --- /dev/null +++ b/packages/components/src/types/index.ts @@ -0,0 +1,2 @@ +export * from './common' +export * from './forms' From 0844d36063a35239848ab68939c95c5d94414b81 Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Mon, 30 Sep 2024 19:50:46 -0700 Subject: [PATCH 24/34] Rename a11y to a11yLabel in TextWithA11y --- .../components/Forms/Checkbox/Checkbox.stories.tsx | 11 +++++++---- .../Forms/CheckboxGroup/CheckboxGroup.stories.tsx | 8 ++++++-- packages/components/src/types/common.ts | 7 +------ 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/packages/components/src/components/Forms/Checkbox/Checkbox.stories.tsx b/packages/components/src/components/Forms/Checkbox/Checkbox.stories.tsx index 72598a23..c6bed27a 100644 --- a/packages/components/src/components/Forms/Checkbox/Checkbox.stories.tsx +++ b/packages/components/src/components/Forms/Checkbox/Checkbox.stories.tsx @@ -71,12 +71,15 @@ const statefulComponentRenderer = (props: CheckboxProps) => { } const header = 'Header' -const hint = { text: 'Hint text', a11y: 'Accessibility override for hint' } -const error = { text: 'Error text', a11y: 'Accessibility override for error' } -const label = { text: 'Label', a11y: 'Accessibility override for label' } +const hint = { text: 'Hint text', a11yLabel: 'Accessibility override for hint' } +const error = { + text: 'Error text', + a11yLabel: 'Accessibility override for error', +} +const label = { text: 'Label', a11yLabel: 'Accessibility override for label' } const description = { text: 'Description', - a11y: 'Accessibility override for description', + a11yLabel: 'Accessibility override for description', } export const _Default: Story = { diff --git a/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.stories.tsx b/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.stories.tsx index 0e39b8a1..5f172821 100644 --- a/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.stories.tsx +++ b/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.stories.tsx @@ -61,7 +61,11 @@ const statefulComponentRenderer = (props: CheckboxGroupProps) => { const items = [ { text: 'Option 1' }, - { text: 'Option 2', a11y: 'Accessibility override for option 2', value: '2' }, + { + text: 'Option 2', + a11yLabel: 'Accessibility override for option 2', + value: '2', + }, { text: 'Option 3' }, { text: 'Option 4' }, { text: 'Option 5' }, @@ -78,7 +82,7 @@ const simpleItems = [ ] const header = 'Header' -const hint = { text: 'Hint text', a11y: 'Accessibility override for hint' } +const hint = { text: 'Hint text', a11yLabel: 'Accessibility override for hint' } const error = { text: 'Error text' } export const _Default: Story = { diff --git a/packages/components/src/types/common.ts b/packages/components/src/types/common.ts index 8818fada..5242f6f9 100644 --- a/packages/components/src/types/common.ts +++ b/packages/components/src/types/common.ts @@ -2,12 +2,7 @@ export type TextWithA11y = { /** Text to display */ text: string /** Accessibility override for text */ - a11y?: string -} - -export type TextWithA11yAndValue = TextWithA11y & { - /** Value that may differ from provided text */ - value?: string | number + a11yLabel?: string } export type StringOrTextWithA11y = string | TextWithA11y From 36348af8a5f498af3ff9b6a0142298a4a06ee79f Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Mon, 30 Sep 2024 19:51:27 -0700 Subject: [PATCH 25/34] Revert to flattened components folder. Move FormText.tsx into 'shared' folder. Add better comments to FormText components --- .../{Forms => }/Checkbox/Checkbox.stories.tsx | 2 +- .../{Forms => }/Checkbox/Checkbox.tsx | 51 ++++++++----------- .../CheckboxGroup/CheckboxGroup.stories.tsx | 2 +- .../CheckboxGroup/CheckboxGroup.tsx | 17 ++++--- .../components/{Forms => shared}/FormText.tsx | 22 +++++--- packages/components/src/index.tsx | 4 +- 6 files changed, 52 insertions(+), 46 deletions(-) rename packages/components/src/components/{Forms => }/Checkbox/Checkbox.stories.tsx (97%) rename packages/components/src/components/{Forms => }/Checkbox/Checkbox.tsx (75%) rename packages/components/src/components/{Forms => }/CheckboxGroup/CheckboxGroup.stories.tsx (97%) rename packages/components/src/components/{Forms => }/CheckboxGroup/CheckboxGroup.tsx (86%) rename packages/components/src/components/{Forms => shared}/FormText.tsx (87%) diff --git a/packages/components/src/components/Forms/Checkbox/Checkbox.stories.tsx b/packages/components/src/components/Checkbox/Checkbox.stories.tsx similarity index 97% rename from packages/components/src/components/Forms/Checkbox/Checkbox.stories.tsx rename to packages/components/src/components/Checkbox/Checkbox.stories.tsx index c6bed27a..28c60cd3 100644 --- a/packages/components/src/components/Forms/Checkbox/Checkbox.stories.tsx +++ b/packages/components/src/components/Checkbox/Checkbox.stories.tsx @@ -3,7 +3,7 @@ import { View } from 'react-native' import React, { useState } from 'react' import { Checkbox, CheckboxProps } from './Checkbox' -import { generateDocs } from '../../../utils/storybook' +import { generateDocs } from '../../utils/storybook' const meta: Meta = { title: 'Checkbox', diff --git a/packages/components/src/components/Forms/Checkbox/Checkbox.tsx b/packages/components/src/components/Checkbox/Checkbox.tsx similarity index 75% rename from packages/components/src/components/Forms/Checkbox/Checkbox.tsx rename to packages/components/src/components/Checkbox/Checkbox.tsx index 8ed6b51a..c50e0093 100644 --- a/packages/components/src/components/Forms/Checkbox/Checkbox.tsx +++ b/packages/components/src/components/Checkbox/Checkbox.tsx @@ -8,12 +8,19 @@ import { import { spacing } from '@department-of-veterans-affairs/mobile-tokens' import React, { FC } from 'react' -import { CheckboxRadioProps, FormElementProps } from '../../../types/forms' -import { ComponentWrapper } from '../../../wrapper' -import { Description, Error, Header, Hint, Label, fontLabel } from '../FormText' -import { Icon, IconProps } from '../../Icon/Icon' -import { Spacer } from '../../Spacer/Spacer' -import { useTheme } from '../../../utils' +import { CheckboxRadioProps, FormElementProps } from '../../types/forms' +import { ComponentWrapper } from '../../wrapper' +import { + Description, + Error, + Header, + Hint, + Label, + fontLabel, +} from '../shared/FormText' +import { Icon, IconProps } from '../Icon/Icon' +import { Spacer } from '../Spacer/Spacer' +import { useTheme } from '../../utils' export type CheckboxProps = FormElementProps & CheckboxRadioProps & { @@ -110,26 +117,14 @@ export const Checkbox: FC = ({ return ( - {header && ( - <> -
- - - )} +
+ {header && } - {hint && ( - <> - - - - )} + + {hint && } - {error && ( - <> - - - - )} + + {error && } = ({ diff --git a/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.stories.tsx b/packages/components/src/components/CheckboxGroup/CheckboxGroup.stories.tsx similarity index 97% rename from packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.stories.tsx rename to packages/components/src/components/CheckboxGroup/CheckboxGroup.stories.tsx index 5f172821..3661fc51 100644 --- a/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.stories.tsx +++ b/packages/components/src/components/CheckboxGroup/CheckboxGroup.stories.tsx @@ -3,7 +3,7 @@ import { View } from 'react-native' import React, { useState } from 'react' import { CheckboxGroup, CheckboxGroupProps } from './CheckboxGroup' -import { generateDocs } from '../../../utils/storybook' +import { generateDocs } from '../../utils/storybook' const meta: Meta = { title: 'Checkbox group', diff --git a/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx b/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx similarity index 86% rename from packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx rename to packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx index 6533b29e..1e13e80e 100644 --- a/packages/components/src/components/Forms/CheckboxGroup/CheckboxGroup.tsx +++ b/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx @@ -3,12 +3,17 @@ import { spacing } from '@department-of-veterans-affairs/mobile-tokens' import React, { FC, Fragment } from 'react' import { Checkbox } from '../Checkbox/Checkbox' -import { ComponentWrapper } from '../../../wrapper' -import { Error, Header, Hint } from '../FormText' -import { FormElementProps } from '../../../types/forms' -import { Spacer } from '../../Spacer/Spacer' -import { TextWithA11yAndValue } from '../../../types/common' -import { useTheme } from '../../../utils' +import { ComponentWrapper } from '../../wrapper' +import { Error, Header, Hint } from '../shared/FormText' +import { FormElementProps } from '../../types/forms' +import { Spacer } from '../Spacer/Spacer' +import { TextWithA11y } from '../../types/common' +import { useTheme } from '../../utils' + +export type TextWithA11yAndValue = TextWithA11y & { + /** Value that may differ from provided text */ + value?: string | number +} export type CheckboxGroupProps = FormElementProps & { /** Array of checkbox options. Can be an array containing strings or objects if values or a11y overrides are needed */ diff --git a/packages/components/src/components/Forms/FormText.tsx b/packages/components/src/components/shared/FormText.tsx similarity index 87% rename from packages/components/src/components/Forms/FormText.tsx rename to packages/components/src/components/shared/FormText.tsx index a641b7e1..83cde6d2 100644 --- a/packages/components/src/components/Forms/FormText.tsx +++ b/packages/components/src/components/shared/FormText.tsx @@ -7,7 +7,7 @@ import { getA11yText, getDisplayText } from '../../utils' import { useTheme } from '../../utils' type FormTextProps = { - text: StringOrTextWithA11y + text?: StringOrTextWithA11y } /** @@ -46,7 +46,7 @@ const fontDescription = { } /** - * Header + * Header text element commonly used in form components */ export type HeaderProps = FormTextProps & { required?: boolean @@ -56,6 +56,8 @@ export const Header: FC = ({ text, required }) => { const theme = useTheme() const { t } = useTranslation() + if (!text) return null + const textStyle = { ...fontHeader, color: theme.vadsColorForegroundDefault, @@ -78,11 +80,13 @@ export const Header: FC = ({ text, required }) => { } /** - * Hint + * Hint text element commonly used in form components */ export const Hint: FC = ({ text }) => { const theme = useTheme() + if (!text) return null + const textStyle = { ...fontHint, color: theme.vadsColorForegroundSubtle, @@ -96,12 +100,14 @@ export const Hint: FC = ({ text }) => { } /** - * Error + * Error text element commonly used in form components */ export const Error: FC = ({ text }) => { const { t } = useTranslation() const theme = useTheme() + if (!text) return null + const textStyle = { ...fontError, color: theme.vadsColorForegroundError, @@ -115,7 +121,7 @@ export const Error: FC = ({ text }) => { } /** - * Label + * Label text element commonly used in form components */ export type LabelProps = FormTextProps & { required?: boolean @@ -126,6 +132,8 @@ export const Label: FC = ({ text, error, required }) => { const theme = useTheme() const { t } = useTranslation() + if (!text) return null + const textStyle = { ...fontLabel, fontFamily: error ? fontBold : fontRegular, @@ -149,11 +157,13 @@ export const Label: FC = ({ text, error, required }) => { } /** - * Description + * Description text element commonly used in form components */ export const Description: FC = ({ text }) => { const theme = useTheme() + if (!text) return null + const textStyle = { ...fontDescription, color: theme.vadsColorForegroundDefault, diff --git a/packages/components/src/index.tsx b/packages/components/src/index.tsx index 0dc7b673..4b1dfcd9 100644 --- a/packages/components/src/index.tsx +++ b/packages/components/src/index.tsx @@ -9,8 +9,8 @@ if (expoApp && App.initiateExpo) { // Export components here so they are exported through npm export { Alert } from './components/Alert/Alert' export { Button, ButtonVariants } from './components/Button/Button' -export { Checkbox } from './components/Forms/Checkbox/Checkbox' -export { CheckboxGroup } from './components/Forms/CheckboxGroup/CheckboxGroup' +export { Checkbox } from './components/Checkbox/Checkbox' +export { CheckboxGroup } from './components/CheckboxGroup/CheckboxGroup' export { Icon } from './components/Icon/Icon' export { Link } from './components/Link/Link' export { LoadingIndicator } from './components/LoadingIndicator/LoadingIndicator' From f025d71e27c90a7d93282cff56207df22afcbfcc Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Mon, 30 Sep 2024 19:53:06 -0700 Subject: [PATCH 26/34] Clean up text element conditionals --- .../src/components/Checkbox/Checkbox.tsx | 2 +- .../CheckboxGroup/CheckboxGroup.tsx | 25 ++++++------------- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/packages/components/src/components/Checkbox/Checkbox.tsx b/packages/components/src/components/Checkbox/Checkbox.tsx index c50e0093..9ac37460 100644 --- a/packages/components/src/components/Checkbox/Checkbox.tsx +++ b/packages/components/src/components/Checkbox/Checkbox.tsx @@ -117,7 +117,7 @@ export const Checkbox: FC = ({ return ( -
+
{header && } diff --git a/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx b/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx index 1e13e80e..29a43aaa 100644 --- a/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx +++ b/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx @@ -67,26 +67,15 @@ export const CheckboxGroup: FC = ({ return ( - {header && ( - <> -
- - - )} +
+ {header && } - {hint && ( - <> - - - - )} + + {hint && } + + + {error && } - {error && ( - <> - - - - )} {items.map((item, index) => { const value = typeof item === 'object' ? item.value || item.text : item From 46f2b8b11d922d652063583607fa496f33278087 Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Mon, 30 Sep 2024 19:56:52 -0700 Subject: [PATCH 27/34] Clean up text element conditionals --- packages/components/src/components/Checkbox/Checkbox.tsx | 2 +- .../components/src/components/CheckboxGroup/CheckboxGroup.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/src/components/Checkbox/Checkbox.tsx b/packages/components/src/components/Checkbox/Checkbox.tsx index 9ac37460..c50e0093 100644 --- a/packages/components/src/components/Checkbox/Checkbox.tsx +++ b/packages/components/src/components/Checkbox/Checkbox.tsx @@ -117,7 +117,7 @@ export const Checkbox: FC = ({ return ( -
+
{header && } diff --git a/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx b/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx index 29a43aaa..20926bec 100644 --- a/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx +++ b/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx @@ -67,7 +67,7 @@ export const CheckboxGroup: FC = ({ return ( -
+
{header && } From fc37aafe61b6195a1a854b9fa610b5ad3a8019f8 Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Mon, 30 Sep 2024 20:27:23 -0700 Subject: [PATCH 28/34] Add comment with selectedItems, onSelectionChange, and TextWithA11yAndValue examples --- .../CheckboxGroup/CheckboxGroup.tsx | 56 ++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx b/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx index 20926bec..b4309008 100644 --- a/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx +++ b/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx @@ -11,7 +11,7 @@ import { TextWithA11y } from '../../types/common' import { useTheme } from '../../utils' export type TextWithA11yAndValue = TextWithA11y & { - /** Value that may differ from provided text */ + /** Value or ID for checkbox item if different than checkbox label */ value?: string | number } @@ -26,6 +26,60 @@ export type CheckboxGroupProps = FormElementProps & { tile?: boolean } +/** + * ### Managing checked item state + * The state of the selected checkbox items should be provided to CheckboxGroup via the `selectedItems` prop and updated + * using the `onSelectionChange` callback. When a checkbox is tapped, the provided `onSelectionChange` callback + * function is fired and passed an array of the newly `selectedItems`, which can be used to update the parent + * component's state, whether that be redux, zustand, useState, or any other state management methods. Here is a basic + * example using the `useState` hook to store the state of the `selectedItems`: + * + * ```jsx + * export const ParentComponent = () => { + * const [selectedItems, setSelectedItems] = useState([]) + * + * const onSelectionChange = (updatedItems) => setSelectedItems(updatedItems) + * + * const items = ['Option 1', 'Option 2', 'Option 3'] + * + * return ( + * + * ) + * + * } + * ``` + * + * ### Providing values or accessibility labels + * CheckboxGroup can accept a simple array of strings in the `items` prop. If you want to provide values for each + * item that differ from the labels, or you want to provide accessibility labels for certain items, you can pass an + * array of objects containing these optional fields as well. For example: + * + * ```jsx + * export const ParentComponent = () => { + * const [selectedItems, setSelectedItems] = useState([]) + * + * const onSelectionChange = (updatedItems) => setSelectedItems(updatedItems) + * + * const items = [ + * { text: 'Minnesota', value: 'MN' }, + * { text: 'California', value: 'CA' }, + * { text: 'New Jersey', value: 'NJ' }, + * { text: 'Washington D.C.', value: 'DC', a11yLabel: 'District of Columbia' }, + * ] + * + * return ( + * + * ) + * + * } + * ``` + */ export const CheckboxGroup: FC = ({ items, selectedItems, From 7790630ed404cb4946378a64a58e67a5cb7f17ef Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Mon, 30 Sep 2024 20:28:55 -0700 Subject: [PATCH 29/34] Fix typo --- .../src/components/CheckboxGroup/CheckboxGroup.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx b/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx index b4309008..7085ce84 100644 --- a/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx +++ b/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx @@ -53,9 +53,9 @@ export type CheckboxGroupProps = FormElementProps & { * ``` * * ### Providing values or accessibility labels - * CheckboxGroup can accept a simple array of strings in the `items` prop. If you want to provide values for each - * item that differ from the labels, or you want to provide accessibility labels for certain items, you can pass an - * array of objects containing these optional fields as well. For example: + * CheckboxGroup can accept a simple array of strings to display as checkboxes as shown above. If you want to provide + * values for each item that differ from display labels, or you want to provide accessibility labels for certain items, + * you can pass an array of objects containing these optional fields as well. For example: * * ```jsx * export const ParentComponent = () => { From 2243bf78e6c8b84a7d8a0fb4bc430bffd1222052 Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Mon, 30 Sep 2024 20:44:34 -0700 Subject: [PATCH 30/34] Rename function and use new a11yLabel field name --- packages/components/src/utils/accessibility.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/src/utils/accessibility.ts b/packages/components/src/utils/accessibility.ts index 360a8c4d..437748cb 100644 --- a/packages/components/src/utils/accessibility.ts +++ b/packages/components/src/utils/accessibility.ts @@ -12,5 +12,5 @@ export const getDisplayText = (text: StringOrTextWithA11y): string => /** * Returns a11y override text or just text if a11y isn't provided */ -export const getA11yText = (text: StringOrTextWithA11y): string => - typeof text === 'string' ? text : text.a11y || text.text +export const getA11yLabel = (text: StringOrTextWithA11y): string => + typeof text === 'string' ? text : text.a11yLabel || text.text From ca2977f78dbe302d255e14b771ac37f25f52fd28 Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Mon, 30 Sep 2024 21:07:00 -0700 Subject: [PATCH 31/34] Reference types index rather than common.ts --- .../components/src/components/CheckboxGroup/CheckboxGroup.tsx | 4 ++-- packages/components/src/utils/accessibility.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx b/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx index 7085ce84..e72924b3 100644 --- a/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx +++ b/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx @@ -7,10 +7,10 @@ import { ComponentWrapper } from '../../wrapper' import { Error, Header, Hint } from '../shared/FormText' import { FormElementProps } from '../../types/forms' import { Spacer } from '../Spacer/Spacer' -import { TextWithA11y } from '../../types/common' +import { TextWithA11y } from '../../types' import { useTheme } from '../../utils' -export type TextWithA11yAndValue = TextWithA11y & { +type TextWithA11yAndValue = TextWithA11y & { /** Value or ID for checkbox item if different than checkbox label */ value?: string | number } diff --git a/packages/components/src/utils/accessibility.ts b/packages/components/src/utils/accessibility.ts index 437748cb..3d056711 100644 --- a/packages/components/src/utils/accessibility.ts +++ b/packages/components/src/utils/accessibility.ts @@ -1,4 +1,4 @@ -import { StringOrTextWithA11y } from '../types/common' +import { StringOrTextWithA11y } from '../types' // Export related hooks export { useIsScreenReaderEnabled } from './hooks/useIsScreenReaderEnabled' From f1bc22f30d4f9285ca4d77e6c6280ea0256d9692 Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Mon, 30 Sep 2024 21:13:58 -0700 Subject: [PATCH 32/34] Add prop comments --- .../src/components/shared/FormText.tsx | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/packages/components/src/components/shared/FormText.tsx b/packages/components/src/components/shared/FormText.tsx index 83cde6d2..072665ac 100644 --- a/packages/components/src/components/shared/FormText.tsx +++ b/packages/components/src/components/shared/FormText.tsx @@ -3,10 +3,11 @@ import { useTranslation } from 'react-i18next' import React, { FC } from 'react' import { StringOrTextWithA11y } from '../../types/common' -import { getA11yText, getDisplayText } from '../../utils' +import { getA11yLabel, getDisplayText } from '../../utils' import { useTheme } from '../../utils' type FormTextProps = { + /** String to display or TextWithA11y object with string and a11y label */ text?: StringOrTextWithA11y } @@ -49,6 +50,7 @@ const fontDescription = { * Header text element commonly used in form components */ export type HeaderProps = FormTextProps & { + /** True to display (*Required) label next to header */ required?: boolean } @@ -68,8 +70,8 @@ export const Header: FC = ({ text, required }) => { } const ariaLabel = required - ? getA11yText(text) + ', ' + t('required') - : getA11yText(text) + ? getA11yLabel(text) + ', ' + t('required') + : getA11yLabel(text) return ( @@ -93,7 +95,7 @@ export const Hint: FC = ({ text }) => { } return ( - + {getDisplayText(text)} ) @@ -114,20 +116,21 @@ export const Error: FC = ({ text }) => { } return ( - + {getDisplayText(text)} ) } - -/** - * Label text element commonly used in form components - */ export type LabelProps = FormTextProps & { + /** True to display (*Required) label next to label */ required?: boolean + /** Error message that modifies label styling when provided */ error?: StringOrTextWithA11y } +/** + * Label text element commonly used in form components + */ export const Label: FC = ({ text, error, required }) => { const theme = useTheme() const { t } = useTranslation() @@ -145,8 +148,8 @@ export const Label: FC = ({ text, error, required }) => { } const ariaLabel = required - ? getA11yText(text) + ', ' + t('required') - : getA11yText(text) + ? getA11yLabel(text) + ', ' + t('required') + : getA11yLabel(text) return ( @@ -170,7 +173,7 @@ export const Description: FC = ({ text }) => { } return ( - + {getDisplayText(text)} ) From f6a1c3aecb74361407f09d5d1b4fbccbe39c6806 Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Tue, 1 Oct 2024 10:17:25 -0700 Subject: [PATCH 33/34] Add testID prop --- .../src/components/CheckboxGroup/CheckboxGroup.tsx | 7 +++++-- packages/components/src/types/forms.ts | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx b/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx index e72924b3..081771e7 100644 --- a/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx +++ b/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx @@ -13,6 +13,8 @@ import { useTheme } from '../../utils' type TextWithA11yAndValue = TextWithA11y & { /** Value or ID for checkbox item if different than checkbox label */ value?: string | number + /** Optional TestID */ + testID?: string } export type CheckboxGroupProps = FormElementProps & { @@ -131,8 +133,8 @@ export const CheckboxGroup: FC = ({ {error && } {items.map((item, index) => { - const value = - typeof item === 'object' ? item.value || item.text : item + const isObject = typeof item === 'object' + const value = isObject ? item.value || item.text : item return ( @@ -140,6 +142,7 @@ export const CheckboxGroup: FC = ({ label={item} checked={selectedItems.includes(value)} onPress={() => handleCheckboxChange(value)} + testID={isObject ? item.testID : undefined} tile={tile} /> {index < items.length - 1 && } diff --git a/packages/components/src/types/forms.ts b/packages/components/src/types/forms.ts index bf8f5fef..804ed477 100644 --- a/packages/components/src/types/forms.ts +++ b/packages/components/src/types/forms.ts @@ -12,6 +12,8 @@ export type FormElementProps = { hint?: StringOrTextWithA11y /** True to append (*Required) suffix to element */ required?: boolean + /** Optional TestID */ + testID?: string } /** From fe0be12d642d376fbb20c7e83136cc808db8f77e Mon Sep 17 00:00:00 2001 From: Narin Ratana Date: Wed, 2 Oct 2024 11:41:15 -0700 Subject: [PATCH 34/34] Move comment to be above Header FC. Merge util imports --- .../src/components/CheckboxGroup/CheckboxGroup.tsx | 3 +-- packages/components/src/components/shared/FormText.tsx | 10 ++++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx b/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx index 081771e7..d600d6a0 100644 --- a/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx +++ b/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx @@ -5,9 +5,8 @@ import React, { FC, Fragment } from 'react' import { Checkbox } from '../Checkbox/Checkbox' import { ComponentWrapper } from '../../wrapper' import { Error, Header, Hint } from '../shared/FormText' -import { FormElementProps } from '../../types/forms' +import { FormElementProps, TextWithA11y } from '../../types' import { Spacer } from '../Spacer/Spacer' -import { TextWithA11y } from '../../types' import { useTheme } from '../../utils' type TextWithA11yAndValue = TextWithA11y & { diff --git a/packages/components/src/components/shared/FormText.tsx b/packages/components/src/components/shared/FormText.tsx index 072665ac..4f248500 100644 --- a/packages/components/src/components/shared/FormText.tsx +++ b/packages/components/src/components/shared/FormText.tsx @@ -3,8 +3,7 @@ import { useTranslation } from 'react-i18next' import React, { FC } from 'react' import { StringOrTextWithA11y } from '../../types/common' -import { getA11yLabel, getDisplayText } from '../../utils' -import { useTheme } from '../../utils' +import { getA11yLabel, getDisplayText, useTheme } from '../../utils' type FormTextProps = { /** String to display or TextWithA11y object with string and a11y label */ @@ -45,15 +44,14 @@ const fontDescription = { fontSize: 16, lineHeight: 22, } - -/** - * Header text element commonly used in form components - */ export type HeaderProps = FormTextProps & { /** True to display (*Required) label next to header */ required?: boolean } +/** + * Header text element commonly used in form components + */ export const Header: FC = ({ text, required }) => { const theme = useTheme() const { t } = useTranslation()