@remoteoss/json-schema-form 0.11.11-beta.0 → 0.11.11-dev.20250220174843

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,9 +1,3 @@
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
-
7
1
  #### 0.11.10-beta.0 (2025-01-22)
8
2
 
9
3
  ##### 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-beta.0
5
- Generated: Thu, 20 Feb 2025 18:25:18 GMT
4
+ NPM Package: @remoteoss/json-schema-form@0.11.11-dev.20250220174843
5
+ Generated: Thu, 20 Feb 2025 17:48:57 GMT
6
6
 
7
7
  MIT License
8
8
 
@@ -101,11 +101,6 @@ function checkIfConditionMatchesProperties(node, formValues, formFields, logic)
101
101
  if (typeof node.if === "boolean") {
102
102
  return node.if;
103
103
  }
104
- if (node.if.anyOf) {
105
- return node.if.anyOf.some(
106
- (property) => checkIfConditionMatchesProperties({ if: property }, formValues, formFields, logic)
107
- );
108
- }
109
104
  return Object.keys(node.if.properties ?? {}).every((name) => {
110
105
  const currentProperty = node.if.properties[name];
111
106
  const value = formValues[name];
@@ -1169,7 +1164,11 @@ function hasType(type, typeName) {
1169
1164
  return Array.isArray(type) ? type.includes(typeName) : type === typeName;
1170
1165
  }
1171
1166
  function getField(fieldName, fields) {
1172
- return fields.find(({ name }) => name === fieldName);
1167
+ if (Array.isArray(fields)) {
1168
+ return fields.find(({ name }) => name === fieldName);
1169
+ } else {
1170
+ return fields[fieldName];
1171
+ }
1173
1172
  }
1174
1173
  function validateFieldSchema(field, value, logic) {
1175
1174
  const validator = buildYupSchema(field, {}, logic);
@@ -1383,6 +1382,25 @@ function processNode({
1383
1382
  logic
1384
1383
  });
1385
1384
  }
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
+ }
1386
1404
  });
1387
1405
  }
