Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add type definition to support e-mail verification #53

Merged
merged 2 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions src/formio/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,15 @@ export interface PrefillConfig {

/**
* @group Open Forms schema extensions
*
* The `Extra` type variable allows specifying additional, component-specific,
* extensions namespaced under the `openForms` key.
*/
export interface OFExtensions<TK extends string = string> {
export interface OFExtensions<TK extends string = string, Extra = {}> {
isSensitiveData?: boolean;
openForms?: {
translations: ComponentTranslations<TK>;
};
} & Extra;
registration?: {
attribute: string;
};
Expand Down Expand Up @@ -173,12 +176,19 @@ export type MultipleCapable<S> = S extends {defaultValue?: infer DV}

/**
* @group Schema primitives
*
* The `ExtraExtensions` type variable allows specifying additional, component-specific,
* extensions namespaced under the `openForms` key.
*/
export type InputComponentSchema<
T = unknown,
VN extends CuratedValidatorNames = CuratedValidatorNames,
TK extends string = string
> = StrictComponentSchema<T | T[]> & DisplayConfig & OFExtensions<TK> & HasValidation<VN>;
TK extends string = string,
ExtraExtensions = {}
> = StrictComponentSchema<T | T[]> &
DisplayConfig &
OFExtensions<TK, ExtraExtensions> &
HasValidation<VN>;

/**
* @group Schema primitives
Expand Down
21 changes: 11 additions & 10 deletions src/formio/components/addressNL.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {HasValidation, InputComponentSchema} from '..';
import {ComponentTranslations} from '../i18n';

type Validator = 'required';
type TranslatableKeys = 'label' | 'description' | 'tooltip';
Expand All @@ -19,22 +18,24 @@ export interface AddressComponents {
city?: HasValidation<'pattern', false>;
}

export type AddressNLInputSchema = InputComponentSchema<AddressData, Validator, TranslatableKeys>;
export interface AddressNLExtensions {
components?: AddressComponents;
}
sergei-maertens marked this conversation as resolved.
Show resolved Hide resolved

export type AddressNLInputSchema = InputComponentSchema<
AddressData,
Validator,
TranslatableKeys,
AddressNLExtensions
>;

/**
* @group Form.io components
* @category Concrete types
*/
export interface AddressNLComponentSchema
extends Omit<
AddressNLInputSchema,
'hideLabel' | 'placeholder' | 'disabled' | 'validateOn' | 'openForms'
> {
extends Omit<AddressNLInputSchema, 'hideLabel' | 'placeholder' | 'disabled' | 'validateOn'> {
type: 'addressNL';
deriveAddress: boolean;
layout: 'singleColumn' | 'doubleColumn';
openForms?: {
components?: AddressComponents;
translations?: ComponentTranslations<TranslatableKeys>;
};
}
21 changes: 12 additions & 9 deletions src/formio/components/date.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {InputComponentSchema, MultipleCapable, PrefillConfig} from '..';
import {OFExtensions} from '../base';
import {
FutureDateConstraint as BaseFutureDateConstraint,
PastDateConstraint as BasePastDateConstraint,
Expand All @@ -11,8 +10,6 @@ import {
type Validator = 'required' | 'minDate' | 'maxDate';
type TranslatableKeys = 'label' | 'description' | 'tooltip';

export type DateInputSchema = InputComponentSchema<string, Validator, TranslatableKeys>;

export interface IncludeToday {
includeToday: boolean | null;
}
Expand All @@ -21,18 +18,24 @@ type FutureOrPastDateConstraint = BaseFutureDateConstraint | BasePastDateConstra
type FutureDateConstraint = BaseFutureDateConstraint & IncludeToday;
type PastDateConstraint = BasePastDateConstraint & IncludeToday;

export interface DateExtensions {
minDate?: Exclude<DateConstraintConfiguration, FutureOrPastDateConstraint> | FutureDateConstraint;
maxDate?: Exclude<DateConstraintConfiguration, FutureOrPastDateConstraint> | PastDateConstraint;
}

export type DateInputSchema = InputComponentSchema<
string,
Validator,
TranslatableKeys,
DateExtensions
>;

/**
* @group Form.io components
* @category Base types
*/
export interface BaseDateComponentSchema extends Omit<DateInputSchema, 'hideLabel'>, PrefillConfig {
type: 'date';
openForms?: OFExtensions<TranslatableKeys>['openForms'] & {
minDate?:
| Exclude<DateConstraintConfiguration, FutureOrPastDateConstraint>
| FutureDateConstraint;
maxDate?: Exclude<DateConstraintConfiguration, FutureOrPastDateConstraint> | PastDateConstraint;
};
datePicker?: DatePickerConfig;
customOptions?: PickerCustomOptions;
}
Expand Down
17 changes: 11 additions & 6 deletions src/formio/components/datetime.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {InputComponentSchema, MultipleCapable, PrefillConfig} from '..';
import {OFExtensions} from '../base';
import {
DateConstraintConfiguration,
DatePickerConfig,
Expand All @@ -11,7 +10,17 @@ import {
type Validator = 'required' | 'minDate' | 'maxDate';
type TranslatableKeys = 'label' | 'description' | 'tooltip';

export type DateTimeInputSchema = InputComponentSchema<string, Validator, TranslatableKeys>;
export interface DateTimeExtensions {
minDate?: Exclude<DateConstraintConfiguration, PastDateConstraint>;
maxDate?: Exclude<DateConstraintConfiguration, FutureDateConstraint>;
}

export type DateTimeInputSchema = InputComponentSchema<
string,
Validator,
TranslatableKeys,
DateTimeExtensions
>;

/**
* @group Form.io components
Expand All @@ -21,10 +30,6 @@ export interface BaseDateTimeComponentSchema
extends Omit<DateTimeInputSchema, 'hideLabel'>,
PrefillConfig {
type: 'datetime';
openForms?: OFExtensions<TranslatableKeys>['openForms'] & {
minDate?: Exclude<DateConstraintConfiguration, PastDateConstraint>;
maxDate?: Exclude<DateConstraintConfiguration, FutureDateConstraint>;
};
datePicker?: DatePickerConfig;
customOptions?: PickerCustomOptions;
}
Expand Down
11 changes: 10 additions & 1 deletion src/formio/components/email.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,16 @@ import {InputComponentSchema, MultipleCapable} from '..';
type Validator = 'required';
type TranslatableKeys = 'label' | 'description' | 'tooltip';

export type EmailInputSchema = InputComponentSchema<string, Validator, TranslatableKeys>;
export interface EmailExtensions {
requireVerification?: boolean;
}

export type EmailInputSchema = InputComponentSchema<
string,
Validator,
TranslatableKeys,
EmailExtensions
>;

/**
* @group Form.io components
Expand Down
23 changes: 14 additions & 9 deletions src/formio/components/radio.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import {InputComponentSchema} from '..';
import {OFExtensions} from '../base';
import {ManualValues, Option, VariableValues} from '../common';
import {Require} from '../util';

type Validator = 'required';
type TranslatableKeys = 'label' | 'description' | 'tooltip';

export type RadioInputSchema = InputComponentSchema<string | null, Validator, TranslatableKeys>;
export type RadioInputSchema<Extensions> = InputComponentSchema<
string | null,
Validator,
TranslatableKeys,
Extensions
>;

/**
* @group Form.io components
Expand All @@ -20,23 +25,23 @@ interface BaseRadioSchema {
* @group Form.io components
* @category Base types
*/
type RadioManualValuesSchema = Omit<RadioInputSchema, 'hideLabel' | 'disabled'> &
type RadioManualValuesSchema = Omit<RadioInputSchema<ManualValues>, 'hideLabel' | 'disabled'> &
BaseRadioSchema & {
openForms: OFExtensions<TranslatableKeys>['openForms'] & ManualValues;
values: Option[];
};

/**
* @group Form.io components
* @category Base types
*/
type RadioVariableValuesSchema = Omit<RadioInputSchema, 'hideLabel' | 'disabled'> &
BaseRadioSchema & {
openForms: OFExtensions<TranslatableKeys>['openForms'] & VariableValues;
};
type RadioVariableValuesSchema = Omit<RadioInputSchema<VariableValues>, 'hideLabel' | 'disabled'> &
BaseRadioSchema;

/**
* @group Form.io components
* @category Concrete types
*/
export type RadioComponentSchema = RadioManualValuesSchema | RadioVariableValuesSchema;
export type RadioComponentSchema = Require<
RadioManualValuesSchema | RadioVariableValuesSchema,
'openForms'
>;
Comment on lines +44 to +47
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the Require here mean that the openForms key is required for RadioComponentSchema?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indeed! I found it a bit weird that there's no built-in utility type for it (Required makes everything required). Without this, the formio builder doesn't build properly, and for select, selectboxes and radio the dataSrc must be specified.

21 changes: 12 additions & 9 deletions src/formio/components/select.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import {InputComponentSchema} from '..';
import {MultipleCapable, OFExtensions} from '../base';
import {MultipleCapable} from '../base';
import {ManualValues, Option, VariableValues} from '../common';
import {Require} from '../util';

type Validator = 'required';
type TranslatableKeys = 'label' | 'description' | 'tooltip';

export type SelectInputSchema = InputComponentSchema<string, Validator, TranslatableKeys>;
export type SelectInputSchema<Extensions> = InputComponentSchema<
string,
Validator,
TranslatableKeys,
Extensions
>;

export type SelectUnsupported = 'hideLabel' | 'disabled' | 'placeholder';

Expand All @@ -26,9 +32,8 @@ interface BaseSelectSchema {
* @group Form.io components
* @category Base types
*/
type SelectManualValuesSchema = Omit<SelectInputSchema, SelectUnsupported> &
type SelectManualValuesSchema = Omit<SelectInputSchema<ManualValues>, SelectUnsupported> &
BaseSelectSchema & {
openForms: OFExtensions<TranslatableKeys>['openForms'] & ManualValues;
data: {
values: Option[];
};
Expand All @@ -38,15 +43,13 @@ type SelectManualValuesSchema = Omit<SelectInputSchema, SelectUnsupported> &
* @group Form.io components
* @category Base types
*/
type SelectVariableValuesSchema = Omit<SelectInputSchema, SelectUnsupported> &
BaseSelectSchema & {
openForms: OFExtensions<TranslatableKeys>['openForms'] & VariableValues;
};
type SelectVariableValuesSchema = Omit<SelectInputSchema<VariableValues>, SelectUnsupported> &
BaseSelectSchema;

/**
* @group Form.io components
* @category Concrete types
*/
export type SelectComponentSchema = MultipleCapable<
SelectManualValuesSchema | SelectVariableValuesSchema
Require<SelectManualValuesSchema | SelectVariableValuesSchema, 'openForms'>
>;
29 changes: 17 additions & 12 deletions src/formio/components/selectboxes.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import {InputComponentSchema} from '..';
import {OFExtensions} from '../base';
import {ManualValues, Option, VariableValues} from '../common';
import {Require} from '../util';

type Validator = 'required' | 'minSelectedCount' | 'maxSelectedCount';
type TranslatableKeys = 'label' | 'description' | 'tooltip';

export type SelectboxesInputSchema = InputComponentSchema<
export type SelectboxesInputSchema<Extensions> = InputComponentSchema<
Record<string, boolean>,
Validator,
TranslatableKeys
TranslatableKeys,
Extensions
>;

/**
Expand All @@ -24,25 +25,29 @@ interface BaseSelectboxesSchema {
* @group Form.io components
* @category Base types
*/
type SelectboxesManualValuesSchema = Omit<SelectboxesInputSchema, 'hideLabel' | 'disabled'> &
type SelectboxesManualValuesSchema = Omit<
SelectboxesInputSchema<ManualValues>,
'hideLabel' | 'disabled'
> &
BaseSelectboxesSchema & {
openForms: OFExtensions<TranslatableKeys>['openForms'] & ManualValues;
values: Option[];
};

/**
* @group Form.io components
* @category Base types
*/
type SelectboxesVariableValuesSchema = Omit<SelectboxesInputSchema, 'hideLabel' | 'disabled'> &
BaseSelectboxesSchema & {
openForms: OFExtensions<TranslatableKeys>['openForms'] & VariableValues;
};
type SelectboxesVariableValuesSchema = Omit<
SelectboxesInputSchema<VariableValues>,
'hideLabel' | 'disabled'
> &
BaseSelectboxesSchema;

/**
* @group Form.io components
* @category Concrete types
*/
export type SelectboxesComponentSchema =
| SelectboxesManualValuesSchema
| SelectboxesVariableValuesSchema;
export type SelectboxesComponentSchema = Require<
SelectboxesManualValuesSchema | SelectboxesVariableValuesSchema,
'openForms'
>;
8 changes: 8 additions & 0 deletions src/formio/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* Given a type `T` with optional key(s) `K`, make the key(s) `K` required.
*
* The ternary is to force distribution over unions in `T`.
*/
export type Require<T, K extends keyof T> = T extends any
? Omit<T, K> & Required<Pick<T, K>>
: never;
1 change: 1 addition & 0 deletions test-d/formio/components/email.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ expectAssignable<EmailComponentSchema>({
translations: {
nl: {label: 'foo'},
},
requireVerification: true,
},
// fixed but not editable
validateOn: 'blur',
Expand Down