From 998bb1b382b43edd534c21af305ab799b6b06b11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?An=C3=ADbal=20Svarcas?= Date: Tue, 1 Jul 2025 23:45:22 -0300 Subject: [PATCH 01/12] Add disable support for RadioButtonGroupInput choices --- docs/RadioButtonGroupInput.md | 13 ++++++++++- .../input/RadioButtonGroupInput.stories.tsx | 22 +++++++++++++++++++ .../src/input/RadioButtonGroupInputItem.tsx | 4 +++- 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/docs/RadioButtonGroupInput.md b/docs/RadioButtonGroupInput.md index bf481c66868..36c649cf67d 100644 --- a/docs/RadioButtonGroupInput.md +++ b/docs/RadioButtonGroupInput.md @@ -94,6 +94,17 @@ const choices = [ /> ``` +You can render some options as disabled by setting the `disabled` field in some choices: + +```jsx +const choices = [ + { id: 'tech', name: 'Tech' }, + { id: 'lifestyle', name: 'Lifestyle' }, + { id: 'people', name: 'People', disabled: true }, +]; + +``` + The choices are translated by default, so you can use translation identifiers as choices: ```jsx @@ -390,4 +401,4 @@ const CompanyInput = () => ( This is the recommended approach for using `` to select a foreign key. This not only signifies that the input is a `` but also highlights its function in fetching choices from another resource, ultimately enhancing the code's readability. -**Tip**: `` is much more powerful than the initial snippet. It optimizes and caches API calls, enables refetching of both API calls with a single command, and stores supplementary data in the ``. `` can provide choices to ``, but also to [``](./AutocompleteInput.md) and [``](./SelectInput.md). For further information, refer to [the `` documentation](./ReferenceInput.md). \ No newline at end of file +**Tip**: `` is much more powerful than the initial snippet. It optimizes and caches API calls, enables refetching of both API calls with a single command, and stores supplementary data in the ``. `` can provide choices to ``, but also to [``](./AutocompleteInput.md) and [``](./SelectInput.md). For further information, refer to [the `` documentation](./ReferenceInput.md). diff --git a/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.stories.tsx b/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.stories.tsx index 09c483ce6fe..6e840914eff 100644 --- a/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.stories.tsx +++ b/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.stories.tsx @@ -278,6 +278,28 @@ export const TranslateChoice = () => { ); }; +export const DisabledChoice = () => ( + + + +); + export const Themed = () => ( } {...sanitizeInputRestProps(rest)} /> From 0ee3348f6405cfe61a2835a45a8ee520c9f3119d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?An=C3=ADbal=20Svarcas?= Date: Wed, 2 Jul 2025 08:43:20 -0300 Subject: [PATCH 02/12] Add test --- .../src/input/RadioButtonGroupInput.spec.tsx | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.spec.tsx b/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.spec.tsx index 408651685a0..bff1a0732a1 100644 --- a/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.spec.tsx +++ b/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.spec.tsx @@ -541,6 +541,35 @@ describe('', () => { expect(screen.queryByRole('progressbar')).toBeNull(); }); + it('should render disabled choices marked as so', () => { + const choices = [ + { id: 1, name: 'VISA' }, + { id: 2, name: 'Mastercard', disabled: true }, + ]; + render( + + + + + + + + ); + fireEvent.mouseDown( + screen.getByLabelText('resources.creditcards.fields.type') + ); + + expect( + screen.getByText('VISA').getAttribute('aria-disabled') + ).toBeNull(); + expect( + screen.getByText('Mastercard').getAttribute('aria-disabled') + ).toEqual('true'); + }); + describe('inside ReferenceArrayInput', () => { it('should use the recordRepresentation as optionText', async () => { render(); From 3d4aeed0ce23681b568c9b9c15fc6072dbb075f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?An=C3=ADbal=20Svarcas?= Date: Wed, 2 Jul 2025 08:51:26 -0300 Subject: [PATCH 03/12] fix test --- .../src/input/RadioButtonGroupInput.spec.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.spec.tsx b/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.spec.tsx index bff1a0732a1..c29d63ca800 100644 --- a/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.spec.tsx +++ b/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.spec.tsx @@ -559,15 +559,15 @@ describe('', () => { ); fireEvent.mouseDown( - screen.getByLabelText('resources.creditcards.fields.type') + screen.getByLabelText('Mastercard') ); expect( - screen.getByText('VISA').getAttribute('aria-disabled') - ).toBeNull(); + screen.getByText('VISA').getAttribute('class') + ).not.toContain('Mui-disabled'); expect( - screen.getByText('Mastercard').getAttribute('aria-disabled') - ).toEqual('true'); + screen.getByText('Mastercard').getAttribute('class') + ).toContain('Mui-disabled'); }); describe('inside ReferenceArrayInput', () => { From 79cd47c9171d93a34dfe90c342f5440912d61e4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?An=C3=ADbal=20Svarcas?= Date: Wed, 2 Jul 2025 09:01:47 -0300 Subject: [PATCH 04/12] fix prettier --- .../src/input/RadioButtonGroupInput.spec.tsx | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.spec.tsx b/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.spec.tsx index c29d63ca800..d3c8579983a 100644 --- a/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.spec.tsx +++ b/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.spec.tsx @@ -558,16 +558,14 @@ describe('', () => { ); - fireEvent.mouseDown( - screen.getByLabelText('Mastercard') - ); + fireEvent.mouseDown(screen.getByLabelText('Mastercard')); - expect( - screen.getByText('VISA').getAttribute('class') - ).not.toContain('Mui-disabled'); - expect( - screen.getByText('Mastercard').getAttribute('class') - ).toContain('Mui-disabled'); + expect(screen.getByText('VISA').getAttribute('class')).not.toContain( + 'Mui-disabled' + ); + expect(screen.getByText('Mastercard').getAttribute('class')).toContain( + 'Mui-disabled' + ); }); describe('inside ReferenceArrayInput', () => { From 67f7efcc3ce2438190800cb866dc0576cc334f1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?An=C3=ADbal=20Svarcas?= Date: Wed, 2 Jul 2025 09:12:01 -0300 Subject: [PATCH 05/12] fix test --- .../src/input/RadioButtonGroupInput.spec.tsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.spec.tsx b/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.spec.tsx index d3c8579983a..0bc9c397312 100644 --- a/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.spec.tsx +++ b/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.spec.tsx @@ -560,12 +560,13 @@ describe('', () => { ); fireEvent.mouseDown(screen.getByLabelText('Mastercard')); - expect(screen.getByText('VISA').getAttribute('class')).not.toContain( - 'Mui-disabled' - ); - expect(screen.getByText('Mastercard').getAttribute('class')).toContain( - 'Mui-disabled' - ); + const enabledInput = screen.getByLabelText('VISA') as HTMLInputElement; + expect(enabledInput.disabled).toBe(false); + + const disabledInput = screen.getByLabelText( + 'Mastercard' + ) as HTMLInputElement; + expect(disabledInput.disabled).toBe(true); }); describe('inside ReferenceArrayInput', () => { From 2c8cf3ea0b2bc69ecbcb7f1755260450f0e38aa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?An=C3=ADbal=20Svarcas?= Date: Wed, 2 Jul 2025 09:16:35 -0300 Subject: [PATCH 06/12] Improve docs --- docs/RadioButtonGroupInput.md | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/docs/RadioButtonGroupInput.md b/docs/RadioButtonGroupInput.md index 36c649cf67d..b67c6a16d4f 100644 --- a/docs/RadioButtonGroupInput.md +++ b/docs/RadioButtonGroupInput.md @@ -94,17 +94,6 @@ const choices = [ /> ``` -You can render some options as disabled by setting the `disabled` field in some choices: - -```jsx -const choices = [ - { id: 'tech', name: 'Tech' }, - { id: 'lifestyle', name: 'Lifestyle' }, - { id: 'people', name: 'People', disabled: true }, -]; - -``` - The choices are translated by default, so you can use translation identifiers as choices: ```jsx @@ -293,6 +282,19 @@ However, in some cases, you may not want the choice to be translated. In that ca Note that `translateChoice` is set to `false` when `` is a child of ``. +## Disabled `choices` + +You can render some options as disabled by setting the `disabled` field in some choices: + +```jsx +const choices = [ + { id: 'tech', name: 'Tech' }, + { id: 'lifestyle', name: 'Lifestyle' }, + { id: 'people', name: 'People', disabled: true }, +]; + +``` + ## Fetching Choices You can use [`useGetList`](./useGetList.md) to fetch choices. For example, to fetch a list of countries for a user profile: From 0baee4dcc8448e6f79ea3ed02fa8291cc92e6084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?An=C3=ADbal=20Svarcas?= Date: Wed, 2 Jul 2025 09:41:05 -0300 Subject: [PATCH 07/12] revert changes to the docs --- docs/RadioButtonGroupInput.md | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/docs/RadioButtonGroupInput.md b/docs/RadioButtonGroupInput.md index b67c6a16d4f..36c649cf67d 100644 --- a/docs/RadioButtonGroupInput.md +++ b/docs/RadioButtonGroupInput.md @@ -94,6 +94,17 @@ const choices = [ /> ``` +You can render some options as disabled by setting the `disabled` field in some choices: + +```jsx +const choices = [ + { id: 'tech', name: 'Tech' }, + { id: 'lifestyle', name: 'Lifestyle' }, + { id: 'people', name: 'People', disabled: true }, +]; + +``` + The choices are translated by default, so you can use translation identifiers as choices: ```jsx @@ -282,19 +293,6 @@ However, in some cases, you may not want the choice to be translated. In that ca Note that `translateChoice` is set to `false` when `` is a child of ``. -## Disabled `choices` - -You can render some options as disabled by setting the `disabled` field in some choices: - -```jsx -const choices = [ - { id: 'tech', name: 'Tech' }, - { id: 'lifestyle', name: 'Lifestyle' }, - { id: 'people', name: 'People', disabled: true }, -]; - -``` - ## Fetching Choices You can use [`useGetList`](./useGetList.md) to fetch choices. For example, to fetch a list of countries for a user profile: From d2cd51e962fcefeda09468d8fcabc629fef384dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?An=C3=ADbal=20Svarcas?= Date: Wed, 2 Jul 2025 11:03:04 -0300 Subject: [PATCH 08/12] Add disableValue prop --- docs/RadioButtonGroupInput.md | 25 +++++++++++++++++++ .../src/input/RadioButtonGroupInput.tsx | 20 +++++++++++++++ .../src/input/RadioButtonGroupInputItem.tsx | 3 +++ 3 files changed, 48 insertions(+) diff --git a/docs/RadioButtonGroupInput.md b/docs/RadioButtonGroupInput.md index 36c649cf67d..2aa91552c7c 100644 --- a/docs/RadioButtonGroupInput.md +++ b/docs/RadioButtonGroupInput.md @@ -62,6 +62,7 @@ The form value for the source must be the selected value, e.g. | `optionValue` | Optional | `string` | `id` | Field name of record containing the value to use as input value | | `row` | Optional | `boolean` | `true` | Display options in a compact row. | | `translateChoice` | Optional | `boolean` | `true` | Whether the choices should be translated | +| `disableValue` | Optional | `string` | `disabled` | The custom field name used in `choices` to disable some choices | `` also accepts the [common input props](./Inputs.md#common-input-props). @@ -293,6 +294,30 @@ However, in some cases, you may not want the choice to be translated. In that ca Note that `translateChoice` is set to `false` when `` is a child of ``. +## `disableValue` + +By default, `` renders the choices with the field `disabled: true` as disabled. + +```jsx +const choices = [ + { id: 'tech', name: 'Tech' }, + { id: 'lifestyle', name: 'Lifestyle' }, + { id: 'people', name: 'People', disabled: true }, +]; + +``` + +If you want to use another field to denote disabled options, set the `disableValue` prop. + +```jsx +const choices = [ + { id: 'tech', name: 'Tech' }, + { id: 'lifestyle', name: 'Lifestyle' }, + { id: 'people', name: 'People', not_available: true }, +]; + +``` + ## Fetching Choices You can use [`useGetList`](./useGetList.md) to fetch choices. For example, to fetch a list of countries for a user profile: diff --git a/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.tsx b/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.tsx index 55c91bc58a0..df89ef36f8d 100644 --- a/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.tsx +++ b/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.tsx @@ -88,6 +88,23 @@ import { LinearProgress } from '../layout'; * * * The object passed as `options` props is passed to the Material UI component + * + * You can disable some choices by providing a `disableValue` field which name is `disabled` by default + * @example + * const choices = [ + * { id: 123, first_name: 'Leo', last_name: 'Tolstoi' }, + * { id: 456, first_name: 'Jane', last_name: 'Austen' }, + * { id: 976, first_name: 'William', last_name: 'Rinkerd', disabled: true }, + * ]; + * + * @example + * const choices = [ + * { id: 123, first_name: 'Leo', last_name: 'Tolstoi' }, + * { id: 456, first_name: 'Jane', last_name: 'Austen' }, + * { id: 976, first_name: 'William', last_name: 'Rinkerd', not_available: true }, + * ]; + * + * */ export const RadioButtonGroupInput = (inProps: RadioButtonGroupInputProps) => { const props = useThemeProps({ @@ -115,6 +132,7 @@ export const RadioButtonGroupInput = (inProps: RadioButtonGroupInputProps) => { source: sourceProp, translateChoice, validate, + disableValue = 'disabled', disabled, readOnly, ...rest @@ -222,6 +240,7 @@ export const RadioButtonGroupInput = (inProps: RadioButtonGroupInputProps) => { optionValue={optionValue} source={id} translateChoice={translateChoice ?? !isFromReference} + disableValue={disableValue} /> ))} @@ -277,6 +296,7 @@ export type RadioButtonGroupInputProps = Omit & RadioGroupProps & { options?: RadioGroupProps; source?: string; + disableValue?: string; }; const PREFIX = 'RaRadioButtonGroupInput'; diff --git a/packages/ra-ui-materialui/src/input/RadioButtonGroupInputItem.tsx b/packages/ra-ui-materialui/src/input/RadioButtonGroupInputItem.tsx index dc66efaa2c2..feae63e6faf 100644 --- a/packages/ra-ui-materialui/src/input/RadioButtonGroupInputItem.tsx +++ b/packages/ra-ui-materialui/src/input/RadioButtonGroupInputItem.tsx @@ -19,6 +19,7 @@ export const RadioButtonGroupInputItem = ( optionValue, source, translateChoice, + disableValue = 'disabled', ...rest } = useThemeProps({ props: props, @@ -29,6 +30,7 @@ export const RadioButtonGroupInputItem = ( optionText, optionValue, translateChoice, + disableValue, }); const label = getChoiceText(choice); const value = getChoiceValue(choice); @@ -55,6 +57,7 @@ export interface RadioButtonGroupInputItemProps Pick { choice: any; source: any; + disableValue?: string; } const PREFIX = 'RaRadioButtonGroupInputItem'; From 776c0ab8cf6592928da73d9e9d96479e938f8c2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?An=C3=ADbal=20Svarcas?= Date: Wed, 2 Jul 2025 11:07:27 -0300 Subject: [PATCH 09/12] Add test --- .../src/input/RadioButtonGroupInput.spec.tsx | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.spec.tsx b/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.spec.tsx index 0bc9c397312..a45e87e712b 100644 --- a/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.spec.tsx +++ b/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.spec.tsx @@ -569,6 +569,35 @@ describe('', () => { expect(disabledInput.disabled).toBe(true); }); + it('should render disabled choices marked as so by disableValue prop', () => { + const choices = [ + { id: 1, name: 'VISA' }, + { id: 2, name: 'Mastercard', not_available: true }, + ]; + render( + + + + + + + + ); + fireEvent.mouseDown(screen.getByLabelText('Mastercard')); + + const enabledInput = screen.getByLabelText('VISA') as HTMLInputElement; + expect(enabledInput.disabled).toBe(false); + + const disabledInput = screen.getByLabelText( + 'Mastercard' + ) as HTMLInputElement; + expect(disabledInput.disabled).toBe(true); + }); + describe('inside ReferenceArrayInput', () => { it('should use the recordRepresentation as optionText', async () => { render(); From 2882c0124a3f55356fe10aaff3ca70a35a3cb36c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?An=C3=ADbal=20Svarcas?= Date: Wed, 2 Jul 2025 12:53:08 -0300 Subject: [PATCH 10/12] Add disableValue to type ChoicesProps and refactor componentes using ChoicesProps --- packages/ra-core/src/form/choices/useChoices.tsx | 1 + packages/ra-ui-materialui/src/field/SelectField.tsx | 2 +- packages/ra-ui-materialui/src/input/AutocompleteInput.tsx | 2 +- packages/ra-ui-materialui/src/input/DatagridInput.tsx | 2 +- .../ra-ui-materialui/src/input/RadioButtonGroupInput.tsx | 1 - .../src/input/RadioButtonGroupInputItem.tsx | 6 ++++-- packages/ra-ui-materialui/src/input/SelectArrayInput.tsx | 1 - packages/ra-ui-materialui/src/input/SelectInput.tsx | 1 - 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/ra-core/src/form/choices/useChoices.tsx b/packages/ra-core/src/form/choices/useChoices.tsx index 6030453259c..c1ce1a0709f 100644 --- a/packages/ra-core/src/form/choices/useChoices.tsx +++ b/packages/ra-core/src/form/choices/useChoices.tsx @@ -20,6 +20,7 @@ export interface ChoicesProps { optionValue?: string; optionText?: OptionText; translateChoice?: boolean; + disableValue?: string; } export interface UseChoicesOptions { diff --git a/packages/ra-ui-materialui/src/field/SelectField.tsx b/packages/ra-ui-materialui/src/field/SelectField.tsx index eadec98b270..f31b2ce255a 100644 --- a/packages/ra-ui-materialui/src/field/SelectField.tsx +++ b/packages/ra-ui-materialui/src/field/SelectField.tsx @@ -138,7 +138,7 @@ export const SelectField = genericMemo(SelectFieldImpl); export interface SelectFieldProps< RecordType extends Record = Record, -> extends ChoicesProps, +> extends Omit, FieldProps, Omit {} diff --git a/packages/ra-ui-materialui/src/input/AutocompleteInput.tsx b/packages/ra-ui-materialui/src/input/AutocompleteInput.tsx index 425041913f4..553036e0826 100644 --- a/packages/ra-ui-materialui/src/input/AutocompleteInput.tsx +++ b/packages/ra-ui-materialui/src/input/AutocompleteInput.tsx @@ -780,7 +780,7 @@ export interface AutocompleteInputProps< DisableClearable extends boolean | undefined = false, SupportCreate extends boolean | undefined = false, > extends Omit, - ChoicesProps, + Omit, UseSuggestionsOptions, Omit, Omit< diff --git a/packages/ra-ui-materialui/src/input/DatagridInput.tsx b/packages/ra-ui-materialui/src/input/DatagridInput.tsx index b649fce16f1..6dc405afcc3 100644 --- a/packages/ra-ui-materialui/src/input/DatagridInput.tsx +++ b/packages/ra-ui-materialui/src/input/DatagridInput.tsx @@ -177,7 +177,7 @@ export type DatagridInputProps = Omit< CommonInputProps, 'source' | 'readOnly' | 'disabled' > & - ChoicesProps & + Omit & Omit & DatagridProps & { children?: ReactNode; diff --git a/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.tsx b/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.tsx index df89ef36f8d..d94a9662c5b 100644 --- a/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.tsx +++ b/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.tsx @@ -296,7 +296,6 @@ export type RadioButtonGroupInputProps = Omit & RadioGroupProps & { options?: RadioGroupProps; source?: string; - disableValue?: string; }; const PREFIX = 'RaRadioButtonGroupInput'; diff --git a/packages/ra-ui-materialui/src/input/RadioButtonGroupInputItem.tsx b/packages/ra-ui-materialui/src/input/RadioButtonGroupInputItem.tsx index feae63e6faf..466cf09a29a 100644 --- a/packages/ra-ui-materialui/src/input/RadioButtonGroupInputItem.tsx +++ b/packages/ra-ui-materialui/src/input/RadioButtonGroupInputItem.tsx @@ -54,10 +54,12 @@ export default RadioButtonGroupInputItem; export interface RadioButtonGroupInputItemProps extends Omit, - Pick { + Pick< + ChoicesProps, + 'optionValue' | 'optionText' | 'translateChoice' | 'disableValue' + > { choice: any; source: any; - disableValue?: string; } const PREFIX = 'RaRadioButtonGroupInputItem'; diff --git a/packages/ra-ui-materialui/src/input/SelectArrayInput.tsx b/packages/ra-ui-materialui/src/input/SelectArrayInput.tsx index 5d91cee2e3e..1ae1b76aa6c 100644 --- a/packages/ra-ui-materialui/src/input/SelectArrayInput.tsx +++ b/packages/ra-ui-materialui/src/input/SelectArrayInput.tsx @@ -380,7 +380,6 @@ export type SelectArrayInputProps = ChoicesProps & Omit & Omit & { options?: SelectProps; - disableValue?: string; source?: string; onChange?: (event: ChangeEvent | RaRecord) => void; }; diff --git a/packages/ra-ui-materialui/src/input/SelectInput.tsx b/packages/ra-ui-materialui/src/input/SelectInput.tsx index 6b3af86b6f1..6cf53f2d252 100644 --- a/packages/ra-ui-materialui/src/input/SelectInput.tsx +++ b/packages/ra-ui-materialui/src/input/SelectInput.tsx @@ -415,7 +415,6 @@ export type SelectInputProps = Omit & ChoicesProps & Omit & Omit & { - disableValue?: string; emptyText?: string | ReactElement; emptyValue?: any; resettable?: boolean; From a7c15445d140e1bd2484fe83c8309ba2a6a8fecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?An=C3=ADbal=20Svarcas?= Date: Wed, 2 Jul 2025 12:53:44 -0300 Subject: [PATCH 11/12] Add disableValue prop to CheckboxGroupInput --- docs/CheckboxGroupInput.md | 36 +++++++++++ .../src/input/CheckboxGroupInput.spec.tsx | 61 +++++++++++++++++++ .../src/input/CheckboxGroupInput.stories.tsx | 14 +++++ .../src/input/CheckboxGroupInput.tsx | 19 ++++++ .../src/input/CheckboxGroupInputItem.tsx | 11 +++- 5 files changed, 139 insertions(+), 2 deletions(-) diff --git a/docs/CheckboxGroupInput.md b/docs/CheckboxGroupInput.md index 347ffbca35d..fe9ae8d92a3 100644 --- a/docs/CheckboxGroupInput.md +++ b/docs/CheckboxGroupInput.md @@ -65,6 +65,7 @@ The form value for the source must be an array of the selected values, e.g. | `optionValue` | Optional | `string` | `id` | Field name of record containing the value to use as input value | | `row` | Optional | `boolean` | `true` | Display group of elements in a compact row. | | `translateChoice` | Optional | `boolean` | `true` | Whether the choices should be translated | +| `disableValue` | Optional | `string` | `disabled` | The custom field name used in `choices` to disable some choices | `` also accepts the [common input props](./Inputs.md#common-input-props). @@ -92,6 +93,17 @@ You can also use an array of objects with different properties for the label and ]} optionValue="_id" optionText="label" /> ``` +You can render some options as disabled by setting the `disabled` field in some choices: + +```jsx +const choices = [ + { id: 'tech', name: 'Tech' }, + { id: 'lifestyle', name: 'Lifestyle' }, + { id: 'people', name: 'People', disabled: true }, +]; + +``` + The choices are translated by default, so you can use translation identifiers as choices: ```jsx @@ -255,6 +267,30 @@ However, in some cases (e.g. inside a ``), you may not want ``` +## `disableValue` + +By default, `` renders the choices with the field `disabled: true` as disabled. + +```jsx +const choices = [ + { id: 'tech', name: 'Tech' }, + { id: 'lifestyle', name: 'Lifestyle' }, + { id: 'people', name: 'People', disabled: true }, +]; + +``` + +If you want to use another field to denote disabled options, set the `disableValue` prop. + +```jsx +const choices = [ + { id: 'tech', name: 'Tech' }, + { id: 'lifestyle', name: 'Lifestyle' }, + { id: 'people', name: 'People', not_available: true }, +]; + +``` + ## Fetching Choices If you want to populate the `choices` attribute with a list of related records, you should decorate `` with [``](./ReferenceArrayInput.md), and leave the `choices` empty: diff --git a/packages/ra-ui-materialui/src/input/CheckboxGroupInput.spec.tsx b/packages/ra-ui-materialui/src/input/CheckboxGroupInput.spec.tsx index c2e76bda554..4da4cb753c7 100644 --- a/packages/ra-ui-materialui/src/input/CheckboxGroupInput.spec.tsx +++ b/packages/ra-ui-materialui/src/input/CheckboxGroupInput.spec.tsx @@ -426,4 +426,65 @@ describe('', () => { await screen.findByText('Option 1 (This is option 1)'); }); }); + + it('should render disabled choices marked as so', () => { + const choices = [ + { id: 'ang', name: 'Angular' }, + { id: 'rct', name: 'React', disabled: true }, + ]; + render( + + + + + + + + ); + fireEvent.mouseDown(screen.getByLabelText('React')); + + const enabledInput = screen.getByLabelText( + 'Angular' + ) as HTMLInputElement; + expect(enabledInput.disabled).toBe(false); + + const disabledInput = screen.getByLabelText( + 'React' + ) as HTMLInputElement; + expect(disabledInput.disabled).toBe(true); + }); + + it('should render disabled choices marked as so by disableValue prop', () => { + const choices = [ + { id: 'ang', name: 'Angular' }, + { id: 'rct', name: 'React', not_available: true }, + ]; + render( + + + + + + + + ); + fireEvent.mouseDown(screen.getByLabelText('React')); + + const enabledInput = screen.getByLabelText( + 'Angular' + ) as HTMLInputElement; + expect(enabledInput.disabled).toBe(false); + + const disabledInput = screen.getByLabelText( + 'React' + ) as HTMLInputElement; + expect(disabledInput.disabled).toBe(true); + }); }); diff --git a/packages/ra-ui-materialui/src/input/CheckboxGroupInput.stories.tsx b/packages/ra-ui-materialui/src/input/CheckboxGroupInput.stories.tsx index 166ce64ea55..aea963071da 100644 --- a/packages/ra-ui-materialui/src/input/CheckboxGroupInput.stories.tsx +++ b/packages/ra-ui-materialui/src/input/CheckboxGroupInput.stories.tsx @@ -322,3 +322,17 @@ export const SetFocus = () => ( ); + +export const DisabledChoice = () => ( + + + +); diff --git a/packages/ra-ui-materialui/src/input/CheckboxGroupInput.tsx b/packages/ra-ui-materialui/src/input/CheckboxGroupInput.tsx index 35fd11b9167..b1a155c85f7 100644 --- a/packages/ra-ui-materialui/src/input/CheckboxGroupInput.tsx +++ b/packages/ra-ui-materialui/src/input/CheckboxGroupInput.tsx @@ -95,6 +95,23 @@ import { LinearProgress } from '../layout'; * * * The object passed as `options` props is passed to the Material UI components + * + * You can disable some choices by providing a `disableValue` field which name is `disabled` by default + * @example + * const choices = [ + * { id: 'programming', name: 'myroot.category.programming' }, + * { id: 'lifestyle', name: 'myroot.category.lifestyle' }, + * { id: 'photography', name: 'myroot.category.photography', disabled: true }, + * ]; + * + * @example + * const choices = [ + * { id: 'programming', name: 'myroot.category.programming' }, + * { id: 'lifestyle', name: 'myroot.category.lifestyle' }, + * { id: 'photography', name: 'myroot.category.photography', not_available: true }, + * ]; + * + * */ export const CheckboxGroupInput = (inProps: CheckboxGroupInputProps) => { const props = useThemeProps({ @@ -124,6 +141,7 @@ export const CheckboxGroupInput = (inProps: CheckboxGroupInputProps) => { source: sourceProp, translateChoice, validate, + disableValue = 'disabled', disabled, readOnly, ...rest @@ -262,6 +280,7 @@ export const CheckboxGroupInput = (inProps: CheckboxGroupInputProps) => { value={value} labelPlacement={labelPlacement} inputRef={index === 0 ? ref : undefined} + disableValue={disableValue} disabled={disabled || readOnly} readOnly={readOnly} {...sanitizeRestProps(rest)} diff --git a/packages/ra-ui-materialui/src/input/CheckboxGroupInputItem.tsx b/packages/ra-ui-materialui/src/input/CheckboxGroupInputItem.tsx index 4e82fee8907..fe034408fe0 100644 --- a/packages/ra-ui-materialui/src/input/CheckboxGroupInputItem.tsx +++ b/packages/ra-ui-materialui/src/input/CheckboxGroupInputItem.tsx @@ -32,16 +32,19 @@ export const CheckboxGroupInputItem = ( value, labelPlacement, inputRef, + disableValue = 'disabled', ...rest } = props; - const { getChoiceText, getChoiceValue } = useChoices({ + const { getChoiceText, getChoiceValue, getDisableValue } = useChoices({ optionText, optionValue, translateChoice, + disableValue, }); const choiceName = getChoiceText(choice); + const disabled = getDisableValue(choice); return ( , - Pick { + Pick< + ChoicesProps, + 'optionValue' | 'optionText' | 'translateChoice' | 'disableValue' + > { choice: any; value: any; fullWidth?: boolean; From a0904e30e96aa862a93d075e075f2f670fcb4452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?An=C3=ADbal=20Svarcas?= Date: Wed, 2 Jul 2025 13:30:27 -0300 Subject: [PATCH 12/12] fix tests --- packages/ra-ui-materialui/src/input/CheckboxGroupInputItem.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ra-ui-materialui/src/input/CheckboxGroupInputItem.tsx b/packages/ra-ui-materialui/src/input/CheckboxGroupInputItem.tsx index fe034408fe0..eeeb4173d88 100644 --- a/packages/ra-ui-materialui/src/input/CheckboxGroupInputItem.tsx +++ b/packages/ra-ui-materialui/src/input/CheckboxGroupInputItem.tsx @@ -53,7 +53,6 @@ export const CheckboxGroupInputItem = ( onChange={onChange} className={className} inputRef={inputRef} - disabled={disabled} control={ }