Repository: woylie/doggo
Pull request #212 (2024-01-14 06:58:32)

add menubar component
contributes to #124 


Patch:
diff --git a/lib/doggo.ex b/lib/doggo.ex
index 5bc564e..47cf681 100644
--- a/lib/doggo.ex
+++ b/lib/doggo.ex
@@ -3377,6 +3377,72 @@ defmodule Doggo do
     """
   end
 
+  @doc """
+  Renders a menubar, similar to those found in desktop applications.
+
+  This component is meant for organizing actions within an application, rather
+  than for navigating between different pages or sections of a website.
+
+  ## Example
+
+  ```heex
+  <Doggo.menubar label="Main">
+    <:item>A</:item>
+  </Doggo.menubar>
+  ```
+  """
+
+  attr :label, :string,
+    default: nil,
+    doc: """
+    A accessibility label for the menubar. Set as `aria-label` attribute.
+
+    You should ensure that either the `label` or the `labelledby` attribute is
+    set.
+    """
+
+  attr :labelledby, :string,
+    default: nil,
+    doc: """
+    The DOM ID of an element that labels this menubar.
+
+    Example:
+
+    ```html
+    <h3 id="dog-menu-label">Dog Actions</h3>
+    <.menubar labelledby="dog-menu-label"></.menubar>
+    ```
+
+    You should ensure that either the `label` or the `labelledby` attribute is
+    set.
+    """
+
+  attr :class, :any,
+    default: [],
+    doc: "Additional CSS classes. Can be a string or a list of strings."
+
+  attr :rest, :global, doc: "Any additional HTML attributes."
+
+  slot :item, required: true
+
+  def menubar(assigns) do
+    ensure_label!(assigns, "Doggo.menubar", "Dog Actions")
+
+    ~H"""
+    <ul
+      class={@class}
+      role="menubar"
+      aria-label={@label}
+      aria-labelledby={@labelledby}
+      {@rest}
+    >
+      <li :for={item <- @item} role="none">
+        <%= render_slot(item) %>
+      </li>
+    </ul>
+    """
+  end
+
   @doc """
   Renders a modal dialog for content such as forms and informational panels.
 


Test patch:
diff --git a/test/doggo_test.exs b/test/doggo_test.exs
index 31b66f6..55f931a 100644
--- a/test/doggo_test.exs
+++ b/test/doggo_test.exs
@@ -3689,6 +3689,103 @@ defmodule DoggoTest do
     end
   end
 
+  describe "menubar/1" do
+    test "default" do
+      assigns = %{}
+
+      html =
+        parse_heex(~H"""
+        <Doggo.menubar label="Dog actions">
+          <:item>A</:item>
+        </Doggo.menubar>
+        """)
+
+      ul = find_one(html, "ul:root")
+      assert attribute(ul, "role") == "menubar"
+      assert attribute(ul, "aria-label") == "Dog actions"
+
+      assert li = find_one(html, "ul > li")
+      assert attribute(li, "role") == "none"
+      assert text(li) == "A"
+    end
+
+    test "with labelledby" do
+      assigns = %{}
+
+      html =
+        parse_heex(~H"""
+        <Doggo.menubar labelledby="dog-menu-label">
+          <:item>A</:item>
+        </Doggo.menubar>
+        """)
+
+      assert attribute(html, ":root", "aria-labelledby") == "dog-menu-label"
+    end
+
+    test "raises if both label and labelledby are set" do
+      assert_raise Doggo.InvalidLabelError, fn ->
+        assigns = %{}
+
+        parse_heex(~H"""
+        <Doggo.menubar label="Dog actions" labelledby="dog-menu-label">
+          <:item>A</:item>
+        </Doggo.menubar>
+        """)
+      end
+    end
+
+    test "raises if neither label nor labelledby are set" do
+      assert_raise Doggo.InvalidLabelError, fn ->
+        assigns = %{}
+
+        parse_heex(~H"""
+        <Doggo.menubar>
+          <:item>A</:item>
+        </Doggo.menubar>
+        """)
+      end
+    end
+
+    test "with additional class as string" do
+      assigns = %{}
+
+      html =
+        parse_heex(~H"""
+        <Doggo.menubar label="Dog actions" class="is-rad">
+          <:item>A</:item>
+        </Doggo.menubar>
+        """)
+
+      assert attribute(html, ":root", "class") == "is-rad"
+    end
+
+    test "with additional classes as list" do
+      assigns = %{}
+
+      html =
+        parse_heex(~H"""
+        <Doggo.menubar label="Dog Carousel" class={["is-rad", "is-good"]}>
+          <:item>A</:item>
+        </Doggo.menubar>
+        """)
+
+      assert attribute(html, ":root", "class") == "is-rad is-good"
+    end
+
+    test "with global attribute" do
+      assigns = %{}
+
+      html =
+        parse_heex(~H"""
+        <Doggo.menubar label="Dog actions" data-test="hello">
+          <:item>A</:item>
+        </Doggo.menubar>
+        """)
+
+      assert attribute(html, ":root", "data-test") == "hello"
+    end
+  end
+
   describe "modal/1" do
     test "default" do
       assigns = %{}