Skip to content

Commit

Permalink
Merge pull request #7 from open-formulieren/feature/date-component
Browse files Browse the repository at this point in the history
✨ [#2] -- define types for date component
  • Loading branch information
sergei-maertens authored Jun 6, 2023
2 parents 983deeb + 2820d29 commit 98be7a1
Show file tree
Hide file tree
Showing 6 changed files with 264 additions and 2 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
],
"scripts": {
"build": "tsc --emitDeclarationOnly",
"build:docs": "typedoc src/index.ts",
"build:docs": "typedoc",
"test": "npm run build && tsd",
"format": "prettier --write 'src/**/*'",
"checkformat": "prettier --check 'src/**/*'"
Expand Down
73 changes: 73 additions & 0 deletions src/formio/components/date.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import {InputComponentSchema, MultipleCapable, PrefillConfig} from '..';
import {OFExtensions} from '../base';

/**
* Date picker min/max date validation types.
*
* These are processed in the backend. For the implementation and type definitions:
* https://github.com/open-formulieren/open-forms/blob/master/src/openforms/formio/dynamic_config/date.py#L53
*/

/**
* Expression of a date constraint delta.
*
* @remarks The numbers are expected to be integers.
*/
interface DateConstraintDelta {
years: number | null;
months: number | null;
days: number | null;
}

interface DateConstraintConfiguration {
mode: '' | 'fixedValue' | 'future' | 'past' | 'relativeToVariable';
includeToday: boolean | null;
variable?: string;
delta: DateConstraintDelta;
operator?: 'add' | 'subtract';
}

/**
* A lot of this is *guesswork*, except for `minDate`/`maxDate`. At this time it's also
* unclear how relevant each property is, except for minDate/maxDate.
*/
export interface DatePickerConfig {
showWeeks: boolean;
startingDay: 0 | 1 | 2 | 3 | 4 | 5 | 6;
initDate: string;
minMode: 'day' | 'month' | 'year';
maxMode: 'day' | 'month' | 'year';
yearRows: number;
yearColumns: number;
minDate: string | null;
maxDate: string | null;
}

type Validator = 'required';

/**
* @group Form.io components
* @category Base types
*/
export interface BaseDateComponentSchema
extends Omit<InputComponentSchema<string, Validator>, 'hideLabel'>,
PrefillConfig {
type: 'date';
openForms?: OFExtensions['openForms'] & {
minDate?: DateConstraintConfiguration;
maxDate?: DateConstraintConfiguration;
};
datePicker?: DatePickerConfig;
}

/**
* A date component schema.
*
* Note that the value/`defaultValue` type is just a plain string, as native Date
* objects must be serialized into a string for data exchange via JSON. The expected
* date format is ISO-8601, i.e. YYYY-MM-DD.
*
* @group Form.io components
* @category Concrete types
*/
export type DateComponentSchema = MultipleCapable<BaseDateComponentSchema>;
1 change: 1 addition & 0 deletions src/formio/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './textfield';
export * from './email';
export * from './date';
export * from './number';
2 changes: 1 addition & 1 deletion src/formio/i18n.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {TranslationsContainer} from '../i18n';
import {BaseErrorKeys} from './validation';

interface Translation {
export interface Translation {
literal: string;
translation: string;
}
Expand Down
183 changes: 183 additions & 0 deletions test-d/formio/components/date.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
import {expectAssignable, expectNotAssignable} from 'tsd';

import {DateComponentSchema} from '../../../lib';

// minimal date component schema
expectAssignable<DateComponentSchema>({
id: 'evneg4v',
type: 'date',
key: 'someDate',
label: 'Some date',
});

// with additional, date-component specific properties
expectAssignable<DateComponentSchema>({
id: 'evneg4v',
type: 'date',
key: 'someDate',
label: 'Some date',
openForms: {
translations: {},
minDate: {
mode: 'relativeToVariable',
includeToday: null,
operator: 'add',
variable: 'someVariable',
delta: {
years: null,
months: 1,
days: null,
},
},
},
datePicker: {
showWeeks: true,
startingDay: 0,
initDate: '',
minMode: 'day',
maxMode: 'year',
yearRows: 4,
yearColumns: 5,
minDate: '2023-06-06',
maxDate: null,
},
});

// multiple false and appropriate default value type
expectAssignable<DateComponentSchema>({
id: 'evneg4v',
type: 'date',
key: 'someDate',
label: 'Some date',
multiple: false,
defaultValue: '',
});
// multiple true and appropriate default value type
expectAssignable<DateComponentSchema>({
id: 'evneg4v',
type: 'date',
key: 'someDate',
label: 'Some date',
multiple: true,
defaultValue: [''],
});

// full, correct schema
expectAssignable<DateComponentSchema>({
id: 'evneg4v',
type: 'date',
// basic tab
label: 'Datum',
key: 'datum',
description: '',
showInSummary: true,
showInEmail: false,
showInPDF: true,
multiple: false,
hidden: false,
clearOnHide: true,
isSensitiveData: true,
defaultValue: '',
disabled: false,
// Advanced tab
conditional: {
show: undefined,
when: '',
eq: '',
},
// Validation tab
validate: {
required: false,
plugins: [],
},
translatedErrors: {
nl: {
required: '',
},
en: {
required: '',
},
},
// dynamically set/mutated by the backend after processing openForms.minDate|maxDate
datePicker: {
showWeeks: true,
startingDay: 0,
initDate: '',
minMode: 'day',
maxMode: 'year',
yearRows: 4,
yearColumns: 5,
minDate: null,
maxDate: null,
},
// registration tab
registration: {
attribute: '',
},
// prefill tab
prefill: {
plugin: '',
attribute: '',
},

// custom OF extensions
openForms: {
// validation processed server-side
minDate: {
mode: '',
includeToday: null,
operator: 'add',
variable: 'now',
delta: {
years: null,
months: null,
days: null,
},
},
maxDate: {
mode: '',
includeToday: null,
operator: 'add',
variable: 'now',
delta: {
years: null,
months: null,
days: null,
},
},
// translations tab in builder form
translations: {
nl: [{literal: 'foo', translation: 'bar'}],
},
},
});

// invalid, multiple true and non-array default value
expectNotAssignable<DateComponentSchema>({
id: 'evneg4v',
type: 'date',
key: 'someDate',
label: 'Some date',
multiple: true,
defaultValue: '',
});

// invalid, multiple false and array default value
expectNotAssignable<DateComponentSchema>({
id: 'evneg4v',
type: 'date',
key: 'someDate',
label: 'Some date',
multiple: false,
defaultValue: [''],
});

// invalid, multiple true and wrong default value in array element
expectNotAssignable<DateComponentSchema>({
id: 'evneg4v',
type: 'date',
key: 'someDate',
label: 'Some date',
multiple: true,
defaultValue: [0],
});
5 changes: 5 additions & 0 deletions typedoc.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
{
"$schema": "https://typedoc.org/schema.json",
"entryPoints": [
"src/index.ts",
"src/formio/i18n.ts",
"src/formio/validation.ts",
],
"groupOrder": [
"Form.io components",
"Schema primitives",
Expand Down

0 comments on commit 98be7a1

Please sign in to comment.