@sealcode/jdd-editor 0.1.0

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 (192) hide show
  1. package/.arcconfig +12 -0
  2. package/.arclint +18 -0
  3. package/.eslintrc.js +37 -0
  4. package/.mocharc.js +6 -0
  5. package/.nycrc +6 -0
  6. package/.prettierrc +14 -0
  7. package/@types/component-preview-actions.d.ts +43 -0
  8. package/@types/components.sreact.d.ts +48 -0
  9. package/@types/controllers/autogrow-textarea.stimulus.d.ts +5 -0
  10. package/@types/controllers/component-debugger.stimulus.d.ts +28 -0
  11. package/@types/controllers/exportable-textarea.stimulus.d.ts +7 -0
  12. package/@types/controllers/input-image-preview.stimulus.d.ts +5 -0
  13. package/@types/controllers/jdd-table-paste.stimulus.d.ts +8 -0
  14. package/@types/controllers/json-editor.stimulus.d.ts +9 -0
  15. package/@types/controllers/markdown-textarea.stimulus.d.ts +20 -0
  16. package/@types/controllers/refresh-on-ts-changes.stimulus.d.ts +6 -0
  17. package/@types/controllers/refresh-styles.stimulus.d.ts +6 -0
  18. package/@types/controllers/submit-on-input.stimulus.d.ts +7 -0
  19. package/@types/controllers/toast.stimulus.d.ts +4 -0
  20. package/@types/edit-jdd-field.d.ts +22 -0
  21. package/@types/index.d.ts +2 -0
  22. package/@types/inputs/component-input-enum.d.ts +8 -0
  23. package/@types/inputs/component-input-image.d.ts +15 -0
  24. package/@types/inputs/component-input-list.d.ts +15 -0
  25. package/@types/inputs/component-input-single-reference.d.ts +11 -0
  26. package/@types/inputs/component-input-structured.d.ts +15 -0
  27. package/@types/inputs/component-input-table.d.ts +15 -0
  28. package/@types/inputs/component-input.d.ts +16 -0
  29. package/@types/inputs/print-arg-path.d.ts +1 -0
  30. package/@types/jdd-creator.d.ts +49 -0
  31. package/@types/jdd-page.d.ts +85 -0
  32. package/assets/icons/table-add-column-right.svg +1 -0
  33. package/assets/icons/table-add-row-below.svg +1 -0
  34. package/assets/icons/table-add-row-header-below.svg +1 -0
  35. package/assets/icons/table-delete-column.svg +1 -0
  36. package/assets/icons/table-delete-row.svg +1 -0
  37. package/assets/icons/table-move-column-right.svg +1 -0
  38. package/assets/icons/table-move-row-down.svg +1 -0
  39. package/assets/icons/table-move-row-up.svg +1 -0
  40. package/assets/styles/component-admin-table.jdd-page.css +11 -0
  41. package/assets/styles/component-debugger.jdd-page.css +71 -0
  42. package/assets/styles/components.jdd-page.css +286 -0
  43. package/assets/styles/grow-wrap.css +33 -0
  44. package/assets/styles/markdown-editor.css +42 -0
  45. package/dist/src/autogrow-textarea.stimulus.js +13 -0
  46. package/dist/src/autogrow-textarea.stimulus.js.map +7 -0
  47. package/dist/src/component-debugger.stimulus.js +190 -0
  48. package/dist/src/component-debugger.stimulus.js.map +7 -0
  49. package/dist/src/component-preview-actions.js +439 -0
  50. package/dist/src/component-preview-actions.js.map +7 -0
  51. package/dist/src/components.sreact.js +93 -0
  52. package/dist/src/components.sreact.js.map +7 -0
  53. package/dist/src/controllers/autogrow-textarea.stimulus.js +13 -0
  54. package/dist/src/controllers/autogrow-textarea.stimulus.js.map +7 -0
  55. package/dist/src/controllers/component-debugger.stimulus.js +193 -0
  56. package/dist/src/controllers/component-debugger.stimulus.js.map +7 -0
  57. package/dist/src/controllers/exportable-textarea.stimulus.js +71 -0
  58. package/dist/src/controllers/exportable-textarea.stimulus.js.map +7 -0
  59. package/dist/src/controllers/input-image-preview.stimulus.js +30 -0
  60. package/dist/src/controllers/input-image-preview.stimulus.js.map +7 -0
  61. package/dist/src/controllers/jdd-table-paste.stimulus.js +78 -0
  62. package/dist/src/controllers/jdd-table-paste.stimulus.js.map +7 -0
  63. package/dist/src/controllers/json-editor.stimulus.js +114 -0
  64. package/dist/src/controllers/json-editor.stimulus.js.map +7 -0
  65. package/dist/src/controllers/markdown-textarea.stimulus.js +174 -0
  66. package/dist/src/controllers/markdown-textarea.stimulus.js.map +7 -0
  67. package/dist/src/controllers/refresh-on-ts-changes.stimulus.js +90 -0
  68. package/dist/src/controllers/refresh-on-ts-changes.stimulus.js.map +7 -0
  69. package/dist/src/controllers/refresh-styles.stimulus.js +67 -0
  70. package/dist/src/controllers/refresh-styles.stimulus.js.map +7 -0
  71. package/dist/src/controllers/submit-on-input.stimulus.js +55 -0
  72. package/dist/src/controllers/submit-on-input.stimulus.js.map +7 -0
  73. package/dist/src/controllers/toast.stimulus.js +19 -0
  74. package/dist/src/controllers/toast.stimulus.js.map +7 -0
  75. package/dist/src/edit-jdd-field.js +94 -0
  76. package/dist/src/edit-jdd-field.js.map +7 -0
  77. package/dist/src/exportable-textarea.stimulus.js +71 -0
  78. package/dist/src/exportable-textarea.stimulus.js.map +7 -0
  79. package/dist/src/index.js +3 -0
  80. package/dist/src/index.js.map +7 -0
  81. package/dist/src/input-image-preview.stimulus.js +30 -0
  82. package/dist/src/input-image-preview.stimulus.js.map +7 -0
  83. package/dist/src/inputs/component-input-enum.js +30 -0
  84. package/dist/src/inputs/component-input-enum.js.map +7 -0
  85. package/dist/src/inputs/component-input-image.js +58 -0
  86. package/dist/src/inputs/component-input-image.js.map +7 -0
  87. package/dist/src/inputs/component-input-list.js +74 -0
  88. package/dist/src/inputs/component-input-list.js.map +7 -0
  89. package/dist/src/inputs/component-input-single-reference.js +31 -0
  90. package/dist/src/inputs/component-input-single-reference.js.map +7 -0
  91. package/dist/src/inputs/component-input-structured.js +36 -0
  92. package/dist/src/inputs/component-input-structured.js.map +7 -0
  93. package/dist/src/inputs/component-input-table.js +228 -0
  94. package/dist/src/inputs/component-input-table.js.map +7 -0
  95. package/dist/src/inputs/component-input.js +129 -0
  96. package/dist/src/inputs/component-input.js.map +7 -0
  97. package/dist/src/inputs/print-arg-path.js +7 -0
  98. package/dist/src/inputs/print-arg-path.js.map +7 -0
  99. package/dist/src/jdd-creator.js +131 -0
  100. package/dist/src/jdd-creator.js.map +7 -0
  101. package/dist/src/jdd-page.js +339 -0
  102. package/dist/src/jdd-page.js.map +7 -0
  103. package/dist/src/jdd-table-paste.stimulus.js +78 -0
  104. package/dist/src/jdd-table-paste.stimulus.js.map +7 -0
  105. package/dist/src/json-editor.stimulus.js +114 -0
  106. package/dist/src/json-editor.stimulus.js.map +7 -0
  107. package/dist/src/markdown-textarea.stimulus.js +174 -0
  108. package/dist/src/markdown-textarea.stimulus.js.map +7 -0
  109. package/dist/src/submit-on-input.stimulus.js +55 -0
  110. package/dist/src/submit-on-input.stimulus.js.map +7 -0
  111. package/dist/src/toast.stimulus.js +19 -0
  112. package/dist/src/toast.stimulus.js.map +7 -0
  113. package/esbuild.cjs +20 -0
  114. package/esbuild.js +23 -0
  115. package/jenkins.sanity.sh +3 -0
  116. package/lib/component-preview-actions.js +286 -0
  117. package/lib/component-preview-actions.js.map +1 -0
  118. package/lib/components.sreact.js +102 -0
  119. package/lib/components.sreact.js.map +1 -0
  120. package/lib/controllers/autogrow-textarea.stimulus.js +15 -0
  121. package/lib/controllers/autogrow-textarea.stimulus.js.map +1 -0
  122. package/lib/controllers/component-debugger.stimulus.js +188 -0
  123. package/lib/controllers/component-debugger.stimulus.js.map +1 -0
  124. package/lib/controllers/exportable-textarea.stimulus.js +79 -0
  125. package/lib/controllers/exportable-textarea.stimulus.js.map +1 -0
  126. package/lib/controllers/input-image-preview.stimulus.js +28 -0
  127. package/lib/controllers/input-image-preview.stimulus.js.map +1 -0
  128. package/lib/controllers/jdd-table-paste.stimulus.js +84 -0
  129. package/lib/controllers/jdd-table-paste.stimulus.js.map +1 -0
  130. package/lib/controllers/json-editor.stimulus.js +134 -0
  131. package/lib/controllers/json-editor.stimulus.js.map +1 -0
  132. package/lib/controllers/markdown-textarea.stimulus.js +186 -0
  133. package/lib/controllers/markdown-textarea.stimulus.js.map +1 -0
  134. package/lib/controllers/refresh-on-ts-changes.stimulus.js +123 -0
  135. package/lib/controllers/refresh-on-ts-changes.stimulus.js.map +1 -0
  136. package/lib/controllers/refresh-styles.stimulus.js +66 -0
  137. package/lib/controllers/refresh-styles.stimulus.js.map +1 -0
  138. package/lib/controllers/submit-on-input.stimulus.js +48 -0
  139. package/lib/controllers/submit-on-input.stimulus.js.map +1 -0
  140. package/lib/controllers/toast.stimulus.js +16 -0
  141. package/lib/controllers/toast.stimulus.js.map +1 -0
  142. package/lib/edit-jdd-field.js +102 -0
  143. package/lib/edit-jdd-field.js.map +1 -0
  144. package/lib/index.js +19 -0
  145. package/lib/index.js.map +1 -0
  146. package/lib/inputs/component-input-enum.js +25 -0
  147. package/lib/inputs/component-input-enum.js.map +1 -0
  148. package/lib/inputs/component-input-image.js +47 -0
  149. package/lib/inputs/component-input-image.js.map +1 -0
  150. package/lib/inputs/component-input-list.js +61 -0
  151. package/lib/inputs/component-input-list.js.map +1 -0
  152. package/lib/inputs/component-input-single-reference.js +36 -0
  153. package/lib/inputs/component-input-single-reference.js.map +1 -0
  154. package/lib/inputs/component-input-structured.js +42 -0
  155. package/lib/inputs/component-input-structured.js.map +1 -0
  156. package/lib/inputs/component-input-table.js +184 -0
  157. package/lib/inputs/component-input-table.js.map +1 -0
  158. package/lib/inputs/component-input.js +133 -0
  159. package/lib/inputs/component-input.js.map +1 -0
  160. package/lib/inputs/print-arg-path.js +7 -0
  161. package/lib/inputs/print-arg-path.js.map +1 -0
  162. package/lib/jdd-creator.js +113 -0
  163. package/lib/jdd-creator.js.map +1 -0
  164. package/lib/jdd-page.js +310 -0
  165. package/lib/jdd-page.js.map +1 -0
  166. package/package.json +61 -0
  167. package/src/component-preview-actions.ts +520 -0
  168. package/src/components.sreact.ts +100 -0
  169. package/src/controllers/autogrow-textarea.stimulus.ts +13 -0
  170. package/src/controllers/component-debugger.stimulus.ts +247 -0
  171. package/src/controllers/exportable-textarea.stimulus.ts +77 -0
  172. package/src/controllers/input-image-preview.stimulus.ts +29 -0
  173. package/src/controllers/jdd-table-paste.stimulus.ts +89 -0
  174. package/src/controllers/json-editor.stimulus.ts +127 -0
  175. package/src/controllers/markdown-textarea.stimulus.ts +198 -0
  176. package/src/controllers/refresh-on-ts-changes.stimulus.ts +112 -0
  177. package/src/controllers/refresh-styles.stimulus.ts +70 -0
  178. package/src/controllers/submit-on-input.stimulus.ts +66 -0
  179. package/src/controllers/toast.stimulus.ts +15 -0
  180. package/src/edit-jdd-field.ts +127 -0
  181. package/src/index.ts +2 -0
  182. package/src/inputs/component-input-enum.ts +36 -0
  183. package/src/inputs/component-input-image.ts +70 -0
  184. package/src/inputs/component-input-list.ts +91 -0
  185. package/src/inputs/component-input-single-reference.ts +45 -0
  186. package/src/inputs/component-input-structured.ts +51 -0
  187. package/src/inputs/component-input-table.ts +262 -0
  188. package/src/inputs/component-input.ts +158 -0
  189. package/src/inputs/print-arg-path.ts +3 -0
  190. package/src/jdd-creator.ts +151 -0
  191. package/src/jdd-page.ts +439 -0
  192. package/tsconfig.json +24 -0
