clapton 0.0.13 → 0.0.14

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 (64) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -0
  3. data/app/helpers/clapton/clapton_helper.rb +16 -1
  4. data/lib/clapton/engine.rb +14 -10
  5. data/lib/clapton/javascripts/dist/client.js +31 -19
  6. data/lib/clapton/javascripts/dist/components-for-test.js +439 -0
  7. data/lib/clapton/javascripts/dist/components.js +356 -382
  8. data/lib/clapton/javascripts/node_modules/diff-dom/LICENSE.txt +165 -0
  9. data/lib/clapton/javascripts/node_modules/diff-dom/README.md +224 -0
  10. data/lib/clapton/javascripts/node_modules/diff-dom/browser/diffDOM.js +2 -0
  11. data/lib/clapton/javascripts/node_modules/diff-dom/browser/diffDOM.js.map +1 -0
  12. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/TraceLogger.d.ts +28 -0
  13. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/dom/apply.d.ts +4 -0
  14. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/dom/fromVirtual.d.ts +2 -0
  15. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/dom/index.d.ts +2 -0
  16. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/dom/undo.d.ts +3 -0
  17. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/helpers.d.ts +11 -0
  18. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/index.d.ts +10 -0
  19. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/types.d.ts +104 -0
  20. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/virtual/apply.d.ts +3 -0
  21. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/virtual/diff.d.ts +22 -0
  22. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/virtual/fromDOM.d.ts +2 -0
  23. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/virtual/fromString.d.ts +2 -0
  24. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/virtual/helpers.d.ts +40 -0
  25. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/virtual/index.d.ts +3 -0
  26. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/index.d.ts +2 -0
  27. data/lib/clapton/javascripts/node_modules/diff-dom/dist/index.d.ts +136 -0
  28. data/lib/clapton/javascripts/node_modules/diff-dom/dist/index.js +1996 -0
  29. data/lib/clapton/javascripts/node_modules/diff-dom/dist/index.js.map +1 -0
  30. data/lib/clapton/javascripts/node_modules/diff-dom/dist/index.min.js +2 -0
  31. data/lib/clapton/javascripts/node_modules/diff-dom/dist/index.min.js.map +1 -0
  32. data/lib/clapton/javascripts/node_modules/diff-dom/dist/module.js +1991 -0
  33. data/lib/clapton/javascripts/node_modules/diff-dom/dist/module.js.map +1 -0
  34. data/lib/clapton/javascripts/node_modules/diff-dom/index.html +62 -0
  35. data/lib/clapton/javascripts/node_modules/diff-dom/package.json +54 -0
  36. data/lib/clapton/javascripts/node_modules/diff-dom/rollup.config.mjs +67 -0
  37. data/lib/clapton/javascripts/node_modules/diff-dom/src/TraceLogger.ts +143 -0
  38. data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/dom/apply.ts +227 -0
  39. data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/dom/fromVirtual.ts +83 -0
  40. data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/dom/index.ts +2 -0
  41. data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/dom/undo.ts +90 -0
  42. data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/helpers.ts +40 -0
  43. data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/index.ts +121 -0
  44. data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/types.ts +154 -0
  45. data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/virtual/apply.ts +349 -0
  46. data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/virtual/diff.ts +855 -0
  47. data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/virtual/fromDOM.ts +74 -0
  48. data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/virtual/fromString.ts +239 -0
  49. data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/virtual/helpers.ts +461 -0
  50. data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/virtual/index.ts +3 -0
  51. data/lib/clapton/javascripts/node_modules/diff-dom/src/index.ts +2 -0
  52. data/lib/clapton/javascripts/node_modules/diff-dom/tsconfig.json +103 -0
  53. data/lib/clapton/javascripts/rollup.config.mjs +17 -2
  54. data/lib/clapton/javascripts/src/actions/initialize-actions.ts +6 -3
  55. data/lib/clapton/javascripts/src/channel/clapton-channel.js +6 -3
  56. data/lib/clapton/javascripts/src/client.ts +15 -15
  57. data/lib/clapton/javascripts/src/components-for-test.ts +29 -0
  58. data/lib/clapton/javascripts/src/components.ts +4 -1
  59. data/lib/clapton/javascripts/src/dom/update-component.ts +3 -2
  60. data/lib/clapton/javascripts/src/inputs/initialize-inputs.ts +2 -2
  61. data/lib/clapton/test_helper/base.rb +1 -1
  62. data/lib/clapton/version.rb +1 -1
  63. metadata +49 -3
  64. data/lib/clapton/javascripts/src/dom/update-component.spec.ts +0 -32
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e238016cc8650d4f218c6a542329d5fcbbe844dd68124f2464063df016f25c1f
4
- data.tar.gz: 36ae66989cf010520398499d54f007dbebb7deb6f91d37a578677eb8555bb53c
3
+ metadata.gz: 7def55e21b26dedfd8843c9ace0bf4db854abf18205de4dea7c3a203d06130f6
4
+ data.tar.gz: 743f8549cd8a901f2f1c76a4807f05ccace77d58e9665ad35c02626df555a08a
5
5
  SHA512:
