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

Implement types for signature component #36

Merged
merged 1 commit into from
Dec 7, 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 @@ -21,6 +21,7 @@ export * from './radio';
export * from './addressNL';
export * from './map';
export * from './editgrid';
export * from './signature';

// Layout components
export * from './content';
Expand Down
61 changes: 61 additions & 0 deletions src/formio/components/signature.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import {InputComponentSchema} from '..';

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

/**
* The value is base64 encoded binary (image) data, or unset and then it's a string.
*
* When a non-empty value is set, enforce that it is serialized as a data URI.
*/
export type SignatureValue = `data:image/png;base64,${string}`;
Copy link
Contributor

@Viicos Viicos Dec 6, 2023

Choose a reason for hiding this comment

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

Imagine having this available in Python.. 🥹

Copy link
Member Author

Choose a reason for hiding this comment

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

I find it a bit scary to be honest. And there doesn't seem to be a definitive way in TS to express that something is a non-empty string, so it's clearly still lacking a lot.


export type SignatureInputSchema = InputComponentSchema<
SignatureValue | '',
Validator,
TranslatableKeys
>;

/**
* The built-in Formio.js signature component type.
*
* Source code this is based on:
* https://github.com/formio/formio.js/blob/4.13.x/src/components/signature/Signature.js
*
* Note that we don't offer support for many properties through our form builder, like:
*
* - width
* - height
* - penColor
* - backgroundColor
* - minWidth
* - maxWidth
*
* Because of that, they are also not added to the type definitions (yet). That may
* change once we implement our own renderer.
*
* @group Form.io components
* @category Concrete types
*/
export interface SignatureComponentSchema
extends Omit<
SignatureInputSchema,
'hideLabel' | 'disabled' | 'placeholder' | 'validateOn' | 'multiple'
> {
type: 'signature';
/**
* The footer is a text displayed below the drawing canvas which may hint the user on
* what is expected of them.
*
* I'm not sure what the difference is with the 'description' field.
*/
footer?: string; // translatable instruction

/**
* The value type of the component. We don't support `multiple: true` in this component.
*
* Note that we use the `defaultValue` property to infer the value type, we do not
* support actually setting a component default value.
*/
defaultValue?: SignatureValue | '';
}
2 changes: 2 additions & 0 deletions src/formio/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
RadioComponentSchema,
SelectComponentSchema,
SelectboxesComponentSchema,
SignatureComponentSchema,
TextFieldComponentSchema,
TextareaComponentSchema,
TimeComponentSchema,
Expand Down Expand Up @@ -72,6 +73,7 @@ export type AnyComponentSchema =
| BsnComponentSchema
| AddressNLComponentSchema
| NpFamilyMembersComponentSchema
| SignatureComponentSchema
| MapComponentSchema
| EditGridComponentSchema
// layout
Expand Down
105 changes: 105 additions & 0 deletions test-d/formio/components/signature.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import {expectAssignable, expectNotAssignable} from 'tsd';

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

// minimal signature component schema
expectAssignable<SignatureComponentSchema>({
id: 'yejak',
type: 'signature',
key: 'someSignature',
label: 'Some signature',
});

// with additional, signature-component specific properties
expectAssignable<SignatureComponentSchema>({
id: 'yejak',
type: 'signature',
key: 'someSignature',
label: 'Some signature',
defaultValue: 'data:image/png;base64,dGhlIGdhbWU=',
footer: 'Please do not draw inappropriate images',
});

// full, correct schema
expectAssignable<SignatureComponentSchema>({
id: 'yejak',
type: 'signature',
// basic tab in builder form
label: 'Some signature',
key: 'someSignature',
description: 'A description',
tooltip: 'A tooltip',
showInSummary: true,
showInEmail: false,
showInPDF: true,
hidden: false,
clearOnHide: true,
isSensitiveData: false,
defaultValue: '',
// advanced tab in builder form
conditional: {
show: undefined,
when: undefined,
eq: undefined,
},
// validation tab in builder form
validate: {
required: false,
plugins: undefined,
},
translatedErrors: {
nl: {
required: 'Je moet een waarde opgeven!!!',
},
},
errors: {
// translatedErrors is converted into errors by the backend
required: 'Je moet een waarde opgeven!!!',
},
// registration tab in builder form
registration: {
attribute: '',
},
// translations tab in builder form
openForms: {
translations: {
nl: {
label: 'foo',
description: 'bar',
},
},
},
});

// different component type
expectNotAssignable<SignatureComponentSchema>({
type: 'fieldset' as const,
});

// using unsupported properties
expectNotAssignable<SignatureComponentSchema>({
id: 'yejak',
type: 'signature' as const,
key: 'someSignature',
label: 'Some signature',
hideLabel: true,
});

// bad value format
expectNotAssignable<SignatureComponentSchema>({
id: 'yejak',
type: 'signature' as const,
key: 'someSignature',
label: 'Some signature',
defaultValue: 'random string',
});

// multiple is not supported
expectNotAssignable<SignatureComponentSchema>({
id: 'yejak',
type: 'signature' as const,
key: 'someSignature',
label: 'Some signature',
multiple: true,
defaultValue: [],
});