mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-15 01:12:56 +03:00
console: improve dropdown api
## Description 🔖 This PR improves the DropdownButton API to make it more generic. - It has been renamed Dropdown. - The children are rendered as the trigger. You can now use other elements than a Button - an option prop has been added to control all the radix ui element - a group class name has been added to the trigger so you can style it based on its state, using tailwindcss-radix plugin - stories of dropdown button as styled in the Hasura design system has been added PR-URL: https://github.com/hasura/graphql-engine-mono/pull/5733 GitOrigin-RevId: 4d292ffcbec93ebae525764431e92b5ed87cb5b5
This commit is contained in:
parent
71de2e0a35
commit
bcd5851164
@ -1,7 +1,7 @@
|
||||
import { getConfirmation } from '@/components/Common/utils/jsUtils';
|
||||
import { QueryCollectionEntry } from '@/metadata/types';
|
||||
import { Button } from '@/new-components/Button';
|
||||
import { DropdownButton } from '@/new-components/DropdownButton';
|
||||
import { DropdownMenu } from '@/new-components/DropdownMenu';
|
||||
import React, { useState } from 'react';
|
||||
import { FaEllipsisH, FaPlusCircle } from 'react-icons/fa';
|
||||
import { useDeleteQueryCollections } from '../../../QueryCollections/hooks/useDeleteQueryCollections';
|
||||
@ -35,7 +35,7 @@ export const QueryCollectionHeader: React.FC<QueryCollectionHeaderProps> =
|
||||
</p>
|
||||
</div>
|
||||
<div className="relative ml-auto mr-sm">
|
||||
<DropdownButton
|
||||
<DropdownMenu
|
||||
items={[
|
||||
[
|
||||
<div
|
||||
@ -75,8 +75,10 @@ export const QueryCollectionHeader: React.FC<QueryCollectionHeaderProps> =
|
||||
],
|
||||
]}
|
||||
>
|
||||
<FaEllipsisH />
|
||||
</DropdownButton>
|
||||
<Button>
|
||||
<FaEllipsisH />
|
||||
</Button>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
<Button mode="primary" icon={<FaPlusCircle />}>
|
||||
Add Operation
|
||||
|
@ -120,7 +120,7 @@ export const Button = (props: ButtonProps) => {
|
||||
? React.cloneElement(icon, {
|
||||
className: `inline-flex ${children && 'mr-2'} ${
|
||||
size === 'sm' ? 'w-4 h-4' : 'w-5 h-5'
|
||||
}`,
|
||||
} ${icon.props.className}`,
|
||||
})
|
||||
: null}
|
||||
<span className="whitespace-nowrap max-w-full">{children}</span>
|
||||
@ -128,7 +128,7 @@ export const Button = (props: ButtonProps) => {
|
||||
? React.cloneElement(icon, {
|
||||
className: `inline-flex ${children && 'ml-2'} ${
|
||||
size === 'sm' ? 'w-4 h-4' : 'w-5 h-5'
|
||||
}`,
|
||||
} ${icon.props.className}`,
|
||||
})
|
||||
: null}
|
||||
</>
|
||||
|
@ -1 +0,0 @@
|
||||
export * from './DropdownButton';
|
@ -2,11 +2,13 @@ import { Canvas, Meta, Story, ArgsTable } from '@storybook/addon-docs';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
|
||||
import { TemplateStoriesFactory } from '@/utils/StoryUtils';
|
||||
import { DropdownButton } from '@/new-components/DropdownButton';
|
||||
import { Button } from '@/new-components/Button';
|
||||
import { DropdownMenu } from '@/new-components/DropdownMenu';
|
||||
import { FaChevronUp } from 'react-icons/fa';
|
||||
|
||||
<Meta
|
||||
title="components/Dropdown Button 🧬"
|
||||
component={DropdownButton}
|
||||
title="components/Dropdown Menu 🧬"
|
||||
component={DropdownMenu}
|
||||
parameters={{
|
||||
docs: { source: { type: 'code' } },
|
||||
chromatic: { disableSnapshot: true },
|
||||
@ -14,57 +16,79 @@ import { DropdownButton } from '@/new-components/DropdownButton';
|
||||
decorators={[Story => <div className={'p-4'}>{Story()}</div>]}
|
||||
/>
|
||||
|
||||
# DropdownButton ⚛️
|
||||
# DropdownMenu ⚛️
|
||||
|
||||
- [🧰 Overview](#-overview)
|
||||
- [🐙 Code on Github](https://github.com/hasura/graphql-engine-mono/tree/main/console/src/new-components/DropdownButton/DropdownButton.tsx)
|
||||
- [🐙 Code on Github](https://github.com/hasura/graphql-engine-mono/tree/main/console/src/new-components/DropdownMenu/DropdownMenu.tsx)
|
||||
|
||||
## 🧰 Overview
|
||||
|
||||
A component that display a button that opens a dropdown menu.
|
||||
A component that display an element that opens a dropdownMenu menu.
|
||||
|
||||
### Basic usage
|
||||
|
||||
```ts
|
||||
import { DropdownButton } from '@/new-components/DropdownButton';
|
||||
import { DropdownMenu } from '@/new-components/DropdownMenu';
|
||||
```
|
||||
|
||||
```tsx
|
||||
<DropdownButton
|
||||
<DropdownMenu
|
||||
items={[
|
||||
['Action', <span className="text-red-600">Destructive Action</span>],
|
||||
['Another action'],
|
||||
]}
|
||||
>
|
||||
The DropdownButton label
|
||||
</DropdownButton>
|
||||
The DropdownMenu label
|
||||
</DropdownMenu>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<Story name="Overview">
|
||||
<div>
|
||||
<DropdownButton
|
||||
<DropdownMenu
|
||||
items={[
|
||||
['Action', <span className="text-red-600">Destructive Action</span>],
|
||||
['Another action'],
|
||||
]}
|
||||
>
|
||||
The DropdownButton label
|
||||
</DropdownButton>
|
||||
The DropdownMenu label
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
<Canvas>
|
||||
<Story name="Dropdown Button">
|
||||
<div>
|
||||
<DropdownMenu
|
||||
items={[
|
||||
['Action', <span className="text-red-600">Destructive Action</span>],
|
||||
['Another action'],
|
||||
]}
|
||||
>
|
||||
<Button
|
||||
iconPosition="end"
|
||||
icon={
|
||||
<FaChevronUp className="transition-transform group-radix-state-open:rotate-180" />
|
||||
}
|
||||
>
|
||||
Dropdown Button
|
||||
</Button>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
#### 🚦 Usage
|
||||
|
||||
- The dropdown button is used for opening a contextual menu with list of actions
|
||||
- The `items` prop is an array of array of react nodes (each array is a group of items) that will be rendered in the dropdown
|
||||
- The Button prop is an object of props forwarded to the button component
|
||||
- The children of this component are forwarded to the button component
|
||||
- The dropdownMenu button is used for opening a contextual menu with list of actions
|
||||
- The `items` prop is an array of array of react nodes (each array is a group of items) that will be rendered in the dropdownMenu
|
||||
- The `children` of this component is the component (usually a button) that opens the menu
|
||||
- the `options` is an object of props that will be passed to radix ui components
|
||||
|
||||
## ⚙️ API
|
||||
|
||||
export const Template = args => <DropdownButton {...args} />;
|
||||
export const Template = args => <DropdownMenu {...args} />;
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
@ -74,7 +98,7 @@ export const Template = args => <DropdownButton {...args} />;
|
||||
['Action', <span className="text-red-600">Destructive</span>],
|
||||
['Another action', 'Another action'],
|
||||
],
|
||||
children: 'Button label',
|
||||
children: 'Label',
|
||||
}}
|
||||
>
|
||||
{Template.bind({})}
|
@ -1,28 +1,33 @@
|
||||
import React from 'react';
|
||||
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
|
||||
import { Button } from '@/new-components/Button';
|
||||
|
||||
interface DropdownButtonProps {
|
||||
buttonProps?: React.ComponentProps<typeof Button>;
|
||||
interface DropdownMenuProps {
|
||||
options?: {
|
||||
root?: React.ComponentProps<typeof DropdownMenuPrimitive.Root>;
|
||||
trigger?: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>;
|
||||
content?: React.ComponentProps<typeof DropdownMenuPrimitive.Content>;
|
||||
item?: React.ComponentProps<typeof DropdownMenuPrimitive.Item>;
|
||||
portal?: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>;
|
||||
};
|
||||
items: React.ReactNode[][];
|
||||
}
|
||||
|
||||
export const DropdownButton: React.FC<DropdownButtonProps> = ({
|
||||
export const DropdownMenu: React.FC<DropdownMenuProps> = ({
|
||||
children,
|
||||
buttonProps,
|
||||
items,
|
||||
options,
|
||||
}) => (
|
||||
<DropdownMenuPrimitive.Root>
|
||||
<DropdownMenuPrimitive.Trigger>
|
||||
<Button {...buttonProps}>{children}</Button>
|
||||
<DropdownMenuPrimitive.Root {...options?.root}>
|
||||
<DropdownMenuPrimitive.Trigger asChild {...options?.trigger}>
|
||||
<div className="group">{children}</div>
|
||||
</DropdownMenuPrimitive.Trigger>
|
||||
<DropdownMenuPrimitive.Portal>
|
||||
<DropdownMenuPrimitive.Content align="start">
|
||||
<DropdownMenuPrimitive.Portal {...options?.portal}>
|
||||
<DropdownMenuPrimitive.Content align="start" {...options?.content}>
|
||||
<div className="origin-top-left absolute left-0 z-10 mt-xs w-max max-w-xs rounded shadow-md bg-white ring-1 ring-gray-300 divide-y divide-gray-300 focus:outline-none">
|
||||
{items.map(group => (
|
||||
<div className="py-1">
|
||||
{group.map(item => (
|
||||
<DropdownMenuPrimitive.Item>
|
||||
<DropdownMenuPrimitive.Item {...options?.item}>
|
||||
<div className="cursor-pointer flex items-center mx-1 px-xs py-xs rounded whitespace-nowrap hover:bg-gray-100">
|
||||
{item}
|
||||
</div>
|
1
console/src/new-components/DropdownMenu/index.ts
Normal file
1
console/src/new-components/DropdownMenu/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './DropdownMenu';
|
Loading…
Reference in New Issue
Block a user