@sealcode/sealgen 0.8.31 → 0.8.32

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 (109) hide show
  1. package/@types/forms/controls/autocomplete.d.ts +2 -2
  2. package/@types/forms/controls/big-radio-group.d.ts +4 -5
  3. package/@types/forms/controls/checkbox-group.d.ts +3 -4
  4. package/@types/forms/controls/checkboxed-list-input.d.ts +2 -3
  5. package/@types/forms/controls/collapsible-checkbox-group.d.ts +2 -3
  6. package/@types/forms/controls/controls.d.ts +2 -1
  7. package/@types/forms/controls/derived-frame.d.ts +21 -0
  8. package/@types/forms/controls/derived.d.ts +6 -6
  9. package/@types/forms/controls/dropdown.d.ts +23 -14
  10. package/@types/forms/controls/editable-collection-subset.d.ts +2 -3
  11. package/@types/forms/controls/field-group.d.ts +2 -4
  12. package/@types/forms/controls/file.d.ts +3 -2
  13. package/@types/forms/controls/form-control.d.ts +10 -1
  14. package/@types/forms/controls/form-field-control.d.ts +3 -4
  15. package/@types/forms/controls/form-header.d.ts +4 -4
  16. package/@types/forms/controls/hidden-input.d.ts +2 -3
  17. package/@types/forms/controls/html.d.ts +3 -4
  18. package/@types/forms/controls/multiple-files.d.ts +3 -3
  19. package/@types/forms/controls/number.d.ts +2 -3
  20. package/@types/forms/controls/photo.d.ts +2 -2
  21. package/@types/forms/controls/simple-input.d.ts +5 -4
  22. package/@types/forms/controls/textarea.d.ts +2 -1
  23. package/@types/forms/controls/tickable.d.ts +2 -1
  24. package/@types/forms/fields/pick-from-list.d.ts +3 -6
  25. package/@types/page/mountable-with-fields.d.ts +3 -2
  26. package/lib/forms/controls/autocomplete.js +2 -2
  27. package/lib/forms/controls/autocomplete.js.map +1 -1
  28. package/lib/forms/controls/big-radio-group.js +4 -4
  29. package/lib/forms/controls/big-radio-group.js.map +1 -1
  30. package/lib/forms/controls/checkbox-group.js +5 -5
  31. package/lib/forms/controls/checkbox-group.js.map +1 -1
  32. package/lib/forms/controls/checkboxed-list-input.js +4 -4
  33. package/lib/forms/controls/checkboxed-list-input.js.map +1 -1
  34. package/lib/forms/controls/collapsible-checkbox-group.js +2 -2
  35. package/lib/forms/controls/collapsible-checkbox-group.js.map +1 -1
  36. package/lib/forms/controls/controls.js +3 -3
  37. package/lib/forms/controls/controls.js.map +1 -1
  38. package/lib/forms/controls/derived-frame.js +57 -0
  39. package/lib/forms/controls/derived-frame.js.map +1 -0
  40. package/lib/forms/controls/derived.js +15 -16
  41. package/lib/forms/controls/derived.js.map +1 -1
  42. package/lib/forms/controls/dropdown.js +23 -9
  43. package/lib/forms/controls/dropdown.js.map +1 -1
  44. package/lib/forms/controls/editable-collection-subset.js +6 -6
  45. package/lib/forms/controls/editable-collection-subset.js.map +1 -1
  46. package/lib/forms/controls/field-group.js +2 -2
  47. package/lib/forms/controls/field-group.js.map +1 -1
  48. package/lib/forms/controls/file.js +4 -4
  49. package/lib/forms/controls/file.js.map +1 -1
  50. package/lib/forms/controls/form-control.js +12 -1
  51. package/lib/forms/controls/form-control.js.map +1 -1
  52. package/lib/forms/controls/form-field-control.js.map +1 -1
  53. package/lib/forms/controls/form-header.js +2 -2
  54. package/lib/forms/controls/form-header.js.map +1 -1
  55. package/lib/forms/controls/hidden-input.js +3 -3
  56. package/lib/forms/controls/hidden-input.js.map +1 -1
  57. package/lib/forms/controls/html.js +2 -2
  58. package/lib/forms/controls/html.js.map +1 -1
  59. package/lib/forms/controls/multiple-files.js +4 -4
  60. package/lib/forms/controls/multiple-files.js.map +1 -1
  61. package/lib/forms/controls/number.js +2 -2
  62. package/lib/forms/controls/number.js.map +1 -1
  63. package/lib/forms/controls/photo.js +3 -3
  64. package/lib/forms/controls/photo.js.map +1 -1
  65. package/lib/forms/controls/simple-input.js +11 -12
  66. package/lib/forms/controls/simple-input.js.map +1 -1
  67. package/lib/forms/controls/textarea.js +2 -2
  68. package/lib/forms/controls/textarea.js.map +1 -1
  69. package/lib/forms/controls/tickable.js +11 -9
  70. package/lib/forms/controls/tickable.js.map +1 -1
  71. package/lib/forms/fields/field.js +1 -1
  72. package/lib/forms/fields/field.js.map +1 -1
  73. package/lib/forms/fields/pick-from-list.js +1 -1
  74. package/lib/forms/fields/pick-from-list.js.map +1 -1
  75. package/lib/forms/form.js +1 -1
  76. package/lib/forms/form.js.map +1 -1
  77. package/lib/page/list.js +1 -1
  78. package/lib/page/list.js.map +1 -1
  79. package/lib/page/mountable-with-fields.js +6 -2
  80. package/lib/page/mountable-with-fields.js.map +1 -1
  81. package/package.json +1 -1
  82. package/src/forms/controls/autocomplete.ts +3 -12
  83. package/src/forms/controls/big-radio-group.ts +9 -28
  84. package/src/forms/controls/checkbox-group.ts +10 -31
  85. package/src/forms/controls/checkboxed-list-input.ts +8 -4
  86. package/src/forms/controls/collapsible-checkbox-group.ts +4 -15
  87. package/src/forms/controls/controls.ts +2 -1
  88. package/src/forms/controls/derived-frame.ts +92 -0
  89. package/src/forms/controls/derived.ts +19 -18
  90. package/src/forms/controls/dropdown.ts +41 -29
  91. package/src/forms/controls/editable-collection-subset.ts +25 -25
  92. package/src/forms/controls/field-group.ts +3 -19
  93. package/src/forms/controls/file.ts +5 -12
  94. package/src/forms/controls/form-control.ts +12 -6
  95. package/src/forms/controls/form-field-control.ts +2 -7
  96. package/src/forms/controls/form-header.ts +6 -3
  97. package/src/forms/controls/hidden-input.ts +6 -6
  98. package/src/forms/controls/html.ts +4 -9
  99. package/src/forms/controls/multiple-files.ts +5 -10
  100. package/src/forms/controls/number.ts +3 -10
  101. package/src/forms/controls/photo.ts +7 -14
  102. package/src/forms/controls/simple-input.ts +21 -34
  103. package/src/forms/controls/textarea.ts +6 -14
  104. package/src/forms/controls/tickable.ts +15 -14
  105. package/src/forms/fields/field.ts +1 -1
  106. package/src/forms/fields/pick-from-list.ts +3 -4
  107. package/src/forms/form.ts +3 -1
  108. package/src/page/list.ts +7 -1
  109. package/src/page/mountable-with-fields.ts +23 -14
