diff --git a/packages/dataviews/CHANGELOG.md b/packages/dataviews/CHANGELOG.md index 8bccc2d10e3137..03cda1e18ec278 100644 --- a/packages/dataviews/CHANGELOG.md +++ b/packages/dataviews/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Enhancements + +- DataForm: support `isDisabled` field property. [#77090](https://github.com/WordPress/gutenberg/pull/77090) + ## 14.0.0 (2026-04-01) ### Breaking Changes diff --git a/packages/dataviews/src/components/dataform-controls/array.tsx b/packages/dataviews/src/components/dataform-controls/array.tsx index e122f3cfa577d1..56381786b5d1fb 100644 --- a/packages/dataviews/src/components/dataform-controls/array.tsx +++ b/packages/dataviews/src/components/dataform-controls/array.tsx @@ -24,6 +24,7 @@ export default function ArrayControl< Item >( { }: DataFormControlProps< Item > ) { const { label, placeholder, getValue, setValue, isValid } = field; const value = getValue( { item: data } ); + const disabled = field.isDisabled( { item: data, field } ); const { elements, isLoading } = useElements( { elements: field.elements, @@ -73,6 +74,7 @@ export default function ArrayControl< Item >( { onChange={ onChangeControl } placeholder={ placeholder } suggestions={ elements?.map( ( element ) => element.value ) } + disabled={ disabled } __experimentalValidateInput={ ( token: string ) => { // If elements validation is required, check if token is valid if ( field.isValid?.elements && elements ) { diff --git a/packages/dataviews/src/components/dataform-controls/checkbox.tsx b/packages/dataviews/src/components/dataform-controls/checkbox.tsx index 9e2637675969dc..34c460d90d9140 100644 --- a/packages/dataviews/src/components/dataform-controls/checkbox.tsx +++ b/packages/dataviews/src/components/dataform-controls/checkbox.tsx @@ -22,6 +22,7 @@ export default function Checkbox< Item >( { validity, }: DataFormControlProps< Item > ) { const { getValue, setValue, label, description, isValid } = field; + const disabled = field.isDisabled( { item: data, field } ); const onChangeControl = useCallback( () => { onChange( @@ -39,6 +40,7 @@ export default function Checkbox< Item >( { help={ description } checked={ getValue( { item: data } ) } onChange={ onChangeControl } + disabled={ disabled } /> ); } diff --git a/packages/dataviews/src/components/dataform-controls/color.tsx b/packages/dataviews/src/components/dataform-controls/color.tsx index e236bc78750427..8d4409bea74e84 100644 --- a/packages/dataviews/src/components/dataform-controls/color.tsx +++ b/packages/dataviews/src/components/dataform-controls/color.tsx @@ -30,9 +30,11 @@ const { ValidatedInputControl } = unlock( privateApis ); const ColorPickerDropdown = ( { color, onColorChange, + disabled, }: { color: string; onColorChange: ( newColor: string ) => void; + disabled?: boolean; } ) => { const validColor = color && colord( color ).isValid() ? color : '#ffffff'; @@ -45,6 +47,8 @@ const ColorPickerDropdown = ( { onClick={ onToggle } aria-label={ __( 'Open color picker' ) } size="small" + disabled={ disabled } + accessibleWhenDisabled icon={ () => } /> ) } @@ -70,6 +74,7 @@ export default function Color< Item >( { validity, }: DataFormControlProps< Item > ) { const { label, placeholder, description, setValue, isValid } = field; + const disabled = field.isDisabled( { item: data, field } ); const value = field.getValue( { item: data } ) || ''; const handleColorChange = useCallback( @@ -98,11 +103,13 @@ export default function Color< Item >( { onChange={ handleInputChange } hideLabelFromVision={ hideLabelFromVision } type="text" + disabled={ disabled } prefix={ } diff --git a/packages/dataviews/src/components/dataform-controls/date.tsx b/packages/dataviews/src/components/dataform-controls/date.tsx index 758d53e47d7474..5fc114e115cd99 100644 --- a/packages/dataviews/src/components/dataform-controls/date.tsx +++ b/packages/dataviews/src/components/dataform-controls/date.tsx @@ -299,6 +299,7 @@ function CalendarDateControl< Item >( { isValid, format: fieldFormat, } = field; + const disabled = field.isDisabled( { item: data, field } ); const [ selectedPresetId, setSelectedPresetId ] = useState< string | null >( null ); @@ -406,6 +407,8 @@ function CalendarDateControl< Item >( { variant="tertiary" isPressed={ isSelected } size="small" + disabled={ disabled } + accessibleWhenDisabled onClick={ () => handlePresetClick( preset ) } @@ -419,8 +422,8 @@ function CalendarDateControl< Item >( { variant="tertiary" isPressed={ ! selectedPresetId } size="small" - disabled={ !! selectedPresetId } - accessibleWhenDisabled={ false } + disabled={ !! selectedPresetId || disabled } + accessibleWhenDisabled > { __( 'Custom' ) } @@ -436,6 +439,7 @@ function CalendarDateControl< Item >( { value={ value } onChange={ handleManualDateChange } required={ !! field.isValid?.required } + disabled={ disabled } /> { /* Calendar widget */ } @@ -449,6 +453,7 @@ function CalendarDateControl< Item >( { onMonthChange={ setCalendarMonth } timeZone={ timezoneString || undefined } weekStartsOn={ weekStartsOn } + disabled={ disabled } /> @@ -472,6 +477,7 @@ function CalendarDateRangeControl< Item >( { setValue, format: fieldFormat, } = field; + const disabled = field.isDisabled( { item: data, field } ); let value: DateRange; const fieldValue = getValue( { item: data } ); if ( @@ -626,6 +632,8 @@ function CalendarDateRangeControl< Item >( { variant="tertiary" isPressed={ isSelected } size="small" + disabled={ disabled } + accessibleWhenDisabled onClick={ () => handlePresetClick( preset ) } @@ -639,8 +647,8 @@ function CalendarDateRangeControl< Item >( { variant="tertiary" isPressed={ ! selectedPresetId } size="small" - accessibleWhenDisabled={ false } - disabled={ !! selectedPresetId } + accessibleWhenDisabled + disabled={ !! selectedPresetId || disabled } > { __( 'Custom' ) } @@ -664,6 +672,7 @@ function CalendarDateRangeControl< Item >( { handleManualDateChange( 'from', newValue ) } required={ !! field.isValid?.required } + disabled={ disabled } /> ( { handleManualDateChange( 'to', newValue ) } required={ !! field.isValid?.required } + disabled={ disabled } /> @@ -687,6 +697,7 @@ function CalendarDateRangeControl< Item >( { onMonthChange={ setCalendarMonth } timeZone={ timezone.string || undefined } weekStartsOn={ weekStartsOn } + disabled={ disabled } /> diff --git a/packages/dataviews/src/components/dataform-controls/datetime.tsx b/packages/dataviews/src/components/dataform-controls/datetime.tsx index 21037428945b38..746c5b5eb878fb 100644 --- a/packages/dataviews/src/components/dataform-controls/datetime.tsx +++ b/packages/dataviews/src/components/dataform-controls/datetime.tsx @@ -41,6 +41,7 @@ function CalendarDateTimeControl< Item >( { }: DataFormControlProps< Item > ) { const { compact } = config || {}; const { id, label, description, setValue, getValue, isValid } = field; + const disabled = field.isDisabled( { item: data, field } ); const fieldValue = getValue( { item: data } ); const value = typeof fieldValue === 'string' ? fieldValue : undefined; @@ -179,6 +180,7 @@ function CalendarDateTimeControl< Item >( { hideLabelFromVision value={ formatDateTime( value ) } onChange={ handleManualDateTimeChange } + disabled={ disabled } /> { /* Calendar widget */ } { ! compact && ( @@ -194,6 +196,7 @@ function CalendarDateTimeControl< Item >( { onMonthChange={ setCalendarMonth } timeZone={ timezoneString || undefined } weekStartsOn={ weekStartsOn } + disabled={ disabled } /> ) } diff --git a/packages/dataviews/src/components/dataform-controls/password.tsx b/packages/dataviews/src/components/dataform-controls/password.tsx index 5b8c75639e7ba2..d9acdbd657afe3 100644 --- a/packages/dataviews/src/components/dataform-controls/password.tsx +++ b/packages/dataviews/src/components/dataform-controls/password.tsx @@ -23,6 +23,7 @@ export default function Password< Item >( { validity, }: DataFormControlProps< Item > ) { const [ isVisible, setIsVisible ] = useState( false ); + const disabled = field.isDisabled( { item: data, field } ); const toggleVisibility = useCallback( () => { setIsVisible( ( prev ) => ! prev ); @@ -49,6 +50,8 @@ export default function Password< Item >( { ? __( 'Hide password' ) : __( 'Show password' ) } + disabled={ disabled } + accessibleWhenDisabled /> ), diff --git a/packages/dataviews/src/components/dataform-controls/radio.tsx b/packages/dataviews/src/components/dataform-controls/radio.tsx index 599f009146f88e..6abf9a41b39885 100644 --- a/packages/dataviews/src/components/dataform-controls/radio.tsx +++ b/packages/dataviews/src/components/dataform-controls/radio.tsx @@ -23,6 +23,7 @@ export default function Radio< Item >( { validity, }: DataFormControlProps< Item > ) { const { label, description, getValue, setValue, isValid } = field; + const disabled = field.isDisabled( { item: data, field } ); const { elements, isLoading } = useElements( { elements: field.elements, getElements: field.getElements, @@ -50,6 +51,7 @@ export default function Radio< Item >( { options={ elements } selected={ value } hideLabelFromVision={ hideLabelFromVision } + disabled={ disabled } /> ); } diff --git a/packages/dataviews/src/components/dataform-controls/select.tsx b/packages/dataviews/src/components/dataform-controls/select.tsx index 19211840ce2926..197166f7c3fa0b 100644 --- a/packages/dataviews/src/components/dataform-controls/select.tsx +++ b/packages/dataviews/src/components/dataform-controls/select.tsx @@ -23,6 +23,7 @@ export default function Select< Item >( { validity, }: DataFormControlProps< Item > ) { const { type, label, description, getValue, setValue, isValid } = field; + const disabled = field.isDisabled( { item: data, field } ); const isMultiple = type === 'array'; const value = getValue( { item: data } ) ?? ( isMultiple ? [] : '' ); @@ -55,6 +56,7 @@ export default function Select< Item >( { __next40pxDefaultSize hideLabelFromVision={ hideLabelFromVision } multiple={ isMultiple } + disabled={ disabled } /> ); } diff --git a/packages/dataviews/src/components/dataform-controls/textarea.tsx b/packages/dataviews/src/components/dataform-controls/textarea.tsx index 6a1785a0376e73..65ca6b496d0fbb 100644 --- a/packages/dataviews/src/components/dataform-controls/textarea.tsx +++ b/packages/dataviews/src/components/dataform-controls/textarea.tsx @@ -23,6 +23,7 @@ export default function Textarea< Item >( { validity, }: DataFormControlProps< Item > ) { const { rows = 4 } = config || {}; + const disabled = field.isDisabled( { item: data, field } ); const { label, placeholder, description, setValue, isValid } = field; const value = field.getValue( { item: data } ); @@ -43,6 +44,7 @@ export default function Textarea< Item >( { help={ description } onChange={ onChangeControl } rows={ rows } + disabled={ disabled } minLength={ isValid.minLength ? isValid.minLength.constraint : undefined } diff --git a/packages/dataviews/src/components/dataform-controls/toggle-group.tsx b/packages/dataviews/src/components/dataform-controls/toggle-group.tsx index 58ec8883337ff9..8d1d03df3aca0a 100644 --- a/packages/dataviews/src/components/dataform-controls/toggle-group.tsx +++ b/packages/dataviews/src/components/dataform-controls/toggle-group.tsx @@ -27,6 +27,7 @@ export default function ToggleGroup< Item >( { validity, }: DataFormControlProps< Item > ) { const { getValue, setValue, isValid } = field; + const disabled = field.isDisabled( { item: data, field } ); const value = getValue( { item: data } ); const onChangeControl = useCallback( @@ -67,6 +68,7 @@ export default function ToggleGroup< Item >( { key={ el.value } label={ el.label } value={ el.value } + disabled={ disabled } /> ) ) } diff --git a/packages/dataviews/src/components/dataform-controls/toggle.tsx b/packages/dataviews/src/components/dataform-controls/toggle.tsx index 045e46384625fe..62e514610fc855 100644 --- a/packages/dataviews/src/components/dataform-controls/toggle.tsx +++ b/packages/dataviews/src/components/dataform-controls/toggle.tsx @@ -22,6 +22,7 @@ export default function Toggle< Item >( { validity, }: DataFormControlProps< Item > ) { const { label, description, getValue, setValue, isValid } = field; + const disabled = field.isDisabled( { item: data, field } ); const onChangeControl = useCallback( () => { onChange( @@ -39,6 +40,7 @@ export default function Toggle< Item >( { help={ description } checked={ getValue( { item: data } ) } onChange={ onChangeControl } + disabled={ disabled } /> ); } diff --git a/packages/dataviews/src/components/dataform-controls/utils/relative-date-control.tsx b/packages/dataviews/src/components/dataform-controls/utils/relative-date-control.tsx index a44f4e634ef275..50de96d4347c78 100644 --- a/packages/dataviews/src/components/dataform-controls/utils/relative-date-control.tsx +++ b/packages/dataviews/src/components/dataform-controls/utils/relative-date-control.tsx @@ -59,6 +59,7 @@ export default function RelativeDateControl< Item >( { ]; const { id, label, description, getValue, setValue } = field; + const disabled = field.isDisabled( { item: data, field } ); const fieldValue = getValue( { item: data } ); const { value: relValue = '', unit = options[ 0 ].value } = fieldValue && typeof fieldValue === 'object' ? fieldValue : {}; @@ -102,6 +103,7 @@ export default function RelativeDateControl< Item >( { step={ 1 } value={ relValue } onChange={ onChangeValue } + disabled={ disabled } /> ( { options={ options } onChange={ onChangeUnit } hideLabelFromVision + disabled={ disabled } /> diff --git a/packages/dataviews/src/components/dataform-controls/utils/validated-input.tsx b/packages/dataviews/src/components/dataform-controls/utils/validated-input.tsx index cc2f1f3055a564..37c2b8f9448b53 100644 --- a/packages/dataviews/src/components/dataform-controls/utils/validated-input.tsx +++ b/packages/dataviews/src/components/dataform-controls/utils/validated-input.tsx @@ -43,6 +43,7 @@ export default function ValidatedText< Item >( { const { label, placeholder, description, getValue, setValue, isValid } = field; const value = getValue( { item: data } ); + const disabled = field.isDisabled( { item: data, field } ); const onChangeControl = useCallback( ( newValue: string ) => @@ -69,6 +70,7 @@ export default function ValidatedText< Item >( { type={ type } prefix={ prefix } suffix={ suffix } + disabled={ disabled } pattern={ isValid.pattern ? isValid.pattern.constraint : undefined } minLength={ isValid.minLength ? isValid.minLength.constraint : undefined diff --git a/packages/dataviews/src/components/dataform-controls/utils/validated-number.tsx b/packages/dataviews/src/components/dataform-controls/utils/validated-number.tsx index f5fbb24c9a137a..9d93de775ec907 100644 --- a/packages/dataviews/src/components/dataform-controls/utils/validated-number.tsx +++ b/packages/dataviews/src/components/dataform-controls/utils/validated-number.tsx @@ -96,6 +96,7 @@ export default function ValidatedNumber< Item >( { const step = Math.pow( 10, Math.abs( decimals ) * -1 ); const { label, description, getValue, setValue, isValid } = field; const value = getValue( { item: data } ) ?? ''; + const disabled = field.isDisabled( { item: data, field } ); const onChangeControl = useCallback( ( newValue: string | undefined ) => { @@ -161,6 +162,7 @@ export default function ValidatedNumber< Item >( { step={ step } min={ isValid.min ? isValid.min.constraint : undefined } max={ isValid.max ? isValid.max.constraint : undefined } + disabled={ disabled } /> ); } diff --git a/packages/dataviews/src/components/dataviews-filters/input-widget.tsx b/packages/dataviews/src/components/dataviews-filters/input-widget.tsx index fa60759f3e981d..8229bc938508a9 100644 --- a/packages/dataviews/src/components/dataviews-filters/input-widget.tsx +++ b/packages/dataviews/src/components/dataviews-filters/input-widget.tsx @@ -64,6 +64,10 @@ export default function InputWidget( { ...currentField, // Deactivate validation for filters. isValid: {} satisfies NormalizedRules< any >, + // Filter controls are always enabled. + isDisabled: () => false, + // Filter controls are always visible. + isVisible: () => true, // Configure getValue/setValue as if Item was a plain object. getValue: ( { item }: { item: any } ) => item[ currentField.id ], diff --git a/packages/dataviews/src/dataform/stories/index.story.tsx b/packages/dataviews/src/dataform/stories/index.story.tsx index 8a75a7be59a35b..dd094de7469c1b 100644 --- a/packages/dataviews/src/dataform/stories/index.story.tsx +++ b/packages/dataviews/src/dataform/stories/index.story.tsx @@ -93,6 +93,13 @@ export const LayoutRegular = { description: 'Chooses the label position.', options: [ 'default', 'top', 'side', 'none' ], }, + disabled: { + control: { type: 'boolean' }, + description: 'Disable all fields in the form.', + }, + }, + args: { + disabled: false, }, }; diff --git a/packages/dataviews/src/dataform/stories/layout-regular.tsx b/packages/dataviews/src/dataform/stories/layout-regular.tsx index 4c6a1b8a646f40..10517bd55a29e7 100644 --- a/packages/dataviews/src/dataform/stories/layout-regular.tsx +++ b/packages/dataviews/src/dataform/stories/layout-regular.tsx @@ -312,8 +312,10 @@ const getLayoutFromStoryArgs = ( { const LayoutRegularComponent = ( { labelPosition, + disabled = false, }: { labelPosition: 'default' | 'top' | 'side' | 'none'; + disabled?: boolean; } ) => { const [ post, setPost ] = useState( { title: 'Hello, World!', @@ -332,6 +334,18 @@ const LayoutRegularComponent = ( { description: 'This is a sample description.', } ); + // Make fields disabled when control is set to disabled. + const _fields: Field< SamplePost >[] = useMemo( () => { + if ( ! disabled ) { + return fields; + } + + return fields.map( ( field ) => ( { + ...field, + isDisabled: true, + } ) ); + }, [ disabled ] ); + const form: Form = useMemo( () => ( { layout: getLayoutFromStoryArgs( { @@ -363,7 +377,7 @@ const LayoutRegularComponent = ( { return ( data={ post } - fields={ fields } + fields={ _fields } form={ form } onChange={ ( edits ) => setPost( ( prev ) => ( { diff --git a/packages/dataviews/src/field-types/index.tsx b/packages/dataviews/src/field-types/index.tsx index 2b570b38bb5eb8..acbb4b8fc54ab0 100644 --- a/packages/dataviews/src/field-types/index.tsx +++ b/packages/dataviews/src/field-types/index.tsx @@ -96,6 +96,10 @@ export default function normalizeFields< Item >( getElements: field.getElements, hasElements: hasElements( field ), isVisible: field.isVisible, + isDisabled: + typeof field.isDisabled === 'function' + ? field.isDisabled + : () => !! field.isDisabled, enableHiding: field.enableHiding ?? true, readOnly: field.readOnly ?? false, // The type provides defaults for the following props diff --git a/packages/dataviews/src/field-types/stories/index.story.tsx b/packages/dataviews/src/field-types/stories/index.story.tsx index 7bf3e152ea399a..fbe84685297850 100644 --- a/packages/dataviews/src/field-types/stories/index.story.tsx +++ b/packages/dataviews/src/field-types/stories/index.story.tsx @@ -66,12 +66,17 @@ const meta = { 'Add 10 more elements to push over the threshold and trigger Combobox rendering', if: { arg: 'Edit', eq: 'adaptiveSelect' }, }, + disabled: { + control: { type: 'boolean' }, + description: 'Whether the field controls are disabled.', + }, }, args: { type: 'regular', Edit: 'default', asyncElements: false, manyElements: false, + disabled: false, }, }; export default meta; @@ -590,6 +595,7 @@ interface FieldTypeStoryProps { Edit: ControlTypes; asyncElements: boolean; manyElements: boolean; + disabled: boolean; } const FieldTypeStory = ( { @@ -598,17 +604,27 @@ const FieldTypeStory = ( { Edit, asyncElements, manyElements, + disabled, }: FieldTypeStoryProps ) => { const storyFields = useMemo( () => { let fieldsToProcess = _fields; - if ( Edit !== 'default' ) { - fieldsToProcess = _fields.map( ( field: Field< DataType > ) => ( { + if ( disabled ) { + fieldsToProcess = fieldsToProcess.map( ( field ) => ( { ...field, - Edit, + isDisabled: true, } ) ); } + if ( Edit !== 'default' ) { + fieldsToProcess = fieldsToProcess.map( + ( field: Field< DataType > ) => ( { + ...field, + Edit, + } ) + ); + } + // Expand elements when adaptiveSelect is selected and manyElements is toggled if ( Edit === 'adaptiveSelect' && manyElements ) { fieldsToProcess = fieldsToProcess.map( ( field ) => { @@ -648,7 +664,7 @@ const FieldTypeStory = ( { } return fieldsToProcess; - }, [ _fields, Edit, asyncElements, manyElements ] ); + }, [ _fields, Edit, asyncElements, manyElements, disabled ] ); const form = useMemo( () => ( { layout: { type }, @@ -756,11 +772,13 @@ export const AllComponent = ( { Edit, asyncElements, manyElements, + disabled, }: { type: PanelTypes; Edit: ControlTypes; asyncElements: boolean; manyElements: boolean; + disabled: boolean; } ) => { return ( ); }; @@ -779,11 +798,13 @@ export const TextComponent = ( { Edit, asyncElements, manyElements, + disabled, }: { type: PanelTypes; Edit: ControlTypes; asyncElements: boolean; manyElements: boolean; + disabled: boolean; } ) => { const textFields = useMemo( () => fields.filter( ( field ) => field.type === 'text' ), @@ -797,6 +818,7 @@ export const TextComponent = ( { Edit={ Edit } asyncElements={ asyncElements } manyElements={ manyElements } + disabled={ disabled } /> ); }; @@ -808,12 +830,14 @@ export const IntegerComponent = ( { asyncElements, manyElements, formatSeparatorThousand, + disabled, }: { type: PanelTypes; Edit: ControlTypes; asyncElements: boolean; manyElements: boolean; formatSeparatorThousand?: string; + disabled: boolean; } ) => { const integerFields = useMemo( () => @@ -840,6 +864,7 @@ export const IntegerComponent = ( { Edit={ Edit } asyncElements={ asyncElements } manyElements={ manyElements } + disabled={ disabled } /> ); }; @@ -863,6 +888,7 @@ export const NumberComponent = ( { formatSeparatorThousand, formatSeparatorDecimal, formatDecimals, + disabled, }: { type: PanelTypes; Edit: ControlTypes; @@ -871,6 +897,7 @@ export const NumberComponent = ( { formatSeparatorThousand?: string; formatSeparatorDecimal?: string; formatDecimals?: number; + disabled: boolean; } ) => { const numberFields = useMemo( () => @@ -913,6 +940,7 @@ export const NumberComponent = ( { Edit={ Edit } asyncElements={ asyncElements } manyElements={ manyElements } + disabled={ disabled } /> ); }; @@ -945,11 +973,13 @@ export const BooleanComponent = ( { Edit, asyncElements, manyElements, + disabled, }: { type: PanelTypes; Edit: ControlTypes; asyncElements: boolean; manyElements: boolean; + disabled: boolean; } ) => { const booleanFields = useMemo( () => fields.filter( ( field ) => field.type === 'boolean' ), @@ -963,6 +993,7 @@ export const BooleanComponent = ( { Edit={ Edit } asyncElements={ asyncElements } manyElements={ manyElements } + disabled={ disabled } /> ); }; @@ -975,6 +1006,7 @@ export const DateTimeComponent = ( { manyElements, formatDatetime, formatWeekStartsOn, + disabled, }: { type: PanelTypes; Edit: ControlTypes; @@ -982,6 +1014,7 @@ export const DateTimeComponent = ( { manyElements: boolean; formatDatetime?: string; formatWeekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6; + disabled: boolean; } ) => { const datetimeFields = useMemo( () => @@ -1006,7 +1039,7 @@ export const DateTimeComponent = ( { } return field; } ), - [ fields, formatDatetime, formatWeekStartsOn ] + [ formatDatetime, formatWeekStartsOn ] ); return ( @@ -1016,6 +1049,7 @@ export const DateTimeComponent = ( { Edit={ Edit } asyncElements={ asyncElements } manyElements={ manyElements } + disabled={ disabled } /> ); }; @@ -1054,6 +1088,7 @@ export const DateComponent = ( { manyElements, formatDate, formatWeekStartsOn, + disabled, }: { type: PanelTypes; Edit: ControlTypes; @@ -1061,6 +1096,7 @@ export const DateComponent = ( { manyElements: boolean; formatDate?: string; formatWeekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6; + disabled: boolean; } ) => { const dateFields = useMemo( () => @@ -1095,6 +1131,7 @@ export const DateComponent = ( { Edit={ Edit } asyncElements={ asyncElements } manyElements={ manyElements } + disabled={ disabled } /> ); }; @@ -1131,11 +1168,13 @@ export const EmailComponent = ( { Edit, asyncElements, manyElements, + disabled, }: { type: PanelTypes; Edit: ControlTypes; asyncElements: boolean; manyElements: boolean; + disabled: boolean; } ) => { const emailFields = useMemo( () => fields.filter( ( field ) => field.type === 'email' ), @@ -1149,6 +1188,7 @@ export const EmailComponent = ( { Edit={ Edit } asyncElements={ asyncElements } manyElements={ manyElements } + disabled={ disabled } /> ); }; @@ -1159,11 +1199,13 @@ export const TelephoneComponent = ( { Edit, asyncElements, manyElements, + disabled, }: { type: PanelTypes; Edit: ControlTypes; asyncElements: boolean; manyElements: boolean; + disabled: boolean; } ) => { const telephoneFields = fields.filter( ( field ) => field.id.startsWith( 'telephone' ) @@ -1176,6 +1218,7 @@ export const TelephoneComponent = ( { Edit={ Edit } asyncElements={ asyncElements } manyElements={ manyElements } + disabled={ disabled } /> ); }; @@ -1186,11 +1229,13 @@ export const UrlComponent = ( { Edit, asyncElements, manyElements, + disabled, }: { type: PanelTypes; Edit: ControlTypes; asyncElements: boolean; manyElements: boolean; + disabled: boolean; } ) => { const urlFields = useMemo( () => fields.filter( ( field ) => field.type === 'url' ), @@ -1204,6 +1249,7 @@ export const UrlComponent = ( { Edit={ Edit } asyncElements={ asyncElements } manyElements={ manyElements } + disabled={ disabled } /> ); }; @@ -1214,11 +1260,13 @@ export const ColorComponent = ( { Edit, asyncElements, manyElements, + disabled, }: { type: PanelTypes; Edit: ControlTypes; asyncElements: boolean; manyElements: boolean; + disabled: boolean; } ) => { const colorFields = useMemo( () => fields.filter( ( field ) => field.type === 'color' ), @@ -1232,6 +1280,7 @@ export const ColorComponent = ( { Edit={ Edit } asyncElements={ asyncElements } manyElements={ manyElements } + disabled={ disabled } /> ); }; @@ -1242,11 +1291,13 @@ export const MediaComponent = ( { Edit, asyncElements, manyElements, + disabled, }: { type: PanelTypes; Edit: ControlTypes; asyncElements: boolean; manyElements: boolean; + disabled: boolean; } ) => { const mediaFields = useMemo( () => fields.filter( ( field ) => field.type === 'media' ), @@ -1260,6 +1311,7 @@ export const MediaComponent = ( { Edit={ Edit } asyncElements={ asyncElements } manyElements={ manyElements } + disabled={ disabled } /> ); }; @@ -1270,11 +1322,13 @@ export const ArrayComponent = ( { Edit, asyncElements, manyElements, + disabled, }: { type: PanelTypes; Edit: ControlTypes; asyncElements: boolean; manyElements: boolean; + disabled: boolean; } ) => { const arrayTextFields = useMemo( () => fields.filter( ( field ) => field.type === 'array' ), @@ -1288,6 +1342,7 @@ export const ArrayComponent = ( { Edit={ Edit } asyncElements={ asyncElements } manyElements={ manyElements } + disabled={ disabled } /> ); }; @@ -1298,11 +1353,13 @@ export const PasswordComponent = ( { Edit, asyncElements, manyElements, + disabled, }: { type: PanelTypes; Edit: ControlTypes; asyncElements: boolean; manyElements: boolean; + disabled: boolean; } ) => { const passwordFields = fields.filter( ( field ) => field.id.startsWith( 'password' ) @@ -1315,6 +1372,7 @@ export const PasswordComponent = ( { Edit={ Edit } asyncElements={ asyncElements } manyElements={ manyElements } + disabled={ disabled } /> ); }; @@ -1325,11 +1383,13 @@ export const NoTypeComponent = ( { Edit, asyncElements, manyElements, + disabled, }: { type: PanelTypes; Edit: ControlTypes; asyncElements: boolean; manyElements: boolean; + disabled: boolean; } ) => { const noTypeFields = useMemo( () => fields.filter( ( field ) => field.type === undefined ), @@ -1343,6 +1403,7 @@ export const NoTypeComponent = ( { Edit={ Edit } asyncElements={ asyncElements } manyElements={ manyElements } + disabled={ disabled } /> ); }; diff --git a/packages/dataviews/src/types/field-api.ts b/packages/dataviews/src/types/field-api.ts index fae835d0e126b8..c1028eb0dfd52a 100644 --- a/packages/dataviews/src/types/field-api.ts +++ b/packages/dataviews/src/types/field-api.ts @@ -244,6 +244,18 @@ export type Field< Item > = { */ isVisible?: ( item: Item ) => boolean; + /** + * Whether a field should be disabled. + * Can be a boolean or a callback receiving the current item and field. + * Defaults to false. + */ + isDisabled?: + | boolean + | ( ( args: { + item: Item; + field: NormalizedField< Item >; + } ) => boolean ); + /** * Whether the field is sortable. */ @@ -380,6 +392,10 @@ export type NormalizedField< Item > = Omit< filterBy: Required< FilterByConfig > | false; filter: FilterOperatorMap< Item >; readOnly: boolean; + isDisabled: ( args: { + item: Item; + field: NormalizedField< Item >; + } ) => boolean; format: | {} | Required< FormatDate >