@remoteoss/json-schema-form 0.7.2-dev.20231106093837 → 0.7.4-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,21 @@
1
+ #### 0.7.4-beta.0 (2023-11-07)
2
+
3
+ ##### Chores
4
+
5
+ - Follow-up of #57. Ignore internal attributes from conditional attributes removal ([#58](https://github.com/remoteoss/json-schema-form/pull/58)) ([ee762c2e](https://github.com/remoteoss/json-schema-form/commit/ee762c2e90834a9ec0d7b88af47cefe1e3a03dd1))
6
+
7
+ #### 0.7.3-beta.0 (2023-11-07)
8
+
9
+ ##### Bug Fixes
10
+
11
+ - Remove conditional attributes after the condition is unmatched ([#57](https://github.com/remoteoss/json-schema-form/pull/57)) ([8bac7145](https://github.com/remoteoss/json-schema-form/commit/8bac7145dfdd4136c0613044389666a614eb12f7))
12
+
13
+ #### 0.7.2-beta.0 (2023-11-06)
14
+
15
+ ##### Bug Fixes
16
+
17
+ - **select/radio:** Support oneOf[].pattern validation ([#47](https://github.com/remoteoss/json-schema-form/pull/47)) ([5a4bb592](https://github.com/remoteoss/json-schema-form/commit/5a4bb59266ff595a9cb65f5b261a4ae2f3ad279f))
18
+
1
19
  #### 0.7.1-beta.0 (2023-10-31)
2
20
 
3
21
  ##### Bug Fixes
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.2-dev.20231106093837
5
- Generated: Mon, 06 Nov 2023 09:38:54 GMT
4
+ NPM Package: @remoteoss/json-schema-form@0.7.4-beta.0
5
+ Generated: Tue, 07 Nov 2023 14:43:48 GMT
6
6
 
7
7
  MIT License
8
8
 
@@ -469,13 +469,34 @@ var yupSchemas = {
469
469
  if (value === "") {
470
470
  return void 0;
471
471
  }
472
- if (options?.includes(null)) {
472
+ if (options?.some((option) => option.value === null)) {
473
473
  return value;
474
474
  }
475
475
  return value === null ? void 0 : value;
476
- }).oneOf(options, ({ value }) => {
477
- return `The option ${JSON.stringify(value)} is not valid.`;
478
- });
476
+ }).test(
477
+ /*
478
+ Custom test determines if the value either:
479
+ - Matches a specific option by value
480
+ - Matches a pattern
481
+ If the option is undefined do not test, to allow for optional fields.
482
+ */
483
+ "matchesOptionOrPattern",
484
+ ({ value }) => `The option ${JSON.stringify(value)} is not valid.`,
485
+ (value) => {
486
+ if (value === void 0) {
487
+ return true;
488
+ }
489
+ const exactMatch = options.some((option) => option.value === value);
490
+ if (exactMatch) {
491
+ return true;
492
+ }
493
+ const patternMatch = options.some((option) => option.pattern?.test(value));
494
+ if (patternMatch) {
495
+ return true;
496
+ }
497
+ return false;
498
+ }
499
+ );
479
500
  },
480
501
  date: ({ minDate, maxDate }) => {
481
502
  let dateString = (0, import_yup.string)().nullable().transform((value) => {
@@ -534,12 +555,15 @@ function getRequiredErrorMessage(inputType, { inlineError, configError }) {
534
555
  }
535
556
  var getJsonTypeInArray = (jsonType) => Array.isArray(jsonType) ? jsonType.find((val) => val !== "null") : jsonType;
536
557
  var getOptions = (field) => {
537
- const allValues = field.options?.map((option) => option.value);
558
+ const allValues = field.options?.map((option) => ({
559
+ value: option.value,
560
+ pattern: option.pattern ? new RegExp(option.pattern) : null
561
+ }));
538
562
  const isOptionalWithNull = Array.isArray(field.jsonType) && // @TODO should also check the "oneOf" directly looking for "null"
539
563
  // option but we don't have direct access at this point.
540
564
  // Otherwise the JSON Schema validator will fail as explained in PR#18
541
565
  field.jsonType.includes("null");
542
- return isOptionalWithNull ? [...allValues, null] : allValues;
566
+ return isOptionalWithNull ? [...allValues, { option: null }] : allValues;
543
567
  };
544
568
  var getYupSchema = ({ inputType, ...field }) => {
545
569
  const jsonType = getJsonTypeInArray(field.jsonType);
@@ -1050,8 +1074,11 @@ var dynamicInternalJsfAttrs = [
1050
1074
  // driven from conditionals
1051
1075
  "calculateCustomValidationProperties",
1052
1076
  // To be deprecated in favor of json-logic
1053
- "scopedJsonSchema"
1077
+ "scopedJsonSchema",
1054
1078
  // The respective JSON Schema
1079
+ // HOTFIX/TODO Internal customizations, check test conditions.test.js for more info.
1080
+ "Component",
1081
+ "calculateDynamicProperties"
1055
1082
  ];
1056
1083
  var dynamicInternalJsfAttrsObj = Object.fromEntries(
1057
1084
  dynamicInternalJsfAttrs.map((k) => [k, true])
@@ -1186,7 +1213,7 @@ function updateField(field, requiredFields, node, formValues, logic, config) {
1186
1213
  conditionBranch: node,
1187
1214
  formValues
1188
1215
  });
1189
- updateAttributes(newAttributes, rootFieldAttrs);
1216
+ updateAttributes(newAttributes);
1190
1217
  removeConditionalStaleAttributes(field, newAttributes, rootFieldAttrs);
1191
1218
  }
1192
1219
  if (field.calculateCustomValidationProperties) {
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.2-dev.20231106093837
5
- Generated: Mon, 06 Nov 2023 09:38:54 GMT
4
+ NPM Package: @remoteoss/json-schema-form@0.7.4-beta.0
5
+ Generated: Tue, 07 Nov 2023 14:43:48 GMT
6
6
 
7
7
  MIT License
8
8
 
@@ -433,13 +433,34 @@ var yupSchemas = {
433
433
  if (value === "") {
434
434
  return void 0;
435
435
  }
436
- if (options?.includes(null)) {
436
+ if (options?.some((option) => option.value === null)) {
437
437
  return value;
438
438
  }
439
439
  return value === null ? void 0 : value;
440
- }).oneOf(options, ({ value }) => {
441
- return `The option ${JSON.stringify(value)} is not valid.`;
442
- });
440
+ }).test(
441
+ /*
442
+ Custom test determines if the value either:
443
+ - Matches a specific option by value
444
+ - Matches a pattern
445
+ If the option is undefined do not test, to allow for optional fields.
446
+ */
447
+ "matchesOptionOrPattern",
448
+ ({ value }) => `The option ${JSON.stringify(value)} is not valid.`,
449
+ (value) => {
450
+ if (value === void 0) {
451
+ return true;
452
+ }
453
+ const exactMatch = options.some((option) => option.value === value);
454
+ if (exactMatch) {
455
+ return true;
456
+ }
457
+ const patternMatch = options.some((option) => option.pattern?.test(value));
458
+ if (patternMatch) {
459
+ return true;
460
+ }
461
+ return false;
462
+ }
463
+ );
443
464
  },
444
465
  date: ({ minDate, maxDate }) => {
445
466
  let dateString = string().nullable().transform((value) => {
@@ -498,12 +519,15 @@ function getRequiredErrorMessage(inputType, { inlineError, configError }) {
498
519
  }
499
520
  var getJsonTypeInArray = (jsonType) => Array.isArray(jsonType) ? jsonType.find((val) => val !== "null") : jsonType;
500
521
  var getOptions = (field) => {
501
- const allValues = field.options?.map((option) => option.value);
522
+ const allValues = field.options?.map((option) => ({
523
+ value: option.value,
524
+ pattern: option.pattern ? new RegExp(option.pattern) : null
525
+ }));
502
526
  const isOptionalWithNull = Array.isArray(field.jsonType) && // @TODO should also check the "oneOf" directly looking for "null"
503
527
  // option but we don't have direct access at this point.
504
528
  // Otherwise the JSON Schema validator will fail as explained in PR#18
505
529
  field.jsonType.includes("null");
506
- return isOptionalWithNull ? [...allValues, null] : allValues;
530
+ return isOptionalWithNull ? [...allValues, { option: null }] : allValues;
507
531
  };
508
532
  var getYupSchema = ({ inputType, ...field }) => {
509
533
  const jsonType = getJsonTypeInArray(field.jsonType);
@@ -1014,8 +1038,11 @@ var dynamicInternalJsfAttrs = [
1014
1038
  // driven from conditionals
1015
1039
  "calculateCustomValidationProperties",
1016
1040
  // To be deprecated in favor of json-logic
1017
- "scopedJsonSchema"
1041
+ "scopedJsonSchema",
1018
1042
  // The respective JSON Schema
1043
+ // HOTFIX/TODO Internal customizations, check test conditions.test.js for more info.
1044
+ "Component",
1045
+ "calculateDynamicProperties"
1019
1046
  ];
1020
1047
  var dynamicInternalJsfAttrsObj = Object.fromEntries(
1021
1048
  dynamicInternalJsfAttrs.map((k) => [k, true])
@@ -1150,7 +1177,7 @@ function updateField(field, requiredFields, node, formValues, logic, config) {
1150
1177
  conditionBranch: node,
1151
1178
  formValues
1152
1179
  });
1153
- updateAttributes(newAttributes, rootFieldAttrs);
1180
+ updateAttributes(newAttributes);
1154
1181
  removeConditionalStaleAttributes(field, newAttributes, rootFieldAttrs);
1155
1182
  }
1156
1183
  if (field.calculateCustomValidationProperties) {
@@ -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.2-dev.20231106093837
5
- Generated: Mon, 06 Nov 2023 09:38:54 GMT
4
+ NPM Package: @remoteoss/json-schema-form@0.7.4-beta.0
5
+ Generated: Tue, 07 Nov 2023 14:43:48 GMT
6
6
 
7
7
  MIT License
8
8
 
@@ -11787,13 +11787,34 @@ var yupSchemas = {
11787
11787
  if (value === "") {
11788
11788
  return void 0;
11789
11789
  }
11790
- if (options?.includes(null)) {
11790
+ if (options?.some((option) => option.value === null)) {
11791
11791
  return value;
11792
11792
  }
11793
11793
  return value === null ? void 0 : value;
11794
- }).oneOf(options, ({ value }) => {
11795
- return `The option ${JSON.stringify(value)} is not valid.`;
11796
- });
11794
+ }).test(
11795
+ /*
11796
+ Custom test determines if the value either:
11797
+ - Matches a specific option by value
11798
+ - Matches a pattern
11799
+ If the option is undefined do not test, to allow for optional fields.
11800
+ */
11801
+ "matchesOptionOrPattern",
11802
+ ({ value }) => `The option ${JSON.stringify(value)} is not valid.`,
11803
+ (value) => {
11804
+ if (value === void 0) {
11805
+ return true;
11806
+ }
11807
+ const exactMatch = options.some((option) => option.value === value);
11808
+ if (exactMatch) {
11809
+ return true;
11810
+ }
11811
+ const patternMatch = options.some((option) => option.pattern?.test(value));
11812
+ if (patternMatch) {
11813
+ return true;
11814
+ }
11815
+ return false;
11816
+ }
11817
+ );
11797
11818
  },
11798
11819
  date: ({ minDate, maxDate }) => {
11799
11820
  let dateString = StringSchema().nullable().transform((value) => {
@@ -11852,12 +11873,15 @@ function getRequiredErrorMessage(inputType, { inlineError, configError }) {
11852
11873
  }
11853
11874
  var getJsonTypeInArray = (jsonType) => Array.isArray(jsonType) ? jsonType.find((val) => val !== "null") : jsonType;
11854
11875
  var getOptions = (field) => {
11855
- const allValues = field.options?.map((option) => option.value);
11876
+ const allValues = field.options?.map((option) => ({
11877
+ value: option.value,
11878
+ pattern: option.pattern ? new RegExp(option.pattern) : null
11879
+ }));
11856
11880
  const isOptionalWithNull = Array.isArray(field.jsonType) && // @TODO should also check the "oneOf" directly looking for "null"
11857
11881
  // option but we don't have direct access at this point.
11858
11882
  // Otherwise the JSON Schema validator will fail as explained in PR#18
11859
11883
  field.jsonType.includes("null");
11860
- return isOptionalWithNull ? [...allValues, null] : allValues;
11884
+ return isOptionalWithNull ? [...allValues, { option: null }] : allValues;
11861
11885
  };
11862
11886
  var getYupSchema = ({ inputType, ...field }) => {
11863
11887
  const jsonType = getJsonTypeInArray(field.jsonType);
@@ -12368,8 +12392,11 @@ var dynamicInternalJsfAttrs = [
12368
12392
  // driven from conditionals
12369
12393
  "calculateCustomValidationProperties",
12370
12394
  // To be deprecated in favor of json-logic
12371
- "scopedJsonSchema"
12395
+ "scopedJsonSchema",
12372
12396
  // The respective JSON Schema
12397
+ // HOTFIX/TODO Internal customizations, check test conditions.test.js for more info.
12398
+ "Component",
12399
+ "calculateDynamicProperties"
12373
12400
  ];
12374
12401
  var dynamicInternalJsfAttrsObj = Object.fromEntries(
12375
12402
  dynamicInternalJsfAttrs.map((k) => [k, true])
@@ -12504,7 +12531,7 @@ function updateField(field, requiredFields, node, formValues, logic, config) {
12504
12531
  conditionBranch: node,
12505
12532
  formValues
12506
12533
  });
12507
- updateAttributes(newAttributes, rootFieldAttrs);
12534
+ updateAttributes(newAttributes);
12508
12535
  removeConditionalStaleAttributes(field, newAttributes, rootFieldAttrs);
12509
12536
  }
12510
12537
  if (field.calculateCustomValidationProperties) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remoteoss/json-schema-form",
3
- "version": "0.7.2-dev.20231106093837",
3
+ "version": "0.7.4-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",
@@ -358,4 +358,62 @@ describe('Conditional attributes updated', () => {
358
358
  ],
359
359
  });
360
360
  });
361
+
362
+ it('Keeps custom attribute Component (fieldAttrsFromJsf) (hotfix temporary)', () => {
363
+ // This is necessary as hotfix because we (Remote) use it internally.
364
+ // Not cool, we'll need a better solution asap.
365
+ const { fields, handleValidation } = createHeadlessForm(
366
+ {
367
+ properties: {
368
+ is_full_time: { type: 'string', oneOf: [{ const: 'yes' }, { const: 'no' }] },
369
+ salary_period: {
370
+ type: 'string',
371
+ title: 'Salary period',
372
+ oneOf: [
373
+ { title: 'Weekly', const: 'weekly' },
374
+ { title: 'Monthly', const: 'monthly' },
375
+ ],
376
+ },
377
+ },
378
+ allOf: [
379
+ {
380
+ if: {
381
+ properties: { is_full_time: { const: 'yes' } },
382
+ required: ['is_full_time'],
383
+ },
384
+ then: {
385
+ properties: {
386
+ salary_period: {
387
+ description: 'We recommend montlhy.',
388
+ },
389
+ },
390
+ },
391
+ },
392
+ ],
393
+ },
394
+ {
395
+ strictInputType: false,
396
+ customProperties: {
397
+ salary_period: {
398
+ Component: '<A React Component>',
399
+ calculateDynamicProperties: () => true,
400
+ },
401
+ },
402
+ }
403
+ );
404
+
405
+ // It's there by default
406
+ expect(fields[1].Component).toBe('<A React Component>');
407
+ expect(fields[1].calculateDynamicProperties).toEqual(expect.any(Function));
408
+
409
+ // Given "Yes", it stays there too.
410
+ handleValidation({ is_full_time: 'yes' });
411
+ expect(fields[1].Component).toBe('<A React Component>');
412
+ expect(fields[1].calculateDynamicProperties).toEqual(expect.any(Function));
413
+
414
+ // Given "No", it stays there too.
415
+ handleValidation({ is_full_time: 'no' });
416
+ expect(fields[1].Component).toBe('<A React Component>');
417
+ expect(fields[1].calculateDynamicProperties).toEqual(expect.any(Function));
418
+ });
361
419
  });
@@ -39,6 +39,7 @@ import {
39
39
  mockFileInput,
40
40
  mockRadioCardInput,
41
41
  mockRadioCardExpandableInput,
42
+ mockTelWithPattern,
42
43
  mockTextInput,
43
44
  mockTextInputDeprecated,
44
45
  mockNumberInput,
@@ -1530,6 +1531,51 @@ describe('createHeadlessForm', () => {
1530
1531
  });
1531
1532
  });
