Skip to content

Commit

Permalink
Add new tooltip component
Browse files Browse the repository at this point in the history
PR Description
This pull request introduces the following changes:

TooltipDemo Component:

Added a new TooltipDemo component that demonstrates the usage of the Tooltip component.
The component includes a TooltipProvider, TooltipTrigger, and TooltipContent to display a tooltip with the text "Add to library" when hovering over a button.
  • Loading branch information
cirdes committed Jul 31, 2024
1 parent c3eda6d commit 6d6b331
Show file tree
Hide file tree
Showing 20 changed files with 367 additions and 51 deletions.
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ gem "tzinfo-data", platforms: %i[ windows jruby ]
# Reduces boot times through caching; required in config/boot.rb
gem "bootsnap", require: false

gem "lucide-rails", "0.5.1"

# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]
# gem "image_processing", "~> 1.2"

Expand Down
3 changes: 3 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ GEM
loofah (2.22.0)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
lucide-rails (0.5.1)
railties (>= 4.1.0)
mail (2.8.1)
mini_mime (>= 0.1.1)
net-imap
Expand Down Expand Up @@ -279,6 +281,7 @@ DEPENDENCIES
debug
dockerfile-rails (>= 1.6)
jsbundling-rails
lucide-rails (= 0.5.1)
phlex-rails (~> 1.2)
propshaft
puma (>= 5.0)
Expand Down
4 changes: 4 additions & 0 deletions app/controllers/phlex_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@ class PhlexController < ApplicationController
def combobox
render(Phlex::Combobox.new)
end

def tooltip
render(Phlex::Tooltip.new)
end
end
26 changes: 26 additions & 0 deletions app/javascript/App/Pages/Tooltip.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import * as React from "react"

import { Button } from "../components/ui/button"
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "../components/ui/tooltip"

function TooltipDemo() {
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="outline">Hover</Button>
</TooltipTrigger>
<TooltipContent>
<p>Add to library</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
)
}

export default TooltipDemo;
10 changes: 7 additions & 3 deletions app/javascript/App/Routes.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@ import { Route, Routes } from "react-router-dom";


import Combobox from "./Pages/Combobox";
import Tooltip from "./Pages/Tooltip";


function Router() {

return (
<Routes>
<Route path="shadcn/combobox" element={<Combobox />} />
</Routes>
<div className="flex flex-col items-center mt-72 gap-10" >
<Routes>
<Route path="shadcn/combobox" element={<Combobox />} />
<Route path="shadcn/tooltip" element={<Tooltip />} />
</Routes>
</div >
);
}

Expand Down
24 changes: 24 additions & 0 deletions app/javascript/App/components/ui/tooltip.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as React from "react"
import * as TooltipPrimitive from "@radix-ui/react-tooltip"

import { cn } from "@/utils"

const TooltipProvider = TooltipPrimitive.Provider

const Tooltip = TooltipPrimitive.Root

const TooltipTrigger = TooltipPrimitive.Trigger

const TooltipContent = React.forwardRef(({ className, sideOffset = 4, ...props }, ref) => (
<TooltipPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-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",
className
)}
{...props} />
))
TooltipContent.displayName = TooltipPrimitive.Content.displayName

export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
2 changes: 2 additions & 0 deletions app/javascript/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import { application } from "./application";
import PhlexuiComboboxController from "app/views/components/phlex_ui/combobox/combobox_controller";
import PhlexuiComboboxContentController from "app/views/components/phlex_ui/combobox/combobox_content_controller";
import PhlexuiComboboxItemController from "app/views/components/phlex_ui/combobox/combobox_item_controller";
import PhlexuiTooltipController from "app/views/components/phlex_ui/tooltip/tooltip_controller";


application.register("phlexui--combobox", PhlexuiComboboxController);
application.register("phlexui--combobox-content", PhlexuiComboboxContentController);
application.register("phlexui--combobox-item", PhlexuiComboboxItemController);
application.register("phlexui--tooltip", PhlexuiTooltipController);
96 changes: 96 additions & 0 deletions app/views/components/phlex_ui/button/button.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# frozen_string_literal: true

module PhlexUI
class Button < Base
def initialize(variant: :primary, size: :md, icon: false, **attrs)
@variant = variant.to_sym
@size = size.to_sym
@icon = icon
super(**attrs)
end

def view_template(&)
button(**attrs, &)
end

private

def size_classes
if @icon
case @size
when :sm then "h-6 w-6"
when :md then "h-9 w-9"
when :lg then "h-10 w-10"
when :xl then "h-12 w-12"
end
else
case @size
when :sm then "px-3 py-1.5 h-8 text-xs"
when :md then "px-4 py-2 h-9 text-sm"
when :lg then "px-4 py-2 h-10 text-base"
when :xl then "px-6 py-3 h-12 text-base"
end
end
end

def primary_classes
tokens(
"whitespace-nowrap inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground shadow hover:bg-primary/90",
size_classes
)
end

