matestack-ui-core 1.0.1 → 1.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +782 -16
  3. data/app/concepts/matestack/ui/core/async/async.js +6 -28
  4. data/app/concepts/matestack/ui/core/async/async.rb +7 -10
  5. data/app/concepts/matestack/ui/core/cable/cable.haml +4 -0
  6. data/app/concepts/matestack/ui/core/cable/cable.js +100 -0
  7. data/app/concepts/matestack/ui/core/cable/cable.rb +28 -0
  8. data/app/concepts/matestack/ui/core/cable/children_wrapper.haml +2 -0
  9. data/app/concepts/matestack/ui/core/collection/content/content.js +2 -2
  10. data/app/concepts/matestack/ui/core/collection/content/content.rb +1 -1
  11. data/app/concepts/matestack/ui/core/component/base.rb +10 -4
  12. data/app/concepts/matestack/ui/core/component/component.js +18 -1
  13. data/app/concepts/matestack/ui/core/component/dynamic.rb +1 -1
  14. data/app/concepts/matestack/ui/core/form/checkbox/base.rb +120 -0
  15. data/app/concepts/matestack/ui/core/form/checkbox/checkbox.js +15 -0
  16. data/app/concepts/matestack/ui/core/form/checkbox/checkbox.rb +7 -70
  17. data/app/concepts/matestack/ui/core/form/checkbox/mixin.js +80 -0
  18. data/app/concepts/matestack/ui/core/form/form.js +15 -46
  19. data/app/concepts/matestack/ui/core/form/input/base.rb +75 -0
  20. data/app/concepts/matestack/ui/core/form/input/input.js +15 -0
  21. data/app/concepts/matestack/ui/core/form/input/input.rb +8 -52
  22. data/app/concepts/matestack/ui/core/form/input/mixin.js +55 -0
  23. data/app/concepts/matestack/ui/core/form/radio/base.rb +90 -0
  24. data/app/concepts/matestack/ui/core/form/radio/mixin.js +62 -0
  25. data/app/concepts/matestack/ui/core/form/radio/radio.js +15 -0
  26. data/app/concepts/matestack/ui/core/form/radio/radio.rb +7 -62
  27. data/app/concepts/matestack/ui/core/form/select/base.rb +98 -0
  28. data/app/concepts/matestack/ui/core/form/select/mixin.js +58 -0
  29. data/app/concepts/matestack/ui/core/form/select/select.js +15 -0
  30. data/app/concepts/matestack/ui/core/form/select/select.rb +11 -60
  31. data/app/concepts/matestack/ui/core/form/submit/base.rb +12 -0
  32. data/app/concepts/matestack/ui/core/form/submit/submit.js +19 -0
  33. data/app/concepts/matestack/ui/core/form/submit/submit.rb +9 -6
  34. data/app/concepts/matestack/ui/core/form/textarea/base.rb +49 -0
  35. data/app/concepts/matestack/ui/core/form/textarea/mixin.js +41 -0
  36. data/app/concepts/matestack/ui/core/form/textarea/textarea.js +15 -0
  37. data/app/concepts/matestack/ui/core/form/textarea/textarea.rb +10 -21
  38. data/app/concepts/matestack/ui/core/js/core.js +12 -0
  39. data/app/concepts/matestack/ui/core/{form/submit/submit.haml → select/select.haml} +1 -1
  40. data/app/concepts/matestack/ui/core/select/select.rb +7 -0
  41. data/app/helpers/matestack/ui/core/application_helper.rb +6 -3
  42. data/app/javascript/matestack-ui-core/index.js +12 -2
  43. data/app/lib/matestack/ui/core/has_view_context.rb +4 -2
  44. data/app/lib/matestack/ui/core/rendering/main_renderer.rb +4 -1
  45. data/lib/matestack/ui/core/components.rb +4 -1
  46. data/lib/matestack/ui/core/version.rb +1 -1
  47. data/vendor/assets/javascripts/dist/matestack-ui-core.js +768 -98
  48. data/vendor/assets/javascripts/dist/matestack-ui-core.js.map +1 -1
  49. data/vendor/assets/javascripts/dist/matestack-ui-core.min.js +1 -1
  50. data/vendor/assets/javascripts/dist/matestack-ui-core.min.js.br +0 -0
  51. data/vendor/assets/javascripts/dist/matestack-ui-core.min.js.gz +0 -0
  52. data/vendor/assets/javascripts/dist/matestack-ui-core.min.js.map +1 -1
  53. data/vendor/assets/javascripts/dist/matestack-ui-core.min.js.map.br +0 -0
  54. data/vendor/assets/javascripts/dist/matestack-ui-core.min.js.map.gz +0 -0
  55. metadata +25 -7
  56. data/app/concepts/matestack/ui/core/component/rerender.rb +0 -8
  57. data/app/concepts/matestack/ui/core/form/select/select.haml +0 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 92c383f00f16838c5ecfa22d10362748192c75c5efac29442f0088022fd3b967
