Module: ViewComponentCssDsl
- Extended by:
- ActiveSupport::Concern
- Defined in:
- lib/view_component_css_dsl.rb,
lib/view_component_css_dsl/version.rb
Constant Summary collapse
- MERGER =
Single shared merger. tailwind_merge builds a conflict-group index on initialization, so we pay that cost once per process rather than per call.
TailwindMerge::Merger.new
- HTML_ATTR_KEYS =
Set[ :alt, :aria, :autofocus, :class, :colspan, :contenteditable, :data, :dir, :disabled, :download, :draggable, :enterkeyhint, :formaction, :headers, :hidden, :href, :id, :inputmode, :lang, :loading, :low, :media, :onclick, :open, :optimum, :popover, :popovertarget, :popovertargetaction, :preload, :readonly, :rel, :role, :rowspan, :spellcheck, :src, :srcset, :style, :tabindex, :target, :title, :type, :value ].freeze
- DATA_MERGE_KEYS =
%i[controller action].freeze
- VERSION =
"0.1.3"
Instance Method Summary collapse
-
#aria_attrs ⇒ Object
Overwrite in subclass to define default aria-attrs.
-
#css ⇒ Object
Instance method: generates final CSS string.
-
#custom_css ⇒ Object
Returns caller’s custom classes from html_attrs.
-
#data_attrs ⇒ Object
Overwrite in component subclass to set default data-attrs.
-
#final_aria_attrs ⇒ Object
Merge in order: DSL declarations -> method override -> caller’s :aria.
-
#final_data_attrs ⇒ Object
Loop through data-attrs and merge values from DATA_MERGE_KEYS.
-
#html_attrs ⇒ Object
Returns the hash to splat onto the top-level element of a component template:.
Instance Method Details
#aria_attrs ⇒ Object
Overwrite in subclass to define default aria-attrs
369 370 371 |
# File 'lib/view_component_css_dsl.rb', line 369 def aria_attrs {} end |
#css ⇒ Object
Instance method: generates final CSS string
276 277 278 |
# File 'lib/view_component_css_dsl.rb', line 276 def css build_classes end |
#custom_css ⇒ Object
Returns caller’s custom classes from html_attrs
281 282 283 284 285 |
# File 'lib/view_component_css_dsl.rb', line 281 def custom_css return "" unless @html_attrs @html_attrs.fetch(:class, "") end |
#data_attrs ⇒ Object
Overwrite in component subclass to set default data-attrs. They will be merged into html_attrs.
Example:
def data_attrs
{
controller: "some-stimulus-controller",
action: "click->some-stimulus-controller#someAction",
active: active?
}
end
327 328 329 |
# File 'lib/view_component_css_dsl.rb', line 327 def data_attrs {} end |
#final_aria_attrs ⇒ Object
Merge in order: DSL declarations -> method override -> caller’s :aria. Hash#merge throughout — caller wins on collision (no additive semantics).
375 376 377 |
# File 'lib/view_component_css_dsl.rb', line 375 def final_aria_attrs resolved_attr_rules(:aria).merge(aria_attrs).merge(@html_attrs.fetch(:aria, {})) end |
#final_data_attrs ⇒ Object
Loop through data-attrs and merge values from DATA_MERGE_KEYS. Overwrite any others.
Ensures the caller doesn’t wipe out e.g. data-controller or data-action values defined by the dev in #data_attrs
Example:
Assuming MyComponent with #data_attrs defined as:
def data_attrs
{
controller: "foo",
label: "Hello world"
}
end
MyComponent.new(data: “bar”, label: “Goodbye”)
Will output the following data-attrs:
<div data-controller=“foo bar” data-label=“Goodbye”>
Notice:
-
data-controller from the caller is set alongside “foo” instead of overwriting
-
In contrast, data-label from the caller overwrites the default
360 361 362 363 364 365 366 |
# File 'lib/view_component_css_dsl.rb', line 360 def final_data_attrs # Merge in order: DSL declarations -> method override -> caller's :data. # Each layer uses DATA_MERGE_KEYS semantics (controller/action concatenate, # everything else replaces). combined = merge_data_layer(resolved_attr_rules(:data), data_attrs) merge_data_layer(combined, @html_attrs.fetch(:data, {})) end |
#html_attrs ⇒ Object
Returns the hash to splat onto the top-level element of a component template:
<%= tag.div **html_attrs do %> ... <% end %>
Includes the smart-merged ‘:class`, merged `:data` and `:aria` (from any component-defined defaults + caller overrides), and every other caller-passed HTML attribute (`id:`, `role:`, etc.) forwarded to the rendered element.
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 |
# File 'lib/view_component_css_dsl.rb', line 294 def html_attrs return {} unless @html_attrs # Start with DSL-declared top-level attrs; caller's html_attrs layer on top # (caller wins on collision, mirroring the css behavior). dsl_attrs = resolved_attr_rules(:attribute) result = dsl_attrs.merge(@html_attrs.except(:aria, :class, :data)) # Only include aria/data if they have content, otherwise they'd override # inline attrs in templates like: tag.div data: {foo: "bar"}, **html_attrs aria = final_aria_attrs data = final_data_attrs result[:aria] = aria if aria.present? result[:data] = data if data.present? css_value = css result[:class] = css_value if css_value.present? result end |