@@ -3,8 +3,9 @@ import { FlatTemplatable, tempstream } from "tempstream";
3
3
  import { getRequiredClass, inputWrapper } from "../../utils/input-wrapper";
4
4
  import { renderAttributes } from "../../utils/render-attributes";
5
5
  import { FormField } from "../fields/field";
6
- import { FormDataValue, FormMessage } from "../form";
6
+ import { FormDataValue } from "../form";
7
7
  import { FormFieldControl } from "./controls";
8
+ import { FormControlContext } from "./form-control";
8
9
 
9
10
  export type SimpleInputOptions = {
10
11
  id?: string;
@@ -73,18 +74,18 @@ export class SimpleInput<
73
74
  }
74
75
 
75
76
  async getInputAttributes(
76
- ctx: Context,
77
- data: Record<string, FormDataValue>,
78
- field_prefix: string,
79
- form_id: string
77
+ fctx: FormControlContext
80
78
  ): Promise<Record<string, string | boolean>> {
81
79
  const readonly = this.options.readonly || false;
82
80
  const required = this.field.required;
83
- const { parsed, raw, valid } = await this.field.getValue(ctx, data);
81
+ const { parsed, raw, valid } = await this.field.getValue(
82
+ fctx.ctx,
83
+ fctx.data
84
+ );
84
85
  return Object.fromEntries([
85
86
  <const>["id", this.getID()],
86
87
  <const>["type", this.getType()],
87
- <const>["name", `${field_prefix}${this.field.name}`],
88
+ <const>["name", `${fctx.field_name_prefix}${this.field.name}`],
88
89
  <const>[
89
90
  "value",
90
91
  !valid && raw
@@ -93,7 +94,7 @@ export class SimpleInput<
93
94
  ? ((parsed as any)?.toString() as string) || ""
94
95
  : "",
95
96
  ],
96
- ...(form_id ? [["form", form_id]] : []),
97
+ ...(fctx.form_id ? [["form", fctx.form_id]] : []),
97
98
  <const>["placeholder", this.getPlaceholder()],
98
99
  ...(readonly ? [["readonly", true]] : []),
99
100
  ...(required ? [["required", true]] : []),
@@ -109,50 +110,36 @@ export class SimpleInput<
109
110
  }
110
111
 
111
112
  async renderInput(
112
- ctx: Context,
113
+ _ctx: Context,
113
114
  attributes_str: string,
114
- data: Record<string, FormDataValue>
115
+ _data: Record<string, FormDataValue>
115
116
  ): Promise<FlatTemplatable> {
116
117
  return `<input ${attributes_str} />`;
117
118
  }
118
119
 
119
120
  async render<Fields extends Record<string, FormField>>(
120
- ctx: Context,
121
- data: Record<string, FormDataValue>,
122
- _messages: FormMessage[],
123
- field_prefix: string,
124
- form_id: string,
125
- show_errors: boolean
121
+ fctx: FormControlContext
126
122
  ): Promise<FlatTemplatable> {
127
123
  const id = this.getID();
128
124
  const label = this.getLabel();
129
125
  const type = this.getType();
130
126
 
131
- const { parsed, raw, valid, message } = await this.field.getValue(
132
- ctx,
133
- data
127
+ const { valid, message } = await this.field.getValue(
128
+ fctx.ctx,
129
+ fctx.data
134
130
  );
135
- const placeholder = this.getPlaceholder();
136
-
137
131
  return inputWrapper(
138
132
  [id, type, getRequiredClass(this.field.required)],
139
133
  tempstream/* HTML */ `
140
134
  ${label ? `<label for="${id}">${label}</label>` : ""}
141
- ${await this.preInput(ctx, data)}
135
+ ${await this.preInput(fctx.ctx, fctx.data)}
142
136
  ${this.renderInput(
143
- ctx,
144
- renderAttributes(
145
- await this.getInputAttributes(
146
- ctx,
147
- data,
148
- field_prefix,
149
- form_id
150
- )
151
- ),
152
- data
137
+ fctx.ctx,
138
+ renderAttributes(await this.getInputAttributes(fctx)),
139
+ fctx.data
153
140
  )}
154
- ${this.postInput(ctx)}
155
- ${~valid && !this.options.hide_errors && show_errors
141
+ ${this.postInput(fctx.ctx)}
142
+ ${~valid && !this.options.hide_errors && fctx.validate
156
143
  ? `<div class="input__error">${message}</div>`
157
144
  : ""}
158
145
  `
@@ -1,10 +1,7 @@
1
1
  import { Context } from "koa";
2
- import { FlatTemplatable, tempstream } from "tempstream";
3
- import { attribute } from "../../sanitize";
4
- import { getRequiredClass, inputWrapper } from "../../utils/input-wrapper";
5
2
  import { FormField } from "../fields/field";
6
3
  import { FormDataValue } from "../form";
7
- import { FormFieldControl } from "./form-field-control";
4
+ import { FormControlContext } from "./form-control";
8
5
  import { SimpleInput, SimpleInputOptions } from "./simple-input";
9
6
 
10
7
  export class Textarea<Required extends boolean> extends SimpleInput<
@@ -32,17 +29,12 @@ export class Textarea<Required extends boolean> extends SimpleInput<
32
29
  }
33
30
 
34
31
  async getInputAttributes(
35
- ctx: Context,
36
- data: Record<string, FormDataValue>,
37
- field_prefix: string,
38
- form_id: string
32
+ fctx: FormControlContext
39
33
  ): Promise<Record<string, string | boolean>> {
40
- const original = (await super.getInputAttributes(
41
- ctx,
42
- data,
43
- field_prefix,
44
- form_id
45
- )) as Record<string, string | boolean>;
34
+ const original = (await super.getInputAttributes(fctx)) as Record<
35
+ string,
36
+ string | boolean
37
+ >;
46
38
  let onkeydown = original.onkeydown || "";
47
39
  if (this.options.autogrow) {
48
40
  onkeydown += `;this.style.height = '5px';this.style.height = Math.max((this.scrollHeight)+32, ${
@@ -5,6 +5,7 @@ import { getRequiredClass, inputWrapper } from "../../utils/input-wrapper";
5
5
  import { FormField } from "../fields/field";
6
6
  import { FormDataValue } from "../form";
7
7
  import { FormFieldControl } from "./controls";
8
+ import { FormControlContext } from "./form-control";
8
9
 
9
10
  export type TickableOptions = {
10
11
  id?: string;
@@ -63,17 +64,15 @@ export abstract class Tickable<T extends unknown> extends FormFieldControl {
63
64
  }
64
65
 
65
66
  async render<Fields extends Record<string, FormField>>(
66
- ctx: Context,
67
- data: Record<string, FormDataValue>,
68
- _: unknown[],
69
- field_prefix: string,
70
- form_id: string,
71
- show_field_errors: boolean
67
+ fctx: FormControlContext
72
68
  ): Promise<FlatTemplatable> {
73
69
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
74
- const { parsed, valid, message } = await this.field.getValue(ctx, data);
75
- const value = this.getValueAttribute(ctx, data, parsed);
76
- const id = this.makeInputID(ctx, data, parsed);
70
+ const { parsed, valid, message } = await this.field.getValue(
71
+ fctx.ctx,
72
+ fctx.data
73
+ );
74
+ const value = this.getValueAttribute(fctx.ctx, fctx.data, parsed);
75
+ const id = this.makeInputID(fctx.ctx, fctx.data, parsed);
77
76
  const label =
78
77
  this.options.label != undefined
79
78
  ? this.options.label
@@ -84,17 +83,19 @@ export abstract class Tickable<T extends unknown> extends FormFieldControl {
84
83
  const required = this.field.required;
85
84
 
86
85
  return inputWrapper(
87
- this.getWrapperClasses(ctx, data, parsed),
86
+ this.getWrapperClasses(fctx.ctx, fctx.data, parsed),
88
87
 
89
88
  /* HTML */ `
90
89
  <input
91
90
  id="${id}"
92
91
  type="${this.type}"
93
- name="${field_prefix}${this.options.name ||
92
+ name="${fctx.field_name_prefix}${this.options.name ||
94
93
  this.field.name}"
95
94
  ${value ? `value="${attribute(value)}"` : ""}
96
- ${form_id ? `form="${form_id}"` : ""}
97
- ${this.isChecked(ctx, data, parsed) ? "checked" : ""}
95
+ ${fctx.form_id ? `form="${fctx.form_id}"` : ""}
96
+ ${this.isChecked(fctx.ctx, fctx.data, parsed)
97
+ ? "checked"
98
+ : ""}
98
99
  ${readonly ? "readonly" : ""}
99
100
  ${required ? "required" : ""}
100
101
  autocomplete="off"
@@ -117,7 +118,7 @@ export abstract class Tickable<T extends unknown> extends FormFieldControl {
117
118
  })();
118
119
  </script>
119
120
 
120
- ${~valid && !this.options.hide_errors && show_field_errors
121
+ ${~valid && !this.options.hide_errors && fctx.validate
121
122
  ? `<div class="input__error">${message}</div>`
122
123
  : ""}
123
124
  `
@@ -105,7 +105,7 @@ export abstract class FormField<
105
105
  parsed: ParsedValue;
106
106
  raw: FormDataValue;
107
107
  }> {
108
- if (Object.keys(all_form_values).length === 0) {
108
+ if (Object.keys(all_form_values || {}).length === 0) {
109
109
  // don't validate on virgin form
110
110
  return {
111
111
  parsed: this.getEmptyValue(),
@@ -1,5 +1,6 @@
1
1
  import { is, predicates } from "@sealcode/ts-predicates";
2
2
  import { Context } from "koa";
3
+ import { DropdownOption } from "../controls/dropdown";
3
4
  import { FormFieldValidationResponse } from "./field";
4
5
  import { SimpleFormField } from "./simple-form-field";
5
6
 
@@ -8,9 +9,7 @@ export class PickFromListField<
8
9
  > extends SimpleFormField<Required> {
9
10
  constructor(
10
11
  public required: Required,
11
- public generateOptions: (
12
- ctx: Context
13
- ) => Promise<Record<string, string> | { [i: string]: string }>,
12
+ public generateOptions: (ctx: Context) => Promise<DropdownOption[]>,
14
13
  public customValidation: (
15
14
  ctx: Context,
16
15
  value: unknown,
@@ -38,7 +37,7 @@ export class PickFromListField<
38
37
  if (!is(value, predicates.string)) {
39
38
  return { valid: false, message: "not a string" };
40
39
  }
41
- if (this.required && !Object.keys(options).includes(value)) {
40
+ if (this.required && !options.map((o) => o.value).includes(value)) {
42
41
  return {
43
42
  valid: false,
44
43
  message: `"${value}" is not one of the options`,
package/src/forms/form.ts CHANGED
@@ -86,7 +86,9 @@ export abstract class Form<
86
86
  ${!this.controls.some((control) => control.role == "messages")
87
87
  ? this.renderMessages(ctx, data)
88
88
  : ""}
89
- ${this.renderControls(ctx, data, show_field_errors)}
89
+ ${this.renderControls(
90
+ this.makeFormControlContext(ctx, data, show_field_errors)
91
+ )}
90
92
  ${this.controls.some((control) => control.role == "submit")
91
93
  ? ""
92
94
  : this.makeSubmitButton()}
package/src/page/list.ts CHANGED
@@ -155,7 +155,13 @@ ${this.renderListContainer(ctx, this.renderItems(ctx, values))}`;
155
155
  ])}
156
156
  ${this.filterControls.map((control) => {
157
157
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
158
- return control.render(ctx, values, [], "", "", false);
158
+ return control.render(
159
+ this.makeFormControlContext(
160
+ ctx,
161
+ { raw_values: values, messages: [] },
162
+ false
163
+ )
164
+ );
159
165
  })}
160
166
  </form>`;
161
167
  }
@@ -1,7 +1,10 @@
1
1
  import { ShapeToType } from "@sealcode/ts-predicates";
2
2
  import { Context } from "koa";
3
3
  import { FlatTemplatable, tempstream } from "tempstream";
4
- import { FormControl } from "../forms/controls/form-control";
4
+ import {
5
+ FormControl,
6
+ FormControlContext,
7
+ } from "../forms/controls/form-control";
5
8
  import { FieldsToShape, FormField } from "../forms/fields/field";
6
9
  import { FormData, FormDataValue, FormMessage } from "../forms/form";
7
10
  import { Mountable } from "./mountable";
@@ -29,6 +32,23 @@ export abstract class MountableWithFields<
29
32
  }
30
33
  }
31
34
 
35
+ makeFormControlContext(
36
+ ctx: Context,
37
+ data: FormData,
38
+ validate: boolean,
39
+ field_name_prefix = this.field_names_prefix,
40
+ form_id = this.form_id
41
+ ) {
42
+ return new FormControlContext(
43
+ ctx,
44
+ data.raw_values,
45
+ data.messages,
46
+ field_name_prefix,
47
+ form_id,
48
+ validate
49
+ );
50
+ }
51
+
32
52
  // this one is meant to be overwritten
33
53
  async validateValues(
34
54
  ctx: Context,
@@ -75,20 +95,9 @@ export abstract class MountableWithFields<
75
95
  return { valid, field_errors, form_messages };
76
96
  }
77
97
 
78
- public renderControls(
79
- ctx: Context,
80
- data: FormData<keyof Fields>,
81
- validate: boolean
82
- ): FlatTemplatable {
98
+ public renderControls(fctx: FormControlContext): FlatTemplatable {
83
99
  return tempstream/* HTML */ `${this.controls.map((control) =>
84
- control.render(
85
- ctx,
86
- data.raw_values,
87
- data.messages,
88
- this.field_names_prefix,
89
- this.form_id,
90
- validate
91
- )
100
+ control.render(fctx)
92
101
  )}`;
93
102
  }
94
103