@remoteoss/json-schema-form 0.12.1-dev.20250929100600 → 0.12.2-beta.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.
- package/CHANGELOG.md +12 -0
- package/dist/index.cjs +23 -39
- package/dist/index.js +23 -39
- package/dist/standalone.js +23 -39
- package/package.json +1 -1
- package/src/tests/createHeadlessForm.test.js +101 -0
- package/src/tests/helpers.js +213 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
#### 0.12.2-beta.0 (2025-10-23)
|
|
2
|
+
|
|
3
|
+
##### New Features
|
|
4
|
+
|
|
5
|
+
* **v0:** Support nested fieldset conditionals ([#156](https://github.com/remoteoss/json-schema-form/pull/156)) ([877e82e1](https://github.com/remoteoss/json-schema-form/commit/877e82e148d1ff6964ba634108f8ca821c040565))
|
|
6
|
+
|
|
7
|
+
#### 0.12.1-beta.0 (2025-10-09)
|
|
8
|
+
|
|
9
|
+
##### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **checkbox:** Support optional boolean type for v0 ([#236](https://github.com/remoteoss/json-schema-form/pull/236)) ([76e8927f](https://github.com/remoteoss/json-schema-form/commit/76e8927fc2f4615620fe34eef303b2f9c8c81e6e))
|
|
12
|
+
|
|
1
13
|
#### 0.12.0-beta.0 (2025-06-25)
|
|
2
14
|
|
|
3
15
|
##### New Features
|
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.12.
|
|
5
|
-
Generated:
|
|
4
|
+
NPM Package: @remoteoss/json-schema-form@0.12.2-beta.0
|
|
5
|
+
Generated: Thu, 23 Oct 2025 14:03:06 GMT
|
|
6
6
|
|
|
7
7
|
MIT License
|
|
8
8
|
|
|
@@ -1264,30 +1264,6 @@ function getPrefillValues(fields, initialValues = {}) {
|
|
|
1264
1264
|
});
|
|
1265
1265
|
return initialValues;
|
|
1266
1266
|
}
|
|
1267
|
-
function preserveNestedFieldsVisibility(field, parentPath = "") {
|
|
1268
|
-
return field.fields?.reduce?.((acc, f) => {
|
|
1269
|
-
const path = parentPath ? `${parentPath}.${f.name}` : f.name;
|
|
1270
|
-
if (!(0, import_isNil.default)(f.isVisible)) {
|
|
1271
|
-
acc[path] = f.isVisible;
|
|
1272
|
-
}
|
|
1273
|
-
if (f.fields) {
|
|
1274
|
-
Object.assign(acc, preserveNestedFieldsVisibility(f, path));
|
|
1275
|
-
}
|
|
1276
|
-
return acc;
|
|
1277
|
-
}, {});
|
|
1278
|
-
}
|
|
1279
|
-
function restoreNestedFieldsVisibility(field, nestedFieldsVisibility, parentPath = "") {
|
|
1280
|
-
field.fields.forEach((f) => {
|
|
1281
|
-
const path = parentPath ? `${parentPath}.${f.name}` : f.name;
|
|
1282
|
-
const visibility = (0, import_get2.default)(nestedFieldsVisibility, path);
|
|
1283
|
-
if (!(0, import_isNil.default)(visibility)) {
|
|
1284
|
-
f.isVisible = visibility;
|
|
1285
|
-
}
|
|
1286
|
-
if (f.fields) {
|
|
1287
|
-
restoreNestedFieldsVisibility(f, nestedFieldsVisibility, path);
|
|
1288
|
-
}
|
|
1289
|
-
});
|
|
1290
|
-
}
|
|
1291
1267
|
function updateField(field, requiredFields, node, formValues, logic, config) {
|
|
1292
1268
|
if (!field) {
|
|
1293
1269
|
return;
|
|
@@ -1299,13 +1275,9 @@ function updateField(field, requiredFields, node, formValues, logic, config) {
|
|
|
1299
1275
|
if (fieldIsRequired) {
|
|
1300
1276
|
field.isVisible = true;
|
|
1301
1277
|
}
|
|
1302
|
-
const nestedFieldsVisibility = preserveNestedFieldsVisibility(field);
|
|
1303
1278
|
const updateAttributes = (fieldAttrs) => {
|
|
1304
1279
|
Object.entries(fieldAttrs).forEach(([key, value]) => {
|
|
1305
1280
|
field[key] = value;
|
|
1306
|
-
if (key === "fields" && !(0, import_isNil.default)(nestedFieldsVisibility)) {
|
|
1307
|
-
restoreNestedFieldsVisibility(field, nestedFieldsVisibility);
|
|
1308
|
-
}
|
|
1309
1281
|
if (key === "schema" && typeof value === "function") {
|
|
1310
1282
|
field[key] = value();
|
|
1311
1283
|
}
|
|
@@ -1334,7 +1306,8 @@ function updateField(field, requiredFields, node, formValues, logic, config) {
|
|
|
1334
1306
|
const { rootFieldAttrs, newAttributes } = field.calculateConditionalProperties({
|
|
1335
1307
|
isRequired: fieldIsRequired,
|
|
1336
1308
|
conditionBranch: node,
|
|
1337
|
-
formValues
|
|
1309
|
+
formValues,
|
|
1310
|
+
currentField: field
|
|
1338
1311
|
});
|
|
1339
1312
|
updateAttributes(newAttributes);
|
|
1340
1313
|
removeConditionalStaleAttributes(field, newAttributes, rootFieldAttrs);
|
|
@@ -1535,7 +1508,7 @@ function extractParametersFromNode(schemaNode) {
|
|
|
1535
1508
|
// — For checkboxes that only accept one value (string)
|
|
1536
1509
|
...presentation?.inputType === "checkbox" && { checkboxValue: node.const },
|
|
1537
1510
|
// - For checkboxes with boolean value
|
|
1538
|
-
...presentation?.inputType === "checkbox" && node.type
|
|
1511
|
+
...presentation?.inputType === "checkbox" && hasType(node.type, "boolean") && {
|
|
1539
1512
|
// true is what describes this checkbox as a boolean, regardless if its required or not
|
|
1540
1513
|
checkboxValue: true
|
|
1541
1514
|
},
|
|
@@ -1618,35 +1591,42 @@ function isFieldRequired(node, field) {
|
|
|
1618
1591
|
node?.required?.includes(field.name)
|
|
1619
1592
|
);
|
|
1620
1593
|
}
|
|
1621
|
-
function rebuildFieldset(fields, property) {
|
|
1594
|
+
function rebuildFieldset(fields, currentFields, property) {
|
|
1622
1595
|
if (property?.properties) {
|
|
1623
|
-
return fields.map((field) => {
|
|
1596
|
+
return fields.map((field, index) => {
|
|
1624
1597
|
const propertyConditionals = property.properties[field.name];
|
|
1598
|
+
const isVisible = currentFields[index].isVisible;
|
|
1625
1599
|
if (!propertyConditionals) {
|
|
1626
|
-
return
|
|
1600
|
+
return {
|
|
1601
|
+
...field,
|
|
1602
|
+
isVisible
|
|
1603
|
+
};
|
|
1627
1604
|
}
|
|
1628
1605
|
const newFieldParams = extractParametersFromNode(propertyConditionals);
|
|
1629
1606
|
if (field.fields) {
|
|
1630
1607
|
return {
|
|
1631
1608
|
...field,
|
|
1632
1609
|
...newFieldParams,
|
|
1633
|
-
|
|
1610
|
+
isVisible,
|
|
1611
|
+
fields: rebuildFieldset(field.fields, currentFields[index].fields, propertyConditionals)
|
|
1634
1612
|
};
|
|
1635
1613
|
}
|
|
1636
1614
|
return {
|
|
1637
1615
|
...field,
|
|
1638
1616
|
...newFieldParams,
|
|
1617
|
+
isVisible,
|
|
1639
1618
|
required: isFieldRequired(property, field)
|
|
1640
1619
|
};
|
|
1641
1620
|
});
|
|
1642
1621
|
}
|
|
1643
|
-
return fields.map((field) => ({
|
|
1622
|
+
return fields.map((field, index) => ({
|
|
1644
1623
|
...field,
|
|
1624
|
+
isVisible: currentFields[index].isVisible,
|
|
1645
1625
|
required: isFieldRequired(property, field)
|
|
1646
1626
|
}));
|
|
1647
1627
|
}
|
|
1648
1628
|
function calculateConditionalProperties({ fieldParams, customProperties, logic, config }) {
|
|
1649
|
-
return ({ isRequired, conditionBranch, formValues }) => {
|
|
1629
|
+
return ({ isRequired, conditionBranch, formValues, currentField }) => {
|
|
1650
1630
|
const conditionalProperty = conditionBranch?.properties?.[fieldParams.name];
|
|
1651
1631
|
if (conditionalProperty) {
|
|
1652
1632
|
const presentation = pickXKey(conditionalProperty, "presentation") ?? {};
|
|
@@ -1657,7 +1637,11 @@ function calculateConditionalProperties({ fieldParams, customProperties, logic,
|
|
|
1657
1637
|
});
|
|
1658
1638
|
let fieldSetFields;
|
|
1659
1639
|
if (fieldParams.inputType === supportedTypes.FIELDSET) {
|
|
1660
|
-
fieldSetFields = rebuildFieldset(
|
|
1640
|
+
fieldSetFields = rebuildFieldset(
|
|
1641
|
+
fieldParams.fields,
|
|
1642
|
+
currentField.fields,
|
|
1643
|
+
conditionalProperty
|
|
1644
|
+
);
|
|
1661
1645
|
newFieldParams.fields = fieldSetFields;
|
|
1662
1646
|
}
|
|
1663
1647
|
const { computedAttributes, ...restNewFieldParams } = newFieldParams;
|
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.12.
|
|
5
|
-
Generated:
|
|
4
|
+
NPM Package: @remoteoss/json-schema-form@0.12.2-beta.0
|
|
5
|
+
Generated: Thu, 23 Oct 2025 14:03:06 GMT
|
|
6
6
|
|
|
7
7
|
MIT License
|
|
8
8
|
|
|
@@ -1226,30 +1226,6 @@ function getPrefillValues(fields, initialValues = {}) {
|
|
|
1226
1226
|
});
|
|
1227
1227
|
return initialValues;
|
|
1228
1228
|
}
|
|
1229
|
-
function preserveNestedFieldsVisibility(field, parentPath = "") {
|
|
1230
|
-
return field.fields?.reduce?.((acc, f) => {
|
|
1231
|
-
const path = parentPath ? `${parentPath}.${f.name}` : f.name;
|
|
1232
|
-
if (!isNil(f.isVisible)) {
|
|
1233
|
-
acc[path] = f.isVisible;
|
|
1234
|
-
}
|
|
1235
|
-
if (f.fields) {
|
|
1236
|
-
Object.assign(acc, preserveNestedFieldsVisibility(f, path));
|
|
1237
|
-
}
|
|
1238
|
-
return acc;
|
|
1239
|
-
}, {});
|
|
1240
|
-
}
|
|
1241
|
-
function restoreNestedFieldsVisibility(field, nestedFieldsVisibility, parentPath = "") {
|
|
1242
|
-
field.fields.forEach((f) => {
|
|
1243
|
-
const path = parentPath ? `${parentPath}.${f.name}` : f.name;
|
|
1244
|
-
const visibility = get2(nestedFieldsVisibility, path);
|
|
1245
|
-
if (!isNil(visibility)) {
|
|
1246
|
-
f.isVisible = visibility;
|
|
1247
|
-
}
|
|
1248
|
-
if (f.fields) {
|
|
1249
|
-
restoreNestedFieldsVisibility(f, nestedFieldsVisibility, path);
|
|
1250
|
-
}
|
|
1251
|
-
});
|
|
1252
|
-
}
|
|
1253
1229
|
function updateField(field, requiredFields, node, formValues, logic, config) {
|
|
1254
1230
|
if (!field) {
|
|
1255
1231
|
return;
|
|
@@ -1261,13 +1237,9 @@ function updateField(field, requiredFields, node, formValues, logic, config) {
|
|
|
1261
1237
|
if (fieldIsRequired) {
|
|
1262
1238
|
field.isVisible = true;
|
|
1263
1239
|
}
|
|
1264
|
-
const nestedFieldsVisibility = preserveNestedFieldsVisibility(field);
|
|
1265
1240
|
const updateAttributes = (fieldAttrs) => {
|
|
1266
1241
|
Object.entries(fieldAttrs).forEach(([key, value]) => {
|
|
1267
1242
|
field[key] = value;
|
|
1268
|
-
if (key === "fields" && !isNil(nestedFieldsVisibility)) {
|
|
1269
|
-
restoreNestedFieldsVisibility(field, nestedFieldsVisibility);
|
|
1270
|
-
}
|
|
1271
1243
|
if (key === "schema" && typeof value === "function") {
|
|
1272
1244
|
field[key] = value();
|
|
1273
1245
|
}
|
|
@@ -1296,7 +1268,8 @@ function updateField(field, requiredFields, node, formValues, logic, config) {
|
|
|
1296
1268
|
const { rootFieldAttrs, newAttributes } = field.calculateConditionalProperties({
|
|
1297
1269
|
isRequired: fieldIsRequired,
|
|
1298
1270
|
conditionBranch: node,
|
|
1299
|
-
formValues
|
|
1271
|
+
formValues,
|
|
1272
|
+
currentField: field
|
|
1300
1273
|
});
|
|
1301
1274
|
updateAttributes(newAttributes);
|
|
1302
1275
|
removeConditionalStaleAttributes(field, newAttributes, rootFieldAttrs);
|
|
@@ -1497,7 +1470,7 @@ function extractParametersFromNode(schemaNode) {
|
|
|
1497
1470
|
// — For checkboxes that only accept one value (string)
|
|
1498
1471
|
...presentation?.inputType === "checkbox" && { checkboxValue: node.const },
|
|
1499
1472
|
// - For checkboxes with boolean value
|
|
1500
|
-
...presentation?.inputType === "checkbox" && node.type
|
|
1473
|
+
...presentation?.inputType === "checkbox" && hasType(node.type, "boolean") && {
|
|
1501
1474
|
// true is what describes this checkbox as a boolean, regardless if its required or not
|
|
1502
1475
|
checkboxValue: true
|
|
1503
1476
|
},
|
|
@@ -1580,35 +1553,42 @@ function isFieldRequired(node, field) {
|
|
|
1580
1553
|
node?.required?.includes(field.name)
|
|
1581
1554
|
);
|
|
1582
1555
|
}
|
|
1583
|
-
function rebuildFieldset(fields, property) {
|
|
1556
|
+
function rebuildFieldset(fields, currentFields, property) {
|
|
1584
1557
|
if (property?.properties) {
|
|
1585
|
-
return fields.map((field) => {
|
|
1558
|
+
return fields.map((field, index) => {
|
|
1586
1559
|
const propertyConditionals = property.properties[field.name];
|
|
1560
|
+
const isVisible = currentFields[index].isVisible;
|
|
1587
1561
|
if (!propertyConditionals) {
|
|
1588
|
-
return
|
|
1562
|
+
return {
|
|
1563
|
+
...field,
|
|
1564
|
+
isVisible
|
|
1565
|
+
};
|
|
1589
1566
|
}
|
|
1590
1567
|
const newFieldParams = extractParametersFromNode(propertyConditionals);
|
|
1591
1568
|
if (field.fields) {
|
|
1592
1569
|
return {
|
|
1593
1570
|
...field,
|
|
1594
1571
|
...newFieldParams,
|
|
1595
|
-
|
|
1572
|
+
isVisible,
|
|
1573
|
+
fields: rebuildFieldset(field.fields, currentFields[index].fields, propertyConditionals)
|
|
1596
1574
|
};
|
|
1597
1575
|
}
|
|
1598
1576
|
return {
|
|
1599
1577
|
...field,
|
|
1600
1578
|
...newFieldParams,
|
|
1579
|
+
isVisible,
|
|
1601
1580
|
required: isFieldRequired(property, field)
|
|
1602
1581
|
};
|
|
1603
1582
|
});
|
|
1604
1583
|
}
|
|
1605
|
-
return fields.map((field) => ({
|
|
1584
|
+
return fields.map((field, index) => ({
|
|
1606
1585
|
...field,
|
|
1586
|
+
isVisible: currentFields[index].isVisible,
|
|
1607
1587
|
required: isFieldRequired(property, field)
|
|
1608
1588
|
}));
|
|
1609
1589
|
}
|
|
1610
1590
|
function calculateConditionalProperties({ fieldParams, customProperties, logic, config }) {
|
|
1611
|
-
return ({ isRequired, conditionBranch, formValues }) => {
|
|
1591
|
+
return ({ isRequired, conditionBranch, formValues, currentField }) => {
|
|
1612
1592
|
const conditionalProperty = conditionBranch?.properties?.[fieldParams.name];
|
|
1613
1593
|
if (conditionalProperty) {
|
|
1614
1594
|
const presentation = pickXKey(conditionalProperty, "presentation") ?? {};
|
|
@@ -1619,7 +1599,11 @@ function calculateConditionalProperties({ fieldParams, customProperties, logic,
|
|
|
1619
1599
|
});
|
|
1620
1600
|
let fieldSetFields;
|
|
1621
1601
|
if (fieldParams.inputType === supportedTypes.FIELDSET) {
|
|
1622
|
-
fieldSetFields = rebuildFieldset(
|
|
1602
|
+
fieldSetFields = rebuildFieldset(
|
|
1603
|
+
fieldParams.fields,
|
|
1604
|
+
currentField.fields,
|
|
1605
|
+
conditionalProperty
|
|
1606
|
+
);
|
|
1623
1607
|
newFieldParams.fields = fieldSetFields;
|
|
1624
1608
|
}
|
|
1625
1609
|
const { computedAttributes, ...restNewFieldParams } = newFieldParams;
|
package/dist/standalone.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.12.
|
|
5
|
-
Generated:
|
|
4
|
+
NPM Package: @remoteoss/json-schema-form@0.12.2-beta.0
|
|
5
|
+
Generated: Thu, 23 Oct 2025 14:03:06 GMT
|
|
6
6
|
|
|
7
7
|
MIT License
|
|
8
8
|
|
|
@@ -12742,30 +12742,6 @@ function getPrefillValues(fields, initialValues = {}) {
|
|
|
12742
12742
|
});
|
|
12743
12743
|
return initialValues;
|
|
12744
12744
|
}
|
|
12745
|
-
function preserveNestedFieldsVisibility(field, parentPath = "") {
|
|
12746
|
-
return field.fields?.reduce?.((acc, f) => {
|
|
12747
|
-
const path = parentPath ? `${parentPath}.${f.name}` : f.name;
|
|
12748
|
-
if (!(0, import_isNil.default)(f.isVisible)) {
|
|
12749
|
-
acc[path] = f.isVisible;
|
|
12750
|
-
}
|
|
12751
|
-
if (f.fields) {
|
|
12752
|
-
Object.assign(acc, preserveNestedFieldsVisibility(f, path));
|
|
12753
|
-
}
|
|
12754
|
-
return acc;
|
|
12755
|
-
}, {});
|
|
12756
|
-
}
|
|
12757
|
-
function restoreNestedFieldsVisibility(field, nestedFieldsVisibility, parentPath = "") {
|
|
12758
|
-
field.fields.forEach((f) => {
|
|
12759
|
-
const path = parentPath ? `${parentPath}.${f.name}` : f.name;
|
|
12760
|
-
const visibility = (0, import_get3.default)(nestedFieldsVisibility, path);
|
|
12761
|
-
if (!(0, import_isNil.default)(visibility)) {
|
|
12762
|
-
f.isVisible = visibility;
|
|
12763
|
-
}
|
|
12764
|
-
if (f.fields) {
|
|
12765
|
-
restoreNestedFieldsVisibility(f, nestedFieldsVisibility, path);
|
|
12766
|
-
}
|
|
12767
|
-
});
|
|
12768
|
-
}
|
|
12769
12745
|
function updateField(field, requiredFields, node, formValues, logic, config) {
|
|
12770
12746
|
if (!field) {
|
|
12771
12747
|
return;
|
|
@@ -12777,13 +12753,9 @@ function updateField(field, requiredFields, node, formValues, logic, config) {
|
|
|
12777
12753
|
if (fieldIsRequired) {
|
|
12778
12754
|
field.isVisible = true;
|
|
12779
12755
|
}
|
|
12780
|
-
const nestedFieldsVisibility = preserveNestedFieldsVisibility(field);
|
|
12781
12756
|
const updateAttributes = (fieldAttrs) => {
|
|
12782
12757
|
Object.entries(fieldAttrs).forEach(([key, value]) => {
|
|
12783
12758
|
field[key] = value;
|
|
12784
|
-
if (key === "fields" && !(0, import_isNil.default)(nestedFieldsVisibility)) {
|
|
12785
|
-
restoreNestedFieldsVisibility(field, nestedFieldsVisibility);
|
|
12786
|
-
}
|
|
12787
12759
|
if (key === "schema" && typeof value === "function") {
|
|
12788
12760
|
field[key] = value();
|
|
12789
12761
|
}
|
|
@@ -12812,7 +12784,8 @@ function updateField(field, requiredFields, node, formValues, logic, config) {
|
|
|
12812
12784
|
const { rootFieldAttrs, newAttributes } = field.calculateConditionalProperties({
|
|
12813
12785
|
isRequired: fieldIsRequired,
|
|
12814
12786
|
conditionBranch: node,
|
|
12815
|
-
formValues
|
|
12787
|
+
formValues,
|
|
12788
|
+
currentField: field
|
|
12816
12789
|
});
|
|
12817
12790
|
updateAttributes(newAttributes);
|
|
12818
12791
|
removeConditionalStaleAttributes(field, newAttributes, rootFieldAttrs);
|
|
@@ -13013,7 +12986,7 @@ function extractParametersFromNode(schemaNode) {
|
|
|
13013
12986
|
// — For checkboxes that only accept one value (string)
|
|
13014
12987
|
...presentation?.inputType === "checkbox" && { checkboxValue: node.const },
|
|
13015
12988
|
// - For checkboxes with boolean value
|
|
13016
|
-
...presentation?.inputType === "checkbox" && node.type
|
|
12989
|
+
...presentation?.inputType === "checkbox" && hasType(node.type, "boolean") && {
|
|
13017
12990
|
// true is what describes this checkbox as a boolean, regardless if its required or not
|
|
13018
12991
|
checkboxValue: true
|
|
13019
12992
|
},
|
|
@@ -13096,35 +13069,42 @@ function isFieldRequired(node, field) {
|
|
|
13096
13069
|
node?.required?.includes(field.name)
|
|
13097
13070
|
);
|
|
13098
13071
|
}
|
|
13099
|
-
function rebuildFieldset(fields, property2) {
|
|
13072
|
+
function rebuildFieldset(fields, currentFields, property2) {
|
|
13100
13073
|
if (property2?.properties) {
|
|
13101
|
-
return fields.map((field) => {
|
|
13074
|
+
return fields.map((field, index) => {
|
|
13102
13075
|
const propertyConditionals = property2.properties[field.name];
|
|
13076
|
+
const isVisible = currentFields[index].isVisible;
|
|
13103
13077
|
if (!propertyConditionals) {
|
|
13104
|
-
return
|
|
13078
|
+
return {
|
|
13079
|
+
...field,
|
|
13080
|
+
isVisible
|
|
13081
|
+
};
|
|
13105
13082
|
}
|
|
13106
13083
|
const newFieldParams = extractParametersFromNode(propertyConditionals);
|
|
13107
13084
|
if (field.fields) {
|
|
13108
13085
|
return {
|
|
13109
13086
|
...field,
|
|
13110
13087
|
...newFieldParams,
|
|
13111
|
-
|
|
13088
|
+
isVisible,
|
|
13089
|
+
fields: rebuildFieldset(field.fields, currentFields[index].fields, propertyConditionals)
|
|
13112
13090
|
};
|
|
13113
13091
|
}
|
|
13114
13092
|
return {
|
|
13115
13093
|
...field,
|
|
13116
13094
|
...newFieldParams,
|
|
13095
|
+
isVisible,
|
|
13117
13096
|
required: isFieldRequired(property2, field)
|
|
13118
13097
|
};
|
|
13119
13098
|
});
|
|
13120
13099
|
}
|
|
13121
|
-
return fields.map((field) => ({
|
|
13100
|
+
return fields.map((field, index) => ({
|
|
13122
13101
|
...field,
|
|
13102
|
+
isVisible: currentFields[index].isVisible,
|
|
13123
13103
|
required: isFieldRequired(property2, field)
|
|
13124
13104
|
}));
|
|
13125
13105
|
}
|
|
13126
13106
|
function calculateConditionalProperties({ fieldParams, customProperties, logic, config }) {
|
|
13127
|
-
return ({ isRequired, conditionBranch, formValues }) => {
|
|
13107
|
+
return ({ isRequired, conditionBranch, formValues, currentField }) => {
|
|
13128
13108
|
const conditionalProperty = conditionBranch?.properties?.[fieldParams.name];
|
|
13129
13109
|
if (conditionalProperty) {
|
|
13130
13110
|
const presentation = pickXKey(conditionalProperty, "presentation") ?? {};
|
|
@@ -13135,7 +13115,11 @@ function calculateConditionalProperties({ fieldParams, customProperties, logic,
|
|
|
13135
13115
|
});
|
|
13136
13116
|
let fieldSetFields;
|
|
13137
13117
|
if (fieldParams.inputType === supportedTypes.FIELDSET) {
|
|
13138
|
-
fieldSetFields = rebuildFieldset(
|
|
13118
|
+
fieldSetFields = rebuildFieldset(
|
|
13119
|
+
fieldParams.fields,
|
|
13120
|
+
currentField.fields,
|
|
13121
|
+
conditionalProperty
|
|
13122
|
+
);
|
|
13139
13123
|
newFieldParams.fields = fieldSetFields;
|
|
13140
13124
|
}
|
|
13141
13125
|
const { computedAttributes, ...restNewFieldParams } = newFieldParams;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remoteoss/json-schema-form",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.2-beta.0",
|
|
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",
|
|
@@ -2307,6 +2307,85 @@ describe('createHeadlessForm', () => {
|
|
|
2307
2307
|
).toBeUndefined();
|
|
2308
2308
|
});
|
|
2309
2309
|
});
|
|
2310
|
+
|
|
2311
|
+
describe('supports computed values based on values from nested fieldsets', () => {
|
|
2312
|
+
it("computed value for total_contributions is calculated correctly with defaults when user selects 'yes' for has_retirement_plan", () => {
|
|
2313
|
+
const { fields, handleValidation } = createHeadlessForm(
|
|
2314
|
+
schemaWithNestedFieldsetsConditionals,
|
|
2315
|
+
{}
|
|
2316
|
+
);
|
|
2317
|
+
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
2318
|
+
|
|
2319
|
+
expect(
|
|
2320
|
+
validateForm({
|
|
2321
|
+
perks: {
|
|
2322
|
+
benefits_package: 'basic',
|
|
2323
|
+
has_retirement_plan: 'yes',
|
|
2324
|
+
declare_amount: 'no',
|
|
2325
|
+
retirement_plan: {
|
|
2326
|
+
plan_name: 'test',
|
|
2327
|
+
create_plan: 'no',
|
|
2328
|
+
},
|
|
2329
|
+
},
|
|
2330
|
+
})
|
|
2331
|
+
).toEqual({ perks: { retirement_plan: { year: 'Required field' } } });
|
|
2332
|
+
|
|
2333
|
+
expect(getField(fields, 'total_contributions').isVisible).toBe(true);
|
|
2334
|
+
expect(getField(fields, 'total_contributions').default).toBe(0);
|
|
2335
|
+
expect(getField(fields, 'total_contributions').const).toBe(0);
|
|
2336
|
+
});
|
|
2337
|
+
|
|
2338
|
+
it('computed value for total_contributions is calculated correctly based on the selected months', () => {
|
|
2339
|
+
const { fields, handleValidation } = createHeadlessForm(
|
|
2340
|
+
schemaWithNestedFieldsetsConditionals,
|
|
2341
|
+
{}
|
|
2342
|
+
);
|
|
2343
|
+
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
2344
|
+
|
|
2345
|
+
expect(
|
|
2346
|
+
validateForm({
|
|
2347
|
+
perks: {
|
|
2348
|
+
benefits_package: 'basic',
|
|
2349
|
+
has_retirement_plan: 'yes',
|
|
2350
|
+
declare_amount: 'no',
|
|
2351
|
+
retirement_plan: {
|
|
2352
|
+
plan_name: 'test',
|
|
2353
|
+
year: 2025,
|
|
2354
|
+
create_plan: 'yes',
|
|
2355
|
+
planned_contributions: {
|
|
2356
|
+
months: ['january', 'february', 'march', 'april', 'may'],
|
|
2357
|
+
},
|
|
2358
|
+
},
|
|
2359
|
+
},
|
|
2360
|
+
})
|
|
2361
|
+
).toBeUndefined();
|
|
2362
|
+
|
|
2363
|
+
expect(getField(fields, 'total_contributions').isVisible).toBe(true);
|
|
2364
|
+
expect(getField(fields, 'total_contributions').default).toBe(5);
|
|
2365
|
+
expect(getField(fields, 'total_contributions').const).toBe(5);
|
|
2366
|
+
|
|
2367
|
+
expect(
|
|
2368
|
+
validateForm({
|
|
2369
|
+
perks: {
|
|
2370
|
+
benefits_package: 'basic',
|
|
2371
|
+
has_retirement_plan: 'yes',
|
|
2372
|
+
declare_amount: 'no',
|
|
2373
|
+
retirement_plan: {
|
|
2374
|
+
plan_name: 'test',
|
|
2375
|
+
year: 2025,
|
|
2376
|
+
create_plan: 'yes',
|
|
2377
|
+
planned_contributions: {
|
|
2378
|
+
months: ['january', 'february', 'march'],
|
|
2379
|
+
},
|
|
2380
|
+
},
|
|
2381
|
+
},
|
|
2382
|
+
})
|
|
2383
|
+
).toBeUndefined();
|
|
2384
|
+
|
|
2385
|
+
expect(getField(fields, 'total_contributions').default).toBe(3);
|
|
2386
|
+
expect(getField(fields, 'total_contributions').const).toBe(3);
|
|
2387
|
+
});
|
|
2388
|
+
});
|
|
2310
2389
|
});
|
|
2311
2390
|
|
|
2312
2391
|
it('support "email" field type', () => {
|
|
@@ -2434,6 +2513,28 @@ describe('createHeadlessForm', () => {
|
|
|
2434
2513
|
// Explained at "Given values from hidden fields, it does not thrown an error"
|
|
2435
2514
|
expect(handleValidation({ has_pet: false, pet_is_cat: true }).formErrors).toBeUndefined();
|
|
2436
2515
|
});
|
|
2516
|
+
|
|
2517
|
+
it('should set checkboxValue: true for optional boolean type', () => {
|
|
2518
|
+
const schema = {
|
|
2519
|
+
type: 'object',
|
|
2520
|
+
properties: {
|
|
2521
|
+
boolean_checkbox: {
|
|
2522
|
+
title: 'Boolean Checkbox Test',
|
|
2523
|
+
type: ['boolean', 'null'],
|
|
2524
|
+
'x-jsf-presentation': {
|
|
2525
|
+
inputType: 'checkbox',
|
|
2526
|
+
},
|
|
2527
|
+
},
|
|
2528
|
+
},
|
|
2529
|
+
required: [],
|
|
2530
|
+
};
|
|
2531
|
+
|
|
2532
|
+
const result = createHeadlessForm(schema);
|
|
2533
|
+
|
|
2534
|
+
const [optionalCheckbox] = result.fields;
|
|
2535
|
+
expect(optionalCheckbox?.inputType).toBe('checkbox');
|
|
2536
|
+
expect(optionalCheckbox?.checkboxValue).toBe(true);
|
|
2537
|
+
});
|
|
2437
2538
|
});
|
|
2438
2539
|
});
|
|
2439
2540
|
|
package/src/tests/helpers.js
CHANGED
|
@@ -2023,7 +2023,7 @@ export const schemaWithNestedFieldsetsConditionals = {
|
|
|
2023
2023
|
title: 'No',
|
|
2024
2024
|
},
|
|
2025
2025
|
],
|
|
2026
|
-
title: 'Declare retirement amount?',
|
|
2026
|
+
title: 'Declare planned retirement amount?',
|
|
2027
2027
|
type: 'string',
|
|
2028
2028
|
default: 'yes',
|
|
2029
2029
|
'x-jsf-presentation': {
|
|
@@ -2031,6 +2031,23 @@ export const schemaWithNestedFieldsetsConditionals = {
|
|
|
2031
2031
|
},
|
|
2032
2032
|
},
|
|
2033
2033
|
retirement_plan: {
|
|
2034
|
+
allOf: [
|
|
2035
|
+
{
|
|
2036
|
+
if: {
|
|
2037
|
+
properties: {
|
|
2038
|
+
create_plan: {
|
|
2039
|
+
const: 'yes',
|
|
2040
|
+
},
|
|
2041
|
+
},
|
|
2042
|
+
},
|
|
2043
|
+
then: {},
|
|
2044
|
+
else: {
|
|
2045
|
+
properties: {
|
|
2046
|
+
planned_contributions: false,
|
|
2047
|
+
},
|
|
2048
|
+
},
|
|
2049
|
+
},
|
|
2050
|
+
],
|
|
2034
2051
|
type: 'object',
|
|
2035
2052
|
title: 'Retirement plan',
|
|
2036
2053
|
properties: {
|
|
@@ -2041,10 +2058,72 @@ export const schemaWithNestedFieldsetsConditionals = {
|
|
|
2041
2058
|
year: {
|
|
2042
2059
|
type: 'number',
|
|
2043
2060
|
title: 'Year',
|
|
2061
|
+
default: 2025,
|
|
2044
2062
|
},
|
|
2045
2063
|
amount: {
|
|
2046
2064
|
type: 'number',
|
|
2047
|
-
title: '
|
|
2065
|
+
title: 'Planned amount',
|
|
2066
|
+
},
|
|
2067
|
+
create_plan: {
|
|
2068
|
+
type: 'radio',
|
|
2069
|
+
title: 'Create plan?',
|
|
2070
|
+
oneOf: [
|
|
2071
|
+
{
|
|
2072
|
+
const: 'yes',
|
|
2073
|
+
title: 'Yes',
|
|
2074
|
+
},
|
|
2075
|
+
{
|
|
2076
|
+
const: 'no',
|
|
2077
|
+
title: 'No',
|
|
2078
|
+
},
|
|
2079
|
+
],
|
|
2080
|
+
default: 'yes',
|
|
2081
|
+
'x-jsf-presentation': {
|
|
2082
|
+
inputType: 'radio',
|
|
2083
|
+
},
|
|
2084
|
+
},
|
|
2085
|
+
planned_contributions: {
|
|
2086
|
+
type: 'object',
|
|
2087
|
+
title: 'Planned contributions',
|
|
2088
|
+
properties: {
|
|
2089
|
+
months: {
|
|
2090
|
+
default: ['january', 'february'],
|
|
2091
|
+
oneOf: [
|
|
2092
|
+
{
|
|
2093
|
+
const: 'january',
|
|
2094
|
+
title: 'January',
|
|
2095
|
+
},
|
|
2096
|
+
{
|
|
2097
|
+
const: 'february',
|
|
2098
|
+
title: 'February',
|
|
2099
|
+
},
|
|
2100
|
+
{
|
|
2101
|
+
const: 'march',
|
|
2102
|
+
title: 'March',
|
|
2103
|
+
},
|
|
2104
|
+
{
|
|
2105
|
+
const: 'april',
|
|
2106
|
+
title: 'April',
|
|
2107
|
+
},
|
|
2108
|
+
{
|
|
2109
|
+
const: 'may',
|
|
2110
|
+
title: 'May',
|
|
2111
|
+
},
|
|
2112
|
+
{
|
|
2113
|
+
const: 'june',
|
|
2114
|
+
title: 'June',
|
|
2115
|
+
},
|
|
2116
|
+
],
|
|
2117
|
+
title: "Select the months when you'll contribute",
|
|
2118
|
+
type: 'array',
|
|
2119
|
+
'x-jsf-presentation': {
|
|
2120
|
+
inputType: 'checkbox',
|
|
2121
|
+
},
|
|
2122
|
+
},
|
|
2123
|
+
},
|
|
2124
|
+
'x-jsf-presentation': {
|
|
2125
|
+
inputType: 'fieldset',
|
|
2126
|
+
},
|
|
2048
2127
|
},
|
|
2049
2128
|
},
|
|
2050
2129
|
required: ['plan_name', 'year'],
|
|
@@ -2060,6 +2139,19 @@ export const schemaWithNestedFieldsetsConditionals = {
|
|
|
2060
2139
|
inputType: 'fieldset',
|
|
2061
2140
|
},
|
|
2062
2141
|
},
|
|
2142
|
+
total_contributions: {
|
|
2143
|
+
title: 'Total contributions',
|
|
2144
|
+
description: 'The total contributions for the retirement plan',
|
|
2145
|
+
type: 'number',
|
|
2146
|
+
'x-jsf-presentation': {
|
|
2147
|
+
inputType: 'number',
|
|
2148
|
+
},
|
|
2149
|
+
'x-jsf-logic-computedAttrs': {
|
|
2150
|
+
const: 'total_contributions',
|
|
2151
|
+
default: 'total_contributions',
|
|
2152
|
+
description: 'You will contribute {{total_contributions}} times this year',
|
|
2153
|
+
},
|
|
2154
|
+
},
|
|
2063
2155
|
},
|
|
2064
2156
|
allOf: [
|
|
2065
2157
|
{
|
|
@@ -2141,6 +2233,125 @@ export const schemaWithNestedFieldsetsConditionals = {
|
|
|
2141
2233
|
},
|
|
2142
2234
|
},
|
|
2143
2235
|
],
|
|
2236
|
+
'x-jsf-logic': {
|
|
2237
|
+
computedValues: {
|
|
2238
|
+
total_contributions: {
|
|
2239
|
+
rule: {
|
|
2240
|
+
if: [
|
|
2241
|
+
{
|
|
2242
|
+
and: [
|
|
2243
|
+
{
|
|
2244
|
+
'===': [
|
|
2245
|
+
{
|
|
2246
|
+
var: 'perks.has_retirement_plan',
|
|
2247
|
+
},
|
|
2248
|
+
'yes',
|
|
2249
|
+
],
|
|
2250
|
+
},
|
|
2251
|
+
{
|
|
2252
|
+
'===': [
|
|
2253
|
+
{
|
|
2254
|
+
var: 'perks.retirement_plan.create_plan',
|
|
2255
|
+
},
|
|
2256
|
+
'yes',
|
|
2257
|
+
],
|
|
2258
|
+
},
|
|
2259
|
+
],
|
|
2260
|
+
},
|
|
2261
|
+
{
|
|
2262
|
+
'+': [
|
|
2263
|
+
{
|
|
2264
|
+
if: [
|
|
2265
|
+
{
|
|
2266
|
+
in: [
|
|
2267
|
+
'january',
|
|
2268
|
+
{
|
|
2269
|
+
var: 'perks.retirement_plan.planned_contributions.months',
|
|
2270
|
+
},
|
|
2271
|
+
],
|
|
2272
|
+
},
|
|
2273
|
+
1,
|
|
2274
|
+
0,
|
|
2275
|
+
],
|
|
2276
|
+
},
|
|
2277
|
+
{
|
|
2278
|
+
if: [
|
|
2279
|
+
{
|
|
2280
|
+
in: [
|
|
2281
|
+
'february',
|
|
2282
|
+
{
|
|
2283
|
+
var: 'perks.retirement_plan.planned_contributions.months',
|
|
2284
|
+
},
|
|
2285
|
+
],
|
|
2286
|
+
},
|
|
2287
|
+
1,
|
|
2288
|
+
0,
|
|
2289
|
+
],
|
|
2290
|
+
},
|
|
2291
|
+
{
|
|
2292
|
+
if: [
|
|
2293
|
+
{
|
|
2294
|
+
in: [
|
|
2295
|
+
'march',
|
|
2296
|
+
{
|
|
2297
|
+
var: 'perks.retirement_plan.planned_contributions.months',
|
|
2298
|
+
},
|
|
2299
|
+
],
|
|
2300
|
+
},
|
|
2301
|
+
1,
|
|
2302
|
+
0,
|
|
2303
|
+
],
|
|
2304
|
+
},
|
|
2305
|
+
{
|
|
2306
|
+
if: [
|
|
2307
|
+
{
|
|
2308
|
+
in: [
|
|
2309
|
+
'april',
|
|
2310
|
+
{
|
|
2311
|
+
var: 'perks.retirement_plan.planned_contributions.months',
|
|
2312
|
+
},
|
|
2313
|
+
],
|
|
2314
|
+
},
|
|
2315
|
+
1,
|
|
2316
|
+
0,
|
|
2317
|
+
],
|
|
2318
|
+
},
|
|
2319
|
+
{
|
|
2320
|
+
if: [
|
|
2321
|
+
{
|
|
2322
|
+
in: [
|
|
2323
|
+
'may',
|
|
2324
|
+
{
|
|
2325
|
+
var: 'perks.retirement_plan.planned_contributions.months',
|
|
2326
|
+
},
|
|
2327
|
+
],
|
|
2328
|
+
},
|
|
2329
|
+
1,
|
|
2330
|
+
0,
|
|
2331
|
+
],
|
|
2332
|
+
},
|
|
2333
|
+
{
|
|
2334
|
+
if: [
|
|
2335
|
+
{
|
|
2336
|
+
in: [
|
|
2337
|
+
'june',
|
|
2338
|
+
{
|
|
2339
|
+
var: 'perks.retirement_plan.planned_contributions.months',
|
|
2340
|
+
},
|
|
2341
|
+
],
|
|
2342
|
+
},
|
|
2343
|
+
1,
|
|
2344
|
+
0,
|
|
2345
|
+
],
|
|
2346
|
+
},
|
|
2347
|
+
],
|
|
2348
|
+
},
|
|
2349
|
+
0,
|
|
2350
|
+
],
|
|
2351
|
+
},
|
|
2352
|
+
},
|
|
2353
|
+
},
|
|
2354
|
+
},
|
|
2144
2355
|
};
|
|
2145
2356
|
|
|
2146
2357
|
export const schemaWorkSchedule = {
|