vident 0.8.0 → 0.10.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: 6907ba81655f5cf18c500edcdfa43c8786d8b2463573a1dadd0dd51ba1637ea3
4
- data.tar.gz: 72964008e3a0c64172726f4edfe2ba030f66018a08713e8bad529eae4dda45d7
3
+ metadata.gz: 95a2b00a3176fdc3fbd06569b20665b3e1d1bc8032758b0945d2dc58990d2fa5
4
+ data.tar.gz: e946108732b2abd5af47e5437b13e72983838cad032fb6b5c4c460504dc4cf8c
5
5
  SHA512:
6
- metadata.gz: dea9a3d4e70478870b829fe050cfbbcd89dad15866a4a4334d8661d217f56e30a47b81285f279008bfaf762a406e7356ca33d56c607e98a34ddde6b2bf26df13
7
- data.tar.gz: ea963a8ba620e0c510c8e4fadf02eb0293159398c576dbd9554bffc01fd7bb930e7b9d31e2011710ab7a4c41a2929a2e8964cceee2bdfe35827a8dedcad148b4
6
+ metadata.gz: 3fd4da39749c72675965bf507287db253b305a2203c29a323a6342fa593709c06480ce1a3671e6044b562503853b78c56ca9a698e5962217a4a1becf23a29722
7
+ data.tar.gz: 11e8f9e658bb2ff4459719a205ae13bcecb7f2c65b1e4d89edb718879d5a54fe947922c0328cf5c15b19f066d46695250a935599fa37fcfd8de0fbfb9e2975af
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.3.0
data/.standard.yml ADDED
@@ -0,0 +1,3 @@
1
+ # For available configuration options, see:
2
+ # https://github.com/testdouble/standard
3
+ ruby_version: 3.3
data/CHANGELOG.md ADDED
@@ -0,0 +1,108 @@
1
+
2
+ # Change Log
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](http://keepachangelog.com/)
6
+ and this project adheres to [Semantic Versioning](http://semver.org/).
7
+
8
+
9
+ ## [Unreleased]
10
+
11
+ ### Added
12
+
13
+ ### Changed
14
+
15
+ ### Fixed
16
+
17
+ ## [0.10.0] - 2024-02-21
18
+
19
+ ### Added
20
+
21
+ - `outlets` option for components, used to specify Stimulus outlets
22
+
23
+ ## [0.9.0] - 2023-08-11
24
+
25
+ ### Added
26
+
27
+ - `#cache_key` support is now part of the core gem, and can be added to components using `Vident::Caching` module
28
+
29
+ ## [0.8.0] - 2023-03-31
30
+
31
+ ### Added
32
+
33
+ - new gems for Vident related functionality, eg `vident-typed` and `vident-tailwind`
34
+ - `vident` is now the core gem which can be used with any component system. Gems for Phlex and ViewComponent are available, `vident-phlex` and `vident-view_component`, and `vident-typed-phlex` and `vident-typed-view_component` are available with typed attributes support.
35
+
36
+ ### Changed
37
+
38
+ - removed functionality for `better_html`, `dry-types`, `view_component`, and `phlex` from the core gem
39
+ - gem is now a Rails Engine and supports eager and autoloading
40
+
41
+ ### Fixed
42
+
43
+ - Fix untyped attributes inheritance
44
+
45
+ ## [0.7.0] - 2023-03-08
46
+
47
+ ### Added
48
+
49
+ - new `Vident::Tailwind` module which uses [tailwind_merge](https://github.com/gjtorikian/tailwind_merge) to merge TailwindCSS classes
50
+
51
+ ### Changed
52
+
53
+ - Removed a dependency on intenal constants from `phlex`
54
+
55
+ ## [0.6.3] - 2023-03-03
56
+
57
+ ### Fixed
58
+
59
+ - Fix for changes to HTML tag collection in Phlex
60
+
61
+
62
+ ## [0.6.2] - 2023-02-23
63
+
64
+ ### Fixed
65
+
66
+ - Element tag options are not set when no ID is provided
67
+
68
+
69
+ ## [0.6.1] - 2023-02-20
70
+
71
+ ### Fixed
72
+
73
+ - `better_html` support fix for aliased dsl methods
74
+
75
+
76
+ ## [0.6.0] - 2023-02-20
77
+
78
+ ### Added
79
+
80
+ - Experimental support for `better_html` in the root components (the stimulus attributes are generated with `html_attributes`)
81
+
82
+
83
+
84
+ ## [0.5.1] - 2023-02-17
85
+
86
+ ### Added
87
+
88
+ - N/A
89
+
90
+ ### Changed
91
+
92
+ - N/A
93
+
94
+ ### Fixed
95
+
96
+ - Typed attributes was not always using custom coercion methods if they were defined
97
+
98
+ ### Removed
99
+
100
+ - N/A
101
+
102
+ ### Deprecated
103
+
104
+ - N/A
105
+
106
+ ### Security
107
+
108
+ - N/A
@@ -0,0 +1,84 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
6
+
7
+ We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
8
+
9
+ ## Our Standards
10
+
11
+ Examples of behavior that contributes to a positive environment for our community include:
12
+
13
+ * Demonstrating empathy and kindness toward other people
14
+ * Being respectful of differing opinions, viewpoints, and experiences
15
+ * Giving and gracefully accepting constructive feedback
16
+ * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
17
+ * Focusing on what is best not just for us as individuals, but for the overall community
18
+
19
+ Examples of unacceptable behavior include:
20
+
21
+ * The use of sexualized language or imagery, and sexual attention or
22
+ advances of any kind
23
+ * Trolling, insulting or derogatory comments, and personal or political attacks
24
+ * Public or private harassment
25
+ * Publishing others' private information, such as a physical or email
26
+ address, without their explicit permission
27
+ * Other conduct which could reasonably be considered inappropriate in a
28
+ professional setting
29
+
30
+ ## Enforcement Responsibilities
31
+
32
+ Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
33
+
34
+ Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
35
+
36
+ ## Scope
37
+
38
+ This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
39
+
40
+ ## Enforcement
41
+
42
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at stevegeek@gmail.com. All complaints will be reviewed and investigated promptly and fairly.
43
+
44
+ All community leaders are obligated to respect the privacy and security of the reporter of any incident.
45
+
46
+ ## Enforcement Guidelines
47
+
48
+ Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
49
+
50
+ ### 1. Correction
51
+
52
+ **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
53
+
54
+ **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
55
+
56
+ ### 2. Warning
57
+
58
+ **Community Impact**: A violation through a single incident or series of actions.
59
+
60
+ **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
61
+
62
+ ### 3. Temporary Ban
63
+
64
+ **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
65
+
66
+ **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
67
+
68
+ ### 4. Permanent Ban
69
+
70
+ **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
71
+
72
+ **Consequence**: A permanent ban from any sort of public interaction within the community.
73
+
74
+ ## Attribution
75
+
76
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0,
77
+ available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
78
+
79
+ Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
80
+
81
+ [homepage]: https://www.contributor-covenant.org
82
+
83
+ For answers to common questions about this code of conduct, see the FAQ at
84
+ https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 Stephen Ierodiaconou
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Vident** is a collection of gems that help you create **flexible** & **maintainable** component libraries for your Rails application.
4
4
 
5
- <a href="https://github.com/stevegeek/vident"><img alt="Vident logo" src="https://raw.githubusercontent.com/stevegeek/vident/main/logo-by-sd-256-colors.png" width="180" /></a>
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>
6
6
 
7
7
  Vident also provides a neat Ruby DSL to make wiring up **Stimulus easier & less error prone** in your view components.
8
8
 
@@ -11,243 +11,69 @@ Vident also provides a neat Ruby DSL to make wiring up **Stimulus easier & less
11
11
  # Motivation
12
12
 
13
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
14
+ targets and actions error-prone and tedious. Vident aims to make this process easier
15
15
  and keep me thinking in Ruby.
16
16
 
17
- I have been using Vident with `ViewComponent` in production apps for a while now (and recently `Phlex`!)
18
- and it has been constantly evolving.
17
+ Vident has been used with `ViewComponent` and `Phlex` in production apps for a while now
18
+ but is still evolving.
19
19
 
20
- This gem is a work in progress and I would love to get your feedback and contributions!
20
+ I would love to get your feedback and contributions!
21
21
 
22
+ ## Example
22
23
 
24
+ The Greeter ViewComponent (that uses Vident):
23
25
 
24
- **The docs below need updating**
26
+ ![docs/images/ex1.gif](docs/images/ex1.gif)
25
27
 
26
-
27
-
28
- ## What does Vident provide?
29
-
30
- - `Vident::Component`: A mixin for your `ViewComponent` components or `Phlex` components that provides the a helper to create the
31
- root element component (in templated or template-less components).
32
-
33
- - `Vident::TypedComponent`: like `Vident::Component` but uses `dry-types` to define typed attributes for your components.
34
-
35
- ### Various utilities
36
-
37
- - `Vident::Tailwind`: a mixin for your vident component which uses [tailwind_merge](https://github.com/gjtorikian/tailwind_merge) to merge TailwindCSS classes
38
- so you can easily override classes when rendering a component.
39
-
40
- - `Vident::Caching::CacheKey`: a mixin for your vident component which provides a `cache_key` method that can be used to generate a cache key for
41
- fragment caching or etag generation.
42
-
43
- - `Vident::RootComponent::*` which are components for creating the 'root' element in your view components. Similar to `Primer::BaseComponent` but
44
- exposes a simple API for configuring and adding Stimulus controllers, targets and actions. Normally you create these
45
- using the `root` helper method on `Vident::Component`/`Vident::TypedComponent`.
46
-
47
- # Features
48
-
49
- - A helper to create the root HTML element for your component, which then handles creation of attributes.
50
- - Component arguments are defined using the `attribute` method which allows you to define default values, (optionally) types and
51
- if blank or nil values should be allowed.
52
- - You can use the same component in multiple contexts and configure the root element differently in each context by passing
53
- options to the component when instantiating it.
54
- - Stimulus support is built in and sets a default controller name based on the component name.
55
- - Stimulus actions, targets and classes can be setup using a simple DSL to avoid hand crafting the data attributes.
56
- - Since data attribute names are generated from the component class name, you can rename easily refactor and move components without
57
- having to update the data attributes in your views.
58
- - Components are rendered with useful class names and IDs to make debugging easier (autogenerated IDs are 'random' but deterministic so they
59
- are the same each time a given view is rendered to avoid content changing/Etag changing).
60
- - (experimental) Support for fragment caching of components (only with ViewComponent and with caveats)
61
- - (experimental) A test helper to make testing components easier by utilising type information from the component arguments to render
62
- automatically configured good and bad examples of the component.
63
- - (experimental) support for `better_html`
64
-
65
-
66
- ## Things still to do...
67
-
68
- This is a work in progress. Here's what's left to do for first release:
69
-
70
- - Iterate on the interfaces and functionality
71
- - Add tests
72
- - Make the gem more configurable to fit more use cases
73
- - Create an example library of a few components for some design system
74
- - Create a demo app with `lookbook` and those components
75
- - Add more documentation
76
- - split `vident` into `vident` + `vident-rails` gems (and maybe `vident-rspec`) (Phlex can be used outside of Rails)
77
- - possibly also split into `vident-phlex` and `vident-view_component` gems ?
78
-
79
-
80
-
81
- # Examples
82
-
83
- Before we dive into a specific example note that there are some components implemented with
84
- both ViewComponent and Phlex (with and without Vident) in the `test/dummy`.
85
- - https://github.com/stevegeek/vident/tree/main/test/dummy/app/components
86
- - https://github.com/stevegeek/vident/tree/main/test/dummy/app/views
87
-
88
- Start Rails:
89
-
90
- ```bash
91
- cd test/dummy
92
- bundle install
93
- rails assets:precompile
94
- rails s
95
- ```
96
-
97
- and visit http://localhost:3000
98
-
99
-
100
- ## A Vident component example (without Stimulus)
101
-
102
- First is an example component that uses `Vident::TypedComponent` but no Stimulus features.
103
-
104
- It is an avatar component that can either be displayed as an image or as initials.
105
-
106
- 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.
28
+ Consider a component, the `GreeterComponent`:
107
29
 
108
30
  ```ruby
109
- class AvatarComponent < ViewComponent::Base
110
- include ::Vident::TypedComponent
111
- include ::Vident::Tailwind
112
- include ::Vident::Caching::CacheKey
113
-
114
- no_stimulus_controller
115
- with_cache_key :attributes
116
-
117
- attribute :url, String, allow_nil: true, allow_blank: false
118
- attribute :initials, String, allow_blank: false
119
-
120
- attribute :shape, Symbol, in: %i[circle square], default: :circle
121
-
122
- attribute :border, :boolean, default: false
123
-
124
- attribute :size, Symbol, in: %i[tiny small normal medium large x_large xx_large], default: :normal
125
-
126
- private
127
-
128
- def html_options
129
- if image_avatar?
130
- { class: "inline-block object-contain", src: url, alt: t(".image") }
131
- else
132
- { class: "inline-flex items-center justify-center bg-gray-500" }
133
- end
134
- end
135
-
136
- def element_classes
137
- [size_classes, shape_class, border? ? "border" : ""]
138
- end
139
-
140
- alias_method :image_avatar?, :url?
141
-
142
- def shape_class
143
- (shape == :circle) ? "rounded-full" : "rounded-md"
144
- end
145
-
146
- def size_classes
147
- case size
148
- when :tiny
149
- "w-6 h-6"
150
- when :small
151
- "w-8 h-8"
152
- when :medium
153
- "w-12 h-12"
154
- when :large
155
- "w-14 h-14"
156
- when :x_large
157
- "sm:w-24 sm:h-24 w-16 h-16"
158
- when :xx_large
159
- "sm:w-32 sm:h-32 w-24 h-24"
160
- else
161
- "w-10 h-10"
162
- end
163
- end
164
-
165
- def text_size_class
166
- case size
167
- when :tiny
168
- "text-xs"
169
- when :small
170
- "text-xs"
171
- when :medium
172
- "text-lg"
173
- when :large
174
- "sm:text-xl text-lg"
175
- when :extra_large
176
- "sm:text-2xl text-xl"
177
- else
178
- "text-medium"
179
- end
180
- end
181
- end
182
- ```
183
-
184
- ```erb
185
- <%= render root(
186
- element_tag: image_avatar? ? :img : :div,
187
- html_options: html_options
188
- ) do %>
189
- <% unless image_avatar? %>
190
- <span class="<%= text_size_class %> font-medium leading-none text-white"><%= initials %></span>
191
- <% end %>
192
- <% end %>
31
+ # app/components/greeter_component.rb
193
32
 
33
+ class GreeterComponent < ::Vident::ViewComponent::Base
34
+ renders_one :trigger, ButtonComponent
35
+ end
194
36
  ```
195
37
 
196
- Example usages:
38
+ with ERB as follows:
197
39
 
198
40
  ```erb
199
- <!-- These will render -->
200
- <%= render AvatarComponent.new(url: "https://someurl.com/avatar.jpg", initials: "AB" size: :large) %>
201
- <%= render AvatarComponent.new(url: "https://someurl.com/avatar.jpg", html_options: {alt: "My alt text", class: "object-scale-down"}) %>
202
- <%= render AvatarComponent.new(initials: "SG", size: :small) %>
203
- <%= render AvatarComponent.new(initials: "SG", size: :large, html_options: {class: "border-2 border-red-600"}) %>
204
-
205
- <!-- These will raise an error -->
206
- <!-- missing initals -->
207
- <%= render AvatarComponent.new(url: "https://someurl.com/avatar.jpg", size: :large) %>
208
- <!-- initials blank -->
209
- <%= render AvatarComponent.new(initials: "", size: :large) %>
210
- <!-- invalid size -->
211
- <%= render AvatarComponent.new(initials: "SG", size: :foo_bar) %>
212
- ```
213
-
214
-
215
- The following is rendered when used `render AvatarComponent.new(initials: "SG", size: :small, border: true)`:
216
-
217
- ```html
218
- <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">
219
- <span class="text-xs font-medium leading-none text-white">SG</span>
220
- </div>
221
- ```
41
+ <%# app/components/greeter_component.html.erb %>
222
42
 
223
- 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"})`:
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. %>
224
45
 
225
- ```html
226
- <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">
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
+ ...
67
+ <% end %>
68
+ <% end %>
227
69
  ```
228
70
 
229
- ----
230
-
231
- ![Example](examples/avatar.png)
232
-
233
- ## Another ViewComponent + Vident example with Stimulus
234
-
235
- Consider the following ERB that might be part of an application's views. The app uses `ViewComponent`, `Stimulus` and `Vident`.
236
-
237
- The Greeter is a component that displays a text input and a button. When the button is clicked, the text input's value is
238
- used to greet the user. At the same time the button changes to be a 'reset' button, which resets the greeting when clicked again.
239
-
240
- ![ex1.gif](examples%2Fex1.gif)
71
+ Now, imagine we render it in a view, and render a `ButtonComponent` in the `trigger` slot:
241
72
 
242
73
  ```erb
243
- <%# app/views/home/index.html.erb %>
244
-
245
- <!-- ... -->
246
-
247
- <!-- render the Greeter ViewComponent (that uses Vident) -->
248
74
  <%= render ::GreeterComponent.new(cta: "Hey!", html_options: {class: "my-4"}) do |greeter| %>
249
75
  <%# this component has a slot called `trigger` that renders a `ButtonComponent` (which also uses Vident) %>
250
- <% greeter.trigger(
76
+ <% greeter.with_trigger(
251
77
 
252
78
  # The button component has attributes that are typed
253
79
  before_clicked: "Greet",
@@ -265,8 +91,6 @@ used to greet the user. At the same time the button changes to be a 'reset' butt
265
91
  }
266
92
  ) %>
267
93
  <% end %>
268
-
269
- <!-- ... -->
270
94
  ```
271
95
 
272
96
  The output HTML of the above, using Vident, is:
@@ -294,237 +118,178 @@ The output HTML of the above, using Vident, is:
294
118
  </div>
295
119
  ```
296
120
 
297
- Let's look at the components in more detail.
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.
298
122
 
299
- The main component is the `GreeterComponent`:
123
+ # Vident is a collection of gems
300
124
 
301
- ```ruby
302
- # app/components/greeter_component.rb
125
+ The core gems are:
303
126
 
304
- class GreeterComponent < ViewComponent::Base
305
- include Vident::Component
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
306
129
 
307
- renders_one :trigger, ButtonComponent
308
- end
309
- ```
130
+ Gems that provide support for `ViewComponent` and `Phlex`:
310
131
 
311
- ```erb
312
- <%# app/components/greeter_component.html.erb %>
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
313
136
 
314
- <%# Rendering the `root` element creates a tag which has stimulus `data-*`s, a unique id & other attributes set. %>
315
- <%# The stimulus controller name (identifier) is derived from the component name, and then used to generate the relavent data attribute names. %>
137
+ There is also:
316
138
 
317
- <%= render root named_classes: {
318
- pre_click: "text-md text-gray-500", # named classes are exposed to Stimulus as `data-<controller>-<name>-class` attributes
319
- post_click: "text-xl text-blue-700",
320
- html_options: {class: "py-2"}
321
- } do |greeter| %>
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/).
322
142
 
323
- <%# `greeter` is the root element and exposes methods to generate stimulus targets and actions %>
324
- <input type="text"
325
- <%= greeter.as_target(:name) %>
326
- class="shadow appearance-none border rounded py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline">
327
-
328
- <%# Render the slot %>
329
- <%= trigger %>
330
-
331
- <%# you can also use the `target_tag` helper to render targets %>
332
- <%= greeter.target_tag(
333
- :span,
334
- :output,
335
- # Stimulus named classes can be referenced to set class attributes at render time
336
- class: "ml-4 #{greeter.named_classes(:pre_click)}"
337
- ) do %>
338
- ...
339
- <% end %>
340
- <% end %>
341
143
 
342
- ```
144
+ # Things still to do...
343
145
 
344
- ```js
345
- // app/components/greeter_component_controller.js
346
-
347
- import { Controller } from "@hotwired/stimulus"
348
-
349
- // This is a Stimulus controller that is automatically registered for the `GreeterComponent`
350
- // and is 'sidecar' to the component. You can see that while in the ERB we use Ruby naming conventions
351
- // with snake_case Symbols, here they are converted to camelCase names. We can also just use camelCase
352
- // in the ERB if we want.
353
- export default class extends Controller {
354
- static targets = [ "name", "output" ]
355
- static classes = [ "preClick", "postClick" ]
356
-
357
- greet() {
358
- this.clicked = !this.clicked;
359
- this.outputTarget.classList.toggle(this.preClickClasses, !this.clicked);
360
- this.outputTarget.classList.toggle(this.postClickClasses, this.clicked);
361
-
362
- if (this.clicked)
363
- this.outputTarget.textContent = `Hello, ${this.nameTarget.value}!`
364
- else
365
- this.clear();
366
- }
367
-
368
- clear() {
369
- this.outputTarget.textContent = '...';
370
- this.nameTarget.value = '';
371
- }
372
- }
373
- ```
146
+ This is a work in progress. Here's what's left to do for first release:
374
147
 
375
- The slot renders a `ButtonComponent` component:
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
376
154
 
377
- ```ruby
378
- # app/components/button_component.rb
379
-
380
- class ButtonComponent < ViewComponent::Base
381
- # This component uses Vident::TypedComponent which uses dry-types to define typed attributes.
382
- include Vident::TypedComponent
383
-
384
- # The attributes can specify an expected type, a default value and if nil is allowed.
385
- attribute :after_clicked, String, default: "Greeted!"
386
- attribute :before_clicked, String, allow_nil: false
387
-
388
- # This example is a templateless ViewComponent.
389
- def call
390
- # The button is rendered as a <button> tag with an click action on its own controller.
391
- render root(
392
- element_tag: :button,
393
-
394
- # We can define actions as arrays of Symbols, or pass manually manually crafted strings.
395
- # Here we specify the action name only, implying an action on the current components controller
396
- # and the default event type of `click`.
397
- actions: [:change_message],
398
- # Alternatively: [:click, :change_message] or ["click", "changeMessage"] or even "click->button-component#changeMessage"
399
-
400
- # A couple of data values are also set which will be available to the controller
401
- data_maps: [{after_clicked_message: after_clicked, before_clicked_message: before_clicked}],
402
-
403
- # The <button> tag has a default styling set directly on it. Note that
404
- # if not using utility classes, you can style the component using its
405
- # canonical class name (which is equal to the component's stimulus identifier),
406
- # in this case `button-component`.
407
- html_options: {class: "ml-4 whitespace-no-wrap bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"}
408
- ) do
409
- @before_clicked
410
- end
411
- end
412
- end
413
- ```
155
+ # About Vident
414
156
 
415
- ```js
416
- // app/components/button_component_controller.js
157
+ ## What does Vident provide?
417
158
 
418
- import { Controller } from "@hotwired/stimulus"
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).
419
161
 
420
- export default class extends Controller {
421
- // The action is in camelCase.
422
- changeMessage() {
423
- this.clicked = !this.clicked;
424
- // The data attributes have their naming convention converted to camelCase.
425
- this.element.textContent = this.clicked ? this.data.get("afterClickedMessage") : this.data.get("beforeClickedMessage");
426
- }
427
- }
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
165
+
166
+ - a way to define attributes for your components, either typed or untyped, with default values and optional validation.
167
+
168
+ ### Various utilities
169
+
170
+ Such as...
171
+
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
177
+
178
+ ## All the Features...
179
+
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`
428
196
 
429
- ```
430
197
 
431
198
  ## Installation
432
199
 
433
200
  This gem (`vident`) provides only base functionality but there are a number of gems that provide additional functionality
434
- or a "out of the box" experience.
201
+ or an "out of the box" experience.
435
202
 
436
203
  It's a "pick your own adventure" approach. You decide what frameworks and features you want to use
437
204
  and add the gems as needed.
438
205
 
439
- Start by asking yorself these questions:
206
+ First, add this line to your application's Gemfile:
440
207
 
441
- _Q1. Do you want to use [`ViewComponent`](https://viewcomponent.org/) or [`Phlex`](https://www.phlex.fun/) for your view components?_
208
+ ```ruby
209
+ gem 'vident'
210
+ ```
442
211
 
443
- _Q2. Do you want to use attributes with runtime type checking (powered by [`dry-types`](https://github.com/dry-rb/dry-types)), or not?_
212
+ Then go on to choose the gems you want to use:
444
213
 
445
- Depending on your answer to Q1, you can choose from either the `*-view_component` or `*-phlex` gems,
446
- then depending on your answer to Q2, you can choose from either the untyped or `*-typed-*` gems.
214
+ #### Q1. Do you want to use [`ViewComponent`](https://viewcomponent.org/) or [`Phlex`](https://www.phlex.fun/) for your view components?
447
215
 
448
- Note you can also use some or all of them in the same app.
216
+ For ViewComponent use:
449
217
 
450
- - [`vident-view_component`](https://github.com/stevegeek/vident-view_component) for using with `ViewComponent` and untyped attributes
451
- - [`vident-typed-view_component`](https://github.com/stevegeek/vident-typed-view_component) for using with `ViewComponent` and typed attributes
452
- - [`vident-phlex`](https://github.com/stevegeek/vident-phlex) for using with `Phlex` and untyped attributes
453
- - [`vident-typed-phlex`](https://github.com/stevegeek/vident-typed-phlex) for using with `Phlex` and typed attributes
218
+ - [`vident-view_component`](https://github.com/stevegeek/vident-view_component)
454
219
 
455
- _Q3. Do you use or want to use [BetterHTML](https://github.com/Shopify/better-html) in your Rails project?_
220
+ For Phlex use:
456
221
 
457
- 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.
458
- Note that `vident-better_html` automatically enables `better_html` support in Vident root components.
222
+ - [`vident-phlex`](https://github.com/stevegeek/vident-phlex)
459
223
 
460
- _Q4. Do you use or want to use [TailwindCSS](https://tailwindcss.com/)?_
461
224
 
462
- If yes, then consider adding [`vident-tailwind`](https://github.com/stevegeek/vident-tailwind) to your Gemfile alongside your vident gems of choice. When creating
463
- your components you can then include `Vident::Tailwind` to get all the benefits of the amazing [`tailwind_merge`](https://github.com/gjtorikian/tailwind_merge/).
225
+ Note: you can also use both in the same app.
464
226
 
465
- Finally if none of the above gems suit your needs, you can always just use base `vident` gems to roll your own
466
- solution:
227
+ For example, if you want to use ViewComponent and Phlex in the same app, you might end up with:
467
228
 
468
- - [`vident`](https://github.com/stevegeek/vident) to get the base functionality to mix with your own view component system
469
- - [`vident-typed`](https://github.com/stevegeek/vident-typed) to define typed attributes for your own view component system
229
+ ```ruby
230
+ gem 'vident'
231
+ gem 'vident-view_component'
232
+ gem 'vident-phlex'
233
+ ```
470
234
 
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))?
471
236
 
472
- And then execute:
237
+ If yes, then add `vident-typed` to your Gemfile:
473
238
 
474
- $ bundle install
239
+ ```ruby
240
+ gem 'vident-typed'
241
+ ```
475
242
 
476
- ## Making 'sidecar' Stimulus Controllers work
243
+ and then use the relavent `*-typed-*` gems for your chosen view component system:
477
244
 
478
- ### When using `stimulus-rails`, `sprockets-rails` & `importmap-rails`
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)
479
247
 
480
- Pin any JS modules from under `app/views` and `app/components` which are sidecar with their respective components.
248
+ Note you must also include the gem for the view component system you are using.
481
249
 
482
- Add to `config/importmap.rb`:
250
+ For example, for ViewComponent, you might end up with:
483
251
 
484
252
  ```ruby
485
- components_directories = [Rails.root.join("app/components"), Rails.root.join("app/views")]
486
- components_directories.each do |components_path|
487
- prefix = components_path.basename.to_s
488
- components_path.glob("**/*_controller.js").each do |controller|
489
- name = controller.relative_path_from(components_path).to_s.remove(/\.js$/)
490
- pin "#{prefix}/#{name}", to: name
491
- end
492
- end
253
+ gem 'vident'
254
+ gem 'vident-view_component'
255
+ gem 'vident-typed'
256
+ gem 'vident-typed-view_component'
493
257
  ```
494
258
 
495
- Note we don't use `pin_all_from` as it is meant to work with a subdirectory in `assets.paths`
496
- See this for more: https://stackoverflow.com/a/73228193/268602
259
+ #### Q3. Do you use or want to use [BetterHTML](https://github.com/Shopify/better-html) in your Rails project?
497
260
 
498
- Then we need to ensure that sprockets picks up those files in build, so add
499
- to the `app/assets/config/manifest.js`:
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.
500
262
 
501
- ```js
502
- //= link_tree ../../components .js
503
- //= link_tree ../../views .js
263
+ ```ruby
264
+ ...
265
+ gem 'better_html'
266
+ gem 'vident-better_html'
504
267
  ```
505
268
 
506
- We also need to add to `assets.paths`. Add to your to `config/application.rb`
269
+ Note that `vident-better_html` automatically enables `better_html` support in Vident root components.
270
+
271
+ ### Q4. Do you use or want to use [TailwindCSS](https://tailwindcss.com/)?
272
+
273
+ If yes, then consider adding [`vident-tailwind`](https://github.com/stevegeek/vident-tailwind) to your Gemfile alongside your vident gems of choice.
507
274
 
508
275
  ```ruby
509
- config.importmap.cache_sweepers.append(Rails.root.join("app/components"), Rails.root.join("app/views"))
510
- config.assets.paths.append("app/components", "app/views")
276
+ ...
277
+ gem 'vident-tailwind'
511
278
  ```
512
279
 
513
- ### When using `webpacker`
514
-
515
- TODO
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/).
516
281
 
517
- ### When using `propshaft`
282
+ ### Q5. Did none of the above gems suit your needs?
518
283
 
519
- TODO
284
+ You can always just use base `vident` gems and then roll your own solutions:
520
285
 
521
- ## Using TypeScript for Stimulus Controllers
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
522
288
 
523
- TODO
524
289
 
525
- ## Usage
290
+ ## Documentation
526
291
 
527
- TODO: Write usage instructions here
292
+ See the [docs](docs/) directory and visit the individual gem pages for more information.
528
293
 
529
294
  ## Development
530
295
 
@@ -532,8 +297,6 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
532
297
 
533
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).
534
299
 
535
-
536
-
537
300
  ## Contributing
538
301
 
539
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).
data/lib/vident/base.rb CHANGED
@@ -145,6 +145,7 @@ module Vident
145
145
  ) + Array.wrap(options[:controllers]) + attribute(:controllers),
146
146
  actions: attribute(:actions) + Array.wrap(options[:actions]),
147
147
  targets: attribute(:targets) + Array.wrap(options[:targets]),
148
+ outlets: attribute(:outlets) + Array.wrap(options[:outlets]),
148
149
  named_classes: merge_stimulus_option(options, :named_classes),
149
150
  data_maps: prepare_stimulus_option(options, :data_maps)
150
151
  }
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vident
4
+ # Rails fragment caching works by either expecting the cached key object to respond to `cache_key` or for that object
5
+ # to be an array or hash.
6
+ module Caching
7
+ extend ActiveSupport::Concern
8
+
9
+ class_methods do
10
+ def inherited(subclass)
11
+ subclass.instance_variable_set(:@named_cache_key_attributes, @named_cache_key_attributes.clone)
12
+ super
13
+ end
14
+
15
+ def with_cache_key(*attrs, name: :_collection)
16
+ # Add view file to cache key
17
+ attrs << :component_modified_time
18
+ attrs << :attributes
19
+ named_cache_key_includes(name, *attrs.uniq)
20
+ end
21
+
22
+ attr_reader :named_cache_key_attributes
23
+
24
+ # Components can be used with fragment caching, but you need to be careful! Read on...
25
+ #
26
+ # <% cache component do %>
27
+ # <%= render component %>
28
+ # <% end %>
29
+ #
30
+ # The most important point is that Rails cannot track dependencies on the component itself, so you need to
31
+ # be careful to be explicit on the attributes, and manually specify any sub Viewcomponent dependencies that the
32
+ # component has. The assumption is that the subcomponent takes any attributes from the parent, so the cache key
33
+ # depends on the parent component attributes. Otherwise changes to the parent or sub component views/Ruby class
34
+ # will result in different cache keys too. Of course if you invalidate all cache keys with a modifier on deploy
35
+ # then no need to worry about changing the cache key on component changes, only on attribute/data changes.
36
+ #
37
+ # A big caveat is that the cache key cannot depend on anything related to the view_context of the component (such
38
+ # as `helpers` as the key is created before the rending pipline is invoked (which is when the view_context is set).
39
+ def depends_on(*klasses)
40
+ @component_dependencies ||= []
41
+ @component_dependencies += klasses
42
+ end
43
+
44
+ attr_reader :component_dependencies
45
+
46
+ def component_modified_time
47
+ return @component_modified_time if Rails.env.production? && @component_modified_time
48
+
49
+ raise StandardError, "Must implement current_component_modified_time" unless respond_to?(:current_component_modified_time)
50
+
51
+ # FIXME: This could stack overflow if there are circular dependencies
52
+ deps = component_dependencies&.map(&:component_modified_time)&.join("-") || ""
53
+ @component_modified_time = deps + current_component_modified_time
54
+ end
55
+
56
+ private
57
+
58
+ def named_cache_key_includes(name, *attrs)
59
+ define_cache_key_method unless @named_cache_key_attributes
60
+ @named_cache_key_attributes ||= {}
61
+ @named_cache_key_attributes[name] = attrs
62
+ end
63
+
64
+ def define_cache_key_method
65
+ # If the presenter defines cache key setup then define the method. Otherwise Rails assumes this
66
+ # will return a valid key if the class will respond to this
67
+ define_method :cache_key do |n = :_collection|
68
+ if defined?(@cache_key)
69
+ return @cache_key[n] if @cache_key.key?(n)
70
+ else
71
+ @cache_key ||= {}
72
+ end
73
+ generate_cache_key(n)
74
+ @cache_key[n]
75
+ end
76
+ end
77
+ end
78
+
79
+ # Component modified time which is combined with other cache key attributes to generate cache key for an instance
80
+ def component_modified_time
81
+ self.class.component_modified_time
82
+ end
83
+
84
+ def cacheable?
85
+ respond_to? :cache_key
86
+ end
87
+
88
+ def cache_key_modifier
89
+ ENV["RAILS_CACHE_ID"]
90
+ end
91
+
92
+ def cache_keys_for_sources(key_attributes)
93
+ sources = key_attributes.flat_map { |n| n.is_a?(Proc) ? instance_eval(&n) : send(n) }
94
+ sources.compact.map do |item|
95
+ next if item == self
96
+ generate_item_cache_key_from(item)
97
+ end
98
+ end
99
+
100
+ def generate_item_cache_key_from(item)
101
+ if item.respond_to? :cache_key_with_version
102
+ item.cache_key_with_version
103
+ elsif item.respond_to? :cache_key
104
+ item.cache_key
105
+ elsif item.is_a?(String)
106
+ Digest::SHA1.hexdigest(item)
107
+ else
108
+ Digest::SHA1.hexdigest(Marshal.dump(item))
109
+ end
110
+ end
111
+
112
+ def generate_cache_key(index)
113
+ key_attributes = self.class.named_cache_key_attributes[index]
114
+ return nil unless key_attributes
115
+ key = "#{self.class.name}/#{cache_keys_for_sources(key_attributes).join("/")}"
116
+ raise StandardError, "Cache key for key #{key} is blank!" if key.blank?
117
+ @cache_key[index] = cache_key_modifier.present? ? "#{key}/#{cache_key_modifier}" : key
118
+ end
119
+ end
120
+ end
@@ -16,6 +16,7 @@ module Vident
16
16
  attribute :controllers, default: [], delegates: false
17
17
  attribute :actions, default: [], delegates: false
18
18
  attribute :targets, default: [], delegates: false
19
+ attribute :outlets, default: [], delegates: false
19
20
  attribute :data_maps, default: [], delegates: false
20
21
  attribute :named_classes, delegates: false
21
22
  end
@@ -6,6 +6,7 @@ module Vident
6
6
  controllers: nil,
7
7
  actions: nil,
8
8
  targets: nil,
9
+ outlets: nil,
9
10
  named_classes: nil, # https://stimulus.hotwired.dev/reference/css-classes
10
11
  data_maps: nil,
11
12
  element_tag: nil,
@@ -18,6 +19,7 @@ module Vident
18
19
  @controllers = Array.wrap(controllers)
19
20
  @actions = actions
20
21
  @targets = targets
22
+ @outlets = outlets
21
23
  @named_classes = named_classes
22
24
  @data_map_kvs = {}
23
25
  @data_maps = data_maps
@@ -123,11 +125,17 @@ module Vident
123
125
  def tag_data_attributes
124
126
  {controller: controller_list(@controllers), action: action_list(@actions)}
125
127
  .merge!(target_list)
128
+ .merge!(outlet_list)
126
129
  .merge!(named_classes_list)
127
130
  .merge!(data_map_attributes)
128
131
  .compact_blank!
129
132
  end
130
133
 
134
+ def outlet_list
135
+ return {} unless @outlets&.size&.positive?
136
+ @outlets.each_with_object({}) { |o, obj| obj["#{implied_controller_name}-#{o.stimulus_identifier}-outlet"] = "[data-controller~=#{o.stimulus_identifier}]" }
137
+ end
138
+
131
139
  # Actions can be specified as a symbol, in which case they imply an action on the primary
132
140
  # controller, or as a string in which case it implies an action that is already fully qualified
133
141
  # stimulus action.
@@ -173,7 +181,7 @@ module Vident
173
181
  end
174
182
 
175
183
  def build_target_data_attributes(targets)
176
- targets.map { |t| ["#{t[:controller]}-target".to_sym, t[:name]] }.to_h
184
+ targets.map { |t| [:"#{t[:controller]}-target", t[:name]] }.to_h
177
185
  end
178
186
 
179
187
  def parse_actions(actions)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Vident
4
- VERSION = "0.8.0"
4
+ VERSION = "0.10.0"
5
5
  end
data/sig/vident.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module Vident
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
data/vident.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/vident/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "vident"
7
+ spec.version = Vident::VERSION
8
+ spec.authors = ["Stephen Ierodiaconou"]
9
+ spec.email = ["stevegeek@gmail.com"]
10
+
11
+ spec.summary = "Vident is the base of your design system implementation, which provides helpers for working with Stimulus. For component libraries with ViewComponent or Phlex."
12
+ spec.description = "Vident makes using Stimulus with your `ViewComponent` or `Phlex` view components as easy as writing Ruby. Vident is the base of your design system implementation, which provides helpers for working with Stimulus. For component libraries with ViewComponent or Phlex."
13
+ spec.homepage = "https://github.com/stevegeek/vident"
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = ">= 3.0.0"
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = spec.homepage
19
+ spec.metadata["changelog_uri"] = spec.homepage + "/blob/main/CHANGELOG.md"
20
+
21
+ spec.files = Dir.chdir(__dir__) do
22
+ `git ls-files -z`.split("\x0").reject do |f|
23
+ (File.expand_path(f) == __FILE__) ||
24
+ f.start_with?(*%w[bin/ test/ spec/ features/ examples/ docs/ .git .github appveyor Gemfile])
25
+ end
26
+ end
27
+
28
+ spec.add_dependency "railties", ">= 7", "< 8.0"
29
+ spec.add_dependency "activesupport", ">= 7", "< 8.0"
30
+ end
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vident
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen Ierodiaconou
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-31 00:00:00.000000000 Z
11
+ date: 2024-02-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rails
14
+ name: railties
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
@@ -19,7 +19,7 @@ dependencies:
19
19
  version: '7'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: '8'
22
+ version: '8.0'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -29,7 +29,27 @@ dependencies:
29
29
  version: '7'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: '8'
32
+ version: '8.0'
33
+ - !ruby/object:Gem::Dependency
34
+ name: activesupport
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '7'
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '8.0'
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '7'
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '8.0'
33
53
  description: Vident makes using Stimulus with your `ViewComponent` or `Phlex` view
34
54
  components as easy as writing Ruby. Vident is the base of your design system implementation,
35
55
  which provides helpers for working with Stimulus. For component libraries with ViewComponent
@@ -40,17 +60,25 @@ executables: []
40
60
  extensions: []
41
61
  extra_rdoc_files: []
42
62
  files:
63
+ - ".ruby-version"
64
+ - ".standard.yml"
65
+ - CHANGELOG.md
66
+ - CODE_OF_CONDUCT.md
67
+ - LICENSE.txt
43
68
  - README.md
44
69
  - Rakefile
45
70
  - lib/tasks/vident_tasks.rake
46
71
  - lib/vident.rb
47
72
  - lib/vident/attributes/not_typed.rb
48
73
  - lib/vident/base.rb
74
+ - lib/vident/caching.rb
49
75
  - lib/vident/component.rb
50
76
  - lib/vident/engine.rb
51
77
  - lib/vident/root_component.rb
52
78
  - lib/vident/stable_id.rb
53
79
  - lib/vident/version.rb
80
+ - sig/vident.rbs
81
+ - vident.gemspec
54
82
  homepage: https://github.com/stevegeek/vident
55
83
  licenses:
56
84
  - MIT
@@ -73,7 +101,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
73
101
  - !ruby/object:Gem::Version
74
102
  version: '0'
75
103
  requirements: []
76
- rubygems_version: 3.4.6
104
+ rubygems_version: 3.5.3
77
105
  signing_key:
78
106
  specification_version: 4
79
107
  summary: Vident is the base of your design system implementation, which provides helpers