clapton 0.0.12 → 0.0.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +33 -0
  3. data/app/helpers/clapton/clapton_helper.rb +16 -1
  4. data/lib/clapton/engine.rb +16 -10
  5. data/lib/clapton/javascripts/dist/client.js +65 -39
  6. data/lib/clapton/javascripts/dist/components-for-test.js +439 -0
  7. data/lib/clapton/javascripts/dist/components.js +357 -369
  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/handle-action.ts +6 -1
  55. data/lib/clapton/javascripts/src/actions/initialize-actions.ts +11 -0
  56. data/lib/clapton/javascripts/src/channel/clapton-channel.js +8 -4
  57. data/lib/clapton/javascripts/src/client.ts +15 -18
  58. data/lib/clapton/javascripts/src/components/box.ts +5 -0
  59. data/lib/clapton/javascripts/src/components/embed.spec.ts +8 -0
  60. data/lib/clapton/javascripts/src/components/embed.ts +11 -0
  61. data/lib/clapton/javascripts/src/components-for-test.ts +29 -0
  62. data/lib/clapton/javascripts/src/components.ts +5 -1
  63. data/lib/clapton/javascripts/src/dom/update-component.ts +3 -2
  64. data/lib/clapton/javascripts/src/inputs/initialize-inputs.ts +3 -3
  65. data/lib/clapton/test_helper/base.rb +1 -1
  66. data/lib/clapton/version.rb +2 -1
  67. metadata +51 -3
  68. data/lib/clapton/javascripts/src/dom/update-component.spec.ts +0 -32
