clapton 0.0.22 → 0.0.24

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ba556f54f55566ad5502aff210ab368c040d332a62313411377314b99a507ab0
4
- data.tar.gz: f8a71c1947ea6eb6544f637f53641ce87fc904543efadac7e30c244b6d1e8c85
3
+ metadata.gz: f15ceb3c247b4a620ea3508dc66511a2d7beb4f2e1bc32a24dd8e69bd0d70332
4
+ data.tar.gz: 329b1b8107968efdcce936a4f71deb904e5a609d846ca245d8c90cc7040ba144
5
5
  SHA512:
6
- metadata.gz: a8b32c159a66aa00df226c792f99e3d8a2ca96706a6189f3f442fec764eefe9f4a90e66f7f4c050a6a3c84212f46469e5f232c219b10999ebe543affb659a3f2
7
- data.tar.gz: eb01a40f84c3e8437be75b05d716f9702c0ed15666041015d06f74449f317f144558bd4c798ac94710008e63bf4c7a062556c14dcfbb9b3ee693217e905c86e0
6
+ metadata.gz: 24846c65443543d58f3e8f6f6018b5ace3af64166be9b9e2bde2bd0aa5056c7bd2f148ba43b7171a7e43756d0eb485bebaad9fca5ad57a913b038bead70baf8e
7
+ data.tar.gz: 60aaeaae14b6277cd5323f5cf1e36201e94f2887e4c1655838ce37a13a58282de3b05c729e2a8212b2e1705f7e4e538f0b2f2b78e57b872f089d9956acc58b57
data/README.md CHANGED
@@ -177,6 +177,30 @@ class TaskListComponent < Clapton::Component
177
177
  end
178
178
  ```
179
179
 
180
+ ### Effect
181
+
182
+ The `effect` method is a method that is triggered when the state is changed.
183
+
184
+ ```ruby
185
+ # app/components/task_list_component.rb
186
+ class TaskListComponent < Clapton::Component
187
+ effect [:tasks] do |state|
188
+ puts state[:tasks]
189
+ end
190
+ end
191
+ ```
192
+
193
+ If dependencies are not specified, the effect will be triggered on the first render.
194
+
195
+ ```ruby
196
+ # app/components/video_player_component.rb
197
+ class VideoPlayerComponent < Clapton::Component
198
+ effect [] do
199
+ puts "First render"
200
+ end
201
+ end
202
+ ```
203
+
180
204
  ### Preset Components Classes
181
205
 
182
206
  ```ruby
@@ -349,6 +373,15 @@ module ApplicationCable
349
373
  end
