@sealcode/sealgen 0.19.31 → 0.19.33

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.
Files changed (85) hide show
  1. package/@types/forms/controls/dropdown.d.ts +2 -2
  2. package/@types/forms/controls/single-reference.d.ts +1 -2
  3. package/@types/forms/fields/CollectionField.d.ts +1 -0
  4. package/@types/forms/fields/boolean.d.ts +1 -2
  5. package/@types/forms/fields/collection-field.d.ts +12 -5
  6. package/@types/forms/fields/coordinates.d.ts +2 -2
  7. package/@types/forms/fields/date.d.ts +1 -2
  8. package/@types/forms/fields/datetime.d.ts +1 -2
  9. package/@types/forms/fields/deep-reverse-single-reference-list.d.ts +1 -1
  10. package/@types/forms/fields/deep-reverse-single-reference-table.d.ts +1 -2
  11. package/@types/forms/fields/enum-multiple-sealious.d.ts +1 -2
  12. package/@types/forms/fields/field.d.ts +6 -2
  13. package/@types/forms/fields/fields.d.ts +1 -0
  14. package/@types/forms/fields/file.d.ts +4 -3
  15. package/@types/forms/fields/int.d.ts +1 -2
  16. package/@types/forms/fields/json.d.ts +1 -2
  17. package/@types/forms/fields/phone-number-with-country-code.d.ts +1 -2
  18. package/@types/forms/fields/regexp.d.ts +1 -2
  19. package/@types/forms/fields/simple-form-field.d.ts +2 -3
  20. package/@types/forms/fields/single-reference.d.ts +2 -3
  21. package/@types/forms/fields/structured-array.d.ts +1 -2
  22. package/@types/forms/fields/structured.d.ts +19 -0
  23. package/@types/forms/fields/text.d.ts +1 -2
  24. package/@types/forms/fields/url.d.ts +1 -2
  25. package/lib/forms/controls/checkboxed-list-input.test.js +3 -3
  26. package/lib/forms/controls/field-group.js +3 -1
  27. package/lib/forms/controls/simple-input.js +6 -4
  28. package/lib/forms/controls/textarea.js +1 -1
  29. package/lib/forms/fields/boolean.js +2 -6
  30. package/lib/forms/fields/collection-field.js +49 -5
  31. package/lib/forms/fields/coordinates.js +1 -5
  32. package/lib/forms/fields/date.js +1 -8
  33. package/lib/forms/fields/datetime.js +1 -8
  34. package/lib/forms/fields/deep-reverse-single-reference-list.js +1 -1
  35. package/lib/forms/fields/deep-reverse-single-reference-table.js +1 -1
  36. package/lib/forms/fields/enum-multiple-sealious.js +1 -5
  37. package/lib/forms/fields/field.js +17 -4
  38. package/lib/forms/fields/fields.js +1 -0
  39. package/lib/forms/fields/file.js +6 -6
  40. package/lib/forms/fields/int.js +1 -8
  41. package/lib/forms/fields/json.js +1 -5
  42. package/lib/forms/fields/phone-number-with-country-code.js +1 -5
  43. package/lib/forms/fields/regexp.js +1 -5
  44. package/lib/forms/fields/simple-form-field.js +6 -16
  45. package/lib/forms/fields/single-reference.js +2 -6
  46. package/lib/forms/fields/structured-array.js +1 -5
  47. package/lib/forms/fields/structured.js +107 -0
  48. package/lib/forms/fields/text.js +1 -5
  49. package/lib/forms/fields/url.js +2 -6
  50. package/lib/forms/form.js +2 -1
  51. package/lib/get-fonts.js +7 -1
  52. package/lib/templates/shared/collection-create-form.js +4 -0
  53. package/lib/templates/shared/collection-edit-form.js +5 -0
  54. package/lib/utils/input-wrapper.js +2 -2
  55. package/package.json +3 -2
  56. package/src/forms/controls/checkboxed-list-input.test.ts +3 -3
  57. package/src/forms/controls/dropdown.ts +1 -1
  58. package/src/forms/controls/field-group.ts +9 -7
  59. package/src/forms/controls/simple-input.ts +19 -15
  60. package/src/forms/controls/textarea.ts +2 -2
  61. package/src/forms/fields/boolean.ts +2 -7
  62. package/src/forms/fields/collection-field.ts +88 -11
  63. package/src/forms/fields/coordinates.ts +3 -7
  64. package/src/forms/fields/date.ts +1 -11
  65. package/src/forms/fields/datetime.ts +1 -11
  66. package/src/forms/fields/deep-reverse-single-reference-list.ts +1 -1
  67. package/src/forms/fields/deep-reverse-single-reference-table.ts +1 -2
  68. package/src/forms/fields/enum-multiple-sealious.ts +1 -6
  69. package/src/forms/fields/field.ts +24 -6
  70. package/src/forms/fields/fields.ts +1 -0
  71. package/src/forms/fields/file.ts +9 -9
  72. package/src/forms/fields/int.ts +1 -11
  73. package/src/forms/fields/json.ts +2 -7
  74. package/src/forms/fields/phone-number-with-country-code.ts +3 -6
  75. package/src/forms/fields/regexp.ts +1 -6
  76. package/src/forms/fields/simple-form-field.ts +6 -22
  77. package/src/forms/fields/single-reference.ts +7 -10
  78. package/src/forms/fields/structured-array.ts +2 -7
  79. package/src/forms/fields/structured.ts +151 -0
  80. package/src/forms/fields/text.ts +1 -6
  81. package/src/forms/fields/url.ts +2 -9
  82. package/src/forms/form.ts +2 -1
  83. package/src/templates/shared/collection-create-form.ts +4 -0
  84. package/src/templates/shared/collection-edit-form.ts +5 -0
  85. package/src/utils/input-wrapper.ts +2 -2
