Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: migrate headless ui components to radix primitives #4517

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
"@aws-sdk/client-s3": "^3.496.0",
"@aws-sdk/lib-storage": "^3.496.0",
"@graphiql/toolkit": "^0.9.1",
"@headlessui/react": "^1.7.18",
"@heroicons/react": "^2.1.1",
"@hey/abis": "workspace:*",
"@hey/data": "workspace:*",
Expand All @@ -36,7 +35,10 @@
"@lexical/react": "^0.12.6",
"@lexical/utils": "^0.12.6",
"@livepeer/react": "^3.1.9",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-hover-card": "^1.0.7",
"@radix-ui/react-tabs": "^1.0.4",
"@tanstack/react-query": "^5.17.15",
"@wagmi/connectors": "^4.1.6",
"alchemy-sdk": "^3.1.1",
Expand Down
186 changes: 100 additions & 86 deletions apps/web/src/components/Composer/Actions/Attachment.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import type { ChangeEvent, FC } from 'react';

import MenuTransition from '@components/Shared/MenuTransition';
import { Menu } from '@headlessui/react';
import {
MusicalNoteIcon,
PhotoIcon,
Expand All @@ -13,6 +11,7 @@ import {
MediaAudioMimeType,
MediaImageMimeType
} from '@lens-protocol/metadata';
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
import { motion } from 'framer-motion';
import { useId, useRef, useState } from 'react';
import toast from 'react-hot-toast';
Expand Down Expand Up @@ -95,99 +94,114 @@ const Attachment: FC = () => {
}
};

const preventDefaultEvent = (e: Event) => {
e.preventDefault();
};

return (
<Menu as="div">
<Menu.Button
aria-label="More"
as={motion.button}
className="outline-brand-500 rounded-full outline-offset-8"
onClick={() => setShowMenu(!showMenu)}
whileTap={{ scale: 0.9 }}
>
{isUploading ? (
<Spinner size="sm" />
) : (
<Tooltip content="Media" placement="top">
<PhotoIcon className="text-brand-500 size-5" />
</Tooltip>
)}
</Menu.Button>
<MenuTransition show={showMenu}>
<Menu.Items
className="absolute z-[5] mt-2 rounded-xl border bg-white py-1 shadow-sm focus:outline-none dark:border-gray-700 dark:bg-gray-900"
<DropdownMenu.Root modal={false} onOpenChange={setShowMenu} open={showMenu}>
<div>
<DropdownMenu.Trigger asChild>
<motion.button
aria-label="More"
className="outline-brand-500 rounded-full outline-offset-8"
whileTap={{ scale: 0.9 }}
>
{isUploading ? (
<Spinner size="sm" />
) : (
<Tooltip content="Media" placement="top">
<PhotoIcon className="text-brand-500 size-5" />
</Tooltip>
)}
</motion.button>
</DropdownMenu.Trigger>
<DropdownMenu.Content
align="start"
className="radix-transition z-[5] mt-3.5 rounded-xl border bg-white py-1 shadow-sm focus:outline-none dark:border-gray-700 dark:bg-gray-900"
ref={dropdownRef}
static
>
<Menu.Item
as="label"
className={({ active }) =>
cn(
{ 'dropdown-active': active },
'menu-item !flex cursor-pointer items-center gap-1 space-x-1 rounded-lg'
)
}
<DropdownMenu.Item
className="menu-item rounded-lg focus:outline-none data-[disabled]:cursor-default data-[highlighted]:bg-gray-100 dark:data-[highlighted]:bg-gray-800"
disabled={disableImageUpload()}
htmlFor={`image_${id}`}
onSelect={preventDefaultEvent}
>
<PhotoIcon className="text-brand-500 size-4" />
<span className="text-sm">Upload image(s)</span>
<input
accept={ImageMimeType.join(',')}
className="hidden"
disabled={disableImageUpload()}
id={`image_${id}`}
multiple
onChange={handleAttachment}
type="file"
/>
</Menu.Item>
<Menu.Item
as="label"
className={({ active }) =>
cn(
{ 'dropdown-active': active },
'menu-item !flex cursor-pointer items-center gap-1 space-x-1 rounded-lg'
)
}
<label
className={cn(
{ 'cursor-pointer': !disableImageUpload() },
{ 'cursor-default': disableImageUpload() },
'!flex items-center gap-1 space-x-1'
)}
htmlFor={`image_${id}`}
>
<PhotoIcon className="text-brand-500 size-4" />
<span className="text-sm">Upload image(s)</span>

<input
accept={ImageMimeType.join(',')}
className="hidden"
disabled={disableImageUpload()}
id={`image_${id}`}
multiple
onChange={handleAttachment}
type="file"
/>
</label>
</DropdownMenu.Item>
<DropdownMenu.Item
className="menu-item rounded-lg focus:outline-none data-[disabled]:cursor-default data-[highlighted]:bg-gray-100 dark:data-[highlighted]:bg-gray-800"
disabled={Boolean(attachments.length)}
htmlFor={`video_${id}`}
onSelect={preventDefaultEvent}
>
<VideoCameraIcon className="text-brand-500 size-4" />
<span className="text-sm">Upload video</span>
<input
accept={VideoMimeType.join(',')}
className="hidden"
disabled={Boolean(attachments.length)}
id={`video_${id}`}
onChange={handleAttachment}
type="file"
/>
</Menu.Item>
<Menu.Item
as="label"
className={({ active }) =>
cn(
{ 'dropdown-active': active },
'menu-item !flex cursor-pointer items-center gap-1 space-x-1 rounded-lg'
)
}
<label
className={cn(
{ 'cursor-pointer': !Boolean(attachments.length) },
{ 'cursor-default': Boolean(attachments.length) },
'!flex items-center gap-1 space-x-1'
)}
htmlFor={`video_${id}`}
>
<VideoCameraIcon className="text-brand-500 size-4" />
<span className="text-sm">Upload video</span>

<input
accept={VideoMimeType.join(',')}
className="hidden"
disabled={Boolean(attachments.length)}
id={`video_${id}`}
onChange={handleAttachment}
type="file"
/>
</label>
</DropdownMenu.Item>
<DropdownMenu.Item
className="menu-item rounded-lg focus:outline-none data-[disabled]:cursor-default data-[highlighted]:bg-gray-100 dark:data-[highlighted]:bg-gray-800"
disabled={Boolean(attachments.length)}
htmlFor={`audio_${id}`}
onSelect={preventDefaultEvent}
>
<MusicalNoteIcon className="text-brand-500 size-4" />
<span className="text-sm">Upload audio</span>
<input
accept={AudioMimeType.join(',')}
className="hidden"
disabled={Boolean(attachments.length)}
id={`audio_${id}`}
onChange={handleAttachment}
type="file"
/>
</Menu.Item>
</Menu.Items>
</MenuTransition>
</Menu>
<label
className={cn(
{ 'cursor-pointer': !Boolean(attachments.length) },
{ 'cursor-default': Boolean(attachments.length) },
'!flex items-center gap-1 space-x-1'
)}
htmlFor={`audio_${id}`}
>
<MusicalNoteIcon className="text-brand-500 size-4" />
<span className="text-sm">Upload audio</span>
<input
accept={AudioMimeType.join(',')}
className="hidden"
disabled={Boolean(attachments.length)}
id={`audio_${id}`}
onChange={handleAttachment}
type="file"
/>
</label>
</DropdownMenu.Item>
</DropdownMenu.Content>
</div>
</DropdownMenu.Root>
);
};

Expand Down
Loading