1532
1533
 
1534
+ it('supports oneOf pattern validation', () => {
1535
+ const result = createHeadlessForm(mockTelWithPattern);
1536
+
1537
+ expect(result).toMatchObject({
1538
+ fields: [
1539
+ {
1540
+ label: 'Phone number',
1541
+ name: 'phone_number',
1542
+ type: 'tel',
1543
+ required: false,
1544
+ options: [
1545
+ {
1546
+ label: 'Portugal',
1547
+ pattern: '^(\\+351)[0-9]{9,}$',
1548
+ },
1549
+ {
1550
+ label: 'United Kingdom (UK)',
1551
+ pattern: '^(\\+44)[0-9]{1,}$',
1552
+ },
1553
+ {
1554
+ label: 'Bolivia',
1555
+ pattern: '^(\\+591)[0-9]{9,}$',
1556
+ },
1557
+ {
1558
+ label: 'Canada',
1559
+ pattern: '^(\\+1)(206|224)[0-9]{1,}$',
1560
+ },
1561
+ {
1562
+ label: 'United States',
1563
+ pattern: '^(\\+1)[0-9]{1,}$',
1564
+ },
1565
+ ],
1566
+ },
1567
+ ],
1568
+ });
1569
+
1570
+ const fieldValidator = result.fields[0].schema;
1571
+
1572
+ expect(fieldValidator.isValidSync('+351123123123')).toBe(true);
1573
+ expect(() => fieldValidator.validateSync('+35100')).toThrowError(
1574
+ 'The option "+35100" is not valid.'
1575
+ );
1576
+ expect(fieldValidator.isValidSync(undefined)).toBe(true);
1577
+ });
1578
+
1533
1579
  describe('supports "fieldset" field type', () => {
1534
1580
  it('supports basic case', () => {
1535
1581
  const result = createHeadlessForm({
@@ -458,6 +458,46 @@ export const mockCheckboxInput = {
458
458
  type: 'string',
459
459
  };
460
460
 
461
+ export const mockTelWithPattern = {
462
+ properties: {
463
+ phone_number: {
464
+ title: 'Phone number',
465
+ description: 'Enter your telephone number',
466
+ type: 'string',
467
+ 'x-jsf-presentation': {
468
+ inputType: 'tel',
469
+ },
470
+ oneOf: [
471
+ {
472
+ title: 'Portugal',
473
+ pattern: '^(\\+351)[0-9]{9,}$',
474
+ 'x-jsf-presentation': { meta: { countryCode: '351' } },
475
+ },
476
+ {
477
+ title: 'United Kingdom (UK)',
478
+ pattern: '^(\\+44)[0-9]{1,}$',
479
+ 'x-jsf-presentation': { meta: { countryCode: '44' } },
480
+ },
481
+ {
482
+ title: 'Bolivia',
483
+ pattern: '^(\\+591)[0-9]{9,}$',
484
+ 'x-jsf-presentation': { meta: { countryCode: '591' } },
485
+ },
486
+ {
487
+ title: 'Canada',
488
+ pattern: '^(\\+1)(206|224)[0-9]{1,}$',
489
+ 'x-jsf-presentation': { meta: { countryCode: '1' } },
490
+ },
491
+ {
492
+ title: 'United States',
493
+ pattern: '^(\\+1)[0-9]{1,}$',
494
+ 'x-jsf-presentation': { meta: { countryCode: '1' } },
495
+ },
496
+ ],
497
+ },
498
+ },
499
+ };
500
+
461
501
  /**
462
502
  * Compose a schema with lower chance of human error
463
503
  * @param {Object} schema version
@@ -250,7 +250,7 @@ export const schemaWithComputedAttributeThatDoesntExist = {
250
250
  field_a: {
251
251
  type: 'number',
252
252
  'x-jsf-logic-computedAttrs': {
253
- default: 'iDontExist',
253
+ minimum: 'iDontExist',
254
254
  },
255
255
  },
256
256
  },