@@ -12,11 +12,7 @@ class EnumMultipleSealious extends CheckboxedListField {
12
12
  generateFieldDeclaration(field_info, vars) {
13
13
  return `new ${vars.form_field_types}.${this.constructor.name}(${vars.sealious_field})`;
14
14
  }
15
- async getSealiousCreateValue(fctx) {
16
- const { parsed } = await this.getParsedValue(
17
- fctx.ctx,
18
- fctx.data.raw_values
19
- );
15
+ async parsedToSealious(parsed) {
20
16
  const result = Object.entries(parsed || {}).filter(([, value]) => value == "on").map(([key]) => key);
21
17
  return result;
22
18
  }
@@ -1,6 +1,7 @@
1
1
  import { predicates } from "@sealcode/ts-predicates";
2
2
  import { t } from "../../utils/translate.js";
3
3
  import { wrapAttribute, wrapKeyName } from "../../utils/wrap-attributes.js";
4
+ import { getProperty } from "dot-prop";
4
5
  function fieldsToShape(obj) {
5
6
  return Object.fromEntries(
6
7
  Object.entries(obj).map(([key, value]) => [key, value.predicate])
@@ -27,6 +28,13 @@ class FormField {
27
28
  this.label = label;
28
29
  return this;
29
30
  }
31
+ getValuePath() {
32
+ return this.value_path || this.name;
33
+ }
34
+ setValuePath(path) {
35
+ this.value_path = path;
36
+ return this;
37
+ }
30
38
  async _validate(ctx, value) {
31
39
  if (value === "" || value === null || value === void 0) {
32
40
  if (this.required) {
@@ -52,7 +60,7 @@ class FormField {
52
60
  return { valid: true, message: "" };
53
61
  }
54
62
  async getParsedValue(ctx, all_form_values, validate = false) {
55
- const raw = all_form_values[this.name];
63
+ const raw = getProperty(all_form_values, this.getValuePath());
56
64
  if (raw == void 0 || raw == null || raw == "") {
57
65
  return {
58
66
  parsed: null,
@@ -80,7 +88,7 @@ class FormField {
80
88
  parsed: parsed_value,
81
89
  ...validate ? { valid } : {},
82
90
  message,
83
- raw: all_form_values[this.name]
91
+ raw
84
92
  };
85
93
  } else {
86
94
  return { parsed: parsed_value, raw, message: "parsed" };
@@ -98,9 +106,14 @@ class FormField {
98
106
  getSealiousCreateValue(fctx) {
99
107
  throw new Error("This field does not have a default sealious mapping");
100
108
  }
101
- sealiousValueToForm(ctx, sealiousValue, item) {
109
+ parsedToSealious(parsed) {
102
110
  throw new Error("This field does not have a default sealious mapping");
103
111
  }
112
+ sealiousValueToForm(ctx, sealiousValue, item) {
113
+ throw new Error(
114
+ `Field '${this.name}' does not have a default sealious mapping`
115
+ );
116
+ }
104
117
  async postSealiousCreate(ctx, created_item, form_data) {
105
118
  }
106
119
  async postSealiousEdit(ctx, edited_item, form_data) {
@@ -111,7 +124,7 @@ class FormField {
111
124
  )})`;
112
125
  }
113
126
  generateCreateValueGetter(field_info, vars) {
114
- return `${wrapKeyName(field_info.name)}: await ${vars.form_fields}${wrapAttribute(field_info.name)}.getSealiousCreateValue(fctx)`;
127
+ return `${wrapKeyName(field_info.name)}: await ${vars.form_fields}${wrapAttribute(field_info.name)}.parsedToSealious(data${wrapAttribute(field_info.name)})`;
115
128
  }
116
129
  generateInitialValue(field_info, vars) {
117
130
  return `${wrapKeyName(field_info.name)}: await ${vars.form_fields}${wrapAttribute(field_info.name)}.sealiousValueToForm(ctx, item.get("${field_info.name}"))`;
@@ -32,4 +32,5 @@ export * from "./structured-array.js";
32
32
  export * from "./table.js";
33
33
  export * from "./text.js";
34
34
  export * from "./url.js";
35
+ export * from "./structured.js";
35
36
  //# sourceMappingURL=fields.js.map
@@ -2,6 +2,7 @@ import { hasFieldOfType, is, predicates } from "@sealcode/ts-predicates";
2
2
  import { PathFilePointer } from "@sealcode/file-manager";
3
3
  import { FormField } from "./field.js";
4
4
  import { File as FileControl } from "../controls/file.js";
5
+ import { ImageValue } from "sealious";
5
6
  class File extends FormField {
6
7
  constructor(required) {
7
8
  super(required);
@@ -27,7 +28,7 @@ class File extends FormField {
27
28
  raw_value,
28
29
  "old",
29
30
  predicates.instanceOf(PathFilePointer)
30
- ) ? await ctx.$app.fileManager.toPointer(raw_value.old) : null;
31
+ ) && raw_value.old ? await ctx.$app.fileManager.toPointer(raw_value.old) : null;
31
32
  const new_file = hasFieldOfType(
32
33
  raw_value,
33
34
  "new",
@@ -56,11 +57,7 @@ class File extends FormField {
56
57
  getControl() {
57
58
  return new FileControl(this, { label: this.name, autocomplete: false });
58
59
  }
59
- async getSealiousCreateValue(fctx) {
60
- const { parsed: value } = await this.getParsedValue(
61
- fctx.ctx,
62
- fctx.data.raw_values
63
- );
60
+ async parsedToSealious(value) {
64
61
  const pointer = value?.new || value?.old || void 0;
65
62
  if (this.required && !pointer) {
66
63
  throw new Error("File is required, but no value is provided");
@@ -71,6 +68,9 @@ class File extends FormField {
71
68
  if (!sealiousValue) {
72
69
  return {};
73
70
  }
71
+ if (sealiousValue instanceof ImageValue) {
72
+ return { old: sealiousValue.toFile() };
73
+ }
74
74
  if (typeof sealiousValue == "string") {
75
75
  sealiousValue = await ctx.$app.fileManager.fromToken(sealiousValue);
76
76
  }
@@ -3,14 +3,7 @@ class Int extends NumberBasedSimpleField {
3
3
  constructor(required) {
4
4
  super(required, "number");
5
5
  }
6
- async getSealiousCreateValue(fctx) {
7
- const { parsed } = await this.getParsedValue(
8
- fctx.ctx,
9
- fctx.data.raw_values
10
- );
11
- if (parsed == null) {
12
- return void 0;
13
- }
6
+ async parsedToSealious(parsed) {
14
7
  if (isNaN(parsed)) {
15
8
  return void 0;
16
9
  } else
@@ -17,11 +17,7 @@ class JSONField extends SimpleFormField {
17
17
  parsed_value: JSON.parse(raw_value)
18
18
  };
19
19
  }
20
- async getSealiousCreateValue(fctx) {
21
- const { parsed } = await this.getParsedValue(
22
- fctx.ctx,
23
- fctx.data.raw_values
24
- );
20
+ async parsedToSealious(parsed) {
25
21
  return parsed;
26
22
  }
27
23
  }
@@ -42,11 +42,7 @@ class PhoneNumberWithCountryCode extends FormField {
42
42
  )
43
43
  });
44
44
  }
45
- async getSealiousCreateValue(fctx) {
46
- const { parsed } = await this.getParsedValue(
47
- fctx.ctx,
48
- fctx.data.raw_values
49
- );
45
+ async parsedToSealious(parsed) {
50
46
  if (!parsed) {
51
47
  return "";
52
48
  }
@@ -39,11 +39,7 @@ class RegExpField extends FormField {
39
39
  getControl() {
40
40
  return new SimpleInput(this, { label: this.label || this.name });
41
41
  }
42
- async getSealiousCreateValue(fctx) {
43
- const { parsed } = await this.getParsedValue(
44
- fctx.ctx,
45
- fctx.data.raw_values
46
- );
42
+ async parsedToSealious(parsed) {
47
43
  return parsed || "";
48
44
  }
49
45
  async sealiousValueToForm(ctx, sealious_value) {
@@ -1,6 +1,7 @@
1
1
  import { predicates } from "@sealcode/ts-predicates";
2
2
  import { FormField } from "./field.js";
3
3
  import { SimpleInput } from "../controls/simple-input.js";
4
+ import { Textarea } from "../controls/controls.js";
4
5
  class SimpleFormField extends FormField {
5
6
  constructor(required, type = "text") {
6
7
  super(required);
@@ -27,22 +28,15 @@ class TextBasedSimpleField extends SimpleFormField {
27
28
  error: null
28
29
  };
29
30
  }
30
- async getSealiousCreateValue(fctx) {
31
- if (this.disabled) {
32
- return null;
33
- }
34
- const { parsed } = await this.getParsedValue(
35
- fctx.ctx,
36
- fctx.data.raw_values
37
- );
38
- return parsed || "";
31
+ async parsedToSealious(value) {
32
+ return value || "";
39
33
  }
40
34
  async postSealiousCreate(_ctx, _created_item, _formData) {
41
35
  }
42
36
  async postSealiousEdit(_ctx, _edited_item, _formData) {
43
37
  }
44
38
  getControl() {
45
- return new SimpleInput(this, {
39
+ return new Textarea(this, {
46
40
  label: this.label || this.name,
47
41
  type: this.type
48
42
  });
@@ -59,12 +53,8 @@ class NumberBasedSimpleField extends SimpleFormField {
59
53
  error: null
60
54
  };
61
55
  }
62
- async getSealiousCreateValue(fctx) {
63
- const { parsed } = await this.getParsedValue(
64
- fctx.ctx,
65
- fctx.data.raw_values
66
- );
67
- return parsed || 0;
56
+ async parsedToSealious(value) {
57
+ return value || 0;
68
58
  }
69
59
  async postSealiousCreate() {
70
60
  }
@@ -8,12 +8,8 @@ class SingleReference extends CollectionField {
8
8
  getLabel: (item) => item.id
9
9
  });
10
10
  }
11
- async getSealiousCreateValue(fctx) {
12
- const { parsed } = await this.getParsedValue(
13
- fctx.ctx,
14
- fctx.data.raw_values
15
- );
16
- return parsed || void 0;
11
+ async parsedToSealious(parsed) {
12
+ return parsed || "";
17
13
  }
18
14
  async sealiousValueToForm(_ctx, value) {
19
15
  return value || void 0;
@@ -32,11 +32,7 @@ class StructuredArray extends Table {
32
32
  generateFieldDeclaration(_field_info, vars) {
33
33
  return `new ${vars.form_field_types}.${this.constructor.name}(${vars.sealious_field})`;
34
34
  }
35
- async getSealiousCreateValue(fctx) {
36
- const { parsed } = await this.getParsedValue(
37
- fctx.ctx,
38
- fctx.data.raw_values
39
- );
35
+ async parsedToSealious(parsed) {
40
36
  return parsed || this.getEmptyValue();
41
37
  }
42
38
  async sealiousValueToForm(ctx, sealiousValue) {
@@ -0,0 +1,107 @@
1
+ import { is, predicates } from "@sealcode/ts-predicates";
2
+ import { FormField } from "./field.js";
3
+ import { FieldGroup } from "../controls/controls.js";
4
+ import { sealiousFieldToFormField } from "./collection-field.js";
5
+ class StructuredSealiousField extends FormField {
6
+ constructor(sealiousField) {
7
+ super(false);
8
+ this.sealiousField = sealiousField;
9
+ }
10
+ getEmptyValue() {
11
+ return {};
12
+ }
13
+ async parse(ctx, raw_value) {
14
+ const sealiousField = this.sealiousField;
15
+ if (!is(raw_value, predicates.object)) {
16
+ raw_value = {};
17
+ }
18
+ const results = await Promise.all(
19
+ Object.entries(sealiousField.fields).map(async ([key, field]) => {
20
+ const formfield = sealiousFieldToFormField(
21
+ field,
22
+ key,
23
+ this.name
24
+ );
25
+ return [
26
+ key,
27
+ await formfield.parse(
28
+ ctx,
29
+ raw_value[key] || ""
30
+ )
31
+ ];
32
+ })
33
+ );
34
+ const parsable = results.every(([, r]) => r.parsable);
35
+ if (parsable) {
36
+ return {
37
+ parsable,
38
+ error: null,
39
+ parsed_value: Object.fromEntries(
40
+ results.map(([key, value]) => [key, value.parsed_value])
41
+ )
42
+ };
43
+ } else
44
+ return {
45
+ parsable: false,
46
+ parsed_value: null,
47
+ error: results.map(([, r]) => r.error).join("; ")
48
+ };
49
+ }
50
+ async parsedToSealious(parsed) {
51
+ return Object.fromEntries(
52
+ await Promise.all(
53
+ Object.entries(parsed).map(
54
+ async ([key, value]) => {
55
+ const sealious_field = this.sealiousField.fields[key];
56
+ const formfield = sealiousFieldToFormField(
57
+ sealious_field,
58
+ key,
59
+ this.name
60
+ );
61
+ return [key, await formfield.parsedToSealious(value)];
62
+ }
63
+ )
64
+ )
65
+ );
66
+ }
67
+ async sealiousValueToForm(ctx, sealiousValue, item) {
68
+ return Object.fromEntries(
69
+ await Promise.all(
70
+ Object.entries(
71
+ sealiousValue || {}
72
+ ).map(async ([key, value]) => {
73
+ const sealious_field = this.sealiousField.fields[key];
74
+ const formfield = sealiousFieldToFormField(
75
+ sealious_field,
76
+ key,
77
+ this.name
78
+ );
79
+ return [
80
+ key,
81
+ await formfield.sealiousValueToForm(ctx, value, item)
82
+ ];
83
+ })
84
+ )
85
+ );
86
+ }
87
+ getControl() {
88
+ const structured = this.sealiousField;
89
+ return new FieldGroup(
90
+ Object.keys(structured.fields).map((key) => {
91
+ return sealiousFieldToFormField(
92
+ structured.fields[key],
93
+ key,
94
+ this.name
95
+ ).setLabel(key).getControl();
96
+ }),
97
+ { label: this.name }
98
+ );
99
+ }
100
+ generateFieldDeclaration(_field_info, vars) {
101
+ return `new ${vars.form_field_types}.${this.constructor.name}(${vars.sealious_field})`;
102
+ }
103
+ }
104
+ export {
105
+ StructuredSealiousField
106
+ };
107
+ //# sourceMappingURL=structured.js.map
@@ -3,11 +3,7 @@ class Text extends TextBasedSimpleField {
3
3
  constructor(required) {
4
4
  super(required, "text");
5
5
  }
6
- async getSealiousCreateValue(fctx) {
7
- const { parsed } = await this.getParsedValue(
8
- fctx.ctx,
9
- fctx.data.raw_values
10
- );
6
+ async parsedToSealious(parsed) {
11
7
  return parsed || this.getEmptyValue();
12
8
  }
13
9
  }
@@ -3,12 +3,8 @@ class URLField extends TextBasedSimpleField {
3
3
  constructor(required) {
4
4
  super(required, "text");
5
5
  }
6
- async getSealiousCreateValue(fctx) {
7
- const { parsed } = await this.getParsedValue(
8
- fctx.ctx,
9
- fctx.data.raw_values
10
- );
11
- return parsed || null;
6
+ async parsedToSealious(parsed) {
7
+ return parsed || "";
12
8
  }
13
9
  }
14
10
  export {
package/lib/forms/form.js CHANGED
@@ -199,10 +199,11 @@ class Form extends MountableWithFields {
199
199
  });
200
200
  router.get(path, async (ctx) => {
201
201
  ctx.type = "html";
202
+ const raw_values = await this.extractRawValues(ctx);
202
203
  ctx.body = await this.render(
203
204
  ctx,
204
205
  {
205
- raw_values: await this.extractRawValues(ctx),
206
+ raw_values,
206
207
  messages: [],
207
208
  field_messages: {}
208
209
  },
package/lib/get-fonts.js CHANGED
@@ -80,7 +80,13 @@ async function getFonts(_ = {}) {
80
80
  } catch {
81
81
  console.info("No fonsta config present, using just google fonts");
82
82
  }
83
- await rmdir("public/tmp");
83
+ try {
84
+ await rmdir("public/tmp");
85
+ } catch {
86
+ console.info(
87
+ "Could not remove ./public/tmp. Maybe it wasn't there in the first place"
88
+ );
89
+ }
84
90
  console.info("Downloaded new fonts pack from Font Squirrel");
85
91
  console.info("Downloaded new fonts pack");
86
92
  }
@@ -33,6 +33,10 @@ async function createItemFormTemplate(create_action_name, newfilefullpath, colle
33
33
  onsubmit: `
34
34
  async onSubmit(ctx: Context, formData: FormData) {
35
35
  const fctx = this.makeFormControlContext(ctx, formData, true);
36
+ const data = await this.getParsedValues(ctx);
37
+ if (!data) {
38
+ throw new Error("Error when parsing the form values");
39
+ }
36
40
 
37
41
  const created = await ctx.$app.collections["${toKebabCase(
38
42
  collection_name
@@ -49,6 +49,11 @@ async function editItemFormTemplate(edit_action_name, newfilefullpath, collectio
49
49
  throw new Error("Unknown id: " + id);
50
50
  }
51
51
 
52
+ const data = await this.getParsedValues(ctx);
53
+ if (!data) {
54
+ throw new Error("Error when parsing the form values");
55
+ }
56
+
52
57
 
53
58
  item.setMultipleExtraSafe(
54
59
  {
@@ -7,13 +7,13 @@ function getModifierClasses(modifiers) {
7
7
  return modifiers.map((m) => "form-input__wrapper--" + m).join(" ");
8
8
  }
9
9
  async function inputWrapper(type, modifiers, input) {
10
- return tempstream`<div
10
+ return tempstream`<label
11
11
  class="form-input form-input--type-${type} form-input__wrapper ${getModifierClasses(
12
12
  modifiers
13
13
  )}"
14
14
  >
15
15
  ${input}
16
- </div>`;
16
+ </label>`;
17
17
  }
18
18
  async function autoWrapInput(field, input) {
19
19
  return inputWrapper(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sealcode/sealgen",
3
- "version": "0.19.31",
3
+ "version": "0.19.33",
4
4
  "description": "Module to automate adding routes and collections to a sealious application",
5
5
  "main": "lib/index.js",
6
6
  "type": "module",
@@ -69,6 +69,7 @@
69
69
  "core-js-pure": "^3.49.0",
70
70
  "country-codes-list": "^2.0.0",
71
71
  "deepmerge": "^4.3.1",
72
+ "dot-prop": "^10.2.0",
72
73
  "esbuild": "^0.20.0",
73
74
  "escape-goat": "^4.0.0",
74
75
  "fonsta": "^1.1.1",
@@ -93,7 +94,7 @@
93
94
  "peerDependencies": {
94
95
  "koa": "^2.13.0",
95
96
  "koa-responsive-image-router": "^0.2.24",
96
- "sealious": "^0.21.38",
97
+ "sealious": "^0.21.43",
97
98
  "stimulus": "^3.2.2"
98
99
  }
99
100
  }
@@ -62,8 +62,8 @@ describe("checkboxed-list", () => {
62
62
  const context = await browser.newContext();
63
63
  page = await context.newPage();
64
64
  await page.goto(`http://localhost:${port}`);
65
- await page.getByLabel("CO").check();
66
- await page.getByLabel("DE").check();
65
+ await page.getByLabel("CO", { exact: true }).check();
66
+ await page.getByLabel("DE", { exact: true }).check();
67
67
  await page.getByRole("button", { name: "Wyślij" }).click();
68
68
  assert.deepStrictEqual(received_values, { syllables: { co: "on", de: "on" } });
69
69
  });
@@ -206,7 +206,7 @@ describe("checkboxed-list", () => {
206
206
  const context = await browser.newContext();
207
207
  page = await context.newPage();
208
208
  await page.goto(`http://localhost:${port}`);
209
- await page.getByLabel("DE").check();
209
+ await page.getByLabel("DE", { exact: true }).check();
210
210
  await page.getByRole("button", { name: "Wyślij" }).click();
211
211
  await sleep(100);
212
212
  assert(submit_called);
@@ -17,7 +17,7 @@ export type DropdownOption = { value: string; label: string };
17
17
 
18
18
  export class FreeformDropdown<ParsedValue> extends SimpleInput {
19
19
  constructor(
20
- public field: FormField<boolean, ParsedValue | null>,
20
+ public field: FormField<boolean, ParsedValue>,
21
21
  public _generateOptions: (ctx: Context) => Promise<DropdownOption[]>,
22
22
  public options: DropdownOptions = {
23
23
  label: field.label || field.name,
@@ -43,17 +43,19 @@ export class FieldGroup extends FormFieldControl {
43
43
 
44
44
  return tempstream /* HTML */ `
45
45
  <div
46
- class="field-group ${(classes || []).join(" ")}"
47
- ${this.options.containerID
48
- ? `id="${this.options.containerID}"`
49
- : ""}
46
+ class="field-group form-input__wrapper ${(classes || []).join(
47
+ " "
48
+ )}"
49
+ ${this.options.containerID ?
50
+ `id="${this.options.containerID}"`
51
+ : ""}
50
52
  >
51
53
  ${this.preLabelContainer()}
52
54
  <div class="field-group__label-container">
53
55
  ${this.preLabel()}
54
- ${label
55
- ? tempstream`<label ${this.getGroupLabelProps()}>${label}</label>`
56
- : ""}
56
+ ${label ?
57
+ tempstream`<label ${this.getGroupLabelProps()}>${label}</label>`
58
+ : ""}
57
59
  ${this.postLabel()}
58
60
  </div>
59
61
  ${this.preFields()}
@@ -127,26 +127,30 @@ export class SimpleInput<
127
127
  fctx.data.raw_values,
128
128
  true
129
129
  );
130
+
130
131
  return inputWrapper(
131
132
  "simple-input",
132
133
  this.getWrapperModifiers(),
133
134
  tempstream /* HTML */ `
134
135
  ${label ? `<label for="${id}">${label}</label>` : ""}
135
- ${await this.preInput(fctx, fctx.data.raw_values)}
136
- ${this.renderInput(
137
- fctx.ctx,
138
- renderAttributes(await this.getInputAttributes(fctx)),
139
- fctx.data.raw_values
140
- )}
141
- ${this.postInput(fctx.ctx)}
142
- ${~valid && !this.options.hide_errors && fctx.validate ?
143
- `<div class="input__error">${[
144
- message,
145
- fctx.data.field_messages?.[this.field.name]?.message,
146
- ]
147
- .filter((e) => !!e)
148
- .join(" · ")}</div>`
149
- : ""}
136
+ <div class="simple-input__inner-wrapper">
137
+ ${await this.preInput(fctx, fctx.data.raw_values)}
138
+ ${this.renderInput(
139
+ fctx.ctx,
140
+ renderAttributes(await this.getInputAttributes(fctx)),
141
+ fctx.data.raw_values
142
+ )}
143
+ ${this.postInput(fctx.ctx)}
144
+ ${~valid && !this.options.hide_errors && fctx.validate ?
145
+ `<div class="input__error">${[
146
+ message,
147
+ fctx.data.field_messages?.[this.field.name]
148
+ ?.message,
149
+ ]
150
+ .filter((e) => !!e)
151
+ .join(" · ")}</div>`
152
+ : ""}
153
+ </div>
150
154
  `
151
155
  );
152
156
  }
@@ -49,10 +49,10 @@ export class Textarea extends SimpleInput {
49
49
  attributes: string,
50
50
  data: Record<string, FormDataValue>
51
51
  ) {
52
- // eslint-disable-next-line no-await-in-loop, @typescript-eslint/no-unsafe-assignment
52
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
53
53
  const { parsed: value } = await this.field.getParsedValue(ctx, data);
54
54
  return /* HTML */ `<textarea ${attributes}>
55
- ${String(value) || ""}</textarea
55
+ ${value ? String(value) : ""}</textarea
56
56
  >`;
57
57
  }
58
58
  }
@@ -3,7 +3,6 @@ import { Context } from "koa";
3
3
  import { Checkbox } from "../controls/checkbox.js";
4
4
  import { FormDataValue } from "../form-types.js";
5
5
  import { FieldParseResult, FormField } from "./field.js";
6
- import { FormControlContext } from "../controls/form-control.js";
7
6
 
8
7
  const truthy = ["true", "on", "yes", "1"];
9
8
  const falsy = ["false", "off", "no", "0"];
@@ -71,12 +70,8 @@ export class Boolean<Required extends boolean> extends FormField<
71
70
  return new Checkbox(this, { label: this.label || this.name });
72
71
  }
73
72
 
74
- async getSealiousCreateValue(fctx: FormControlContext): Promise<boolean> {
75
- const { parsed } = await this.getParsedValue(
76
- fctx.ctx,
77
- fctx.data.raw_values
78
- );
79
- return !!parsed;
73
+ async parsedToSealious(value: boolean): Promise<boolean> {
74
+ return !!value;
80
75
  }
81
76
 
82
77
  async sealiousValueToForm(