Skip to content

Commit 80e0206

Browse files
committed
refactor(ArrayField): extract UI schema computation logic and fix checkbox value handling
Refactors ArrayField by extracting computeItemUiSchema helper method to eliminate duplicate code - Creates a shared private method for computing item UI schema that handles both function and object cases - Used in both regular arrays and fixed arrays rendering paths - Improves error handling for dynamic UI schema functions Fixes CheckboxWidget components in Fluent UI and MUI packages: - Changes onBlur/onFocus handlers to pass the checkbox checked state instead of its value Fixes getDisplayLabel to safely handle undefined uiSchema
1 parent 873059b commit 80e0206

File tree

4 files changed

+45
-39
lines changed

4 files changed

+45
-39
lines changed

packages/core/src/components/fields/ArrayField.tsx

Lines changed: 39 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,39 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
423423
onChange(value, undefined, idSchema && idSchema.$id);
424424
};
425425

426+
/** Helper method to compute item UI schema for both normal and fixed arrays
427+
* Handles both static object and dynamic function cases
428+
*
429+
* @param uiSchema - The parent UI schema containing items definition
430+
* @param item - The item data
431+
* @param index - The index of the item
432+
* @param formContext - The form context
433+
* @returns The computed UI schema for the item
434+
*/
435+
private computeItemUiSchema(
436+
uiSchema: UiSchema<T[], S, F>,
437+
item: T,
438+
index: number,
439+
formContext: F,
440+
): UiSchema<T[], S, F> | undefined {
441+
if (typeof uiSchema.items === 'function') {
442+
try {
443+
// Call the function with item data, index, and form context
444+
// TypeScript now correctly infers the types thanks to the ArrayElement type in UiSchema
445+
const result = uiSchema.items(item, index, formContext);
446+
// Only use the result if it's truthy
447+
return result as UiSchema<T[], S, F>;
448+
} catch (e) {
449+
console.error(`Error executing dynamic uiSchema.items function for item at index ${index}:`, e);
450+
// Fall back to undefined to allow the field to still render
451+
return undefined;
452+
}
453+
} else {
454+
// Static object case - preserve undefined to maintain backward compatibility
455+
return uiSchema.items as UiSchema<T[], S, F> | undefined;
456+
}
457+
}
458+
426459
/** Renders the `ArrayField` depending on the specific needs of the schema and uischema elements
427460
*/
428461
render() {
@@ -501,24 +534,8 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
501534
const itemIdPrefix = idSchema.$id + idSeparator + index;
502535
const itemIdSchema = schemaUtils.toIdSchema(itemSchema, itemIdPrefix, itemCast, idPrefix, idSeparator);
503536

504-
// Compute the item UI schema - either use the static object or call the function
505-
let itemUiSchema: UiSchema<T[], S, F> | undefined;
506-
if (typeof uiSchema.items === 'function') {
507-
try {
508-
// Call the function with item data, index, and form context
509-
// TypeScript now correctly infers the types thanks to the ArrayElement type in UiSchema
510-
const result = uiSchema.items(item, index, formContext);
511-
// Only use the result if it's truthy
512-
itemUiSchema = result as UiSchema<T[], S, F>;
513-
} catch (e) {
514-
console.error(`Error executing dynamic uiSchema.items function for item at index ${index}:`, e);
515-
// Fall back to undefined to allow the field to still render
516-
itemUiSchema = undefined;
517-
}
518-
} else {
519-
// Static object case - preserve undefined to maintain backward compatibility
520-
itemUiSchema = uiSchema.items as UiSchema<T[], S, F> | undefined;
521-
}
537+
// Compute the item UI schema using the helper method
538+
const itemUiSchema = this.computeItemUiSchema(uiSchema, item, index, formContext);
522539

523540
return this.renderArrayFieldItem({
524541
key,
@@ -780,20 +797,9 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
780797
// For fixed items, uiSchema.items can be an array, a function, or a single object
781798
if (Array.isArray(uiSchema.items)) {
782799
itemUiSchema = uiSchema.items[index] as UiSchema<T[], S, F>;
783-
} else if (typeof uiSchema.items === 'function') {
784-
try {
785-
// Call the function with item data, index, and form context
786-
const result = uiSchema.items(item, index, formContext);
787-
// Only use the result if it's truthy
788-
itemUiSchema = result as UiSchema<T[], S, F>;
789-
} catch (e) {
790-
console.error(`Error executing dynamic uiSchema.items function for item at index ${index}:`, e);
791-
// Fall back to undefined to allow the field to still render
792-
itemUiSchema = undefined;
793-
}
794800
} else {
795-
// Static object case
796-
itemUiSchema = uiSchema.items as UiSchema<T[], S, F>;
801+
// Use the helper method for function or static object cases
802+
itemUiSchema = this.computeItemUiSchema(uiSchema, item, index, formContext);
797803
}
798804
}
799805
const itemErrorSchema = errorSchema ? (errorSchema[index] as ErrorSchema<T[]>) : undefined;
@@ -903,7 +909,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
903909
title={title}
904910
index={index}
905911
schema={itemSchema}
906-
uiSchema={itemUiSchema || {}}
912+
uiSchema={itemUiSchema}
907913
formData={itemData}
908914
formContext={formContext}
909915
errorSchema={itemErrorSchema}
@@ -939,7 +945,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
939945
onReorderClick: this.onReorderClick,
940946
registry: registry,
941947
schema: itemSchema,
942-
uiSchema: itemUiSchema || {},
948+
uiSchema: itemUiSchema,
943949
},
944950
className: 'rjsf-array-item',
945951
disabled,

packages/fluentui-rc/src/CheckboxWidget/CheckboxWidget.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ export default function CheckboxWidget<
4848
const required = schemaRequiresTrueValue<S>(schema);
4949

5050
const _onChange = ({ target: { checked } }: ChangeEvent<HTMLInputElement>) => onChange(checked);
51-
const _onBlur = ({ target }: FocusEvent<HTMLInputElement>) => onBlur(id, target && target.value);
52-
const _onFocus = ({ target }: FocusEvent<HTMLInputElement>) => onFocus(id, target && target.value);
51+
const _onBlur = ({ target }: FocusEvent<HTMLInputElement>) => onBlur(id, target && target.checked);
52+
const _onFocus = ({ target }: FocusEvent<HTMLInputElement>) => onFocus(id, target && target.checked);
5353
const description = options.description ?? schema.description;
5454

5555
return (

packages/mui/src/CheckboxWidget/CheckboxWidget.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ export default function CheckboxWidget<
5050
const required = schemaRequiresTrueValue<S>(schema);
5151

5252
const _onChange = (_: any, checked: boolean) => onChange(checked);
53-
const _onBlur = ({ target }: FocusEvent<HTMLButtonElement>) => onBlur(id, target && target.value);
54-
const _onFocus = ({ target }: FocusEvent<HTMLButtonElement>) => onFocus(id, target && target.value);
53+
const _onBlur = ({ target }: FocusEvent<HTMLButtonElement>) => onBlur(id, target && target.checked);
54+
const _onFocus = ({ target }: FocusEvent<HTMLButtonElement>) => onFocus(id, target && target.checked);
5555
const description = options.description ?? schema.description;
5656

5757
return (

packages/utils/src/schema/getDisplayLabel.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,10 @@ export default function getDisplayLabel<
5252
if (schemaType === 'object') {
5353
displayLabel = false;
5454
}
55-
if (schemaType === 'boolean' && !uiSchema[UI_WIDGET_KEY]) {
55+
if (schemaType === 'boolean' && uiSchema && !uiSchema[UI_WIDGET_KEY]) {
5656
displayLabel = false;
5757
}
58-
if (uiSchema[UI_FIELD_KEY]) {
58+
if (uiSchema && uiSchema[UI_FIELD_KEY]) {
5959
displayLabel = false;
6060
}
6161
return displayLabel;

0 commit comments

Comments
 (0)