@remoteoss/json-schema-form 0.11.11-dev.20250220174843 → 0.11.12-dev.20250310202108

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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ #### 0.11.11-beta.0 (2025-02-20)
2
+
3
+ ##### Bug Fixes
4
+
5
+ * **conditionals:** Add support to `oneOf` ([#136](https://github.com/remoteoss/json-schema-form/pull/136)) ([966cec59](https://github.com/remoteoss/json-schema-form/commit/966cec595ed2a1ff35f9d15e22acaea16cdd5113))
6
+
1
7
  #### 0.11.10-beta.0 (2025-01-22)
2
8
 
3
9
  ##### Bug Fixes
package/dist/index.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  /*!
3
3
  Copyright (c) 2025 Remote Technology, Inc.
4
- NPM Package: @remoteoss/json-schema-form@0.11.11-dev.20250220174843
5
- Generated: Thu, 20 Feb 2025 17:48:57 GMT
4
+ NPM Package: @remoteoss/json-schema-form@0.11.12-dev.20250310202108
5
+ Generated: Mon, 10 Mar 2025 20:22:24 GMT
6
6
 
7
7
  MIT License
8
8
 
@@ -96,70 +96,6 @@ function hasProperty(object2, propertyName) {
96
96
  return Object.prototype.hasOwnProperty.call(object2, propertyName);
97
97
  }
98
98
 
99
- // src/internals/checkIfConditionMatches.js
100
- function checkIfConditionMatchesProperties(node, formValues, formFields, logic) {
101
- if (typeof node.if === "boolean") {
102
- return node.if;
103
- }
104
- return Object.keys(node.if.properties ?? {}).every((name) => {
105
- const currentProperty = node.if.properties[name];
106
- const value = formValues[name];
107
- const hasEmptyValue = typeof value === "undefined" || // NOTE: This is a "Remote API" dependency, as empty fields are sent as "null".
108
- value === null;
109
- const hasIfExplicit = node.if.required?.includes(name);
110
- if (hasEmptyValue && !hasIfExplicit) {
111
- return true;
112
- }
113
- if (hasProperty(currentProperty, "const")) {
114
- return compareFormValueWithSchemaValue(value, currentProperty.const);
115
- }
116
- if (currentProperty.contains?.pattern) {
117
- const formValue = value || [];
118
- if (Array.isArray(formValue)) {
119
- const pattern = new RegExp(currentProperty.contains.pattern);
120
- return (value || []).some((item) => pattern.test(item));
121
- }
122
- }
123
- if (currentProperty.enum) {
124
- return currentProperty.enum.includes(value);
125
- }
126
- if (currentProperty.properties) {
127
- return checkIfConditionMatchesProperties(
128
- { if: currentProperty },
129
- formValues[name],
130
- getField(name, formFields).fields,
131
- logic
132
- );
133
- }
134
- const field = getField(name, formFields);
135
- return validateFieldSchema(
136
- {
137
- ...field,
138
- ...currentProperty,
139
- required: true
140
- },
141
- value
142
- );
143
- });
144
- }
145
- function checkIfMatchesValidationsAndComputedValues(node, formValues, logic, parentID) {
146
- const validationsMatch = Object.entries(node.if.validations ?? {}).every(([name, property]) => {
147
- const currentValue = logic.getScope(parentID).applyValidationRuleInCondition(name, formValues);
148
- if (Object.hasOwn(property, "const") && currentValue === property.const)
149
- return true;
150
- return false;
151
- });
152
- const computedValuesMatch = Object.entries(node.if.computedValues ?? {}).every(
153
- ([name, property]) => {
154
- const currentValue = logic.getScope(parentID).applyComputedValueRuleInCondition(name, formValues);
155
- if (Object.hasOwn(property, "const") && currentValue === property.const)
156
- return true;
157
- return false;
158
- }
159
- );
160
- return computedValuesMatch && validationsMatch;
161
- }
162
-
163
99
  // src/internals/helpers.js
164
100
  var import_merge = __toESM(require("lodash/fp/merge"));
165
101
  var import_get = __toESM(require("lodash/get"));
@@ -419,6 +355,76 @@ function _composeFieldCustomClosure(defaultComposeFn) {
419
355
  };
420
356
  }
421
357
 
358
+ // src/internals/checkIfConditionMatches.js
359
+ function checkIfConditionMatchesProperties(node, formValues, formFields, logic) {
360
+ if (typeof node.if === "boolean") {
361
+ return node.if;
362
+ }
363
+ if (node.if.anyOf) {
364
+ return node.if.anyOf.some(
365
+ (property) => checkIfConditionMatchesProperties({ if: property }, formValues, formFields, logic)
366
+ );
367
+ }
368
+ return Object.keys(node.if.properties ?? {}).every((name) => {
369
+ const currentProperty = node.if.properties[name];
370
+ const field = getField(name, formFields ?? []);
371
+ const isFieldsetField = field?.inputType === supportedTypes.FIELDSET;
372
+ const value = formValues?.[name] ?? (isFieldsetField ? {} : void 0);
373
+ const hasEmptyValue = typeof value === "undefined" || // NOTE: This is a "Remote API" dependency, as empty fields are sent as "null".
374
+ value === null;
375
+ const hasIfExplicit = node.if.required?.includes(name);
376
+ if (hasEmptyValue && !hasIfExplicit) {
377
+ return true;
378
+ }
379
+ if (hasProperty(currentProperty, "const")) {
380
+ return compareFormValueWithSchemaValue(value, currentProperty.const);
381
+ }
382
+ if (currentProperty.contains?.pattern) {
383
+ const formValue = value || [];
384
+ if (Array.isArray(formValue)) {
385
+ const pattern = new RegExp(currentProperty.contains.pattern);
386
+ return (value || []).some((item) => pattern.test(item));
387
+ }
388
+ }
389
+ if (currentProperty.enum) {
390
+ return currentProperty.enum.includes(value);
391
+ }
392
+ if (currentProperty.properties) {
393
+ return checkIfConditionMatchesProperties(
394
+ { if: currentProperty },
395
+ formValues[name],
396
+ getField(name, formFields).fields,
397
+ logic
398
+ );
399
+ }
400
+ return validateFieldSchema(
401
+ {
402
+ ...field,
403
+ ...currentProperty,
404
+ required: true
405
+ },
406
+ value
407
+ );
408
+ });
409
+ }
410
+ function checkIfMatchesValidationsAndComputedValues(node, formValues, logic, parentID) {
411
+ const validationsMatch = Object.entries(node.if.validations ?? {}).every(([name, property]) => {
412
+ const currentValue = logic.getScope(parentID).applyValidationRuleInCondition(name, formValues);
413
+ if (Object.hasOwn(property, "const") && currentValue === property.const)
414
+ return true;
415
+ return false;
416
+ });
417
+ const computedValuesMatch = Object.entries(node.if.computedValues ?? {}).every(
418
+ ([name, property]) => {
419
+ const currentValue = logic.getScope(parentID).applyComputedValueRuleInCondition(name, formValues);
420
+ if (Object.hasOwn(property, "const") && currentValue === property.const)
421
+ return true;
422
+ return false;
423
+ }
424
+ );
425
+ return computedValuesMatch && validationsMatch;
426
+ }
427
+
422
428
  // src/jsonLogic.js
423
429
  var import_json_logic_js = __toESM(require("json-logic-js"));
424
430
 
@@ -1164,11 +1170,7 @@ function hasType(type, typeName) {
1164
1170
  return Array.isArray(type) ? type.includes(typeName) : type === typeName;
1165
1171
  }
1166
1172
  function getField(fieldName, fields) {
1167
- if (Array.isArray(fields)) {
1168
- return fields.find(({ name }) => name === fieldName);
1169
- } else {
1170
- return fields[fieldName];
1171
- }
1173
+ return fields.find(({ name }) => name === fieldName);
1172
1174
  }
1173
1175
  function validateFieldSchema(field, value, logic) {
1174
1176
  const validator = buildYupSchema(field, {}, logic);
@@ -1382,25 +1384,6 @@ function processNode({
1382
1384
  logic
1383
1385
  });
1384
1386
  }
1385
- if (inputType === supportedTypes.GROUP_ARRAY) {
1386
- const values = formValues[name];
1387
- if (Array.isArray(values)) {
1388
- const newFields = [];
1389
- const field = getField(name, formFields);
1390
- values.forEach((value) => {
1391
- const fields = field.fields();
1392
- processNode({
1393
- node: nestedNode.items,
1394
- formValues: value,
1395
- formFields: fields,
1396
- parentID: name,
1397
- logic
1398
- });
1399
- newFields.push(fields);
1400
- });
1401
- field.dynamicFields = newFields;
1402
- }
1403
- }
1404
1387
  });
1405
1388
  }
1406
1389
  if (node["x-jsf-logic"]) {
@@ -1772,16 +1755,6 @@ function buildFieldParameters(name, fieldProperties, required = [], config = {},
1772
1755
  logic
1773
1756
  );
1774
1757
  }
1775
- if (inputType === supportedTypes.GROUP_ARRAY) {
1776
- fields = () => getFieldsFromJSONSchema(
1777
- fieldProperties.items,
1778
- {
1779
- customProperties: (0, import_get3.default)(config, `customProperties.${name}.customProperties`, {}),
1780
- parentID: name
1781
- },
1782
- logic
1783
- );
1784
- }
1785
1758
  const result = {
1786
1759
  name,
1787
1760
  inputType,
@@ -1875,10 +1848,12 @@ function getFieldsFromJSONSchema(scopedJsonSchema, config, logic) {
1875
1848
  if (fieldParams.inputType === "group-array") {
1876
1849
  const groupArrayItems = convertJSONSchemaPropertiesToFieldParameters(fieldParams.items);
1877
1850
  const groupArrayFields = groupArrayItems.map((groupArrayItem) => {
1851
+ groupArrayItem.nameKey = groupArrayItem.name;
1878
1852
  const customProperties = null;
1879
1853
  const composeFn = getComposeFunctionForField(groupArrayItem, !!customProperties);
1880
1854
  return composeFn(groupArrayItem);
1881
1855
  });
1856
+ fieldParams.nameKey = fieldParams.name;
1882
1857
  fieldParams.nthFieldGroup = {
1883
1858
  name: fieldParams.name,
1884
1859
  label: fieldParams.label,
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  /*!
3
3
  Copyright (c) 2025 Remote Technology, Inc.
4
- NPM Package: @remoteoss/json-schema-form@0.11.11-dev.20250220174843
5
- Generated: Thu, 20 Feb 2025 17:48:57 GMT
4
+ NPM Package: @remoteoss/json-schema-form@0.11.12-dev.20250310202108
5
+ Generated: Mon, 10 Mar 2025 20:22:24 GMT
6
6
 
7
7
  MIT License
8
8
 
@@ -59,70 +59,6 @@ function hasProperty(object2, propertyName) {
59
59
  return Object.prototype.hasOwnProperty.call(object2, propertyName);
60
60
  }
61
61
 
62
- // src/internals/checkIfConditionMatches.js
63
- function checkIfConditionMatchesProperties(node, formValues, formFields, logic) {
64
- if (typeof node.if === "boolean") {
65
- return node.if;
66
- }
67
- return Object.keys(node.if.properties ?? {}).every((name) => {
68
- const currentProperty = node.if.properties[name];
69
- const value = formValues[name];
70
- const hasEmptyValue = typeof value === "undefined" || // NOTE: This is a "Remote API" dependency, as empty fields are sent as "null".
71
- value === null;
72
- const hasIfExplicit = node.if.required?.includes(name);
73
- if (hasEmptyValue && !hasIfExplicit) {
74
- return true;
75
- }
76
- if (hasProperty(currentProperty, "const")) {
77
- return compareFormValueWithSchemaValue(value, currentProperty.const);
78
- }
79
- if (currentProperty.contains?.pattern) {
80
- const formValue = value || [];
81
- if (Array.isArray(formValue)) {
82
- const pattern = new RegExp(currentProperty.contains.pattern);
83
- return (value || []).some((item) => pattern.test(item));
84
- }
85
- }
86
- if (currentProperty.enum) {
87
- return currentProperty.enum.includes(value);
88
- }
89
- if (currentProperty.properties) {
90
- return checkIfConditionMatchesProperties(
91
- { if: currentProperty },
92
- formValues[name],
93
- getField(name, formFields).fields,
94
- logic
95
- );
96
- }
97
- const field = getField(name, formFields);
98
- return validateFieldSchema(
99
- {
100
- ...field,
101
- ...currentProperty,
102
- required: true
103
- },
104
- value
105
- );
106
- });
107
- }
108
- function checkIfMatchesValidationsAndComputedValues(node, formValues, logic, parentID) {
109
- const validationsMatch = Object.entries(node.if.validations ?? {}).every(([name, property]) => {
110
- const currentValue = logic.getScope(parentID).applyValidationRuleInCondition(name, formValues);
111
- if (Object.hasOwn(property, "const") && currentValue === property.const)
112
- return true;
113
- return false;
114
- });
115
- const computedValuesMatch = Object.entries(node.if.computedValues ?? {}).every(
116
- ([name, property]) => {
117
- const currentValue = logic.getScope(parentID).applyComputedValueRuleInCondition(name, formValues);
118
- if (Object.hasOwn(property, "const") && currentValue === property.const)
119
- return true;
120
- return false;
121
- }
122
- );
123
- return computedValuesMatch && validationsMatch;
124
- }
125
-
126
62
  // src/internals/helpers.js
127
63
  import merge from "lodash/fp/merge";
128
64
  import get from "lodash/get";
@@ -382,6 +318,76 @@ function _composeFieldCustomClosure(defaultComposeFn) {
382
318
  };
383
319
  }
384
320
 
321
+ // src/internals/checkIfConditionMatches.js
322
+ function checkIfConditionMatchesProperties(node, formValues, formFields, logic) {
323
+ if (typeof node.if === "boolean") {
324
+ return node.if;
325
+ }
326
+ if (node.if.anyOf) {
327
+ return node.if.anyOf.some(
328
+ (property) => checkIfConditionMatchesProperties({ if: property }, formValues, formFields, logic)
329
+ );
330
+ }
331
+ return Object.keys(node.if.properties ?? {}).every((name) => {
332
+ const currentProperty = node.if.properties[name];
333
+ const field = getField(name, formFields ?? []);
334
+ const isFieldsetField = field?.inputType === supportedTypes.FIELDSET;
335
+ const value = formValues?.[name] ?? (isFieldsetField ? {} : void 0);
336
+ const hasEmptyValue = typeof value === "undefined" || // NOTE: This is a "Remote API" dependency, as empty fields are sent as "null".
337
+ value === null;
338
+ const hasIfExplicit = node.if.required?.includes(name);
339
+ if (hasEmptyValue && !hasIfExplicit) {
340
+ return true;
341
+ }
342
+ if (hasProperty(currentProperty, "const")) {
343
+ return compareFormValueWithSchemaValue(value, currentProperty.const);
344
+ }
345
+ if (currentProperty.contains?.pattern) {
346
+ const formValue = value || [];
347
+ if (Array.isArray(formValue)) {
348
+ const pattern = new RegExp(currentProperty.contains.pattern);
349
+ return (value || []).some((item) => pattern.test(item));
350
+ }
351
+ }
352
+ if (currentProperty.enum) {
353
+ return currentProperty.enum.includes(value);
354
+ }
355
+ if (currentProperty.properties) {
356
+ return checkIfConditionMatchesProperties(
357
+ { if: currentProperty },
358
+ formValues[name],
359
+ getField(name, formFields).fields,
360
+ logic
361
+ );
362
+ }
363
+ return validateFieldSchema(
364
+ {
365
+ ...field,
366
+ ...currentProperty,
367
+ required: true
368
+ },
369
+ value
370
+ );
371
+ });
372
+ }
373
+ function checkIfMatchesValidationsAndComputedValues(node, formValues, logic, parentID) {
374
+ const validationsMatch = Object.entries(node.if.validations ?? {}).every(([name, property]) => {
375
+ const currentValue = logic.getScope(parentID).applyValidationRuleInCondition(name, formValues);
376
+ if (Object.hasOwn(property, "const") && currentValue === property.const)
377
+ return true;
378
+ return false;
379
+ });
380
+ const computedValuesMatch = Object.entries(node.if.computedValues ?? {}).every(
381
+ ([name, property]) => {
382
+ const currentValue = logic.getScope(parentID).applyComputedValueRuleInCondition(name, formValues);
383
+ if (Object.hasOwn(property, "const") && currentValue === property.const)
384
+ return true;
385
+ return false;
386
+ }
387
+ );
388
+ return computedValuesMatch && validationsMatch;
389
+ }
390
+
385
391
  // src/jsonLogic.js
386
392
  import jsonLogic from "json-logic-js";
387
393
 
@@ -1127,11 +1133,7 @@ function hasType(type, typeName) {
1127
1133
  return Array.isArray(type) ? type.includes(typeName) : type === typeName;
1128
1134
  }
1129
1135
  function getField(fieldName, fields) {
1130
- if (Array.isArray(fields)) {
1131
- return fields.find(({ name }) => name === fieldName);
1132
- } else {
1133
- return fields[fieldName];
1134
- }
1136
+ return fields.find(({ name }) => name === fieldName);
1135
1137
  }
1136
1138
  function validateFieldSchema(field, value, logic) {
1137
1139
  const validator = buildYupSchema(field, {}, logic);
@@ -1345,25 +1347,6 @@ function processNode({
1345
1347
  logic
1346
1348
  });
1347
1349
  }
1348
- if (inputType === supportedTypes.GROUP_ARRAY) {
1349
- const values = formValues[name];
1350
- if (Array.isArray(values)) {
1351
- const newFields = [];
1352
- const field = getField(name, formFields);
1353
- values.forEach((value) => {
1354
- const fields = field.fields();
1355
- processNode({
1356
- node: nestedNode.items,
1357
- formValues: value,
1358
- formFields: fields,
1359
- parentID: name,
1360
- logic
1361
- });
1362
- newFields.push(fields);
1363
- });
1364
- field.dynamicFields = newFields;
1365
- }
1366
- }
1367
1350
  });
1368
1351
  }
1369
1352
  if (node["x-jsf-logic"]) {
@@ -1735,16 +1718,6 @@ function buildFieldParameters(name, fieldProperties, required = [], config = {},
1735
1718
  logic
1736
1719
  );
1737
1720
  }
1738
- if (inputType === supportedTypes.GROUP_ARRAY) {
1739
- fields = () => getFieldsFromJSONSchema(
1740
- fieldProperties.items,
1741
- {
1742
- customProperties: get3(config, `customProperties.${name}.customProperties`, {}),
1743
- parentID: name
1744
- },
1745
- logic
1746
- );
1747
- }
1748
1721
  const result = {
1749
1722
  name,
1750
1723
  inputType,
@@ -1838,10 +1811,12 @@ function getFieldsFromJSONSchema(scopedJsonSchema, config, logic) {
1838
1811
  if (fieldParams.inputType === "group-array") {
1839
1812
  const groupArrayItems = convertJSONSchemaPropertiesToFieldParameters(fieldParams.items);
1840
1813
  const groupArrayFields = groupArrayItems.map((groupArrayItem) => {
1814
+ groupArrayItem.nameKey = groupArrayItem.name;
1841
1815
  const customProperties = null;
1842
1816
  const composeFn = getComposeFunctionForField(groupArrayItem, !!customProperties);
1843
1817
  return composeFn(groupArrayItem);
1844
1818
  });
1819
+ fieldParams.nameKey = fieldParams.name;
1845
1820
  fieldParams.nthFieldGroup = {
1846
1821
  name: fieldParams.name,
1847
1822
  label: fieldParams.label,
@@ -1,8 +1,8 @@
1
1
 
2
2
  /*!
3
3
  Copyright (c) 2025 Remote Technology, Inc.
4
- NPM Package: @remoteoss/json-schema-form@0.11.11-dev.20250220174843
5
- Generated: Thu, 20 Feb 2025 17:48:57 GMT
4
+ NPM Package: @remoteoss/json-schema-form@0.11.12-dev.20250310202108
5
+ Generated: Mon, 10 Mar 2025 20:22:24 GMT
6
6
 
7
7
  MIT License
8
8
 
@@ -11576,70 +11576,6 @@ function hasProperty(object2, propertyName) {
11576
11576
  return Object.prototype.hasOwnProperty.call(object2, propertyName);
11577
11577
  }
11578
11578
 
11579
- // src/internals/checkIfConditionMatches.js
11580
- function checkIfConditionMatchesProperties(node, formValues, formFields, logic) {
11581
- if (typeof node.if === "boolean") {
11582
- return node.if;
11583
- }
11584
- return Object.keys(node.if.properties ?? {}).every((name) => {
11585
- const currentProperty = node.if.properties[name];
11586
- const value = formValues[name];
11587
- const hasEmptyValue = typeof value === "undefined" || // NOTE: This is a "Remote API" dependency, as empty fields are sent as "null".
11588
- value === null;
11589
- const hasIfExplicit = node.if.required?.includes(name);
11590
- if (hasEmptyValue && !hasIfExplicit) {
11591
- return true;
11592
- }
11593
- if (hasProperty(currentProperty, "const")) {
11594
- return compareFormValueWithSchemaValue(value, currentProperty.const);
11595
- }
11596
- if (currentProperty.contains?.pattern) {
11597
- const formValue = value || [];
11598
- if (Array.isArray(formValue)) {
11599
- const pattern = new RegExp(currentProperty.contains.pattern);
11600
- return (value || []).some((item) => pattern.test(item));
11601
- }
11602
- }
11603
- if (currentProperty.enum) {
11604
- return currentProperty.enum.includes(value);
11605
- }
11606
- if (currentProperty.properties) {
11607
- return checkIfConditionMatchesProperties(
11608
- { if: currentProperty },
11609
- formValues[name],
11610
- getField(name, formFields).fields,
11611
- logic
11612
- );
11613
- }
11614
- const field = getField(name, formFields);
11615
- return validateFieldSchema(
11616
- {
11617
- ...field,
11618
- ...currentProperty,
11619
- required: true
11620
- },
11621
- value
11622
- );
11623
- });
11624
- }
11625
- function checkIfMatchesValidationsAndComputedValues(node, formValues, logic, parentID) {
11626
- const validationsMatch = Object.entries(node.if.validations ?? {}).every(([name, property2]) => {
11627
- const currentValue = logic.getScope(parentID).applyValidationRuleInCondition(name, formValues);
11628
- if (Object.hasOwn(property2, "const") && currentValue === property2.const)
11629
- return true;
11630
- return false;
11631
- });
11632
- const computedValuesMatch = Object.entries(node.if.computedValues ?? {}).every(
11633
- ([name, property2]) => {
11634
- const currentValue = logic.getScope(parentID).applyComputedValueRuleInCondition(name, formValues);
11635
- if (Object.hasOwn(property2, "const") && currentValue === property2.const)
11636
- return true;
11637
- return false;
11638
- }
11639
- );
11640
- return computedValuesMatch && validationsMatch;
11641
- }
11642
-
11643
11579
  // src/internals/helpers.js
11644
11580
  var import_merge = __toESM(require_merge2());
11645
11581
  var import_get2 = __toESM(require_get());
@@ -11899,6 +11835,76 @@ function _composeFieldCustomClosure(defaultComposeFn) {
11899
11835
  };
11900
11836
  }
11901
11837
 
11838
+ // src/internals/checkIfConditionMatches.js
11839
+ function checkIfConditionMatchesProperties(node, formValues, formFields, logic) {
11840
+ if (typeof node.if === "boolean") {
11841
+ return node.if;
11842
+ }
11843
+ if (node.if.anyOf) {
11844
+ return node.if.anyOf.some(
11845
+ (property2) => checkIfConditionMatchesProperties({ if: property2 }, formValues, formFields, logic)
11846
+ );
11847
+ }
11848
+ return Object.keys(node.if.properties ?? {}).every((name) => {
11849
+ const currentProperty = node.if.properties[name];
11850
+ const field = getField(name, formFields ?? []);
11851
+ const isFieldsetField = field?.inputType === supportedTypes.FIELDSET;
11852
+ const value = formValues?.[name] ?? (isFieldsetField ? {} : void 0);
11853
+ const hasEmptyValue = typeof value === "undefined" || // NOTE: This is a "Remote API" dependency, as empty fields are sent as "null".
11854
+ value === null;
11855
+ const hasIfExplicit = node.if.required?.includes(name);
11856
+ if (hasEmptyValue && !hasIfExplicit) {
11857
+ return true;
11858
+ }
11859
+ if (hasProperty(currentProperty, "const")) {
11860
+ return compareFormValueWithSchemaValue(value, currentProperty.const);
11861
+ }
11862
+ if (currentProperty.contains?.pattern) {
11863
+ const formValue = value || [];
11864
+ if (Array.isArray(formValue)) {
11865
+ const pattern = new RegExp(currentProperty.contains.pattern);
11866
+ return (value || []).some((item) => pattern.test(item));
11867
+ }
11868
+ }
11869
+ if (currentProperty.enum) {
11870
+ return currentProperty.enum.includes(value);
11871
+ }
11872
+ if (currentProperty.properties) {
11873
+ return checkIfConditionMatchesProperties(
11874
+ { if: currentProperty },
11875
+ formValues[name],
11876
+ getField(name, formFields).fields,
11877
+ logic
11878
+ );
11879
+ }
11880
+ return validateFieldSchema(
11881
+ {
11882
+ ...field,
11883
+ ...currentProperty,
11884
+ required: true
11885
+ },
11886
+ value
11887
+ );
11888
+ });
11889
+ }
11890
+ function checkIfMatchesValidationsAndComputedValues(node, formValues, logic, parentID) {
11891
+ const validationsMatch = Object.entries(node.if.validations ?? {}).every(([name, property2]) => {
11892
+ const currentValue = logic.getScope(parentID).applyValidationRuleInCondition(name, formValues);
11893
+ if (Object.hasOwn(property2, "const") && currentValue === property2.const)
11894
+ return true;
11895
+ return false;
11896
+ });
11897
+ const computedValuesMatch = Object.entries(node.if.computedValues ?? {}).every(
11898
+ ([name, property2]) => {
11899
+ const currentValue = logic.getScope(parentID).applyComputedValueRuleInCondition(name, formValues);
11900
+ if (Object.hasOwn(property2, "const") && currentValue === property2.const)
11901
+ return true;
11902
+ return false;
11903
+ }
11904
+ );
11905
+ return computedValuesMatch && validationsMatch;
11906
+ }
11907
+
11902
11908
  // src/jsonLogic.js
11903
11909
  var import_json_logic_js = __toESM(require_logic());
11904
11910
 
@@ -12643,11 +12649,7 @@ function hasType(type, typeName) {
12643
12649
  return Array.isArray(type) ? type.includes(typeName) : type === typeName;
12644
12650
  }
12645
12651
  function getField(fieldName, fields) {
12646
- if (Array.isArray(fields)) {
12647
- return fields.find(({ name }) => name === fieldName);
12648
- } else {
12649
- return fields[fieldName];
12650
- }
12652
+ return fields.find(({ name }) => name === fieldName);
12651
12653
  }
12652
12654
  function validateFieldSchema(field, value, logic) {
12653
12655
  const validator = buildYupSchema(field, {}, logic);
@@ -12861,25 +12863,6 @@ function processNode({
12861
12863
  logic
12862
12864
  });
12863
12865
  }
12864
- if (inputType === supportedTypes.GROUP_ARRAY) {
12865
- const values2 = formValues[name];
12866
- if (Array.isArray(values2)) {
12867
- const newFields = [];
12868
- const field = getField(name, formFields);
12869
- values2.forEach((value) => {
12870
- const fields = field.fields();
12871
- processNode({
12872
- node: nestedNode.items,
12873
- formValues: value,
12874
- formFields: fields,
12875
- parentID: name,
12876
- logic
12877
- });
12878
- newFields.push(fields);
12879
- });
12880
- field.dynamicFields = newFields;
12881
- }
12882
- }
12883
12866
  });
12884
12867
  }
12885
12868
  if (node["x-jsf-logic"]) {
@@ -13251,16 +13234,6 @@ function buildFieldParameters(name, fieldProperties, required2 = [], config = {}
13251
13234
  logic
13252
13235
  );
13253
13236
  }
13254
- if (inputType === supportedTypes.GROUP_ARRAY) {
13255
- fields = () => getFieldsFromJSONSchema(
13256
- fieldProperties.items,
13257
- {
13258
- customProperties: (0, import_get4.default)(config, `customProperties.${name}.customProperties`, {}),
13259
- parentID: name
13260
- },
13261
- logic
13262
- );
13263
- }
13264
13237
  const result = {
13265
13238
  name,
13266
13239
  inputType,
@@ -13354,10 +13327,12 @@ function getFieldsFromJSONSchema(scopedJsonSchema, config, logic) {
13354
13327
  if (fieldParams.inputType === "group-array") {
13355
13328
  const groupArrayItems = convertJSONSchemaPropertiesToFieldParameters(fieldParams.items);
13356
13329
  const groupArrayFields = groupArrayItems.map((groupArrayItem) => {
13330
+ groupArrayItem.nameKey = groupArrayItem.name;
13357
13331
  const customProperties = null;
13358
13332
  const composeFn = getComposeFunctionForField(groupArrayItem, !!customProperties);
13359
13333
  return composeFn(groupArrayItem);
13360
13334
  });
13335
+ fieldParams.nameKey = fieldParams.name;
13361
13336
  fieldParams.nthFieldGroup = {
13362
13337
  name: fieldParams.name,
13363
13338
  label: fieldParams.label,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remoteoss/json-schema-form",
3
- "version": "0.11.11-dev.20250220174843",
3
+ "version": "0.11.12-dev.20250310202108",
4
4
  "description": "Headless UI form powered by JSON Schemas",
5
5
  "author": "Remote.com <engineering@remote.com> (https://remote.com/)",
6
6
  "license": "MIT",
@@ -422,233 +422,6 @@ describe('Conditional attributes updated', () => {
422
422
  handleValidation({ is_full_time: 'no' });
423
423
  expect(fields[1].visibilityCondition).toEqual(expect.any(Function));
424
424
  });
425
-
426
- it('Group array nested condition', () => {
427
- const { fields, handleValidation } = createHeadlessForm({
428
- type: 'object',
429
- additionalProperties: false,
430
- properties: {
431
- companies: {
432
- type: 'array',
433
- 'x-jsf-presentation': {
434
- inputType: 'group-array',
435
- },
436
- items: {
437
- type: 'object',
438
- properties: {
439
- company: {
440
- type: 'string',
441
- oneOf: [
442
- {
443
- title: 'A',
444
- const: 'A',
445
- },
446
- {
447
- title: 'B',
448
- const: 'B',
449
- },
450
- ],
451
- 'x-jsf-presentation': {
452
- inputType: 'select',
453
- },
454
- },
455
- role: {
456
- title: 'Role',
457
- oneOf: [],
458
- 'x-jsf-presentation': {
459
- inputType: 'select',
460
- },
461
- },
462
- },
463
- allOf: [
464
- {
465
- if: {
466
- properties: {
467
- company: {
468
- const: 'A',
469
- },
470
- },
471
- required: ['company'],
472
- },
473
- then: {
474
- properties: {
475
- role: {
476
- oneOf: [
477
- {
478
- title: 'adminA',
479
- const: 'adminA',
480
- },
481
- {
482
- title: 'userA',
483
- const: 'userA',
484
- },
485
- ],
486
- 'x-jsf-presentation': {
487
- inputType: 'select',
488
- },
489
- },
490
- },
491
- required: ['role'],
492
- },
493
- },
494
- {
495
- if: {
496
- properties: {
497
- company: {
498
- const: 'B',
499
- },
500
- },
501
- required: ['company'],
502
- },
503
- then: {
504
- properties: {
505
- role: {
506
- oneOf: [
507
- {
508
- title: 'adminB',
509
- const: 'adminB',
510
- },
511
- {
512
- title: 'userB',
513
- const: 'userB',
514
- },
515
- ],
516
- 'x-jsf-presentation': {
517
- inputType: 'select',
518
- },
519
- },
520
- },
521
- required: ['role'],
522
- },
523
- },
524
- ],
525
- required: ['company', 'role'],
526
- },
527
- },
528
- },
529
- required: ['companies'],
530
- });
531
-
532
- handleValidation({ companies: [{ company: 'A' }, { company: 'B' }] });
533
- expect(fields[0].dynamicFields[0][1].options).toEqual([
534
- { label: 'adminA', value: 'adminA' },
535
- { label: 'userA', value: 'userA' },
536
- ]);
537
- expect(fields[0].dynamicFields[1][1].options).toEqual([
538
- { label: 'adminB', value: 'adminB' },
539
- { label: 'userB', value: 'userB' },
540
- ]);
541
- handleValidation({ companies: [] });
542
- expect(fields[0].dynamicFields).toEqual([]);
543
- });
544
-
545
- it('select multiple conditions', () => {
546
- const { fields, handleValidation } = createHeadlessForm({
547
- type: 'object',
548
- additionalProperties: false,
549
- properties: {
550
- company: {
551
- title: 'Select Company',
552
- type: 'string',
553
- description: 'Choose a company',
554
- oneOf: [
555
- {
556
- title: 'A',
557
- const: 'A',
558
- },
559
- {
560
- title: 'B',
561
- const: 'B',
562
- },
563
- ],
564
- 'x-jsf-presentation': {
565
- inputType: 'select',
566
- },
567
- },
568
- role: {
569
- title: 'Role',
570
- oneOf: [],
571
- 'x-jsf-presentation': {
572
- inputType: 'select',
573
- },
574
- },
575
- },
576
- allOf: [
577
- {
578
- if: {
579
- properties: {
580
- company: {
581
- const: 'A',
582
- },
583
- },
584
- required: ['company'],
585
- },
586
- then: {
587
- properties: {
588
- role: {
589
- oneOf: [
590
- {
591
- title: 'adminA',
592
- const: 'adminA',
593
- },
594
- {
595
- title: 'userA',
596
- const: 'userA',
597
- },
598
- ],
599
- 'x-jsf-presentation': {
600
- inputType: 'select',
601
- },
602
- },
603
- },
604
- required: ['role'],
605
- },
606
- },
607
- {
608
- if: {
609
- properties: {
610
- company: {
611
- const: 'B',
612
- },
613
- },
614
- required: ['company'],
615
- },
616
- then: {
617
- properties: {
618
- role: {
619
- oneOf: [
620
- {
621
- title: 'adminB',
622
- const: 'adminB',
623
- },
624
- {
625
- title: 'userB',
626
- const: 'userB',
627
- },
628
- ],
629
- 'x-jsf-presentation': {
630
- inputType: 'select',
631
- },
632
- },
633
- },
634
- required: ['role'],
635
- },
636
- },
637
- ],
638
- required: ['company', 'role'],
639
- });
640
-
641
- handleValidation({ company: 'A' });
642
- expect(fields[1].options).toEqual([
643
- { label: 'adminA', value: 'adminA' },
644
- { label: 'userA', value: 'userA' },
645
- ]);
646
- handleValidation({ company: 'B' });
647
- expect(fields[1].options).toEqual([
648
- { label: 'adminB', value: 'adminB' },
649
- { label: 'userB', value: 'userB' },
650
- ]);
651
- });
652
425
  });
653
426
 
654
427
  describe('Conditional with a minimum value check', () => {
@@ -775,6 +548,122 @@ describe('Conditional with literal booleans', () => {
775
548
  });
776
549
  });
777
550
 
551
+ describe('Conditional with anyOf', () => {
552
+ const schema = {
553
+ additionalProperties: false,
554
+ type: 'object',
555
+ properties: {
556
+ field_a: { type: 'string' },
557
+ field_b: { type: 'string' },
558
+ field_c: { type: 'string' },
559
+ },
560
+ allOf: [
561
+ {
562
+ if: {
563
+ anyOf: [
564
+ { properties: { field_a: { const: '1' } }, required: ['field_a'] },
565
+ { properties: { field_b: { const: '2' } }, required: ['field_b'] },
566
+ ],
567
+ },
568
+ then: {
569
+ required: ['field_c'],
570
+ },
571
+ else: {
572
+ properties: {
573
+ field_c: false,
574
+ },
575
+ },
576
+ },
577
+ ],
578
+ };
579
+
580
+ it('handles true case', () => {
581
+ const { fields, handleValidation } = createHeadlessForm(schema, { strictInputType: false });
582
+
583
+ expect(fields[2].isVisible).toBe(false);
584
+ expect(handleValidation({ field_a: 'x', field_b: '2' }).formErrors).toEqual({
585
+ field_c: 'Required field',
586
+ });
587
+ expect(fields[2].isVisible).toBe(true);
588
+ });
589
+
590
+ it('handles false case', () => {
591
+ const { fields, handleValidation } = createHeadlessForm(schema, { strictInputType: false });
592
+
593
+ expect(fields[2].isVisible).toBe(false);
594
+ expect(handleValidation({ field_a: 'x', field_b: 'x' }).formErrors).toBeUndefined();
595
+ expect(fields[2].isVisible).toBe(false);
596
+ });
597
+ });
598
+
599
+ describe('Conditional with fieldset', () => {
600
+ const schema = {
601
+ additionalProperties: false,
602
+ type: 'object',
603
+ properties: {
604
+ field_a: {
605
+ type: 'object',
606
+ properties: {
607
+ min: { type: 'number' },
608
+ max: { type: 'number' },
609
+ },
610
+ },
611
+ field_b: { type: 'string' },
612
+ },
613
+ allOf: [
614
+ {
615
+ if: {
616
+ properties: {
617
+ field_a: {
618
+ properties: {
619
+ min: {
620
+ minimum: 10,
621
+ },
622
+ },
623
+ required: ['min'],
624
+ },
625
+ },
626
+ required: ['field_a'],
627
+ },
628
+ then: {
629
+ required: ['field_b'],
630
+ },
631
+ else: {
632
+ properties: {
633
+ field_b: false,
634
+ },
635
+ },
636
+ },
637
+ ],
638
+ };
639
+
640
+ it('handles true case', () => {
641
+ const { fields, handleValidation } = createHeadlessForm(schema, { strictInputType: false });
642
+
643
+ expect(fields[1].isVisible).toBe(false);
644
+ expect(handleValidation({ field_a: { min: 100 } }).formErrors).toEqual({
645
+ field_b: 'Required field',
646
+ });
647
+ expect(fields[1].isVisible).toBe(true);
648
+ });
649
+
650
+ it('handles false case', () => {
651
+ const { fields, handleValidation } = createHeadlessForm(schema, { strictInputType: false });
652
+
653
+ expect(fields[1].isVisible).toBe(false);
654
+ expect(handleValidation({ field_a: { min: 1 } }).formErrors).toBeUndefined();
655
+ expect(fields[1].isVisible).toBe(false);
656
+ });
657
+
658
+ it('handles undefined fieldset case', () => {
659
+ const { fields, handleValidation } = createHeadlessForm(schema, { strictInputType: false });
660
+
661
+ expect(fields[1].isVisible).toBe(false);
662
+ expect(handleValidation({}).formErrors).toBeUndefined();
663
+ expect(fields[1].isVisible).toBe(false);
664
+ });
665
+ });
666
+
778
667
  describe('Conditionals - bugs and code-smells', () => {
779
668
  // Why do we have these bugs?
780
669
  // To be honest we never realized it much later later.
@@ -63,7 +63,6 @@ import {
63
63
  schemaForErrorMessageSpecificity,
64
64
  jsfConfigForErrorMessageSpecificity,
65
65
  schemaInputTypeFile,
66
- nestedGroupArrayForm,
67
66
  } from './helpers';
68
67
  import { mockConsole, restoreConsoleAndEnsureItWasNotCalled } from './testUtils';
69
68
  import { createHeadlessForm } from '@/createHeadlessForm';
@@ -1605,6 +1604,7 @@ describe('createHeadlessForm', () => {
1605
1604
  type: 'text',
1606
1605
  description: 'Enter your child’s full name',
1607
1606
  maxLength: 255,
1607
+ nameKey: 'full_name',
1608
1608
  label: 'Child Full Name',
1609
1609
  name: 'full_name',
1610
1610
  required: true,
@@ -1616,6 +1616,7 @@ describe('createHeadlessForm', () => {
1616
1616
  required: true,
1617
1617
  description: 'Enter your child’s date of birth',
1618
1618
  maxLength: 255,
1619
+ nameKey: 'birthdate',
1619
1620
  },
1620
1621
  {
1621
1622
  type: 'radio',
@@ -1634,6 +1635,7 @@ describe('createHeadlessForm', () => {
1634
1635
  required: true,
1635
1636
  description:
1636
1637
  'We know sex is non-binary but for insurance and payroll purposes, we need to collect this information.',
1638
+ nameKey: 'sex',
1637
1639
  },
1638
1640
  ]);
1639
1641
  });
@@ -1735,63 +1737,6 @@ describe('createHeadlessForm', () => {
1735
1737
  });
1736
1738
  });
1737
1739
 
1738
- it('nested "group-array" fields', () => {
1739
- const result = createHeadlessForm({
1740
- properties: {
1741
- nestedGroupArray: nestedGroupArrayForm,
1742
- },
1743
- });
1744
-
1745
- expect(result.fields[0]).toMatchObject({
1746
- label: 'Parent object',
1747
- name: 'nestedGroupArray',
1748
- required: false,
1749
- type: 'group-array',
1750
- inputType: 'group-array',
1751
- jsonType: 'array',
1752
- fields: expect.any(Function),
1753
- });
1754
-
1755
- expect(result.fields[0].fields()).toMatchObject([
1756
- {
1757
- type: 'text',
1758
- description: 'Simple text field',
1759
- maxLength: 255,
1760
- label: 'Outer Field',
1761
- name: 'notNested',
1762
- required: true,
1763
- },
1764
- {
1765
- label: 'Nested group-array',
1766
- name: 'nested',
1767
- required: true,
1768
- type: 'group-array',
1769
- inputType: 'group-array',
1770
- jsonType: 'array',
1771
- fields: expect.any(Function),
1772
- },
1773
- ]);
1774
-
1775
- expect(result.fields[0].fields()[1].fields()).toMatchObject([
1776
- {
1777
- type: 'text',
1778
- description: 'First nested text field',
1779
- maxLength: 255,
1780
- label: 'Inner Field 1',
1781
- name: 'nestedField1',
1782
- required: true,
1783
- },
1784
- {
1785
- type: 'text',
1786
- description: 'Second nested text field',
1787
- maxLength: 255,
1788
- label: 'Inner Field 2',
1789
- name: 'nestedField2',
1790
- required: true,
1791
- },
1792
- ]);
1793
- });
1794
-
1795
1740
  it('can pass custom field attributes', () => {
1796
1741
  const result = createHeadlessForm(
1797
1742
  {
@@ -2327,59 +2327,3 @@ export const schemaWithCustomValidationsAndConditionals = {
2327
2327
  },
2328
2328
  ],
2329
2329
  };
2330
-
2331
- export const nestedGroupArrayForm = {
2332
- items: {
2333
- properties: {
2334
- notNested: {
2335
- description: 'Simple text field',
2336
- 'x-jsf-presentation': {
2337
- inputType: 'text',
2338
- },
2339
- title: 'Outer Field',
2340
- type: 'string',
2341
- maxLength: 255,
2342
- },
2343
- nested: {
2344
- items: {
2345
- properties: {
2346
- nestedField1: {
2347
- description: 'First nested text field',
2348
- 'x-jsf-presentation': {
2349
- inputType: 'text',
2350
- },
2351
- title: 'Inner Field 1',
2352
- type: 'string',
2353
- maxLength: 255,
2354
- },
2355
- nestedField2: {
2356
- description: 'Second nested text field',
2357
- 'x-jsf-presentation': {
2358
- inputType: 'text',
2359
- },
2360
- title: 'Inner Field 2',
2361
- type: 'string',
2362
- maxLength: 255,
2363
- },
2364
- },
2365
- 'x-jsf-order': ['nestedField1', 'nestedField2'],
2366
- required: ['nestedField1', 'nestedField2'],
2367
- type: 'object',
2368
- },
2369
- 'x-jsf-presentation': {
2370
- inputType: 'group-array',
2371
- },
2372
- title: 'Nested group-array',
2373
- type: 'array',
2374
- },
2375
- },
2376
- 'x-jsf-order': ['notNested', 'nested'],
2377
- required: ['notNested', 'nested'],
2378
- type: 'object',
2379
- },
2380
- 'x-jsf-presentation': {
2381
- inputType: 'group-array',
2382
- },
2383
- title: 'Parent object',
2384
- type: 'array',
2385
- };