matestack-ui-core 1.1.0 → 1.2.0

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