From 1f6c617a249b432fae2d7652c97c16d9188c6992 Mon Sep 17 00:00:00 2001 From: Marcelo Alexandre Date: Mon, 12 May 2025 09:32:48 -0300 Subject: [PATCH] Add DropdownMenuOverlay --- .../dropdown_menu/dropdown_menu_content.rb | 2 +- .../dropdown_menu/dropdown_menu_overlay.rb | 21 +++++++++++++++++++ .../ruby_ui/dropdown_menu_controller.js | 12 +++++++++-- app/views/docs/dropdown_menu.rb | 19 +++++++++++++++++ 4 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 app/components/ruby_ui/dropdown_menu/dropdown_menu_overlay.rb diff --git a/app/components/ruby_ui/dropdown_menu/dropdown_menu_content.rb b/app/components/ruby_ui/dropdown_menu/dropdown_menu_content.rb index 44b8e16..07c2ec5 100644 --- a/app/components/ruby_ui/dropdown_menu/dropdown_menu_content.rb +++ b/app/components/ruby_ui/dropdown_menu/dropdown_menu_content.rb @@ -15,7 +15,7 @@ def default_attrs data: { state: :open }, - class: "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-background p-1 text-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 w-56" + class: "relative z-50 min-w-[8rem] overflow-hidden rounded-md border bg-background p-1 text-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 w-56" } end end diff --git a/app/components/ruby_ui/dropdown_menu/dropdown_menu_overlay.rb b/app/components/ruby_ui/dropdown_menu/dropdown_menu_overlay.rb new file mode 100644 index 0000000..3138922 --- /dev/null +++ b/app/components/ruby_ui/dropdown_menu/dropdown_menu_overlay.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module RubyUI + class DropdownMenuOverlay < Base + def view_template + div(**attrs) + end + + private + + def default_attrs + { + data: { + ruby_ui__dropdown_menu_target: "overlay", + action: "click->ruby-ui--dropdown-menu#onClickOutside" + }, + class: "absolute fixed inset-0 z-40 bg-black opacity-20 hidden" + } + end + end +end diff --git a/app/javascript/controllers/ruby_ui/dropdown_menu_controller.js b/app/javascript/controllers/ruby_ui/dropdown_menu_controller.js index 266c0fe..65a9855 100644 --- a/app/javascript/controllers/ruby_ui/dropdown_menu_controller.js +++ b/app/javascript/controllers/ruby_ui/dropdown_menu_controller.js @@ -2,7 +2,7 @@ import { Controller } from "@hotwired/stimulus"; import { computePosition, flip, shift, offset } from "@floating-ui/dom"; export default class extends Controller { - static targets = ["trigger", "content", "menuItem"]; + static targets = ["trigger", "content", "menuItem", "overlay"]; static values = { open: { type: Boolean, @@ -33,7 +33,7 @@ export default class extends Controller { onClickOutside(event) { if (!this.openValue) return; - if (this.element.contains(event.target)) return; + if (this.element.contains(event.target) && (!this.hasOverlayTarget || event.target !== this.overlayTarget)) return; event.preventDefault(); this.close(); @@ -49,12 +49,20 @@ export default class extends Controller { this.#addEventListeners(); this.#computeTooltip() this.contentTarget.classList.remove("hidden"); + + if (this.hasOverlayTarget) { + this.overlayTarget.classList.remove("hidden"); + } } close() { this.openValue = false; this.#removeEventListeners(); this.contentTarget.classList.add("hidden"); + + if (this.hasOverlayTarget) { + this.overlayTarget.classList.add("hidden"); + } } #handleKeydown(e) { diff --git a/app/views/docs/dropdown_menu.rb b/app/views/docs/dropdown_menu.rb index 12261ab..e0d1244 100644 --- a/app/views/docs/dropdown_menu.rb +++ b/app/views/docs/dropdown_menu.rb @@ -222,6 +222,25 @@ def view_template RUBY end + render Docs::VisualCodeExample.new(title: "Overlay", context: self) do + <<~RUBY + DropdownMenu do + DropdownMenuOverlay() + DropdownMenuTrigger(class: 'w-full') do + Button(variant: :outline) { "Open" } + end + DropdownMenuContent do + DropdownMenuLabel { "My Account" } + DropdownMenuSeparator + DropdownMenuItem(href: '#') { "Profile" } + DropdownMenuItem(href: '#') { "Billing" } + DropdownMenuItem(href: '#') { "Team" } + DropdownMenuItem(href: '#') { "Subscription" } + end + end + RUBY + end + render Components::ComponentSetup::Tabs.new(component_name: component) render Docs::ComponentsTable.new(component_files(component))