Created
May 15, 2024 03:40
-
-
Save danielvlopes/4da43ff07d6efea7aafb51093b6675c3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- Enabled: "bg-indigo-600", Not Enabled: "bg-gray-200" --> | |
<button type="button" class="bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2" role="switch" aria-checked="false"> | |
<span class="sr-only">Use setting</span> | |
<!-- Enabled: "translate-x-5", Not Enabled: "translate-x-0" --> | |
<span aria-hidden="true" class="translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"></span> | |
</button> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Controller } from "@hotwired/stimulus"; | |
export default class extends Controller { | |
static targets = ["button", "span", "input"]; | |
toggle() { | |
const isEnabled = this.buttonTarget.getAttribute("aria-checked") === "true"; | |
this.buttonTarget.classList.remove( | |
isEnabled | |
? this.buttonTarget.dataset["onClass"] | |
: this.buttonTarget.dataset["offClass"], | |
); | |
this.buttonTarget.classList.add( | |
isEnabled | |
? this.buttonTarget.dataset["offClass"] | |
: this.buttonTarget.dataset["onClass"], | |
); | |
console.log(this.buttonTarget.classList); | |
this.buttonTarget.setAttribute("aria-checked", String(!isEnabled)); | |
this.spanTarget.classList.toggle("translate-x-5", !isEnabled); | |
this.spanTarget.classList.toggle("translate-x-0", isEnabled); | |
this.inputTarget.value = !isEnabled ? "true" : "false"; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module SwitchHelper | |
# Creates a toggle switch button with dynamic styling and data attributes. | |
# Example: | |
# <%= switch_tag 'toggle_active', checked: true, on_class: 'bg-green-500', off_class: 'bg-red-500' %> | |
# | |
# @param name [String] the name attribute for the hidden input field. | |
# @param checked [Boolean] initial checked state of the switch. | |
# @param options [Hash] additional options passed to the switch_button method. | |
def switch_tag(name, checked: false, **options) | |
content_tag :div, data: { controller: "switch" } do | |
concat switch_button(checked, **options) | |
concat hidden_field_tag(name, checked ? "true" : "false", data: { switch_target: "input" }) | |
end | |
end | |
# Integrates the toggle switch within a Rails form using the form builder. | |
# Example: | |
# <%= form_with model: @user do |f| %> | |
# <%= switch_field f, :active, checked: @user.active, on_class: 'bg-green-500', off_class: 'bg-red-500' %> | |
# <% end %> | |
# | |
# @param f [ActionView::Helpers::FormBuilder] the form builder instance. | |
# @param method [Symbol] the method name corresponding to the model attribute. | |
# @param checked [Boolean] initial checked state of the switch. | |
# @param options [Hash] additional options passed to the switch_button method. | |
def switch_field(f, method, checked: false, **options) | |
content_tag :div, data: { controller: "switch" } do | |
concat(switch_button(checked: checked, **options)) | |
concat(f.hidden_field(method, value: checked ? "true" : "false", data: { switch_target: "input" })) | |
end | |
end | |
private | |
# Helper to generate the toggle button element. | |
# @param checked [Boolean] if the switch is checked. | |
# @param on_class [String] CSS class for 'on' state. | |
# @param off_class [String] CSS class for 'off' state. | |
# @param button_options [Hash] additional attributes for the button element. | |
def switch_button(checked, on_class: "bg-zinc-900", off_class: "bg-zinc-100", button_options: {}) | |
initial_class = checked ? on_class : off_class | |
default_classes = "relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2 #{initial_class}" | |
classes = [default_classes, button_options.delete(:class)].compact.join(" ") | |
default_data = { switch_target: "button", action: "click->switch#toggle", on_class: on_class, off_class: off_class } | |
data = default_data.merge(button_options.delete(:data) || {}) | |
button_options.merge!(type: "button", role: "switch", "aria-checked" => checked, data: data, class: classes) | |
button_tag(**button_options) do | |
concat(content_tag(:span, "Use setting", class: "sr-only")) if button_options[:sr_only] | |
concat(content_tag(:span, "", data: { switch_target: "span" }, aria: { hidden: true }, class: "translate-x-#{checked ? '5' : '0'} pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out")) | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment