Skip to content

Commit

Permalink
Refactor DropdownMenu (asyncapi#1108)
Browse files Browse the repository at this point in the history
  • Loading branch information
KhudaDad414 authored Jun 11, 2024
1 parent 606a933 commit a428b15
Show file tree
Hide file tree
Showing 15 changed files with 11,136 additions and 13,612 deletions.
49 changes: 19 additions & 30 deletions apps/design-system/src/components/DropdownMenu.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,31 @@
import { DropdownMenu } from '@asyncapi/studio-ui'
import React from 'react';
import { Meta } from '@storybook/react';
import { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger, DropdownMenuItem, DropdownMenuSeparator } from '@asyncapi/studio-ui'

export default {
const meta: Meta = {
component: DropdownMenu,
parameters: {
layout: 'fullscreen',
backgrounds: {
default: 'dark'
}
},
}
}

const items = [
{
title: 'Import from URL',
onSelect: () => console.log('Import from URL')
},
{
title: 'Import from file',
onSelect: () => console.log('Import from file')
},
{
title: 'Import from Base64',
onSelect: () => console.log('Import from Base64')
},
{
type: 'separator'
},
{
title: 'Generate code/docs',
onSelect: () => console.log('Generate code/docs')
},
]
export default meta


export const Default = {
args: {
trigger: <button className="text-black bg-white rounded mx-3 my-3 px-3">Click me!</button>,
items,
side: 'bottom',
align: 'start'
}
render: () => (<DropdownMenu>
<DropdownMenuTrigger asChild>
<button className="text-black bg-white rounded mx-3 my-3 px-3">Click me!</button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem onSelect={(e) => console.log(e.target)}>Import from URL</DropdownMenuItem>
<DropdownMenuItem onSelect={(e) => console.log(e.target)}>Import from file</DropdownMenuItem>
<DropdownMenuItem onSelect={(e) => console.log(e.target)}>Import from Base64</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem onSelect={(e) => console.log(e.target)}>Generate code/docs</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>)
}
36 changes: 28 additions & 8 deletions apps/design-system/src/styles/tailwind.output.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
! tailwindcss v3.3.3 | MIT License | https://tailwindcss.com
! tailwindcss v3.4.3 | MIT License | https://tailwindcss.com
*/

/*
Expand Down Expand Up @@ -32,9 +32,11 @@
4. Use the user's configured `sans` font-family by default.
5. Use the user's configured `sans` font-feature-settings by default.
6. Use the user's configured `sans` font-variation-settings by default.
7. Disable tap highlights on iOS
*/

html {
html,
:host {
line-height: 1.5;
/* 1 */
-webkit-text-size-adjust: 100%;
Expand All @@ -48,6 +50,8 @@ html {
/* 5 */
font-variation-settings: normal;
/* 6 */
-webkit-tap-highlight-color: transparent;
/* 7 */
}

/*
Expand Down Expand Up @@ -119,8 +123,10 @@ strong {
}

/*
1. Use the user's configured `mono` font family by default.
2. Correct the odd `em` font sizing in all browsers.
1. Use the user's configured `mono` font-family by default.
2. Use the user's configured `mono` font-feature-settings by default.
3. Use the user's configured `mono` font-variation-settings by default.
4. Correct the odd `em` font sizing in all browsers.
*/

code,
Expand All @@ -129,8 +135,12 @@ samp,
pre {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
/* 1 */
font-size: 1em;
font-feature-settings: normal;
/* 2 */
font-variation-settings: normal;
/* 3 */
font-size: 1em;
/* 4 */
}

/*
Expand Down Expand Up @@ -199,6 +209,8 @@ textarea {
/* 1 */
line-height: inherit;
/* 1 */
letter-spacing: inherit;
/* 1 */
color: inherit;
/* 1 */
margin: 0;
Expand All @@ -222,9 +234,9 @@ select {
*/

button,
[type='button'],
[type='reset'],
[type='submit'] {
input:where([type='button']),
input:where([type='reset']),
input:where([type='submit']) {
-webkit-appearance: button;
/* 1 */
background-color: transparent;
Expand Down Expand Up @@ -473,6 +485,10 @@ video {
--tw-backdrop-opacity: ;
--tw-backdrop-saturate: ;
--tw-backdrop-sepia: ;
--tw-contain-size: ;
--tw-contain-layout: ;
--tw-contain-paint: ;
--tw-contain-style: ;
}

::backdrop {
Expand Down Expand Up @@ -523,6 +539,10 @@ video {
--tw-backdrop-opacity: ;
--tw-backdrop-saturate: ;
--tw-backdrop-sepia: ;
--tw-contain-size: ;
--tw-contain-layout: ;
--tw-contain-paint: ;
--tw-contain-style: ;
}

.m-3 {
Expand Down
131 changes: 72 additions & 59 deletions packages/ui/components/DropdownMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,67 +1,80 @@
import type { FunctionComponent, ReactNode } from 'react'
import * as RadixDropdownMenu from '@radix-ui/react-dropdown-menu'
"use client"

interface DropdownMenuRegularItem {
type?: 'regular'
title: string
onSelect: () => void
}
import * as React from "react"
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"

interface DropdownMenuSeparatorItem {
type: 'separator'
}
import { cn } from "@asyncapi/studio-utils"

export type DropdownMenuItem = DropdownMenuRegularItem | DropdownMenuSeparatorItem
const DropdownMenu = DropdownMenuPrimitive.Root

interface DropdownMenuProps {
trigger: ReactNode
items: DropdownMenuItem[]
side?: 'top' | 'right' | 'bottom' | 'left'
align?: 'start' | 'center' | 'end'
onSelect?: (options: string[]) => void
}
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger

interface DropdownMenuItemComponentProps {
item: DropdownMenuItem
}
const DropdownMenuGroup = DropdownMenuPrimitive.Group

const DropdownMenuPortal = DropdownMenuPrimitive.Portal

const DropdownMenuSub = DropdownMenuPrimitive.Sub

const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup


const DropdownMenuContent = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
>(({ className, sideOffset = 5, ...props }, ref) => (
<DropdownMenuPrimitive.Portal>
<DropdownMenuPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
"min-w-[220px] bg-gray-950 rounded-md p-2.5 shadow",
className
)}
{...props}
/>
</DropdownMenuPrimitive.Portal>
))
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName

const DropdownMenuItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
inset?: boolean
}
>(({ className, ...props }, ref) => (
<DropdownMenuPrimitive.Item
ref={ref}
className={cn(
"text-gray-200 text-sm leading-7 px-2.5 cursor-pointer rounded outline-none select-none hover:bg-gray-700 focus:bg-gray-700",
className
)}
{...props}
/>
))
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName


const DropdownMenuSeparator = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
>(({ className, ...props }, ref) => (
<DropdownMenuPrimitive.Separator
ref={ref}
className={cn("w-full h-px bg-gray-700 my-2", className)}
{...props}
/>
))
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName

const DropdownMenuItemComponent: FunctionComponent<DropdownMenuItemComponentProps> = ({ item }) => {
return (
item.type === 'separator' ? (
<RadixDropdownMenu.Separator className="w-full h-px bg-gray-700 my-2" />
) : (
<RadixDropdownMenu.Item
className="text-gray-200 text-sm leading-7 px-2.5 cursor-pointer rounded outline-none select-none hover:bg-gray-700 focus:bg-gray-700"
onSelect={item.onSelect}
>
{item.title}
</RadixDropdownMenu.Item>
)
)
}

export const DropdownMenu: FunctionComponent<DropdownMenuProps> = ({
trigger,
items,
side,
align,
onSelect
}) => {
return (
<RadixDropdownMenu.Root>
<RadixDropdownMenu.Trigger aria-label='Select an Option.' asChild>
{trigger}
</RadixDropdownMenu.Trigger>
<RadixDropdownMenu.Portal>
<RadixDropdownMenu.Content className="min-w-[220px] bg-gray-950 rounded-md p-2.5 shadow" sideOffset={5} side={side} align={align}>
{
items.map((item, index) => (
<DropdownMenuItemComponent key={index} item={item} />
))
}
<RadixDropdownMenu.Arrow className="fill-gray-950" />
</RadixDropdownMenu.Content>
</RadixDropdownMenu.Portal>
</RadixDropdownMenu.Root>
)
export {
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuGroup,
DropdownMenuPortal,
DropdownMenuSub,
DropdownMenuRadioGroup,
}
33 changes: 23 additions & 10 deletions packages/ui/components/Toolbar.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Tooltip from './Tooltip'
import * as RadixToolbar from '@radix-ui/react-toolbar'
import { FunctionComponent } from 'react'
import { DropdownMenu, DropdownMenuItem } from './DropdownMenu'
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from './DropdownMenu'

interface ToolbarToggleItem {
type: 'toggle'
Expand Down Expand Up @@ -31,10 +31,21 @@ interface ToolbarSeparatorItem {
type: 'separator'
}

interface DropdownMenuRegularItem {
type?: 'regular'
title: string
onSelect: () => void
}

interface DropdownMenuSeparatorItem {
type: 'separator'
}

type DropdownMenuItemInterface = DropdownMenuRegularItem | DropdownMenuSeparatorItem
interface ToolbarDropdownMenuItem {
type: 'dropdownMenu',
icon: FunctionComponent<any>
items: DropdownMenuItem[]
items: DropdownMenuItemInterface[]
}

type ToolbarItem = ToolbarToggleItem | ToolbarToggleGroupSingleItem | ToolbarToggleGroupMultipleItem | ToolbarSeparatorItem | ToolbarDropdownMenuItem
Expand Down Expand Up @@ -117,17 +128,19 @@ const ToolbarItem: FunctionComponent<ToolbarItemProps> = ({ item }) => {
)
} else if (type === 'dropdownMenu') {
return (
<DropdownMenu
trigger={
<DropdownMenu>
<DropdownMenuTrigger asChild>
<button className="flex text-sm focus:outline-none border-box py-2 my-3.5 text-gray-500 hover:text-white focus:text-white rounded">
<item.icon className="w-6 h-6"/>
</button>
}
items={item.items}
side="bottom"
align="end"
/>

</DropdownMenuTrigger>
<DropdownMenuContent>
{item.items.map((menuItem) => (
menuItem.type === 'separator' ? <DropdownMenuSeparator key={menuItem.type} /> :
<DropdownMenuItem key={menuItem.title} onSelect={menuItem.onSelect}>{menuItem.title}</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
)
}
throw new Error(`Unsupported type of Toolbar item: ${type}`)
Expand Down
Loading

0 comments on commit a428b15

Please sign in to comment.