@rjsf/core 6.7.0 → 6.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -72,6 +72,16 @@ function getDefaultValue<T = any, S extends StrictRJSFSchema = RJSFSchema, F ext
72
72
  }
73
73
  }
74
74
 
75
+ function isAdditionalPropertySchema(schema: unknown) {
76
+ return Boolean((schema as RJSFMarkedSchema)?.[ADDITIONAL_PROPERTY_FLAG]);
77
+ }
78
+
79
+ function getAdditionalPropertyOrder<S extends StrictRJSFSchema = RJSFSchema>(
80
+ schemaProperties: NonNullable<S['properties']>,
81
+ ) {
82
+ return Object.keys(schemaProperties).filter((property) => isAdditionalPropertySchema(schemaProperties[property]));
83
+ }
84
+
75
85
  /** Props for the `ObjectFieldProperty` component */
76
86
  interface ObjectFieldPropertyProps<
77
87
  T = any,
@@ -234,10 +244,17 @@ export default function ObjectField<T = any, S extends StrictRJSFSchema = RJSFSc
234
244
  [schemaUtils, rawSchema, formData],
235
245
  );
236
246
  const uiOptions = useMemo(() => getUiOptions<T, S, F>(uiSchema, globalUiOptions), [uiSchema, globalUiOptions]);
237
- const { properties: schemaProperties = {} } = schema;
247
+ const schemaProperties = useMemo(() => schema.properties ?? {}, [schema.properties]);
238
248
  // All the children will use childFieldPathId if present in the props, falling back to the fieldPathId
239
249
  const childFieldPathId = props.childFieldPathId ?? fieldPathId;
240
250
  const lastRenamedProperty = useRef({ previousKey: '', currentKey: undefined as string | undefined });
251
+ const [additionalPropertyOrder, setAdditionalPropertyOrder] = useState(() =>
252
+ getAdditionalPropertyOrder<S>(schemaProperties),
253
+ );
254
+ const definedPropertyOrder = useMemo(() => {
255
+ const additionalPropertySet = new Set(getAdditionalPropertyOrder<S>(schemaProperties));
256
+ return Object.keys(schemaProperties).filter((property) => !additionalPropertySet.has(property));
257
+ }, [schemaProperties]);
241
258
 
242
259
  const templateTitle = uiOptions.title ?? schema.title ?? title ?? name;
243
260
  const description = uiOptions.description ?? schema.description;
@@ -308,6 +325,7 @@ export default function ObjectField<T = any, S extends StrictRJSFSchema = RJSFSc
308
325
  lastRenamedProperty.current.currentKey = newKey;
309
326
  lastRenamedProperty.current.previousKey = getAvailableKey(newKey, newFormData);
310
327
  }
328
+ setAdditionalPropertyOrder((order) => [...order, newKey]);
311
329
  onChange(newFormData, childFieldPathId.path);
312
330
  }, [formData, onChange, translateString, schemaUtils, childFieldPathId, getAvailableKey, schema]);
313
331
 
@@ -339,6 +357,7 @@ export default function ObjectField<T = any, S extends StrictRJSFSchema = RJSFSc
339
357
  lastRenamedProperty.current.previousKey = oldKey;
340
358
  }
341
359
  lastRenamedProperty.current.currentKey = actualNewKey;
360
+ setAdditionalPropertyOrder((order) => order.map((property) => (property === oldKey ? actualNewKey : property)));
342
361
  onChange(renamedObj, childFieldPathId.path);
343
362
  }
344
363
  },
@@ -350,6 +369,7 @@ export default function ObjectField<T = any, S extends StrictRJSFSchema = RJSFSc
350
369
  */
351
370
  const handleRemoveProperty = useCallback(
352
371
  (key: string) => {
372
+ setAdditionalPropertyOrder((order) => order.filter((property) => property !== key));
353
373
  onChange(ADDITIONAL_PROPERTY_KEY_REMOVE as T, [...childFieldPathId.path, key]);
354
374
  },
355
375
  [onChange, childFieldPathId],
@@ -369,8 +389,11 @@ export default function ObjectField<T = any, S extends StrictRJSFSchema = RJSFSc
369
389
 
370
390
  if (!renderOptionalField || hasFormData) {
371
391
  try {
372
- const properties = Object.keys(schemaProperties);
373
- orderedProperties = orderProperties(properties, uiOptions.order);
392
+ const definedPropertySet = new Set(definedPropertyOrder);
393
+ const currentAdditionalProperties = additionalPropertyOrder.filter(
394
+ (property) => Object.hasOwn(schemaProperties, property) && !definedPropertySet.has(property),
395
+ );
396
+ orderedProperties = orderProperties([...definedPropertyOrder, ...currentAdditionalProperties], uiOptions.order);
374
397
  } catch (err) {
375
398
  return (
376
399
  <div>
@@ -395,9 +418,7 @@ export default function ObjectField<T = any, S extends StrictRJSFSchema = RJSFSc
395
418
  title: uiOptions.label === false ? '' : templateTitle,
396
419
  description: uiOptions.label === false ? undefined : description,
397
420
  properties: orderedProperties.map((propertyName) => {
398
- const addedByAdditionalProperties = Boolean(
399
- (schema.properties?.[propertyName] as RJSFMarkedSchema)?.[ADDITIONAL_PROPERTY_FLAG],
400
- );
421
+ const addedByAdditionalProperties = isAdditionalPropertySchema(schema.properties?.[propertyName]);
401
422
  const fieldUiSchema = addedByAdditionalProperties ? uiSchema.additionalProperties : uiSchema[propertyName];
402
423
  const hidden = getUiOptions<T, S, F>(fieldUiSchema).widget === 'hidden';
403
424
  const content = (
@@ -10,9 +10,24 @@ import { getTemplate } from '@rjsf/utils';
10
10
  export default function TimeWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
11
11
  props: WidgetProps<T, S, F>,
12
12
  ) {
13
- const { onChange, options, registry } = props;
13
+ const { onChange, options, registry, schema, value } = props;
14
14
  const BaseInputTemplate = getTemplate<'BaseInputTemplate', T, S, F>('BaseInputTemplate', registry, options);
15
- const handleChange = useCallback((value: any) => onChange(value ? `${value}:00` : undefined), [onChange]);
15
+ const hasSecondPrecision =
16
+ typeof schema.multipleOf === 'number' && Number.isFinite(schema.multipleOf) && schema.multipleOf < 60;
17
+ const handleChange = useCallback(
18
+ (newValue: any) => {
19
+ if (!newValue) {
20
+ onChange(undefined);
21
+ } else if (hasSecondPrecision) {
22
+ onChange(newValue);
23
+ } else {
24
+ onChange(`${newValue}:00`);
25
+ }
26
+ },
27
+ [hasSecondPrecision, onChange],
28
+ );
29
+ const displayValue =
30
+ typeof value === 'string' && !hasSecondPrecision && /^\d{2}:\d{2}:00$/.test(value) ? value.slice(0, -3) : value;
16
31
 
17
- return <BaseInputTemplate type='time' {...props} onChange={handleChange} />;
32
+ return <BaseInputTemplate type='time' {...props} value={displayValue} onChange={handleChange} />;
18
33
  }