matestack-ui-core 1.1.0 → 1.4.0

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