refactor: replace button elements with Button component for improved consistency and styling across additional UI components

This commit is contained in:
Anish Sarkar 2026-05-14 15:02:46 +05:30
parent 13b2e874f6
commit c77babf39b
25 changed files with 148 additions and 92 deletions

View file

@ -2,6 +2,7 @@
import { Search, X } from "lucide-react";
import type { FC } from "react";
import { Button } from "@/components/ui/button";
import { DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { TabsList, TabsTrigger } from "@/components/ui/tabs";
import { cn } from "@/lib/utils";
@ -76,14 +77,16 @@ export const ConnectorDialogHeader: FC<ConnectorDialogHeaderProps> = ({
onChange={(e) => onSearchChange(e.target.value)}
/>
{searchQuery && (
<button
<Button
variant="ghost"
size="icon"
type="button"
onClick={() => onSearchChange("")}
className="absolute right-3 top-1/2 -translate-y-1/2 size-4 text-muted-foreground hover:text-accent-foreground transition-colors"
className="absolute right-1.5 top-1/2 size-7 -translate-y-1/2 text-muted-foreground transition-colors hover:bg-transparent hover:text-accent-foreground"
aria-label="Clear search"
>
<X className="size-4" />
</button>
<X data-icon="inline-start" />
</Button>
)}
</div>
</div>

View file

@ -3,6 +3,7 @@
import { AlertTriangle, X } from "lucide-react";
import type { FC } from "react";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
interface ConnectorWarningBannerProps {
@ -42,14 +43,16 @@ export const ConnectorWarningBanner: FC<ConnectorWarningBannerProps> = ({
)}
</div>
{onDismiss && (
<button
<Button
variant="ghost"
size="icon"
type="button"
onClick={handleDismiss}
className="shrink-0 p-0.5 rounded hover:bg-yellow-500/20 transition-colors"
className="size-6 shrink-0 rounded p-0 transition-colors hover:bg-yellow-500/20"
aria-label="Dismiss warning"
>
<X className="size-3.5 text-yellow-700 dark:text-yellow-300" />
</button>
<X data-icon="inline-start" className="text-yellow-700 dark:text-yellow-300" />
</Button>
)}
</div>
);

View file

@ -90,14 +90,15 @@ export const ConnectorConnectView: FC<ConnectorConnectViewProps> = ({
<div className="flex-1 flex flex-col min-h-0 overflow-hidden">
{/* Header */}
<div className="flex-shrink-0 px-6 sm:px-12 pt-8 sm:pt-10">
<button
<Button
variant="ghost"
type="button"
onClick={onBack}
className="flex items-center gap-2 text-xs sm:text-sm text-muted-foreground hover:text-accent-foreground mb-6 w-fit"
className="mb-6 h-auto w-fit justify-start gap-2 px-0 py-0 text-xs text-muted-foreground hover:bg-transparent hover:text-accent-foreground sm:text-sm"
>
<ArrowLeft className="size-4" />
<ArrowLeft data-icon="inline-start" />
Back to connectors
</button>
</Button>
<div className="flex items-center gap-4 mb-6">
<div className="flex h-14 w-14 items-center justify-center rounded-xl border border-slate-400/30">

View file

@ -206,14 +206,15 @@ export const ConnectorEditView: FC<ConnectorEditViewProps> = ({
)}
>
{/* Back button */}
<button
<Button
variant="ghost"
type="button"
onClick={onBack}
className="flex items-center gap-2 text-xs sm:text-sm text-muted-foreground hover:text-accent-foreground mb-6 w-fit"
className="mb-6 h-auto w-fit justify-start gap-2 px-0 py-0 text-xs text-muted-foreground hover:bg-transparent hover:text-accent-foreground sm:text-sm"
>
<ArrowLeft className="size-4" />
<ArrowLeft data-icon="inline-start" />
Back to connectors
</button>
</Button>
{/* Connector header */}
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-4 mb-6">

View file

@ -128,14 +128,15 @@ export const IndexingConfigurationView: FC<IndexingConfigurationViewProps> = ({
>
{/* Back button - only show if not from OAuth */}
{!isFromOAuth && (
<button
<Button
variant="ghost"
type="button"
onClick={onSkip}
className="flex items-center gap-2 text-xs sm:text-sm text-muted-foreground hover:text-accent-foreground mb-6 w-fit"
className="mb-6 h-auto w-fit justify-start gap-2 px-0 py-0 text-xs text-muted-foreground hover:bg-transparent hover:text-accent-foreground sm:text-sm"
>
<ArrowLeft className="size-4" />
<ArrowLeft data-icon="inline-start" />
Back to connectors
</button>
</Button>
)}
{/* Success header */}

View file

@ -216,14 +216,15 @@ export const YouTubeCrawlerView: FC<YouTubeCrawlerViewProps> = ({ searchSpaceId,
<div className="flex-1 flex flex-col min-h-0 overflow-hidden">
{/* Header */}
<div className="shrink-0 px-6 sm:px-12 pt-8 sm:pt-10">
<button
<Button
variant="ghost"
type="button"
onClick={onBack}
className="flex items-center gap-2 text-xs sm:text-sm text-muted-foreground hover:text-accent-foreground mb-6 w-fit"
className="mb-6 h-auto w-fit justify-start gap-2 px-0 py-0 text-xs text-muted-foreground hover:bg-transparent hover:text-accent-foreground sm:text-sm"
>
<ArrowLeft className="size-4" />
<ArrowLeft data-icon="inline-start" />
Back to connectors
</button>
</Button>
<div className="flex items-center gap-4 mb-6">
<div className="flex h-14 w-14 items-center justify-center rounded-xl border border-slate-400/30">

View file

@ -1,6 +1,7 @@
"use client";
import type { MouseEventHandler, ReactNode } from "react";
import { Button } from "@/components/ui/button";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { cn } from "@/lib/utils";
@ -60,13 +61,14 @@ export function MentionChip({
const isInteractive = Boolean(onClick) && !disabled;
const chip = (
<button
<Button
variant="ghost"
type="button"
onClick={onClick}
disabled={disabled}
aria-label={ariaLabel ?? label}
className={cn(
"inline-flex max-w-[220px] items-center gap-1.5 rounded-md border bg-background px-2 py-0.5 align-middle text-xs font-medium text-foreground leading-5 transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
"h-auto max-w-[220px] justify-start gap-1.5 rounded-md border bg-background px-2 py-0.5 align-middle text-xs leading-5 text-foreground shadow-none transition-colors focus-visible:ring-1 focus-visible:ring-ring",
isInteractive
? "cursor-pointer hover:bg-accent hover:text-accent-foreground"
: "cursor-default",
@ -76,7 +78,7 @@ export function MentionChip({
>
<span className="inline-flex shrink-0 text-muted-foreground">{icon}</span>
<span className="truncate">{label}</span>
</button>
</Button>
);
if (!tooltip) return chip;

View file

@ -4,6 +4,7 @@ import type { ReasoningMessagePartComponent } from "@assistant-ui/react";
import { ChevronRightIcon } from "lucide-react";
import { useEffect, useMemo, useState } from "react";
import { TextShimmerLoader } from "@/components/prompt-kit/loader";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
/**
@ -45,11 +46,12 @@ export const ReasoningMessagePart: ReasoningMessagePartComponent = ({ text, stat
return (
<div className="mx-auto w-full max-w-(--thread-max-width) px-2 py-2">
<div className="rounded-lg">
<button
<Button
variant="ghost"
type="button"
onClick={() => setIsOpen((prev) => !prev)}
className={cn(
"flex w-full items-center gap-1.5 text-left text-sm transition-colors",
"h-auto w-full justify-start gap-1.5 p-0 text-left text-sm font-normal transition-colors hover:bg-transparent",
"text-muted-foreground hover:text-accent-foreground"
)}
>
@ -59,9 +61,10 @@ export const ReasoningMessagePart: ReasoningMessagePartComponent = ({ text, stat
<span>{headerLabel}</span>
)}
<ChevronRightIcon
className={cn("size-4 transition-transform duration-200", isOpen && "rotate-90")}
data-icon="inline-end"
className={cn("transition-transform duration-200", isOpen && "rotate-90")}
/>
</button>
</Button>
<div
className={cn(

View file

@ -330,8 +330,15 @@ const PendingScreenImageStrip: FC = () => {
key={url}
className="group relative h-14 w-14 shrink-0 overflow-hidden rounded-md border border-border/50 bg-muted"
>
{/* biome-ignore lint/performance/noImgElement: data URL thumbnails from capture */}
<img src={url} alt="" className="size-full object-cover" draggable={false} />
<Image
src={url}
alt="Pending screenshot preview"
fill
sizes="56px"
className="object-cover"
draggable={false}
unoptimized
/>
<Button
type="button"
onClick={() => setUrls((prev) => prev.filter((_, i) => i !== index))}

View file

@ -1,6 +1,7 @@
"use client";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import type { MemberMentionItemProps } from "./types";
@ -25,10 +26,11 @@ export function MemberMentionItem({
const displayName = member.displayName || member.email.split("@")[0];
return (
<button
<Button
variant="ghost"
type="button"
className={cn(
"flex w-full items-center gap-3 px-3 py-2 text-left transition-colors",
"h-auto w-full justify-start gap-3 rounded-none px-3 py-2 text-left transition-colors",
isHighlighted ? "bg-primary/15 text-accent-foreground" : "hover:bg-accent hover:text-accent-foreground"
)}
onClick={() => onSelect(member)}
@ -44,6 +46,6 @@ export function MemberMentionItem({
<span className="truncate text-sm font-medium">{displayName}</span>
<span className="truncate text-xs text-muted-foreground">{member.email}</span>
</div>
</button>
</Button>
);
}

View file

@ -48,9 +48,9 @@ export const DEFAULT_SHORTCUTS = {
export function Kbd({ keys, className }: { keys: string[]; className?: string }) {
return (
<span className={cn("inline-flex items-center gap-0.5", className)}>
{keys.map((key, i) => (
{keys.map((key) => (
<kbd
key={`${key}-${i}`}
key={key}
className={cn(
"inline-flex h-6 min-w-6 items-center justify-center rounded border bg-muted px-1 font-mono text-[11px] font-medium text-muted-foreground",
key.length > 3 && "px-1.5"
@ -136,14 +136,15 @@ export function ShortcutRecorder({
<RotateCcw className="size-3" />
</Button>
)}
<button
<Button
variant="ghost"
ref={inputRef}
type="button"
onClick={() => setRecording(true)}
onKeyDown={handleKeyDown}
onBlur={() => setRecording(false)}
className={cn(
"flex h-7 items-center gap-0.5 rounded-md border px-2 transition-all focus:outline-none",
"h-7 justify-start gap-0.5 rounded-md border px-2 transition-all",
recording
? "border-primary bg-primary/5 ring-2 ring-primary/20"
: "border-input bg-muted/40 hover:bg-muted"
@ -156,7 +157,7 @@ export function ShortcutRecorder({
) : (
<Kbd keys={displayKeys} />
)}
</button>
</Button>
</div>
</div>
);

View file

@ -2,6 +2,7 @@
import type { LucideIcon } from "lucide-react";
import type React from "react";
import { Button } from "@/components/ui/button";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { cn } from "@/lib/utils";
@ -22,7 +23,7 @@ interface SidebarButtonProps {
}
const baseClassName = cn(
"group/sidebar-button relative flex h-9 items-center rounded-md mx-2 px-2 text-sm text-left",
"group/sidebar-button relative h-9 justify-start gap-0 rounded-md mx-2 px-2 text-sm text-left",
"transition-colors hover:bg-accent hover:text-accent-foreground",
"focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
);
@ -49,7 +50,8 @@ export function SidebarButton({
: (expandedIconNode ?? <Icon className="h-3.5 w-3.5 shrink-0" />);
const button = (
<button
<Button
variant="ghost"
type="button"
onClick={onClick}
aria-label={isCollapsed ? label : undefined}
@ -100,7 +102,7 @@ export function SidebarButton({
)}
<span className="sr-only">{label}</span>
</button>
</Button>
);
const renderTooltip = isCollapsed || !!tooltipContent;

View file

@ -4,6 +4,7 @@ import { AnimatePresence, motion } from "motion/react";
import type React from "react";
import { useEffect, useRef, useState } from "react";
import { Pricing } from "@/components/pricing";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
const demoPlans = [
@ -264,7 +265,7 @@ function PricingFAQ() {
<div ref={containerRef} className="relative mt-16 flex w-full flex-col gap-12 px-4 md:px-8">
{faqData.map((section) => (
<div key={section.title + "faq"}>
<div key={`${section.title}faq`}>
<h3 className="mb-6 text-lg font-medium text-neutral-800 dark:text-neutral-200">
{section.title}
</h3>
@ -275,7 +276,7 @@ function PricingFAQ() {
return (
<div
key={id + "faq-item"}
key={`${id}faq-item`}
className={cn(
"relative rounded-lg transition-all duration-200",
isActive
@ -291,10 +292,11 @@ function PricingFAQ() {
<GridLineVertical className="-right-[2px] left-auto" offset="100px" />
</div>
)}
<button
<Button
variant="ghost"
type="button"
onClick={() => toggleQuestion(id)}
className="flex w-full items-center justify-between px-4 py-4 text-left"
className="h-auto w-full justify-between rounded-lg px-4 py-4 text-left hover:bg-transparent"
>
<span className="text-sm font-medium text-neutral-700 md:text-base dark:text-neutral-300">
{item.question}
@ -306,7 +308,7 @@ function PricingFAQ() {
>
<IconPlus className="size-5 text-neutral-500 dark:text-neutral-400" />
</motion.div>
</button>
</Button>
<AnimatePresence initial={false}>
{isActive && (
<motion.div

View file

@ -194,13 +194,14 @@ export function FolderWatchDialog({
</Button>
</div>
) : (
<button
<Button
variant="ghost"
type="button"
onClick={handleSelectFolder}
className="flex flex-1 w-full items-center justify-center gap-2 rounded-lg border-2 border-dashed border-muted-foreground/30 text-sm text-muted-foreground transition-colors hover:border-foreground/50 hover:text-accent-foreground"
className="h-auto flex-1 w-full gap-2 rounded-lg border-2 border-dashed border-muted-foreground/30 bg-transparent text-sm text-muted-foreground transition-colors hover:border-foreground/50 hover:bg-transparent hover:text-accent-foreground"
>
Browse for a folder
</button>
</Button>
)}
{selectedFolder && (

View file

@ -4,6 +4,7 @@ import { motion } from "motion/react";
import { useTheme } from "next-themes";
import { useCallback, useEffect, useId, useState } from "react";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
// ///////////////////////////////////////////////////////////////////////////
@ -706,10 +707,12 @@ export const ThemeToggleButton = ({
const clipPathId = `theme-toggle-clip-${clipId}`;
return (
<button
<Button
variant="ghost"
size="icon"
type="button"
className={cn(
"size-10 cursor-pointer rounded-full p-2 transition-all duration-300 active:scale-95 bg-transparent",
"size-10 cursor-pointer rounded-full bg-transparent p-2 transition-all duration-300 hover:bg-transparent active:scale-95",
isDark ? "text-white" : "text-black",
className
)}
@ -720,6 +723,7 @@ export const ThemeToggleButton = ({
<svg
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
className="size-full"
fill="currentColor"
strokeLinecap="round"
viewBox="0 0 32 32"
@ -759,7 +763,7 @@ export const ThemeToggleButton = ({
</motion.g>
</g>
</svg>
</button>
</Button>
);
};

View file

@ -3,6 +3,7 @@
import { ExternalLink, Globe } from "lucide-react";
import NextImage from "next/image";
import * as React from "react";
import { Button } from "@/components/ui/button";
import { openSafeNavigationHref, sanitizeHref } from "../shared/media";
import { cn, Popover, PopoverContent, PopoverTrigger } from "./_adapter";
import type { CitationVariant, SerializableCitation } from "./schema";
@ -126,7 +127,8 @@ export function Citation(props: CitationProps) {
return (
<Popover open={open}>
<PopoverTrigger asChild>
<button
<Button
variant="ghost"
type="button"
aria-label={title}
data-tool-ui-id={id}
@ -135,7 +137,7 @@ export function Citation(props: CitationProps) {
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
className={cn(
"inline-flex cursor-pointer items-center gap-1.5 rounded-md px-2 py-1",
"h-auto cursor-pointer gap-1.5 rounded-md px-2 py-1",
"bg-muted/60 text-sm outline-none",
"transition-colors duration-150",
"hover:bg-accent hover:text-accent-foreground",
@ -145,7 +147,7 @@ export function Citation(props: CitationProps) {
>
{iconElement}
<span className="text-muted-foreground">{domain}</span>
</button>
</Button>
</PopoverTrigger>
<PopoverContent
side="top"

View file

@ -9,6 +9,7 @@ import { z } from "zod";
import { openReportPanelAtom, reportPanelAtom } from "@/atoms/chat/report-panel.atom";
import { PlateEditor } from "@/components/editor/plate-editor";
import { TextShimmerLoader } from "@/components/prompt-kit/loader";
import { Button } from "@/components/ui/button";
import { useMediaQuery } from "@/hooks/use-media-query";
import { baseApiService } from "@/lib/apis/base-api.service";
@ -215,10 +216,11 @@ function ReportCard({
<div
className={`my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 transition-[box-shadow] duration-300 ${isActive ? "ring-1 ring-primary/50" : ""}`}
>
<button
<Button
variant="ghost"
type="button"
onClick={handleOpen}
className="w-full text-left transition-colors hover:bg-accent hover:text-accent-foreground focus:outline-none focus-visible:outline-none cursor-pointer"
className="h-auto w-full flex-col items-stretch justify-start gap-0 rounded-2xl p-0 text-left font-normal whitespace-normal transition-colors hover:bg-accent hover:text-accent-foreground focus:outline-none focus-visible:outline-none cursor-pointer"
>
<div className="px-5 pt-5 pb-4 select-none">
<p className="text-sm font-semibold text-foreground line-clamp-2">
@ -262,7 +264,7 @@ function ReportCard({
<p className="text-sm text-muted-foreground italic">No content available</p>
)}
</div>
</button>
</Button>
</div>
);
}

View file

@ -9,6 +9,7 @@ import { useCallback, useEffect, useRef, useState } from "react";
import { z } from "zod";
import { openReportPanelAtom, reportPanelAtom } from "@/atoms/chat/report-panel.atom";
import { TextShimmerLoader } from "@/components/prompt-kit/loader";
import { Button } from "@/components/ui/button";
import { useMediaQuery } from "@/hooks/use-media-query";
import { baseApiService } from "@/lib/apis/base-api.service";
import { getAuthHeaders } from "@/lib/auth-utils";
@ -281,10 +282,11 @@ function ResumeCard({
<div
className={`my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 transition-[box-shadow] duration-300 ${isActive ? "ring-1 ring-primary/50" : ""}`}
>
<button
<Button
variant="ghost"
type="button"
onClick={handleOpen}
className="w-full text-left transition-colors hover:bg-accent hover:text-accent-foreground focus:outline-none focus-visible:outline-none cursor-pointer select-none"
className="h-auto w-full flex-col items-stretch justify-start gap-0 rounded-2xl p-0 text-left font-normal whitespace-normal transition-colors hover:bg-accent hover:text-accent-foreground focus:outline-none focus-visible:outline-none cursor-pointer select-none"
>
<div className="px-5 pt-5 pb-4">
<p className="text-sm font-semibold text-foreground line-clamp-2">{title}</p>
@ -316,7 +318,7 @@ function ResumeCard({
</div>
)}
</div>
</button>
</Button>
</div>
);
}

View file

@ -6,6 +6,7 @@ import type { TCalloutElement } from "platejs";
import { PlateElement, type PlateElementProps, useEditorPlugin } from "platejs/react";
import * as React from "react";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
const calloutVariants = cva("my-1 flex w-full items-start gap-2 rounded-lg border p-4", {
@ -24,7 +25,10 @@ const calloutVariants = cva("my-1 flex w-full items-start gap-2 rounded-lg borde
},
});
const calloutIcons: Record<string, string> = {
const variantCycle = ["info", "warning", "error", "success", "note", "tip"] as const;
type CalloutVariant = (typeof variantCycle)[number];
const calloutIcons: Record<CalloutVariant, string> = {
info: "💡",
warning: "⚠️",
error: "🚨",
@ -33,13 +37,13 @@ const calloutIcons: Record<string, string> = {
tip: "💜",
};
const variantCycle = ["info", "warning", "error", "success", "note", "tip"] as const;
export function CalloutElement({ children, ...props }: PlateElementProps<TCalloutElement>) {
const { editor } = useEditorPlugin(CalloutPlugin);
const element = props.element;
const variant = element.variant || "info";
const icon = element.icon || calloutIcons[variant] || "💡";
const variant = variantCycle.includes(element.variant as CalloutVariant)
? (element.variant as CalloutVariant)
: "info";
const icon = element.icon || calloutIcons[variant];
const cycleVariant = React.useCallback(() => {
const currentIndex = variantCycle.indexOf(variant as (typeof variantCycle)[number]);
@ -58,17 +62,18 @@ export function CalloutElement({ children, ...props }: PlateElementProps<TCallou
return (
<PlateElement
{...props}
className={cn(calloutVariants({ variant: variant as any }), props.className)}
className={cn(calloutVariants({ variant }), props.className)}
>
<button
className="mt-0.5 shrink-0 cursor-pointer select-none text-lg leading-none"
<Button
variant="ghost"
className="mt-0.5 h-auto shrink-0 cursor-pointer select-none p-0 text-lg leading-none hover:bg-transparent"
contentEditable={false}
onClick={cycleVariant}
type="button"
aria-label="Change callout type"
>
{icon}
</button>
</Button>
<div className="min-w-0 flex-1">{children}</div>
</PlateElement>
);

View file

@ -263,11 +263,12 @@ function SidebarTrigger({ className, onClick, ...props }: React.ComponentProps<t
);
}
function SidebarRail({ className, ...props }: React.ComponentProps<"button">) {
function SidebarRail({ className, ...props }: React.ComponentProps<typeof Button>) {
const { toggleSidebar } = useSidebar();
return (
<button
<Button
variant="ghost"
data-sidebar="rail"
data-slot="sidebar-rail"
aria-label="Toggle Sidebar"
@ -275,7 +276,7 @@ function SidebarRail({ className, ...props }: React.ComponentProps<"button">) {
onClick={toggleSidebar}
title="Toggle Sidebar"
className={cn(
"hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] sm:flex",
"hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden h-auto w-4 -translate-x-1/2 rounded-none p-0 transition-all ease-linear hover:bg-transparent group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] sm:flex",
"in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize",
"[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize",
"hover:group-data-[collapsible=offcanvas]:bg-sidebar group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full",

View file

@ -3,8 +3,8 @@
import { useToggleButton, useToggleButtonState } from "@platejs/toggle/react";
import { ChevronRightIcon } from "lucide-react";
import { PlateElement, type PlateElementProps } from "platejs/react";
import * as React from "react";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
export function ToggleElement({ children, ...props }: PlateElementProps) {
@ -14,7 +14,9 @@ export function ToggleElement({ children, ...props }: PlateElementProps) {
return (
<PlateElement {...props} className="relative py-1 pl-6">
<button
<Button
variant="ghost"
size="icon"
className={cn(
"absolute top-1.5 left-0 flex size-6 cursor-pointer select-none items-center justify-center rounded-sm text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground"
)}
@ -25,7 +27,7 @@ export function ToggleElement({ children, ...props }: PlateElementProps) {
<ChevronRightIcon
className={cn("size-4 transition-transform duration-200", open && "rotate-90")}
/>
</button>
</Button>
<div>{children}</div>
</PlateElement>
);

View file

@ -6,6 +6,7 @@ import { cva, type VariantProps } from "class-variance-authority";
import { ChevronDown } from "lucide-react";
import * as React from "react";
import { Button } from "@/components/ui/button";
import {
DropdownMenuLabel,
DropdownMenuRadioGroup,
@ -219,7 +220,8 @@ export function ToolbarSplitButtonSecondary({
...props
}: React.ComponentPropsWithoutRef<"span"> & VariantProps<typeof dropdownArrowVariants>) {
return (
<button
<Button
variant="ghost"
type="button"
className={cn(
dropdownArrowVariants({
@ -233,7 +235,7 @@ export function ToolbarSplitButtonSecondary({
{...(props as React.ComponentPropsWithoutRef<"button">)}
>
<ChevronDown className="size-3.5 text-muted-foreground" data-icon />
</button>
</Button>
);
}