vident 0.12.1 → 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -1,76 +1,288 @@
1
1
  # Vident
2
2
 
3
- **Vident** is a collection of gems that help you create **flexible** & **maintainable** component libraries for your Rails application.
3
+ Vident is a collection of gems that provide a set of tools for building web applications with Ruby on Rails.
4
4
 
5
- <a href="https://github.com/stevegeek/vident"><img alt="Vident logo" src="https://raw.githubusercontent.com/stevegeek/vident/main/docs/images/logo-by-sd-256-colors.png" width="180" /></a>
5
+ ## Included Gems
6
6
 
7
- Vident also provides a neat Ruby DSL to make wiring up **Stimulus easier & less error prone** in your view components.
7
+ The core gems:
8
8
 
9
- [`ViewComponent`](https://viewcomponent.org/) and [`Phlex`](https://phlex.fun) supported.
9
+ - `vident`: The core Vident library
10
+ - `vident-phlex`: Phlex integration for Vident
11
+ - `vident-view_component`: ViewComponent integration for Vident
10
12
 
11
- # Motivation
13
+ Note that you can use both `Phlex` and `ViewComponent` in the same application if desired.
12
14
 
13
- I love working with Stimulus, but I find manually crafting the data attributes for
14
- targets and actions error-prone and tedious. Vident aims to make this process easier
15
- and keep me thinking in Ruby.
15
+ And then optional extra features:
16
16
 
17
- Vident has been used with `ViewComponent` and `Phlex` in production apps for a while now
18
- but is still evolving.
17
+ - `vident-tailwind`: Tailwind CSS integration for Vident
18
+ - `vident-typed`: Type system for Vident components
19
+ - `vident-typed-minitest`: Minitest integration for typed Vident components
20
+ - `vident-typed-phlex`: Phlex integration for typed Vident components
21
+ - `vident-typed-view_component`: ViewComponent integration for typed Vident
22
+ - `vident-better_html`: Better HTML integration for Vident
19
23
 
20
- I would love to get your feedback and contributions!
24
+ ## Directory Structure
21
25
 
22
- ## Example
26
+ The repository is structured like this:
23
27
 
24
- The Greeter ViewComponent (that uses Vident):
28
+ ```
29
+ vident/
30
+ ├── lib/ # All gem code
31
+ │ ├── vident.rb # Core entry point
32
+ │ ├── vident-phlex.rb # Gem entry points
33
+ │ ├── vident-better_html.rb
34
+ │ ├── vident/ # Shared code
35
+ │ ├── base.rb
36
+ │ ├── phlex/ # Phlex integration
37
+ │ ├── better_html/ # Better HTML integration
38
+ │ └── ...
39
+ ├── test/ # All tests
40
+ │ ├── vident/ # Core tests
41
+ │ ├── vident-phlex/ # Tests for each gem
42
+ │ └── ...
43
+ ├── docs/ # Documentation
44
+ ├── examples/ # Examples
45
+ ├── vident.gemspec # Gemspec for core gem
46
+ ├── vident-phlex.gemspec # Gemspecs for each gem
47
+ └── ...
48
+ ```
25
49
 
26
- ![docs/images/ex1.gif](docs/images/ex1.gif)
50
+ ## Development
27
51
 
28
- Consider a component, the `GreeterComponent`:
52
+ ### Setting Up Development Environment
29
53
 
30
- ```ruby
31
- # app/components/greeter_component.rb
54
+ ```bash
55
+ # Clone the repository
56
+ git clone https://github.com/stevegeek/vident.git
57
+ cd vident
32
58
 
33
- class GreeterComponent < ::Vident::ViewComponent::Base
34
- renders_one :trigger, ButtonComponent
59
+ # Install dependencies
60
+ bundle install
61
+ ```
62
+
63
+ ### Running Tests
64
+
65
+ To run tests for all gems:
66
+
67
+ ```bash
68
+ rake test
69
+ ```
70
+
71
+ To run tests for a specific gem:
72
+
73
+ ```bash
74
+ rake test:vident-phlex
75
+ ```
76
+
77
+ ### Building and Installing Gems
78
+
79
+ To build all gems:
80
+
81
+ ```bash
82
+ rake build
83
+ ```
84
+
85
+ To install all gems locally:
86
+
87
+ ```bash
88
+ rake install
89
+ ```
90
+
91
+ ## Contributing
92
+
93
+ 1. Fork the repository
94
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
95
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
96
+ 4. Push to the branch (`git push origin my-new-feature`)
97
+ 5. Create a new Pull Request
98
+
99
+ ## License
100
+
101
+ The gems are available as open source under the terms of the [MIT License](LICENSE.txt).
102
+
103
+ ---
104
+
105
+ # Component Documentation
106
+
107
+ ---
108
+
109
+ ## gem: vident-typed-view_component
110
+
111
+ # Vident::Typed::ViewComponent
112
+
113
+ Adds typed attributes to Vident ViewComponent components.
114
+
115
+ ```ruby
116
+ class ApplicationComponent < ::Vident::Typed::ViewComponent::Base
35
117
  end
36
118
  ```
37
119
 
38
- with ERB as follows:
120
+ For more details see [vident](https://github.com/stevegeek/vident).
39
121
 
40
- ```erb
41
- <%# app/components/greeter_component.html.erb %>
122
+ ### Examples
42
123
 
43
- <%# Rendering the `root` element creates a tag which has stimulus `data-*`s, a unique id & other attributes set. %>
44
- <%# The stimulus controller name (identifier) is derived from the component name, and then used to generate the relavent data attribute names. %>
124
+ Before we dive into a specific example note that there are some components implemented in `test/dummy/app/components`.
45
125
 
46
- <%= render root named_classes: {
47
- pre_click: "text-md text-gray-500", # named classes are exposed to Stimulus as `data-<controller>-<name>-class` attributes
48
- post_click: "text-xl text-blue-700",
49
- html_options: {class: "py-2"}
50
- } do |greeter| %>
51
- <%# `greeter` is the root element and exposes methods to generate stimulus targets and actions %>
52
- <input type="text"
53
- <%= greeter.as_target(:name) %>
54
- class="shadow appearance-none border rounded py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline">
55
-
56
- <%# Render the slot %>
57
- <%= trigger %>
58
-
59
- <%# you can also use the `target_tag` helper to render targets %>
60
- <%= greeter.target_tag(
61
- :span,
62
- :output,
63
- # Stimulus named classes can be referenced to set class attributes at render time
64
- class: "ml-4 #{greeter.named_classes(:pre_click)}"
65
- ) do %>
66
- ...
126
+ Try them out by starting Rails:
127
+
128
+ ```bash
129
+ cd test/dummy
130
+ bundle install
131
+ rails assets:precompile
132
+ rails s
133
+ ```
134
+
135
+ and visiting http://localhost:3000
136
+
137
+
138
+ ### A Vident component example (without Stimulus)
139
+
140
+ First is an example component that uses `Vident::Typed::ViewComponent::Base` but no Stimulus features.
141
+
142
+ It is an avatar component that can either be displayed as an image or as initials.
143
+
144
+ It supports numerous sizes and shapes and can optionally have a border. It also generates a cache key for use in fragment caching or etag generation.
145
+
146
+ ```ruby
147
+ class AvatarComponent < ::Vident::Typed::ViewComponent::Base
148
+ include ::Vident::Tailwind
149
+ include ::Vident::Caching
150
+
151
+ no_stimulus_controller
152
+ with_cache_key :attributes
153
+
154
+ attribute :url, String, allow_nil: true, allow_blank: false
155
+ attribute :initials, String, allow_blank: false
156
+
157
+ attribute :shape, Symbol, in: %i[circle square], default: :circle
158
+
159
+ attribute :border, :boolean, default: false
160
+
161
+ attribute :size, Symbol, in: %i[tiny small normal medium large x_large xx_large], default: :normal
162
+
163
+ private
164
+
165
+ def default_html_options
166
+ if image_avatar?
167
+ { class: "inline-block object-contain", src: url, alt: t(".image") }
168
+ else
169
+ { class: "inline-flex items-center justify-center bg-gray-500" }
170
+ end
171
+ end
172
+
173
+ def element_classes
174
+ [size_classes, shape_class, border? ? "border" : ""]
175
+ end
176
+
177
+ alias_method :image_avatar?, :url?
178
+
179
+ def shape_class
180
+ (shape == :circle) ? "rounded-full" : "rounded-md"
181
+ end
182
+
183
+ def size_classes
184
+ case size
185
+ when :tiny
186
+ "w-6 h-6"
187
+ when :small
188
+ "w-8 h-8"
189
+ when :medium
190
+ "w-12 h-12"
191
+ when :large
192
+ "w-14 h-14"
193
+ when :x_large
194
+ "sm:w-24 sm:h-24 w-16 h-16"
195
+ when :xx_large
196
+ "sm:w-32 sm:h-32 w-24 h-24"
197
+ else
198
+ "w-10 h-10"
199
+ end
200
+ end
201
+
202
+ def text_size_class
203
+ case size
204
+ when :tiny
205
+ "text-xs"
206
+ when :small
207
+ "text-xs"
208
+ when :medium
209
+ "text-lg"
210
+ when :large
211
+ "sm:text-xl text-lg"
212
+ when :extra_large
213
+ "sm:text-2xl text-xl"
214
+ else
215
+ "text-medium"
216
+ end
217
+ end
218
+ end
219
+ ```
220
+
221
+ ```erb
222
+ <%= render root(
223
+ element_tag: image_avatar? ? :img : :div,
224
+ html_options: default_html_options
225
+ ) do %>
226
+ <% unless image_avatar? %>
227
+ <span class="<%= text_size_class %> font-medium leading-none text-white"><%= initials %></span>
67
228
  <% end %>
68
229
  <% end %>
230
+
231
+ ```
232
+
233
+ Example usages:
234
+
235
+ ```erb
236
+ <!-- These will render -->
237
+ <%= render AvatarComponent.new(url: "https://someurl.com/avatar.jpg", initials: "AB" size: :large) %>
238
+ <%= render AvatarComponent.new(url: "https://someurl.com/avatar.jpg", html_options: {alt: "My alt text", class: "object-scale-down"}) %>
239
+ <%= render AvatarComponent.new(initials: "SG", size: :small) %>
240
+ <%= render AvatarComponent.new(initials: "SG", size: :large, html_options: {class: "border-2 border-red-600"}) %>
241
+
242
+ <!-- These will raise an error -->
243
+ <!-- missing initals -->
244
+ <%= render AvatarComponent.new(url: "https://someurl.com/avatar.jpg", size: :large) %>
245
+ <!-- initials blank -->
246
+ <%= render AvatarComponent.new(initials: "", size: :large) %>
247
+ <!-- invalid size -->
248
+ <%= render AvatarComponent.new(initials: "SG", size: :foo_bar) %>
249
+ ```
250
+
251
+
252
+ The following is rendered when used `render AvatarComponent.new(initials: "SG", size: :small, border: true)`:
253
+
254
+ ```html
255
+ <div class="avatar-component w-8 h-8 rounded-full border inline-flex items-center justify-center bg-gray-500" id="avatar-component-9790427-12">
256
+ <span class="text-xs font-medium leading-none text-white">SG</span>
257
+ </div>
258
+ ```
259
+
260
+ The following is rendered when used `render AvatarComponent.new(url: "https://i.pravatar.cc/300", initials: "AB", html_options: {alt: "My alt text", class: "block"})`:
261
+
262
+ ```html
263
+ <img src="https://i.pravatar.cc/300" alt="My alt text" class="avatar-component w-10 h-10 rounded-full object-contain block" id="avatar-component-7083941-11">
69
264
  ```
70
265
 
71
- Now, imagine we render it in a view, and render a `ButtonComponent` in the `trigger` slot:
266
+ ----
267
+
268
+ ![Example](examples/avatar.png)
269
+
270
+
271
+ ### Another ViewComponent + Vident example with Stimulus
272
+
273
+ Consider the following ERB that might be part of an application's views. The app uses `ViewComponent`, `Stimulus` and `Vident`.
274
+
275
+ The Greeter is a component that displays a text input and a button. When the button is clicked, the text input's value is
276
+ used to greet the user. At the same time the button changes to be a 'reset' button, which resets the greeting when clicked again.
277
+
278
+ ![ex1.gif](examples/ex1.gif)
72
279
 
73
280
  ```erb
281
+ <%# app/views/home/index.html.erb %>
282
+
283
+ <!-- ... -->
284
+
285
+ <!-- render the Greeter ViewComponent (that uses Vident) -->
74
286
  <%= render ::GreeterComponent.new(cta: "Hey!", html_options: {class: "my-4"}) do |greeter| %>
75
287
  <%# this component has a slot called `trigger` that renders a `ButtonComponent` (which also uses Vident) %>
76
288
  <% greeter.with_trigger(
@@ -91,6 +303,8 @@ Now, imagine we render it in a view, and render a `ButtonComponent` in the `trig
91
303
  }