@@ -0,0 +1,151 @@
1
+ import type { Context } from "koa";
2
+ import { ComponentPreviewActions } from "./component-preview-actions.js";
3
+ import type { JDDPageState } from "./jdd-page.js";
4
+ import JDDPage from "./jdd-page.js";
5
+ import { htmlEscape } from "escape-goat";
6
+ import { tempstream } from "tempstream";
7
+
8
+ export default abstract class JDDCreator extends JDDPage {
9
+ actions = ComponentPreviewActions;
10
+
11
+ /**
12
+ * This method returns list of components allowed in JDD Editor instance.
13
+ * If list is empty it will allow all of the components in registry,
14
+ * if you overide this function you can decide on what components should
15
+ * available.
16
+ */
17
+ getAllowedComponents(): string[] {
18
+ return [];
19
+ }
20
+
21
+ getRegistryComponents() {
22
+ const all_components = super.getRegistryComponents();
23
+ const allowed_components = this.getAllowedComponents();
24
+
25
+ if (allowed_components.length > 0) {
26
+ return Object.fromEntries(
27
+ Object.entries(all_components).filter(([name]) =>
28
+ allowed_components.includes(name)
29
+ )
30
+ );
31
+ }
32
+
33
+ return all_components;
34
+ }
35
+
36
+ renderParameterButtons(state: JDDPageState) {
37
+ {
38
+ /*The below button has to be here in order for it to be the default behavior */
39
+ }
40
+ return `<div class="jdd-editor__toolbar">
41
+ <input type="submit" value="Preview" />
42
+ <select name="component">
43
+ ${Object.keys(this.getRegistryComponents())
44
+ .map((cmp) => `<option value="${cmp}">${cmp}</option>`)
45
+ .join("")}
46
+ </select>
47
+ ${this.makeActionButton(state, {
48
+ action: "add_component",
49
+ label: "Add component",
50
+ })}
51
+ </div>`;
52
+ }
53
+
54
+ renderComponentBlock(
55
+ ctx: Context,
56
+ state: JDDPageState,
57
+ component_data: {
58
+ component_name: string;
59
+ args: Record<string, unknown>;
60
+ },
61
+ component_index: number
62
+ ) {
63
+ const component =
64
+ this.getRegistryComponents()[component_data.component_name];
65
+ const checkbox_id = `component_${component_index}_open`;
66
+ return tempstream/* HTML */ `<div
67
+ class="jdd-editor__component-block jdd-editor__component-block--number-${component_index}"
68
+ id="${`jdd-editor__component-block--${component_data.component_name}-${component_index}`}"
69
+ data-component-debugger-target="componentBlock"
70
+ data-component-index="${component_index.toString()}"
71
+ >
72
+ <summary class="jdd-editor__component-block__top_bar">
73
+ ${this.makeActionButton(
74
+ state,
75
+ { action: "remove_component", label: "❌" },
76
+ component_index
77
+ )}
78
+ ${this.makeActionButton(
79
+ state,
80
+ {
81
+ action: "move_component_up",
82
+ label: "Move this row up",
83
+ content: /* HTML */ `<img
84
+ width="20"
85
+ height="20"
86
+ src="${this.makeAssetURL(
87
+ "icons/table-move-row-up.svg"
88
+ )}"
89
+ />`,
90
+ },
91
+ component_index
92
+ )}
93
+ ${this.makeActionButton(
94
+ state,
95
+ {
96
+ action: "move_component_down",
97
+ label: "Move this row down",
98
+ content: /* HTML */ `<img
99
+ width="20"
100
+ height="20"
101
+ src="${this.makeAssetURL(
102
+ "icons/table-move-row-down.svg"
103
+ )}"
104
+ />`,
105
+ },
106
+ component_index
107
+ )}
108
+ <span class="jdd-editor__component-block__title">
109
+ <div class="jdd-editor__component-block__title__main">
110
+ ${htmlEscape(
111
+ component?.getTitle(
112
+ this.makeJDDContext(ctx),
113
+ component_data.args
114
+ ) || ""
115
+ )}
116
+ </div>
117
+ <div class="jdd-editor__component-block__title__secondary">
118
+ ${component_data.component_name}
119
+ </div>
120
+ </span>
121
+ <label
122
+ class="component-block__handle"
123
+ for="${checkbox_id}"
124
+ style="flex-grow: 1"
125
+ data-action="click->component-debugger#labelClicked"
126
+ >
127
+ <span class="jdd-editor__component-block__chevron">
128
+ ${" "} &gt;${" "}
129
+ </span>
130
+ </label>
131
+ </summary>
132
+ <input
133
+ type="checkbox"
134
+ class="component-collapse-toggle"
135
+ name="${`$[components][${component_index}][open]`}"
136
+ data-turbo-permanent
137
+ id="${checkbox_id}"
138
+ style="display:none"
139
+ data-component-debugger-target="checkbox"
140
+ />
141
+ <div class="jdd-editor__component-block__inner">
142
+ ${super.renderComponentBlock(
143
+ ctx,
144
+ state,
145
+ component_data,
146
+ component_index
147
+ )}
148
+ </div>
149
+ </div>`;
150
+ }
151
+ }
@@ -0,0 +1,439 @@
1
+ /* eslint-disable @typescript-eslint/restrict-template-expressions */
2
+ import type { Readable } from "node:stream";
3
+ import type { Component, JDDContext, RawJDDocument } from "@sealcode/jdd";
4
+ import { documentContainerFromParsed, Registry } from "@sealcode/jdd";
5
+ import { JDD } from "@sealcode/jdd";
6
+ import { StatefulPage } from "@sealcode/sealgen";
7
+ import { hasFieldOfType, hasShape, predicates } from "@sealcode/ts-predicates";
8
+ import type { Context } from "koa";
9
+ import type { FlatTemplatable, Templatable } from "tempstream";
10
+ import { tempstream } from "tempstream";
11
+ import { ComponentInput } from "./inputs/component-input.js";
12
+ import { ComponentPreviewActions } from "./component-preview-actions.js";
13
+
14
+ export const actionName = "Components";
15
+
16
+ export type JDDPageState = {
17
+ components: RawJDDocument;
18
+ preview_size?: string;
19
+ messages?: string[];
20
+ };
21
+
22
+ export default abstract class JDDPage extends StatefulPage<
23
+ JDDPageState,
24
+ typeof ComponentPreviewActions
25
+ > {
26
+ actions = ComponentPreviewActions;
27
+
28
+ previewSizes = ["320", "600", "800", "1024", "1300", "1920"];
29
+ classes: string[] = [];
30
+
31
+ public registry: Registry;
32
+ public makeJDDContext: (ctx: Context) => JDDContext;
33
+ public html: (
34
+ args: unknown
35
+ ) => string | Promise<string> | Readable | Promise<Readable>;
36
+ public defaultHead: (
37
+ ...args: unknown[]
38
+ ) => string | Promise<string> | Readable | Promise<Readable>;
39
+ public makeAssetURL: (asset: string) => string;
40
+
41
+ constructor(args: {
42
+ registry: Registry;
43
+ makeJDDContext: (ctx: Context) => JDDContext;
44
+ html: (
45
+ args: unknown
46
+ ) => string | Promise<string> | Readable | Promise<Readable>;
47
+ defaultHead: (
48
+ ...args: unknown[]
49
+ ) => string | Promise<string> | Readable | Promise<Readable>;
50
+ makeAssetURL?: (asset: string) => string;
51
+ }) {
52
+ super();
53
+ this.registry = args.registry;
54
+ this.makeJDDContext = args.makeJDDContext;
55
+ this.defaultHead = args.defaultHead;
56
+ this.html = args.html;
57
+ this.makeAssetURL =
58
+ args.makeAssetURL ||
59
+ ((str) =>
60
+ `/dist/jdd-page/${str.startsWith("/") ? str.slice(1) : str}`);
61
+ }
62
+
63
+ getRegistryComponents() {
64
+ return this.registry.getAll();
65
+ }
66
+
67
+ async getInitialState(ctx: Context) {
68
+ const all_components = Object.entries(this.getRegistryComponents());
69
+ const first_component = all_components[0];
70
+ if (!first_component) {
71
+ throw new Error("No defined components!");
72
+ }
73
+ const [component_name, component] = first_component;
74
+ const initial_state = {
75
+ components: [
76
+ {
77
+ component_name: component_name,
78
+ args: await component.getExampleValues(
79
+ this.makeJDDContext(ctx)
80
+ ),
81
+ },
82
+ ],
83
+ };
84
+ return initial_state;
85
+ }
86
+
87
+ wrapInLayout(
88
+ ctx: Context,
89
+ content: Templatable,
90
+ state: JDDPageState
91
+ ): Templatable {
92
+ const jdd = new JDD(
93
+ this.registry,
94
+ this.makeJDDContext(ctx),
95
+ documentContainerFromParsed(state.components)
96
+ );
97
+ return this.html({
98
+ ctx,
99
+ title: "Components",
100
+ body: content,
101
+ description: "",
102
+ css_clumps: ["jdd-page", ...jdd.getAllCSSClumps()],
103
+ htmlOptions: {
104
+ morphing: true,
105
+ preserveScroll: true,
106
+ autoRefreshCSS: false,
107
+ navbar: () => ``,
108
+ bodyClasses: ["jdd-editor"],
109
+ showBottomNavbar: false,
110
+ showBanner: false,
111
+ showFooter: false,
112
+ loadHamburgerMenu: false,
113
+ loadSearchModal: false,
114
+ },
115
+ makeHead: (...args: unknown[]) =>
116
+ tempstream/* HTML */ `${this.defaultHead(...args)}
117
+ <link
118
+ href="/dist/jdd-page.entrypoint.css"
119
+ rel="stylesheet"
120
+ type="text/css"
121
+ />
122
+ ${jdd.renderEarlyAssets()}`,
123
+ });
124
+ }
125
+
126
+ async preprocessOverrides(
127
+ _ctx: Context,
128
+ state: JDDPageState,
129
+ overrides: Record<string, unknown>
130
+ ) {
131
+ const jdd_context = this.makeJDDContext(_ctx);
132
+ if (
133
+ !hasFieldOfType(
134
+ "components",
135
+ overrides,
136
+ predicates.array(
137
+ predicates.shape({
138
+ args: predicates.object,
139
+ })
140
+ )
141
+ )
142
+ ) {
143
+ return {};
144
+ }
145
+ for (const [component_index, { component_name }] of Object.entries(
146
+ state.components
147
+ )) {
148
+ const component = this.registry.get(component_name);
149
+ if (!component) {
150
+ throw new Error(`Unknown component: ${component_name}`);
151
+ }
152
+ const overrides_for_component = overrides.components[
153
+ parseInt(component_index)
154
+ ] || { args: {} };
155
+ const promises = Object.entries(component.getArguments()).map(
156
+ async ([arg_name, arg]) => {
157
+ const value = overrides_for_component.args[arg_name];
158
+ if (value) {
159
+ const new_value = await arg.receivedToParsed(
160
+ jdd_context,
161
+ value
162
+ );
163
+ overrides_for_component.args[arg_name] = new_value;
164
+ }
165
+ }
166
+ );
167
+ // eslint-disable-next-line no-await-in-loop
168
+ await Promise.all(promises);
169
+ }
170
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
171
+ return overrides;
172
+ }
173
+
174
+ // eslint-disable-next-line no-unused-vars
175
+ abstract renderParameterButtons(_state: JDDPageState): FlatTemplatable;
176
+
177
+ renderComponentArgs<C extends Component>(
178
+ ctx: Context,
179
+ state: JDDPageState,
180
+ component: C,
181
+ args: Record<string, unknown>,
182
+ index: number
183
+ ): FlatTemplatable {
184
+ const jdd_context = this.makeJDDContext(ctx);
185
+ return tempstream/* HTML */ `<div
186
+ class="component-preview-parameters"
187
+ id="${`component-preview-parameters--${index}`}"
188
+ >
189
+ ${Object.entries(component.getArguments()).map(
190
+ async ([arg_name, arg]) =>
191
+ ComponentInput({
192
+ state,
193
+ arg_path: [
194
+ "components",
195
+ index.toString(),
196
+ "args",
197
+ arg_name,
198
+ ],
199
+ ctx,
200
+ arg,
201
+ value:
202
+ args[arg_name] === undefined
203
+ ? arg.getExampleValue(jdd_context)
204
+ : args[arg_name],
205
+ page: this,
206
+ makeJDDContext: this.makeJDDContext,
207
+ makeAssetURL: this.makeAssetURL,
208
+ })
209
+ )}
210
+ </div>`;
211
+ }
212
+
213
+ renderComponentBlock(
214
+ ctx: Context,
215
+ state: JDDPageState,
216
+ {
217
+ component_name,
218
+ args: component_args,
219
+ }: {
220
+ component_name: string;
221
+ args: Record<string, unknown>;
222
+ },
223
+ component_index: number
224
+ ) {
225
+ const component = this.registry.get(component_name);
226
+ if (!component) {
227
+ return null;
228
+ }
229
+ return this.renderComponentArgs(
230
+ ctx,
231
+ state,
232
+ component,
233
+ component_args,
234
+ component_index
235
+ );
236
+ }
237
+
238
+ async serializeState(ctx: Context, state: JDDPageState, pretty = false) {
239
+ console.time("serializing state");
240
+ const serialized_components = await Promise.all(
241
+ state.components.map(async ({ component_name, args }) => {
242
+ const component = this.registry.get(component_name);
243
+ const single_result = {
244
+ component_name,
245
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
246
+ args: component
247
+ ? await component.convertParsedToStorage(
248
+ this.makeJDDContext(ctx),
249
+ args
250
+ )
251
+ : {},
252
+ };
253
+ return single_result;
254
+ })
255
+ );
256
+ const serialized_state = JSON.stringify(
257
+ { components: serialized_components },
258
+ null,
259
+ pretty ? 4 : ""
260
+ );
261
+ console.timeEnd("serializing state");
262
+ return serialized_state;
263
+ }
264
+
265
+ async deserializeState(ctx: Context, state_string: string) {
266
+ const jdd_context = this.makeJDDContext(ctx);
267
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
268
+ const raw = JSON.parse(state_string);
269
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
270
+ const components_storage = raw.components;
271
+ if (!Array.isArray(components_storage)) {
272
+ throw new Error(
273
+ "'components' key is not an array, got ${components_storage}"
274
+ );
275
+ }
276
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
277
+ const components_parsed = await Promise.all(
278
+ components_storage.map(async (entry) => {
279
+ if (
280
+ !hasShape(
281
+ {
282
+ component_name: predicates.string,
283
+ args: predicates.object,
284
+ },
285
+ entry
286
+ )
287
+ ) {
288
+ throw new Error(
289
+ `Expected components[] items to be objects with 'component_name' and 'args' keys, got ${entry}`
290
+ );
291
+ }
292
+ const { component_name, args } = entry;
293
+ const component = this.registry.get(component_name);
294
+ if (!component) {
295
+ throw new Error("Unknown component: ${component_name}");
296
+ }
297
+ return {
298
+ component_name,
299
+ args: await component.convertStorageToParsed(
300
+ jdd_context,
301
+ args
302
+ ),
303
+ };
304
+ })
305
+ );
306
+ const result = { components: components_parsed };
307
+ return result;
308
+ }
309
+
310
+ renderPreParameterButtons(
311
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
312
+ _ctx: Context,
313
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
314
+ _state: JDDPageState
315
+ ): FlatTemplatable | Promise<FlatTemplatable> {
316
+ return "";
317
+ }
318
+
319
+ renderMessages(_ctx: Context, state: JDDPageState) {
320
+ return /* HTML */ `<ul
321
+ class="jdd-editor__messages"
322
+ data-controller="toast"
323
+ >
324
+ ${(state.messages || []).map(
325
+ (e) => `<li class="jdd-editor__message">${e}</li>`
326
+ )}
327
+ </ul>`;
328
+ }
329
+
330
+ async render(ctx: Context, state: JDDPageState): Promise<string> {
331
+ return tempstream/* HTML */ `<div
332
+ class="${["two-column", "component-debugger", ...this.classes].join(
333
+ " "
334
+ )}"
335
+ id="component-debugger"
336
+ style="${`--resizable-column-width: ${
337
+ state.preview_size ? state.preview_size + "px" : "50vw"
338
+ }`}"
339
+ data-controller="component-debugger"
340
+ >
341
+ <div class="component-arguments" id="component-arguments">
342
+ ${this.renderPreParameterButtons(ctx, state)}
343
+ ${this.renderParameterButtons(state)}
344
+ ${this.renderMessages(ctx, state)}
345
+ ${state.components.map((component, component_index) =>
346
+ this.renderComponentBlock(
347
+ ctx,
348
+ state,
349
+ component,
350
+ component_index
351
+ )
352
+ )}
353
+ <details
354
+ class="component-debugger__json"
355
+ data-controller="exportable-textarea"
356
+ id="exportable-textarea"
357
+ open
358
+ >
359
+ <summary>Edit/Export raw JSON</summary>
360
+ <textarea
361
+ name="state_override"
362
+ rows="40"
363
+ cols="40"
364
+ data-controller="json-editor"
365
+ id="component-debugger-json-textarea"
366
+ autocomplete="off"
367
+ >
368
+ ${(await this.serializeState(ctx, state, true)).replaceAll("<", "&lt;")}
369
+ </textarea
370
+ >
371
+ ${this.makeActionButton(state, {
372
+ action: "replace_state",
373
+ label: "Apply",
374
+ })}
375
+ <button data-action="exportable-textarea#copy">Copy</button>
376
+ <button data-action="exportable-textarea#download">
377
+ Download
378
+ </button>
379
+ <input type="file" />${" "}
380
+ <button data-action="exportable-textarea#import">
381
+ Import
382
+ </button>
383
+ </details>
384
+ </div>
385
+ <div
386
+ id="resize-gutter"
387
+ class="resize-gutter"
388
+ data-component-debugger-target="gutter"
389
+ ></div>
390
+ <div
391
+ id="component-preview"
392
+ class="component-preview"
393
+ data-component-debugger-target="preview"
394
+ >
395
+ <div
396
+ id="component-preview__header"
397
+ class="component-preview__header"
398
+ >
399
+ <span>Preview</span>
400
+ <select
401
+ name="$[preview_size]"
402
+ autocomplete="off"
403
+ class="component-preview-size-select"
404
+ data-component-debugger-target="sizeSelect"
405
+ data-action="change->component-debugger#handleWidthDropdown"
406
+ data-turbo-data-turbo-permanent
407
+ >
408
+ ${state.preview_size
409
+ ? /* HTML */ `<option
410
+ class="dynamic"
411
+ value="${state.preview_size}"
412
+ selected
413
+ >
414
+ ${state.preview_size} px
415
+ </option>`
416
+ : ""}
417
+ ${this.previewSizes.map(
418
+ (size) => /* HTML */ `<option value="${size}">
419
+ ${`${size} px`}
420
+ </option>`
421
+ )}
422
+ </select>
423
+ <noscript>
424
+ ${this.makeActionButton(state, "change_size")}
425
+ </noscript>
426
+ </div>
427
+ <div class="jdd-outer-container">
428
+ <div class="jdd-container">
429
+ ${JDD.render(
430
+ this.registry,
431
+ documentContainerFromParsed(state.components),
432
+ this.makeJDDContext(ctx)
433
+ )}
434
+ </div>
435
+ </div>
436
+ </div>
437
+ </div>`;
438
+ }
439
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "commonjs",
4
+ "moduleResolution": "node",
5
+ "noImplicitAny": true,
6
+ "noImplicitThis": true,
7
+ "strictNullChecks": true,
8
+ "target": "ES6",
9
+ "declaration": true,
10
+ "esModuleInterop": true,
11
+ "lib": ["ES6", "ESNext", "dom"],
12
+ "outDir": "lib",
13
+ "checkJs": true,
14
+ "allowJs": true,
15
+ "declarationDir": "@types",
16
+ "resolveJsonModule": true,
17
+ "sourceMap": true,
18
+ "skipLibCheck": true,
19
+ "noUncheckedIndexedAccess": true,
20
+ "strictBindCallApply": true
21
+ },
22
+ "include": ["src/**/*"],
23
+ "exclude": ["node_modules/**"]
24
+ }