StyledHelpers
Pre-configure Action View Helpers with ActionView::Attributes instances with support for mixing variant styles.
Define your variants:
# app/helpers/my_styled_helpers.rb
class MyStyledHelpers < StyledHelpers::Helpers
def link
styled :a, class: "ring-inset ring-current focus:outline-none focus:ring"
end
def button
styled :button, variants: {
defaults: {class: "inline-flex items-center justify-center disabled:cursor-none ring-current focus:outline-none focus:ring"},
color: {
primary: {class: "bg-purple-900 text-white ring-purple-900 focus:ring-offset-2"},
secondary: {class: "bg-purple-900/5 text-purple-900/95"},
tertiary: {class: "bg-white text-purple-900 border border-current/20 hover:bg-opacity-20 aria-expanded:bg-opacity-30"}
},
size: {
small: "text-sm p-1",
medium: "text-md p-2"
large: "text-lg p-4"
}
}
end
def label
styled :label, variants: {
defaults: {class: "text-sm"},
interactive: {
true: {class: "cursor-pointer peer-focus:ring ring-current focus:outline-none focus:ring"}
}
}
end
def input
placeholder = "placeholder:text-current placeholder:text-opacity-95 before:text-opacity-95"
styled :input, variants: {
defaults: {class: "ring-current focus:outline-none focus:ring"},
text: {
class: ["border-black/20 text-sm", placeholder]
},
textarea: styled(:textarea, {
class: ["min-h-fit border-0 text-sm bg-white", placeholder]
}),
}
end
end
# app/helpers/application_helper.rb
module ApplicationHelper
def ui
MyStyledHelpers.new(self)
end
end
From your view templates, invoke Action View helper methods:
ui.link.link_to "A page", "/page"
# => <a class="ring-inset ring-current focus:outline-none focus:ring" href="/page">A page</a>
ui.button.with(color: :primary, size: :large).button_tag "Click Me!", type: :button
# => <button type="button"
# => class="ring-current focus:outline-none focus:ring
# => inline-flex items-center justify-center disabled:cursor-none bg-purple-900 text-white ring-purple-900 focus:ring-offset-2 text-lg p-4">
# => Click Me!
# => </button>
You can also invoke the
tag
helper. Passing content, keyword arguments, or a block will construct an
element with the pre-configured tag name (defaults to <div>
):
ui.button.with(size: :large).tag "Click Me!", type: :button
# => <button type="button" class="inline-flex items-center justify-center disabled:cursor-none ring-current focus:outline-none focus:ring text-lg p-4">
# => Click Me!
# => </button>
You can also chain another tag name off the tag
to override the default:
ui.button.with(size: :large).tag.a "Click Me!", href: "/",
# => <a href="/" class="inline-flex items-center justify-center disabled:cursor-none ring-current focus:outline-none focus:ring text-lg p-4">
# => Click Me!
# => </a>
If variant names are unique across keys, you can pass them directly to #with
:
ui.button.with(:primary, :large).button_tag "Click Me!", type: :button
# => <button type="button"
# => class="ring-current focus:outline-none focus:ring
# => inline-flex items-center justify-center disabled:cursor-none bg-purple-900 text-white ring-purple-900 focus:ring-offset-2 text-lg p-4">
# => Click Me!
# => </button>
You can mix-and-match variant arguments:
ui.button.with(:primary, size: :large).link_to "Click Me!", "/"
# => <a href="/"
# => class="ring-current focus:outline-none focus:ring
# => inline-flex items-center justify-center disabled:cursor-none bg-purple-900 text-white ring-purple-900 focus:ring-offset-2 text-lg p-4">
# => Click Me!
# => </a>
When invoking a single variant, you can forego calls to #with
and invoke the name of the variant directly:
ui.button.primary.button_tag "Click Me!"
# => <button class="ring-current focus:outline-none focus:ring
# => inline-flex items-center justify-center disabled:cursor-none bg-purple-900 text-white ring-purple-900 focus:ring-offset-2">
# => Click Me!
# => </button>
When rendering their default tag, invoke #tag:
ui.button.primary.tag "Click Me!"
# => <button class="ring-current focus:outline-none focus:ring
# => inline-flex items-center justify-center disabled:cursor-none bg-purple-900 text-white ring-purple-900 focus:ring-offset-2">
# => Click Me!
# => </button>
Coerce StyledHelpers::Helpers
instances with Hash#to_h
, and can be double-splatted with **
.
They're also valid Object#with_options
arguments:
form.with_options(ui.input.text).text_field :name
# => <input id="article_name" name="article[name]" type="text"
# => class="placeholder:text-current placeholder:text-opacity-95 before:text-opacity-95
# => ring-current focus:outline-none focus:ring
# => border-black/20 text-sm">
Installation
Add this line to your application's Gemfile:
gem "action_view-attributes", github: "seanpdoyle/action_view-attributes", tag: "v0.1.0"
gem "styled_helpers", github: "seanpdoyle/styled_helpers", tag: "v0.1.0"
And then execute:
$ bundle
Or install it yourself as:
$ gem install styled_helpers
Contributing
Contribution directions go here.
License
The gem is available as open source under the terms of the MIT License.
Acknowledgements
This project was originally forked from seanpdoyle/attributes_and_token_lists. It draws inspiration from the @stitches/react package, namely its support for variants. Its development was encouraged by a comment from Dom Christie.