Skip to content

Commit

Permalink
James RadioGroup PR
Browse files Browse the repository at this point in the history
Merge

Fix form submission data

Fix demo

Add initial tests

Port Composite tests

Remove passing of non-DOM props

Switch to name prop

Fix docs lint

Use span indicator

Add autoselect

Remove unrelated changes

use client

Refactor touched state

Remove orientation

Remove elementsRef

use client

Fix test

Remove unused hook

Codegen

name -> value

Update docs

Docs

Update

Docs

value: string | number

Rename state

Update demo

Update Radio APIs

Add styling

Fix test linting

use client

Update tests

Delete tests

Update

Fix error throw

Update types

Comment out all Radio tests

Comment out Composite tests

Add Radio tests back

Update APIs

Test composite navigation directly

Fix form test

Integrate with Field

Update
  • Loading branch information
atomiks authored and mj12albert committed Sep 3, 2024
1 parent abe5a3e commit 83ed1f6
Show file tree
Hide file tree
Showing 50 changed files with 2,725 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import * as React from 'react';
import * as RadioGroup from '@base_ui/react/RadioGroup';
import * as Radio from '@base_ui/react/Radio';
import { styled } from '@mui/system';

export default function UnstyledRadioGroupIntroduction() {
return (
<RadioGroup.Root name="root" style={{ display: 'flex', gap: 8 }}>
<RadioItem value="light">
<Indicator />
Light
</RadioItem>
<RadioItem value="medium">
<Indicator />
Medium
</RadioItem>
<RadioItem value="heavy">
<Indicator />
Heavy
</RadioItem>
</RadioGroup.Root>
);
}

const grey = {
100: '#E5EAF2',
200: '#D8E0E9',
300: '#CBD4E2',
};

const blue = {
400: '#3399FF',
600: '#0072E6',
800: '#004C99',
};

const RadioItem = styled(Radio.Root)`
display: flex;
align-items: center;
padding: 8px 16px;
border-radius: 4px;
border: none;
background-color: ${grey[100]};
color: black;
outline: none;
font-size: 16px;
cursor: default;
&:hover {
background-color: ${grey[100]};
}
&:focus-visible {
outline: 2px solid ${blue[400]};
outline-offset: 2px;
}
&[data-radio='checked'] {
background-color: ${blue[600]};
color: white;
}
`;