@@ -0,0 +1,461 @@
1
+ import {
2
+ diffNodeType,
3
+ elementDiffNodeType,
4
+ elementNodeType,
5
+ nodeType,
6
+ subsetType,
7
+ textDiffNodeType,
8
+ textNodeType,
9
+ } from "../types"
10
+ import { Diff } from "../helpers"
11
+ const elementDescriptors = (el: diffNodeType) => {
12
+ const output = []
13
+ output.push(el.nodeName)
14
+ if (el.nodeName !== "#text" && el.nodeName !== "#comment") {
15
+ el = el as elementDiffNodeType
16
+ if (el.attributes) {
17
+ if (el.attributes["class"]) {
18
+ output.push(
19
+ `${el.nodeName}.${el.attributes["class"].replace(
20
+ / /g,
21
+ ".",
22
+ )}`,
23
+ )
24
+ }
25
+ if (el.attributes.id) {
26
+ output.push(`${el.nodeName}#${el.attributes.id}`)
27
+ }
28
+ }
29
+ }
30
+ return output
31
+ }
32
+
33
+ const findUniqueDescriptors = (li: diffNodeType[]) => {
34
+ const uniqueDescriptors = {}
35
+ const duplicateDescriptors = {}
36
+
37
+ li.forEach((node: nodeType) => {
38
+ elementDescriptors(node).forEach((descriptor) => {
39
+ const inUnique = descriptor in uniqueDescriptors
40
+ const inDupes = descriptor in duplicateDescriptors
41
+ if (!inUnique && !inDupes) {
42
+ uniqueDescriptors[descriptor] = true
43
+ } else if (inUnique) {
44
+ delete uniqueDescriptors[descriptor]
45
+ duplicateDescriptors[descriptor] = true
46
+ }
47
+ })
48
+ })
49
+
50
+ return uniqueDescriptors
51
+ }
52
+
53
+ export const uniqueInBoth = (l1: diffNodeType[], l2: diffNodeType[]) => {
54
+ const l1Unique = findUniqueDescriptors(l1)
55
+ const l2Unique = findUniqueDescriptors(l2)
56
+ const inBoth = {}
57
+
58
+ Object.keys(l1Unique).forEach((key) => {
59
+ if (l2Unique[key]) {
60
+ inBoth[key] = true
61
+ }
62
+ })
63
+
64
+ return inBoth
65
+ }
66
+
67
+ export const removeDone = (tree: elementDiffNodeType) => {
68
+ delete tree.outerDone
69
+ delete tree.innerDone
70
+ delete tree.valueDone
71
+ if (tree.childNodes) {
72
+ return tree.childNodes.every(removeDone)
73
+ } else {
74
+ return true
75
+ }
76
+ }
77
+
78
+ export const cleanNode = (diffNode: diffNodeType) => {
79
+ if (Object.prototype.hasOwnProperty.call(diffNode, "data")) {
80
+ const textNode: textNodeType = {
81
+ nodeName: diffNode.nodeName === "#text" ? "#text" : "#comment",
82
+ data: (diffNode as textDiffNodeType).data,
83
+ }
84
+ return textNode
85
+ } else {
86
+ const elementNode: elementNodeType = {
87
+ nodeName: diffNode.nodeName,
88
+ }
89
+ diffNode = diffNode as elementDiffNodeType
90
+ if (Object.prototype.hasOwnProperty.call(diffNode, "attributes")) {
91
+ elementNode.attributes = { ...diffNode.attributes }
92
+ }
93
+ if (Object.prototype.hasOwnProperty.call(diffNode, "checked")) {
94
+ elementNode.checked = diffNode.checked
95
+ }
96
+ if (Object.prototype.hasOwnProperty.call(diffNode, "value")) {
97
+ elementNode.value = diffNode.value
98
+ }
99
+ if (Object.prototype.hasOwnProperty.call(diffNode, "selected")) {
100
+ elementNode.selected = diffNode.selected
101
+ }
102
+ if (Object.prototype.hasOwnProperty.call(diffNode, "childNodes")) {
103
+ elementNode.childNodes = diffNode.childNodes.map((diffChildNode) =>
104
+ cleanNode(diffChildNode),
105
+ )
106
+ }
107
+ return elementNode
108
+ }
109
+ }
110
+
111
+ export const isEqual = (e1: diffNodeType, e2: diffNodeType) => {
112
+ if (
113
+ !["nodeName", "value", "checked", "selected", "data"].every(
114
+ (element) => {
115
+ if (e1[element] !== e2[element]) {
116
+ return false
117
+ }
118
+ return true
119
+ },
120
+ )
121
+ ) {
122
+ return false
123
+ }
124
+ if (Object.prototype.hasOwnProperty.call(e1, "data")) {
125
+ // Comment or Text
126
+ return true
127
+ }
128
+ e1 = e1 as elementDiffNodeType
129
+ e2 = e2 as elementDiffNodeType
130
+ if (Boolean(e1.attributes) !== Boolean(e2.attributes)) {
131
+ return false
132
+ }
133
+
134
+ if (Boolean(e1.childNodes) !== Boolean(e2.childNodes)) {
135
+ return false
136
+ }
137
+ if (e1.attributes) {
138
+ const e1Attributes = Object.keys(e1.attributes)
139
+ const e2Attributes = Object.keys(e2.attributes)
140
+
141
+ if (e1Attributes.length !== e2Attributes.length) {
142
+ return false
143
+ }
144
+ if (
145
+ !e1Attributes.every((attribute) => {
146
+ if (
147
+ (e1 as elementDiffNodeType).attributes[attribute] !==
148
+ (e2 as elementDiffNodeType).attributes[attribute]
149
+ ) {
150
+ return false
151
+ }
152
+ return true
153
+ })
154
+ ) {
155
+ return false
156
+ }
157
+ }
158
+ if (e1.childNodes) {
159
+ if (e1.childNodes.length !== e2.childNodes.length) {
160
+ return false
161
+ }
162
+ if (
163
+ !e1.childNodes.every((childNode: nodeType, index: number) =>
164
+ isEqual(childNode, e2.childNodes[index]),
165
+ )
166
+ ) {
167
+ return false
168
+ }
169
+ }
170
+
171
+ return true
172
+ }
173
+
174
+ export const roughlyEqual = (
175
+ e1: diffNodeType,
176
+ e2: diffNodeType,
177
+ uniqueDescriptors: { [key: string]: boolean },
178
+ sameSiblings: boolean,
179
+ preventRecursion = false,
180
+ ) => {
181
+ if (!e1 || !e2) {
182
+ return false
183
+ }
184
+
185
+ if (e1.nodeName !== e2.nodeName) {
186
+ return false
187
+ }
188
+
189
+ if (["#text", "#comment"].includes(e1.nodeName)) {
190
+ // Note that we initially don't care what the text content of a node is,
191
+ // the mere fact that it's the same tag and "has text" means it's roughly
192
+ // equal, and then we can find out the true text difference later.
193
+ return preventRecursion
194
+ ? true
195
+ : (e1 as textDiffNodeType).data === (e2 as textDiffNodeType).data
196
+ }
197
+
198
+ e1 = e1 as elementDiffNodeType
199
+ e2 = e2 as elementDiffNodeType
200
+
201
+ if (e1.nodeName in uniqueDescriptors) {
202
+ return true
203
+ }
204
+
205
+ if (e1.attributes && e2.attributes) {
206
+ if (e1.attributes.id) {
207
+ if (e1.attributes.id !== e2.attributes.id) {
208
+ return false
209
+ } else {
210
+ const idDescriptor = `${e1.nodeName}#${e1.attributes.id}`
211
+ if (idDescriptor in uniqueDescriptors) {
212
+ return true
213
+ }
214
+ }
215
+ }
216
+ if (
217
+ e1.attributes["class"] &&
218
+ e1.attributes["class"] === e2.attributes["class"]
219
+ ) {
220
+ const classDescriptor = `${e1.nodeName}.${e1.attributes[
221
+ "class"
222
+ ].replace(/ /g, ".")}`
223
+ if (classDescriptor in uniqueDescriptors) {
224
+ return true
225
+ }
226
+ }
227
+ }
228
+
229
+ if (sameSiblings) {
230
+ return true
231
+ }
232
+
233
+ const nodeList1 = e1.childNodes ? e1.childNodes.slice().reverse() : []
234
+ const nodeList2 = e2.childNodes ? e2.childNodes.slice().reverse() : []
235
+
236
+ if (nodeList1.length !== nodeList2.length) {
237
+ return false
238
+ }
239
+
240
+ if (preventRecursion) {
241
+ return nodeList1.every(
242
+ (element: nodeType, index: number) =>
243
+ element.nodeName === nodeList2[index].nodeName,
244
+ )
245
+ } else {
246
+ // note: we only allow one level of recursion at any depth. If 'preventRecursion'
247
+ // was not set, we must explicitly force it to true for child iterations.
248
+ const childUniqueDescriptors = uniqueInBoth(nodeList1, nodeList2)
249
+ return nodeList1.every((element: nodeType, index: number) =>
250
+ roughlyEqual(
251
+ element,
252
+ nodeList2[index],
253
+ childUniqueDescriptors,
254
+ true,
255
+ true,
256
+ ),
257
+ )
258
+ }
259
+ }
260
+
261
+ /**
262
+ * based on https://en.wikibooks.org/wiki/Algorithm_implementation/Strings/Longest_common_substring#JavaScript
263
+ */
264
+ const findCommonSubsets = (
265
+ c1: diffNodeType[],
266
+ c2: diffNodeType[],
267
+ marked1: boolean[],
268
+ marked2: boolean[],
269
+ ) => {
270
+ let lcsSize = 0
271
+ let index: number[] = []
272
+ const c1Length = c1.length
273
+ const c2Length = c2.length
274
+
275
+ const // set up the matching table
276
+ matches = [...new Array(c1Length + 1)].map(() => [])
277
+
278
+ const uniqueDescriptors = uniqueInBoth(c1, c2)
279
+
280
+ let // If all of the elements are the same tag, id and class, then we can
281
+ // consider them roughly the same even if they have a different number of
282
+ // children. This will reduce removing and re-adding similar elements.
283
+ subsetsSame = c1Length === c2Length
284
+
285
+ if (subsetsSame) {
286
+ c1.some((element: nodeType, i: number) => {
287
+ const c1Desc = elementDescriptors(element)
288
+ const c2Desc = elementDescriptors(c2[i])
289
+ if (c1Desc.length !== c2Desc.length) {
290
+ subsetsSame = false
291
+ return true
292
+ }
293
+ c1Desc.some((description, i) => {
294
+ if (description !== c2Desc[i]) {
295
+ subsetsSame = false
296
+ return true
297
+ }
298
+ })
299
+ if (!subsetsSame) {
300
+ return true
301
+ }
302
+ })
303
+ }
304
+
305
+ // fill the matches with distance values
306
+ for (let c1Index = 0; c1Index < c1Length; c1Index++) {
307
+ const c1Element = c1[c1Index]
308
+ for (let c2Index = 0; c2Index < c2Length; c2Index++) {
309
+ const c2Element = c2[c2Index]
310
+ if (
311
+ !marked1[c1Index] &&
312
+ !marked2[c2Index] &&
313
+ roughlyEqual(
314
+ c1Element,
315
+ c2Element,
316
+ uniqueDescriptors,
317
+ subsetsSame,
318
+ )
319
+ ) {
320
+ matches[c1Index + 1][c2Index + 1] = matches[c1Index][c2Index]
321
+ ? matches[c1Index][c2Index] + 1
322
+ : 1
323
+ if (matches[c1Index + 1][c2Index + 1] >= lcsSize) {
324
+ lcsSize = matches[c1Index + 1][c2Index + 1]
325
+ index = [c1Index + 1, c2Index + 1]
326
+ }
327
+ } else {
328
+ matches[c1Index + 1][c2Index + 1] = 0
329
+ }
330
+ }
331
+ }
332
+
333
+ if (lcsSize === 0) {
334
+ return false
335
+ }
336
+
337
+ return {
338
+ oldValue: index[0] - lcsSize,
339
+ newValue: index[1] - lcsSize,
340
+ length: lcsSize,
341
+ }
342
+ }
343
+
344
+ const makeBooleanArray = (n: number, v: boolean) =>
345
+ [...new Array(n)].map(() => v)
346
+
347
+ /**
348
+ * Generate arrays that indicate which node belongs to which subset,
349
+ * or whether it's actually an orphan node, existing in only one
350
+ * of the two trees, rather than somewhere in both.
351
+ *
352
+ * So if t1 = <img><canvas><br>, t2 = <canvas><br><img>.
353
+ * The longest subset is "<canvas><br>" (length 2), so it will group 0.
354
+ * The second longest is "<img>" (length 1), so it will be group 1.
355
+ * gaps1 will therefore be [1,0,0] and gaps2 [0,0,1].
356
+ *
357
+ * If an element is not part of any group, it will stay being 'true', which
358
+ * is the initial value. For example:
359
+ * t1 = <img><p></p><br><canvas>, t2 = <b></b><br><canvas><img>
360
+ *
361
+ * The "<p></p>" and "<b></b>" do only show up in one of the two and will
362
+ * therefore be marked by "true". The remaining parts are parts of the
363
+ * groups 0 and 1:
364
+ * gaps1 = [1, true, 0, 0], gaps2 = [true, 0, 0, 1]
365
+ *
366
+ */
367
+ export const getGapInformation = (
368
+ t1: elementDiffNodeType,
369
+ t2: elementDiffNodeType,
370
+ stable: subsetType[],
371
+ ) => {
372
+ const gaps1: (true | number)[] = t1.childNodes
373
+ ? (makeBooleanArray(t1.childNodes.length, true) as true[])
374
+ : []
375
+ const gaps2: (true | number)[] = t2.childNodes
376
+ ? (makeBooleanArray(t2.childNodes.length, true) as true[])
377
+ : []
378
+ let group = 0
379
+
380
+ // give elements from the same subset the same group number
381
+ stable.forEach((subset: subsetType) => {
382
+ const endOld = subset.oldValue + subset.length
383
+ const endNew = subset.newValue + subset.length
384
+
385
+ for (let j = subset.oldValue; j < endOld; j += 1) {
386
+ gaps1[j] = group
387
+ }
388
+ for (let j = subset.newValue; j < endNew; j += 1) {
389
+ gaps2[j] = group
390
+ }
391
+ group += 1
392
+ })
393
+
394
+ return {
395
+ gaps1,
396
+ gaps2,
397
+ }
398
+ }
399
+
400
+ /**
401
+ * Find all matching subsets, based on immediate child differences only.
402
+ */
403
+ const markBoth = (marked1, marked2, subset: subsetType, i: number) => {
404
+ marked1[subset.oldValue + i] = true
405
+ marked2[subset.newValue + i] = true
406
+ }
407
+
408
+ export const markSubTrees = (
409
+ oldTree: elementDiffNodeType,
410
+ newTree: elementDiffNodeType,
411
+ ) => {
412
+ // note: the child lists are views, and so update as we update old/newTree
413
+ const oldChildren = oldTree.childNodes ? oldTree.childNodes : []
414
+
415
+ const newChildren = newTree.childNodes ? newTree.childNodes : []
416
+ const marked1 = makeBooleanArray(oldChildren.length, false)
417
+ const marked2 = makeBooleanArray(newChildren.length, false)
418
+ const subsets = []
419
+
420
+ const returnIndex = function () {
421
+ return arguments[1]
422
+ }
423
+
424
+ let foundAllSubsets = false
425
+
426
+ while (!foundAllSubsets) {
427
+ const subset = findCommonSubsets(
428
+ oldChildren,
429
+ newChildren,
430
+ marked1,
431
+ marked2,
432
+ )
433
+ if (subset) {
434
+ subsets.push(subset)
435
+ const subsetArray = [...new Array(subset.length)].map(returnIndex)
436
+ subsetArray.forEach((item) =>
437
+ markBoth(marked1, marked2, subset, item),
438
+ )
439
+ } else {
440
+ foundAllSubsets = true
441
+ }
442
+ }
443
+
444
+ oldTree.subsets = subsets
445
+ oldTree.subsetsAge = 100
446
+ return subsets
447
+ }
448
+
449
+ export class DiffTracker {
450
+ list: Diff[]
451
+ constructor() {
452
+ this.list = []
453
+ }
454
+
455
+ add(diffs: Diff[]) {
456
+ this.list.push(...diffs)
457
+ }
458
+ forEach(fn: (Diff) => void) {
459
+ this.list.forEach((li: Diff) => fn(li))
460
+ }
461
+ }
@@ -0,0 +1,3 @@
1
+ export { DiffFinder } from "./diff"
2
+ export { nodeToObj } from "./fromDOM"
3
+ export { stringToObj } from "./fromString"
@@ -0,0 +1,2 @@
1
+ export { DiffDOM, nodeToObj, stringToObj } from "./diffDOM/index"
2
+ export { TraceLogger } from "./TraceLogger"
@@ -0,0 +1,103 @@
1
+ {
2
+ "compilerOptions": {
3
+ /* Visit https://aka.ms/tsconfig to read more about this file */
4
+
5
+ /* Projects */
6
+ // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
7
+ // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
8
+ // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
9
+ // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
10
+ // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
11
+ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
12
+
13
+ /* Language and Environment */
14
+ //"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
15
+ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
16
+ // "jsx": "preserve", /* Specify what JSX code is generated. */
17
+ // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
18
+ // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
19
+ // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
20
+ // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
21
+ // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
22
+ // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
23
+ // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
24
+ // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
25
+ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
26
+
27
+ /* Modules */
28
+ //"module": "commonjs", /* Specify what module code is generated. */
29
+ // "rootDir": "./", /* Specify the root folder within your source files. */
30
+ // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
31
+ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
32
+ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
33
+ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
34
+ // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
35
+ // "types": [], /* Specify type package names to be included without being referenced in a source file. */
36
+ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
37
+ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
38
+ // "resolveJsonModule": true, /* Enable importing .json files. */
39
+ // "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
40
+
41
+ /* JavaScript Support */
42
+ // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
43
+ // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
44
+ // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
45
+
46
+ /* Emit */
47
+ "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
48
+ // "declarationMap": true, /* Create sourcemaps for d.ts files. */
49
+ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
50
+ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */
51
+ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
52
+ // "outDir": "./", /* Specify an output folder for all emitted files. */
53
+ // "removeComments": true, /* Disable emitting comments. */
54
+ // "noEmit": true, /* Disable emitting files from a compilation. */
55
+ // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
56
+ // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
57
+ // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
58
+ // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
59
+ // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
60
+ // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
61
+ // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
62
+ // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
63
+ // "newLine": "crlf", /* Set the newline character for emitting files. */
64
+ // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
65
+ // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
66
+ // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
67
+ // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
68
+ "declarationDir": "dts", /* Specify the output directory for generated declaration files. */
69
+ // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
70
+
71
+ /* Interop Constraints */
72
+ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
73
+ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
74
+ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
75
+ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
76
+ "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
77
+
78
+ /* Type Checking */
79
+ //"strict": true, /* Enable all strict type-checking options. */
80
+ // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
81
+ // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
82
+ // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
83
+ // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
84
+ // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
85
+ // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
86
+ // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
87
+ // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
88
+ // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
89
+ // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
90
+ // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
91
+ // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
92
+ // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
93
+ // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
94
+ // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
95
+ // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
96
+ // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
97
+ // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
98
+
99
+ /* Completeness */
100
+ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
101
+ "skipLibCheck": true /* Skip type checking all .d.ts files. */
102
+ }
103
+ }
@@ -7,8 +7,23 @@ export default [
7
7
  input: 'src/components.ts',
8
8
  output: {
9
9
  file: 'dist/components.js',
10
- format: 'iife',
11
- name: 'Clapton'
10
+ format: 'esm'
11
+ },
12
+ plugins: [
13
+ resolve(),
14
+ commonjs(),
15
+ typescript({
16
+ tsconfig: './tsconfig.json',
17
+ sourceMap: false
18
+ })
19
+ ]
20
+ },
21
+ {
22
+ input: 'src/components-for-test.ts',
23
+ output: {
24
+ file: 'dist/components-for-test.js',
25
+ format: "iife",
26
+ name: "Clapton"
12
27
  },
13
28
  plugins: [
14
29
  resolve(),
@@ -1,7 +1,12 @@
1
1
  import { claptonChannel } from "../channel/clapton-channel";
2
2
 
3
3
  export const handleAction = async (target: HTMLElement, stateName: string, fn: string) => {
4
- const targetComponent = target.closest(`[data-component="${stateName.replace("State", "Component")}"]`) as HTMLElement;
4
+ let targetComponent = target;
5
+ if (target.dataset.component === stateName.replace("State", "Component")) {
6
+ targetComponent = target
7
+ } else {
8
+ targetComponent = target.closest(`[data-component="${stateName.replace("State", "Component")}"]`) as HTMLElement;
9
+ }
5
10
  if (!targetComponent) return;
6
11
  const component = target.closest(`[data-component]`) as HTMLElement;
7
12
  const attribute = target.getAttribute("data-attribute");
@@ -14,6 +14,17 @@ const initializeActionsForElement = (element: HTMLElement) => {
14
14
  const { eventType, componentName, stateName, fnName, bounceTime } = splitActionAttribute(action);
15
15
  if (!eventType || !componentName || !fnName) return;
16
16
 
17
+ if (eventType === "render") {
18
+ const interval = setInterval(() => {
19
+ if ((window as any).actionCableConnected === true) {
20
+ handleAction(element, stateName, fnName);
21
+ clearInterval(interval);
22
+ }
23
+ }, 10);
24
+ element.setAttribute("data-render-event-handler", "true");
25
+ return;
26
+ }
27
+
17
28
  if (bounceTime > 0) {
18
29
  element.addEventListener(eventType, debounce((event) =>
19
30
  handleAction(event.target as HTMLElement, stateName, fnName), bounceTime)
@@ -1,24 +1,28 @@
1
1
  import morphdom from "morphdom"
2
2
  import { createConsumer } from "@rails/actioncable"
3
3
  import { initializeActions } from "../actions/initialize-actions.ts"
4
-
4
+ import { initializeInputs } from "../inputs/initialize-inputs.ts"
5
5
  const consumer = createConsumer()
6
6
 
7
7
  export const claptonChannel = consumer.subscriptions.create("Clapton::ClaptonChannel", {
8
- connected() {},
8
+ connected() {
9
+ window.actionCableConnected = true;
10
+ },
9
11
 
10
12
  disconnected() {},
11
13
 
12
- received(response) {
14
+ async received(response) {
13
15
  const { data, errors } = response;
14
16
  const component = document.querySelector(`[data-id="${data.component.id}"]`)
15
- const instance = new window[data.component.name](data.state, data.component.id, errors);
17
+ const module = await import(`${data.component.name}`);
18
+ const instance = new module[data.component.name](data.state, data.component.id, errors);
16
19
  morphdom(component, instance.render, {
17
20
  onBeforeElUpdated: (_fromEl, toEl) => {
18
21
  toEl.setAttribute("data-set-event-handler", "true");
19
22
  return true;
20
23
  }
21
24
  });
25
+
22
26
  initializeInputs();
23
27
  initializeActions();
24
28
  }