92
304
  ) %>
93
305
  <% end %>
306
+
307
+ <!-- ... -->
94
308
  ```
95
309
 
96
310
  The output HTML of the above, using Vident, is:
@@ -118,193 +332,520 @@ The output HTML of the above, using Vident, is:
118
332
  </div>
119
333
  ```
120
334
 
121
- To see this example in more detail, see the [vident-typed-view_component](https://github.com/stevegeek/vident-typed-view_component/tree/main/test/dummy/app/components) test dummy app.
335
+ Let's look at the components in more detail.
122
336
 
123
- # Vident is a collection of gems
337
+ The main component is the `GreeterComponent`:
124
338
 
125
- The core gems are:
339
+ ```ruby
340
+ # app/components/greeter_component.rb
126
341
 
127
- - [`vident`](https://github.com/stevegeek/vident) to get the base functionality
128
- - [`vident-typed`](https://github.com/stevegeek/vident-typed) to optionally define typed attributes for your view components
342
+ class GreeterComponent < ::Vident::ViewComponent::Base
343
+ renders_one :trigger, ButtonComponent
344
+ end
345
+ ```
129
346
 
130
- Gems that provide support for `ViewComponent` and `Phlex`:
347
+ ```erb
348
+ <%# app/components/greeter_component.html.erb %>
131
349
 
132
- - [`vident-view_component`](https://github.com/stevegeek/vident-view_component) for using with `ViewComponent` and untyped attributes
133
- - [`vident-typed-view_component`](https://github.com/stevegeek/vident-typed-view_component) for using with `ViewComponent` and typed attributes
134
- - [`vident-phlex`](https://github.com/stevegeek/vident-phlex) for using with `Phlex` and untyped attributes
135
- - [`vident-typed-phlex`](https://github.com/stevegeek/vident-typed-phlex) for using with `Phlex` and typed attributes
350
+ <%# Rendering the `root` element creates a tag which has stimulus `data-*`s, a unique id & other attributes set. %>
351
+ <%# The stimulus controller name (identifier) is derived from the component name, and then used to generate the relavent data attribute names. %>
136
352
 
137
- There is also:
353
+ <%= render root named_classes: {
354
+ pre_click: "text-md text-gray-500", # named classes are exposed to Stimulus as `data-<controller>-<n>-class` attributes
355
+ post_click: "text-xl text-blue-700",
356
+ html_options: {class: "py-2"}
357
+ } do |greeter| %>
138
358
 
139
- - [`vident-typed-minitest`](https://github.com/stevegeek/vident-typed-minitest) to get some test helpers for typed attributes (auto generates inputs to test attributes)
140
- - [`vident-better_html`](https://github.com/stevegeek/vident-better_html) to support `better_html` if you use it in your Rails app
141
- - [`vident-tailwind`](https://github.com/stevegeek/vident-tailwind) to get all the benefits of the amazing [`tailwind_merge`](https://github.com/gjtorikian/tailwind_merge/).
359
+ <%# `greeter` is the root element and exposes methods to generate stimulus targets and actions %>
360
+ <input type="text"
361
+ <%= greeter.as_target(:name) %>
362
+ class="shadow appearance-none border rounded py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline">
363
+
364
+ <%# Render the slot %>
365
+ <%= trigger %>
366
+
367
+ <%# you can also use the `target_tag` helper to render targets %>
368
+ <%= greeter.target_tag(
369
+ :span,
370
+ :output,
371
+ # Stimulus named classes can be referenced to set class attributes at render time
372
+ class: "ml-4 #{greeter.named_classes(:pre_click)}"
373
+ ) do %>
374
+ ...
375
+ <% end %>
376
+ <% end %>
377
+
378
+ ```
379
+
380
+ ```js
381
+ // app/components/greeter_component_controller.js
382
+
383
+ import { Controller } from "@hotwired/stimulus"
384
+
385
+ // This is a Stimulus controller that is automatically registered for the `GreeterComponent`
386
+ // and is 'sidecar' to the component. You can see that while in the ERB we use Ruby naming conventions
387
+ // with snake_case Symbols, here they are converted to camelCase names. We can also just use camelCase
388
+ // in the ERB if we want.
389
+ export default class extends Controller {
390
+ static targets = [ "name", "output" ]
391
+ static classes = [ "preClick", "postClick" ]
392
+
393
+ greet() {
394
+ this.clicked = !this.clicked;
395
+ this.outputTarget.classList.toggle(this.preClickClasses, !this.clicked);
396
+ this.outputTarget.classList.toggle(this.postClickClasses, this.clicked);
397
+
398
+ if (this.clicked)
399
+ this.outputTarget.textContent = `Hello, ${this.nameTarget.value}!`
400
+ else
401
+ this.clear();
402
+ }
403
+
404
+ clear() {
405
+ this.outputTarget.textContent = '...';
406
+ this.nameTarget.value = '';
407
+ }
408
+ }
409
+ ```
410
+
411
+ The slot renders a `ButtonComponent` component:
412
+
413
+ ```ruby
414
+ # app/components/button_component.rb
415
+
416
+ class ButtonComponent < ::Vident::Typed::ViewComponent::Base
417
+ # The attributes can specify an expected type, a default value and if nil is allowed.
418
+ attribute :after_clicked, String, default: "Greeted!"
419
+ attribute :before_clicked, String, allow_nil: false
420
+
421
+ # This example is a templateless ViewComponent.
422
+ def call
423
+ # The button is rendered as a <button> tag with an click action on its own controller.
424
+ render root(
425
+ element_tag: :button,
426
+
427
+ # We can define actions as arrays of Symbols, or pass manually manually crafted strings.
428
+ # Here we specify the action name only, implying an action on the current components controller
429
+ # and the default event type of `click`.
430
+ actions: [:change_message],
431
+ # Alternatively: [:click, :change_message] or ["click", "changeMessage"] or even "click->button-component#changeMessage"
432
+
433
+ # A couple of data values are also set which will be available to the controller
434
+ data_maps: [{after_clicked_message: after_clicked, before_clicked_message: before_clicked}],
435
+
436
+ # The <button> tag has a default styling set directly on it. Note that
437
+ # if not using utility classes, you can style the component using its
438
+ # canonical class name (which is equal to the component's stimulus identifier),
439
+ # in this case `button-component`.
440
+ html_options: {class: "ml-4 whitespace-no-wrap bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"}
441
+ ) do
442
+ @before_clicked
443
+ end
444
+ end
445
+ end
446
+ ```
447
+
448
+ ```js
449
+ // app/components/button_component_controller.js
450
+
451
+ import { Controller } from "@hotwired/stimulus"
452
+
453
+ export default class extends Controller {
454
+ // The action is in camelCase.
455
+ changeMessage() {
456
+ this.clicked = !this.clicked;
457
+ // The data attributes have their naming convention converted to camelCase.
458
+ this.element.textContent = this.clicked ? this.data.get("afterClickedMessage") : this.data.get("beforeClickedMessage");
459
+ }
460
+ }
461
+
462
+ ```
463
+
464
+ ### Usage
465
+ How to use my plugin.
466
+
467
+ ### Installation
468
+ Add this line to your application's Gemfile:
469
+
470
+ ```ruby
471
+ gem "vident-typed-view_component"
472
+ ```
473
+
474
+ And then execute:
475
+ ```bash
476
+ $ bundle
477
+ ```
478
+
479
+ Or install it yourself as:
480
+ ```bash
481
+ $ gem install vident-typed-view_component
482
+ ```
483
+
484
+ ---
485
+
486
+
487
+ ## gem: vident-view_component
488
+
489
+ # Vident::ViewComponent
142
490
 
491
+ [ViewComponent](https://viewcomponent.org/) powered [Vident](https://github.com/stevegeek/vident) components.
143
492
 
144
- # Things still to do...
493
+ ```ruby
494
+ class ApplicationComponent < ::Vident::ViewComponent::Base
495
+ end
496
+ ```
497
+
498
+ For more details see [vident](https://github.com/stevegeek/vident).
499
+
500
+ ### Examples
501
+
502
+ Before we dive into a specific example note that there are some components implemented in the `test/dummy/app/components`.
503
+
504
+ Try them out by starting Rails:
145
505
 
146
- This is a work in progress. Here's what's left to do for first release:
506
+ ```bash
507
+ cd test/dummy
508
+ bundle install
509
+ rails assets:precompile
510
+ rails s
511
+ ```
512
+
513
+ and visiting http://localhost:3000
514
+
515
+
516
+ ### A Vident component example (without Stimulus)
147
517
 
148
- - Iterate on the interfaces and functionality
149
- - Add tests
150
- - Make the gem more configurable to fit more use cases
151
- - Create an example library of a few components for some design system
152
- - Create a demo app with `lookbook` and those components
153
- - Add more documentation
518
+ First is an example component that uses `Vident::ViewComponent::Base` but no Stimulus features.
154
519
 
155
- # About Vident
520
+ It is an avatar component that can either be displayed as an image or as initials. It supports numerous sizes and shapes and can optionally have a border. It also generates a cache key for use in fragment caching or etag generation.
156
521
 
157
- ## What does Vident provide?
522
+ ```ruby
523
+ class AvatarComponent < ::Vident::ViewComponent::Base
524
+ include ::Vident::Tailwind
525
+ include ::Vident::Caching
526
+
527
+ no_stimulus_controller
528
+ with_cache_key :attributes
529
+
530
+ attribute :url, allow_nil: true
531
+ attribute :initials, allow_nil: false
532
+
533
+ attribute :shape, default: :circle
534
+
535
+ attribute :border, default: false
536
+
537
+ attribute :size, default: :normal
538
+
539
+ private
540
+
541
+ def default_html_options
542
+ if image_avatar?
543
+ { class: "inline-block object-contain", src: url, alt: t(".image") }
544
+ else
545
+ { class: "inline-flex items-center justify-center bg-gray-500" }
546
+ end
547
+ end
548
+
549
+ def element_classes
550
+ [size_classes, shape_class, border? ? "border" : ""]
551
+ end
552
+
553
+ alias_method :image_avatar?, :url?
554
+
555
+ def shape_class
556
+ (shape == :circle) ? "rounded-full" : "rounded-md"
557
+ end
558
+
559
+ def size_classes
560
+ case size
561
+ when :tiny
562
+ "w-6 h-6"
563
+ when :small
564
+ "w-8 h-8"
565
+ when :medium
566
+ "w-12 h-12"
567
+ when :large
568
+ "w-14 h-14"
569
+ when :x_large
570
+ "sm:w-24 sm:h-24 w-16 h-16"
571
+ when :xx_large
572
+ "sm:w-32 sm:h-32 w-24 h-24"
573
+ else
574
+ "w-10 h-10"
575
+ end
576
+ end
577
+
578
+ def text_size_class
579
+ case size
580
+ when :tiny
581
+ "text-xs"
582
+ when :small
583
+ "text-xs"
584
+ when :medium
585
+ "text-lg"
586
+ when :large
587
+ "sm:text-xl text-lg"
588
+ when :extra_large
589
+ "sm:text-2xl text-xl"
590
+ else
591
+ "text-medium"
592
+ end
593
+ end
594
+ end
595
+ ```
158
596
 
159
- - Base classes for your `ViewComponent` components or `Phlex` components that provides a helper to create the
160
- all important 'root' element component (can be used with templated or template-less components).
597
+ ```erb
598
+ <%= render root(
599
+ element_tag: image_avatar? ? :img : :div,
600
+ html_options: default_html_options
601
+ ) do %>
602
+ <% unless image_avatar? %>
603
+ <span class="<%= text_size_class %> font-medium leading-none text-white"><%= initials %></span>
604
+ <% end %>
605
+ <% end %>
606
+ ```
161
607
 
162
- - implementations of these root components for creating the 'root' element in your view components. Similar to `Primer::BaseComponent` but
163
- exposes a simple API for configuring and adding Stimulus controllers, targets and actions. The root component also handles deduplication
164
- of classes, creating a unique ID, setting the element tag type, handling possible overrides set at the render site, and determining stimulus controller identifiers etc
608
+ Example usages:
165
609
 
166
- - a way to define attributes for your components, either typed or untyped, with default values and optional validation.
610
+ ```erb
611
+ <%= render AvatarComponent.new(url: "https://someurl.com/avatar.jpg", initials: "AB" size: :large) %>
612
+ <%= render AvatarComponent.new(url: "https://someurl.com/avatar.jpg", html_options: {alt: "My alt text", class: "object-scale-down"}) %>
613
+ <%= render AvatarComponent.new(initials: "SG", size: :small) %>
614
+ <%= render AvatarComponent.new(initials: "SG", size: :large, html_options: {class: "border-2 border-red-600"}) %>
615
+ ```
167
616
 
168
- ### Various utilities
617
+ The following is rendered when used `render AvatarComponent.new(initials: "SG", size: :small, border: true)`:
169
618
 
170
- Such as...
619
+ ```html
620
+ <div class="avatar-component w-8 h-8 rounded-full border inline-flex items-center justify-center bg-gray-500" id="avatar-component-9790427-12">
621
+ <span class="text-xs font-medium leading-none text-white">SG</span>
622
+ </div>
623
+ ```
171
624
 
172
- - for Taiwind users, a mixin for your vident component which uses [tailwind_merge](https://github.com/gjtorikian/tailwind_merge) to merge TailwindCSS classes
173
- so you can easily override classes when rendering a component.
174
- - a mixin for your Vident Components which provides a `#cache_key` method that can be used to generate a cache key for
175
- fragment caching or etag generation.
176
- - a test helper for your typed Vident ViewComponents which can be used to generate good and bad attribute/params/inputs
625
+ The following is rendered when used `render AvatarComponent.new(url: "https://i.pravatar.cc/300", initials: "AB", html_options: {alt: "My alt text", class: "block"})`:
177
626
 
178
- ## All the Features...
627
+ ```html
628
+ <img src="https://i.pravatar.cc/300" alt="My alt text" class="avatar-component w-10 h-10 rounded-full object-contain block" id="avatar-component-7083941-11">
629
+ ```
179
630
 
180
- - use Vident with `ViewComponent` or `Phlex` or your own view component system
181
- - A helper to create the root HTML element for your component, which then handles creation of attributes.
182
- - Component arguments are defined using the `attribute` method which allows you to define default values, (optionally) types and
183
- if blank or nil values should be allowed.
184
- - You can use the same component in multiple contexts and configure the root element differently in each context by passing
185
- options to the component when instantiating it.
186
- - Stimulus support is built in and sets a default controller name based on the component name.
187
- - Stimulus actions, targets and classes can be setup using a simple DSL to avoid hand crafting the data attributes.
188
- - Since data attribute names are generated from the component class name, you can rename easily refactor and move components without
189
- having to update the data attributes in your views.
190
- - Components are rendered with useful class names and IDs to make debugging easier (autogenerated IDs are 'random' but deterministic so they
191
- are the same each time a given view is rendered to avoid content changing/Etag changing).
192
- - (experimental) Support for fragment caching of components (`Vident::Caching` and `Vident::<ViewComponent | Phlex>::Caching`... implementation has caveats)
193
- - (experimental) A test helper to make testing components easier by utilising type information from the component arguments to render
194
- automatically configured good and bad examples of the component.
195
- - (experimental) support for `better_html`
631
+ ----
196
632
 
633
+ ![Example](examples/avatar.png)
197
634
 
198
- ## Installation
635
+ ### Usage
636
+ How to use my plugin.
199
637
 
200
- This gem (`vident`) provides only base functionality but there are a number of gems that provide additional functionality
201
- or an "out of the box" experience.
638
+ ### Installation
639
+ Add this line to your application's Gemfile:
202
640
 
203
- It's a "pick your own adventure" approach. You decide what frameworks and features you want to use
204
- and add the gems as needed.
641
+ ```ruby
642
+ gem "vident-view_component"
643
+ ```
205
644
 
206
- First, add this line to your application's Gemfile:
645
+ And then execute:
646
+ ```bash
647
+ $ bundle
648
+ ```
207
649
 
208
- ```ruby
209
- gem 'vident'
650
+ Or install it yourself as:
651
+ ```bash
652
+ $ gem install vident-view_component
210
653
  ```
211
654
 
212
- Then go on to choose the gems you want to use:
655
+ ---
656
+
657
+ ## gem: vident-better_html
658
+
659
+ # Vident::BetterHtml
660
+ Short description and motivation.
213
661
 
214
- #### Q1. Do you want to use [`ViewComponent`](https://viewcomponent.org/) or [`Phlex`](https://www.phlex.fun/) for your view components?
662
+ ### Usage
663
+ How to use my plugin.
215
664
 
216
- For ViewComponent use:
665
+ ```ruby
666
+ BetterHtml.config = BetterHtml::Config.new(YAML.load(File.read(".better-html.yml")))
667
+
668
+ BetterHtml.configure do |config|
669
+ config.template_exclusion_filter = proc { |filename| !filename.start_with?(Rails.root.to_s) }
670
+ end
671
+ # ViewComponent needs to do this hack to work in certain cases
672
+ # see https://github.com/Shopify/better-html/pull/98
673
+ class BetterHtml::HtmlAttributes
674
+ alias_method :to_s_without_html_safe, :to_s
675
+
676
+ def to_s
677
+ to_s_without_html_safe.html_safe
678
+ end
679
+ end
680
+ ```
681
+
682
+ ### Installation
683
+ Add this line to your application's Gemfile:
684
+
685
+ ```ruby
686
+ gem "vident-better_html"
687
+ ```
217
688
 
218
- - [`vident-view_component`](https://github.com/stevegeek/vident-view_component)
689
+ And then execute:
690
+ ```bash
691
+ $ bundle
692
+ ```
219
693
 
220
- For Phlex use:
694
+ Or install it yourself as:
695
+ ```bash
696
+ $ gem install vident-better_html
697
+ ```
221
698
 
222
- - [`vident-phlex`](https://github.com/stevegeek/vident-phlex)
699
+ ---
223
700
 
701
+ ## gem: vident-phlex
224
702
 
225
- Note: you can also use both in the same app.
703
+ # Vident::Phlex
226
704
 
227
- For example, if you want to use ViewComponent and Phlex in the same app, you might end up with:
705
+ [Phlex](https://phlex.fun/) powered [Vident](https://github.com/stevegeek/vident) components.
228
706
 
229
707
  ```ruby
230
- gem 'vident'
231
- gem 'vident-view_component'
232
- gem 'vident-phlex'
708
+ class ApplicationComponent < ::Vident::Phlex::HTML
709
+ end
233
710
  ```
234
711
 
235
- #### Q2. Do you want to build components where the attributes have runtime type checking (powered by [`dry-types`](https://github.com/dry-rb/dry-types))?
712
+ For more details see [vident](https://github.com/stevegeek/vident).
713
+
714
+ ### Usage
715
+ How to use my plugin.
236
716
 
237
- If yes, then add `vident-typed` to your Gemfile:
717
+ ### Installation
718
+ Add this line to your application's Gemfile:
238
719
 
239
720
  ```ruby
240
- gem 'vident-typed'
721
+ gem "vident-phlex"
722
+ ```
723
+
724
+ And then execute:
725
+ ```bash
726
+ $ bundle
727
+ ```
728
+
729
+ Or install it yourself as:
730
+ ```bash
731
+ $ gem install vident-phlex
241
732
  ```
242
733
 
243
- and then use the relavent `*-typed-*` gems for your chosen view component system:
734
+ ---
735
+
736
+ ## gem: vident-tailwind
244
737
 
245
- - use [`vident-typed-view_component`](https://github.com/stevegeek/vident-typed-view_component)
246
- - and/or [`vident-typed-phlex`](https://github.com/stevegeek/vident-typed-phlex)
738
+ # Vident::Tailwind
739
+ Short description and motivation.
247
740
 
248
- Note you must also include the gem for the view component system you are using.
741
+ ### Usage
742
+ How to use my plugin.
249
743
 
250
- For example, for ViewComponent, you might end up with:
744
+ ### Installation
745
+ Add this line to your application's Gemfile:
251
746
 
252
747
  ```ruby
253
- gem 'vident'
254
- gem 'vident-view_component'
255
- gem 'vident-typed'
256
- gem 'vident-typed-view_component'
748
+ gem "vident-tailwind"
749
+ ```
750
+
751
+ And then execute:
752
+ ```bash
753
+ $ bundle
754
+ ```
755
+
756
+ Or install it yourself as:
757
+ ```bash
758
+ $ gem install vident-tailwind
257
759
  ```
258
760
 
259
- #### Q3. Do you use or want to use [BetterHTML](https://github.com/Shopify/better-html) in your Rails project?
761
+ ---
762
+
763
+ ## gem: vident-typed-minitest
764
+
765
+ # Vident::Typed::Minitest
766
+ Short description and motivation.
767
+
768
+ ### Usage
769
+ How to use my plugin.
260
770
 
261
- If yes, then include [`vident-better_html`](https://github.com/stevegeek/vident-better_html) in your Gemfile alongside `better_html` and your vident gems of choice.
771
+ ### Installation
772
+ Add this line to your application's Gemfile:
262
773
 
263
774
  ```ruby
264
- ...
265
- gem 'better_html'
266
- gem 'vident-better_html'
775
+ gem "vident-typed-minitest"
776
+ ```
777
+
778
+ And then execute:
779
+ ```bash
780
+ $ bundle
781
+ ```
782
+
783
+ Or install it yourself as:
784
+ ```bash
785
+ $ gem install vident-typed-minitest
267
786
  ```
268
787
 
269
- Note that `vident-better_html` automatically enables `better_html` support in Vident root components.
788
+ ---
789
+
790
+ ## gem: vident-typed-phlex
270
791
 
271
- ### Q4. Do you use or want to use [TailwindCSS](https://tailwindcss.com/)?
792
+ # Vident::Typed::Phlex
272
793
 
273
- If yes, then consider adding [`vident-tailwind`](https://github.com/stevegeek/vident-tailwind) to your Gemfile alongside your vident gems of choice.
794
+ Adds typed attributes to Vident Phlex based components.
274
795
 
275
796
  ```ruby
276
- ...
277
- gem 'vident-tailwind'
797
+ class ApplicationComponent < ::Vident::Typed::Phlex::HTML
798
+ end
278
799
  ```
279
800
 
280
- When creating your components you can then include `Vident::Tailwind` to get all the benefits of the amazing [`tailwind_merge`](https://github.com/gjtorikian/tailwind_merge/).
801
+ For more details see [vident](https://github.com/stevegeek/vident).
281
802
 
282
- ### Q5. Did none of the above gems suit your needs?
803
+ ### Usage
804
+ How to use my plugin.
283
805
 
284
- You can always just use base `vident` gems and then roll your own solutions:
806
+ ### Installation
807
+ Add this line to your application's Gemfile:
285
808
 
286
- - [`vident`](https://github.com/stevegeek/vident) to get the base functionality to mix with your own view component system
287
- - [`vident-typed`](https://github.com/stevegeek/vident-typed) to define typed attributes for your own view component system
809
+ ```ruby
810
+ gem "vident-typed-phlex"
811
+ ```
288
812
 
813
+ And then execute:
814
+ ```bash
815
+ $ bundle
816
+ ```
289
817
 
290
- ## Documentation
818
+ Or install it yourself as:
819
+ ```bash
820
+ $ gem install vident-typed-phlex
821
+ ```
291
822
 
292
- See the [docs](docs/) directory and visit the individual gem pages for more information.
823
+ ---
293
824
 
294
- ## Development
295
825
 
296
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
826
+ ## gem: vident-typed
297
827
 
298
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
828
+ # Vident::Typed
829
+ Short description and motivation.
299
830
 
300
- ## Contributing
831
+ ### Usage
832
+ How to use my plugin.
301
833
 
302
- Bug reports and pull requests are welcome on GitHub at https://github.com/stevegeek/vident. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/vident/blob/master/CODE_OF_CONDUCT.md).
834
+ ### Installation
835
+ Add this line to your application's Gemfile:
303
836
 
304
- ## License
837
+ ```ruby
838
+ gem "vident-typed"
839
+ ```
305
840
 
306
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
841
+ And then execute:
842
+ ```bash
843
+ $ bundle
844
+ ```
307
845
 
308
- ## Code of Conduct
846
+ Or install it yourself as:
847
+ ```bash
848
+ $ gem install vident-typed
849
+ ```
309
850
 
310
- Everyone interacting in the Vident project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/vident/blob/master/CODE_OF_CONDUCT.md).
851
+ ---