@sealcode/sealgen 0.8.47 → 0.8.48

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 (243) hide show
  1. package/@types/index.d.ts +1 -0
  2. package/@types/page/stateful-page.d.ts +34 -0
  3. package/@types/templates/stateful-page.d.ts +1 -0
  4. package/@types/utils/base64.d.ts +2 -0
  5. package/@types/utils/utils.d.ts +3 -0
  6. package/lib/add-route.js +3 -0
  7. package/lib/cli.js +0 -0
  8. package/lib/generate-routes.js +2 -1
  9. package/lib/index.js +1 -0
  10. package/lib/page/stateful-page.js +117 -0
  11. package/lib/templates/stateful-page.js +66 -0
  12. package/lib/utils/base64.js +12 -0
  13. package/lib/utils/utils.js +6 -1
  14. package/package.json +2 -1
  15. package/.arcconfig +0 -12
  16. package/.arclint +0 -18
  17. package/.eslintrc.js +0 -38
  18. package/.mocharc.js +0 -10
  19. package/.nycrc +0 -6
  20. package/.prettierrc +0 -21
  21. package/jenkins.sanity.sh +0 -3
  22. package/lib/add-collection.js.map +0 -1
  23. package/lib/add-route.js.map +0 -1
  24. package/lib/add-route.test.js.map +0 -1
  25. package/lib/build.js.map +0 -1
  26. package/lib/cli.js.map +0 -1
  27. package/lib/components/components.js.map +0 -1
  28. package/lib/components/tabs.js.map +0 -1
  29. package/lib/components/toggle-modal.js.map +0 -1
  30. package/lib/example.test.js.map +0 -1
  31. package/lib/find-scss-includes.js.map +0 -1
  32. package/lib/forms/controls/array.js.map +0 -1
  33. package/lib/forms/controls/autocomplete.js.map +0 -1
  34. package/lib/forms/controls/big-radio-group.js.map +0 -1
  35. package/lib/forms/controls/checkbox-group.js.map +0 -1
  36. package/lib/forms/controls/checkbox.js.map +0 -1
  37. package/lib/forms/controls/checkboxed-list-input.js.map +0 -1
  38. package/lib/forms/controls/collapsible-checkbox-group.js.map +0 -1
  39. package/lib/forms/controls/collapsible-field-group.js.map +0 -1
  40. package/lib/forms/controls/controls.js.map +0 -1
  41. package/lib/forms/controls/derived-frame.js.map +0 -1
  42. package/lib/forms/controls/derived.js.map +0 -1
  43. package/lib/forms/controls/dropdown.js.map +0 -1
  44. package/lib/forms/controls/editable-collection-subset.js.map +0 -1
  45. package/lib/forms/controls/field-group.js.map +0 -1
  46. package/lib/forms/controls/file.js.map +0 -1
  47. package/lib/forms/controls/form-control.js.map +0 -1
  48. package/lib/forms/controls/form-field-control.js.map +0 -1
  49. package/lib/forms/controls/form-header.js.map +0 -1
  50. package/lib/forms/controls/form-paragraph.js.map +0 -1
  51. package/lib/forms/controls/frame.js.map +0 -1
  52. package/lib/forms/controls/hidden-input.js.map +0 -1
  53. package/lib/forms/controls/html.js.map +0 -1
  54. package/lib/forms/controls/multiple-files.js.map +0 -1
  55. package/lib/forms/controls/multiple-photos.js.map +0 -1
  56. package/lib/forms/controls/number.js.map +0 -1
  57. package/lib/forms/controls/photo.js.map +0 -1
  58. package/lib/forms/controls/radio.js.map +0 -1
  59. package/lib/forms/controls/reverse-single-reference.js.map +0 -1
  60. package/lib/forms/controls/simple-input.js.map +0 -1
  61. package/lib/forms/controls/textarea.js.map +0 -1
  62. package/lib/forms/controls/tickable.js.map +0 -1
  63. package/lib/forms/fields/boolean.js.map +0 -1
  64. package/lib/forms/fields/boolean.test.js.map +0 -1
  65. package/lib/forms/fields/checkboxed-list.js.map +0 -1
  66. package/lib/forms/fields/collection-field.js.map +0 -1
  67. package/lib/forms/fields/email.js.map +0 -1
  68. package/lib/forms/fields/email.test.js.map +0 -1
  69. package/lib/forms/fields/enum-multiple.js.map +0 -1
  70. package/lib/forms/fields/enum-multiple.test.js.map +0 -1
  71. package/lib/forms/fields/enum.js.map +0 -1
  72. package/lib/forms/fields/enum.test.js.map +0 -1
  73. package/lib/forms/fields/existing-sealious-value.js.map +0 -1
  74. package/lib/forms/fields/field.js.map +0 -1
  75. package/lib/forms/fields/file.js.map +0 -1
  76. package/lib/forms/fields/multiple-files.js.map +0 -1
  77. package/lib/forms/fields/number.js.map +0 -1
  78. package/lib/forms/fields/number.test.js.map +0 -1
  79. package/lib/forms/fields/pick-from-list.js.map +0 -1
  80. package/lib/forms/fields/pick-from-list.test.js.map +0 -1
  81. package/lib/forms/fields/proxy-field.js.map +0 -1
  82. package/lib/forms/fields/regexp.js.map +0 -1
  83. package/lib/forms/fields/regexp.test.js.map +0 -1
  84. package/lib/forms/fields/reverse-single-reference.js.map +0 -1
  85. package/lib/forms/fields/simple-form-field.js.map +0 -1
  86. package/lib/forms/fields/structured-array.js.map +0 -1
  87. package/lib/forms/form.js.map +0 -1
  88. package/lib/forms/form.test.js.map +0 -1
  89. package/lib/forms/multiform.js.map +0 -1
  90. package/lib/forms/multiform.test.js.map +0 -1
  91. package/lib/generate-collections.js.map +0 -1
  92. package/lib/generate-routes.js.map +0 -1
  93. package/lib/index.js.map +0 -1
  94. package/lib/make-env.js.map +0 -1
  95. package/lib/make-hidden-inputs.js.map +0 -1
  96. package/lib/mount.js.map +0 -1
  97. package/lib/page/access-control.js.map +0 -1
  98. package/lib/page/list.js.map +0 -1
  99. package/lib/page/mountable-with-fields.js.map +0 -1
  100. package/lib/page/mountable.js.map +0 -1
  101. package/lib/page/page.js.map +0 -1
  102. package/lib/page/props-parser.js.map +0 -1
  103. package/lib/run.js.map +0 -1
  104. package/lib/sanitize.js.map +0 -1
  105. package/lib/templates/collection.js.map +0 -1
  106. package/lib/templates/form.js.map +0 -1
  107. package/lib/templates/list.js.map +0 -1
  108. package/lib/templates/multiform.js.map +0 -1
  109. package/lib/templates/page.js.map +0 -1
  110. package/lib/templates/post.js.map +0 -1
  111. package/lib/templates/redirect.js.map +0 -1
  112. package/lib/templates/route-test.js.map +0 -1
  113. package/lib/test_utils/locator_is_visible.js.map +0 -1
  114. package/lib/utils/assert-throws.js.map +0 -1
  115. package/lib/utils/browser-creator.js.map +0 -1
  116. package/lib/utils/escape-url-params.js.map +0 -1
  117. package/lib/utils/exec.js.map +0 -1
  118. package/lib/utils/format-external-url.js.map +0 -1
  119. package/lib/utils/import-path.js.map +0 -1
  120. package/lib/utils/input-wrapper.js.map +0 -1
  121. package/lib/utils/list-collections.js.map +0 -1
  122. package/lib/utils/make-slug.js.map +0 -1
  123. package/lib/utils/natural-numbers.js.map +0 -1
  124. package/lib/utils/prettier.js.map +0 -1
  125. package/lib/utils/question.js.map +0 -1
  126. package/lib/utils/render-attributes.js.map +0 -1
  127. package/lib/utils/sleep.js.map +0 -1
  128. package/lib/utils/translate.js.map +0 -1
  129. package/lib/utils/url-with-new-params.js.map +0 -1
  130. package/lib/utils/utils.js.map +0 -1
  131. package/lib/utils/walk.js.map +0 -1
  132. package/mocha_root_hooks.js +0 -6
  133. package/src/add-collection.ts +0 -31
  134. package/src/add-route.test.ts +0 -58
  135. package/src/add-route.ts +0 -86
  136. package/src/build.ts +0 -94
  137. package/src/cli.ts +0 -36
  138. package/src/components/components.ts +0 -2
  139. package/src/components/tabs.ts +0 -95
  140. package/src/components/toggle-modal.ts +0 -52
  141. package/src/example.test.ts +0 -3
  142. package/src/find-scss-includes.ts +0 -32
  143. package/src/forms/controls/array.ts +0 -226
  144. package/src/forms/controls/autocomplete.ts +0 -33
  145. package/src/forms/controls/big-radio-group.ts +0 -48
  146. package/src/forms/controls/checkbox-group.ts +0 -71
  147. package/src/forms/controls/checkbox.ts +0 -34
  148. package/src/forms/controls/checkboxed-list-input.ts +0 -50
  149. package/src/forms/controls/collapsible-checkbox-group.ts +0 -28
  150. package/src/forms/controls/collapsible-field-group.ts +0 -94
  151. package/src/forms/controls/controls.ts +0 -30
  152. package/src/forms/controls/derived-frame.ts +0 -91
  153. package/src/forms/controls/derived.ts +0 -108
  154. package/src/forms/controls/dropdown.ts +0 -87
  155. package/src/forms/controls/editable-collection-subset.ts +0 -97
  156. package/src/forms/controls/field-group.ts +0 -69
  157. package/src/forms/controls/file.ts +0 -47
  158. package/src/forms/controls/form-control.ts +0 -24
  159. package/src/forms/controls/form-field-control.ts +0 -22
  160. package/src/forms/controls/form-header.ts +0 -19
  161. package/src/forms/controls/form-paragraph.ts +0 -11
  162. package/src/forms/controls/frame.ts +0 -26
  163. package/src/forms/controls/hidden-input.ts +0 -22
  164. package/src/forms/controls/html.ts +0 -38
  165. package/src/forms/controls/multiple-files.ts +0 -256
  166. package/src/forms/controls/multiple-photos.ts +0 -44
  167. package/src/forms/controls/number.ts +0 -38
  168. package/src/forms/controls/photo.ts +0 -74
  169. package/src/forms/controls/radio.ts +0 -43
  170. package/src/forms/controls/reverse-single-reference.ts +0 -50
  171. package/src/forms/controls/simple-input.ts +0 -148
  172. package/src/forms/controls/textarea.ts +0 -60
  173. package/src/forms/controls/tickable.ts +0 -127
  174. package/src/forms/fields/boolean.test.ts +0 -36
  175. package/src/forms/fields/boolean.ts +0 -63
  176. package/src/forms/fields/checkboxed-list.ts +0 -66
  177. package/src/forms/fields/collection-field.ts +0 -62
  178. package/src/forms/fields/email.test.ts +0 -24
  179. package/src/forms/fields/email.ts +0 -20
  180. package/src/forms/fields/enum-multiple.test.ts +0 -31
  181. package/src/forms/fields/enum-multiple.ts +0 -62
  182. package/src/forms/fields/enum.test.ts +0 -25
  183. package/src/forms/fields/enum.ts +0 -56
  184. package/src/forms/fields/existing-sealious-value.ts +0 -22
  185. package/src/forms/fields/field.ts +0 -172
  186. package/src/forms/fields/file.ts +0 -89
  187. package/src/forms/fields/multiple-files.ts +0 -20
  188. package/src/forms/fields/number.test.ts +0 -34
  189. package/src/forms/fields/number.ts +0 -70
  190. package/src/forms/fields/pick-from-list.test.ts +0 -19
  191. package/src/forms/fields/pick-from-list.ts +0 -52
  192. package/src/forms/fields/proxy-field.ts +0 -24
  193. package/src/forms/fields/regexp.test.ts +0 -25
  194. package/src/forms/fields/regexp.ts +0 -53
  195. package/src/forms/fields/reverse-single-reference.ts +0 -20
  196. package/src/forms/fields/simple-form-field.ts +0 -30
  197. package/src/forms/fields/structured-array.ts +0 -27
  198. package/src/forms/form.test.ts +0 -351
  199. package/src/forms/form.ts +0 -294
  200. package/src/forms/forms.scss +0 -85
  201. package/src/forms/multiform.test.ts +0 -540
  202. package/src/forms/multiform.ts +0 -236
  203. package/src/generate-collections.ts +0 -77
  204. package/src/generate-routes.ts +0 -120
  205. package/src/index.ts +0 -24
  206. package/src/make-env.ts +0 -15
  207. package/src/make-hidden-inputs.ts +0 -24
  208. package/src/mount.ts +0 -85
  209. package/src/page/access-control.ts +0 -18
  210. package/src/page/list.ts +0 -240
  211. package/src/page/mountable-with-fields.ts +0 -158
  212. package/src/page/mountable.ts +0 -13
  213. package/src/page/page.ts +0 -46
  214. package/src/page/props-parser.ts +0 -38
  215. package/src/run.ts +0 -0
  216. package/src/sanitize.ts +0 -9
  217. package/src/templates/collection.ts +0 -11
  218. package/src/templates/form.ts +0 -60
  219. package/src/templates/list.ts +0 -75
  220. package/src/templates/multiform.ts +0 -58
  221. package/src/templates/page.ts +0 -25
  222. package/src/templates/post.ts +0 -21
  223. package/src/templates/redirect.ts +0 -22
  224. package/src/templates/route-test.ts +0 -27
  225. package/src/test_utils/locator_is_visible.ts +0 -17
  226. package/src/utils/assert-throws.ts +0 -18
  227. package/src/utils/browser-creator.js +0 -10
  228. package/src/utils/escape-url-params.ts +0 -14
  229. package/src/utils/exec.ts +0 -30
  230. package/src/utils/format-external-url.ts +0 -13
  231. package/src/utils/import-path.ts +0 -25
  232. package/src/utils/input-wrapper.ts +0 -21
  233. package/src/utils/list-collections.ts +0 -16
  234. package/src/utils/make-slug.ts +0 -5
  235. package/src/utils/natural-numbers.ts +0 -5
  236. package/src/utils/prettier.ts +0 -13
  237. package/src/utils/question.ts +0 -23
  238. package/src/utils/render-attributes.ts +0 -17
  239. package/src/utils/sleep.ts +0 -3
  240. package/src/utils/translate.ts +0 -13
  241. package/src/utils/url-with-new-params.ts +0 -9
  242. package/src/utils/utils.ts +0 -14
  243. package/src/utils/walk.ts +0 -20
