@sealcode/sealgen 0.19.2 → 0.19.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/@types/forms/controls/hybrid.d.ts +10 -0
- package/@types/forms/controls/simple-input.d.ts +1 -0
- package/@types/forms/fields/field.d.ts +2 -0
- package/@types/forms/fields/fields.d.ts +2 -0
- package/@types/forms/fields/phone-number-with-country-code.d.ts +10 -0
- package/@types/forms/fields/phone-number.d.ts +17 -0
- package/@types/forms/fields/simple-form-field.d.ts +5 -3
- package/@types/utils/input-wrapper.d.ts +2 -0
- package/lib/forms/controls/checkboxed-list-input.js +2 -2
- package/lib/forms/controls/dropdown.js +3 -3
- package/lib/forms/controls/hybrid.js +41 -0
- package/lib/forms/controls/multiple-files.js +3 -1
- package/lib/forms/controls/simple-input.js +7 -2
- package/lib/forms/controls/single-reference.js +1 -1
- package/lib/forms/controls/table.js +1 -1
- package/lib/forms/fields/boolean.js +1 -1
- package/lib/forms/fields/checkboxed-list.js +3 -1
- package/lib/forms/fields/coordinates.js +1 -1
- package/lib/forms/fields/date.js +4 -1
- package/lib/forms/fields/datetime.js +1 -1
- package/lib/forms/fields/deep-reverse-single-reference-table.js +1 -1
- package/lib/forms/fields/email.js +4 -1
- package/lib/forms/fields/field.js +4 -0
- package/lib/forms/fields/fields.js +2 -0
- package/lib/forms/fields/phone-number-with-country-code.js +50 -0
- package/lib/forms/fields/phone-number.js +33 -0
- package/lib/forms/fields/regexp.js +1 -1
- package/lib/forms/fields/simple-form-field.js +8 -4
- package/lib/forms/fields/single-reference.js +1 -1
- package/lib/forms/fields/structured-array.js +1 -1
- package/lib/forms/fields/table.js +1 -1
- package/lib/utils/input-wrapper.js +13 -0
- package/package.json +2 -1
- package/src/forms/controls/checkboxed-list-input.ts +4 -2
- package/src/forms/controls/dropdown.ts +3 -3
- package/src/forms/controls/hybrid.ts +44 -0
- package/src/forms/controls/multiple-files.ts +5 -1
- package/src/forms/controls/simple-input.ts +9 -1
- package/src/forms/controls/single-reference.ts +1 -1
- package/src/forms/controls/table.ts +1 -1
- package/src/forms/fields/boolean.ts +1 -1
- package/src/forms/fields/checkboxed-list.ts +3 -1
- package/src/forms/fields/coordinates.ts +1 -1
- package/src/forms/fields/date.ts +4 -1
- package/src/forms/fields/datetime.ts +1 -1
- package/src/forms/fields/deep-reverse-single-reference-table.ts +1 -1
- package/src/forms/fields/email.ts +4 -1
- package/src/forms/fields/field.ts +6 -0
- package/src/forms/fields/fields.ts +2 -0
- package/src/forms/fields/phone-number-with-country-code.ts +59 -0
- package/src/forms/fields/phone-number.ts +39 -0
- package/src/forms/fields/regexp.ts +1 -1
- package/src/forms/fields/simple-form-field.ts +14 -6
- package/src/forms/fields/single-reference.ts +1 -1
- package/src/forms/fields/structured-array.ts +1 -1
- package/src/forms/fields/table.ts +1 -1
- package/src/utils/input-wrapper.ts +14 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FlatTemplatable } from "tempstream";
|
|
2
|
+
import { FormControlContext } from "./form-control.js";
|
|
3
|
+
import { FormFieldControl } from "./form-field-control.js";
|
|
4
|
+
import { FormField } from "../fields/field.js";
|
|
5
|
+
export declare class Hybrid extends FormFieldControl {
|
|
6
|
+
main_field: FormField;
|
|
7
|
+
subfields: Record<string, FormField>;
|
|
8
|
+
constructor(main_field: FormField, subfields: Record<string, FormField>);
|
|
9
|
+
render(fctx: FormControlContext): Promise<FlatTemplatable>;
|
|
10
|
+
}
|
|
@@ -16,6 +16,7 @@ export type SimpleInputOptions = {
|
|
|
16
16
|
step?: number;
|
|
17
17
|
suffix?: string;
|
|
18
18
|
pattern?: string;
|
|
19
|
+
inputmode?: string;
|
|
19
20
|
};
|
|
20
21
|
export declare class SimpleInput<Options extends SimpleInputOptions = SimpleInputOptions> extends FormFieldControl {
|
|
21
22
|
field: FormField<boolean, any>;
|
|
@@ -32,11 +32,13 @@ export type FieldParseResult<T> = {
|
|
|
32
32
|
export declare abstract class FormField<Required extends boolean = boolean, ParsedValue = unknown, DefaultFormControl extends FormControl = FormControl, SealiousValue = any> {
|
|
33
33
|
readonly required: Required;
|
|
34
34
|
name: string;
|
|
35
|
+
label: string;
|
|
35
36
|
constructor(required: Required);
|
|
36
37
|
predicate: Predicate;
|
|
37
38
|
mapToFilter: (parsed: ParsedValue) => unknown;
|
|
38
39
|
init(): Promise<void>;
|
|
39
40
|
setName(name: string): this;
|
|
41
|
+
setLabel(label: string): this;
|
|
40
42
|
_validate(ctx: Context, value: ParsedValue): Promise<FormFieldValidationResponse>;
|
|
41
43
|
abstract getEmptyValue(): ParsedValue;
|
|
42
44
|
isValueValid(_ctx: Context, _value: ParsedValue): Promise<FormFieldValidationResponse>;
|
|
@@ -20,6 +20,8 @@ export * from "./markdown.js";
|
|
|
20
20
|
export * from "./multiple-files.js";
|
|
21
21
|
export * from "./number.js";
|
|
22
22
|
export * from "./password.js";
|
|
23
|
+
export * from "./phone-number.js";
|
|
24
|
+
export * from "./phone-number-with-country-code.js";
|
|
23
25
|
export * from "./pick-from-list-sealious.js";
|
|
24
26
|
export * from "./pick-from-list.js";
|
|
25
27
|
export * from "./regexp.js";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Context } from "koa";
|
|
2
|
+
import { FieldTypes as SealiousFieldTypes } from "sealious";
|
|
3
|
+
import { FormControl } from "../controls/controls.js";
|
|
4
|
+
import { FormDataValue } from "../form-types.js";
|
|
5
|
+
import { FieldParseResult, FormField } from "./field.js";
|
|
6
|
+
export declare class PhoneNumberWithCountryCode<Required extends boolean> extends FormField<Required, SealiousFieldTypes.PhoneNumberValue> {
|
|
7
|
+
getEmptyValue(): SealiousFieldTypes.PhoneNumberValue;
|
|
8
|
+
parse(ctx: Context, raw_value: FormDataValue): Promise<FieldParseResult<SealiousFieldTypes.PhoneNumberValue>>;
|
|
9
|
+
getControl(): FormControl;
|
|
10
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Context } from "koa";
|
|
2
|
+
import { FormControl } from "../controls/controls.js";
|
|
3
|
+
import { FormDataValue } from "../form-types.js";
|
|
4
|
+
import { FormField } from "./field.js";
|
|
5
|
+
export declare class PhoneNumberWithoutCountryCode<Required extends boolean> extends FormField<Required, string> {
|
|
6
|
+
getEmptyValue(): string;
|
|
7
|
+
parse(ctx: Context, raw_value: FormDataValue): Promise<{
|
|
8
|
+
parsable: true;
|
|
9
|
+
parsed_value: string;
|
|
10
|
+
error: null;
|
|
11
|
+
} | {
|
|
12
|
+
parsable: false;
|
|
13
|
+
parsed_value: null;
|
|
14
|
+
error: string;
|
|
15
|
+
}>;
|
|
16
|
+
getControl(): FormControl;
|
|
17
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FormDataValue } from "../form-types.js";
|
|
1
|
+
import { FormData, FormDataValue } from "../form-types.js";
|
|
2
2
|
import { Context } from "koa";
|
|
3
3
|
import { FieldParseResult, FormField } from "./field.js";
|
|
4
4
|
import { SimpleInput } from "../controls/simple-input.js";
|
|
@@ -8,14 +8,16 @@ import { FormControlContext } from "../controls/form-control.js";
|
|
|
8
8
|
export declare abstract class SimpleFormField<Required extends boolean, DefaultControl extends FormControl = SimpleInput, Parsed = string> extends FormField<Required, Parsed, DefaultControl> {
|
|
9
9
|
type: string;
|
|
10
10
|
predicate: import("@sealcode/ts-predicates").Predicate<string>;
|
|
11
|
+
placeholder: string;
|
|
11
12
|
constructor(required: Required, type?: string);
|
|
12
13
|
sealiousValueToForm(_ctx: Context, value: unknown): Promise<FormDataValue>;
|
|
14
|
+
setPlaceholder(placeholder: string): this;
|
|
13
15
|
}
|
|
14
16
|
export declare class TextBasedSimpleField<Required extends boolean, DefaultControl extends FormControl = SimpleInput> extends SimpleFormField<Required, DefaultControl, string | null> {
|
|
15
17
|
parse(_: Context, raw_value: FormDataValue): Promise<FieldParseResult<string>>;
|
|
16
18
|
getSealiousCreateValue(fctx: FormControlContext): Promise<string | null>;
|
|
17
|
-
postSealiousCreate(
|
|
18
|
-
postSealiousEdit(ctx: Context,
|
|
19
|
+
postSealiousCreate(_ctx: Context, _created_item: CollectionItem<any>, _formData: FormData): Promise<void>;
|
|
20
|
+
postSealiousEdit(ctx: Context, _edited_item: CollectionItem<any>, _formData: FormData): Promise<void>;
|
|
19
21
|
getControl(): DefaultControl;
|
|
20
22
|
getEmptyValue(): string;
|
|
21
23
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import { FlatTemplatable } from "tempstream";
|
|
2
|
+
import { FormField } from "../index.js";
|
|
2
3
|
export declare function getRequiredClass(isRequired: boolean): string;
|
|
3
4
|
export declare function inputWrapper(type: string, modifiers: string[], input: FlatTemplatable): Promise<string>;
|
|
5
|
+
export declare function autoWrapInput(field: FormField, input: FlatTemplatable): Promise<string>;
|
|
@@ -2,7 +2,7 @@ import { tempstream } from "tempstream";
|
|
|
2
2
|
import { getRequiredClass, inputWrapper } from "../../utils/input-wrapper.js";
|
|
3
3
|
import { FormFieldControl } from "./form-field-control.js";
|
|
4
4
|
class CheckboxedListInput extends FormFieldControl {
|
|
5
|
-
constructor(field, options = { label: field.name }) {
|
|
5
|
+
constructor(field, options = { label: field.label || field.name }) {
|
|
6
6
|
super([field]);
|
|
7
7
|
this.field = field;
|
|
8
8
|
this.options = options;
|
|
@@ -52,7 +52,7 @@ class CheckboxedListInput extends FormFieldControl {
|
|
|
52
52
|
...this.generateCountBasedClasses(options.length)
|
|
53
53
|
],
|
|
54
54
|
tempstream`<label
|
|
55
|
-
>${this.options.label || this.field.name}</label
|
|
55
|
+
>${this.options.label || this.field.label || this.field.name}</label
|
|
56
56
|
>
|
|
57
57
|
${~valid && fctx.validate ? `<div class="input__error">${message}</div>` : ""}
|
|
58
58
|
<ul>
|
|
@@ -3,7 +3,7 @@ import { attribute } from "../../sanitize.js";
|
|
|
3
3
|
import { SimpleInput } from "./simple-input.js";
|
|
4
4
|
class FreeformDropdown extends SimpleInput {
|
|
5
5
|
constructor(field, _generateOptions, options = {
|
|
6
|
-
label: field.name,
|
|
6
|
+
label: field.label || field.name,
|
|
7
7
|
autosubmit: false,
|
|
8
8
|
autocomplete: true
|
|
9
9
|
}) {
|
|
@@ -36,7 +36,7 @@ class FreeformDropdown extends SimpleInput {
|
|
|
36
36
|
);
|
|
37
37
|
return (
|
|
38
38
|
/* HTML */
|
|
39
|
-
tempstream`<select ${attributes_str}>
|
|
39
|
+
tempstream`<select ${attributes_str} autocomplete="off">
|
|
40
40
|
${Promise.resolve(this.generateOptions(ctx)).then(
|
|
41
41
|
(options) => options.map(
|
|
42
42
|
({ value, label }) => `<option value="${attribute(value)}" ${(value || "") == picked_value ? "selected" : ""}>${label}</option>`
|
|
@@ -48,7 +48,7 @@ class FreeformDropdown extends SimpleInput {
|
|
|
48
48
|
}
|
|
49
49
|
class Dropdown extends FreeformDropdown {
|
|
50
50
|
constructor(field, options = {
|
|
51
|
-
label: field.name,
|
|
51
|
+
label: field.label || field.name,
|
|
52
52
|
autosubmit: false,
|
|
53
53
|
autocomplete: true
|
|
54
54
|
}) {
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { tempstream } from "tempstream";
|
|
2
|
+
import { FormControlContext } from "./form-control.js";
|
|
3
|
+
import { FormFieldControl } from "./form-field-control.js";
|
|
4
|
+
import { autoWrapInput } from "../../utils/input-wrapper.js";
|
|
5
|
+
class Hybrid extends FormFieldControl {
|
|
6
|
+
constructor(main_field, subfields) {
|
|
7
|
+
super(Object.values(subfields));
|
|
8
|
+
this.main_field = main_field;
|
|
9
|
+
this.subfields = subfields;
|
|
10
|
+
for (const [field_name, field] of Object.entries(subfields)) {
|
|
11
|
+
field.setName(`${main_field.name}[${field_name}]`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
async render(fctx) {
|
|
15
|
+
const raw_values = fctx.data.raw_values[this.main_field.name] || {};
|
|
16
|
+
const new_fctx = new FormControlContext(
|
|
17
|
+
fctx.ctx,
|
|
18
|
+
{
|
|
19
|
+
raw_values,
|
|
20
|
+
messages: [],
|
|
21
|
+
field_messages: {}
|
|
22
|
+
},
|
|
23
|
+
[],
|
|
24
|
+
fctx.field_name_prefix,
|
|
25
|
+
fctx.form_id,
|
|
26
|
+
fctx.validate
|
|
27
|
+
);
|
|
28
|
+
return tempstream`<fieldset><legend>${this.main_field.label || this.main_field.name}</legend>${Object.values(
|
|
29
|
+
this.subfields
|
|
30
|
+
).map(
|
|
31
|
+
async (subfield) => tempstream`${autoWrapInput(
|
|
32
|
+
subfield,
|
|
33
|
+
await subfield.getControl().render(new_fctx)
|
|
34
|
+
)}`
|
|
35
|
+
)}</fieldset>`;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export {
|
|
39
|
+
Hybrid
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=hybrid.js.map
|
|
@@ -164,7 +164,9 @@ class MultipleFiles extends FormFieldControl {
|
|
|
164
164
|
"multiple-files",
|
|
165
165
|
["multiple-files", this.field.name, ...this.getClassModifiers()],
|
|
166
166
|
tempstream`
|
|
167
|
-
<label
|
|
167
|
+
<label
|
|
168
|
+
>${this.options.label || this.field.label || this.field.name}</label
|
|
169
|
+
>
|
|
168
170
|
<ul class="multiple-files__list">
|
|
169
171
|
${files.map(
|
|
170
172
|
([item, file]) => this.renderFileItem(item, file)
|
|
@@ -2,6 +2,7 @@ import { tempstream } from "tempstream";
|
|
|
2
2
|
import { getRequiredClass, inputWrapper } from "../../utils/input-wrapper.js";
|
|
3
3
|
import { renderAttributes } from "../../utils/render-attributes.js";
|
|
4
4
|
import { FormFieldControl } from "./form-field-control.js";
|
|
5
|
+
import { SimpleFormField } from "../fields/simple-form-field.js";
|
|
5
6
|
class SimpleInput extends FormFieldControl {
|
|
6
7
|
constructor(field, options) {
|
|
7
8
|
super([field]);
|
|
@@ -15,12 +16,15 @@ class SimpleInput extends FormFieldControl {
|
|
|
15
16
|
return this.options.type || "text";
|
|
16
17
|
}
|
|
17
18
|
getLabel() {
|
|
18
|
-
return this.options.label != void 0 ? this.options.label : this.field.name;
|
|
19
|
+
return this.options.label != void 0 ? this.options.label : this.field.label || this.field.name;
|
|
19
20
|
}
|
|
20
21
|
getID() {
|
|
21
22
|
return this.options.id || this.field.name;
|
|
22
23
|
}
|
|
23
24
|
getPlaceholder() {
|
|
25
|
+
if (this.field instanceof SimpleFormField && this.field.placeholder) {
|
|
26
|
+
return this.field.placeholder;
|
|
27
|
+
}
|
|
24
28
|
return this.options.placeholder === "" ? "" : this.options.placeholder || this.getType();
|
|
25
29
|
}
|
|
26
30
|
async getInputAttributes(fctx) {
|
|
@@ -42,7 +46,8 @@ class SimpleInput extends FormFieldControl {
|
|
|
42
46
|
...required ? [["required", true]] : [],
|
|
43
47
|
...!this.options.autocomplete ? [["autocomplete", "off"]] : [],
|
|
44
48
|
...this.options.step ? [["step", this.options.step]] : [],
|
|
45
|
-
["aria-invalid", String(!valid)]
|
|
49
|
+
["aria-invalid", String(!valid)],
|
|
50
|
+
...this.options.inputmode ? [["inputmode", this.options.inputmode]] : []
|
|
46
51
|
]);
|
|
47
52
|
}
|
|
48
53
|
async postInput(_) {
|
|
@@ -88,7 +88,7 @@ class Table extends FormControl {
|
|
|
88
88
|
...rows.length >= 20 ? ["form-input__wrapper--options-count--20-or-more"] : []
|
|
89
89
|
].join(" ")}"
|
|
90
90
|
>
|
|
91
|
-
<label>${this.options.label}</label>
|
|
91
|
+
<label>${this.options.label || this.table_field.label}</label>
|
|
92
92
|
<div class="table__wrapper">
|
|
93
93
|
<table>
|
|
94
94
|
<tbody>
|
|
@@ -44,7 +44,7 @@ class Boolean extends FormField {
|
|
|
44
44
|
return false;
|
|
45
45
|
}
|
|
46
46
|
getControl() {
|
|
47
|
-
return new Checkbox(this, { label: this.name });
|
|
47
|
+
return new Checkbox(this, { label: this.label || this.name });
|
|
48
48
|
}
|
|
49
49
|
async getSealiousCreateValue(fctx) {
|
|
50
50
|
const { parsed } = await this.getParsedValue(
|
package/lib/forms/fields/date.js
CHANGED
|
@@ -15,7 +15,10 @@ class DateField extends SimpleFormField {
|
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
17
|
getControl() {
|
|
18
|
-
return new SimpleInput(this, {
|
|
18
|
+
return new SimpleInput(this, {
|
|
19
|
+
label: this.label || this.name,
|
|
20
|
+
type: this.type
|
|
21
|
+
});
|
|
19
22
|
}
|
|
20
23
|
async getSealiousCreateValue(fctx) {
|
|
21
24
|
const { parsed } = await this.getParsedValue(
|
|
@@ -31,7 +31,7 @@ class DeepReverseSingleReferenceTable extends Table {
|
|
|
31
31
|
}
|
|
32
32
|
getControl() {
|
|
33
33
|
return new TableControl(this, {
|
|
34
|
-
label: this.name,
|
|
34
|
+
label: this.label || this.name,
|
|
35
35
|
allow_adding: false,
|
|
36
36
|
subfield_controls: {
|
|
37
37
|
selected: this.columns.selected.getControl(),
|
|
@@ -17,7 +17,10 @@ class EmailField extends RegExpField {
|
|
|
17
17
|
this.error_message = message;
|
|
18
18
|
}
|
|
19
19
|
getControl() {
|
|
20
|
-
return new SimpleInput(this, {
|
|
20
|
+
return new SimpleInput(this, {
|
|
21
|
+
label: this.label || this.name,
|
|
22
|
+
type: "email"
|
|
23
|
+
});
|
|
21
24
|
}
|
|
22
25
|
}
|
|
23
26
|
export {
|
|
@@ -20,6 +20,8 @@ export * from "./markdown.js";
|
|
|
20
20
|
export * from "./multiple-files.js";
|
|
21
21
|
export * from "./number.js";
|
|
22
22
|
export * from "./password.js";
|
|
23
|
+
export * from "./phone-number.js";
|
|
24
|
+
export * from "./phone-number-with-country-code.js";
|
|
23
25
|
export * from "./pick-from-list-sealious.js";
|
|
24
26
|
export * from "./pick-from-list.js";
|
|
25
27
|
export * from "./regexp.js";
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import * as countryCodes from "country-codes-list";
|
|
2
|
+
import { FieldTypes as SealiousFieldTypes } from "sealious";
|
|
3
|
+
import { Hybrid } from "../controls/hybrid.js";
|
|
4
|
+
import { FormField } from "./field.js";
|
|
5
|
+
import { PickFromListField } from "./pick-from-list.js";
|
|
6
|
+
import { PhoneNumberWithoutCountryCode } from "./phone-number.js";
|
|
7
|
+
class PhoneNumberWithCountryCode extends FormField {
|
|
8
|
+
getEmptyValue() {
|
|
9
|
+
return new SealiousFieldTypes.PhoneNumberValue("48", "0000000");
|
|
10
|
+
}
|
|
11
|
+
async parse(ctx, raw_value) {
|
|
12
|
+
try {
|
|
13
|
+
return {
|
|
14
|
+
parsable: true,
|
|
15
|
+
parsed_value: SealiousFieldTypes.PhoneNumberValue.fromInput(
|
|
16
|
+
ctx.$context,
|
|
17
|
+
raw_value
|
|
18
|
+
),
|
|
19
|
+
error: null
|
|
20
|
+
};
|
|
21
|
+
} catch (e) {
|
|
22
|
+
return {
|
|
23
|
+
parsable: false,
|
|
24
|
+
parsed_value: null,
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
26
|
+
error: e.message
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
getControl() {
|
|
31
|
+
return new Hybrid(this, {
|
|
32
|
+
country_code: new PickFromListField(
|
|
33
|
+
true,
|
|
34
|
+
async () => countryCodes.all().sort(
|
|
35
|
+
(a, b) => a.countryCallingCode < b.countryCallingCode ? -1 : 1
|
|
36
|
+
).map((code) => ({
|
|
37
|
+
value: code.countryCallingCode,
|
|
38
|
+
label: "+" + code.countryCallingCode + " " + code.flag
|
|
39
|
+
}))
|
|
40
|
+
).setLabel("Country code"),
|
|
41
|
+
number: new PhoneNumberWithoutCountryCode(true).setLabel(
|
|
42
|
+
"Phone number"
|
|
43
|
+
)
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export {
|
|
48
|
+
PhoneNumberWithCountryCode
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=phone-number-with-country-code.js.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { SimpleInput } from "../controls/controls.js";
|
|
2
|
+
import { FormField } from "./field.js";
|
|
3
|
+
class PhoneNumberWithoutCountryCode extends FormField {
|
|
4
|
+
getEmptyValue() {
|
|
5
|
+
return "000 000 000";
|
|
6
|
+
}
|
|
7
|
+
async parse(ctx, raw_value) {
|
|
8
|
+
if (typeof raw_value == "string") {
|
|
9
|
+
return {
|
|
10
|
+
parsable: true,
|
|
11
|
+
parsed_value: raw_value.replaceAll(/[^0-9]/, "").replace(/(\d{3})(?=\d)/g, "$1 ").trim(),
|
|
12
|
+
error: null
|
|
13
|
+
};
|
|
14
|
+
} else {
|
|
15
|
+
return {
|
|
16
|
+
parsable: false,
|
|
17
|
+
parsed_value: null,
|
|
18
|
+
error: "Expected string"
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
getControl() {
|
|
23
|
+
return new SimpleInput(this, {
|
|
24
|
+
inputmode: "tel",
|
|
25
|
+
type: "text",
|
|
26
|
+
placeholder: "123 456 789"
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export {
|
|
31
|
+
PhoneNumberWithoutCountryCode
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=phone-number.js.map
|
|
@@ -37,7 +37,7 @@ class RegExpField extends FormField {
|
|
|
37
37
|
return this.default_value || "";
|
|
38
38
|
}
|
|
39
39
|
getControl() {
|
|
40
|
-
return new SimpleInput(this, { label: this.name });
|
|
40
|
+
return new SimpleInput(this, { label: this.label || this.name });
|
|
41
41
|
}
|
|
42
42
|
async getSealiousCreateValue(fctx) {
|
|
43
43
|
const { parsed } = await this.getParsedValue(
|
|
@@ -13,6 +13,10 @@ class SimpleFormField extends FormField {
|
|
|
13
13
|
}
|
|
14
14
|
return String(value);
|
|
15
15
|
}
|
|
16
|
+
setPlaceholder(placeholder) {
|
|
17
|
+
this.placeholder = placeholder;
|
|
18
|
+
return this;
|
|
19
|
+
}
|
|
16
20
|
}
|
|
17
21
|
class TextBasedSimpleField extends SimpleFormField {
|
|
18
22
|
async parse(_, raw_value) {
|
|
@@ -30,13 +34,13 @@ class TextBasedSimpleField extends SimpleFormField {
|
|
|
30
34
|
);
|
|
31
35
|
return parsed || "";
|
|
32
36
|
}
|
|
33
|
-
async postSealiousCreate(
|
|
37
|
+
async postSealiousCreate(_ctx, _created_item, _formData) {
|
|
34
38
|
}
|
|
35
|
-
async postSealiousEdit(ctx,
|
|
39
|
+
async postSealiousEdit(ctx, _edited_item, _formData) {
|
|
36
40
|
}
|
|
37
41
|
getControl() {
|
|
38
42
|
return new SimpleInput(this, {
|
|
39
|
-
label: this.name,
|
|
43
|
+
label: this.label || this.name,
|
|
40
44
|
type: this.type
|
|
41
45
|
});
|
|
42
46
|
}
|
|
@@ -65,7 +69,7 @@ class NumberBasedSimpleField extends SimpleFormField {
|
|
|
65
69
|
}
|
|
66
70
|
getControl() {
|
|
67
71
|
return new SimpleInput(this, {
|
|
68
|
-
label: this.name,
|
|
72
|
+
label: this.label || this.name,
|
|
69
73
|
type: this.type
|
|
70
74
|
});
|
|
71
75
|
}
|
|
@@ -18,7 +18,7 @@ class StructuredArray extends Table {
|
|
|
18
18
|
}
|
|
19
19
|
getControl() {
|
|
20
20
|
return new TableControl(this, {
|
|
21
|
-
label: this.name,
|
|
21
|
+
label: this.label || this.name,
|
|
22
22
|
subfield_controls: Object.fromEntries(
|
|
23
23
|
Object.entries(this.columns).map(([column_name, subfield]) => [
|
|
24
24
|
column_name,
|
|
@@ -70,7 +70,7 @@ class Table extends FormField {
|
|
|
70
70
|
}
|
|
71
71
|
getControl() {
|
|
72
72
|
return new TableControl(this, {
|
|
73
|
-
label: this.name,
|
|
73
|
+
label: this.label || this.name,
|
|
74
74
|
subfield_controls: Object.fromEntries(
|
|
75
75
|
Object.entries(this.columns).map(([column_name, field]) => [
|
|
76
76
|
column_name,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { tempstream } from "tempstream";
|
|
2
|
+
import { toKebabCase } from "js-convert-case";
|
|
2
3
|
function getRequiredClass(isRequired) {
|
|
3
4
|
return isRequired ? "required" : "";
|
|
4
5
|
}
|
|
@@ -14,7 +15,19 @@ async function inputWrapper(type, modifiers, input) {
|
|
|
14
15
|
${input}
|
|
15
16
|
</div>`;
|
|
16
17
|
}
|
|
18
|
+
async function autoWrapInput(field, input) {
|
|
19
|
+
return inputWrapper(
|
|
20
|
+
toKebabCase(field.constructor.name),
|
|
21
|
+
[
|
|
22
|
+
`type--` + toKebabCase(field.constructor.name),
|
|
23
|
+
`name--` + toKebabCase(field.name),
|
|
24
|
+
getRequiredClass(field.required)
|
|
25
|
+
],
|
|
26
|
+
input
|
|
27
|
+
);
|
|
28
|
+
}
|
|
17
29
|
export {
|
|
30
|
+
autoWrapInput,
|
|
18
31
|
getRequiredClass,
|
|
19
32
|
inputWrapper
|
|
20
33
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sealcode/sealgen",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.4",
|
|
4
4
|
"description": "Module to automate adding routes and collections to a sealious application",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -66,6 +66,7 @@
|
|
|
66
66
|
"@sealcode/ts-predicates": "^0.4.3",
|
|
67
67
|
"chokidar": "^3.6.0",
|
|
68
68
|
"colord": "^2.9.3",
|
|
69
|
+
"country-codes-list": "^2.0.0",
|
|
69
70
|
"deepmerge": "^4.3.1",
|
|
70
71
|
"esbuild": "^0.20.0",
|
|
71
72
|
"escape-goat": "^4.0.0",
|
|
@@ -12,7 +12,7 @@ export class CheckboxedListInput<
|
|
|
12
12
|
> extends FormFieldControl {
|
|
13
13
|
constructor(
|
|
14
14
|
public field: CheckboxedListField<boolean, Values>,
|
|
15
|
-
public options: { label: string } = { label: field.name }
|
|
15
|
+
public options: { label: string } = { label: field.label || field.name }
|
|
16
16
|
) {
|
|
17
17
|
super([field]);
|
|
18
18
|
}
|
|
@@ -67,7 +67,9 @@ export class CheckboxedListInput<
|
|
|
67
67
|
...this.generateCountBasedClasses(options.length),
|
|
68
68
|
],
|
|
69
69
|
tempstream /* HTML */ `<label
|
|
70
|
-
>${this.options.label ||
|
|
70
|
+
>${this.options.label ||
|
|
71
|
+
this.field.label ||
|
|
72
|
+
this.field.name}</label
|
|
71
73
|
>
|
|
72
74
|
${~valid && fctx.validate
|
|
73
75
|
? `<div class="input__error">${message}</div>`
|
|
@@ -20,7 +20,7 @@ export class FreeformDropdown extends SimpleInput {
|
|
|
20
20
|
public field: FormField<boolean, string | null>,
|
|
21
21
|
public _generateOptions: (ctx: Context) => Promise<DropdownOption[]>,
|
|
22
22
|
public options: DropdownOptions = {
|
|
23
|
-
label: field.name,
|
|
23
|
+
label: field.label || field.name,
|
|
24
24
|
autosubmit: false,
|
|
25
25
|
autocomplete: true,
|
|
26
26
|
}
|
|
@@ -61,7 +61,7 @@ export class FreeformDropdown extends SimpleInput {
|
|
|
61
61
|
ctx,
|
|
62
62
|
data
|
|
63
63
|
);
|
|
64
|
-
return /* HTML */ tempstream`<select ${attributes_str}>
|
|
64
|
+
return /* HTML */ tempstream`<select ${attributes_str} autocomplete="off">
|
|
65
65
|
${Promise.resolve(this.generateOptions(ctx)).then((options) =>
|
|
66
66
|
options.map(
|
|
67
67
|
({ value, label }) =>
|
|
@@ -78,7 +78,7 @@ export class Dropdown extends FreeformDropdown {
|
|
|
78
78
|
constructor(
|
|
79
79
|
public field: PickFromListField<boolean>,
|
|
80
80
|
public options: DropdownOptions = {
|
|
81
|
-
label: field.name,
|
|
81
|
+
label: field.label || field.name,
|
|
82
82
|
autosubmit: false,
|
|
83
83
|
autocomplete: true,
|
|
84
84
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { FlatTemplatable, tempstream } from "tempstream";
|
|
2
|
+
import { FormControlContext } from "./form-control.js";
|
|
3
|
+
import { FormFieldControl } from "./form-field-control.js";
|
|
4
|
+
import { FormField } from "../fields/field.js";
|
|
5
|
+
import { FormDataValue } from "../form-types.js";
|
|
6
|
+
import { autoWrapInput } from "../../utils/input-wrapper.js";
|
|
7
|
+
|
|
8
|
+
export class Hybrid extends FormFieldControl {
|
|
9
|
+
constructor(
|
|
10
|
+
public main_field: FormField,
|
|
11
|
+
public subfields: Record<string, FormField>
|
|
12
|
+
) {
|
|
13
|
+
super(Object.values(subfields));
|
|
14
|
+
for (const [field_name, field] of Object.entries(subfields)) {
|
|
15
|
+
field.setName(`${main_field.name}[${field_name}]`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async render(fctx: FormControlContext): Promise<FlatTemplatable> {
|
|
20
|
+
const raw_values = (fctx.data.raw_values[this.main_field.name] ||
|
|
21
|
+
{}) as Record<string, FormDataValue>;
|
|
22
|
+
const new_fctx = new FormControlContext(
|
|
23
|
+
fctx.ctx,
|
|
24
|
+
{
|
|
25
|
+
raw_values,
|
|
26
|
+
messages: [],
|
|
27
|
+
field_messages: {},
|
|
28
|
+
},
|
|
29
|
+
[],
|
|
30
|
+
fctx.field_name_prefix,
|
|
31
|
+
fctx.form_id,
|
|
32
|
+
fctx.validate
|
|
33
|
+
);
|
|
34
|
+
return tempstream`<fieldset><legend>${this.main_field.label || this.main_field.name}</legend>${Object.values(
|
|
35
|
+
this.subfields
|
|
36
|
+
).map(
|
|
37
|
+
async (subfield) =>
|
|
38
|
+
tempstream`${autoWrapInput(
|
|
39
|
+
subfield,
|
|
40
|
+
await subfield.getControl().render(new_fctx)
|
|
41
|
+
)}`
|
|
42
|
+
)}</fieldset>`;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -231,7 +231,11 @@ export class MultipleFiles extends FormFieldControl {
|
|
|
231
231
|
"multiple-files",
|
|
232
232
|
["multiple-files", this.field.name, ...this.getClassModifiers()],
|
|
233
233
|
tempstream /* HTML */ `
|
|
234
|
-
<label
|
|
234
|
+
<label
|
|
235
|
+
>${this.options.label ||
|
|
236
|
+
this.field.label ||
|
|
237
|
+
this.field.name}</label
|
|
238
|
+
>
|
|
235
239
|
<ul class="multiple-files__list">
|
|
236
240
|
${files.map(([item, file]) =>
|
|
237
241
|
this.renderFileItem(item, file)
|
|
@@ -6,6 +6,7 @@ import { FormField } from "../fields/field.js";
|
|
|
6
6
|
import { FormDataValue } from "../form-types.js";
|
|
7
7
|
import { FormControlContext } from "./form-control.js";
|
|
8
8
|
import { FormFieldControl } from "./form-field-control.js";
|
|
9
|
+
import { SimpleFormField } from "../fields/simple-form-field.js";
|
|
9
10
|
|
|
10
11
|
export type SimpleInputOptions = {
|
|
11
12
|
id?: string;
|
|
@@ -19,6 +20,7 @@ export type SimpleInputOptions = {
|
|
|
19
20
|
step?: number;
|
|
20
21
|
suffix?: string;
|
|
21
22
|
pattern?: string;
|
|
23
|
+
inputmode?: string;
|
|
22
24
|
};
|
|
23
25
|
|
|
24
26
|
export class SimpleInput<
|
|
@@ -48,7 +50,7 @@ export class SimpleInput<
|
|
|
48
50
|
getLabel(): string {
|
|
49
51
|
return this.options.label != undefined
|
|
50
52
|
? this.options.label
|
|
51
|
-
: this.field.name;
|
|
53
|
+
: this.field.label || this.field.name;
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
getID(): string {
|
|
@@ -56,6 +58,9 @@ export class SimpleInput<
|
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
getPlaceholder(): string {
|
|
61
|
+
if (this.field instanceof SimpleFormField && this.field.placeholder) {
|
|
62
|
+
return this.field.placeholder;
|
|
63
|
+
}
|
|
59
64
|
return this.options.placeholder === ""
|
|
60
65
|
? ""
|
|
61
66
|
: this.options.placeholder || this.getType();
|
|
@@ -83,6 +88,9 @@ export class SimpleInput<
|
|
|
83
88
|
...(!this.options.autocomplete ? [["autocomplete", "off"]] : []),
|
|
84
89
|
...(this.options.step ? [["step", this.options.step]] : []),
|
|
85
90
|
["aria-invalid", String(!valid)],
|
|
91
|
+
...(this.options.inputmode
|
|
92
|
+
? [["inputmode", this.options.inputmode]]
|
|
93
|
+
: []),
|
|
86
94
|
]) as Record<string, string>;
|
|
87
95
|
}
|
|
88
96
|
|
|
@@ -159,7 +159,7 @@ export class Table<F extends Record<string, FormField>> extends FormControl {
|
|
|
159
159
|
: []),
|
|
160
160
|
].join(" ")}"
|
|
161
161
|
>
|
|
162
|
-
<label>${this.options.label}</label>
|
|
162
|
+
<label>${this.options.label || this.table_field.label}</label>
|
|
163
163
|
<div class="table__wrapper">
|
|
164
164
|
<table>
|
|
165
165
|
<tbody>
|
|
@@ -68,7 +68,7 @@ export class Boolean<Required extends boolean> extends FormField<
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
public getControl(): Checkbox {
|
|
71
|
-
return new Checkbox(this, { label: this.name });
|
|
71
|
+
return new Checkbox(this, { label: this.label || this.name });
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
async getSealiousCreateValue(fctx: FormControlContext): Promise<boolean> {
|
package/src/forms/fields/date.ts
CHANGED
|
@@ -30,7 +30,10 @@ export class DateField<Required extends boolean> extends SimpleFormField<
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
getControl(): SimpleInput<SimpleInputOptions> {
|
|
33
|
-
return new SimpleInput(this, {
|
|
33
|
+
return new SimpleInput(this, {
|
|
34
|
+
label: this.label || this.name,
|
|
35
|
+
type: this.type,
|
|
36
|
+
});
|
|
34
37
|
}
|
|
35
38
|
|
|
36
39
|
async getSealiousCreateValue(
|
|
@@ -56,7 +56,7 @@ export class DeepReverseSingleReferenceTable extends Table<
|
|
|
56
56
|
|
|
57
57
|
getControl(): TableControl<any> {
|
|
58
58
|
return new TableControl(this, {
|
|
59
|
-
label: this.name,
|
|
59
|
+
label: this.label || this.name,
|
|
60
60
|
allow_adding: false,
|
|
61
61
|
subfield_controls: {
|
|
62
62
|
selected: this.columns.selected.getControl(),
|
|
@@ -66,6 +66,7 @@ export abstract class FormField<
|
|
|
66
66
|
SealiousValue = any,
|
|
67
67
|
> {
|
|
68
68
|
name: string;
|
|
69
|
+
label: string;
|
|
69
70
|
constructor(public readonly required: Required) {}
|
|
70
71
|
predicate: Predicate = predicates.unknown;
|
|
71
72
|
mapToFilter: (parsed: ParsedValue) => unknown = (value) => value;
|
|
@@ -77,6 +78,11 @@ export abstract class FormField<
|
|
|
77
78
|
return this;
|
|
78
79
|
}
|
|
79
80
|
|
|
81
|
+
setLabel(label: string): this {
|
|
82
|
+
this.label = label;
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
|
|
80
86
|
public async _validate(
|
|
81
87
|
ctx: Context,
|
|
82
88
|
value: ParsedValue
|
|
@@ -20,6 +20,8 @@ export * from "./markdown.js";
|
|
|
20
20
|
export * from "./multiple-files.js";
|
|
21
21
|
export * from "./number.js";
|
|
22
22
|
export * from "./password.js";
|
|
23
|
+
export * from "./phone-number.js";
|
|
24
|
+
export * from "./phone-number-with-country-code.js";
|
|
23
25
|
export * from "./pick-from-list-sealious.js";
|
|
24
26
|
export * from "./pick-from-list.js";
|
|
25
27
|
export * from "./regexp.js";
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as countryCodes from "country-codes-list";
|
|
2
|
+
import { Context } from "koa";
|
|
3
|
+
import { FieldTypes as SealiousFieldTypes } from "sealious";
|
|
4
|
+
import { FormControl } from "../controls/controls.js";
|
|
5
|
+
import { Hybrid } from "../controls/hybrid.js";
|
|
6
|
+
import { FormDataValue } from "../form-types.js";
|
|
7
|
+
import { FieldParseResult, FormField } from "./field.js";
|
|
8
|
+
import { PickFromListField } from "./pick-from-list.js";
|
|
9
|
+
import { PhoneNumberWithoutCountryCode } from "./phone-number.js";
|
|
10
|
+
|
|
11
|
+
export class PhoneNumberWithCountryCode<
|
|
12
|
+
Required extends boolean,
|
|
13
|
+
> extends FormField<Required, SealiousFieldTypes.PhoneNumberValue> {
|
|
14
|
+
public getEmptyValue(): SealiousFieldTypes.PhoneNumberValue {
|
|
15
|
+
return new SealiousFieldTypes.PhoneNumberValue("48", "0000000");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async parse(
|
|
19
|
+
ctx: Context,
|
|
20
|
+
raw_value: FormDataValue
|
|
21
|
+
): Promise<FieldParseResult<SealiousFieldTypes.PhoneNumberValue>> {
|
|
22
|
+
try {
|
|
23
|
+
return {
|
|
24
|
+
parsable: true,
|
|
25
|
+
parsed_value: SealiousFieldTypes.PhoneNumberValue.fromInput(
|
|
26
|
+
ctx.$context,
|
|
27
|
+
raw_value
|
|
28
|
+
),
|
|
29
|
+
error: null,
|
|
30
|
+
};
|
|
31
|
+
} catch (e) {
|
|
32
|
+
return {
|
|
33
|
+
parsable: false,
|
|
34
|
+
parsed_value: null,
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
36
|
+
error: e.message as string,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
getControl(): FormControl {
|
|
42
|
+
return new Hybrid(this, {
|
|
43
|
+
country_code: new PickFromListField(true, async () =>
|
|
44
|
+
countryCodes
|
|
45
|
+
.all()
|
|
46
|
+
.sort((a, b) =>
|
|
47
|
+
a.countryCallingCode < b.countryCallingCode ? -1 : 1
|
|
48
|
+
)
|
|
49
|
+
.map((code) => ({
|
|
50
|
+
value: code.countryCallingCode,
|
|
51
|
+
label: "+" + code.countryCallingCode + " " + code.flag,
|
|
52
|
+
}))
|
|
53
|
+
).setLabel("Country code"),
|
|
54
|
+
number: new PhoneNumberWithoutCountryCode(true).setLabel(
|
|
55
|
+
"Phone number"
|
|
56
|
+
),
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Context } from "koa";
|
|
2
|
+
import { FormControl, SimpleInput } from "../controls/controls.js";
|
|
3
|
+
import { FormDataValue } from "../form-types.js";
|
|
4
|
+
import { FormField } from "./field.js";
|
|
5
|
+
|
|
6
|
+
export class PhoneNumberWithoutCountryCode<
|
|
7
|
+
Required extends boolean,
|
|
8
|
+
> extends FormField<Required, string> {
|
|
9
|
+
public getEmptyValue(): string {
|
|
10
|
+
return "000 000 000";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async parse(ctx: Context, raw_value: FormDataValue) {
|
|
14
|
+
if (typeof raw_value == "string") {
|
|
15
|
+
return {
|
|
16
|
+
parsable: <const>true,
|
|
17
|
+
parsed_value: raw_value
|
|
18
|
+
.replaceAll(/[^0-9]/, "")
|
|
19
|
+
.replace(/(\d{3})(?=\d)/g, "$1 ")
|
|
20
|
+
.trim(),
|
|
21
|
+
error: null,
|
|
22
|
+
};
|
|
23
|
+
} else {
|
|
24
|
+
return {
|
|
25
|
+
parsable: <const>false,
|
|
26
|
+
parsed_value: null,
|
|
27
|
+
error: "Expected string",
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
getControl(): FormControl {
|
|
33
|
+
return new SimpleInput(this, {
|
|
34
|
+
inputmode: "tel",
|
|
35
|
+
type: "text",
|
|
36
|
+
placeholder: "123 456 789",
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -59,7 +59,7 @@ export class RegExpField<Required extends boolean> extends FormField<
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
public getControl(): SimpleInput {
|
|
62
|
-
return new SimpleInput(this, { label: this.name });
|
|
62
|
+
return new SimpleInput(this, { label: this.label || this.name });
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
async getSealiousCreateValue(fctx: FormControlContext): Promise<string> {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint @typescript-eslint/no-unused-vars: off */
|
|
2
|
-
import { FormDataValue } from "../form-types.js";
|
|
2
|
+
import { FormData, FormDataValue } from "../form-types.js";
|
|
3
3
|
import { Context } from "koa";
|
|
4
4
|
import { predicates } from "@sealcode/ts-predicates";
|
|
5
5
|
import { FieldParseResult, FormField } from "./field.js";
|
|
@@ -14,6 +14,7 @@ export abstract class SimpleFormField<
|
|
|
14
14
|
Parsed = string,
|
|
15
15
|
> extends FormField<Required, Parsed, DefaultControl> {
|
|
16
16
|
predicate = predicates.string;
|
|
17
|
+
public placeholder: string;
|
|
17
18
|
|
|
18
19
|
constructor(
|
|
19
20
|
required: Required,
|
|
@@ -32,6 +33,11 @@ export abstract class SimpleFormField<
|
|
|
32
33
|
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
33
34
|
return String(value) as FormDataValue;
|
|
34
35
|
}
|
|
36
|
+
|
|
37
|
+
setPlaceholder(placeholder: string) {
|
|
38
|
+
this.placeholder = placeholder;
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
35
41
|
}
|
|
36
42
|
|
|
37
43
|
export class TextBasedSimpleField<
|
|
@@ -61,20 +67,22 @@ export class TextBasedSimpleField<
|
|
|
61
67
|
}
|
|
62
68
|
|
|
63
69
|
async postSealiousCreate(
|
|
64
|
-
|
|
70
|
+
_ctx: Context,
|
|
65
71
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
66
|
-
|
|
72
|
+
_created_item: CollectionItem<any>,
|
|
73
|
+
_formData: FormData
|
|
67
74
|
): Promise<void> {}
|
|
68
75
|
|
|
69
76
|
async postSealiousEdit(
|
|
70
77
|
ctx: Context,
|
|
71
78
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
72
|
-
|
|
79
|
+
_edited_item: CollectionItem<any>,
|
|
80
|
+
_formData: FormData
|
|
73
81
|
): Promise<void> {}
|
|
74
82
|
|
|
75
83
|
getControl(): DefaultControl {
|
|
76
84
|
return new SimpleInput(this, {
|
|
77
|
-
label: this.name,
|
|
85
|
+
label: this.label || this.name,
|
|
78
86
|
type: this.type,
|
|
79
87
|
}) as unknown as DefaultControl;
|
|
80
88
|
}
|
|
@@ -115,7 +123,7 @@ export class NumberBasedSimpleField<
|
|
|
115
123
|
|
|
116
124
|
getControl(): DefaultControl {
|
|
117
125
|
return new SimpleInput(this, {
|
|
118
|
-
label: this.name,
|
|
126
|
+
label: this.label || this.name,
|
|
119
127
|
type: this.type,
|
|
120
128
|
}) as unknown as DefaultControl;
|
|
121
129
|
}
|
|
@@ -13,7 +13,7 @@ export class SingleReference<
|
|
|
13
13
|
> extends CollectionField<F, Required> {
|
|
14
14
|
getControl(): SingleReferenceDropdown<TargetCollection, F, Required> {
|
|
15
15
|
return new SingleReferenceDropdown(this, {
|
|
16
|
-
label: this.name,
|
|
16
|
+
label: this.label || this.name,
|
|
17
17
|
getLabel: (item) => item.id,
|
|
18
18
|
});
|
|
19
19
|
}
|
|
@@ -55,7 +55,7 @@ export class StructuredArray<
|
|
|
55
55
|
SealiousFields[name]
|
|
56
56
|
>;
|
|
57
57
|
}>(this as any, {
|
|
58
|
-
label: this.name,
|
|
58
|
+
label: this.label || this.name,
|
|
59
59
|
subfield_controls: Object.fromEntries(
|
|
60
60
|
Object.entries(this.columns).map(([column_name, subfield]) => [
|
|
61
61
|
column_name as keyof SealiousFields,
|
|
@@ -98,7 +98,7 @@ export class Table<F extends Record<string, FormField>> extends FormField<
|
|
|
98
98
|
|
|
99
99
|
getControl(): TableControl<F> {
|
|
100
100
|
return new TableControl<F>(this, {
|
|
101
|
-
label: this.name,
|
|
101
|
+
label: this.label || this.name,
|
|
102
102
|
subfield_controls: Object.fromEntries(
|
|
103
103
|
Object.entries(this.columns).map(([column_name, field]) => [
|
|
104
104
|
column_name as keyof F,
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { FlatTemplatable, tempstream } from "tempstream";
|
|
2
|
+
import { FormField } from "../index.js";
|
|
3
|
+
import { toKebabCase } from "js-convert-case";
|
|
2
4
|
|
|
3
5
|
export function getRequiredClass(isRequired: boolean): string {
|
|
4
6
|
return isRequired ? "required" : "";
|
|
@@ -21,3 +23,15 @@ export async function inputWrapper(
|
|
|
21
23
|
${input}
|
|
22
24
|
</div>`;
|
|
23
25
|
}
|
|
26
|
+
|
|
27
|
+
export async function autoWrapInput(field: FormField, input: FlatTemplatable) {
|
|
28
|
+
return inputWrapper(
|
|
29
|
+
toKebabCase(field.constructor.name),
|
|
30
|
+
[
|
|
31
|
+
`type--` + toKebabCase(field.constructor.name),
|
|
32
|
+
`name--` + toKebabCase(field.name),
|
|
33
|
+
getRequiredClass(field.required),
|
|
34
|
+
],
|
|
35
|
+
input
|
|
36
|
+
);
|
|
37
|
+
}
|