From e981978a8b8b0d3b42369b3ee82fc738c25c7bf1 Mon Sep 17 00:00:00 2001 From: David Alejandro <15317732+davidalejandroaguilar@users.noreply.github.com> Date: Sun, 4 Aug 2024 00:41:37 +0300 Subject: [PATCH] Add Menu component --- lib/phlexy_ui.rb | 1 + lib/phlexy_ui/menu.rb | 51 ++++++++++++++++++ lib/phlexy_ui/menu/sub_menu.rb | 57 ++++++++++++++++++++ spec/lib/phlexy_ui/menu_spec.rb | 92 +++++++++++++++++++++++++++++++++ 4 files changed, 201 insertions(+) create mode 100644 lib/phlexy_ui/menu.rb create mode 100644 lib/phlexy_ui/menu/sub_menu.rb create mode 100644 spec/lib/phlexy_ui/menu_spec.rb diff --git a/lib/phlexy_ui.rb b/lib/phlexy_ui.rb index 5ddbe74..24d655b 100644 --- a/lib/phlexy_ui.rb +++ b/lib/phlexy_ui.rb @@ -17,6 +17,7 @@ module PhlexyUI autoload :Tabs, "phlexy_ui/tabs" autoload :Drawer, "phlexy_ui/drawer" autoload :Dropdown, "phlexy_ui/dropdown" + autoload :Menu, "phlexy_ui/menu" end loader.eager_load diff --git a/lib/phlexy_ui/menu.rb b/lib/phlexy_ui/menu.rb new file mode 100644 index 0000000..bf74a03 --- /dev/null +++ b/lib/phlexy_ui/menu.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +module PhlexyUI + class Menu < Base + def view_template(&) + generate_classes!( + component_html_class: :menu, + modifiers_map: MENU_MODIFIERS_MAP, + base_modifiers:, + options: + ).then do |classes| + ul(class: classes, **options, &) + end + end + + def title(*, **, &) + li(class: "menu-title", **, &) + end + + def item(*base_modifiers, **, &) + generate_classes!( + modifiers_map: MENU_ITEM_MODIFIERS_MAP, + base_modifiers:, + options: + ).then do |classes| + li(class: classes, &) + end + end + + def submenu(*, **, &) + render SubMenu.new(*, **, &) + end + + private + + MENU_MODIFIERS_MAP = { + xs: "menu-xs", + sm: "menu-sm", + md: "menu-md", + lg: "menu-lg", + vertical: "menu-vertical", + horizontal: "menu-horizontal" + }.freeze + + MENU_ITEM_MODIFIERS_MAP = { + disabled: "disabled", + active: "active", + focus: "focus" + } + end +end diff --git a/lib/phlexy_ui/menu/sub_menu.rb b/lib/phlexy_ui/menu/sub_menu.rb new file mode 100644 index 0000000..9a26fef --- /dev/null +++ b/lib/phlexy_ui/menu/sub_menu.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +module PhlexyUI + class Menu + # @private + class SubMenu < Base + include Phlex::DeferredRender + + def initialize(*, **) + super + @items ||= [] + end + + def view_template(&) + attributes = ATTRIBUTES_MAP.select do |key| + base_modifiers.include?(key) + end + + details(**attributes) do + if @subtitle + summary do + render @subtitle + end + end + + if @items.any? + ul do + @items.each do |item| + li do + render item + end + end + end + end + end + end + + def subtitle(&block) + @subtitle = block + end + + def item(&block) + @items << block + end + + def submenu(*, **, &) + @items << self.class.new(*, **, &) + end + + private + + ATTRIBUTES_MAP = { + open: true + }.freeze + end + end +end diff --git a/spec/lib/phlexy_ui/menu_spec.rb b/spec/lib/phlexy_ui/menu_spec.rb new file mode 100644 index 0000000..0df3990 --- /dev/null +++ b/spec/lib/phlexy_ui/menu_spec.rb @@ -0,0 +1,92 @@ +require "spec_helper" + +describe PhlexyUI::Dropdown do + subject(:output) { render described_class.new } + + describe "rendering a full menu" do + let(:component) do + Class.new(Phlex::HTML) do + def view_template(&) + render PhlexyUI::Menu.new(:xs) do |menu| + menu.title do + "My Menu" + end + + menu.item do + "Item 1" + end + + menu.item(:disabled) do + "Item 2" + end + + menu.item(:active) do + "Item 3" + end + + menu.item(:focus) do + "Item 4" + end + + menu.item do + menu.submenu do |submenu_1| + submenu_1.subtitle do + "Parent 1" + end + + submenu_1.item do + "Child 1" + end + + submenu_1.submenu(:open) do |submenu_2| + submenu_2.subtitle do + "Parent 2" + end + + submenu_2.item do + "Child 2" + 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 + + HTML + + is_expected.to eq(expected_html) + end + end +end