import { Meta, Canvas, Controls } from '@storybook/addon-docs/blocks'
import * as RadioStories from './radio.stories.tsx'

<Meta of={RadioStories} />

# GridEditorRadio

```tsx
import { GridEditorRadio } from '@planview/pv-grid'
```

This is a special type of editor called a hybrid editor. The radio will be used as both the Renderer and the Editor. This means even without the grid being in edit mode it will still trigger `onCellChange` when changed. If you are just displaying a true/false value but do not wish to enable editing, do not use this control.

Use this editor to model single-selection across rows — for example, marking one row as the default item in a list. The column value is a boolean (`true` = this row is selected). Consumer code is responsible for enforcing the single-selection invariant: in `onCellChange`, set the clicked row to `true` and all other rows to `false`.

<Canvas of={RadioStories.Default} />

### Props provided by the Grid (via `Editor`)

Additional props are provided by the grid that are not used by this editor.

<Controls include={['value', 'onConfirm', 'onCancel', 'mode', 'tabIndex']} />

## Usage with Column definition

This component should be used as part of a custom `Editor` method on the Column configuration. You will also need to set `hybridEditor` to `true`.

```tsx
import { GridEditorRadio, Column } from '@planview/pv-grid'

const EditableColumn: Column = {
    id: 'isDefault',
    label: 'Default',
    cell: {
        editable: true,
        hybridEditor: true,
        Editor: GridEditorRadio,
    },
}
```

### Enforcing single-selection

Because each `GridEditorRadio` is an independent cell editor, the grid does not enforce that only one row is selected at a time. Enforce this in `onCellChange`:

```tsx
onCellChange={(confirm) => {
    setRows((rows) =>
        rows.map((row) => ({
            ...row,
            isDefault:
                confirm.columnId === 'isDefault'
                    ? row.id === confirm.rowId
                    : row.isDefault,
        }))
    )
}}
```

## Conditionally rendering disabled state

To render the `GridEditorRadio` as disabled you would need to set the `hybridEditor` attribute to `"always"` and then control the disabled state of each row using the `editable` attribute.

```tsx
import { GridEditorRadio, Column } from '@planview/pv-grid'

const EditableColumn: Column = {
    id: 'isDefault',
    label: 'Default',
    cell: {
        editable: ({ row }) => checkIfRowCanBeEdited(row),
        hybridEditor: 'always',
        Editor: GridEditorRadio,
    },
}
```

<Canvas of={RadioStories.Disabled} />

## Accessibility

### Why this is not a WAI-ARIA `radiogroup`

The WAI-ARIA [radio group pattern](https://www.w3.org/WAI/ARIA/apg/patterns/radio/) requires sibling radio buttons under a single `role="radiogroup"` container with arrow-key navigation between them. Inside a grid, cells have `role="gridcell"` inside `role="row"`, and arrow keys are owned by the grid for row and cell navigation. Wrapping all cells in a `radiogroup` is not structurally possible, and intercepting arrow keys for radio roving would conflict with the grid's keyboard model.

### What we do instead

- Each cell renders a native `<input type="radio">` with a shared `name` attribute equal to the column ID. Browsers treat all radios with the same `name` as a group for form submission and reset purposes.
- Arrow keys (`ArrowUp`, `ArrowDown`, `ArrowLeft`, `ArrowRight`) are suppressed at the cell level so they do not trigger native radio roving and do not fight with the grid's own navigation.
- Each radio receives an `aria-label` from the column label so assistive technology announces "radio button, checked" / "radio button, not checked" along with the column name.
- The Space key selects the focused radio natively — no custom handler is needed.

Assistive technology will announce each cell as an individual radio button. Users navigate between rows using the grid's standard arrow-key navigation and activate a radio with Space or click.
