Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix disabled Radio #373

Merged
merged 5 commits into from
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/sharp-items-impress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@utilitywarehouse/web-ui': patch
---

Fix disabled Radio
14 changes: 14 additions & 0 deletions packages/web-ui/src/BaseRadioGroup/BaseRadioGroup.context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { createContext, useContext } from 'react';

export type BaseRadioGroupContextValue = {
hasGroupHelperText: boolean;
'aria-describedby'?: string;
};

export const BaseRadioGroupContext = createContext<BaseRadioGroupContextValue>({
hasGroupHelperText: false,
} as BaseRadioGroupContextValue);

export const BaseRadioGroupProvider = BaseRadioGroupContext.Provider;

export const useBaseRadioGroup = () => useContext(BaseRadioGroupContext);
38 changes: 38 additions & 0 deletions packages/web-ui/src/BaseRadioGroup/BaseRadioGroup.props.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { type ReactNode } from 'react';
import { type RadioGroupProps as RadixRadioGroupProps } from '@radix-ui/react-radio-group';

export interface BaseRadioGroupProps extends Omit<RadixRadioGroupProps, 'dir'> {
children: ReactNode;
/**
* The label for the radio group. This should contain the question being
* answered by the radio group.
*
* If you don't include a label you need to ensure you use the `aria-label`
* or `aria-labelledby` prop to properly associate a label with the radio
* group.
*/
label?: ReactNode;
/**
* Helper text for the radio group. Provides a hint such as specific
* requirements for what to choose. When displayed, child `Radio` or
* `RadioTile` components will not display `helperText`.
*/
helperText?: ReactNode;
/**
* Position of the helper text.
* @default 'top'
*/
helperTextPosition?: 'top' | 'bottom';
/**
* Set whether to display the helper text icon.
*/
showHelperTextIcon?: boolean;
/** Controls whether the error message is displayed. */
error?: boolean;
/** The error message to be displayed. */
errorMessage?: ReactNode;
/**
* Set whether to display the error message icon.
*/
showErrorMessageIcon?: boolean;
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import { HelperText } from '../HelperText';
import { useIds } from '../hooks';
import { PropsWithSx } from '../types';
import { mergeIds } from '../utils';
import { BaseRadioGroupProps } from './RadioGroup.props';
import { RadioGroupContext } from './RadioGroup.context';
import { BaseRadioGroupProps } from './BaseRadioGroup.props';
import { BaseRadioGroupProvider } from './BaseRadioGroup.context';

const componentName = 'RadioGroupFormField';
const componentName = 'BaseRadioGroup';

export const RadioGroupFormField = forwardRef<HTMLDivElement, PropsWithSx<BaseRadioGroupProps>>(
export const BaseRadioGroup = forwardRef<HTMLDivElement, PropsWithSx<BaseRadioGroupProps>>(
(
{
id: providedId,
Expand Down Expand Up @@ -72,7 +72,7 @@ export const RadioGroupFormField = forwardRef<HTMLDivElement, PropsWithSx<BaseRa
{helperText}
</HelperText>
) : null}
<RadioGroupContext.Provider value={value}>{children}</RadioGroupContext.Provider>
<BaseRadioGroupProvider value={value}>{children}</BaseRadioGroupProvider>
</Box>

{showErrorMessage ? (
Expand All @@ -90,4 +90,4 @@ export const RadioGroupFormField = forwardRef<HTMLDivElement, PropsWithSx<BaseRa
}
);

RadioGroupFormField.displayName = componentName;
BaseRadioGroup.displayName = componentName;
8 changes: 8 additions & 0 deletions packages/web-ui/src/BaseRadioGroup/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export { BaseRadioGroup } from './BaseRadioGroup';
export type { BaseRadioGroupProps } from './BaseRadioGroup.props';
export {
BaseRadioGroupContext,
BaseRadioGroupProvider,
useBaseRadioGroup,
} from './BaseRadioGroup.context';
export type { BaseRadioGroupContextValue } from './BaseRadioGroup.context';
5 changes: 1 addition & 4 deletions packages/web-ui/src/HelperText/HelperText.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import * as React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { HelperText } from './HelperText';

Expand All @@ -23,6 +22,4 @@ const meta: Meta<typeof HelperText> = {
export default meta;
type Story = StoryObj<typeof HelperText>;

export const Workshop: Story = {
render: args => <HelperText {...args} />,
};
export const Workshop: Story = {};
2 changes: 1 addition & 1 deletion packages/web-ui/src/HelperText/HelperText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const StyledElement = styled('span')({
// Button's color property if not set.
color: 'var(--helper-text-color)',
},
':where([data-disabled])': {
':where([data-disabled],[data-disabled] &)': {
'--helper-text-color': 'var(--helper-text-color-disabled)',
},
[classSelectors.valid]: {
Expand Down
4 changes: 2 additions & 2 deletions packages/web-ui/src/Radio/Radio.props.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type RadioGroupItemProps } from '@radix-ui/react-radio-group';
import { type ReactNode } from 'react';
import type { RadioGroupItemProps } from '@radix-ui/react-radio-group';
import type { ReactNode } from 'react';

export interface RadioProps extends Omit<RadioGroupItemProps, 'children'> {
/**
Expand Down
2 changes: 1 addition & 1 deletion packages/web-ui/src/Radio/Radio.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Stack } from '../Stack';
import { Text, TextProps } from '../Text';

const meta: Meta<typeof Radio> = {
title: 'Web UI / Components / RadioGroup',
title: 'Web UI / Components / Radio / Radio',
component: Radio,
};

Expand Down
11 changes: 7 additions & 4 deletions packages/web-ui/src/Radio/Radio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ import { HelperText } from '../HelperText';
import { useIds } from '../hooks';
import { PropsWithSx } from '../types';
import { RadioProps } from './Radio.props';
import { RadioGroupContext } from '../RadioGroup/RadioGroup.context';
import { styled } from '../theme';
import { spacing, withGlobalPrefix } from '../utils';
import clsx from 'clsx';
import { Flex } from '../Flex';
import { useBaseRadioGroup } from '../BaseRadioGroup';

const componentName = 'Radio';
const componentClassName = withGlobalPrefix(componentName);
Expand Down Expand Up @@ -111,13 +111,16 @@ export const Radio = React.forwardRef<HTMLButtonElement, PropsWithSx<RadioProps>
ref
) => {
const { id, labelId, helperTextId } = useIds({ providedId, componentPrefix: 'radio' });
const { hasGroupHelperText, 'aria-describedby': ariaDescribedby } =
React.useContext(RadioGroupContext);
const { hasGroupHelperText, 'aria-describedby': ariaDescribedby } = useBaseRadioGroup();
const showHelperText = !hasGroupHelperText && !!helperText;
const showLabel = !!label;

return (
<StyledElement className={clsx(componentClassName, className)} sx={sx}>
<StyledElement
className={clsx(componentClassName, className)}
sx={sx}
data-disabled={disabled ? '' : undefined}
>
<StyledRadioContainer>
<StyledRadioItem
ref={ref}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Stack } from '../Stack';
import { RadioTile } from '../RadioTile';

const meta: Meta<typeof RadioGridGroup> = {
title: 'Web UI / Components / RadioGridGroup',
title: 'Web UI / Components / Radio / RadioGridGroup',
component: RadioGridGroup,
tags: ['autodocs'],
argTypes: {
Expand Down
27 changes: 4 additions & 23 deletions packages/web-ui/src/RadioGridGroup/RadioGridGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,14 @@
import * as React from 'react';
import { Box } from '../Box';
import { RadioGroupFormField } from '../RadioGroup/RadioGroupFormField';
import { breakpoints } from '../tokens';
import { PropsWithSx } from '../types';
import { RadioGridGroupProps } from './RadioGridGroup.props';
import clsx from 'clsx';
import { withGlobalPrefix } from '../utils';
import { getColumns, withGlobalPrefix } from '../utils';
import { BaseRadioGroup } from '../BaseRadioGroup';

const componentName = 'RadioGridGroup';
const componentClassName = withGlobalPrefix(componentName);

function convert(c: string) {
return `repeat(${c}, minmax(10px, 1fr))`;
}
function getColumns(columns: RadioGridGroupProps['columns']) {
if (Array.isArray(columns)) {
return columns.map(s => convert(s as string));
}
if (typeof columns === 'object') {
return Object.keys(breakpoints).reduce((acc: { [key: string]: string }, breakpoint: string) => {
if (columns[breakpoint] !== null) {
acc[breakpoint] = convert(columns[breakpoint] as string);
}
return acc;
}, {});
}
return convert(columns as string);
}

/**
* The `RadioGridGroup` provides an accessible way to group and control a set
* of `Radio` or `RadioTile` components, displayed in a grid layout, allowing
Expand All @@ -46,7 +27,7 @@ function getColumns(columns: RadioGridGroupProps['columns']) {
export const RadioGridGroup = React.forwardRef<HTMLDivElement, PropsWithSx<RadioGridGroupProps>>(
({ children, contentWidth = 'fit-content', columns = 2, className, ...props }, ref) => {
return (
<RadioGroupFormField ref={ref} className={clsx(componentClassName, className)} {...props}>
<BaseRadioGroup ref={ref} className={clsx(componentClassName, className)} {...props}>
<Box
display="grid"
gap={2}
Expand All @@ -56,7 +37,7 @@ export const RadioGridGroup = React.forwardRef<HTMLDivElement, PropsWithSx<Radio
>
{children}
</Box>
</RadioGroupFormField>
</BaseRadioGroup>
);
}
);
Expand Down
6 changes: 0 additions & 6 deletions packages/web-ui/src/RadioGroup/RadioGroup.context.ts

This file was deleted.

8 changes: 4 additions & 4 deletions packages/web-ui/src/RadioGroup/RadioGroup.docs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { Divider } from '@mui/material';
- [Keyboard interactions](#keyboard-interactions)
- [Helper text](#helper-text)
- [Error message](#error-message)
- [Width](#width)
- [Content Width](#content-width)
- [Controlled](#controlled)
- [RadioGroup props](#radiogroup-props)
- [Radio & RadioTile](#radio-&-radiotile)
Expand Down Expand Up @@ -95,7 +95,7 @@ either above or below the group's radio items. While the radio items can also
display a helper text, these will not be displayed if the radio group has a
helper text.

<Canvas of={RadioGroupStories.WithRadioHelperText} />
<Canvas of={RadioGroupStories.RadioHelperText} />

## Error message

Expand All @@ -105,7 +105,7 @@ submitted.

<Canvas of={RadioGroupStories.ShowingError} />

## Width
## Content width

The width of the `RadioGroup` should be set by the parent layout, however it is
possible to independently set the width of the children using `contentWidth`
Expand All @@ -119,7 +119,7 @@ the `RadioGroup`.
This is a responsive property, so you are able to set different widths for
different breakpoints.

<Canvas of={RadioGroupStories.Width} />
<Canvas of={RadioGroupStories.ContentWidth} />

## Controlled

Expand Down
39 changes: 1 addition & 38 deletions packages/web-ui/src/RadioGroup/RadioGroup.props.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,5 @@
import { BaseRadioGroupProps } from '../BaseRadioGroup';
import { BoxProps } from '../Box';
import { type ReactNode } from 'react';
import { type RadioGroupProps as RadixRadioGroupProps } from '@radix-ui/react-radio-group';

export interface BaseRadioGroupProps extends Omit<RadixRadioGroupProps, 'dir'> {
children: ReactNode;
/**
* The label for the radio group. This should contain the question being
* answered by the radio group.
*
* If you don't include a label you need to ensure you use the `aria-label`
* or `aria-labelledby` prop to properly associate a label with the radio
* group.
*/
label?: ReactNode;
/**
* Helper text for the radio group. Provides a hint such as specific
* requirements for what to choose. When displayed, child `Radio` or
* `RadioTile` components will not display `helperText`.
*/
helperText?: ReactNode;
/**
* Position of the helper text.
* @default 'top'
*/
helperTextPosition?: 'top' | 'bottom';
/**
* Set whether to display the helper text icon.
*/
showHelperTextIcon?: boolean;
/** Controls whether the error message is displayed. */
error?: boolean;
/** The error message to be displayed. */
errorMessage?: ReactNode;
/**
* Set whether to display the error message icon.
*/
showErrorMessageIcon?: boolean;
}

export interface RadioGroupProps extends Omit<BaseRadioGroupProps, 'orientation'> {
/** The direction of the radios, will also set the aria-orientation value. */
Expand Down
12 changes: 6 additions & 6 deletions packages/web-ui/src/RadioGroup/RadioGroup.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Box } from '../Box';
import { colors } from '@utilitywarehouse/colour-system';

const meta: Meta<typeof RadioGroup> = {
title: 'Web UI / Components / RadioGroup',
title: 'Web UI / Components / Radio / RadioGroup',
component: RadioGroup,
argTypes: {
direction: {
Expand Down Expand Up @@ -62,8 +62,8 @@ export const Workshop: Story = {
},
};

export const WithRadioHelperText: Story = {
name: 'With Radio HelperText',
export const RadioHelperText: Story = {
name: 'Radio HelperText',
render: args => {
return (
<RadioGroup {...args}>
Expand All @@ -78,8 +78,8 @@ export const WithRadioHelperText: Story = {
},
};

export const Width: Story = {
name: 'Width',
export const ContentWidth: Story = {
name: 'Content Width',
render: args => {
return (
<RadioGroup {...args} helperText="Setting the width of the children elements">
Expand All @@ -89,7 +89,7 @@ export const Width: Story = {
</RadioGroup>
);
},
args: { contentWidth: '100%' },
args: { contentWidth: '200px' },
};

export const Controlled: Story = {
Expand Down
6 changes: 3 additions & 3 deletions packages/web-ui/src/RadioGroup/RadioGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import * as React from 'react';
import { PropsWithSx } from '../types';
import { withGlobalPrefix } from '../utils';
import { RadioGroupProps } from './RadioGroup.props';
import { RadioGroupFormField } from './RadioGroupFormField';
import clsx from 'clsx';
import { Flex } from '../Flex';
import { styled } from '../theme';
import { BaseRadioGroup } from '../BaseRadioGroup';

const componentName = 'RadioGroup';
const componentClassName = withGlobalPrefix(componentName);
Expand Down Expand Up @@ -36,7 +36,7 @@ const StyledElement = styled(Flex)({
export const RadioGroup = React.forwardRef<HTMLDivElement, PropsWithSx<RadioGroupProps>>(
({ children, contentWidth = 'fit-content', direction = 'column', className, ...props }, ref) => {
return (
<RadioGroupFormField
<BaseRadioGroup
ref={ref}
className={clsx(componentClassName, className)}
{...props}
Expand All @@ -45,7 +45,7 @@ export const RadioGroup = React.forwardRef<HTMLDivElement, PropsWithSx<RadioGrou
<StyledElement width={contentWidth} gap={2}>
{children}
</StyledElement>
</RadioGroupFormField>
</BaseRadioGroup>
);
}
);
Expand Down
Loading
Loading