Skip to content

Commit

Permalink
Add Button component
Browse files Browse the repository at this point in the history
  • Loading branch information
davidalejandroaguilar committed Aug 2, 2024
1 parent c08c077 commit b917733
Show file tree
Hide file tree
Showing 4 changed files with 249 additions and 0 deletions.
2 changes: 2 additions & 0 deletions lib/phlexy_ui.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
module PhlexyUI
extend Configurable
extend Phlex::Kit

autoload :Button, "phlexy_ui/button"
end

loader.eager_load
47 changes: 47 additions & 0 deletions lib/phlexy_ui/base.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# frozen_string_literal: true

module PhlexyUI
class Base < Phlex::HTML
def initialize(*normal_conditions, sm: [], md: [], lg: [], **options)
@normal_conditions = normal_conditions
@sm_conditions = Array(sm)
@md_conditions = Array(md)
@lg_conditions = Array(lg)
@options = options
@data = options.delete(:data)
end

private

attr_reader :normal_conditions,
:sm_conditions,
:md_conditions,
:lg_conditions,
:options,
:data

def classes
[
prefixed(self.class::BASE_HTML_CLASS),
*html_classes_for_conditions(normal_conditions),
*html_classes_for_conditions(sm_conditions, responsive_prefix: :sm),
*html_classes_for_conditions(md_conditions, responsive_prefix: :md),
*html_classes_for_conditions(lg_conditions, responsive_prefix: :lg)
]
end

def html_classes_for_conditions(conditions, responsive_prefix: nil)
conditions.map do |condition|
class_name = prefixed self.class::CONDITIONS_CLASSES.fetch(condition)

responsive_prefix ? "#{responsive_prefix}:#{class_name}" : class_name
end
rescue KeyError => e
raise ArgumentError, "Condition `#{e.key}` is not defined for #{self.class}"
end

def prefixed(string)
"#{PhlexyUI.configuration.prefix}#{string}"
end
end
end
39 changes: 39 additions & 0 deletions lib/phlexy_ui/button.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# frozen_string_literal: true

module PhlexyUI
class Button < Base
CONDITIONS_CLASSES = {
# Modifiers
no_animation: "no-animation",
glass: "glass",
ghost: "btn-ghost",
link: "btn-link",
outline: "btn-outline",
active: "btn-active",
disabled: "btn-disabled",
lg: "btn-lg",
md: "btn-md",
sm: "btn-sm",
xs: "btn-xs",
wide: "btn-wide",
block: "btn-block",
circle: "btn-circle",
square: "btn-square",
# Colors
neutral: "btn-neutral",
primary: "btn-primary",
secondary: "btn-secondary",
accent: "btn-accent",
info: "btn-info",
success: "btn-success",
warning: "btn-warning",
error: "btn-error"
}.freeze

BASE_HTML_CLASS = "btn"

def view_template(&)
button(class: classes, data:, &)
end
end
end
161 changes: 161 additions & 0 deletions spec/phlexy_ui/button_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
require "spec_helper"

describe PhlexyUI::Button do
subject(:output) { render described_class.new }

it { is_expected.to eq(%(<button class="btn"></button>)) }

describe "conditions" do
{
# Modifiers
no_animation: "no-animation",
glass: "glass",
ghost: "btn-ghost",
link: "btn-link",
outline: "btn-outline",
active: "btn-active",
disabled: "btn-disabled",
lg: "btn-lg",
md: "btn-md",
sm: "btn-sm",
xs: "btn-xs",
wide: "btn-wide",
block: "btn-block",
circle: "btn-circle",
square: "btn-square",
# Colors
neutral: "btn-neutral",
primary: "btn-primary",
secondary: "btn-secondary",
accent: "btn-accent",
info: "btn-info",
success: "btn-success",
warning: "btn-warning",
error: "btn-error"
}.each do |condition, css|
context "when given :#{condition} condition" do
subject(:output) { render described_class.new(condition) }

it "renders it apart from the main class" do
expect(output).to eq(%(<button class="btn #{css}"></button>))
end
end
end

context "when condition doesn't exist" do
subject(:output) { render described_class.new(:foo) }

it "raises an error" do
expect { render described_class.new(:foo) }
.to raise_error(
ArgumentError,
"Condition `foo` is not defined for PhlexyUI::Button"
)
end
end

context "when given multiple conditions" do
subject(:output) { render described_class.new(:neutral, :primary) }

it "renders them separately" do
expect(output)
.to eq(%(<button class="btn btn-neutral btn-primary"></button>))
end
end
end

describe "data" do
subject(:output) do
render described_class.new(:neutral, data: {foo: "bar"})
end

it "renders it correctly" do
expect(output).to eq(%(<button class="btn btn-neutral" data-foo="bar"></button>))
end
end

describe "prefix" do
around do |example|
original_prefix = PhlexyUI.configuration.prefix

PhlexyUI.configure do |config|
config.prefix = "foo-"
end

example.run

PhlexyUI.configure do |config|
config.prefix = original_prefix
end
end

subject(:output) do
render described_class.new(:neutral)
end

it "renders it correctly" do
expect(output).to eq(%(<button class="foo-btn foo-btn-neutral"></button>))
end
end

describe "responsiveness" do
%i[sm md lg].each do |viewport|
context "when given an :#{viewport} responsive option as a single argument" do
subject(:output) do
render described_class.new(:neutral, viewport => :primary)
end

it "renders it separately with a responsive prefix" do
expect(output)
.to eq(%(<button class="btn btn-neutral #{viewport}:btn-primary"></button>))
end
end

context "when given multiple responsive options as an array" do
subject(:output) do
render described_class.new(:neutral, viewport => [:primary, :active])
end

it "renders it separately with a responsive prefix" do
expect(output)
.to eq(%(<button class="btn btn-neutral #{viewport}:btn-primary #{viewport}:btn-active"></button>))
end
end

context "when it's prefixed" do
around do |example|
original_prefix = PhlexyUI.configuration.prefix

PhlexyUI.configure do |config|
config.prefix = "foo-"
end

example.run

PhlexyUI.configure do |config|
config.prefix = original_prefix
end
end

subject(:output) do
render described_class.new(:neutral, viewport => [:primary, :active])
end

it "renders it separately with a responsive prefix" do
expect(output)
.to eq(%(<button class="foo-btn foo-btn-neutral #{viewport}:foo-btn-primary #{viewport}:foo-btn-active"></button>))
end
end
end
end

describe "rendering via Kit" do
subject(:output) do
Button(:neutral)
end

it "renders it correctly" do
expect(output).to eq(%(<button class="btn btn-neutral"></button>))
end
end
end

0 comments on commit b917733

Please sign in to comment.