diff --git a/components/formElements/TextEditor.tsx b/components/formElements/TextEditor.tsx index df0bf80..d6e187f 100644 --- a/components/formElements/TextEditor.tsx +++ b/components/formElements/TextEditor.tsx @@ -20,6 +20,12 @@ import FileUpload from '@/components/media/FileUpload' import ConsumerModal from '@/components/consumer/ConsumerModal' import { fileAddress, coerceToString } from '@/helpers' import { cn } from '@/lib/cn' +import { buttonVariants } from '@heroui/react' + +const CONSUMER_TOOLBAR_TRIGGER_CLASS = + 'min-h-10 rounded-[10px] border border-consumer-border bg-consumer-surface px-3 text-sm font-medium text-consumer-text outline-none' + +const ADMIN_TOOLBAR_TRIGGER_CLASS = cn(buttonVariants({ size: 'sm', variant: 'secondary' }), 'outline-none') interface TextEditorProps { label?: string @@ -186,14 +192,11 @@ const TextEditor = ({ label, required, value, onChange, className, variant = 'de {isConsumer ? ( <> - - + + عنوان - - + + فهرست - - - + heading - - - + link ['placement'] | 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end' trigger?: 'press' | 'longPress' } -export function DropdownTrigger({ children }: { children?: ReactNode }) { +export function DropdownTrigger({ children }: DropdownTriggerProps) { return children } @@ -124,13 +132,65 @@ function renderMenuChildren(children: ReactNode, showIndicator: boolean): ReactN }) } +function isButtonLikeTrigger(child: ReactElement): boolean { + if (typeof child.type === 'string') return child.type === 'button' + + const displayName = + typeof child.type === 'function' || typeof child.type === 'object' + ? (child.type as { displayName?: string; name?: string }).displayName || + (child.type as { name?: string }).name + : undefined + + return displayName === 'ConsumerButton' || displayName === 'Button' +} + +/** Button/`button` داخل MenuTrigger reliably باز نمی‌شود؛ محتوا را به Dropdown.Trigger واقعی منتقل می‌کنیم. */ +function resolveTrigger(triggerElement: ReactElement): { + 'aria-label'?: string + className?: string + content: ReactNode + isDisabled?: boolean + style?: CSSProperties +} { + const { children, className, isDisabled, style } = triggerElement.props + const ariaLabel = triggerElement.props['aria-label'] + const onlyChild = Children.count(children) === 1 ? Children.toArray(children)[0] : null + + if (isValidElement(onlyChild) && isButtonLikeTrigger(onlyChild)) { + const nested = onlyChild.props as { + 'aria-label'?: string + children?: ReactNode + className?: string + disabled?: boolean + style?: CSSProperties + } + + return { + 'aria-label': nested['aria-label'] ?? ariaLabel, + className: nested.className ?? className, + content: nested.children, + isDisabled: nested.disabled ?? isDisabled, + style: nested.style ?? style, + } + } + + return { + 'aria-label': ariaLabel, + className, + content: children, + isDisabled, + style, + } +} + export function Dropdown({ children, placement, trigger }: DropdownProps) { const parts = Children.toArray(children).filter(isValidElement) - const triggerElement = parts.find((part) => part.type === DropdownTrigger) as ReactElement<{ children?: ReactNode }> | undefined + const triggerElement = parts.find((part) => part.type === DropdownTrigger) as ReactElement | undefined const menuElement = parts.find((part) => part.type === DropdownMenu) as ReactElement | undefined if (!triggerElement || !menuElement) return null + const resolvedTrigger = resolveTrigger(triggerElement) const menuChildren = menuElement.props.children const menuProps = { 'aria-label': menuElement.props['aria-label'], @@ -146,7 +206,14 @@ export function Dropdown({ children, placement, trigger }: DropdownProps) { return ( - {triggerElement.props.children} + + {resolvedTrigger.content} + {renderMenuChildren(menuChildren, showIndicator)} diff --git a/components/ui/UserDropdown.tsx b/components/ui/UserDropdown.tsx index 66dd37a..7c03ef9 100644 --- a/components/ui/UserDropdown.tsx +++ b/components/ui/UserDropdown.tsx @@ -1,16 +1,17 @@ 'use client' import { useRouter } from 'next/navigation' import { useMemo } from 'react' +import { buttonVariants } from '@heroui/react' import { Dropdown, DropdownItem, DropdownMenu, DropdownSection, DropdownTrigger } from '@/components/heroui/Dropdown' import { Avatar } from '@/components/heroui/Avatar' -import Button from '@/components/formElements/Button' import LogoutIcon from '@/components/icons/LogoutIcon' import { fileAddress } from '@/helpers' import { resolveUserAvatarSrc } from '@/lib/resolveUserAvatarSrc' import useAuth from '@/hooks/useAuth' import useAlertModal from '@/hooks/useAlertModal' import EditIcon from '@/components/icons/EditIcon' +import { cn } from '@/lib/cn' const UserDropdown = () => { const { user, logout } = useAuth() @@ -25,21 +26,23 @@ const UserDropdown = () => { return ( <> - - + +