Skip to content

Commit

Permalink
Add Drawer component
Browse files Browse the repository at this point in the history
  • Loading branch information
davidalejandroaguilar committed Aug 3, 2024
1 parent 795cdc9 commit df07b7f
Show file tree
Hide file tree
Showing 4 changed files with 315 additions and 1 deletion.
1 change: 1 addition & 0 deletions lib/phlexy_ui.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ module PhlexyUI
autoload :Button, "phlexy_ui/button"
autoload :Card, "phlexy_ui/card"
autoload :Tabs, "phlexy_ui/tabs"
autoload :Drawer, "phlexy_ui/drawer"
end

loader.eager_load
2 changes: 1 addition & 1 deletion lib/phlexy_ui/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def initialize(*base_modifiers, **options)

private

attr_reader :base_modifiers, :options, :data, :as
attr_reader :base_modifiers, :options, :data, :as, :id

def generate_classes!(
component_html_class:,
Expand Down
69 changes: 69 additions & 0 deletions lib/phlexy_ui/drawer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# frozen_string_literal: true

module PhlexyUI
class Drawer < Base
def initialize(*, id:, as: :section, **)
super(*, **)
@as = as
@id = id
end

def view_template(&)
generate_classes!(
component_html_class: :drawer,
modifiers_map: DRAWER_MODIFIERS_MAP,
base_modifiers:,
options:
).then do |classes|
public_send(as, class: classes, **options, &)
end
end

def toggle(**options, &)
generate_classes!(
component_html_class: :"drawer-toggle",
options:
).then do |classes|
input(id:, type: :checkbox, class: classes, **options, &)
end
end

def content(as: :div, **options, &)
generate_classes!(
component_html_class: :"drawer-content",
options:
).then do |classes|
public_send(as, class: classes, **options, &)
end
end

def side(as: :div, **options, &)
generate_classes!(
component_html_class: :"drawer-side",
options:
).then do |classes|
public_send(as, class: classes, **options, &)
end
end

def overlay(**options, &)
generate_classes!(
component_html_class: :"drawer-overlay",
options:
).then do |classes|
label(for: id, class: classes, **options, &)
end
end

def button(*, **, &)
render Button.new(*, as: :label, for: id, **, &)
end

private

DRAWER_MODIFIERS_MAP = {
end: "drawer-end",
open: "drawer-open"
}.freeze
end
end
244 changes: 244 additions & 0 deletions spec/lib/phlexy_ui/drawer_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
require "spec_helper"

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

describe "conditions" do
{
end: "drawer-end",
open: "drawer-open"
}.each do |condition, css|
context "when given :#{condition} condition" do
subject(:output) { render described_class.new(condition, id: :my_drawer) }

it "renders it apart from the main class" do
expected_html = html <<~HTML
<section class="drawer #{css}"></section>
HTML

expect(output).to eq(expected_html)
end
end
end

context "when condition doesn't exist" do
it "raises an error" do
expect { render described_class.new(:foo, id: :my_drawer) }
.to raise_error(
ArgumentError,
"Condition `foo` is not defined for PhlexyUI::Drawer"
)
end
end

context "when given multiple conditions" do
subject(:output) { render described_class.new(:end, :open, id: :my_drawer) }

it "renders them separately" do
expected_html = html <<~HTML
<section class="drawer drawer-end drawer-open"></section>
HTML

expect(output).to eq(expected_html)
end
end
end

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

it "renders it correctly" do
expected_html = html <<~HTML
<section class="drawer drawer-open" data-foo="bar"></section>
HTML

expect(output).to eq(expected_html)
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(:open, id: :my_drawer)
end

it "renders it correctly" do
expected_html = html <<~HTML
<section class="foo-drawer foo-drawer-open"></section>
HTML

expect(output).to eq(expected_html)
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(:open, viewport => :end, :id => :my_drawer)
end

it "renders it separately with a responsive prefix" do
expected_html = html <<~HTML
<section class="drawer drawer-open #{viewport}:drawer-end">
</section>
HTML

expect(output).to eq(expected_html)
end
end

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

it "renders it separately with a responsive prefix" do
expected_html = html <<~HTML
<section class="
drawer
drawer-open
#{viewport}:drawer-open
#{viewport}:drawer-end">
</section>
HTML

expect(output).to eq(expected_html)
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(:open, viewport => [:open, :end], :id => :my_drawer)
end

it "renders it separately with a responsive prefix" do
expected_html = html <<~HTML
<section class="
foo-drawer
foo-drawer-open
#{viewport}:foo-drawer-open
#{viewport}:foo-drawer-end">
</section>
HTML

expect(output).to eq(expected_html)
end
end
end
end

describe "rendering via Kit" do
subject(:output) do
Drawer(:end, id: :my_drawer)
end

it "renders it correctly" do
expected_html = html <<~HTML
<section class="drawer drawer-end"></section>
HTML

expect(output).to eq(expected_html)
end
end

describe "passing :as option" do
subject(:output) { render described_class.new(as: :div, id: :my_drawer) }

it "renders the card as the given tag" do
expected_html = html <<~HTML
<div class="drawer"></div>
HTML

expect(output).to eq(expected_html)
end
end

describe "rendering a full drawer" do
let(:component) do
Class.new(Phlex::HTML) do
def view_template(&)
render PhlexyUI::Drawer.new(:end, id: :my_drawer) do |drawer|
drawer.toggle(class: "my-toggle", data: {my: "toggles"})
drawer.content(class: "my-content", data: {my: "contents"}) do
drawer.button(:primary, class: "my-button", data: {my: "buttons"}) do
"Open Drawer"
end

div do
"Content"
end
end
drawer.side(class: "my-side", data: {my: "sides"}) do |side|
side.overlay

ul do
li do
a do
"Sidebar Item 1"
end
end
end
end
end
end
end
end

subject(:output) do
render component.new
end

it "is expected to match the formatted HTML" do
expected_html = html <<~HTML
<section class="drawer drawer-end">
<input id="my_drawer" type="checkbox" class="drawer-toggle my-toggle" data-my="toggles">
<div class="drawer-content my-content" data-my="contents">
<label class="btn btn-primary my-button" for="my_drawer" data-my="buttons">Open Drawer</label>
<div>Content</div>
</div>
<div class="drawer-side my-side" data-my="sides">
<label for="my_drawer" class="drawer-overlay"></label>
<ul>
<li>
<a>Sidebar Item 1</a>
</li>
</ul>
</div>
</section>
HTML

is_expected.to eq(expected_html)
end
end
end

0 comments on commit df07b7f

Please sign in to comment.