Skip to content

Commit

Permalink
fix(a11y): connect labels to inputs (#1542)
Browse files Browse the repository at this point in the history
  • Loading branch information
vtsvetkov-splunk authored Jan 31, 2025
1 parent 1c5beac commit 5335782
Show file tree
Hide file tree
Showing 57 changed files with 280 additions and 260 deletions.
11 changes: 11 additions & 0 deletions ui/.storybook/withControlGroup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import ControlGroup from '@splunk/react-ui/ControlGroup';
import { Decorator } from '@storybook/react';

export const withControlGroup: Decorator = (StoryFn, { name }) => {
return (
<ControlGroup label={name} labelWidth={260}>
{StoryFn()}
</ControlGroup>
);
};
15 changes: 7 additions & 8 deletions ui/src/components/BaseFormView/BaseFormViewGrups.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ it('should modify correctly all properties of field in groups', async () => {
handleFormSubmit={handleFormSubmit}
/>
);
await screen.findByText('Text 1 Group 2');
await screen.findByRole('textbox', { name: 'Text 1 Group 2' });

const getAndValidateGroupFieldLabels = (
fieldId: string,
Expand All @@ -46,14 +46,13 @@ it('should modify correctly all properties of field in groups', async () => {
return modifiedFieldSameGroup;
};

const modifiedFieldSameGroup = getAndValidateGroupFieldLabels(
'text_field_2_group_1',
'help after mods 2-1',
'label after mods 2-1',
'markdown message after mods 2-1'
);
const modifiedFieldSameGroup = screen.getByRole('textbox', {
name: 'label after mods 2-1',
description: 'markdown message after mods 2-1 help after mods 2-1',
});

expect(within(modifiedFieldSameGroup).queryByText('*')).toBeInTheDocument();
expect(modifiedFieldSameGroup).toBeInTheDocument();
expect(modifiedFieldSameGroup).toHaveAttribute('required');

const modifiedFieldDiffGroup = getAndValidateGroupFieldLabels(
'text_field_2_group_2',
Expand Down
3 changes: 1 addition & 2 deletions ui/src/components/BaseFormView/tests/BaseFormView.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,7 @@ it('should render base form correctly with name and File fields', async () => {
/>
);

const nameField = document.querySelector('[data-name="name"]');
expect(nameField).toBeInTheDocument();
screen.getByRole('textbox', { name: 'Name' });

const fileField = document.querySelector('[data-name="name"]');
expect(fileField).toBeInTheDocument();
Expand Down
11 changes: 7 additions & 4 deletions ui/src/components/CheckBoxComponent/CheckBoxComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import React from 'react';
import Switch from '@splunk/react-ui/Switch';
import { isFalse } from '../../util/considerFalseAndTruthy';

import { excludeControlWrapperProps } from '../ControlWrapper/utils';

export interface CheckBoxComponentProps {
value: 0 | 1 | boolean;
handleChange: (field: string, value: 0 | 1) => void;
Expand All @@ -19,13 +21,14 @@ class CheckBoxComponent extends React.Component<CheckBoxComponentProps> {
};

render() {
const { field, value, ...restProps } = this.props;
const restSuiProps = excludeControlWrapperProps(restProps);
return (
<Switch
key={this.props.field}
value={this.props.field}
{...restSuiProps}
value={field}
onClick={this.handleChange}
disabled={this.props.disabled}
selected={!(this.props.value ? isFalse(this.props.value) : true)}
selected={!(value ? isFalse(value) : true)}
appearance="checkbox"
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import type { Meta, StoryObj } from '@storybook/react';
import React, { useState } from 'react';
import { fn } from '@storybook/test';
import CheckBoxComponent from '../CheckBoxComponent';
import { withControlGroup } from '../../../../.storybook/withControlGroup';

const meta = {
component: CheckBoxComponent,
title: 'CheckBoxComponent',
decorators: [withControlGroup],
render: (props) => {
// due to stories incompatibility, eslint rule is off
// React Hook "useState" is called in function "render" that is neither a React function component
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 9 additions & 5 deletions ui/src/components/CheckboxGroup/CheckboxGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react';
import ColumnLayout from '@splunk/react-ui/ColumnLayout';
import Button from '@splunk/react-ui/Button';
import { StyledColumnLayout } from './StyledComponent';
import styled from 'styled-components';
import {
CheckboxGroupProps,
getDefaultValues,
Expand All @@ -16,6 +16,10 @@ import CheckboxRowWrapper from './CheckboxRowWrapper';
import { useValidation } from './checkboxGroupValidation';
import { MODE_CREATE } from '../../constants/modes';

const FullWidth = styled.div`
width: 100%;
`;

function CheckboxGroup(props: CheckboxGroupProps) {
const { field, handleChange, controlOptions, addCustomValidator, disabled } = props;
const flattenedRowsWithGroups = getFlattenRowsWithGroups(controlOptions);
Expand Down Expand Up @@ -60,8 +64,8 @@ function CheckboxGroup(props: CheckboxGroupProps) {
};

return (
<>
<StyledColumnLayout gutter={5}>
<FullWidth>
<ColumnLayout gutter={5}>
{flattenedRowsWithGroups.map((row) => {
if (isGroupWithRows(row)) {
// labels are unique across groups
Expand All @@ -88,7 +92,7 @@ function CheckboxGroup(props: CheckboxGroupProps) {
);
})}
<ColumnLayout.Row />
</StyledColumnLayout>
</ColumnLayout>
<div>
<Button
label="Select All"
Expand All @@ -101,7 +105,7 @@ function CheckboxGroup(props: CheckboxGroupProps) {
onClick={() => handleCheckboxToggleAll(false)}
/>
</div>
</>
</FullWidth>
);
}

Expand Down
3 changes: 1 addition & 2 deletions ui/src/components/CheckboxGroup/CheckboxRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React, { useEffect, useState } from 'react';
import NumberComponent, { NumberChangeHandler } from '@splunk/react-ui/Number';
import styled from 'styled-components';
import Switch from '@splunk/react-ui/Switch';
import { FixedCheckboxRowWidth } from './StyledComponent';

const StyledSwitch = styled(Switch)`
padding: 0 3px;
Expand All @@ -16,7 +15,7 @@ const StyledRow = styled.div`
display: flex;
align-items: baseline;
justify-content: space-between;
${FixedCheckboxRowWidth}
width: 100%;
`;

interface CheckboxRowProps {
Expand Down
9 changes: 0 additions & 9 deletions ui/src/components/CheckboxGroup/StyledComponent.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import type { Meta, StoryObj } from '@storybook/react';
import { fn } from '@storybook/test';
import CheckboxGroup from '../CheckboxGroup';
import { MODE_CREATE, MODE_EDIT } from '../../../constants/modes';
import { withControlGroup } from '../../../../.storybook/withControlGroup';

const meta = {
component: CheckboxGroup,
title: 'CheckboxGroup/Component',
decorators: [withControlGroup],
} satisfies Meta<typeof CheckboxGroup>;

export default meta;
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 9 additions & 5 deletions ui/src/components/CheckboxTree/CheckboxTree.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useEffect, useState, useCallback, useMemo } from 'react';
import ColumnLayout from '@splunk/react-ui/ColumnLayout';
import Button from '@splunk/react-ui/Button';
import { StyledColumnLayout } from './StyledComponent';
import styled from 'styled-components';
import {
getDefaultValues,
getFlattenRowsWithGroups,
Expand All @@ -14,6 +14,10 @@ import { MODE_CREATE } from '../../constants/modes';
import { CheckboxTreeProps, ValueByField } from './types';
import { packValue, parseValue } from './utils';

const FullWidth = styled.div`
width: 100%;
`;

function CheckboxTree(props: CheckboxTreeProps) {
const { field, handleChange, controlOptions, disabled } = props;

Expand Down Expand Up @@ -94,8 +98,8 @@ function CheckboxTree(props: CheckboxTreeProps) {
);

return (
<>
<StyledColumnLayout gutter={5}>
<FullWidth>
<ColumnLayout gutter={5}>
{flattenedRowsWithGroups.map((row) =>
row && isGroupWithRows(row) ? (
<ColumnLayout.Row key={`group_${row.label}`}>
Expand All @@ -121,7 +125,7 @@ function CheckboxTree(props: CheckboxTreeProps) {
)
)}
<ColumnLayout.Row />
</StyledColumnLayout>
</ColumnLayout>
<div>
<Button
label="Select All"
Expand All @@ -134,7 +138,7 @@ function CheckboxTree(props: CheckboxTreeProps) {
onClick={() => handleCheckboxToggleAll(false)}
/>
</div>
</>
</FullWidth>
);
}

Expand Down
9 changes: 0 additions & 9 deletions ui/src/components/CheckboxTree/StyledComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,15 @@
import styled, { css } from 'styled-components';
import ColumnLayout from '@splunk/react-ui/ColumnLayout';
import CollapsiblePanel from '@splunk/react-ui/CollapsiblePanel';
import { pick, variables } from '@splunk/themes';
import Switch from '@splunk/react-ui/Switch';

const FixedCheckboxRowWidth = css`
width: 320px;
`;

const CheckboxInHeader = css`
align-self: center;
background-color: ${pick({
enterprise: variables.neutral100,
})};
`;

export const StyledColumnLayout = styled(ColumnLayout)`
${FixedCheckboxRowWidth}
`;

export const CheckboxContainer = styled.div`
display: flex;
flex-direction: column;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import type { Meta, StoryObj } from '@storybook/react';
import { fn } from '@storybook/test';
import CheckboxTree from '../CheckboxTree';
import { MODE_CREATE, MODE_EDIT } from '../../../constants/modes';
import { withControlGroup } from '../../../../.storybook/withControlGroup';

const meta = {
component: CheckboxTree,
title: 'CheckboxTree/Component',
decorators: [withControlGroup],
} satisfies Meta<typeof CheckboxTree>;

export default meta;
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 3 additions & 11 deletions ui/src/components/ControlWrapper/ControlWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,14 @@ import { AcceptableFormValueOrNullish } from '../../types/components/shareableTy
import CustomControl from '../CustomControl/CustomControl';
import { Mode } from '../../constants/modes';

const CustomElement = styled.div``;

const ControlGroupWrapper = styled(ControlGroup).attrs((props: { dataName: string }) => ({
'data-name': props.dataName,
}))`
max-width: 100%;
// label width + control width
width: calc(260px + 320px);
span[class*='ControlGroupStyles__StyledAsterisk-'] {
color: red;
}
> * {
&:nth-child(3) {
width: 320px;
}
}
`;

export interface ControlWrapperProps {
Expand Down Expand Up @@ -152,7 +144,7 @@ class ControlWrapper extends React.PureComponent<ControlWrapperProps> {
required={isFieldRequired}
label={label}
>
<CustomElement>{rowView}</CustomElement>
{rowView}
</ControlGroupWrapper>
)
);
Expand Down
Loading

0 comments on commit 5335782

Please sign in to comment.