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

feat(ffe-form-react): standardize selectedValue in radio components #2447

Merged
merged 1 commit into from
Dec 17, 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
12 changes: 0 additions & 12 deletions packages/ffe-form-react/src/BaseRadioButton.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,6 @@ describe('<BaseRadioButton />', () => {
expect(radio).not.toBeChecked();
});

it('accepts boolean values and checks the input if it is selected', () => {
renderBaseRadioButton({ selectedValue: true, value: true });
const radio = screen.getByRole('radio');
expect(radio).toBeChecked();
});

it('accepts boolean values and does not check the input if it is not selected', () => {
renderBaseRadioButton({ selectedValue: 'false', value: true });
const radio = screen.getByRole('radio');
expect(radio).not.toBeChecked();
});

describe('id', () => {
it('is unique across instances', () => {
renderBaseRadioButton();
Expand Down
5 changes: 3 additions & 2 deletions packages/ffe-form-react/src/BaseRadioButton.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import React, { useId } from 'react';
import classNames from 'classnames';
import { Tooltip, TooltipProps } from './Tooltip';
import { SelectedRadioValue } from './types';

export interface BaseRadioButtonProps
extends Omit<React.ComponentPropsWithoutRef<'input'>, 'value'> {
/** Additional props passed to the label element */
labelProps?: React.ComponentProps<'label'>;
/** The selected value of the radio button set */
selectedValue?: boolean | string | number | null;
selectedValue?: SelectedRadioValue;
/** The value of the radio button */
value: boolean | string | number;
value: string;
/** Tooltip providing further detail about the choice */
tooltip?: string;
tooltipProps?: TooltipProps;
Expand Down
7 changes: 4 additions & 3 deletions packages/ffe-form-react/src/RadioBlock.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React, { useId } from 'react';
import classNames from 'classnames';
import { SelectedRadioValue } from './types';

export interface RadioBlockProps
extends React.ComponentPropsWithoutRef<'input'> {
/** Whether or not the radio block is selected */
/** Whether the radio block is selected */
checked?: boolean;
/** The always visible label of the radio block */
label: React.ReactNode;
Expand All @@ -12,8 +13,8 @@ export interface RadioBlockProps
/** The name of the radio button set */
name: string;
/** The selected value of the radio button set */
selectedValue?: string | null;
/** Whether or not children are always visible */
selectedValue?: SelectedRadioValue;
/** Whether children are always visible */
showChildren?: boolean;
/** The value of the radio block */
value: string;
Expand Down
51 changes: 34 additions & 17 deletions packages/ffe-form-react/src/RadioButtonInputGroup.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useState } from 'react';
import type { StoryObj, Meta } from '@storybook/react';
import { RadioButtonInputGroup } from './RadioButtonInputGroup';
import { RadioButton } from './RadioButton';
Expand All @@ -21,8 +21,14 @@ export const Standard: Story = {
label: 'Hva er din favorittlukt?',
},
render: function Render(args) {
type Value = 'grass' | 'asphalt' | 'pollen';
const [selectedValue, setSelectedValue] = useState<Value>('asphalt');
return (
<RadioButtonInputGroup {...args}>
<RadioButtonInputGroup
{...args}
selectedValue={selectedValue}
onChange={e => setSelectedValue(e.target.value as Value)}
>
{inputProps => (
<>
<RadioButton {...inputProps} value="grass">
Expand All @@ -44,8 +50,14 @@ export const Standard: Story = {
export const FieldMessage: Story = {
args: { ...Standard.args, fieldMessage: 'Feil lukt', name: 'feil-lukt' },
render: function Render(args) {
type Value = 'grass' | 'asphalt' | 'pollen';
const [selectedValue, setSelectedValue] = useState<Value>('pollen');
return (
<RadioButtonInputGroup {...args}>
<RadioButtonInputGroup
{...args}
selectedValue={selectedValue}
onChange={e => setSelectedValue(e.target.value as Value)}
>
{inputProps => (
<>
<RadioButton {...inputProps} value="grass">
Expand All @@ -67,14 +79,20 @@ export const FieldMessage: Story = {
export const WithRadioSwitch: Story = {
args: { ...Standard.args, name: 'radio-switch' },
render: function Render(args) {
type Value = 'yes' | 'no';
const [selectedValue, setSelectedValue] = useState<Value>('yes');
return (
<RadioButtonInputGroup {...args}>
<RadioButtonInputGroup
{...args}
selectedValue={selectedValue}
onChange={e => setSelectedValue(e.target.value as Value)}
>
{inputProps => (
<RadioSwitch
leftLabel="Ja"
leftValue={true}
leftValue="yes"
rightLabel="Nei"
rightValue={false}
rightValue="no"
{...inputProps}
/>
)}
Expand All @@ -84,23 +102,22 @@ export const WithRadioSwitch: Story = {
};

export const WithRadioBlock: Story = {
args: { ...Standard.args, selectedValue: 'yes', name: 'radio-block' },
args: { ...Standard.args, name: 'radio-block' },
render: function Render(args) {
type Value = 'yes' | 'no';
const [selectedValue, setSelectedValue] = useState<Value>('yes');

return (
<RadioButtonInputGroup {...args}>
<RadioButtonInputGroup
{...args}
selectedValue={selectedValue}
onChange={e => setSelectedValue(e.target.value as Value)}
>
{inputProps => (
<>
<RadioBlock {...inputProps} label="Ja" value="yes" />
<RadioBlock
{...inputProps}
label="Ja"
value="yes"
// @ts-ignore
selectedValue={args.selectedValue}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Her har vi buggen også i dokumentasjonen

/>
<RadioBlock
{...inputProps}
// @ts-ignore
selectedValue={args.selectedValue}
label="Nei"
showChildren={true}
value="no"
Expand Down
5 changes: 3 additions & 2 deletions packages/ffe-form-react/src/RadioButtonInputGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useId } from 'react';
import classNames from 'classnames';
import { ErrorFieldMessage } from './message';
import { Tooltip } from './Tooltip';
import { SelectedRadioValue } from './types';

export interface RadioButtonInputGroupProps
extends Omit<
Expand All @@ -17,7 +18,7 @@ export interface RadioButtonInputGroupProps
inline?: boolean;
name: string;
onChange: React.ChangeEventHandler<HTMLInputElement>;
selectedValue?: boolean | string | number | null;
selectedValue?: SelectedRadioValue;
onColoredBg?: boolean;
}) => React.ReactNode;
/** Additional class names applied to the fieldset */
Expand Down Expand Up @@ -50,7 +51,7 @@ export interface RadioButtonInputGroupProps
/** Change handler, receives value of selected radio button */
onChange?: React.ChangeEventHandler<HTMLInputElement>;
/** The currently selected value */
selectedValue?: string | boolean | number | null;
selectedValue?: SelectedRadioValue;
/**
* String or Tooltip component with further detail about the radio button
* set
Expand Down
4 changes: 2 additions & 2 deletions packages/ffe-form-react/src/RadioSwitch.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { render, screen } from '@testing-library/react';

const defaultProps = {
leftLabel: 'Ja',
leftValue: true,
leftValue: 'ja',
name: 'choice',
rightLabel: 'Nei',
rightValue: 'nei',
Expand All @@ -17,7 +17,7 @@ describe('<RadioSwitch />', () => {
it('sets aria-invalid correctly', () => {
renderRadioSwitch({
'aria-invalid': 'true',
selectedValue: true,
selectedValue: 'ja',
});

const [radioLeft, radioRight] = screen.getAllByRole('radio');
Expand Down
10 changes: 4 additions & 6 deletions packages/ffe-form-react/src/RadioSwitch.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import React from 'react';
import classNames from 'classnames';

import { BaseRadioButton } from './BaseRadioButton';

type Value = boolean | string | number;
import { SelectedRadioValue } from './types';

export interface RadioSwitchProps
extends Omit<React.ComponentPropsWithoutRef<'input'>, 'value'> {
Expand All @@ -12,17 +10,17 @@ export interface RadioSwitchProps
/** The label of the choice to the left */
leftLabel: string;
/** The value of the choice to the left */
leftValue: Value /** Ref-setting function, or ref created by useRef, passed to the input element */;
leftValue: string /** Ref-setting function, or ref created by useRef, passed to the input element */;
/** Ref to left radio */
leftInnerRef?: React.Ref<HTMLInputElement>;
/** The label of the choice to the right */
rightLabel: string;
/** The value of the choice to the right */
rightValue: Value;
rightValue: string;
/** Ref to right radio */
rightInnerRef?: React.Ref<HTMLInputElement>;
/** The selected value of the radio button set */
selectedValue?: Value | null;
selectedValue?: SelectedRadioValue;
/** Condensed modifier. Use in condensed designs */
condensed?: boolean;
}
Expand Down
2 changes: 2 additions & 0 deletions packages/ffe-form-react/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@ export type ComponentWithRefAsPropParams<As extends ElementType> = {
>;

export type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;

export type SelectedRadioValue = string | null | undefined;
Loading