const Indicator = styled(Radio.Indicator)`
border-radius: 50%;
width: 8px;
height: 8px;
margin-right: 8px;
outline: 1px solid black;
&[data-radio='checked'] {
background-color: white;
border: none;
outline: none;
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import * as React from 'react';
import * as RadioGroup from '@base_ui/react/RadioGroup';
import * as Radio from '@base_ui/react/Radio';
import { styled } from '@mui/system';

export default function UnstyledRadioGroupIntroduction() {
return (
<RadioGroup.Root name="root" style={{ display: 'flex', gap: 8 }}>
<RadioItem value="light">
<Indicator />
Light
</RadioItem>
<RadioItem value="medium">
<Indicator />
Medium
</RadioItem>
<RadioItem value="heavy">
<Indicator />
Heavy
</RadioItem>
</RadioGroup.Root>
);
}

const grey = {
100: '#E5EAF2',
200: '#D8E0E9',
300: '#CBD4E2',
};

const blue = {
400: '#3399FF',
600: '#0072E6',
800: '#004C99',
};

const RadioItem = styled(Radio.Root)`
display: flex;
align-items: center;
padding: 8px 16px;
border-radius: 4px;
border: none;
background-color: ${grey[100]};
color: black;
outline: none;
font-size: 16px;
cursor: default;
&:hover {
background-color: ${grey[100]};
}
&:focus-visible {
outline: 2px solid ${blue[400]};
outline-offset: 2px;
}
&[data-radio='checked'] {
background-color: ${blue[600]};
color: white;
}
`;

const Indicator = styled(Radio.Indicator)`
border-radius: 50%;
width: 8px;
height: 8px;
margin-right: 8px;
outline: 1px solid black;
&[data-radio='checked'] {
background-color: white;
border: none;
outline: none;
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<RadioGroup.Root name="root" style={{ display: 'flex', gap: 8 }}>
<RadioItem value="light">
<Indicator />
Light
</RadioItem>
<RadioItem value="medium">
<Indicator />
Medium
</RadioItem>
<RadioItem value="heavy">
<Indicator />
Heavy
</RadioItem>
</RadioGroup.Root>
135 changes: 135 additions & 0 deletions docs/data/base/components/radio-group/radio-group.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
---
productId: base-ui
title: React Radio Group component
components: RadioGroupRoot, RadioRoot, RadioIndicator
githubLabel: 'component: radio'
waiAria: https://www.w3.org/WAI/ARIA/apg/patterns/radio/
---

# Radio Group

<p class="description">Radio Groups contain a set of checkable buttons where only one of the buttons can be checked at a time.</p>

{{"component": "@mui/docs/ComponentLinkHeader", "design": false}}

{{"component": "modules/components/ComponentPageTabs.js"}}

## Introduction

{{"demo": "UnstyledRadioGroupIntroduction", "defaultCodeOpen": false, "bg": "gradient"}}

## Installation

Base UI components are all available as a single package.

<codeblock storageKey="package-manager">

```bash npm
npm install @base_ui/react
```

```bash yarn
yarn add @base_ui/react
```

```bash pnpm
pnpm add @base_ui/react
```

</codeblock>

Once you have the package installed, import the components.

```ts
import * as RadioGroup from '@base_ui/react/RadioGroup';
import * as Radio from '@base_ui/react/Radio';
```

## Anatomy

Radio Group is composed of a `Root` and `Radio` components:

- `<RadioGroup.Root />` is a top-level element that wraps the other components.
- `<Radio.Root />` renders an individual `<button>` radio item.
- `<Radio.Indicator />` renders a `<span>` for providing a visual indicator. You can style this itself and/or place an icon inside.

```jsx
<RadioGroup.Root>
<Radio.Root>
<Radio.Indicator />
</Radio.Root>
</RadioGroup.Root>
```

## Identifying items

The `value` prop is required on `Radio.Root` to identify it in the Radio Group:

```jsx
<RadioGroup.Root>
<Radio.Root value="a">
<Radio.Indicator />
</Radio.Root>
<Radio.Root value="b">
<Radio.Indicator />
</Radio.Root>
</RadioGroup.Root>
```

## Default value

The `defaultValue` prop determines the initial value of the component when uncontrolled, linked to the `value` prop on an individual Radio item:

```jsx
<RadioGroup.Root defaultValue="a">
<Radio.Root value="a" />
<Radio.Root value="b" />
</RadioGroup.Root>
```

## Controlled

The `value` and `onValueChange` props contain the `value` string of the currently selected Radio item in the Radio Group:

```jsx
const [value, setValue] = React.useState('a');

return (
<RadioGroup.Root value={value} onValueChange={setValue}>
<Radio.Root value="a" />
<Radio.Root value="b" />
</RadioGroup.Root>
);
```

## Styling

The `Radio` components have a `[data-radio]` attribute with values `"checked"` or `"unchecked"` to style based on the checked state:

```jsx
<Radio.Root className="Radio">
<Radio.Indicator className="RadioIndicator" />
</Radio.Root>
```

```css
.Radio {
border: 1px solid black;
}

.RadioIndicator {
width: 20px;
height: 20px;
border-radius: 50%;
border: 1px solid black;
}

.Radio[data-radio='checked'] {
background: black;
color: white;
}

.RadioIndicator[data-radio='checked'] {
background: white;
}
```
2 changes: 1 addition & 1 deletion docs/data/base/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const pages: readonly MuiPage[] = [
// { pathname: '/base-ui/react-autocomplete', title: 'Autocomplete' },
{ pathname: '/base-ui/react-checkbox', title: 'Checkbox' },
{ pathname: '/base-ui/react-number-field', title: 'Number Field' },
// { pathname: '/base-ui/react-radio-group', title: 'Radio Group', planned: true },
{ pathname: '/base-ui/react-radio-group', title: 'Radio Group' },
// { pathname: '/base-ui/react-select', title: 'Select' },
{ pathname: '/base-ui/react-slider', title: 'Slider' },
{ pathname: '/base-ui/react-switch', title: 'Switch' },
Expand Down
12 changes: 12 additions & 0 deletions docs/data/base/pagesApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,18 @@ module.exports = [
pathname: '/base-ui/react-progress/components-api/#progress-track',
title: 'ProgressTrack',
},
{
pathname: '/base-ui/react-radio-group/components-api/#radio-group-root',
title: 'RadioGroupRoot',
},
{
pathname: '/base-ui/react-radio-group/components-api/#radio-indicator',
title: 'RadioIndicator',
},
{
pathname: '/base-ui/react-radio-group/components-api/#radio-root',
title: 'RadioRoot',
},
{ pathname: '/base-ui/react-select/components-api/#select', title: 'Select' },
{
pathname: '/base-ui/react-slider/components-api/#slider-control',
Expand Down
26 changes: 26 additions & 0 deletions docs/pages/base-ui/api/radio-group-root.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"props": {
"className": { "type": { "name": "union", "description": "func<br>&#124;&nbsp;string" } },
"defaultValue": { "type": { "name": "union", "description": "number<br>&#124;&nbsp;string" } },
"disabled": { "type": { "name": "bool" }, "default": "false" },
"name": { "type": { "name": "string" } },
"onValueChange": { "type": { "name": "func" } },
"readOnly": { "type": { "name": "bool" }, "default": "false" },
"render": { "type": { "name": "union", "description": "element<br>&#124;&nbsp;func" } },
"required": { "type": { "name": "bool" }, "default": "false" },
"value": { "type": { "name": "union", "description": "number<br>&#124;&nbsp;string" } }
},
"name": "RadioGroupRoot",
"imports": [
"import * as RadioGroup from '@base_ui/react/RadioGroup';\nconst RadioGroupRoot = RadioGroup.Root;"
],
"classes": [],
"spread": true,
"themeDefaultProps": true,
"muiName": "RadioGroupRoot",
"forwardsRefTo": "HTMLDivElement",
"filename": "/packages/mui-base/src/RadioGroup/Root/RadioGroupRoot.tsx",
"inheritance": null,
"demos": "<ul><li><a href=\"/base-ui/react-radio-group/\">Radio Group</a></li></ul>",
"cssComponent": false
}
19 changes: 19 additions & 0 deletions docs/pages/base-ui/api/radio-indicator.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"props": {
"className": { "type": { "name": "union", "description": "func<br>&#124;&nbsp;string" } },
"render": { "type": { "name": "union", "description": "element<br>&#124;&nbsp;func" } }
},
"name": "RadioIndicator",
"imports": [
"import * as Radio from '@base_ui/react/Radio';\nconst RadioIndicator = Radio.Indicator;"
],
"classes": [],
"spread": true,
"themeDefaultProps": true,
"muiName": "RadioIndicator",
"forwardsRefTo": "HTMLSpanElement",
"filename": "/packages/mui-base/src/Radio/Indicator/RadioIndicator.tsx",
"inheritance": null,
"demos": "<ul><li><a href=\"/base-ui/react-radio-group/\">Radio Group</a></li></ul>",
"cssComponent": false
}
Loading

0 comments on commit 83ed1f6

Please sign in to comment.