@remoteoss/json-schema-form 0.4.1-dev.20230703203242 → 0.4.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 CHANGED
@@ -1,3 +1,16 @@
1
+ #### 0.4.2-beta.0 (2023-07-20)
2
+
3
+ ##### Bug Fixes
4
+
5
+ * **date:** Validate based on minDate and maxDate ([#30](https://github.com/remoteoss/json-schema-form/pull/30)) ([01c0143e](https://github.com/remoteoss/json-schema-form/commit/01c0143ea4a3775f9489ae6cb8fd99a90b3f1394))
6
+
7
+ #### 0.4.1-beta.0 (2023-07-03)
8
+
9
+ ##### Bug Fixes
10
+
11
+ * **fieldset:** support root conditionals for fieldsets ([#23](https://github.com/remoteoss/json-schema-form/pull/23)) ([65d87b3a](https://github.com/remoteoss/json-schema-form/commit/65d87b3a93018f0729aed565000eb2a2ce1f2ce7))
12
+ * **select/radio:** Accept just the values in options (plus `''` and `null` for backward-compatibility) ([#18](https://github.com/remoteoss/json-schema-form/pull/18)) ([37501d2d](https://github.com/remoteoss/json-schema-form/commit/37501d2ddafdd5e207b34d2ca3f6b7b7a1006e9d))
13
+
1
14
  #### 0.4.0-beta.0 (2023-06-22)
2
15
 
3
16
  ##### New Features
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.4.1-dev.20230703203242
5
- Generated: Mon, 03 Jul 2023 20:32:50 GMT
4
+ NPM Package: @remoteoss/json-schema-form@0.4.2-beta.0
5
+ Generated: Thu, 20 Jul 2023 11:13:46 GMT
6
6
 
7
7
  MIT License
8
8
 
@@ -381,6 +381,25 @@ var validateOnlyStrings = (0, import_yup.string)().trim().nullable().test(
381
381
  return true;
382
382
  }
383
383
  );
384
+ var compareDates = (d1, d2) => {
385
+ let date1 = new Date(d1).getTime();
386
+ let date2 = new Date(d2).getTime();
387
+ if (date1 < date2) {
388
+ return "LESSER";
389
+ } else if (date1 > date2) {
390
+ return "GREATER";
391
+ } else {
392
+ return "EQUAL";
393
+ }
394
+ };
395
+ var validateMinDate = (value, minDate) => {
396
+ const compare = compareDates(value, minDate);
397
+ return compare === "GREATER" || compare === "EQUAL" ? true : false;
398
+ };
399
+ var validateMaxDate = (value, minDate) => {
400
+ const compare = compareDates(value, minDate);
401
+ return compare === "LESSER" || compare === "EQUAL" ? true : false;
402
+ };
384
403
  var yupSchemas = {
385
404
  text: validateOnlyStrings,
386
405
  radioOrSelect: (options) => (0, import_yup.string)().nullable().transform((value) => {
@@ -394,10 +413,32 @@ var yupSchemas = {
394
413
  }).oneOf(options, ({ value }) => {
395
414
  return `The option ${JSON.stringify(value)} is not valid.`;
396
415
  }),
397
- date: (0, import_yup.string)().nullable().trim().matches(
398
- /(?:\d){4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9]|3[0-1])/,
399
- `Must be a valid date in ${DEFAULT_DATE_FORMAT.toLocaleLowerCase()} format. e.g. ${todayDateHint}`
400
- ),
416
+ date: ({ minDate, maxDate }) => {
417
+ let dateString = (0, import_yup.string)().nullable().transform((value) => {
418
+ if (value === "") {
419
+ return void 0;
420
+ }
421
+ return value === null ? void 0 : value;
422
+ }).trim().matches(
423
+ /(?:\d){4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9]|3[0-1])/,
424
+ `Must be a valid date in ${DEFAULT_DATE_FORMAT.toLocaleLowerCase()} format. e.g. ${todayDateHint}`
425
+ );
426
+ if (minDate) {
427
+ dateString = dateString.test(
428
+ "minDate",
429
+ `The date must be ${minDate} or after.`,
430
+ (value) => validateMinDate(value, minDate)
431
+ );
432
+ }
433
+ if (maxDate) {
434
+ dateString = dateString.test(
435
+ "maxDate",
436
+ `The date must be ${maxDate} or before.`,
437
+ (value) => validateMaxDate(value, maxDate)
438
+ );
439
+ }
440
+ return dateString;
441
+ },
401
442
  number: (0, import_yup.number)().typeError("The value must be a number").nullable(),
402
443
  file: (0, import_yup.array)().nullable(),
403
444
  email: (0, import_yup.string)().trim().email("Please enter a valid email address").nullable(),
@@ -442,6 +483,9 @@ var getYupSchema = ({ inputType, ...field }) => {
442
483
  const optionValues = getOptions(field);
443
484
  return yupSchemas.radioOrSelect(optionValues);
444
485
  }
486
+ if (field.format === "date") {
487
+ return yupSchemas.date({ minDate: field.minDate, maxDate: field.maxDate });
488
+ }
445
489
  return yupSchemas[inputType] || yupSchemasToJsonTypes[jsonType];
446
490
  };
447
491
  function buildYupSchema(field, config) {
@@ -901,6 +945,7 @@ function extractParametersFromNode(schemaNode) {
901
945
  maxFileSize: node.maxFileSize,
902
946
  // @deprecated in favor of presentation.maxFileSize
903
947
  default: node.default,
948
+ format: node.format,
904
949
  // Checkboxes conditions
905
950
  // — For checkboxes that only accept one value (string)
906
951
  ...presentation?.inputType === "checkbox" && { checkboxValue: node.const },
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.4.1-dev.20230703203242
5
- Generated: Mon, 03 Jul 2023 20:32:50 GMT
4
+ NPM Package: @remoteoss/json-schema-form@0.4.2-beta.0
5
+ Generated: Thu, 20 Jul 2023 11:13:46 GMT
6
6
 
7
7
  MIT License
8
8
 
@@ -345,6 +345,25 @@ var validateOnlyStrings = string().trim().nullable().test(
345
345
  return true;
346
346
  }
347
347
  );
348
+ var compareDates = (d1, d2) => {
349
+ let date1 = new Date(d1).getTime();
350
+ let date2 = new Date(d2).getTime();
351
+ if (date1 < date2) {
352
+ return "LESSER";
353
+ } else if (date1 > date2) {
354
+ return "GREATER";
355
+ } else {
356
+ return "EQUAL";
357
+ }
358
+ };
359
+ var validateMinDate = (value, minDate) => {
360
+ const compare = compareDates(value, minDate);
361
+ return compare === "GREATER" || compare === "EQUAL" ? true : false;
362
+ };
363
+ var validateMaxDate = (value, minDate) => {
364
+ const compare = compareDates(value, minDate);
365
+ return compare === "LESSER" || compare === "EQUAL" ? true : false;
366
+ };
348
367
  var yupSchemas = {
349
368
  text: validateOnlyStrings,
350
369
  radioOrSelect: (options) => string().nullable().transform((value) => {
@@ -358,10 +377,32 @@ var yupSchemas = {
358
377
  }).oneOf(options, ({ value }) => {
359
378
  return `The option ${JSON.stringify(value)} is not valid.`;
360
379
  }),
361
- date: string().nullable().trim().matches(
362
- /(?:\d){4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9]|3[0-1])/,
363
- `Must be a valid date in ${DEFAULT_DATE_FORMAT.toLocaleLowerCase()} format. e.g. ${todayDateHint}`
364
- ),
380
+ date: ({ minDate, maxDate }) => {
381
+ let dateString = string().nullable().transform((value) => {
382
+ if (value === "") {
383
+ return void 0;
384
+ }
385
+ return value === null ? void 0 : value;
386
+ }).trim().matches(
387
+ /(?:\d){4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9]|3[0-1])/,
388
+ `Must be a valid date in ${DEFAULT_DATE_FORMAT.toLocaleLowerCase()} format. e.g. ${todayDateHint}`
389
+ );
390
+ if (minDate) {
391
+ dateString = dateString.test(
392
+ "minDate",
393
+ `The date must be ${minDate} or after.`,
394
+ (value) => validateMinDate(value, minDate)
395
+ );
396
+ }
397
+ if (maxDate) {
398
+ dateString = dateString.test(
399
+ "maxDate",
400
+ `The date must be ${maxDate} or before.`,
401
+ (value) => validateMaxDate(value, maxDate)
402
+ );
403
+ }
404
+ return dateString;
405
+ },
365
406
  number: number().typeError("The value must be a number").nullable(),
366
407
  file: array().nullable(),
367
408
  email: string().trim().email("Please enter a valid email address").nullable(),
@@ -406,6 +447,9 @@ var getYupSchema = ({ inputType, ...field }) => {
406
447
  const optionValues = getOptions(field);
407
448
  return yupSchemas.radioOrSelect(optionValues);
408
449
  }
450
+ if (field.format === "date") {
451
+ return yupSchemas.date({ minDate: field.minDate, maxDate: field.maxDate });
452
+ }
409
453
  return yupSchemas[inputType] || yupSchemasToJsonTypes[jsonType];
410
454
  };
411
455
  function buildYupSchema(field, config) {
@@ -865,6 +909,7 @@ function extractParametersFromNode(schemaNode) {
865
909
  maxFileSize: node.maxFileSize,
866
910
  // @deprecated in favor of presentation.maxFileSize
867
911
  default: node.default,
912
+ format: node.format,
868
913
  // Checkboxes conditions
869
914
  // — For checkboxes that only accept one value (string)
870
915
  ...presentation?.inputType === "checkbox" && { checkboxValue: node.const },
@@ -1,8 +1,8 @@
1
1
 
2
2
  /*!
3
3
  Copyright (c) 2023 Remote Technology, Inc.
4
- NPM Package: @remoteoss/json-schema-form@0.4.1-dev.20230703203242
5
- Generated: Mon, 03 Jul 2023 20:32:50 GMT
4
+ NPM Package: @remoteoss/json-schema-form@0.4.2-beta.0
5
+ Generated: Thu, 20 Jul 2023 11:13:46 GMT
6
6
 
7
7
  MIT License
8
8
 
@@ -11321,6 +11321,25 @@ var validateOnlyStrings = StringSchema().trim().nullable().test(
11321
11321
  return true;
11322
11322
  }
11323
11323
  );
11324
+ var compareDates = (d1, d2) => {
11325
+ let date1 = new Date(d1).getTime();
11326
+ let date2 = new Date(d2).getTime();
11327
+ if (date1 < date2) {
11328
+ return "LESSER";
11329
+ } else if (date1 > date2) {
11330
+ return "GREATER";
11331
+ } else {
11332
+ return "EQUAL";
11333
+ }
11334
+ };
11335
+ var validateMinDate = (value, minDate) => {
11336
+ const compare = compareDates(value, minDate);
11337
+ return compare === "GREATER" || compare === "EQUAL" ? true : false;
11338
+ };
11339
+ var validateMaxDate = (value, minDate) => {
11340
+ const compare = compareDates(value, minDate);
11341
+ return compare === "LESSER" || compare === "EQUAL" ? true : false;
11342
+ };
11324
11343
  var yupSchemas = {
11325
11344
  text: validateOnlyStrings,
11326
11345
  radioOrSelect: (options) => StringSchema().nullable().transform((value) => {
@@ -11334,10 +11353,32 @@ var yupSchemas = {
11334
11353
  }).oneOf(options, ({ value }) => {
11335
11354
  return `The option ${JSON.stringify(value)} is not valid.`;
11336
11355
  }),
11337
- date: StringSchema().nullable().trim().matches(
11338
- /(?:\d){4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9]|3[0-1])/,
11339
- `Must be a valid date in ${DEFAULT_DATE_FORMAT.toLocaleLowerCase()} format. e.g. ${todayDateHint}`
11340
- ),
11356
+ date: ({ minDate, maxDate }) => {
11357
+ let dateString = StringSchema().nullable().transform((value) => {
11358
+ if (value === "") {
11359
+ return void 0;
11360
+ }
11361
+ return value === null ? void 0 : value;
11362
+ }).trim().matches(
11363
+ /(?:\d){4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9]|3[0-1])/,
11364
+ `Must be a valid date in ${DEFAULT_DATE_FORMAT.toLocaleLowerCase()} format. e.g. ${todayDateHint}`
11365
+ );
11366
+ if (minDate) {
11367
+ dateString = dateString.test(
11368
+ "minDate",
11369
+ `The date must be ${minDate} or after.`,
11370
+ (value) => validateMinDate(value, minDate)
11371
+ );
11372
+ }
11373
+ if (maxDate) {
11374
+ dateString = dateString.test(
11375
+ "maxDate",
11376
+ `The date must be ${maxDate} or before.`,
11377
+ (value) => validateMaxDate(value, maxDate)
11378
+ );
11379
+ }
11380
+ return dateString;
11381
+ },
11341
11382
  number: NumberSchema().typeError("The value must be a number").nullable(),
11342
11383
  file: array_default().nullable(),
11343
11384
  email: StringSchema().trim().email("Please enter a valid email address").nullable(),
@@ -11382,6 +11423,9 @@ var getYupSchema = ({ inputType, ...field }) => {
11382
11423
  const optionValues = getOptions(field);
11383
11424
  return yupSchemas.radioOrSelect(optionValues);
11384
11425
  }
11426
+ if (field.format === "date") {
11427
+ return yupSchemas.date({ minDate: field.minDate, maxDate: field.maxDate });
11428
+ }
11385
11429
  return yupSchemas[inputType] || yupSchemasToJsonTypes[jsonType];
11386
11430
  };
11387
11431
  function buildYupSchema(field, config) {
@@ -11841,6 +11885,7 @@ function extractParametersFromNode(schemaNode) {
11841
11885
  maxFileSize: node.maxFileSize,
11842
11886
  // @deprecated in favor of presentation.maxFileSize
11843
11887
  default: node.default,
11888
+ format: node.format,
11844
11889
  // Checkboxes conditions
11845
11890
  // — For checkboxes that only accept one value (string)
11846
11891
  ...presentation?.inputType === "checkbox" && { checkboxValue: node.const },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remoteoss/json-schema-form",
3
- "version": "0.4.1-dev.20230703203242",
3
+ "version": "0.4.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",
@@ -439,23 +439,15 @@ describe('createHeadlessForm', () => {
439
439
 
440
440
  // All allowed options are valid
441
441
  validOptions.forEach((value) => {
442
- expect(
443
- validateForm({
444
- [fieldName]: value,
445
- })
446
- ).toBeUndefined();
442
+ expect(validateForm({ [fieldName]: value })).toBeUndefined();
447
443
  });
448
444
 
449
445
  // Any other arbitrary value is not valid.
450
- expect(
451
- validateForm({
452
- [fieldName]: 'blah-blah',
453
- })
454
- ).toEqual({
446
+ expect(validateForm({ [fieldName]: 'blah-blah' })).toEqual({
455
447
  [fieldName]: 'The option "blah-blah" is not valid.',
456
448
  });
457
449
 
458
- // This is a required field:
450
+ // Given undefined, it says it's a required field.
459
451
  expect(validateForm({})).toEqual({
460
452
  [fieldName]: 'Required field',
461
453
  });
@@ -831,6 +823,9 @@ describe('createHeadlessForm', () => {
831
823
 
832
824
  describe('support "radio" optional field - more examples @BUG RMT-518', () => {
833
825
  function assertCommonBehavior(validateForm) {
826
+ // Note: Very similar to assertOptionsAllowed()
827
+ // We could reuse it in a next iteration.
828
+
834
829
  // Happy path
835
830
  expect(validateForm({ has_car: 'yes' })).toBeUndefined();
836
831
 
@@ -1014,30 +1009,112 @@ describe('createHeadlessForm', () => {
1014
1009
  });
1015
1010
 
1016
1011
  it('support "date" field type', () => {
1017
- const result = createHeadlessForm(schemaInputTypeDate);
1012
+ const { fields, handleValidation } = createHeadlessForm(schemaInputTypeDate);
1018
1013
 
1019
- expect(result).toMatchObject({
1020
- fields: [
1021
- {
1022
- label: 'Birthdate',
1023
- name: 'birthdate',
1024
- required: true,
1025
- schema: expect.any(Object),
1026
- type: 'date',
1027
- maxLength: 10,
1028
- minDate: '1922-03-01',
1029
- maxDate: '2022-03-01',
1030
- },
1031
- ],
1014
+ const validateForm = (vals) => friendlyError(handleValidation(vals));
1015
+
1016
+ expect(fields[0]).toMatchObject({
1017
+ label: 'Birthdate',
1018
+ name: 'birthdate',
1019
+ required: true,
1020
+ schema: expect.any(Object),
1021
+ type: 'date',
1022
+ minDate: '1922-03-01',
1023
+ maxDate: '2022-03-17',
1032
1024
  });
1033
1025
 
1034
- const fieldValidator = result.fields[0].schema;
1035
1026
  const todayDateHint = new Date().toISOString().substring(0, 10);
1036
- expect(fieldValidator.isValidSync('2020-10-10')).toBe(true);
1037
- expect(fieldValidator.isValidSync('2020-13-10')).toBe(false);
1038
- expect(() => fieldValidator.validateSync('')).toThrowError(
1039
- `Must be a valid date in yyyy-mm-dd format. e.g. ${todayDateHint}`
1040
- );
1027
+
1028
+ expect(validateForm({})).toEqual({
1029
+ birthdate: 'Required field',
1030
+ });
1031
+
1032
+ expect(validateForm({ birthdate: '2020-10-10' })).toBeUndefined();
1033
+ expect(validateForm({ birthdate: '2020-13-10' })).toEqual({
1034
+ birthdate: `Must be a valid date in yyyy-mm-dd format. e.g. ${todayDateHint}`,
1035
+ });
1036
+ });
1037
+
1038
+ it('support "date" field type with a minDate', () => {
1039
+ const { fields, handleValidation } = createHeadlessForm(schemaInputTypeDate);
1040
+
1041
+ const validateForm = (vals) => friendlyError(handleValidation(vals));
1042
+
1043
+ expect(fields[0]).toMatchObject({
1044
+ label: 'Birthdate',
1045
+ name: 'birthdate',
1046
+ required: true,
1047
+ schema: expect.any(Object),
1048
+ type: 'date',
1049
+ minDate: '1922-03-01',
1050
+ maxDate: '2022-03-17',
1051
+ });
1052
+
1053
+ expect(validateForm({})).toEqual({
1054
+ birthdate: 'Required field',
1055
+ });
1056
+
1057
+ expect(validateForm({ birthdate: '' })).toEqual({
1058
+ birthdate: `Required field`,
1059
+ });
1060
+
1061
+ expect(validateForm({ birthdate: '1922-02-01' })).toEqual({
1062
+ birthdate: 'The date must be 1922-03-01 or after.',
1063
+ });
1064
+
1065
+ expect(validateForm({ birthdate: '1922-03-01' })).toBeUndefined();
1066
+
1067
+ expect(validateForm({ birthdate: '2021-03-01' })).toBeUndefined();
1068
+ });
1069
+
1070
+ it('support "date" field type with a maxDate', () => {
1071
+ const { fields, handleValidation } = createHeadlessForm(schemaInputTypeDate);
1072
+
1073
+ const validateForm = (vals) => friendlyError(handleValidation(vals));
1074
+
1075
+ expect(fields[0]).toMatchObject({
1076
+ label: 'Birthdate',
1077
+ name: 'birthdate',
1078
+ required: true,
1079
+ schema: expect.any(Object),
1080
+ type: 'date',
1081
+ minDate: '1922-03-01',
1082
+ maxDate: '2022-03-17',
1083
+ });
1084
+
1085
+ expect(validateForm({ birthdate: '' })).toEqual({
1086
+ birthdate: `Required field`,
1087
+ });
1088
+
1089
+ expect(validateForm({ birthdate: '2022-02-01' })).toBeUndefined();
1090
+ expect(validateForm({ birthdate: '2022-03-01' })).toBeUndefined();
1091
+ expect(validateForm({ birthdate: '2022-04-01' })).toEqual({
1092
+ birthdate: 'The date must be 2022-03-17 or before.',
1093
+ });
1094
+ });
1095
+
1096
+ it('support format date with minDate and maxDate', () => {
1097
+ const schemaFormatDate = {
1098
+ properties: {
1099
+ birthdate: {
1100
+ title: 'Birthdate',
1101
+ type: 'string',
1102
+ format: 'date',
1103
+ 'x-jsf-presentation': {
1104
+ inputType: 'myDateType',
1105
+ maxDate: '2022-03-01',
1106
+ minDate: '1922-03-01',
1107
+ },
1108
+ },
1109
+ },
1110
+ };
1111
+
1112
+ const { handleValidation } = createHeadlessForm(schemaFormatDate);
1113
+ const validateForm = (vals) => friendlyError(handleValidation(vals));
1114
+
1115
+ expect(validateForm({ birthdate: '1922-02-01' })).toEqual({
1116
+ birthdate: 'The date must be 1922-03-01 or after.',
1117
+ });
1041
1118
  });
1042
1119
 
1043
1120
  it('supports "file" field type', () => {
@@ -272,18 +272,6 @@ export const mockSelectInputMultipleOptional = {
272
272
  type: ['array', 'null'],
273
273
  };
274
274
 
275
- export const mockDateInput = {
276
- 'x-jsf-presentation': {
277
- inputType: 'date',
278
- maxDate: '2022-03-01',
279
- minDate: '1922-03-01',
280
- },
281
- title: 'Birthdate',
282
- type: 'string',
283
- format: 'date',
284
- maxLength: 10,
285
- };
286
-
287
275
  export const mockFileInput = {
288
276
  description: 'File Input Description',
289
277
  'x-jsf-presentation': {
@@ -998,12 +986,19 @@ export const schemaInputTypeNumberWithPercentage = JSONSchemaBuilder()
998
986
  .setRequiredFields(['shares'])
999
987
  .build();
1000
988
 
1001
- export const schemaInputTypeDate = JSONSchemaBuilder()
1002
- .addInput({
1003
- birthdate: mockDateInput,
1004
- })
1005
- .setRequiredFields(['birthdate'])
1006
- .build();
989
+ export const schemaInputTypeDate = {
990
+ type: 'object',
991
+ additionalProperties: false,
992
+ properties: {
993
+ birthdate: {
994
+ 'x-jsf-presentation': { inputType: 'date', maxDate: '2022-03-17', minDate: '1922-03-01' },
995
+ title: 'Birthdate',
996
+ type: 'string',
997
+ format: 'date',
998
+ },
999
+ },
1000
+ required: ['birthdate'],
1001
+ };
1007
1002
 
1008
1003
  export const schemaInputTypeEmail = JSONSchemaBuilder()
1009
1004
  .addInput({