@remoteoss/json-schema-form 0.11.2-beta.0 → 0.11.3-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 CHANGED
@@ -1,3 +1,9 @@
1
+ #### 0.11.3-beta.0 (2024-08-19)
2
+
3
+ ##### Bug Fixes
4
+
5
+ * **select/radio:** Add support for options with boolean type ([#89](https://github.com/remoteoss/json-schema-form/pull/89)) ([127f70b3](https://github.com/remoteoss/json-schema-form/commit/127f70b3b19974a404e710548b83d4e4b17e1339))
6
+
1
7
  #### 0.11.2-beta.0 (2024-07-30)
2
8
 
3
9
  ##### Bug Fixes
package/dist/index.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  /*!
3
3
  Copyright (c) 2024 Remote Technology, Inc.
4
- NPM Package: @remoteoss/json-schema-form@0.11.2-beta.0
5
- Generated: Tue, 30 Jul 2024 12:00:17 GMT
4
+ NPM Package: @remoteoss/json-schema-form@0.11.3-beta.0
5
+ Generated: Mon, 19 Aug 2024 17:56:28 GMT
6
6
 
7
7
  MIT License
8
8
 
@@ -526,6 +526,24 @@ var yupSchemas = {
526
526
  return validateRadioOrSelectOptions(value, options);
527
527
  }
528
528
  ).nullable(),
529
+ radioOrSelectBoolean: (options) => {
530
+ return (0, import_yup.boolean)().nullable().transform((value) => {
531
+ if (options?.some((option) => option.value === null)) {
532
+ return value;
533
+ }
534
+ return value === null ? void 0 : value;
535
+ }).test(
536
+ "matchesOptionOrPattern",
537
+ ({ originalValue }) => {
538
+ return `The option ${JSON.stringify(originalValue)} is not valid.`;
539
+ },
540
+ (castValue, { originalValue }) => {
541
+ if (typeof originalValue !== "boolean" && castValue !== void 0)
542
+ return false;
543
+ return validateRadioOrSelectOptions(castValue, options);
544
+ }
545
+ );
546
+ },
529
547
  number: (0, import_yup.number)().typeError("The value must be a number").nullable(),
530
548
  file: (0, import_yup.array)().nullable(),
531
549
  email: (0, import_yup.string)().trim().email("Please enter a valid email address").nullable(),
@@ -574,7 +592,14 @@ var getYupSchema = ({ inputType, ...field }) => {
574
592
  const hasOptions = field.options?.length > 0;
575
593
  const generateOptionSchema = (type) => {
576
594
  const optionValues = getOptions(field);
577
- return type === "number" ? yupSchemas.radioOrSelectNumber(optionValues) : yupSchemas.radioOrSelectString(optionValues);
595
+ switch (type) {
596
+ case "number":
597
+ return yupSchemas.radioOrSelectNumber(optionValues);
598
+ case "boolean":
599
+ return yupSchemas.radioOrSelectBoolean(optionValues);
600
+ default:
601
+ return yupSchemas.radioOrSelectString(optionValues);
602
+ }
578
603
  };
579
604
  if (hasOptions) {
580
605
  if (Array.isArray(field.jsonType)) {
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  /*!
3
3
  Copyright (c) 2024 Remote Technology, Inc.
4
- NPM Package: @remoteoss/json-schema-form@0.11.2-beta.0
5
- Generated: Tue, 30 Jul 2024 12:00:17 GMT
4
+ NPM Package: @remoteoss/json-schema-form@0.11.3-beta.0
5
+ Generated: Mon, 19 Aug 2024 17:56:28 GMT
6
6
 
7
7
  MIT License
8
8
 
@@ -489,6 +489,24 @@ var yupSchemas = {
489
489
  return validateRadioOrSelectOptions(value, options);
490
490
  }
491
491
  ).nullable(),
492
+ radioOrSelectBoolean: (options) => {
493
+ return boolean().nullable().transform((value) => {
494
+ if (options?.some((option) => option.value === null)) {
495
+ return value;
496
+ }
497
+ return value === null ? void 0 : value;
498
+ }).test(
499
+ "matchesOptionOrPattern",
500
+ ({ originalValue }) => {
501
+ return `The option ${JSON.stringify(originalValue)} is not valid.`;
502
+ },
503
+ (castValue, { originalValue }) => {
504
+ if (typeof originalValue !== "boolean" && castValue !== void 0)
505
+ return false;
506
+ return validateRadioOrSelectOptions(castValue, options);
507
+ }
508
+ );
509
+ },
492
510
  number: number().typeError("The value must be a number").nullable(),
493
511
  file: array().nullable(),
494
512
  email: string().trim().email("Please enter a valid email address").nullable(),
@@ -537,7 +555,14 @@ var getYupSchema = ({ inputType, ...field }) => {
537
555
  const hasOptions = field.options?.length > 0;
538
556
  const generateOptionSchema = (type) => {
539
557
  const optionValues = getOptions(field);
540
- return type === "number" ? yupSchemas.radioOrSelectNumber(optionValues) : yupSchemas.radioOrSelectString(optionValues);
558
+ switch (type) {
559
+ case "number":
560
+ return yupSchemas.radioOrSelectNumber(optionValues);
561
+ case "boolean":
562
+ return yupSchemas.radioOrSelectBoolean(optionValues);
563
+ default:
564
+ return yupSchemas.radioOrSelectString(optionValues);
565
+ }
541
566
  };
542
567
  if (hasOptions) {
543
568
  if (Array.isArray(field.jsonType)) {
@@ -1,8 +1,8 @@
1
1
 
2
2
  /*!
3
3
  Copyright (c) 2024 Remote Technology, Inc.
4
- NPM Package: @remoteoss/json-schema-form@0.11.2-beta.0
5
- Generated: Tue, 30 Jul 2024 12:00:17 GMT
4
+ NPM Package: @remoteoss/json-schema-form@0.11.3-beta.0
5
+ Generated: Mon, 19 Aug 2024 17:56:28 GMT
6
6
 
7
7
  MIT License
8
8
 
@@ -12005,6 +12005,24 @@ var yupSchemas = {
12005
12005
  return validateRadioOrSelectOptions(value, options);
12006
12006
  }
12007
12007
  ).nullable(),
12008
+ radioOrSelectBoolean: (options) => {
12009
+ return boolean2().nullable().transform((value) => {
12010
+ if (options?.some((option) => option.value === null)) {
12011
+ return value;
12012
+ }
12013
+ return value === null ? void 0 : value;
12014
+ }).test(
12015
+ "matchesOptionOrPattern",
12016
+ ({ originalValue }) => {
12017
+ return `The option ${JSON.stringify(originalValue)} is not valid.`;
12018
+ },
12019
+ (castValue, { originalValue }) => {
12020
+ if (typeof originalValue !== "boolean" && castValue !== void 0)
12021
+ return false;
12022
+ return validateRadioOrSelectOptions(castValue, options);
12023
+ }
12024
+ );
12025
+ },
12008
12026
  number: NumberSchema().typeError("The value must be a number").nullable(),
12009
12027
  file: array_default().nullable(),
12010
12028
  email: StringSchema().trim().email("Please enter a valid email address").nullable(),
@@ -12053,7 +12071,14 @@ var getYupSchema = ({ inputType, ...field }) => {
12053
12071
  const hasOptions = field.options?.length > 0;
12054
12072
  const generateOptionSchema = (type) => {
12055
12073
  const optionValues = getOptions(field);
12056
- return type === "number" ? yupSchemas.radioOrSelectNumber(optionValues) : yupSchemas.radioOrSelectString(optionValues);
12074
+ switch (type) {
12075
+ case "number":
12076
+ return yupSchemas.radioOrSelectNumber(optionValues);
12077
+ case "boolean":
12078
+ return yupSchemas.radioOrSelectBoolean(optionValues);
12079
+ default:
12080
+ return yupSchemas.radioOrSelectString(optionValues);
12081
+ }
12057
12082
  };
12058
12083
  if (hasOptions) {
12059
12084
  if (Array.isArray(field.jsonType)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remoteoss/json-schema-form",
3
- "version": "0.11.2-beta.0",
3
+ "version": "0.11.3-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",
@@ -2,7 +2,7 @@ import merge from 'lodash/fp/merge';
2
2
 
3
3
  import { createHeadlessForm } from '../createHeadlessForm';
4
4
 
5
- import { JSONSchemaBuilder, mockFieldset, mockRadioInput } from './helpers';
5
+ import { JSONSchemaBuilder, mockFieldset, mockRadioInputString } from './helpers';
6
6
  import { mockMoneyInput } from './helpers.custom';
7
7
 
8
8
  function friendlyError({ formErrors }) {
@@ -52,7 +52,7 @@ const schemaWithConditional = ({ newProperties } = {}) =>
52
52
  .addInput(
53
53
  merge(
54
54
  {
55
- is_employee: mockRadioInput,
55
+ is_employee: mockRadioInputString,
56
56
  salary: { ...mockMoneyInput, minimum: 0 },
57
57
  bonus: { ...mockMoneyInput, minimum: 0 },
58
58
  },
@@ -8,7 +8,9 @@ import {
8
8
  JSONSchemaBuilder,
9
9
  schemaInputTypeText,
10
10
  schemaInputTypeRadioDeprecated,
11
- schemaInputTypeRadio,
11
+ schemaInputTypeRadioString,
12
+ schemaInputTypeRadioBoolean,
13
+ schemaInputTypeRadioNumber,
12
14
  schemaInputTypeRadioRequiredAndOptional,
13
15
  schemaInputRadioOptionalNull,
14
16
  schemaInputRadioOptionalConventional,
@@ -432,7 +434,7 @@ describe('createHeadlessForm', () => {
432
434
  });
433
435
 
434
436
  describe('field support', () => {
435
- function assertOptionsAllowed({ handleValidation, fieldName, validOptions }) {
437
+ function assertOptionsAllowed({ handleValidation, fieldName, validOptions, type = 'string' }) {
436
438
  const validateForm = (vals) => friendlyError(handleValidation(vals));
437
439
 
438
440
  // All allowed options are valid
@@ -440,22 +442,24 @@ describe('createHeadlessForm', () => {
440
442
  expect(validateForm({ [fieldName]: value })).toBeUndefined();
441
443
  });
442
444
 
443
- // Any other arbitrary value is not valid.
444
- expect(validateForm({ [fieldName]: 'blah-blah' })).toEqual({
445
- [fieldName]: 'The option "blah-blah" is not valid.',
446
- });
445
+ if (type === 'string') {
446
+ // Any other arbitrary value is not valid.
447
+ expect(validateForm({ [fieldName]: 'blah-blah' })).toEqual({
448
+ [fieldName]: 'The option "blah-blah" is not valid.',
449
+ });
450
+
451
+ // As required field, empty string ("") is also considered empty. @BUG RMT-518
452
+ // Expectation: The error to be "The option '' is not valid."
453
+ expect(validateForm({ [fieldName]: '' })).toEqual({
454
+ [fieldName]: 'Required field',
455
+ });
456
+ }
447
457
 
448
458
  // Given undefined, it says it's a required field.
449
459
  expect(validateForm({})).toEqual({
450
460
  [fieldName]: 'Required field',
451
461
  });
452
462
 
453
- // As required field, empty string ("") is also considered empty. @BUG RMT-518
454
- // Expectation: The error to be "The option '' is not valid."
455
- expect(validateForm({ [fieldName]: '' })).toEqual({
456
- [fieldName]: 'Required field',
457
- });
458
-
459
463
  // As required field, null is also considered empty @BUG RMT-518
460
464
  // Expectation: The error to be "The option null is not valid."
461
465
  expect(validateForm({ [fieldName]: null })).toEqual({
@@ -745,8 +749,8 @@ describe('createHeadlessForm', () => {
745
749
  validOptions: ['yes', 'no'],
746
750
  });
747
751
  });
748
- it('support "radio" field type', () => {
749
- const { fields, handleValidation } = createHeadlessForm(schemaInputTypeRadio);
752
+ it('support "radio" field string type', () => {
753
+ const { fields, handleValidation } = createHeadlessForm(schemaInputTypeRadioString);
750
754
 
751
755
  expect(fields).toMatchObject([
752
756
  {
@@ -776,6 +780,86 @@ describe('createHeadlessForm', () => {
776
780
  });
777
781
  });
778
782
 
783
+ it('support "radio" field boolean type', () => {
784
+ const { fields, handleValidation } = createHeadlessForm(schemaInputTypeRadioBoolean);
785
+
786
+ const validateForm = (vals) => friendlyError(handleValidation(vals));
787
+
788
+ expect(fields).toMatchObject([
789
+ {
790
+ description: 'Are you over 18 years old?',
791
+ label: 'Over 18',
792
+ name: 'over_18',
793
+ options: [
794
+ {
795
+ label: 'Yes',
796
+ value: true,
797
+ },
798
+ {
799
+ label: 'No',
800
+ value: false,
801
+ },
802
+ ],
803
+ required: true,
804
+ schema: expect.any(Object),
805
+ type: 'radio',
806
+ },
807
+ ]);
808
+
809
+ assertOptionsAllowed({
810
+ handleValidation,
811
+ fieldName: 'over_18',
812
+ validOptions: [true, false],
813
+ type: schemaInputTypeRadioBoolean.properties.over_18.type,
814
+ });
815
+
816
+ expect(validateForm({ over_18: 'true' })).toEqual({
817
+ over_18: 'The option "true" is not valid.',
818
+ });
819
+ });
820
+
821
+ it('support "radio" field number type', () => {
822
+ const { fields, handleValidation } = createHeadlessForm(schemaInputTypeRadioNumber);
823
+
824
+ const validateForm = (vals) => friendlyError(handleValidation(vals));
825
+
826
+ expect(fields).toMatchObject([
827
+ {
828
+ description: 'How many siblings do you have?',
829
+ label: 'Number of siblings',
830
+ name: 'siblings_count',
831
+ options: [
832
+ {
833
+ label: 'One',
834
+ value: 1,
835
+ },
836
+ {
837
+ label: 'Two',
838
+ value: 2,
839
+ },
840
+ {
841
+ label: 'Three',
842
+ value: 3,
843
+ },
844
+ ],
845
+ required: true,
846
+ schema: expect.any(Object),
847
+ type: 'radio',
848
+ },
849
+ ]);
850
+
851
+ assertOptionsAllowed({
852
+ handleValidation,
853
+ fieldName: 'siblings_count',
854
+ validOptions: [1, 2, 3],
855
+ type: schemaInputTypeRadioNumber.properties.siblings_count.type,
856
+ });
857
+
858
+ expect(validateForm({ siblings_count: '3' })).toEqual({
859
+ siblings_count: 'The option "3" is not valid.',
860
+ });
861
+ });
862
+
779
863
  it('support "radio" optional field', () => {
780
864
  const { fields, handleValidation } = createHeadlessForm(
781
865
  schemaInputTypeRadioRequiredAndOptional
@@ -110,7 +110,7 @@ export const mockRadioInputDeprecated = {
110
110
  },
111
111
  };
112
112
 
113
- export const mockRadioInput = {
113
+ export const mockRadioInputString = {
114
114
  title: 'Has siblings',
115
115
  description: 'Do you have any siblings?',
116
116
  oneOf: [
@@ -129,6 +129,48 @@ export const mockRadioInput = {
129
129
  type: 'string',
130
130
  };
131
131
 
132
+ export const mockRadioInputBoolean = {
133
+ title: 'Over 18',
134
+ description: 'Are you over 18 years old?',
135
+ oneOf: [
136
+ {
137
+ title: 'Yes',
138
+ const: true,
139
+ },
140
+ {
141
+ title: 'No',
142
+ const: false,
143
+ },
144
+ ],
145
+ 'x-jsf-presentation': {
146
+ inputType: 'radio',
147
+ },
148
+ type: 'boolean',
149
+ };
150
+
151
+ export const mockRadioInputNumber = {
152
+ title: 'Number of siblings',
153
+ description: 'How many siblings do you have?',
154
+ oneOf: [
155
+ {
156
+ title: 'One',
157
+ const: 1,
158
+ },
159
+ {
160
+ title: 'Two',
161
+ const: 2,
162
+ },
163
+ {
164
+ title: 'Three',
165
+ const: 3,
166
+ },
167
+ ],
168
+ 'x-jsf-presentation': {
169
+ inputType: 'radio',
170
+ },
171
+ type: 'number',
172
+ };
173
+
132
174
  export const mockRadioCardExpandableInput = {
133
175
  title: 'Experience level',
134
176
  description:
@@ -831,13 +873,27 @@ export const schemaInputTypeRadioDeprecated = {
831
873
  required: ['has_siblings'],
832
874
  };
833
875
 
834
- export const schemaInputTypeRadio = {
876
+ export const schemaInputTypeRadioString = {
835
877
  properties: {
836
- has_siblings: mockRadioInput,
878
+ has_siblings: mockRadioInputString,
837
879
  },
838
880
  required: ['has_siblings'],
839
881
  };
840
882
 
883
+ export const schemaInputTypeRadioBoolean = {
884
+ properties: {
885
+ over_18: mockRadioInputBoolean,
886
+ },
887
+ required: ['over_18'],
888
+ };
889
+
890
+ export const schemaInputTypeRadioNumber = {
891
+ properties: {
892
+ siblings_count: mockRadioInputNumber,
893
+ },
894
+ required: ['siblings_count'],
895
+ };
896
+
841
897
  export const mockRadioInputOptionalNull = {
842
898
  title: 'Has car',
843
899
  oneOf: [
@@ -853,7 +909,7 @@ export const mockRadioInputOptionalNull = {
853
909
 
854
910
  export const schemaInputTypeRadioRequiredAndOptional = {
855
911
  properties: {
856
- has_siblings: mockRadioInput,
912
+ has_siblings: mockRadioInputString,
857
913
  has_car: {
858
914
  ...mockRadioInputOptionalNull,
859
915
  description: 'Do you have a car? (optional field, check oneOf)',
@@ -1440,7 +1496,7 @@ export const schemaAnyOfValidation = JSONSchemaBuilder()
1440
1496
 
1441
1497
  export const schemaWithConditionalPresentationProperties = JSONSchemaBuilder()
1442
1498
  .addInput({
1443
- mock_radio: mockRadioInput,
1499
+ mock_radio: mockRadioInputString,
1444
1500
  })
1445
1501
  .addAllOf([
1446
1502
  {
@@ -1477,7 +1533,7 @@ export const schemaWithConditionalPresentationProperties = JSONSchemaBuilder()
1477
1533
  .build();
1478
1534
 
1479
1535
  export const schemaWithConditionalReadOnlyProperty = JSONSchemaBuilder()
1480
- .addInput({ field_a: mockRadioInput })
1536
+ .addInput({ field_a: mockRadioInputString })
1481
1537
  .addInput({ field_b: mockTextInput })
1482
1538
  .addAllOf([
1483
1539
  {
@@ -1526,7 +1582,7 @@ export const schemaWithConditionalReadOnlyProperty = JSONSchemaBuilder()
1526
1582
  .build();
1527
1583
 
1528
1584
  export const schemaWithConditionalAcknowledgementProperty = JSONSchemaBuilder()
1529
- .addInput({ field_a: mockRadioInput })
1585
+ .addInput({ field_a: mockRadioInputString })
1530
1586
  .addInput({ field_b: mockCheckboxInput })
1531
1587
  .addAllOf([
1532
1588
  {
@@ -1554,9 +1610,9 @@ export const schemaWithConditionalAcknowledgementProperty = JSONSchemaBuilder()
1554
1610
  // Note: The second conditional (field_a_wrong) is incorrect,
1555
1611
  // it's used to test/catch the scenario where devs forget to add the if.required[]
1556
1612
  export const schemaWithWrongConditional = JSONSchemaBuilder()
1557
- .addInput({ field_a: mockRadioInput })
1613
+ .addInput({ field_a: mockRadioInputString })
1558
1614
  .addInput({ field_b: mockTextInput })
1559
- .addInput({ field_a_wrong: mockRadioInput })
1615
+ .addInput({ field_a_wrong: mockRadioInputString })
1560
1616
  .addInput({ field_b_wrong: mockTextInput })
1561
1617
  .addAllOf([
1562
1618
  {