@@ -1,91 +0,0 @@
1
- import Router from "@koa/router";
2
- import { hasShape, predicates } from "@sealcode/ts-predicates";
3
- import { Context } from "koa";
4
- import { ParsedUrlQuery } from "querystring";
5
- import { FlatTemplatable, tempstream } from "tempstream";
6
- import { makeSlug } from "../../utils/make-slug";
7
- import { FormField } from "../fields/field";
8
- import { Derived } from "./derived";
9
- import { FormControlContext } from "./form-control";
10
-
11
- export class DerivedFrame extends Derived<{
12
- frame_id: string;
13
- form_id: string;
14
- field_name_prefix: string;
15
- }> {
16
- constructor(
17
- public frame_name: string,
18
- fields: FormField[],
19
- public generateFrameContent: (
20
- ctx: FormControlContext,
21
- args: ParsedUrlQuery
22
- ) => Promise<FlatTemplatable>,
23
- // "a" is to make it a valid DOM id
24
- public frame_id = "a" + makeSlug(frame_name)
25
- ) {
26
- super(
27
- fields,
28
- async (values, consts) => /* HTML */ `<turbo-frame
29
- id="${consts.frame_id}"
30
- src="./${consts.frame_id}?${Object.entries({
31
- ...consts,
32
- ...(values || {}),
33
- })
34
- .map(([key, value]) => `${key}=${value}`)
35
- .join("&")}"
36
- ></turbo-frame>`,
37
- async (fctx) => ({
38
- form_id: fctx.form_id,
39
- field_name_prefix: fctx.field_name_prefix,
40
- frame_id,
41
- validate: fctx.validate,
42
- })
43
- );
44
- }
45
-
46
- renderBackendResponseFrame(_ctx: Context, content: FlatTemplatable) {
47
- return tempstream/* HTML */ `<turbo-frame
48
- id="${this.frame_id}"
49
- target="_top"
50
- >
51
- ${content || ""}
52
- </turbo-frame>`;
53
- }
54
-
55
- mount(router: Router) {
56
- router.get(this.frame_id, async (ctx) => {
57
- const query = ctx.query;
58
- if (
59
- !hasShape(
60
- {
61
- field_name_prefix: predicates.string,
62
- form_id: predicates.string,
63
- validate: predicates.string,
64
- },
65
- query
66
- )
67
- ) {
68
- ctx.body = this.renderBackendResponseFrame(
69
- ctx,
70
- "Missing query params"
71
- );
72
- return;
73
- }
74
- ctx.body = this.renderBackendResponseFrame(
75
- ctx,
76
- await this.generateFrameContent(
77
- new FormControlContext(
78
- ctx,
79
- ctx.query,
80
- [],
81
- query.field_name_prefix,
82
- query.form_id,
83
- query.validate === "true" ? true : false
84
- ),
85
- ctx.query
86
- )
87
- );
88
- });
89
- return;
90
- }
91
- }
@@ -1,108 +0,0 @@
1
- import { randomUUID } from "crypto";
2
- import { FlatTemplatable, tempstream } from "tempstream";
3
- import { FormField } from "../fields/field";
4
- import { FormDataValue } from "../form";
5
- import { FormControl, FormControlContext } from "./form-control";
6
-
7
- export class Derived<
8
- Consts extends Record<string, unknown | undefined>
9
- > extends FormControl {
10
- role = <const>"decoration";
11
-
12
- constructor(
13
- public fields: FormField[],
14
- public _render: (
15
- values: Record<string, string>,
16
- consts: Consts
17
- ) => Promise<FlatTemplatable>,
18
- public getConsts: (
19
- fctx: FormControlContext
20
- ) => Promise<Consts> = async () => ({} as Consts)
21
- ) {
22
- super();
23
- }
24
-
25
- async getBackendValues(
26
- fctx: FormControlContext
27
- ): Promise<Record<string, FormDataValue>> {
28
- const fieldnames = this.fields.map((f) => f.name);
29
- const result = Object.fromEntries(
30
- Object.entries(fctx.data).filter(([key]) =>
31
- fieldnames.includes(key)
32
- )
33
- );
34
- return result;
35
- }
36
-
37
- async render(fctx: FormControlContext): Promise<FlatTemplatable> {
38
- // the A makes it always a valid id, as it cannot start with a number
39
- const id = "A" + randomUUID();
40
-
41
- const consts = this.getConsts(fctx);
42
-
43
- const frontend_side_refresh_code = (values_code = "getValues()") =>
44
- `render(${values_code}, consts)
45
- .then(result=>document.querySelector("#${id}").innerHTML=result)`;
46
-
47
- return tempstream/* HTML */ `<div>
48
- <script>
49
- (function () {
50
- const consts = ${"{" +
51
- Object.entries((await consts) || {})
52
- .map(([key, value]) => {
53
- return `"${key}": ${
54
- typeof value === "object"
55
- ? JSON.stringify(value)
56
- : typeof value == "string"
57
- ? '"' + (value as string).toString() + '"'
58
- : (value as string).toString()
59
- }`;
60
- })
61
- .join(",") +
62
- "}"};
63
- const form_container =
64
- document.currentScript.closest(".form-container");
65
- const render = ${this._render.toString()};
66
- function getValues() {
67
- return Object.fromEntries(
68
- ${JSON.stringify(
69
- this.fields.map((field) => field.name)
70
- )}.map((field_name) => {
71
- let input = form_container.querySelector(
72
- \`input[name="\${field_name}"]\`
73
- );
74
- if (!input) {
75
- return [field_name, ""];
76
- }
77
- if (input.type === "radio") {
78
- input = form_container.querySelector(
79
- \`input[name="\${field_name}"]:checked\`
80
- );
81
- }
82
- return [field_name, input.value];
83
- })
84
- );
85
- }
86
- function setupWatcher(field_name) {
87
- form_container
88
- .querySelectorAll(\`input[name="\${field_name}"]\`)
89
- .forEach((input) => {
90
- input.addEventListener("change", () => {
91
- ${frontend_side_refresh_code()};
92
- });
93
- });
94
- }
95
- ${JSON.stringify(
96
- this.fields.map((field) => field.name)
97
- )}.forEach(setupWatcher);
98
- setTimeout(() => {
99
- ${frontend_side_refresh_code(
100
- JSON.stringify(await this.getBackendValues(fctx))
101
- )};
102
- }, 0);
103
- })();
104
- </script>
105
- <div id="${id}">${this._render({}, await consts)}</div>
106
- </div>`;
107
- }
108
- }
@@ -1,87 +0,0 @@
1
- import { Context } from "koa";
2
- import { FlatTemplatable, tempstream } from "tempstream";
3
- import { attribute } from "../../sanitize";
4
- import { FormField, PickFromListField } from "../fields/field";
5
- import { FormDataValue } from "../form";
6
- import { FormControlContext } from "./form-control";
7
- import { SimpleInput } from "./simple-input";
8
-
9
- export type DropdownOptions = {
10
- label: string;
11
- autosubmit?: boolean;
12
- autocomplete?: boolean;
13
- };
14
-
15
- export type DropdownOption = { value: string; label: string };
16
-
17
- export class FreeformDropdown extends SimpleInput<string | null> {
18
- constructor(
19
- public field: FormField<boolean, string | null>,
20
- public _generateOptions: (ctx: Context) => Promise<DropdownOption[]>,
21
- public options: DropdownOptions = {
22
- label: field.name,
23
- autosubmit: false,
24
- autocomplete: true,
25
- }
26
- ) {
27
- super(field, options);
28
- }
29
-
30
- async generateOptions(ctx: Context): Promise<DropdownOption[]> {
31
- return this._generateOptions(ctx);
32
- }
33
-
34
- async getInputAttributes(
35
- fctx: FormControlContext
36
- ): Promise<Record<string, string | boolean>> {
37
- const original = await super.getInputAttributes(fctx);
38
- return {
39
- ...original,
40
- ...Object.fromEntries([
41
- ...(this.options.autosubmit
42
- ? [
43
- [
44
- "onchange",
45
- (original.onchange || "") +
46
- ";this.form.submit();",
47
- ],
48
- ]
49
- : []),
50
- ]),
51
- };
52
- }
53
-
54
- async renderInput(
55
- ctx: Context,
56
- attributes_str: string,
57
- data: Record<string, FormDataValue>
58
- ): Promise<FlatTemplatable> {
59
- const { parsed: picked_value } = await this.field.getValue(ctx, data);
60
- return /* HTML */ tempstream`<select ${attributes_str}>
61
- ${
62
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
63
- Promise.resolve(this.generateOptions(ctx)).then((options) =>
64
- options.map(
65
- ({ value, label }) =>
66
- `<option value="${attribute(value)}" ${
67
- (value || "") == picked_value ? "selected" : ""
68
- }>${label}</option>`
69
- )
70
- )
71
- }
72
- </select>`;
73
- }
74
- }
75
-
76
- export class Dropdown extends FreeformDropdown {
77
- constructor(
78
- public field: PickFromListField<boolean>,
79
- public options: DropdownOptions = {
80
- label: field.name,
81
- autosubmit: false,
82
- autocomplete: true,
83
- }
84
- ) {
85
- super(field, (ctx) => field.generateOptions(ctx), options);
86
- }
87
- }
@@ -1,97 +0,0 @@
1
- import { FlatTemplatable, tempstream } from "tempstream";
2
- import { attribute } from "../../sanitize";
3
- import { PickFromListField } from "../fields/field";
4
- import { FormFieldControl } from "./controls";
5
- import { FormControlContext } from "./form-control";
6
-
7
- /**
8
- * This control has own forms in it so if you want to use it you
9
- * probably shouldn't use `await super.render(ctx, data, path)` in
10
- * render method of you from implementation and you should write
11
- * your own implementation of this method. See forms that uses
12
- * this control for reference.
13
- */
14
- export class EditableCollectionSubset extends FormFieldControl {
15
- constructor(
16
- public field: PickFromListField<false>,
17
- public actionname: string,
18
- public listLabel?: string,
19
- public selectLabel?: string
20
- ) {
21
- super([field]);
22
- }
23
-
24
- async render(fctx: FormControlContext): Promise<FlatTemplatable> {
25
- const { parsed: values } = await this.field.getValue(
26
- fctx.ctx,
27
- fctx.data
28
- );
29
-
30
- return tempstream/* HTML */ `<div>
31
- <ul>
32
- ${Promise.resolve(this.field.generateOptions(fctx.ctx)).then(
33
- (options) =>
34
- Object.entries(options)
35
- .filter(([value]) =>
36
- (values || ([] as string[])).includes(value)
37
- )
38
- .map(
39
- ([value, text]) => /* HTML */ `
40
- <li>
41
- <form
42
- method="POST"
43
- action="${fctx.ctx.path}"
44
- >
45
- <span>${text}</span>
46
- <input
47
- type="hidden"
48
- name="${this.field.name}"
49
- value="${attribute(value)}"
50
- />
51
- <input
52
- type="hidden"
53
- name="${this.actionname}"
54
- value="list"
55
- />
56
- <input
57
- type="submit"
58
- ${this.listLabel
59
- ? `value="${this.listLabel}"`
60
- : ""}
61
- />
62
- </form>
63
- </li>
64
- `
65
- )
66
- )}
67
- </ul>
68
- <form method="POST" action="${fctx.ctx.path}">
69
- <select name="${this.field.name}">
70
- ${Promise.resolve(
71
- this.field.generateOptions(fctx.ctx)
72
- ).then((options) =>
73
- Object.entries(options)
74
- .filter(
75
- ([value]) =>
76
- !(values || ([] as string[])).includes(
77
- value
78
- )
79
- )
80
- .map(
81
- ([value, text]) =>
82
- `<option value="${attribute(
83
- value
84
- )}">${text}</option>`
85
- )
86
- )}
87
- </select>
88
- <input type="hidden" name="${this.actionname}" value="select" />
89
- <input
90
- type="submit"
91
- ${this.selectLabel ? `value="${this.selectLabel}"` : ""}
92
- />
93
- </form>
94
- </div>`;
95
- }
96
- role = <const>"input";
97
- }
@@ -1,69 +0,0 @@
1
- import { Context } from "koa";
2
- import { FlatTemplatable, tempstream } from "tempstream";
3
- import { FormDataValue, FormMessage } from "../form";
4
- import { FormControl, FormControlContext } from "./form-control";
5
- import { FormFieldControl } from "./form-field-control";
6
-
7
- export class FieldGroup extends FormFieldControl {
8
- constructor(
9
- public controls: FormControl[],
10
- public options: {
11
- label?: string;
12
- classes?: string[];
13
- containerID?: string;
14
- } = {}
15
- ) {
16
- super([]);
17
- }
18
-
19
- preLabel(): FlatTemplatable {
20
- return "";
21
- }
22
-
23
- preLabelContainer(): FlatTemplatable {
24
- return "";
25
- }
26
-
27
- postLabel(): FlatTemplatable {
28
- return "";
29
- }
30
-
31
- preFields(): FlatTemplatable {
32
- return "";
33
- }
34
-
35
- postFields(): FlatTemplatable {
36
- return "";
37
- }
38
-
39
- getGroupLabelProps(): FlatTemplatable {
40
- return `class="field-group__label"`;
41
- }
42
-
43
- async render(fctx: FormControlContext): Promise<FlatTemplatable> {
44
- const { label, classes } = this.options;
45
-
46
- return tempstream/* HTML */ `
47
- <div
48
- class="field-group ${(classes || []).join(" ")}"
49
- ${this.options.containerID
50
- ? `id="${this.options.containerID}"`
51
- : ""}
52
- >
53
- ${this.preLabelContainer()}
54
- <div class="field-group__label-container">
55
- ${this.preLabel()}
56
- ${label
57
- ? `<label ${this.getGroupLabelProps()}>${label}</label>`
58
- : ""}
59
- ${this.postLabel()}
60
- </div>
61
- ${this.preFields()}
62
- <div class="field-group__fields">
63
- ${this.controls.map((control) => control.render(fctx))}
64
- </div>
65
- ${this.postFields()}
66
- </div>
67
- `;
68
- }
69
- }
@@ -1,47 +0,0 @@
1
- import { Context } from "koa";
2
- import { FlatTemplatable, tempstream } from "tempstream";
3
- import { FileContainer } from "../fields/file";
4
- import { FormDataValue } from "../form";
5
- import { FormControlContext } from "./form-control";
6
- import { SimpleInput } from "./simple-input";
7
-
8
- export class File extends SimpleInput<FileContainer> {
9
- getType() {
10
- return "file";
11
- }
12
-
13
- async renderFilePreview(
14
- _ctx: Context,
15
- file_data: { id?: string; filename?: string } | null
16
- ): Promise<FlatTemplatable> {
17
- return file_data?.filename || "";
18
- }
19
-
20
- async preInput(ctx: Context, data: Record<string, FormDataValue>) {
21
- const { parsed } = await this.field.getValue(ctx, data);
22
- return tempstream/* HTML */ `${this.renderFilePreview(ctx, parsed.old)}
23
- <input
24
- type="hidden"
25
- name="${this.field.name}[old][id]"
26
- value="${parsed.old?.id || ""}"
27
- />
28
- <input
29
- type="hidden"
30
- name="${this.field.name}[old][filename]"
31
- value="${parsed.old?.filename || ""}"
32
- />`;
33
- }
34
-
35
- async getInputAttributes(
36
- fctx: FormControlContext
37
- ): Promise<Record<string, string | boolean>> {
38
- const original = await super.getInputAttributes(fctx);
39
- const { parsed } = await this.field.getValue(fctx.ctx, fctx.data);
40
- return {
41
- ...original,
42
- name: this.field.name + "[new]",
43
- required: original.required && !parsed.old,
44
- value: false,
45
- };
46
- }
47
- }
@@ -1,24 +0,0 @@
1
- import Router from "@koa/router";
2
- import { Context } from "koa";
3
- import { FlatTemplatable } from "tempstream";
4
- import { FormDataValue, FormMessage } from "../form";
5
-
6
- export class FormControlContext {
7
- constructor(
8
- public ctx: Context,
9
- public data: Record<string, FormDataValue>,
10
- public messages: FormMessage[],
11
- public field_name_prefix: string,
12
- public form_id: string,
13
- public validate: boolean
14
- ) {}
15
- }
16
-
17
- export abstract class FormControl {
18
- abstract render(
19
- fctx: FormControlContext
20
- ): FlatTemplatable | Promise<FlatTemplatable>;
21
- abstract role: "input" | "decoration" | "messages" | "submit";
22
-
23
- mount(router: Router) {}
24
- }
@@ -1,22 +0,0 @@
1
- import { Context } from "koa";
2
- import { FlatTemplatable } from "tempstream";
3
- import { FormField } from "../fields/field";
4
- import { FieldValueType, FormDataValue } from "../form";
5
- import { FormControl, FormControlContext } from "./form-control";
6
-
7
- export type FormFieldsToTypes<FormFields extends readonly FormField[]> = {
8
- [Index in keyof FormFields]: FormFields[Index] extends FormField
9
- ? FieldValueType<FormFields[Index]>
10
- : never;
11
- };
12
-
13
- export abstract class FormFieldControl extends FormControl {
14
- role = <const>"input";
15
- constructor(public fields: FormField[]) {
16
- super();
17
- }
18
-
19
- abstract render(
20
- fctx: FormControlContext
21
- ): FlatTemplatable | Promise<FlatTemplatable>;
22
- }
@@ -1,19 +0,0 @@
1
- import { Context } from "koa";
2
- import { FormControl } from "./controls";
3
- import { FormControlContext } from "./form-control";
4
-
5
- export class FormHeader extends FormControl {
6
- role = <const>"decoration";
7
- constructor(
8
- public text: string,
9
- public isVisible: (
10
- fctx: FormControlContext
11
- ) => Promise<boolean> = async () => true
12
- ) {
13
- super();
14
- }
15
- async render(fctx: FormControlContext) {
16
- const isVsbl = await this.isVisible(fctx);
17
- return isVsbl ? `<h2>${this.text}</h2>` : "";
18
- }
19
- }
@@ -1,11 +0,0 @@
1
- import { FormControl } from "./controls";
2
-
3
- export class FormParagraph extends FormControl {
4
- role = <const>"decoration";
5
- constructor(public text: string) {
6
- super();
7
- }
8
- render() {
9
- return `<p>${this.text}</p>`;
10
- }
11
- }
@@ -1,26 +0,0 @@
1
- import { FlatTemplatable, Templatable } from "tempstream";
2
- import { FormControl } from "./controls";
3
-
4
- /**
5
- * This class will render `turbo-frame` tag so that u can
6
- * embed other route inside your form. This will require
7
- * to add value to `data: FormData` (inside your master form
8
- * render function) with key `Frame.FRAME_PATH_KEY`. Value
9
- * needs to be url to route that you want to embed. If you
10
- * this value wont be provided frame will redner empty string.
11
- * See `src/back/routes/profile/[id].form.ts` for an example.
12
- */
13
- export class Frame extends FormControl {
14
- constructor(public src: string) {
15
- super();
16
- }
17
-
18
- render(): FlatTemplatable | Promise<FlatTemplatable> {
19
- return /* HTML */ `<turbo-frame
20
- id="contrahents"
21
- loading="lazy"
22
- src="${this.src}"
23
- ></turbo-frame>`;
24
- }
25
- role = <const>"decoration";
26
- }
@@ -1,22 +0,0 @@
1
- import { Context } from "koa";
2
- import { FlatTemplatable, tempstream } from "tempstream";
3
- import { attribute } from "../../sanitize";
4
- import { FormField } from "../fields/field";
5
- import { FormDataValue } from "../form";
6
- import { FormControlContext } from "./form-control";
7
- import { FormFieldControl } from "./form-field-control";
8
-
9
- export class HiddenInput extends FormFieldControl {
10
- constructor(public field: FormField) {
11
- super([field]);
12
- }
13
-
14
- async render(fctx: FormControlContext): Promise<FlatTemplatable> {
15
- const { raw } = await this.field.getValue(fctx.ctx, fctx.data);
16
- return tempstream`<input type="hidden" name="${
17
- this.field.name
18
- }" value="${attribute((raw || "").toString())}" form="${
19
- fctx.form_id
20
- }">`;
21
- }
22
- }
@@ -1,38 +0,0 @@
1
- import { Context } from "koa";
2
- import { FlatTemplatable } from "tempstream";
3
- import { FormDataValue, FormMessage } from "../form";
4
- import { FormControl } from "./controls";
5
- import { FormControlContext } from "./form-control";
6
-
7
- type Renderer =
8
- | ((fctx: FormControlContext) => FlatTemplatable)
9
- | FlatTemplatable;
10
-
11
- export class HTML extends FormControl {
12
- role = (<const>"decoration") as "decoration" | "submit";
13
- public renderer: Renderer;
14
-
15
- constructor(role: "decoration" | "submit", renderer: Renderer);
16
- constructor(renderer: Renderer);
17
- constructor(
18
- role_or_renderer: "decoration" | "submit" | Renderer,
19
- renderer_or_undefined?: Renderer | FlatTemplatable
20
- ) {
21
- super();
22
- if (arguments.length == 2) {
23
- this.role = role_or_renderer as "decoration" | "submit";
24
- this.renderer = renderer_or_undefined as Renderer;
25
- } else {
26
- this.renderer = role_or_renderer;
27
- }
28
- }
29
-
30
- async render(fctx: FormControlContext): Promise<FlatTemplatable> {
31
- if (typeof this.renderer === "string") {
32
- return this.renderer;
33
- }
34
- return typeof this.renderer == "function"
35
- ? this.renderer(fctx)
36
- : this.renderer;
37
- }
38
- }