def link_classes
tokens(
"whitespace-nowrap inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 text-primary underline-offset-4 hover:underline",
size_classes
)
end

def secondary_classes
tokens(
"whitespace-nowrap inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 bg-secondary text-secondary-foreground hover:bg-opacity-80",
size_classes
)
end

def destructive_classes
tokens(
"whitespace-nowrap inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
size_classes
)
end

def outline_classes
tokens(
"whitespace-nowrap inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
size_classes
)
end

def ghost_classes
tokens(
"whitespace-nowrap inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 hover:bg-accent hover:text-accent-foreground",
size_classes
)
end

def default_classes
case @variant
when :primary then primary_classes
when :link then link_classes
when :secondary then secondary_classes
when :destructive then destructive_classes
when :outline then outline_classes
when :ghost then ghost_classes
end
end

def default_attrs
{
type: "button",
class: default_classes
}
end
end
end
File renamed without changes.
26 changes: 26 additions & 0 deletions app/views/components/phlex_ui/tooltip/tooltip.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# frozen_string_literal: true

module PhlexUI
class Tooltip < Base
def initialize(placement: "top", **attrs)
@placement = placement
super(**attrs)
end

def view_template(&)
div(**attrs, &)
end

private

def default_attrs
{
data: {
controller: "phlexui--tooltip",
phlexui__tooltip_placement_value: @placement
},
class: "group"
}
end
end
end
26 changes: 26 additions & 0 deletions app/views/components/phlex_ui/tooltip/tooltip_content.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# frozen_string_literal: true

module PhlexUI
class TooltipContent < Base
def initialize(**attrs)
@id = "tooltip#{SecureRandom.hex(4)}"
super(**attrs)
end

def view_template(&block)
div(**attrs, &block)
end

private

def default_attrs
{
id: @id,
data: {
phlexui__tooltip_target: "content"
},
class: "invisible peer-hover:visible peer-focus:visible w-max absolute top-0 left-0 z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md peer-focus:zoom-in-95 animate-out fade-out-0 zoom-out-95 peer-hover:animate-in peer-focus:animate-in peer-hover:fade-in-0 peer-focus:fade-in-0 peer-hover:zoom-in-95 group-data-[phlexui--tooltip-placement-value=bottom]:slide-in-from-top-2 group-data-[phlexui--tooltip-placement-value=left]:slide-in-from-right-2 group-data-[phlexui--tooltip-placement-value=right]:slide-in-from-left-2 group-data-[phlexui--tooltip-placement-value=top]:slide-in-from-bottom-2 delay-500"
}
end
end
end
37 changes: 37 additions & 0 deletions app/views/components/phlex_ui/tooltip/tooltip_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Controller } from "@hotwired/stimulus";
import { computePosition, autoUpdate, offset } from "@floating-ui/dom";

export default class extends Controller {
static targets = ["trigger", "content"];
static values = { placement: String }

constructor(...args) {
super(...args);
this.cleanup;
}

connect() {
this.setFloatingElement();

const tooltipId = this.contentTarget.getAttribute("id");
this.triggerTarget.setAttribute("aria-describedby", tooltipId);

}

disconnect() {
this.cleanup();
}

setFloatingElement() {
console.log(this.placementValue);

this.cleanup = autoUpdate(this.triggerTarget, this.contentTarget, () => {
computePosition(this.triggerTarget, this.contentTarget, { placement: this.placementValue, middleware: [offset(4)] }).then(({ x, y }) => {
Object.assign(this.contentTarget.style, {
left: `${x}px`,
top: `${y}px`,
});
});
});
}
}
19 changes: 19 additions & 0 deletions app/views/components/phlex_ui/tooltip/tooltip_trigger.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

module PhlexUI
class TooltipTrigger < Base
def view_template(&)
Button(**attrs, &)
end

private

def default_attrs
{
data: { phlexui__tooltip_target: "trigger" },
variant: :outline,
class: "peer"
}
end
end
end
2 changes: 2 additions & 0 deletions app/views/main/index.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ def view_template

ul(class: "max-w-md space-y-1 text-gray-500 list-disc list-inside dark:text-gray-400") do
li { a(href: "/phlex/combobox", class: "font-medium text-blue-600 dark:text-blue-500 hover:underline") { "Combobox" } }
li { a(href: "/phlex/tooltip", class: "font-medium text-blue-600 dark:text-blue-500 hover:underline") { "Tooltip" } }
end
end

Expand All @@ -20,6 +21,7 @@ def view_template

ul(class: "max-w-md space-y-1 text-gray-500 list-disc list-inside dark:text-gray-400") do
li { a(href: "/shadcn/combobox", class: "font-medium text-blue-600 dark:text-blue-500 hover:underline") { "Combobox" } }
li { a(href: "/shadcn/tooltip", class: "font-medium text-blue-600 dark:text-blue-500 hover:underline") { "Tooltip" } }
end
end
end
Expand Down
Loading

0 comments on commit 6d6b331

Please sign in to comment.