6
- metadata.gz: ac72a228524042ed8748391c92076d3f05707b8f0763485ea7316f4b27e6c2a11c29643e4a6f43fc351bfffeb757dfd633afdcc710b81487f6a8754567a7d308
7
- data.tar.gz: c5f4c34dbfc32e4ad8dd0bff57f160568cc98875f9b918c90275aa8abe39aa54dc9a1dddb8ed58eb80c380b45ec3476c78a0afb9de0630e4f65d3d0bfb5a6f66
6
+ metadata.gz: b05ba6c72f46212b628cee66c18e01644e285e6380862669eb7de55174338b4b9109ebf69505d398227c85f0a19a6e55580e6cf760951fad573bc13d78c73845
7
+ data.tar.gz: 2359db5b15a7ef59f43dc61d2bcb96609858cc0a19c996e9b18288046fe739a3d68bf5868f221c97c349af8781ff8483c979199e3c1c27914f617e8912555aba
data/README.md CHANGED
@@ -12,6 +12,7 @@ Clapton is a Ruby on Rails gem for building web apps with pure Ruby only (no Jav
12
12
  - Action Cable (WebSocket)
13
13
  - [Ruby2JS](https://www.ruby2js.com/) (for compiling Ruby to JavaScript)
14
14
  - [Morphdom](https://github.com/patrick-steele-idem/morphdom)
15
+ - importmap
15
16
 
16
17
  ## Installation
17
18
 
@@ -2,7 +2,22 @@ module Clapton
2
2
  module ClaptonHelper
3
3
 
4
4
  def clapton_javascript_tag
5
- tag.script(src: "/clapton/index.js", type: "text/javascript")
5
+ all_components = Dir.glob(Rails.root.join("app", "components", "**", "*.rb"))
6
+ tags = <<~HTML
7
+ <script type="importmap">
8
+ {
9
+ "imports": {
10
+ "client": "/clapton/client.js",
11
+ "components": "/clapton/components.js",
12
+ #{ all_components.map do
13
+ |component| "\"#{File.basename(component, ".rb").camelize}\": \"/clapton/#{File.basename(component, ".rb").camelize}.js\""
14
+ end.join(",\n") }
15
+ }
16
+ }
17
+ </script>
18
+ <script type="module" src="/clapton/client.js"></script>
19
+ HTML
20
+ tags.html_safe
6
21
  end
7
22
 
8
23
  def clapton_tag
@@ -32,20 +32,24 @@ module Clapton
32
32
  end
33
33
 
34
34
  def compile_components
35
- js = File.read(File.join(__dir__, "javascripts", "dist", "components.js"))
36
- js += "\n"
37
- js += File.read(File.join(__dir__, "javascripts", "dist", "client.js"))
38
- js += "\n"
39
- js += "window.components = [];"
40
- js += "\n"
35
+ FileUtils.mkdir_p(Rails.root.join("public", "clapton")) unless Rails.root.join("public", "clapton").exist?
36
+ File.write(Rails.root.join("public", "clapton", "components.js"), File.read(File.join(__dir__, "javascripts", "dist", "components.js")))
37
+ File.write(Rails.root.join("public", "clapton", "client.js"), File.read(File.join(__dir__, "javascripts", "dist", "client.js")))
41
38
  Dir.glob(Rails.root.join("app", "components", "**", "*.rb")).each do |file|
42
- js += Ruby2JS.convert(File.read(file), preset: true)
39
+ code = File.read(file)
40
+ js = ""
41
+ js += "import { Clapton } from 'components';"
42
+ js += "\n"
43
+ code.scan(/(\w+)Component\.new/).each do |match|
44
+ js += "import { #{match[0]}Component } from '#{match[0]}Component';"
45
+ js += "\n"
46
+ end
47
+ js += Ruby2JS.convert(code, preset: true)
43
48
  js += "\n"
44
- js += "window.#{File.basename(file, ".rb").camelize} = #{File.basename(file, ".rb").camelize};"
49
+ js += "export { #{File.basename(file, ".rb").camelize} };"
45
50
  js += "\n"
51
+ File.write(Rails.root.join("public", "clapton", "#{File.basename(file, ".rb").camelize}.js"), js)
46
52
  end
47
- FileUtils.mkdir_p(Rails.root.join("public", "clapton")) unless Rails.root.join("public", "clapton").exist?
48
- File.write(Rails.root.join("public", "clapton", "index.js"), js)
49
53
  end
50
54
  end
51
55
  end
@@ -1285,11 +1285,12 @@ function getConfig(name) {
1285
1285
  }
1286
1286
  }
1287
1287
 
1288
- const updateComponent = (component, state, property, target) => {
1288
+ const updateComponent = async (component, state, property, target) => {
1289
1289
  state[property] = target.value;
1290
1290
  component.setAttribute("data-state", JSON.stringify(state));
1291
1291
  const componentName = component.getAttribute("data-component");
1292
- const ComponentClass = window[componentName];
1292
+ const module = await import(`${componentName}`);
1293
+ const ComponentClass = module[componentName];
1293
1294
  const instance = new ComponentClass(state, component.dataset.id);
1294
1295
  morphdom(component, instance.render);
1295
1296
  };
@@ -1303,8 +1304,8 @@ const initializeInputs = () => {
1303
1304
  if (!attribute || !component)
1304
1305
  return;
1305
1306
  if (element.tagName === "INPUT") {
1306
- element.addEventListener("input", (event) => {
1307
- updateComponent(component, state, attribute, event.target);
1307
+ element.addEventListener("input", async (event) => {
1308
+ await updateComponent(component, state, attribute, event.target);
1308
1309
  });
1309
1310
  }
1310
1311
  });
@@ -1313,14 +1314,17 @@ const initializeInputs = () => {
1313
1314
  const consumer = createConsumer();
1314
1315
 
1315
1316
  const claptonChannel = consumer.subscriptions.create("Clapton::ClaptonChannel", {
1316
- connected() {},
1317
+ connected() {
1318
+ window.actionCableConnected = true;
1319
+ },
1317
1320
 
1318
1321
  disconnected() {},
1319
1322
 
1320
- received(response) {
1323
+ async received(response) {
1321
1324
  const { data, errors } = response;
1322
1325
  const component = document.querySelector(`[data-id="${data.component.id}"]`);
1323
- const instance = new window[data.component.name](data.state, data.component.id, errors);
1326
+ const module = await import(`${data.component.name}`);
1327
+ const instance = new module[data.component.name](data.state, data.component.id, errors);
1324
1328
  morphdom(component, instance.render, {
1325
1329
  onBeforeElUpdated: (_fromEl, toEl) => {
1326
1330
  toEl.setAttribute("data-set-event-handler", "true");
@@ -1389,9 +1393,12 @@ const initializeActionsForElement = (element) => {
1389
1393
  if (!eventType || !componentName || !fnName)
1390
1394
  return;
1391
1395
  if (eventType === "render") {
1392
- setTimeout(() => {
1393
- handleAction(element, stateName, fnName);
1394
- }, 100);
1396
+ const interval = setInterval(() => {
1397
+ if (window.actionCableConnected === true) {
1398
+ handleAction(element, stateName, fnName);
1399
+ clearInterval(interval);
1400
+ }
1401
+ }, 10);
1395
1402
  element.setAttribute("data-render-event-handler", "true");
1396
1403
  return;
1397
1404
  }
@@ -1405,25 +1412,30 @@ const initializeActionsForElement = (element) => {
1405
1412
  });
1406
1413
  };
1407
1414
 
1408
- const initializeComponents = () => {
1415
+ const initializeComponents = async () => {
1409
1416
  const components = document.querySelector("#clapton")?.getAttribute("data-clapton") || "[]";
1410
- JSON.parse(components).forEach((component) => createAndAppendComponent(component, document.querySelector("#clapton")));
1411
- document.querySelectorAll(".clapton-component").forEach((element) => {
1417
+ const componentArray = JSON.parse(components);
1418
+ for (const component of componentArray) {
1419
+ await createAndAppendComponent(component, document.querySelector("#clapton"));
1420
+ }
1421
+ const elements = document.querySelectorAll(".clapton-component");
1422
+ for (const element of elements) {
1412
1423
  const component = JSON.parse(element.getAttribute("data-clapton") || "{}");
1413
- createAndAppendComponent(component, element);
1414
- });
1424
+ await createAndAppendComponent(component, element);
1425
+ }
1415
1426
  };
1416
- const createAndAppendComponent = (component, element) => {
1427
+ const createAndAppendComponent = async (component, element) => {
1417
1428
  const componentDom = document.createElement('div');
1418
- const instance = new window[component.component](component.state);
1429
+ const module = await import(`${component.component}`);
1430
+ const instance = new module[component.component](component.state);
1419
1431
  componentDom.innerHTML = instance.render;
1420
1432
  const firstChild = componentDom.firstChild;
1421
1433
  if (firstChild) {
1422
1434
  element.appendChild(firstChild);
1423
1435
  }
1424
1436
  };
1425
- document.addEventListener("DOMContentLoaded", () => {
1426
- initializeComponents();
1437
+ document.addEventListener("DOMContentLoaded", async () => {
1438
+ await initializeComponents();
1427
1439
  initializeActions();
1428
1440
  initializeInputs();
1429
1441
  });
@@ -0,0 +1,439 @@
1
+ var Clapton = (function (exports) {
2
+ 'use strict';
3
+
4
+ const htmlAttributes = (params) => {
5
+ const customDataAttributes = params.data || {};
6
+ const others = Object.keys(params).filter(key => key !== "data");
7
+ const flattenDataAttributes = (data, prefix = "data") => {
8
+ return Object.keys(data).reduce((acc, key) => {
9
+ const value = data[key];
10
+ if (typeof value === "object" && value !== null) {
11
+ acc.push(...flattenDataAttributes(value, `${prefix}-${key}`));
12
+ }
13
+ else {
14
+ acc.push(`${prefix}-${key}='${escapeHtml(value)}'`);
15
+ }
16
+ return acc;
17
+ }, []);
18
+ };
19
+ return [
20
+ others.map(key => {
21
+ if (key === "disabled") {
22
+ if (params[key] === false) {
23
+ return "";
24
+ }
25
+ else {
26
+ return `${key}`;
27
+ }
28
+ }
29
+ return `${key}='${escapeHtml(params[key])}'`;
30
+ }).join(" "),
31
+ flattenDataAttributes(customDataAttributes).join(" ")
32
+ ].filter(Boolean).join(" ");
33
+ };
34
+ const escapeHtml = (unsafe) => {
35
+ if (typeof unsafe !== "string") {
36
+ return "";
37
+ }
38
+ return unsafe
39
+ .replace(/&/g, "&amp;")
40
+ .replace(/</g, "&lt;")
41
+ .replace(/>/g, "&gt;")
42
+ .replace(/"/g, "&quot;")
43
+ .replace(/'/g, "&#039;");
44
+ };
45
+
46
+ class BlockQuote {
47
+ constructor(attributes = {}) {
48
+ this.children = [];
49
+ this.attributes = attributes;
50
+ }
51
+ get render() {
52
+ return `<blockquote ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</blockquote>`;
53
+ }
54
+ add(child) {
55
+ this.children.push(child);
56
+ return this;
57
+ }
58
+ }
59
+
60
+ class Box {
61
+ constructor(attributes = {}) {
62
+ this.children = [];
63
+ this.attributes = attributes;
64
+ }
65
+ add(child) {
66
+ this.children.push(child);
67
+ return this;
68
+ }
69
+ get render() {
70
+ return `<div ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</div>`;
71
+ }
72
+ add_action(eventType, stateName, fnName, options = {}) {
73
+ this.attributes["data-action"] = `${this.attributes["data-action"] || ""} ${eventType}->${stateName}#${fnName}@${options.debounce || 0}`;
74
+ return this;
75
+ }
76
+ }
77
+
78
+ class Button {
79
+ constructor(attributes = {}) {
80
+ this.attributes = attributes;
81
+ this.children = [];
82
+ }
83
+ add(child) {
84
+ this.children.push(child);
85
+ return this;
86
+ }
87
+ get render() {
88
+ return `<button ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</button>`;
89
+ }
90
+ add_action(event, klass, fn, options = {}) {
91
+ this.attributes["data-action"] = `${this.attributes["data-action"] || ""} ${event}->${klass}#${fn}@${options.debounce || 0}`;
92
+ return this;
93
+ }
94
+ }
95
+
96
+ class Checkbox {
97
+ constructor(state, attribute, attributes = {}) {
98
+ this.state = state;
99
+ this.attributes = attributes;
100
+ this.attribute = attribute;
101
+ this.attributes["data-attribute"] = attribute;
102
+ }
103
+ get render() {
104
+ return `<input type='checkbox' ${htmlAttributes(this.attributes)} value='${this.state[this.attribute] || ""}'/>`;
105
+ }
106
+ add_action(event, klass, fn, options = {}) {
107
+ this.attributes["data-action"] = `${this.attributes["data-action"] || ""} ${event}->${klass}#${fn}@${options.debounce || 0}`;
108
+ return this;
109
+ }
110
+ }
111
+
112
+ class Code {
113
+ constructor(attributes = {}) {
114
+ this.children = [];
115
+ this.attributes = attributes;
116
+ }
117
+ get render() {
118
+ return `<code ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</code>`;
119
+ }
120
+ add(child) {
121
+ this.children.push(child);
122
+ return this;
123
+ }
124
+ }
125
+
126
+ class DateTimeField {
127
+ constructor(state, attribute, attributes = {}) {
128
+ this.attributes = {};
129
+ this.state = state;
130
+ this.attribute = attribute;
131
+ this.attributes = attributes;
132
+ this.attributes["data-attribute"] = attribute;
133
+ }
134
+ get render() {
135
+ const value = this.state[this.attribute] ? this.datetime_local_value(this.state[this.attribute]) : "";
136
+ return `<input type='datetime-local' ${htmlAttributes(this.attributes)} value='${value}'/>`;
137
+ }
138
+ add_action(event, klass, fn, options = {}) {
139
+ this.attributes["data-action"] = `${this.attributes["data-action"] || ""} ${event}->${klass}#${fn}@${options.debounce || 0}`;
140
+ return this;
141
+ }
142
+ datetime_local_value(value) {
143
+ if (!value) {
144
+ return "";
145
+ }
146
+ const date = new Date(value);
147
+ date.setMinutes(date.getMinutes() - date.getTimezoneOffset());
148
+ let month = date.getMonth() + 1;
149
+ let day = date.getDate();
150
+ let hours = date.getHours();
151
+ let minutes = date.getMinutes();
152
+ if (month < 10) {
153
+ month = `0${month}`;
154
+ }
155
+ if (day < 10) {
156
+ day = `0${day}`;
157
+ }
158
+ if (hours < 10) {
159
+ hours = `0${hours}`;
160
+ }
161
+ if (minutes < 10) {
162
+ minutes = `0${minutes}`;
163
+ }
164
+ return `${date.getFullYear()}-${month}-${day}T${hours}:${minutes}`;
165
+ }
166
+ }
167
+
168
+ class Element {
169
+ constructor(type, attributes = {}) {
170
+ this.children = [];
171
+ this.type = type;
172
+ this.attributes = attributes;
173
+ }
174
+ get render() {
175
+ return `<${this.type} ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</${this.type}>`;
176
+ }
177
+ add(child) {
178
+ this.children.push(child);
179
+ return this;
180
+ }
181
+ }
182
+
183
+ class Embed {
184
+ constructor(html) {
185
+ this.html = html;
186
+ }
187
+ get render() {
188
+ return this.html;
189
+ }
190
+ }
191
+
192
+ class Emphasis {
193
+ constructor(attributes = {}) {
194
+ this.children = [];
195
+ this.attributes = attributes;
196
+ }
197
+ get render() {
198
+ return `<em ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</em>`;
199
+ }
200
+ add(child) {
201
+ this.children.push(child);
202
+ return this;
203
+ }
204
+ }
205
+
206
+ class Form {
207
+ constructor(attributes = {}) {
208
+ this.children = [];
209
+ this.attributes = attributes;
210
+ }
211
+ get render() {
212
+ return `<form ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</form>`;
213
+ }
214
+ add(child) {
215
+ this.children.push(child);
216
+ return this;
217
+ }
218
+ }
219
+
220
+ class Heading {
221
+ constructor(level, attributes = {}) {
222
+ this.children = [];
223
+ this.level = level;
224
+ this.attributes = attributes;
225
+ }
226
+ get render() {
227
+ return `<h${this.level} ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</h${this.level}>`;
228
+ }
229
+ add(child) {
230
+ this.children.push(child);
231
+ return this;
232
+ }
233
+ }
234
+
235
+ class Image {
236
+ constructor(src, alt, attributes = {}) {
237
+ this.children = [];
238
+ this.attributes = attributes;
239
+ this.src = src;
240
+ this.alt = alt;
241
+ }
242
+ get render() {
243
+ return `<img src='${this.src}' alt='${this.alt}' ${htmlAttributes(this.attributes)}/>`;
244
+ }
245
+ }
246
+
247
+ class Link {
248
+ constructor(href, attributes = {}) {
249
+ this.children = [];
250
+ this.attributes = attributes;
251
+ this.href = href;
252
+ }
253
+ get render() {
254
+ return `<a href='${this.href}' ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</a>`;
255
+ }
256
+ add(child) {
257
+ this.children.push(child);
258
+ return this;
259
+ }
260
+ }
261
+
262
+ class ListItem {
263
+ constructor(attributes = {}) {
264
+ this.children = [];
265
+ this.attributes = attributes;
266
+ }
267
+ add(child) {
268
+ this.children.push(child);
269
+ return this;
270
+ }
271
+ get render() {
272
+ return `<li ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</li>`;
273
+ }
274
+ }
275
+
276
+ class List {
277
+ constructor(attributes = {}) {
278
+ this.children = [];
279
+ this.attributes = attributes;
280
+ }
281
+ add(child) {
282
+ this.children.push(child);
283
+ return this;
284
+ }
285
+ get render() {
286
+ return `<ul ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</ul>`;
287
+ }
288
+ }
289
+
290
+ class OrderedList {
291
+ constructor(attributes = {}) {
292
+ this.children = [];
293
+ this.attributes = attributes;
294
+ }
295
+ add(child) {
296
+ this.children.push(child);
297
+ return this;
298
+ }
299
+ get render() {
300
+ return `<ol ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</ol>`;
301
+ }
302
+ }
303
+
304
+ class Paragraph {
305
+ constructor(attributes = {}) {
306
+ this.children = [];
307
+ this.attributes = attributes;
308
+ }
309
+ get render() {
310
+ return `<p ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</p>`;
311
+ }
312
+ add(child) {
313
+ this.children.push(child);
314
+ return this;
315
+ }
316
+ }
317
+
318
+ class Quote {
319
+ constructor(attributes = {}) {
320
+ this.children = [];
321
+ this.attributes = attributes;
322
+ }
323
+ get render() {
324
+ return `<q ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</q>`;
325
+ }
326
+ add(child) {
327
+ this.children.push(child);
328
+ return this;
329
+ }
330
+ }
331
+
332
+ class RadioButton {
333
+ constructor(state, attribute, attributes = {}) {
334
+ this.state = state;
335
+ this.attributes = attributes;
336
+ this.attribute = attribute;
337
+ this.attributes["data-attribute"] = attribute;
338
+ }
339
+ get render() {
340
+ return `<input type='radio' ${htmlAttributes(this.attributes)} value='${this.state[this.attribute] || ""}'/>`;
341
+ }
342
+ add_action(event, klass, fn, options = {}) {
343
+ this.attributes["data-action"] = `${this.attributes["data-action"] || ""} ${event}->${klass}#${fn}@${options.debounce || 0}`;
344
+ return this;
345
+ }
346
+ }
347
+
348
+ class Select {
349
+ constructor(options = [], state, attribute, attributes = {}) {
350
+ this.children = [];
351
+ this.options = options;
352
+ this.state = state;
353
+ this.attribute = attribute;
354
+ this.attributes = attributes;
355
+ }
356
+ get render() {
357
+ return `<select ${htmlAttributes(this.attributes)}>${this.options.map(option => `<option value='${option.value}'${option.value === this.state[this.attribute] ? " selected" : ""}>${option.text}</option>`).join("")}${this.children.map(child => child.render).join("")}</select>`;
358
+ }
359
+ }
360
+
361
+ class Span {
362
+ constructor(attributes = {}) {
363
+ this.children = [];
364
+ this.attributes = attributes;
365
+ }
366
+ get render() {
367
+ return `<span ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</span>`;
368
+ }
369
+ add(child) {
370
+ this.children.push(child);
371
+ return this;
372
+ }
373
+ }
374
+
375
+ class Component {
376
+ constructor(state = {}, id = Math.random().toString(36).substring(2, 10), errors = []) {
377
+ this._state = state;
378
+ this.id = id;
379
+ this._errors = errors;
380
+ this._root = new Box({ data: { component: this.constructor.name, state: JSON.stringify(this._state), id: this.id, errors: this._errors } });
381
+ }
382
+ get render() {
383
+ return this._root.render;
384
+ }
385
+ }
386
+
387
+ class TextField {
388
+ constructor(state, attribute, attributes = {}) {
389
+ this.state = state;
390
+ this.attributes = attributes;
391
+ this.attribute = attribute;
392
+ this.attributes["data-attribute"] = attribute;
393
+ }
394
+ get render() {
395
+ return `<input type='text' ${htmlAttributes(this.attributes)} value='${this.state[this.attribute] || ""}'/>`;
396
+ }
397
+ add_action(event, klass, fn, options = {}) {
398
+ this.attributes["data-action"] = `${this.attributes["data-action"] || ""} ${event}->${klass}#${fn}@${options.debounce || 0}`;
399
+ return this;
400
+ }
401
+ }
402
+
403
+ class Text {
404
+ constructor(value) {
405
+ this.value = value;
406
+ }
407
+ get render() {
408
+ return this.value;
409
+ }
410
+ }
411
+
412
+ exports.BlockQuote = BlockQuote;
413
+ exports.Box = Box;
414
+ exports.Button = Button;
415
+ exports.Checkbox = Checkbox;
416
+ exports.Code = Code;
417
+ exports.Component = Component;
418
+ exports.DateTimeField = DateTimeField;
419
+ exports.Element = Element;
420
+ exports.Embed = Embed;
421
+ exports.Emphasis = Emphasis;
422
+ exports.Form = Form;
423
+ exports.Heading = Heading;
424
+ exports.Image = Image;
425
+ exports.Link = Link;
426
+ exports.List = List;
427
+ exports.ListItem = ListItem;
428
+ exports.OrderedList = OrderedList;
429
+ exports.Paragraph = Paragraph;
430
+ exports.Quote = Quote;
431
+ exports.RadioButton = RadioButton;
432
+ exports.Select = Select;
433
+ exports.Span = Span;
434
+ exports.Text = Text;
435
+ exports.TextField = TextField;
436
+
437
+ return exports;
438
+
439
+ })({});