Skip to content

Commit

Permalink
Merge pull request #24 from open-formulieren/feature/2-select
Browse files Browse the repository at this point in the history
✨ [#2] Implement types for `select`
  • Loading branch information
sergei-maertens authored Nov 13, 2023
2 parents 68a544b + fa1c3fc commit c51f719
Show file tree
Hide file tree
Showing 4 changed files with 287 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/formio/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export * from './iban';
export * from './licenseplate';
export * from './bsn';
export * from './number';
export * from './select';
export * from './checkbox';
export * from './selectboxes';
export * from './file';
Expand Down
52 changes: 52 additions & 0 deletions src/formio/components/select.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import {InputComponentSchema} from '..';
import {MultipleCapable, OFExtensions} from '../base';
import {ManualValues, Option, VariableValues} from '../common';

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

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

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

/**
* @group Form.io components
* @category Base types
*/
interface BaseSelectSchema {
type: 'select';
// not to be confused with openforms.dataSrc. Formio itself supports dynamic sources
// like json/url/resource/custom but we don't use any of that, our backend resolves
// dynamic values into data.values already.
// So our openForms.dataSrc == itemsExpression results in dataSrc == values.
dataSrc: 'values';
}

/**
* @group Form.io components
* @category Base types
*/
type SelectManualValuesSchema = Omit<SelectInputSchema, SelectUnsupported> &
BaseSelectSchema & {
openForms: OFExtensions<TranslatableKeys>['openForms'] & ManualValues;
data: {
values: Option[];
};
};

/**
* @group Form.io components
* @category Base types
*/
type SelectVariableValuesSchema = Omit<SelectInputSchema, SelectUnsupported> &
BaseSelectSchema & {
openForms: OFExtensions<TranslatableKeys>['openForms'] & VariableValues;
};

/**
* @group Form.io components
* @category Concrete types
*/
export type SelectComponentSchema = MultipleCapable<
SelectManualValuesSchema | SelectVariableValuesSchema
>;
2 changes: 2 additions & 0 deletions src/formio/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
PhoneNumberComponentSchema,
PostcodeComponentSchema,
RadioComponentSchema,
SelectComponentSchema,
SelectboxesComponentSchema,
TextFieldComponentSchema,
TimeComponentSchema,
Expand Down Expand Up @@ -52,6 +53,7 @@ export type AnyComponentSchema =
| PostcodeComponentSchema
| FileComponentSchema
| NumberComponentSchema
| SelectComponentSchema
| CheckboxComponentSchema
| SelectboxesComponentSchema
| CurrencyComponentSchema
Expand Down
232 changes: 232 additions & 0 deletions test-d/formio/components/select.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
import {expectAssignable, expectNotAssignable} from 'tsd';

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

// minimal component schema, manual:
expectAssignable<SelectComponentSchema>({
id: 'yejak',
type: 'select',
dataSrc: 'values',
key: 'someSelect',
label: 'Some select',
openForms: {
dataSrc: 'manual',
translations: {},
},
data: {
values: [
{
value: 'dummy',
label: 'dummy',
},
],
},
});

// minimal component schema, variable:
expectAssignable<SelectComponentSchema>({
id: 'yejak',
type: 'select',
dataSrc: 'values',
key: 'someSelect',
label: 'Some select',
openForms: {
dataSrc: 'variable',
itemsExpression: 'dummy',
translations: {},
},
});

// minimal component schema, multiple false:
expectAssignable<SelectComponentSchema>({
id: 'yejak',
type: 'select',
dataSrc: 'values',
key: 'someSelect',
label: 'Some select',
multiple: false,
defaultValue: 'dummy',
openForms: {
dataSrc: 'variable',
itemsExpression: 'dummy',
translations: {},
},
});

// minimal component schema, multiple true:
expectAssignable<SelectComponentSchema>({
id: 'yejak',
type: 'select',
dataSrc: 'values',
key: 'someSelect',
label: 'Some select',
multiple: true,
defaultValue: ['dummy'],
openForms: {
dataSrc: 'variable',
itemsExpression: 'dummy',
translations: {},
},
});

// minimal component schema, multiple true and empty defaults:
expectAssignable<SelectComponentSchema>({
id: 'yejak',
type: 'select',
dataSrc: 'values',
key: 'someSelect',
label: 'Some select',
multiple: true,
defaultValue: [],
openForms: {
dataSrc: 'variable',
itemsExpression: 'dummy',
translations: {},
},
});

// values translations
expectAssignable<SelectComponentSchema>({
id: 'yejak',
type: 'select',
dataSrc: 'values',
key: 'someSelect',
label: 'Some select',
defaultValue: 'dummy',
openForms: {
dataSrc: 'manual',
translations: {},
},
data: {
values: [
{
value: 'dummy',
label: 'dummy',
openForms: {
translations: {
en: {
label: 'dummy_en',
},
nl: {
label: 'dummy_nl',
},
},
},
},
],
},
});

// full, correct schema
expectAssignable<SelectComponentSchema>({
id: 'yejak',
type: 'select',
dataSrc: 'values',
// basic tab
label: 'Some select',
key: 'someSelect',
description: '',
tooltip: 'A tooltip',
showInSummary: true,
showInEmail: false,
showInPDF: true,
hidden: false,
clearOnHide: true,
isSensitiveData: true,
defaultValue: 'dummy',
// Advanced tab
conditional: {
show: undefined,
when: '',
eq: '',
},
// Validation tab
validate: {
required: false,
plugins: [],
},
translatedErrors: {nl: {required: 'Geef checkbox.'}},
errors: {required: 'Geef checkbox.'},
// registration tab
registration: {
attribute: '',
},
// translations tab in builder form
openForms: {
translations: {
nl: {label: 'foo'},
},
dataSrc: 'variable',
itemsExpression: 'dummy',
},
// fixed but not editable
validateOn: 'blur',
});

// Missing openForms
expectNotAssignable<SelectComponentSchema>({
id: 'yejak',
type: 'select',
dataSrc: 'values',
key: 'someSelect',
label: 'Some select',
});

// multiple true, wrong default value
expectNotAssignable<SelectComponentSchema>({
id: 'yejak',
type: 'select',
dataSrc: 'values',
key: 'someSelect',
label: 'Some select',
multiple: true,
defaultValue: 'dummy',
openForms: {
dataSrc: 'variable',
itemsExpression: 'dummy',
translations: {},
},
});

// multiple false, wrong default value
expectNotAssignable<SelectComponentSchema>({
id: 'yejak',
type: 'select',
dataSrc: 'values',
key: 'someSelect',
label: 'Some select',
multiple: false,
defaultValue: ['dummy'],
openForms: {
dataSrc: 'variable',
itemsExpression: 'dummy',
translations: {},
},
});

// manual without values
expectNotAssignable<SelectComponentSchema>({
id: 'yejak',
type: 'select',
dataSrc: 'values',
key: 'someSelect',
label: 'Some select',
openForms: {
dataSrc: 'manual',
translations: {},
},
data: {},
});

// variable without itemsExpressions
expectNotAssignable<SelectComponentSchema>({
id: 'yejak',
type: 'select',
dataSrc: 'values',
key: 'someSelect',
label: 'Some select',
openForms: {
dataSrc: 'variable',
translations: {},
},
});

0 comments on commit c51f719

Please sign in to comment.