@remoteoss/json-schema-form 0.7.1-dev.20231026204916 → 0.7.1-dev.20231031082524

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/dist/index.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  /*!
3
3
  Copyright (c) 2023 Remote Technology, Inc.
4
- NPM Package: @remoteoss/json-schema-form@0.7.1-dev.20231026204916
5
- Generated: Thu, 26 Oct 2023 20:49:34 GMT
4
+ NPM Package: @remoteoss/json-schema-form@0.7.1-dev.20231031082524
5
+ Generated: Tue, 31 Oct 2023 08:25:53 GMT
6
6
 
7
7
  MIT License
8
8
 
@@ -461,38 +461,22 @@ var validateMaxDate = (value, minDate) => {
461
461
  };
462
462
  var yupSchemas = {
463
463
  text: validateOnlyStrings,
464
- radioOrSelect: (options) => (0, import_yup.string)().nullable().transform((value) => {
465
- if (value === "") {
466
- return void 0;
464
+ radioOrSelect: (options, isString) => {
465
+ if (isString) {
466
+ return (0, import_yup.string)().nullable();
467
467
  }
468
- if (options?.some((option) => option.value === null)) {
469
- return value;
470
- }
471
- return value === null ? void 0 : value;
472
- }).test(
473
- /*
474
- Custom test determines if the value either:
475
- - Matches a specific option by value
476
- - Matches a pattern
477
- If the option is undefined do not test, to allow for optional fields.
478
- */
479
- "matchesOptionOrPattern",
480
- ({ value }) => `The option ${JSON.stringify(value)} is not valid.`,
481
- (value) => {
482
- if (value === void 0) {
483
- return true;
484
- }
485
- const exactMatch = options.some((option) => option.value === value);
486
- if (exactMatch) {
487
- return true;
468
+ return (0, import_yup.string)().nullable().transform((value) => {
469
+ if (value === "") {
470
+ return void 0;
488
471
  }
489
- const patternMatch = options.some((option) => option.pattern?.test(value));
490
- if (patternMatch) {
491
- return true;
472
+ if (options?.includes(null)) {
473
+ return value;
492
474
  }
493
- return false;
494
- }
495
- ),
475
+ return value === null ? void 0 : value;
476
+ }).oneOf(options, ({ value }) => {
477
+ return `The option ${JSON.stringify(value)} is not valid.`;
478
+ });
479
+ },
496
480
  date: ({ minDate, maxDate }) => {
497
481
  let dateString = (0, import_yup.string)().nullable().transform((value) => {
498
482
  if (value === "") {
@@ -550,21 +534,19 @@ function getRequiredErrorMessage(inputType, { inlineError, configError }) {
550
534
  }
551
535
  var getJsonTypeInArray = (jsonType) => Array.isArray(jsonType) ? jsonType.find((val) => val !== "null") : jsonType;
552
536
  var getOptions = (field) => {
553
- const allValues = field.options?.map((option) => ({
554
- value: option.value,
555
- pattern: option.pattern ? new RegExp(option.pattern) : null
556
- }));
537
+ const allValues = field.options?.map((option) => option.value);
557
538
  const isOptionalWithNull = Array.isArray(field.jsonType) && // @TODO should also check the "oneOf" directly looking for "null"
558
539
  // option but we don't have direct access at this point.
559
540
  // Otherwise the JSON Schema validator will fail as explained in PR#18
560
541
  field.jsonType.includes("null");
561
- return isOptionalWithNull ? [...allValues, { option: null }] : allValues;
542
+ return isOptionalWithNull ? [...allValues, null] : allValues;
562
543
  };
563
544
  var getYupSchema = ({ inputType, ...field }) => {
564
545
  const jsonType = getJsonTypeInArray(field.jsonType);
565
546
  if (field.options?.length > 0) {
547
+ const isString = field.options?.findIndex((option) => option.type === "string") > -1;
566
548
  const optionValues = getOptions(field);
567
- return yupSchemas.radioOrSelect(optionValues);
549
+ return yupSchemas.radioOrSelect(optionValues, isString);
568
550
  }
569
551
  if (field.format === "date") {
570
552
  return yupSchemas.date({ minDate: field.minDate, maxDate: field.maxDate });
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  /*!
3
3
  Copyright (c) 2023 Remote Technology, Inc.
4
- NPM Package: @remoteoss/json-schema-form@0.7.1-dev.20231026204916
5
- Generated: Thu, 26 Oct 2023 20:49:34 GMT
4
+ NPM Package: @remoteoss/json-schema-form@0.7.1-dev.20231031082524
5
+ Generated: Tue, 31 Oct 2023 08:25:53 GMT
6
6
 
7
7
  MIT License
8
8
 
@@ -425,38 +425,22 @@ var validateMaxDate = (value, minDate) => {
425
425
  };
426
426
  var yupSchemas = {
427
427
  text: validateOnlyStrings,
428
- radioOrSelect: (options) => string().nullable().transform((value) => {
429
- if (value === "") {
430
- return void 0;
428
+ radioOrSelect: (options, isString) => {
429
+ if (isString) {
430
+ return string().nullable();
431
431
  }
432
- if (options?.some((option) => option.value === null)) {
433
- return value;
434
- }
435
- return value === null ? void 0 : value;
436
- }).test(
437
- /*
438
- Custom test determines if the value either:
439
- - Matches a specific option by value
440
- - Matches a pattern
441
- If the option is undefined do not test, to allow for optional fields.
442
- */
443
- "matchesOptionOrPattern",
444
- ({ value }) => `The option ${JSON.stringify(value)} is not valid.`,
445
- (value) => {
446
- if (value === void 0) {
447
- return true;
448
- }
449
- const exactMatch = options.some((option) => option.value === value);
450
- if (exactMatch) {
451
- return true;
432
+ return string().nullable().transform((value) => {
433
+ if (value === "") {
434
+ return void 0;
452
435
  }
453
- const patternMatch = options.some((option) => option.pattern?.test(value));
454
- if (patternMatch) {
455
- return true;
436
+ if (options?.includes(null)) {
437
+ return value;
456
438
  }
457
- return false;
458
- }
459
- ),
439
+ return value === null ? void 0 : value;
440
+ }).oneOf(options, ({ value }) => {
441
+ return `The option ${JSON.stringify(value)} is not valid.`;
442
+ });
443
+ },
460
444
  date: ({ minDate, maxDate }) => {
461
445
  let dateString = string().nullable().transform((value) => {
462
446
  if (value === "") {
@@ -514,21 +498,19 @@ function getRequiredErrorMessage(inputType, { inlineError, configError }) {
514
498
  }
515
499
  var getJsonTypeInArray = (jsonType) => Array.isArray(jsonType) ? jsonType.find((val) => val !== "null") : jsonType;
516
500
  var getOptions = (field) => {
517
- const allValues = field.options?.map((option) => ({
518
- value: option.value,
519
- pattern: option.pattern ? new RegExp(option.pattern) : null
520
- }));
501
+ const allValues = field.options?.map((option) => option.value);
521
502
  const isOptionalWithNull = Array.isArray(field.jsonType) && // @TODO should also check the "oneOf" directly looking for "null"
522
503
  // option but we don't have direct access at this point.
523
504
  // Otherwise the JSON Schema validator will fail as explained in PR#18
524
505
  field.jsonType.includes("null");
525
- return isOptionalWithNull ? [...allValues, { option: null }] : allValues;
506
+ return isOptionalWithNull ? [...allValues, null] : allValues;
526
507
  };
527
508
  var getYupSchema = ({ inputType, ...field }) => {
528
509
  const jsonType = getJsonTypeInArray(field.jsonType);
529
510
  if (field.options?.length > 0) {
511
+ const isString = field.options?.findIndex((option) => option.type === "string") > -1;
530
512
  const optionValues = getOptions(field);
531
- return yupSchemas.radioOrSelect(optionValues);
513
+ return yupSchemas.radioOrSelect(optionValues, isString);
532
514
  }
533
515
  if (field.format === "date") {
534
516
  return yupSchemas.date({ minDate: field.minDate, maxDate: field.maxDate });
@@ -1,8 +1,8 @@
1
1
 
2
2
  /*!
3
3
  Copyright (c) 2023 Remote Technology, Inc.
4
- NPM Package: @remoteoss/json-schema-form@0.7.1-dev.20231026204916
5
- Generated: Thu, 26 Oct 2023 20:49:34 GMT
4
+ NPM Package: @remoteoss/json-schema-form@0.7.1-dev.20231031082524
5
+ Generated: Tue, 31 Oct 2023 08:25:53 GMT
6
6
 
7
7
  MIT License
8
8
 
@@ -11779,38 +11779,22 @@ var validateMaxDate = (value, minDate) => {
11779
11779
  };
11780
11780
  var yupSchemas = {
11781
11781
  text: validateOnlyStrings,
11782
- radioOrSelect: (options) => StringSchema().nullable().transform((value) => {
11783
- if (value === "") {
11784
- return void 0;
11782
+ radioOrSelect: (options, isString2) => {
11783
+ if (isString2) {
11784
+ return StringSchema().nullable();
11785
11785
  }
11786
- if (options?.some((option) => option.value === null)) {
11787
- return value;
11788
- }
11789
- return value === null ? void 0 : value;
11790
- }).test(
11791
- /*
11792
- Custom test determines if the value either:
11793
- - Matches a specific option by value
11794
- - Matches a pattern
11795
- If the option is undefined do not test, to allow for optional fields.
11796
- */
11797
- "matchesOptionOrPattern",
11798
- ({ value }) => `The option ${JSON.stringify(value)} is not valid.`,
11799
- (value) => {
11800
- if (value === void 0) {
11801
- return true;
11802
- }
11803
- const exactMatch = options.some((option) => option.value === value);
11804
- if (exactMatch) {
11805
- return true;
11786
+ return StringSchema().nullable().transform((value) => {
11787
+ if (value === "") {
11788
+ return void 0;
11806
11789
  }
11807
- const patternMatch = options.some((option) => option.pattern?.test(value));
11808
- if (patternMatch) {
11809
- return true;
11790
+ if (options?.includes(null)) {
11791
+ return value;
11810
11792
  }
11811
- return false;
11812
- }
11813
- ),
11793
+ return value === null ? void 0 : value;
11794
+ }).oneOf(options, ({ value }) => {
11795
+ return `The option ${JSON.stringify(value)} is not valid.`;
11796
+ });
11797
+ },
11814
11798
  date: ({ minDate, maxDate }) => {
11815
11799
  let dateString = StringSchema().nullable().transform((value) => {
11816
11800
  if (value === "") {
@@ -11868,21 +11852,19 @@ function getRequiredErrorMessage(inputType, { inlineError, configError }) {
11868
11852
  }
11869
11853
  var getJsonTypeInArray = (jsonType) => Array.isArray(jsonType) ? jsonType.find((val) => val !== "null") : jsonType;
11870
11854
  var getOptions = (field) => {
11871
- const allValues = field.options?.map((option) => ({
11872
- value: option.value,
11873
- pattern: option.pattern ? new RegExp(option.pattern) : null
11874
- }));
11855
+ const allValues = field.options?.map((option) => option.value);
11875
11856
  const isOptionalWithNull = Array.isArray(field.jsonType) && // @TODO should also check the "oneOf" directly looking for "null"
11876
11857
  // option but we don't have direct access at this point.
11877
11858
  // Otherwise the JSON Schema validator will fail as explained in PR#18
11878
11859
  field.jsonType.includes("null");
11879
- return isOptionalWithNull ? [...allValues, { option: null }] : allValues;
11860
+ return isOptionalWithNull ? [...allValues, null] : allValues;
11880
11861
  };
11881
11862
  var getYupSchema = ({ inputType, ...field }) => {
11882
11863
  const jsonType = getJsonTypeInArray(field.jsonType);
11883
11864
  if (field.options?.length > 0) {
11865
+ const isString2 = field.options?.findIndex((option) => option.type === "string") > -1;
11884
11866
  const optionValues = getOptions(field);
11885
- return yupSchemas.radioOrSelect(optionValues);
11867
+ return yupSchemas.radioOrSelect(optionValues, isString2);
11886
11868
  }
11887
11869
  if (field.format === "date") {
11888
11870
  return yupSchemas.date({ minDate: field.minDate, maxDate: field.maxDate });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remoteoss/json-schema-form",
3
- "version": "0.7.1-dev.20231026204916",
3
+ "version": "0.7.1-dev.20231031082524",
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",
@@ -15,6 +15,7 @@ import {
15
15
  schemaInputTypeRadioOptionsWithDetails,
16
16
  schemaInputTypeSelectSoloDeprecated,
17
17
  schemaInputTypeSelectSolo,
18
+ schemaInputTypeSelectString,
18
19
  schemaInputTypeSelectMultipleDeprecated,
19
20
  schemaInputTypeSelectMultiple,
20
21
  schemaInputTypeSelectMultipleOptional,
@@ -38,7 +39,6 @@ import {
38
39
  mockFileInput,
39
40
  mockRadioCardInput,
40
41
  mockRadioCardExpandableInput,
41
- mockTelWithPattern,
42
42
  mockTextInput,
43
43
  mockTextInputDeprecated,
44
44
  mockNumberInput,
@@ -431,7 +431,7 @@ describe('createHeadlessForm', () => {
431
431
  });
432
432
 
433
433
  describe('field support', () => {
434
- function assertOptionsAllowed({ handleValidation, fieldName, validOptions }) {
434
+ function assertOptionsAllowed({ handleValidation, fieldName, validOptions, isString = false }) {
435
435
  const validateForm = (vals) => friendlyError(handleValidation(vals));
436
436
 
437
437
  // All allowed options are valid
@@ -439,27 +439,34 @@ describe('createHeadlessForm', () => {
439
439
  expect(validateForm({ [fieldName]: value })).toBeUndefined();
440
440
  });
441
441
 
442
- // Any other arbitrary value is not valid.
443
- expect(validateForm({ [fieldName]: 'blah-blah' })).toEqual({
444
- [fieldName]: 'The option "blah-blah" is not valid.',
445
- });
442
+ if (!isString) {
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
+ });
446
447
 
447
- // Given undefined, it says it's a required field.
448
- expect(validateForm({})).toEqual({
449
- [fieldName]: 'Required field',
450
- });
448
+ // Given undefined, it says it's a required field.
449
+ expect(validateForm({})).toEqual({
450
+ [fieldName]: 'Required field',
451
+ });
451
452
 
452
- // As required field, empty string ("") is also considered empty. @BUG RMT-518
453
- // Expectation: The error to be "The option '' is not valid."
454
- expect(validateForm({ [fieldName]: '' })).toEqual({
455
- [fieldName]: 'Required field',
456
- });
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
+ });
457
458
 
458
- // As required field, null is also considered empty @BUG RMT-518
459
- // Expectation: The error to be "The option null is not valid."
460
- expect(validateForm({ [fieldName]: null })).toEqual({
461
- [fieldName]: 'Required field',
462
- });
459
+ // As required field, null is also considered empty @BUG RMT-518
460
+ // Expectation: The error to be "The option null is not valid."
461
+ expect(validateForm({ [fieldName]: null })).toEqual({
462
+ [fieldName]: 'Required field',
463
+ });
464
+ }
465
+
466
+ if (isString) {
467
+ // Any other arbitrary value is valid.
468
+ expect(validateForm({ [fieldName]: 'blah-blah' })).toBeUndefined();
469
+ }
463
470
  }
464
471
 
465
472
  it('support "text" field type', () => {
@@ -631,6 +638,41 @@ describe('createHeadlessForm', () => {
631
638
  });
632
639
  });
633
640
 
641
+ it('supports "select" field type with string option', () => {
642
+ const { fields, handleValidation } = createHeadlessForm(schemaInputTypeSelectString);
643
+ const fieldSelect = fields[0];
644
+ expect(fieldSelect).toMatchObject({
645
+ name: 'browsers',
646
+ label: 'Browsers (solo)',
647
+ description: 'This solo select also includes a disabled option.',
648
+ options: [
649
+ {
650
+ value: 'chr',
651
+ label: 'Chrome',
652
+ },
653
+ {
654
+ value: 'ff',
655
+ label: 'Firefox',
656
+ },
657
+ {
658
+ value: 'ie',
659
+ label: 'Internet Explorer',
660
+ disabled: true,
661
+ },
662
+ { value: undefined, type: 'string', label: '{Create another}' },
663
+ ],
664
+ });
665
+
666
+ expect(fieldSelect).not.toHaveProperty('multiple');
667
+
668
+ assertOptionsAllowed({
669
+ handleValidation,
670
+ fieldName: 'browsers',
671
+ validOptions: ['chr', 'ff', 'ie'],
672
+ isString: true,
673
+ });
674
+ });
675
+
634
676
  it('supports "select" field type with multiple options @deprecated', () => {
635
677
  const result = createHeadlessForm(schemaInputTypeSelectMultipleDeprecated);
636
678
  expect(result).toMatchObject({
@@ -1443,51 +1485,6 @@ describe('createHeadlessForm', () => {
1443
1485
  });
1444
1486
  });
1445
1487
 
1446
- it('supports oneOf pattern validation', () => {
1447
- const result = createHeadlessForm(mockTelWithPattern);
1448
-
1449
- expect(result).toMatchObject({
1450
- fields: [
1451
- {
1452
- label: 'Phone number',
1453
- name: 'phone_number',
1454
- type: 'tel',
1455
- required: false,
1456
- options: [
1457
- {
1458
- label: 'Portugal',
1459
- pattern: '^(\\+351)[0-9]{9,}$',
1460
- },
1461
- {
1462
- label: 'United Kingdom (UK)',
1463
- pattern: '^(\\+44)[0-9]{1,}$',
1464
- },
1465
- {
1466
- label: 'Bolivia',
1467
- pattern: '^(\\+591)[0-9]{9,}$',
1468
- },
1469
- {
1470
- label: 'Canada',
1471
- pattern: '^(\\+1)(206|224)[0-9]{1,}$',
1472
- },
1473
- {
1474
- label: 'United States',
1475
- pattern: '^(\\+1)[0-9]{1,}$',
1476
- },
1477
- ],
1478
- },
1479
- ],
1480
- });
1481
-
1482
- const fieldValidator = result.fields[0].schema;
1483
-
1484
- expect(fieldValidator.isValidSync('+351123123123')).toBe(true);
1485
- expect(() => fieldValidator.validateSync('+35100')).toThrowError(
1486
- 'The option "+35100" is not valid.'
1487
- );
1488
- expect(fieldValidator.isValidSync(undefined)).toBe(true);
1489
- });
1490
-
1491
1488
  describe('supports "fieldset" field type', () => {
1492
1489
  it('supports basic case', () => {
1493
1490
  const result = createHeadlessForm({
@@ -238,6 +238,11 @@ export const mockSelectInputSolo = {
238
238
  },
239
239
  };
240
240
 
241
+ export const mockSelectInputSoloCreatable = {
242
+ ...mockSelectInputSolo,
243
+ oneOf: [...mockSelectInputSolo.oneOf, { type: 'string', title: '{Create another}' }],
244
+ };
245
+
241
246
  export const mockSelectInputMultiple = {
242
247
  title: 'Browsers (multiple)',
243
248
  description: 'This multi-select also includes a disabled option.',
@@ -453,46 +458,6 @@ export const mockCheckboxInput = {
453
458
  type: 'string',
454
459
  };
455
460
 
456
- export const mockTelWithPattern = {
457
- properties: {
458
- phone_number: {
459
- title: 'Phone number',
460
- description: 'Enter your telephone number',
461
- type: 'string',
462
- 'x-jsf-presentation': {
463
- inputType: 'tel',
464
- },
465
- oneOf: [
466
- {
467
- title: 'Portugal',
468
- pattern: '^(\\+351)[0-9]{9,}$',
469
- 'x-jsf-presentation': { meta: { countryCode: '351' } },
470
- },
471
- {
472
- title: 'United Kingdom (UK)',
473
- pattern: '^(\\+44)[0-9]{1,}$',
474
- 'x-jsf-presentation': { meta: { countryCode: '44' } },
475
- },
476
- {
477
- title: 'Bolivia',
478
- pattern: '^(\\+591)[0-9]{9,}$',
479
- 'x-jsf-presentation': { meta: { countryCode: '591' } },
480
- },
481
- {
482
- title: 'Canada',
483
- pattern: '^(\\+1)(206|224)[0-9]{1,}$',
484
- 'x-jsf-presentation': { meta: { countryCode: '1' } },
485
- },
486
- {
487
- title: 'United States',
488
- pattern: '^(\\+1)[0-9]{1,}$',
489
- 'x-jsf-presentation': { meta: { countryCode: '1' } },
490
- },
491
- ],
492
- },
493
- },
494
- };
495
-
496
461
  /**
497
462
  * Compose a schema with lower chance of human error
498
463
  * @param {Object} schema version
@@ -937,6 +902,10 @@ export const schemaInputTypeSelectSolo = JSONSchemaBuilder()
937
902
  .setRequiredFields(['browsers'])
938
903
  .build();
939
904
 
905
+ export const schemaInputTypeSelectString = JSONSchemaBuilder().addInput({
906
+ browsers: mockSelectInputSoloCreatable,
907
+ });
908
+
940
909
  /** @deprecated */
941
910
  export const schemaInputTypeSelectMultipleDeprecated = JSONSchemaBuilder()
942
911
  .addInput({