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: enable to always display detail value #1187

Merged
merged 5 commits into from
Dec 10, 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
4 changes: 3 additions & 1 deletion docs/docs/hook/parameters.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ Toutes les options sont **optionnelles**.
- **missingShortcut** raccourcis clavier déclanchant les boutons missing (défaut `{ dontKnow: '', refused: '' }`)
- **dontKnowButton** label du bouton "Ne sait pas" (défaut `{ fr: 'Ne sais pas', en: "Don't know" }`)
- **refusedButton** label du bouton "Refus" (défaut `{ fr: 'Refus', en: 'Refused' }`)
- **trackChanges**, active le [suivi des changements](#trackChanges) (défaut `false`)
- **trackChanges**, active le [suivi des changements](#trackChanges) (défaut `false`),
- **componentsOptions** permet de définir des options sur le fonctionnement des composants. Toutes les options sont optionnelles (défaut objet contenant la valeur par défaut de chaque paramètre)
- **detailAlwaysDisplayed** permet d'afficher par défaut les modalités 'detail' associées aux modalités de réponse

### Vue d'ensemble {#vue-densemble}

Expand Down
2 changes: 1 addition & 1 deletion e2e/checkbox.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ test.describe('Checkboxes', () => {
});

test('Can select arbitrary value', async ({ page }) => {
await goToStory(page, 'components-checkboxgroup--arbitrary');
await goToStory(page, 'components-checkboxgroup--with-detail');
const selector = page.getByRole('checkbox', { name: 'Autre préciser' });
await expect(selector).toBeVisible();
await selector.click();
Expand Down
3 changes: 3 additions & 0 deletions src/components/CheckboxGroup/CheckboxGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { LunaticComponentProps } from '../type';
import { CustomCheckboxGroup } from './CustomCheckboxGroup';
import { getComponentErrors } from '../shared/ComponentErrors/ComponentErrors';
import { useLunaticComponentsOptions } from '../../use-lunatic/lunatic-context';

export function CheckboxGroup({
id,
Expand All @@ -14,6 +15,7 @@ export function CheckboxGroup({
declarations,
orientation,
}: LunaticComponentProps<'CheckboxGroup'>) {
const { detailAlwaysDisplayed } = useLunaticComponentsOptions();
return (
<CustomCheckboxGroup
id={id}
Expand All @@ -26,6 +28,7 @@ export function CheckboxGroup({
readOnly={readOnly}
declarations={declarations}
orientation={orientation}
detailAlwaysDisplayed={detailAlwaysDisplayed}
/>
);
}
17 changes: 3 additions & 14 deletions src/components/CheckboxGroup/CustomCheckboxGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { CheckboxOption } from '../shared/Checkbox/CheckboxOption';
import { getShortcutKey } from '../shared/Checkbox/getShortcutKey';
import type { LunaticComponentProps } from '../type';
import { Declarations } from '../shared/Declarations/Declarations';
import { CustomInput } from '../Input/Input';

type Props = Pick<
LunaticComponentProps<'CheckboxGroup'>,
Expand All @@ -19,6 +18,7 @@ type Props = Pick<
| 'disabled'
| 'options'
| 'orientation'
| 'detailAlwaysDisplayed'
> & {
errors?: LunaticError[];
};
Expand All @@ -35,6 +35,7 @@ export const CustomCheckboxGroup = slottableComponent<Props>(
readOnly,
declarations,
orientation,
detailAlwaysDisplayed,
}: Props) => {
return (
<Fieldset
Expand All @@ -59,20 +60,8 @@ export const CustomCheckboxGroup = slottableComponent<Props>(
codeModality={
shortcut ? getShortcutKey(index, options.length) : undefined
}
detailAlwaysDisplayed={detailAlwaysDisplayed}
/>
{option.onDetailChange && option.checked && (
<CustomInput
id="detailId"
label={option.detailLabel ?? 'Précisez :'}
value={
typeof option.detailValue === 'string'
? option.detailValue
: ''
}
onChange={option.onDetailChange}
disabled={disabled}
/>
)}
</div>
);
})}
Expand Down
3 changes: 3 additions & 0 deletions src/components/CheckboxOne/CheckboxOne.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { RadioGroup } from '../shared/Radio/RadioGroup';
import type { LunaticComponentProps } from '../type';
import { getComponentErrors } from '../shared/ComponentErrors/ComponentErrors';
import { useLunaticComponentsOptions } from '../../use-lunatic/lunatic-context';

/**
* Checkbox acting as a radio (only one option can be checked at a time)
Expand All @@ -18,6 +19,7 @@ export function CheckboxOne({
declarations,
orientation,
}: LunaticComponentProps<'CheckboxOne'>) {
const { detailAlwaysDisplayed } = useLunaticComponentsOptions();
return (
<RadioGroup
id={id}
Expand All @@ -33,6 +35,7 @@ export function CheckboxOne({
shortcut={shortcut}
declarations={declarations}
orientation={orientation ?? 'vertical'}
detailAlwaysDisplayed={detailAlwaysDisplayed}
clearable
/>
);
Expand Down
3 changes: 3 additions & 0 deletions src/components/Radio/Radio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { LunaticComponentProps } from '../type';
import { getComponentErrors } from '../shared/ComponentErrors/ComponentErrors';
import { RadioGroup } from '../shared/Radio/RadioGroup';
import { slottableComponent } from '../shared/HOC/slottableComponent';
import { useLunaticComponentsOptions } from '../../use-lunatic/lunatic-context';

function LunaticRadio(props: LunaticComponentProps<'Radio'>) {
const {
Expand All @@ -19,6 +20,7 @@ function LunaticRadio(props: LunaticComponentProps<'Radio'>) {
declarations,
orientation,
} = props;
const { detailAlwaysDisplayed } = useLunaticComponentsOptions();
return (
<RadioGroup
id={id}
Expand All @@ -34,6 +36,7 @@ function LunaticRadio(props: LunaticComponentProps<'Radio'>) {
readOnly={readOnly}
declarations={declarations}
orientation={orientation ?? 'vertical'}
detailAlwaysDisplayed={detailAlwaysDisplayed}
/>
);
}
Expand Down
21 changes: 21 additions & 0 deletions src/components/shared/Checkbox/CheckboxOption.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ describe('CheckboxOption', () => {
id: 'test-checkbox',
onCheck: vi.fn(),
label: 'Test checkbox',
detailLabel: 'My detail',
onDetailChange: () => {},
};

it('renders the component correctly', () => {
Expand Down Expand Up @@ -55,4 +57,23 @@ describe('CheckboxOption', () => {
fireEvent.keyDown(checkbox, { code: 'Space' });
expect(defaultProps.onCheck).toHaveBeenCalledWith(true);
});

it('renders the detail when checked', () => {
const { getByText } = render(
<CheckboxOption {...defaultProps} checked={true} />
);
expect(getByText(defaultProps.detailLabel)).toBeInTheDocument();
});
it('does not render the detail when unchecked', () => {
const { queryByText } = render(
<CheckboxOption {...defaultProps} checked={false} />
);
expect(queryByText(defaultProps.detailLabel)).toBeNull();
});
it('renders the details when unchecked with the detail always displayed attribute', () => {
const { getByText } = render(
<CheckboxOption {...defaultProps} checked={false} detailAlwaysDisplayed />
);
expect(getByText(defaultProps.detailLabel)).toBeInTheDocument();
});
});
19 changes: 19 additions & 0 deletions src/components/shared/Checkbox/CheckboxOption.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { LunaticBaseProps } from '../../type';
import { slottableComponent } from '../HOC/slottableComponent';
import { Label } from '../Label/Label';
import { useKeyboardKey } from '../../../hooks/useKeyboardKey';
import { CustomInput } from '../../Input/Input';

export type CheckboxOptionProps = {
disabled?: boolean;
Expand All @@ -15,6 +16,10 @@ export type CheckboxOptionProps = {
codeModality?: string;
shortcut?: boolean;
invalid?: boolean;
detailAlwaysDisplayed?: boolean;
detailLabel?: ReactNode;
detailValue?: string | null;
onDetailChange?: (value: string) => void;
};

function LunaticCheckboxOption({
Expand All @@ -25,11 +30,16 @@ function LunaticCheckboxOption({
onCheck,
label,
description,
detailAlwaysDisplayed,
detailLabel,
detailValue,
onDetailChange,
codeModality,
shortcut,
invalid,
}: CheckboxOptionProps) {
const isEnabled = !readOnly && !disabled;
const hasDetail = !!onDetailChange;
const hasKeyboardShortcut = Boolean(shortcut && codeModality && isEnabled);
const onClickOption = () => {
if (isEnabled) {
Expand Down Expand Up @@ -88,6 +98,15 @@ function LunaticCheckboxOption({
)}{' '}
{label}
</Label>
{hasDetail && (checked || detailAlwaysDisplayed) && (
<CustomInput
id="detailId"
label={detailLabel ?? 'Précisez :'}
value={typeof detailValue === 'string' ? detailValue : ''}
onChange={onDetailChange}
disabled={disabled}
/>
)}
</div>
);
}
Expand Down
3 changes: 3 additions & 0 deletions src/components/shared/Radio/RadioGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export type RadioGroupProps = Pick<
| 'description'
| 'declarations'
| 'orientation'
| 'detailAlwaysDisplayed'
> & {
errors?: LunaticError[];
clearable?: boolean;
Expand All @@ -44,6 +45,7 @@ function LunaticRadioGroup({
readOnly,
declarations,
orientation,
detailAlwaysDisplayed,
}: RadioGroupProps) {
const onKeyDown = useListKeyboardHandler(options);
const maxIndex = options.length;
Expand All @@ -61,6 +63,7 @@ function LunaticRadioGroup({
id={radioId}
index={index}
checked={value === option.value}
detailAlwaysDisplayed={detailAlwaysDisplayed}
onKeyDown={onKeyDown}
checkboxStyle={checkboxStyle}
codeModality={shortcut ? codeModality : undefined}
Expand Down
36 changes: 36 additions & 0 deletions src/components/shared/Radio/RadioOption.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,40 @@ describe('RadioOption', () => {
fireEvent.keyDown(option, { key: 'Enter', code: 'Enter' });
expect(onKeyDownMock).toHaveBeenCalled();
});

it('renders the detail when checked', () => {
const { getByText } = render(
<RadioOption
id="radio-option"
label="Test Option"
onDetailChange={() => {}}
detailLabel="My detail"
checked
/>
);
expect(getByText('My detail')).toBeInTheDocument();
});
it('does not render the detail when unchecked', () => {
const { queryByText } = render(
<RadioOption
id="radio-option"
label="Test Option"
onDetailChange={() => {}}
detailLabel="My detail"
/>
);
expect(queryByText('My detail')).toBeNull();
});
it('renders the details when unchecked with the detail always displayed attribute', () => {
const { getByText } = render(
<RadioOption
id="radio-option"
label="Test Option"
onDetailChange={() => {}}
detailLabel="My detail"
detailAlwaysDisplayed
/>
);
expect(getByText('My detail')).toBeInTheDocument();
});
});
6 changes: 5 additions & 1 deletion src/components/shared/Radio/RadioOption.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export type Props = {
labelledBy?: string;
codeModality?: string;
invalid?: boolean;
detailAlwaysDisplayed?: boolean;
} & InterpretedOption;

function LunaticRadioOption({
Expand All @@ -30,10 +31,12 @@ function LunaticRadioOption({
shortcut,
codeModality,
id,
invalid,
labelledBy,
description,
label,
onDetailChange,
detailAlwaysDisplayed,
detailLabel,
detailValue,
onCheck,
Expand Down Expand Up @@ -80,6 +83,7 @@ function LunaticRadioOption({
<div
id={id}
role="radio"
aria-invalid={invalid}
aria-disabled={disabled}
className={classnames(
'lunatic-input-checkbox',
Expand Down Expand Up @@ -113,7 +117,7 @@ function LunaticRadioOption({
{label}
</Label>
</div>
{hasDetail && checked && (
{hasDetail && (checked || detailAlwaysDisplayed) && (
<CustomInput
id="detailId"
label={detailLabel ?? 'Précisez :'}
Expand Down
3 changes: 3 additions & 0 deletions src/components/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,13 +191,15 @@ export type ComponentPropsByType = {
detailLabel?: ReactNode;
}[];
orientation?: 'horizontal' | 'vertical';
detailAlwaysDisplayed?: boolean;
componentType?: 'CheckboxGroup';
};
CheckboxOne: LunaticBaseProps<string | null> &
LunaticExtraProps & {
options: Array<InterpretedOption>;
componentType?: 'CheckboxOne';
orientation?: 'horizontal' | 'vertical';
detailAlwaysDisplayed?: boolean;
};
Switch: LunaticBaseProps<boolean> &
LunaticExtraProps & {
Expand All @@ -217,6 +219,7 @@ export type ComponentPropsByType = {
response: { name: string };
componentType?: 'Radio';
orientation?: 'horizontal' | 'vertical';
detailAlwaysDisplayed?: boolean;
};
Roundabout: LunaticBaseProps<string> &
LunaticExtraProps & {
Expand Down
9 changes: 9 additions & 0 deletions src/stories/behaviour/missing/missing.stories.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,20 @@ const stories = {
component: Orchestrator,
argTypes: {
...defaultArgTypes,
shortcut: {
table: { disable: false },
control: 'boolean',
defaultValue: true,
},
missing: {
table: { disable: false },
control: 'boolean',
defaultValue: true,
},
missingStrategy: {
table: { disable: false },
control: 'object',
},
activeGoNextForMissing: {
table: { disable: false },
control: 'boolean',
Expand Down
Loading
Loading