1388
1406
  if (node["x-jsf-logic"]) {
@@ -1754,6 +1772,16 @@ function buildFieldParameters(name, fieldProperties, required = [], config = {},
1754
1772
  logic
1755
1773
  );
1756
1774
  }
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
+ }
1757
1785
  const result = {
1758
1786
  name,
1759
1787
  inputType,
@@ -1847,12 +1875,10 @@ function getFieldsFromJSONSchema(scopedJsonSchema, config, logic) {
1847
1875
  if (fieldParams.inputType === "group-array") {
1848
1876
  const groupArrayItems = convertJSONSchemaPropertiesToFieldParameters(fieldParams.items);
1849
1877
  const groupArrayFields = groupArrayItems.map((groupArrayItem) => {
1850
- groupArrayItem.nameKey = groupArrayItem.name;
1851
1878
  const customProperties = null;
1852
1879
  const composeFn = getComposeFunctionForField(groupArrayItem, !!customProperties);
1853
1880
  return composeFn(groupArrayItem);
1854
1881
  });
1855
- fieldParams.nameKey = fieldParams.name;
1856
1882
  fieldParams.nthFieldGroup = {
1857
1883
  name: fieldParams.name,
1858
1884
  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-beta.0
5
- Generated: Thu, 20 Feb 2025 18:25:18 GMT
4
+ NPM Package: @remoteoss/json-schema-form@0.11.11-dev.20250220174843
5
+ Generated: Thu, 20 Feb 2025 17:48:57 GMT
6
6
 
7
7
  MIT License
8
8
 
@@ -64,11 +64,6 @@ function checkIfConditionMatchesProperties(node, formValues, formFields, logic)
64
64
  if (typeof node.if === "boolean") {
65
65
  return node.if;
66
66
  }
67
- if (node.if.anyOf) {
68
- return node.if.anyOf.some(
69
- (property) => checkIfConditionMatchesProperties({ if: property }, formValues, formFields, logic)
70
- );
71
- }
72
67
  return Object.keys(node.if.properties ?? {}).every((name) => {
73
68
  const currentProperty = node.if.properties[name];
74
69
  const value = formValues[name];
@@ -1132,7 +1127,11 @@ function hasType(type, typeName) {
1132
1127
  return Array.isArray(type) ? type.includes(typeName) : type === typeName;
1133
1128
  }
1134
1129
  function getField(fieldName, fields) {
1135
- return fields.find(({ name }) => name === fieldName);
1130
+ if (Array.isArray(fields)) {
1131
+ return fields.find(({ name }) => name === fieldName);
1132
+ } else {
1133
+ return fields[fieldName];
1134
+ }
1136
1135
  }
1137
1136
  function validateFieldSchema(field, value, logic) {
1138
1137
  const validator = buildYupSchema(field, {}, logic);
@@ -1346,6 +1345,25 @@ function processNode({
1346
1345
  logic
1347
1346
  });
1348
1347
  }
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
+ }
1349
1367
  });
1350
1368
  }
1351
1369
  if (node["x-jsf-logic"]) {
@@ -1717,6 +1735,16 @@ function buildFieldParameters(name, fieldProperties, required = [], config = {},
1717
1735
  logic
1718
1736
  );
1719
1737
  }
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
+ }
1720
1748
  const result = {
1721
1749
  name,
1722
1750
  inputType,
@@ -1810,12 +1838,10 @@ function getFieldsFromJSONSchema(scopedJsonSchema, config, logic) {
1810
1838
  if (fieldParams.inputType === "group-array") {
1811
1839
  const groupArrayItems = convertJSONSchemaPropertiesToFieldParameters(fieldParams.items);
1812
1840
  const groupArrayFields = groupArrayItems.map((groupArrayItem) => {
1813
- groupArrayItem.nameKey = groupArrayItem.name;
1814
1841
  const customProperties = null;
1815
1842
  const composeFn = getComposeFunctionForField(groupArrayItem, !!customProperties);
1816
1843
  return composeFn(groupArrayItem);
1817
1844
  });
1818
- fieldParams.nameKey = fieldParams.name;
1819
1845
  fieldParams.nthFieldGroup = {
1820
1846
  name: fieldParams.name,
1821
1847
  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-beta.0
5
- Generated: Thu, 20 Feb 2025 18:25:18 GMT
4
+ NPM Package: @remoteoss/json-schema-form@0.11.11-dev.20250220174843
5
+ Generated: Thu, 20 Feb 2025 17:48:57 GMT
6
6
 
7
7
  MIT License
8
8
 
@@ -11581,11 +11581,6 @@ function checkIfConditionMatchesProperties(node, formValues, formFields, logic)
11581
11581
  if (typeof node.if === "boolean") {
11582
11582
  return node.if;
11583
11583
  }
11584
- if (node.if.anyOf) {
11585
- return node.if.anyOf.some(
11586
- (property2) => checkIfConditionMatchesProperties({ if: property2 }, formValues, formFields, logic)
11587
- );
11588
- }
11589
11584
  return Object.keys(node.if.properties ?? {}).every((name) => {
11590
11585
  const currentProperty = node.if.properties[name];
11591
11586
  const value = formValues[name];
@@ -12648,7 +12643,11 @@ function hasType(type, typeName) {
12648
12643
  return Array.isArray(type) ? type.includes(typeName) : type === typeName;
12649
12644
  }
12650
12645
  function getField(fieldName, fields) {
12651
- return fields.find(({ name }) => name === fieldName);
12646
+ if (Array.isArray(fields)) {
12647
+ return fields.find(({ name }) => name === fieldName);
12648
+ } else {
12649
+ return fields[fieldName];
12650
+ }
12652
12651
  }
12653
12652
  function validateFieldSchema(field, value, logic) {
12654
12653
  const validator = buildYupSchema(field, {}, logic);
@@ -12862,6 +12861,25 @@ function processNode({
12862
12861
  logic
12863
12862
  });
12864
12863
  }
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
+ }
12865
12883
  });
12866
12884
  }
12867
12885
  if (node["x-jsf-logic"]) {
@@ -13233,6 +13251,16 @@ function buildFieldParameters(name, fieldProperties, required2 = [], config = {}
13233
13251
  logic
13234
13252
  );
13235
13253
  }
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
+ }
13236
13264
  const result = {
13237
13265
  name,
13238
13266
  inputType,
@@ -13326,12 +13354,10 @@ function getFieldsFromJSONSchema(scopedJsonSchema, config, logic) {
13326
13354
  if (fieldParams.inputType === "group-array") {
13327
13355
  const groupArrayItems = convertJSONSchemaPropertiesToFieldParameters(fieldParams.items);
13328
13356
  const groupArrayFields = groupArrayItems.map((groupArrayItem) => {
13329
- groupArrayItem.nameKey = groupArrayItem.name;
13330
13357
  const customProperties = null;
13331
13358
  const composeFn = getComposeFunctionForField(groupArrayItem, !!customProperties);
13332
13359
  return composeFn(groupArrayItem);
13333
13360
  });
13334
- fieldParams.nameKey = fieldParams.name;
13335
13361
  fieldParams.nthFieldGroup = {
13336
13362
  name: fieldParams.name,
13337
13363
  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-beta.0",
3
+ "version": "0.11.11-dev.20250220174843",
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,6 +422,233 @@ 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
+ });
425
652
  });
426
653
 
427
654
  describe('Conditional with a minimum value check', () => {
@@ -548,54 +775,6 @@ describe('Conditional with literal booleans', () => {
548
775
  });
549
776
  });
550
777
 
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
778
  describe('Conditionals - bugs and code-smells', () => {
600
779
  // Why do we have these bugs?
601
780
  // To be honest we never realized it much later later.
@@ -63,6 +63,7 @@ import {
63
63
  schemaForErrorMessageSpecificity,
64
64
  jsfConfigForErrorMessageSpecificity,
65
65
  schemaInputTypeFile,
66
+ nestedGroupArrayForm,
66
67
  } from './helpers';
67
68
  import { mockConsole, restoreConsoleAndEnsureItWasNotCalled } from './testUtils';
68
69
  import { createHeadlessForm } from '@/createHeadlessForm';
@@ -1604,7 +1605,6 @@ describe('createHeadlessForm', () => {
1604
1605
  type: 'text',
1605
1606
  description: 'Enter your child’s full name',
1606
1607
  maxLength: 255,
1607
- nameKey: 'full_name',
1608
1608
  label: 'Child Full Name',
1609
1609
  name: 'full_name',
1610
1610
  required: true,
@@ -1616,7 +1616,6 @@ describe('createHeadlessForm', () => {
1616
1616
  required: true,
1617
1617
  description: 'Enter your child’s date of birth',
1618
1618
  maxLength: 255,
1619
- nameKey: 'birthdate',
1620
1619
  },
1621
1620
  {
1622
1621
  type: 'radio',
@@ -1635,7 +1634,6 @@ describe('createHeadlessForm', () => {
1635
1634
  required: true,
1636
1635
  description:
1637
1636
  'We know sex is non-binary but for insurance and payroll purposes, we need to collect this information.',
1638
- nameKey: 'sex',
1639
1637
  },
1640
1638
  ]);
1641
1639
  });
@@ -1737,6 +1735,63 @@ describe('createHeadlessForm', () => {
1737
1735
  });
1738
1736
  });
1739
1737
 
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
+
1740
1795
  it('can pass custom field attributes', () => {
1741
1796
  const result = createHeadlessForm(
1742
1797
  {
@@ -2327,3 +2327,59 @@ 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
+ };