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

✨ [#2] Implement types for select #24

Merged
merged 1 commit into from
Nov 13, 2023
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
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: {},
},
});