4
- data.tar.gz: a85aee4506cd366c6364cc2fe53d82154fea5e38d47ed590733ff57bea9ead44
3
+ metadata.gz: 41c80a6f5789f72a5d72ac93e16b15935026c5a9abe849e8de69558ed6a21caa
4
+ data.tar.gz: 81e3567844fd8137016cd54e80c5ad642e445614cff671dfcf0ea031838aa816
5
5
  SHA512:
6
- metadata.gz: 70404756a9689a71569b6af255b724c0eee8a639c46e865de62113ff1dd8fde3f4c95e9fa32c738875af0fac80096d8911a7a9865b68132fa0cc0b110e2d117e
7
- data.tar.gz: f5b28b154d4c8a2d27d0916f18242d050a6a664a975cb355d5422bcc549a48cf75d67a475c514cde6e3be5fb0c317f0375208a3179a213d1629d395add6e35a6
6
+ metadata.gz: 4376b8f3a2807f77ca7915d6642074cb73e9ddbd17ba1de2f81bb53573f9fdb4a978b1be3c4878218ea4abe611b061d2463dc17bbecbb147626a151434df6cdc
7
+ data.tar.gz: b00695ffa067070d9c6b362b28fec733af2fa97fb9b887b8ecd9afb18c21a88a6e5df146259dba09d3ffc2ff732aa566dae154935a7cc5379cb6a5747c268e32
data/README.md CHANGED
@@ -1,25 +1,22 @@
1
1
  [![Specs](https://github.com/matestack/matestack-ui-core/workflows/specs/badge.svg)](https://github.com/matestack/matestack-ui-core/actions)
2
- [![Gitter](https://badges.gitter.im/basemate/community.svg)](https://gitter.im/basemate/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
2
+ [![Discord](https://img.shields.io/discord/771413294136426496.svg)](https://discord.com/invite/c6tQxFG)
3
3
  [![Gem Version](https://badge.fury.io/rb/matestack-ui-core.svg)](https://badge.fury.io/rb/matestack-ui-core)
4
4
  [![Docs](https://img.shields.io/badge/docs-matestack-blue.svg)](https://docs.matestack.io)
5
- [![Twitter Follow](https://img.shields.io/twitter/follow/matestack.svg?style=social)](https://twitter.com/matestack)
5
+ [![Twitter Follow](https://img.shields.io/twitter/follow/matestack.svg?style=social)](https://twitter.com/matestack)
6
6
 
7
7
  ![matestack logo](./logo.png)
8
8
 
9
- # matestack-ui-core
9
+ # matestack-ui-core | UI in pure Ruby
10
10
 
11
- ## Escape the frontend hustle & easily create interactive web apps in pure Ruby
11
+ Boost your productivity & easily create component based web UIs in pure Ruby.
12
+ Reactivity included if desired.
12
13
 
13
- `matestack-ui-core` is a Rails engine for Ruby on Rails developers.
14
+ `matestack-ui-core` enables you to craft maintainable web UIs in pure Ruby, skipping ERB and HTML. UI code becomes a native and fun part of your Rails app. Thanks to reactive core components, reactivity can be optionally added on top without writing JavaScript, just using a simple Ruby DSL.
14
15
 
15
- `matestack-ui-core` enables you to craft interactive web UIs without JavaScript in pure Ruby with minimum effort.
16
- UI code becomes a native and fun part of your Rails app.
17
-
18
- Work with pure Ruby. If necessary, extend with pure JavaScript. No Opal involved.
16
+ You end up writing 50% less code while increasing productivity, maintainability and developer happiness. Work with pure Ruby. If necessary, extend with pure JavaScript. No Opal involved.
19
17
 
20
18
  The main goals are:
21
19
 
22
- - Reduction of complexity of modern web development, moving front and backend closer together
23
20
  - More maintainable UI code, using a component-based structure written in Ruby
24
21
  - Increased development speed and happiness, offering prebuilt UI-Components for typical requirements
25
22
  - Modern, dynamic UI feeling without the need to implement a separate JavaScript Application
@@ -28,25 +25,794 @@ The main goals are:
28
25
  it alongside your classic views and incrementally turn your Rails-App into a
29
26
  dynamic Web-App.
30
27
 
31
- ## Features
32
-
33
- Please have a look at our [landingpage](https://www.matestack.io), presenting the main features of `matestack-ui-core`
34
-
35
28
  ## Documentation/Installation
36
29
 
37
30
  Documentation can be found [here](https://docs.matestack.io)
38
31
 
32
+ ## Getting started
33
+
34
+ A getting started guide can be found [here](https://docs.matestack.io/docs/start/150-getting_started)
35
+
39
36
  ## Changelog
40
37
 
41
38
  Changelog can be found [here](./CHANGELOG.md)
42
39
 
43
40
  ## Community
44
41
 
45
- As a low-barrier feedback channel for our early users, we have set up a Gitter chat that can be found [here](https://gitter.im/basemate/community). You are very welcome to ask questions and send us feedback there!
42
+ As a low-barrier feedback channel for our early users, we have set up a Discord server that can be found [here](https://discord.com/invite/c6tQxFG). You are very welcome to ask questions and send us feedback there!
46
43
 
47
44
  ## Contribution
48
45
 
49
- We are happy to accept contributors of any kind. Please refer to the [Contribution Guide](https://docs.matestack.io/docs/guides/1500-contribute/README.md)
46
+ We are happy to accept contributors of any kind! In order to make it as easy and fun as possible to contribute to `matestack-ui-core`, we would like to onboard contributors personally! Best way to become a contributor: Ping us on Discord! We will schedule a video call with you and show you, how and what to work on :)
47
+
48
+ Here are some good first issues for first time contributors: [good first issues](https://github.com/matestack/matestack-ui-core/issues?q=is%3Aopen+is%3Aissue+label%3A"good+first+issue")
49
+
50
+ ## Features
51
+
52
+ On our [landingpage](https://www.matestack.io), we're presenting the following features alongside some live demos!
53
+
54
+ ### 1. Create UI components in pure Ruby
55
+
56
+ Craft your UI based on your components written in pure Ruby. Utilizing Ruby's amazing language features, you're able to create a cleaner and more maintainable UI implementation.
57
+
58
+ #### Implement UI components in pure Ruby
59
+
60
+ Create Ruby classes within your Rails project and call matestack's core components through a Ruby DSL in order to craft your UIs.
61
+ The Ruby method \"div\" for example calls one of the static core components, responsible for rendering HTML tags. A component can take Strings, Integers Symbols, Arrays or Hashes (...) as optional properties (e.g. \"title\") or require them (e.g. \"body\").
62
+
63
+ `app/matestack/components/card.rb`
64
+
65
+ ```ruby
66
+
67
+ class Components::Card < Matestack::Ui::Component
68
+
69
+ requires :body
70
+ optional :title
71
+ optional :image
72
+
73
+ def response
74
+ div class: "card shadow-sm border-0 bg-light" do
75
+ img path: image, class: "w-100" if image.present?
76
+ div class: "card-body" do
77
+ heading size: 5, text: title if title.present?
78
+ paragraph class: "card-text", text: body
79
+ end
80
+ end
81
+ end
82
+
83
+ end
84
+
85
+ ```
86
+
87
+ #### Use your Ruby UI components on your existing Rails views
88
+
89
+ Register your Ruby UI component classes with your desired DSL method and use the \"matestack_component\" helper in order to render your component within existing ERB views or Rails controllers.
90
+ The Ruby method \"card\" for example calls your \"Card\" class, enabling you to create a reuseable card components, abstracting UI complexity in your ow components.
91
+
92
+ `app/views/your_view.html.erb`
93
+
94
+ ```erb
95
+
96
+ <!-- some other erb markup -->
97
+ <%= matestack_component :card, title: "hello", body: "world" %>
98
+ <!-- some other erb markup -->
99
+
100
+ ```
101
+
102
+ `app/matestack/components/registry.rb`
103
+
104
+ ```ruby
105
+ module Components::Registry
106
+
107
+ Matestack::Ui::Core::Component::Registry.register_components(
108
+ card: Components::Card,
109
+ #...
110
+ )
111
+
112
+ end
113
+ ```
114
+
115
+
116
+ #### Use Ruby methods as partials
117
+
118
+ Split your UI implementation into multiple small chunks helping others (and yourself) to better understand your implementation.
119
+ Using this approach helps you to create a clean, readable and maintainable codebase.
120
+
121
+ `app/matestack/components/card.rb`
122
+
123
+ ```ruby
124
+
125
+ class Components::Card < Matestack::Ui::Component
126
+
127
+ requires :body
128
+ optional :title
129
+ optional :image
130
+ optional :footer
131
+
132
+ def response
133
+ div class: "card shadow-sm border-0 bg-light" do
134
+ img path: image, class: "w-100" if image.present?
135
+ card_content
136
+ card_footer if footer.present?
137
+ end
138
+ end
139
+
140
+ def card_content
141
+ div class: "card-body" do
142
+ heading size: 5, text: title if title.present?
143
+ paragraph class: "card-text", text: body
144
+ end
145
+ end
146
+
147
+ def card_footer
148
+ div class: "card-footer text-muted" do
149
+ plain footer
150
+ end
151
+ end
152
+
153
+ end
154
+
155
+ ```
156
+
157
+ `app/views/your_view.html.erb`
158
+
159
+ ```erb
160
+ <!-- some other erb markup -->
161
+ <%= matestack_component :card, title: "hello", body: "world", footer: "foo" %>
162
+ <!-- some other erb markup -->
163
+ ```
164
+
165
+
166
+ #### Use class inheritance
167
+
168
+ Because it's just a Ruby class, you can use class inheritance in order to further improve the quality of your UI implementation.
169
+ Class inheritance can be used to easily create variants of UI components but still reuse parts of the implementation.
170
+
171
+ `app/matestack/components/blue_card.rb`
172
+
173
+ ```ruby
174
+
175
+ class Components::BlueCard < Components::Card
176
+
177
+ def response
178
+ div class: "card shadow-sm border-0 bg-primary text-white" do
179
+ img path: image, class: "w-100" if image.present?
180
+ card_content #defined in parent class
181
+ card_footer if footer.present? #defined in parent class
182
+ end
183
+ end
184
+
185
+ end
186
+
187
+ ```
188
+
189
+ `app/matestack/components/registry.rb`
190
+
191
+ ```ruby
192
+ module Components::Registry
193
+
194
+ Matestack::Ui::Core::Component::Registry.register_components(
195
+ blue_card: Components::BlueCard,
196
+ #...
197
+ )
198
+
199
+ end
200
+ ```
201
+
202
+ `app/views/your_view.html.erb`
203
+
204
+ ```erb
205
+ <!-- some other erb markup -->
206
+ <%= matestack_component :blue_card, title: "hello", body: "world" %>
207
+ <!-- some other erb markup -->
208
+ ```
209
+
210
+ #### Use components within components
211
+
212
+ Just like you used matestack's core components on your own UI component, you can use your own UI components within other custom UI components.
213
+ You decide when using a Ruby method partial should be replaced by another self contained UI component!
214
+
215
+ `app/matestack/components/card.rb`
216
+
217
+ ```ruby
218
+
219
+ class Components::Card < Matestack::Ui::Component
220
+
221
+ requires :body
222
+ optional :title
223
+ optional :image
224
+
225
+ def response
226
+ div class: "card shadow-sm border-0 bg-light" do
227
+ img path: image, class: "w-100" if image.present?
228
+ # calling the CardBody component rather than using Ruby method partials
229
+ card_body title: title, body: body
230
+ end
231
+ end
232
+
233
+ end
234
+
235
+ ```
236
+ `app/matestack/components/card_body.rb`
237
+
238
+ ```ruby
239
+
240
+ class Components::CardBody < Matestack::Ui::Component
241
+
242
+ requires :body
243
+ optional :title
244
+
245
+ def response
246
+ # Just an example. Would make more sense, if this component had
247
+ # a more complex structure
248
+ div class: "card-body" do
249
+ heading size: 5, text: title if title.present?
250
+ paragraph class: "card-text", text: body
251
+ end
252
+ end
253
+
254
+ end
255
+
256
+ ```
257
+
258
+
259
+ `app/matestack/components/registry.rb`
260
+
261
+ ```ruby
262
+ module Components::Registry
263
+
264
+ Matestack::Ui::Core::Component::Registry.register_components(
265
+ card: Components::Card,
266
+ card_body: Components::CardBody,
267
+ #...
268
+ )
269
+
270
+ end
271
+ ```
272
+
273
+ #### Yield components into components
274
+
275
+ Sometimes it's not enough to just pass simple data into a component. No worries! You can just yield a block into your components!
276
+ Using this approach gives you more flexibility when using your UI components. Ofcourse yielding can be used alongside passing in simple params.
277
+
278
+
279
+ `app/matestack/components/card.rb`
280
+
281
+ ```ruby
282
+
283
+ class Components::Card < Matestack::Ui::Component
284
+
285
+ requires :body
286
+ optional :title
287
+ optional :image
288
+
289
+ def response
290
+ div class: "card shadow-sm border-0 bg-light" do
291
+ img path: image, class: "w-100" if image.present?
292
+ card_body do
293
+ # yielding a block into the card_body component
294
+ heading size: 5, text: title if title.present?
295
+ paragraph class: "card-text", text: body
296
+ end
297
+ end
298
+ end
299
+
300
+ end
301
+
302
+ ```
303
+
304
+ `app/matestack/components/card_body.rb`
305
+
306
+ ```ruby
307
+
308
+ class Components::CardBody < Matestack::Ui::Component
309
+
310
+ def response
311
+ # Just an example. Would make more sense, if this component had
312
+ # a more complex structure
313
+ div class: "card-body" do
314
+ yield_components
315
+ end
316
+ end
317
+
318
+ end
319
+
320
+ ```
321
+
322
+ #### Use named slots for advanced content injection
323
+
324
+ If you need to inject multiple blocks into your UI component, you can use \"slots\"!
325
+ Slots help you to build complex UI components with multiple named content placeholders for highest implementation flexibility!
326
+
327
+ `app/matestack/components/card.rb`
328
+
329
+ ```ruby
330
+
331
+ class Components::Card < Matestack::Ui::Component
332
+
333
+ requires :body
334
+ optional :title
335
+ optional :image
336
+
337
+ def response
338
+ div class: "card shadow-sm border-0 bg-light" do
339
+ img path: image, class: "w-100" if image.present?
340
+ card_body slots: { heading: heading_slot, body: body_slot }
341
+ end
342
+ end
343
+
344
+ def heading_slot
345
+ slot do
346
+ heading size: 5, text: title if title.present?
347
+ end
348
+ end
349
+
350
+ def body_slot
351
+ slot do
352
+ paragraph class: "card-text", text: body
353
+ end
354
+ end
355
+
356
+ end
357
+
358
+ ```
359
+ `app/matestack/components/card_body.rb`
360
+
361
+ ```ruby
362
+
363
+ class Components::CardBody < Matestack::Ui::Component
364
+
365
+ requires :slots
366
+
367
+ def response
368
+ # Just an example. Would make more sense, if this component had
369
+ # a more complex structure
370
+ div class: "card-body" do
371
+ div class: "heading-section" do
372
+ slot slots[:heading]
373
+ end
374
+ div class: "body-section" do
375
+ slot slots[:body]
376
+ end
377
+ end
378
+ end
379
+
380
+ end
381
+
382
+ ```
383
+
384
+
385
+ ### 2. Use reactive UI components in pure Ruby
386
+
387
+ What about going even one step further and implement REACTIVE UIs in pure Ruby? Matestack's reactive core components can be used with a simple Ruby DSL enabling you to create reactive UIs without touching JavaScript!
388
+
389
+ #### Toggle parts of the UI based on events
390
+
391
+ Matestack offers an event hub. Reactive components can emit and receive events through this event hub. \"onclick\" and \"toggle\" calling two of these reactive core components.
392
+ \"onclick\" emits an event which causes the body of the \"toggle\" component to be visible for 5 seconds in this example.
393
+
394
+ `app/matestack/components/some_component.rb`
395
+
396
+ ```ruby
397
+
398
+ class Components::SomeComponent < Matestack::Ui::Component
399
+
400
+ def response
401
+ onclick emit: "some_event" do
402
+ button text: "click me"
403
+ end
404
+ toggle show_on: "some_event", hide_after: 5000 do
405
+ plain "Oh yes! You clicked me!"
406
+ end
407
+ end
408
+
409
+ end
410
+
411
+ ```
412
+
413
+ #### Call controller actions without JavaScript
414
+
415
+ Core components offer basic dynamic behaviour and let you easily call controller actions and react to server responses on the client side without full page reload.
416
+ The \"action\" component is configured to emit an event after successfully performed an HTTP request against a Rails controller action, which is receive by the \"toggle\" component, displaying the success message.
417
+
418
+ `app/matestack/components/some_component.rb`
419
+
420
+ ```ruby
421
+
422
+ class Components::SomeComponent < Matestack::Ui::Component
423
+
424
+ def response
425
+ action my_action_config do
426
+ button text: "click me"
427
+ end
428
+ toggle show_on: "some_event", hide_after: 5000 do
429
+ plain "Success!"
430
+ end
431
+ end
432
+
433
+ def my_action_config
434
+ {
435
+ path: some_rails_route_path,
436
+ method: :post,
437
+ success: {
438
+ emit: "some_event"
439
+ }
440
+ }
441
+ end
442
+
443
+ end
444
+
445
+ ```
446
+
447
+
448
+ ### Dynamically handle form input without JavaScript
449
+
450
+ Create dynamic forms for ActiveRecord Models (or plain objects) and display server side responses, like validation errors or success messages, without relying on a full page reload.
451
+ Events emitted by the \"form\" component can be used to toggle parts of the UI.
452
+
453
+ `app/matestack/components/some_component.rb`
454
+
455
+ ```ruby
456
+
457
+ class Components::SomeComponent < Matestack::Ui::Component
458
+
459
+ def prepare
460
+ @new_active_record_instance = MyActiveRecordModel.new
461
+ end
462
+
463
+ def response
464
+ form my_form_config do
465
+ form_input key: :some_attribute, type: :text
466
+ form_submit do
467
+ button text: "click me"
468
+ end
469
+ end
470
+ toggle show_on: "submitted", hide_after: 5000 do
471
+ span class: "message success" do
472
+ plain "created successfully"
473
+ end
474
+ end
475
+ toggle show_on: "failed", hide_after: 5000 do
476
+ span class: "message failure" do
477
+ plain "data was not saved, please check form"
478
+ end
479
+ end
480
+ end
481
+
482
+ def my_form_config
483
+ {
484
+ for: @new_active_record_instance,
485
+ path: some_rails_route_path,
486
+ method: :post,
487
+ success: {
488
+ emit: "submitted"
489
+ },
490
+ failure: {
491
+ emit: "failed"
492
+ }
493
+ }
494
+ end
495
+
496
+ end
497
+
498
+ ```
499
+
500
+ #### Implement asynchronous, event-based UI rerendering in pure Ruby
501
+
502
+ Using matestack's built-in event system, you can rerender parts of the UI on client side events, such as form or action submissions. Even server side events pushed via ActionCable may be received!
503
+ The \"async\" component requests a new version of its body at the server via an HTTP GET request after receiving the configured event. After successfu server response, the DOM of the \"async\" component gets updated. Everything else stays untouched.
504
+
505
+ `app/matestack/components/some_component.rb`
506
+
507
+ ```ruby
508
+
509
+ class Components::SomeComponent < Matestack::Ui::Component
510
+
511
+ def response
512
+ form my_form_config do
513
+ #...
514
+ end
515
+ #...
516
+ async rerender_on: "submitted", id: "my-model-list" do
517
+ ul do
518
+ MyActiveRecordModel.last(5).each do |model|
519
+ li text: model.some_attribute
520
+ end
521
+ end
522
+ end
523
+ end
524
+
525
+ def my_form_config
526
+ {
527
+ #...
528
+ success: {
529
+ emit: "submitted"
530
+ },
531
+ failure: {
532
+ emit: "failed"
533
+ }
534
+ }
535
+ end
536
+
537
+ end
538
+
539
+ ```
540
+
541
+ #### Manipulate parts of the UI via ActionCable
542
+
543
+ \"async\" rerenders its whole body - but what about just appending the element to the list after successful form submission?
544
+ The \"cable\" component can be configured to receive events and data pushed via ActionCable from the server side and just append/prepend new chunks of HTM (ideally rendered through a component) to the current \"cable\" component body. Updating and deleting is also supported!
545
+
546
+ `app/matestack/components/some_component.rb`
547
+
548
+ ```ruby
549
+
550
+ class Components::SomeComponent < Matestack::Ui::Component
551
+
552
+ def response
553
+ form my_form_config do
554
+ #...
555
+ end
556
+ #...
557
+ ul do
558
+ cable prepend_on: "new_element_created", id: "mocked-instance-list" do
559
+ MyActiveRecordModel.last(5).each do |model|
560
+ li text: model
561
+ end
562
+ end
563
+ end
564
+ end
565
+
566
+ end
567
+
568
+ ```
569
+
570
+ `app/controllers/some_controller.rb`
571
+
572
+ ```ruby
573
+ # within your controller action handling the form input
574
+ ActionCable.server.broadcast("matestack_ui_core", {
575
+ event: "new_element_created",
576
+ data: matestack_component(:li, text: params[:some_attribute])
577
+ })
578
+
579
+ ```
580
+
581
+ #### Easily extend with Vue.js
582
+
583
+ Matestack's dynamic parts are built on Vue.js. If you want to implement custom dynamic behaviour, you can simply create your own Vue components and use them along matestacks core components.
584
+ It's even possible to interact with matestack's core components using the built-in event bus.
585
+
586
+ `app/matestack/components/some_component.rb`
587
+
588
+ ```ruby
589
+
590
+ class Components::SomeComponent < Matestack::Ui::Component
591
+
592
+ def response
593
+ my_vue_js_component
594
+ toggle show_on: "some_event", hide_after: "3000" do
595
+ span class: "message success" do
596
+ plain "event triggered from custom vuejs component"
597
+ end
598
+ end
599
+ end
600
+
601
+ end
602
+
603
+ ```
604
+ `app/matestack/components/my_vue_js_component.rb`
605
+
606
+ ```ruby
607
+ class Components::MyVueJsComponent < Matestack::Ui::VueJsComponent
608
+
609
+ vue_js_component_name "my-vue-js-component"
610
+
611
+ def response
612
+ div class: "my-vue-js-component" do
613
+ button attributes: {"@click": "increaseValue"}
614
+ br
615
+ plain "{{ dynamicValue }}!"
616
+ end
617
+ end
618
+
619
+ end
620
+ ```
621
+
622
+ `app/matestack/components/my_vue_js_component.js`
623
+
624
+ ```javascript
625
+ MatestackUiCore.Vue.component('my-vue-js-component', {
626
+ mixins: [MatestackUiCore.componentMixin],
627
+ data: () => {
628
+ return {
629
+ dynamicValue: 0
630
+ };
631
+ },
632
+ methods: {
633
+ increaseValue(){
634
+ this.dynamicValue++
635
+ MatestackUiCore.matestackEventHub.$emit("some_event")
636
+ }
637
+ }
638
+ });
639
+ ```
640
+
641
+ ### 3. Create whole SPA-like apps in pure Ruby
642
+
643
+ The last step in order to leverage the full Matestack power: Create app (~Rails layout) and page (Rails ~view) classes and implement dynamic page transitions without any JavaScript implementation required.
644
+
645
+ #### Create your layouts and views in pure Ruby
646
+
647
+ The app class is used to define a layout, usually containing some kind of header, footer and navigation. The page class is used to define a view. Following the same principles as seen on components, you can use components (core or your own) in order to create the UI.
648
+ The \"transition\" component enables dynamic page transition, replacing the content within \"yield_page\" with new serverside rendered content.
649
+
650
+ `app/matestack/some_app/app.rb`
651
+
652
+ ```ruby
653
+
654
+ class SomeApp::App < Matestack::Ui::App
655
+
656
+ def response
657
+ nav do
658
+ transition path: page1_path do
659
+ button text: "Page 1"
660
+ end
661
+ transition path: page2_path do
662
+ button text: "Page 2"
663
+ end
664
+ end
665
+ main do
666
+ div class: "container" do
667
+ yield_page
668
+ end
669
+ end
670
+ end
671
+
672
+ end
673
+
674
+ ```
675
+
676
+ `app/matestack/some_app/pages/page1.rb`
677
+
678
+ ```ruby
679
+ class SomeApp::Pages::Page1 < Matestack::Ui::Page
680
+
681
+ def response
682
+ div class: "row" do
683
+ div class: "col" do
684
+ plain "Page 1"
685
+ end
686
+ end
687
+ end
688
+
689
+ end
690
+
691
+ ```
692
+
693
+ `app/matestack/some_app/pages/page2.rb`
694
+
695
+ ```ruby
696
+ class SomeApp::Pages::Page2 < Matestack::Ui::Page
697
+
698
+ def response
699
+ div class: "row" do
700
+ div class: "col" do
701
+ plain "Page 2"
702
+ end
703
+ end
704
+ end
705
+
706
+ end
707
+
708
+ ```
709
+
710
+ #### Apps and pages are referenced in your Rails controllers and actions
711
+
712
+ Instead of referencing Rails layouts and views on your controllers, you just use apps and pages as substitutes.
713
+ Work with controllers, actions and routing as you're used to! Controller hooks (e.g. devise's authenticate_user) would still work!
714
+
715
+ `app/controllers/some_controller.rb`
716
+
717
+ ```ruby
718
+
719
+ class SomeController < ApplicationController
720
+
721
+ include Matestack::Ui::Core::ApplicationHelper
722
+ include Components::Registry
723
+
724
+ matestack_app SomeApp::App
725
+
726
+ def page1
727
+ render SomeApp::Page1
728
+ end
729
+
730
+ def page2
731
+ render SomeApp::Page2
732
+ end
733
+
734
+ end
735
+
736
+ ```
737
+
738
+ `app/config/routes.rb`
739
+
740
+ ```ruby
741
+ Rails.application.routes.draw do
742
+
743
+ root to: 'some#page1'
744
+
745
+ get :page1, to: 'some#page1'
746
+ get :page2, to: 'some#page2'
747
+
748
+ end
749
+
750
+ ```
751
+
752
+ #### Use CSS animations for fancy page transition animations
753
+
754
+ Use matestack's css classes applied to the wrapping DOM structure of a page in order to add CSS animiations, whenever a page transition is performed."
755
+ You can even inject a loading state element, enriching your page transition effect.
756
+
757
+ `app/matestack/some_app/app.rb`
758
+
759
+ ```ruby
760
+
761
+ class SomeApp::App < Matestack::Ui::App
762
+
763
+ def response
764
+ nav do
765
+ transition path: page1_path do
766
+ button text: "Page 1"
767
+ end
768
+ transition path: page2_path do
769
+ button text: "Page 2"
770
+ end
771
+ end
772
+ main do
773
+ div class: "container" do
774
+ yield_page slots: { loading_state: loading_state_element }
775
+ end
776
+ end
777
+ end
778
+
779
+ def loading_state_element
780
+ slot do
781
+ div class: 'some-loading-element-styles'
782
+ end
783
+ end
784
+
785
+ end
786
+
787
+ ```
788
+
789
+ `app/assets/stylesheets/application.scss`
790
+
791
+ ```scss
792
+
793
+ .matestack-page-container{
794
+
795
+ .matestack-page-wrapper {
796
+ opacity: 1;
797
+ transition: opacity 0.2s ease-in-out;
798
+
799
+ &.loading {
800
+ opacity: 0;
801
+ }
802
+ }
803
+
804
+ .loading-state-element-wrapper{
805
+ opacity: 0;
806
+ transition: opacity 0.3s ease-in-out;
807
+
808
+ &.loading {
809
+ opacity: 1;
810
+ }
811
+ }
812
+
813
+ }
814
+
815
+ ```
50
816
 
51
817
  ## License
52
818
  matestack-ui-core is an Open Source project licensed under the terms of the [LGPLv3 license](./LICENSE)