350
374
  ```
351
375
 
376
+ ### Using with importmap-rails
377
+
378
+ Use `clapton_javascript_tag` instead of `javascript_importmap_tags`.
379
+
380
+ ```diff
381
+ - <%= javascript_importmap_tags %>
382
+ + <%= clapton_javascript_tag %>
383
+ ```
384
+
352
385
  ### Events
353
386
 
354
387
  #### clapton:render
@@ -1,11 +1,10 @@
1
1
  module Clapton
2
2
  module ClaptonHelper
3
3
 
4
- def clapton_javascript_tag
4
+ def clapton_javascript_tag(entry_point = "application", importmap: nil)
5
5
  all_components = Dir.glob(Rails.root.join("app", "components", "**", "*.rb"))
6
- tags = <<~HTML
7
- <script type="importmap">
8
- {
6
+ clapton_json = JSON.parse <<~JSON
7
+ {
9
8
  "imports": {
10
9
  "client": "/clapton/client.js",
11
10
  "components": "/clapton/components.js",
@@ -15,10 +14,25 @@ module Clapton
15
14
  end.join(",\n") }
16
15
  }
17
16
  }
18
- </script>
19
- <script type="module" src="/clapton/client.js"></script>
20
- HTML
21
- tags.html_safe
17
+ JSON
18
+ if defined?(javascript_importmap_tags)
19
+ importmap ||= Rails.application.importmap
20
+ json = { imports: JSON.parse(importmap.to_json(resolver: self))["imports"].merge(clapton_json["imports"]) }
21
+ safe_join [
22
+ javascript_inline_importmap_tag(json.to_json),
23
+ javascript_importmap_module_preload_tags(importmap, entry_point:),
24
+ javascript_import_module_tag(entry_point),
25
+ tag.script(type: "module", src: "/clapton/client.js"),
26
+ ], "\n"
27
+ else
28
+ html = <<~HTML
29
+ <script type="importmap">
30
+ #{clapton_json.to_json}
31
+ </script>
32
+ <script type="module" src="/clapton/client.js"></script>
33
+ HTML
34
+ html.html_safe
35
+ end
22
36
  end
23
37
 
24
38
  def clapton_tag
@@ -405,7 +405,28 @@ var c = (function () {
405
405
  }
406
406
  return root.renderWrapper;
407
407
  }
408
+ static effect(dependencies, callback) {
409
+ this._effects.push({ dependencies, callback });
410
+ }
411
+ get effects() {
412
+ return this.constructor._effects;
413
+ }
414
+ runEffects() {
415
+ this.effects.forEach((effect) => {
416
+ if (effect.dependencies.some((dependency) => this._state[dependency] !== undefined)) {
417
+ effect.callback(this._state);
418
+ }
419
+ });
420
+ }
421
+ runEffectOnFirstRender() {
422
+ this.effects.forEach((effect) => {
423
+ if (effect.dependencies.length === 0) {
424
+ effect.callback(this._state);
425
+ }
426
+ });
427
+ }
408
428
  }
429
+ Component._effects = [];
409
430
 
410
431
  class TextField {
411
432
  constructor(state, attribute, attributes = {}) {
@@ -402,7 +402,28 @@ class Component {
402
402
  }
403
403
  return root.renderWrapper;
404
404
  }
405
+ static effect(dependencies, callback) {
406
+ this._effects.push({ dependencies, callback });
407
+ }
408
+ get effects() {
409
+ return this.constructor._effects;
410
+ }
411
+ runEffects() {
412
+ this.effects.forEach((effect) => {
413
+ if (effect.dependencies.some((dependency) => this._state[dependency] !== undefined)) {
414
+ effect.callback(this._state);
415
+ }
416
+ });
417
+ }
418
+ runEffectOnFirstRender() {
419
+ this.effects.forEach((effect) => {
420
+ if (effect.dependencies.length === 0) {
421
+ effect.callback(this._state);
422
+ }
423
+ });
424
+ }
405
425
  }
426
+ Component._effects = [];
406
427
 
407
428
  class TextField {
408
429
  constructor(state, attribute, attributes = {}) {
@@ -1292,6 +1292,7 @@ const updateComponent = async (component, state, property, target) => {
1292
1292
  const ComponentClass = module[componentName];
1293
1293
  const instance = new ComponentClass(state, component.dataset.id);
1294
1294
  morphdom(component, instance.renderWrapper);
1295
+ instance.runEffects();
1295
1296
  };
1296
1297
 
1297
1298
  const initializeInputs = () => {
@@ -1333,6 +1334,7 @@ const claptonChannel = consumer.subscriptions.create("Clapton::ClaptonChannel",
1333
1334
 
1334
1335
  initializeInputs();
1335
1336
  initializeActions();
1337
+ instance.runEffects();
1336
1338
  }
1337
1339
  });
1338
1340
 
@@ -1440,6 +1442,7 @@ const createAndAppendComponent = async (component, element) => {
1440
1442
  element.outerHTML = firstChild.outerHTML;
1441
1443
  }
1442
1444
  }
1445
+ instance.runEffects();
1443
1446
  };
1444
1447
  document.addEventListener("DOMContentLoaded", async () => {
1445
1448
  await initializeComponents();
@@ -1448,6 +1451,13 @@ document.addEventListener("DOMContentLoaded", async () => {
1448
1451
  const event = new Event('clapton:render');
1449
1452
  document.dispatchEvent(event);
1450
1453
  });
1454
+ document.addEventListener("turbo:render", async () => {
1455
+ await initializeComponents();
1456
+ initializeActions();
1457
+ initializeInputs();
1458
+ const event = new Event('clapton:render');
1459
+ document.dispatchEvent(event);
1460
+ });
1451
1461
  window.addEventListener('beforeunload', () => {
1452
1462
  sessionStorage.setItem('scrollPosition', window.scrollY.toString());
1453
1463
  });
@@ -405,7 +405,28 @@ var Clapton = (function (exports) {
405
405
  }
406
406
  return root.renderWrapper;
407
407
  }
408
+ static effect(dependencies, callback) {
409
+ this._effects.push({ dependencies, callback });
410
+ }
411
+ get effects() {
412
+ return this.constructor._effects;
413
+ }
414
+ runEffects() {
415
+ this.effects.forEach((effect) => {
416
+ if (effect.dependencies.some((dependency) => this._state[dependency] !== undefined)) {
417
+ effect.callback(this._state);
418
+ }
419
+ });
420
+ }
421
+ runEffectOnFirstRender() {
422
+ this.effects.forEach((effect) => {
423
+ if (effect.dependencies.length === 0) {
424
+ effect.callback(this._state);
425
+ }
426
+ });
427
+ }
408
428
  }
429
+ Component._effects = [];
409
430
 
410
431
  class TextField {
411
432
  constructor(state, attribute, attributes = {}) {
@@ -402,7 +402,28 @@ class Component {
402
402
  }
403
403
  return root.renderWrapper;
404
404
  }
405
+ static effect(dependencies, callback) {
406
+ this._effects.push({ dependencies, callback });
407
+ }
408
+ get effects() {
409
+ return this.constructor._effects;
410
+ }
411
+ runEffects() {
412
+ this.effects.forEach((effect) => {
413
+ if (effect.dependencies.some((dependency) => this._state[dependency] !== undefined)) {
414
+ effect.callback(this._state);
415
+ }
416
+ });
417
+ }
418
+ runEffectOnFirstRender() {
419
+ this.effects.forEach((effect) => {
420
+ if (effect.dependencies.length === 0) {
421
+ effect.callback(this._state);
422
+ }
423
+ });
424
+ }
405
425
  }
426
+ Component._effects = [];
406
427
 
407
428
  class TextField {
408
429
  constructor(state, attribute, attributes = {}) {
@@ -0,0 +1,160 @@
1
+ import { Clapton } from "components"
2
+
3
+ const bq = (...props: any[]) => {
4
+ return new Clapton.BlockQuote(...props)
5
+ }
6
+
7
+ const box = (...props: any[]) => {
8
+ return new Clapton.Box(...props)
9
+ }
10
+
11
+ const b = (...props: any[]) => {
12
+ return new Clapton.Bold(...props)
13
+ }
14
+
15
+ const button = (...props: any[]) => {
16
+ return new Clapton.Button(...props)
17
+ }
18
+
19
+ const check = (...props: any[]) => {
20
+ return new Clapton.Checkbox(props[0], props[1], props[2])
21
+ }
22
+
23
+ const code = (...props: any[]) => {
24
+ return new Clapton.Code(...props)
25
+ }
26
+
27
+ const datetime = (...props: any[]) => {
28
+ return new Clapton.DateTimeField(props[0], props[1], props[2])
29
+ }
30
+
31
+ const el = (...props: any[]) => {
32
+ return new Clapton.Element(props[0], props[1])
33
+ }
34
+
35
+ const embed = (...props: any[]) => {
36
+ return new Clapton.Embed(props[0])
37
+ }
38
+
39
+ const em = (...props: any[]) => {
40
+ return new Clapton.Emphasis(...props)
41
+ }
42
+
43
+ const form = (...props: any[]) => {
44
+ return new Clapton.Form(...props)
45
+ }
46
+
47
+ const h = (...props: any[]) => {
48
+ return new Clapton.Heading(props[0], props[1])
49
+ }
50
+
51
+ const img = (...props: any[]) => {
52
+ return new Clapton.Image(props[0], props[1], props[2])
53
+ }
54
+
55
+ const a = (...props: any[]) => {
56
+ return new Clapton.Link(props[0], props[1])
57
+ }
58
+
59
+ const li = (...props: any[]) => {
60
+ return new Clapton.ListItem(...props)
61
+ }
62
+
63
+ const ul = (...props: any[]) => {
64
+ return new Clapton.List(...props)
65
+ }
66
+
67
+ const ol = (...props: any[]) => {
68
+ return new Clapton.OrderedList(...props)
69
+ }
70
+
71
+ const p = (...props: any[]) => {
72
+ return new Clapton.Paragraph(...props)
73
+ }
74
+
75
+ const q = (...props: any[]) => {
76
+ return new Clapton.Quote(...props)
77
+ }
78
+
79
+ const radio = (...props: any[]) => {
80
+ return new Clapton.RadioButton(props[0], props[1], props[2])
81
+ }
82
+
83
+ const select = (...props: any[]) => {
84
+ return new Clapton.Select(props[0], props[1], props[2])
85
+ }
86
+
87
+ const span = (...props: any[]) => {
88
+ return new Clapton.Span(...props)
89
+ }
90
+
91
+ const textarea = (...props: any[]) => {
92
+ return new Clapton.TextArea(props[0], props[1], props[2])
93
+ }
94
+
95
+ const input = (...props: any[]) => {
96
+ return new Clapton.TextField(props[0], props[1], props[2])
97
+ }
98
+
99
+ const text = (...props: any[]) => {
100
+ return new Clapton.Text(props[0])
101
+ }
102
+
103
+ const c = (name: string, ...props: any[]) => {
104
+ switch (name) {
105
+ case "bq":
106
+ return bq(...props)
107
+ case "box":
108
+ return box(...props)
109
+ case "b":
110
+ return b(...props)
111
+ case "button":
112
+ return button(...props)
113
+ case "check":
114
+ return check(...props)
115
+ case "code":
116
+ return code(...props)
117
+ case "datetime":
118
+ return datetime(...props)
119
+ case "el":
120
+ return el(...props)
121
+ case "embed":
122
+ return embed(...props)
123
+ case "em":
124
+ return em(...props)
125
+ case "form":
126
+ return form(...props)
127
+ case "h":
128
+ return h(...props)
129
+ case "img":
130
+ return img(...props)
131
+ case "a":
132
+ return a(...props)
133
+ case "li":
134
+ return li(...props)
135
+ case "ul":
136
+ return ul(...props)
137
+ case "ol":
138
+ return ol(...props)
139
+ case "p":
140
+ return p(...props)
141
+ case "q":
142
+ return q(...props)
143
+ case "radio":
144
+ return radio(...props)
145
+ case "select":
146
+ return select(...props)
147
+ case "span":
148
+ return span(...props)
149
+ case "textarea":
150
+ return textarea(...props)
151
+ case "input":
152
+ return input(...props)
153
+ case "text":
154
+ return text(...props)
155
+ default:
156
+ return new Clapton.Component(...props)
157
+ }
158
+ }
159
+
160
+ export { c }
@@ -1,160 +1,3 @@
1
- import { Clapton } from "components"
2
-
3
- const bq = (...props: any[]) => {
4
- return new Clapton.BlockQuote(...props)
5
- }
6
-
7
- const box = (...props: any[]) => {
8
- return new Clapton.Box(...props)
9
- }
10
-
11
- const b = (...props: any[]) => {
12
- return new Clapton.Bold(...props)
13
- }
14
-
15
- const button = (...props: any[]) => {
16
- return new Clapton.Button(...props)
17
- }
18
-
19
- const check = (...props: any[]) => {
20
- return new Clapton.Checkbox(props[0], props[1], props[2])
21
- }
22
-
23
- const code = (...props: any[]) => {
24
- return new Clapton.Code(...props)
25
- }
26
-
27
- const datetime = (...props: any[]) => {
28
- return new Clapton.DateTimeField(props[0], props[1], props[2])
29
- }
30
-
31
- const el = (...props: any[]) => {
32
- return new Clapton.Element(props[0], props[1])
33
- }
34
-
35
- const embed = (...props: any[]) => {
36
- return new Clapton.Embed(props[0])
37
- }
38
-
39
- const em = (...props: any[]) => {
40
- return new Clapton.Emphasis(...props)
41
- }
42
-
43
- const form = (...props: any[]) => {
44
- return new Clapton.Form(...props)
45
- }
46
-
47
- const h = (...props: any[]) => {
48
- return new Clapton.Heading(props[0], props[1])
49
- }
50
-
51
- const img = (...props: any[]) => {
52
- return new Clapton.Image(props[0], props[1], props[2])
53
- }
54
-
55
- const a = (...props: any[]) => {
56
- return new Clapton.Link(props[0], props[1])
57
- }
58
-
59
- const li = (...props: any[]) => {
60
- return new Clapton.ListItem(...props)
61
- }
62
-
63
- const ul = (...props: any[]) => {
64
- return new Clapton.List(...props)
65
- }
66
-
67
- const ol = (...props: any[]) => {
68
- return new Clapton.OrderedList(...props)
69
- }
70
-
71
- const p = (...props: any[]) => {
72
- return new Clapton.Paragraph(...props)
73
- }
74
-
75
- const q = (...props: any[]) => {
76
- return new Clapton.Quote(...props)
77
- }
78
-
79
- const radio = (...props: any[]) => {
80
- return new Clapton.RadioButton(props[0], props[1], props[2])
81
- }
82
-
83
- const select = (...props: any[]) => {
84
- return new Clapton.Select(props[0], props[1], props[2])
85
- }
86
-
87
- const span = (...props: any[]) => {
88
- return new Clapton.Span(...props)
89
- }
90
-
91
- const textarea = (...props: any[]) => {
92
- return new Clapton.TextArea(props[0], props[1], props[2])
93
- }
94
-
95
- const input = (...props: any[]) => {
96
- return new Clapton.TextField(props[0], props[1], props[2])
97
- }
98
-
99
- const text = (...props: any[]) => {
100
- return new Clapton.Text(props[0])
101
- }
102
-
103
- const c = (name: string, ...props: any[]) => {
104
- switch (name) {
105
- case "bq":
106
- return bq(...props)
107
- case "box":
108
- return box(...props)
109
- case "b":
110
- return b(...props)
111
- case "button":
112
- return button(...props)
113
- case "check":
114
- return check(...props)
115
- case "code":
116
- return code(...props)
117
- case "datetime":
118
- return datetime(...props)
119
- case "el":
120
- return el(...props)
121
- case "embed":
122
- return embed(...props)
123
- case "em":
124
- return em(...props)
125
- case "form":
126
- return form(...props)
127
- case "h":
128
- return h(...props)
129
- case "img":
130
- return img(...props)
131
- case "a":
132
- return a(...props)
133
- case "li":
134
- return li(...props)
135
- case "ul":
136
- return ul(...props)
137
- case "ol":
138
- return ol(...props)
139
- case "p":
140
- return p(...props)
141
- case "q":
142
- return q(...props)
143
- case "radio":
144
- return radio(...props)
145
- case "select":
146
- return select(...props)
147
- case "span":
148
- return span(...props)
149
- case "textarea":
150
- return textarea(...props)
151
- case "input":
152
- return input(...props)
153
- case "text":
154
- return text(...props)
155
- default:
156
- return new Clapton.Component(...props)
157
- }
158
- }
1
+ import { c } from "./c-base"
159
2
 
160
3
  export default c
@@ -1,160 +1,3 @@
1
- import { Clapton } from "components"
2
-
3
- const bq = (...props: any[]) => {
4
- return new Clapton.BlockQuote(...props)
5
- }
6
-
7
- const box = (...props: any[]) => {
8
- return new Clapton.Box(...props)
9
- }
10
-
11
- const b = (...props: any[]) => {
12
- return new Clapton.Bold(...props)
13
- }
14
-
15
- const button = (...props: any[]) => {
16
- return new Clapton.Button(...props)
17
- }
18
-
19
- const check = (...props: any[]) => {
20
- return new Clapton.Checkbox(props[0], props[1], props[2])
21
- }
22
-
23
- const code = (...props: any[]) => {
24
- return new Clapton.Code(...props)
25
- }
26
-
27
- const datetime = (...props: any[]) => {
28
- return new Clapton.DateTimeField(props[0], props[1], props[2])
29
- }
30
-
31
- const el = (...props: any[]) => {
32
- return new Clapton.Element(props[0], props[1])
33
- }
34
-
35
- const embed = (...props: any[]) => {
36
- return new Clapton.Embed(props[0])
37
- }
38
-
39
- const em = (...props: any[]) => {
40
- return new Clapton.Emphasis(...props)
41
- }
42
-
43
- const form = (...props: any[]) => {
44
- return new Clapton.Form(...props)
45
- }
46
-
47
- const h = (...props: any[]) => {
48
- return new Clapton.Heading(props[0], props[1])
49
- }
50
-
51
- const img = (...props: any[]) => {
52
- return new Clapton.Image(props[0], props[1], props[2])
53
- }
54
-
55
- const a = (...props: any[]) => {
56
- return new Clapton.Link(props[0], props[1])
57
- }
58
-
59
- const li = (...props: any[]) => {
60
- return new Clapton.ListItem(...props)
61
- }
62
-
63
- const ul = (...props: any[]) => {
64
- return new Clapton.List(...props)
65
- }
66
-
67
- const ol = (...props: any[]) => {
68
- return new Clapton.OrderedList(...props)
69
- }
70
-
71
- const p = (...props: any[]) => {
72
- return new Clapton.Paragraph(...props)
73
- }
74
-
75
- const q = (...props: any[]) => {
76
- return new Clapton.Quote(...props)
77
- }
78
-
79
- const radio = (...props: any[]) => {
80
- return new Clapton.RadioButton(props[0], props[1], props[2])
81
- }
82
-
83
- const select = (...props: any[]) => {
84
- return new Clapton.Select(props[0], props[1], props[2])
85
- }
86
-
87
- const span = (...props: any[]) => {
88
- return new Clapton.Span(...props)
89
- }
90
-
91
- const textarea = (...props: any[]) => {
92
- return new Clapton.TextArea(props[0], props[1], props[2])
93
- }
94
-
95
- const input = (...props: any[]) => {
96
- return new Clapton.TextField(props[0], props[1], props[2])
97
- }
98
-
99
- const text = (...props: any[]) => {
100
- return new Clapton.Text(props[0])
101
- }
102
-
103
- const c = (name: string, ...props: any[]) => {
104
- switch (name) {
105
- case "bq":
106
- return bq(...props)
107
- case "box":
108
- return box(...props)
109
- case "b":
110
- return b(...props)
111
- case "button":
112
- return button(...props)
113
- case "check":
114
- return check(...props)
115
- case "code":
116
- return code(...props)
117
- case "datetime":
118
- return datetime(...props)
119
- case "el":
120
- return el(...props)
121
- case "embed":
122
- return embed(...props)
123
- case "em":
124
- return em(...props)
125
- case "form":
126
- return form(...props)
127
- case "h":
128
- return h(...props)
129
- case "img":
130
- return img(...props)
131
- case "a":
132
- return a(...props)
133
- case "li":
134
- return li(...props)
135
- case "ul":
136
- return ul(...props)
137
- case "ol":
138
- return ol(...props)
139
- case "p":
140
- return p(...props)
141
- case "q":
142
- return q(...props)
143
- case "radio":
144
- return radio(...props)
145
- case "select":
146
- return select(...props)
147
- case "span":
148
- return span(...props)
149
- case "textarea":
150
- return textarea(...props)
151
- case "input":
152
- return input(...props)
153
- case "text":
154
- return text(...props)
155
- default:
156
- return new Clapton.Component(...props)
157
- }
158
- }
1
+ import { c } from "./c-base"
159
2
 
160
3
  export { c }
@@ -25,5 +25,6 @@ export const claptonChannel = consumer.subscriptions.create("Clapton::ClaptonCha
25
25
 
26
26
  initializeInputs();
27
27
  initializeActions();
28
+ instance.runEffects();
28
29
  }
29
30
  })
@@ -36,6 +36,7 @@ const createAndAppendComponent = async (component: ComponentDefinition, element:
36
36
  element.outerHTML = firstChild.outerHTML;
37
37
  }
38
38
  }
39
+ instance.runEffects();
39
40
  };
40
41
 
41
42
  document.addEventListener("DOMContentLoaded", async () => {
@@ -46,6 +47,14 @@ document.addEventListener("DOMContentLoaded", async () => {
46
47
  document.dispatchEvent(event);
47
48
  });
48
49
 
50
+ document.addEventListener("turbo:render", async () => {
51
+ await initializeComponents();
52
+ initializeActions();
53
+ initializeInputs();
54
+ const event = new Event('clapton:render');
55
+ document.dispatchEvent(event);
56
+ });
57
+
49
58
  window.addEventListener('beforeunload', () => {
50
59
  sessionStorage.setItem('scrollPosition', window.scrollY.toString());
51
60
  });
@@ -5,6 +5,8 @@ export class Component {
5
5
  _state: any;
6
6
  _errors: any[];
7
7
 
8
+ static _effects: any[] = [];
9
+
8
10
  constructor(state: any = {}, id: string = Math.random().toString(36).substring(2, 10), errors: any[] = []) {
9
11
  this._state = state;
10
12
  this.id = id;
@@ -24,4 +26,28 @@ export class Component {
24
26
  }
25
27
  return root.renderWrapper;
26
28
  }
29
+
30
+ static effect(dependencies: any[], callback: () => void) {
31
+ this._effects.push({ dependencies, callback });
32
+ }
33
+
34
+ get effects(): any[] {
35
+ return (this.constructor as typeof Component)._effects;
36
+ }
37
+
38
+ runEffects() {
39
+ this.effects.forEach((effect) => {
40
+ if (effect.dependencies.some((dependency: any) => this._state[dependency] !== undefined)) {
41
+ effect.callback(this._state);
42
+ }
43
+ });
44
+ }
45
+
46
+ runEffectOnFirstRender() {
47
+ this.effects.forEach((effect) => {
48
+ if (effect.dependencies.length === 0) {
49
+ effect.callback(this._state);
50
+ }
51
+ });
52
+ }
27
53
  }
@@ -7,4 +7,5 @@ export const updateComponent = async (component: HTMLElement, state: any, proper
7
7
  const ComponentClass = module[componentName] as any;
8
8
  const instance = new ComponentClass(state, component.dataset.id);
9
9
  morphdom(component, instance.renderWrapper);
10
+ instance.runEffects();
10
11
  };
@@ -1,3 +1,3 @@
1
1
  module Clapton
2
- VERSION = '0.0.22'
2
+ VERSION = '0.0.24'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: clapton
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.22
4
+ version: 0.0.24
5
5
  platform: ruby
6
6
  authors:
7
7
  - Moeki Kawakami
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-10-16 00:00:00.000000000 Z
11
+ date: 2024-10-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -6706,6 +6706,7 @@ files:
6706
6706
  - lib/clapton/javascripts/src/actions/handle-action.spec.ts
6707
6707
  - lib/clapton/javascripts/src/actions/handle-action.ts
6708
6708
  - lib/clapton/javascripts/src/actions/initialize-actions.ts
6709
+ - lib/clapton/javascripts/src/c-base.ts
6709
6710
  - lib/clapton/javascripts/src/c-for-test.ts
6710
6711
  - lib/clapton/javascripts/src/c.ts
6711
6712
  - lib/clapton/javascripts/src/channel/clapton-channel.js