[Product Block Editor]: Introduce ButtonWithDropdownMenuProps component (#43103)

* first approach

* improve story. fix TS issues

* support `variant` prop

* add position props

* add offset popover prop

* reorganize popover props

* changelog

* set component roles

* rotate chevron when opened

* Introduce defaultOpen prop

* export component

* improve story

* ensure 1px of gap

* reorganize types

* change API. Add Readme,md

* dropdownButtonLabel is optional

* fix border-radious

* minor change in doc

* pass down defaultOpen prop
This commit is contained in:
Damián Suárez 2023-12-27 12:29:37 -03:00 committed by GitHub
parent de9322fb38
commit ccdfb16fc8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 225 additions and 0 deletions

View File

@ -0,0 +1,4 @@
Significance: patch
Type: add
[Product Block Editor]: Introduce ButtonWithDropdownMenuProps component

View File

@ -0,0 +1,27 @@
# ButtonWithDropdownMenu Component
## Description
The `ButtonWithDropdownMenu` is a React component that renders a button with an associated dropdown menu. It provides flexibility in configuring the dropdown's content, appearance, and behavior.
## Usage
```jsx
import { ButtonWithDropdownMenu } from 'path_to_component';
<ButtonWithDropdownMenu
text="Add to store"
variant="secondary"
controls={ [
{
title: 'First Menu Item Label',
onClick: () => console.log( 'First option clicked' ).
},
{
title: 'Second Menu Item Label',
onClick: () => console.log( 'Second option clicked' ).
},
] }
onButtonClick={() => console.log( 'Button clicked' ) }
/>
```

View File

@ -0,0 +1,71 @@
/**
* External dependencies
*/
import { createElement } from '@wordpress/element';
import { chevronDown } from '@wordpress/icons';
import { Button, DropdownMenu, Flex, FlexItem } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
*/
import type { ButtonWithDropdownMenuProps } from './types';
export const ButtonWithDropdownMenu: React.FC<
ButtonWithDropdownMenuProps
> = ( {
text,
dropdownButtonLabel = __( 'More options', 'woocommerce' ),
onButtonClick = () => {},
controls = [],
variant = 'primary',
defaultOpen = false,
popoverProps: {
placement = 'bottom-end',
position = 'bottom left left',
offset = 0,
} = {
placement: 'bottom-end',
position: 'bottom left left',
offset: 0,
},
} ) => {
return (
<Flex
className="woocommerce-button-with-dropdown-menu"
justify="left"
gap={ 0 }
expanded={ false }
role="group"
>
<FlexItem role="none">
<Button
variant={ variant }
onClick={ onButtonClick }
className="woocommerce-button-with-dropdown-menu__main-button"
>
{ text }
</Button>
</FlexItem>
<FlexItem role="none">
<DropdownMenu
toggleProps={ {
className:
'woocommerce-button-with-dropdown-menu__dropdown-button',
variant,
} }
controls={ controls }
icon={ chevronDown }
label={ dropdownButtonLabel }
popoverProps={ {
placement,
// @ts-expect-error no exported member.
position,
offset,
} }
defaultOpen={ defaultOpen }
/>
</FlexItem>
</Flex>
);
};

View File

@ -0,0 +1,52 @@
/**
* External dependencies
*/
import React from 'react';
/**
* Internal dependencies
*/
import { ButtonWithDropdownMenu } from '../';
import type { ButtonWithDropdownMenuProps } from '../types';
export default {
title: 'Product Editor/components/ButtonWithDropdownMenu',
component: ButtonWithDropdownMenu,
};
export const Default = ( args: ButtonWithDropdownMenuProps ) => {
return (
<div
style={ {
display: 'flex',
justifyContent: 'center',
minHeight: '300px',
} }
>
<ButtonWithDropdownMenu { ...args } />
</div>
);
};
Default.args = {
text: 'Add to store',
dropdownButtonLabel: 'More options',
variant: 'secondary',
defaultOpen: false,
popoverProps: {
placement: 'bottom-end',
position: 'bottom left left',
offset: 0,
},
controls: [
{
title: 'First Menu Item Label',
onClick: function noRefCheck() {},
},
{
onClick: function noRefCheck() {},
title: 'Second Menu Item Label',
},
],
onButtonClick: console.log, // eslint-disable-line no-console
};

View File

@ -0,0 +1,19 @@
.woocommerce-button-with-dropdown-menu {
&__main-button {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
&__dropdown-button {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
&.is-opened svg {
transform: rotate( 180deg ); // @todo: consider to set the is-opened in the local state
}
}
}
.woocommerce-button-with-dropdown-menu.components-flex {
gap: 1px;
}

View File

@ -0,0 +1,50 @@
/**
* External dependencies
*/
import { Button } from '@wordpress/components';
import type {
// @ts-expect-error no exported member.
DropdownOption,
} from '@wordpress/components';
type ButtonVariant = Button.ButtonProps[ 'variant' ];
type PositionYAxis = 'top' | 'middle' | 'bottom';
type PositionXAxis = 'left' | 'center' | 'right';
type PositionCorner = 'top' | 'right' | 'bottom' | 'left';
type PopoverPlacement =
| 'left'
| 'right'
| 'bottom'
| 'top'
| 'left-end'
| 'left-start'
| 'right-end'
| 'right-start'
| 'bottom-end'
| 'bottom-start'
| 'top-end'
| 'top-start'; // @todo: pick from core
type popoverPosition =
| `${ PositionYAxis }`
| `${ PositionYAxis } ${ PositionXAxis }`
| `${ PositionYAxis } ${ PositionXAxis } ${ PositionCorner }`;
type popoverProps = {
placement?: PopoverPlacement;
position?: popoverPosition;
offset?: number;
};
export interface ButtonWithDropdownMenuProps {
text: string;
dropdownButtonLabel?: string;
variant?: ButtonVariant;
defaultOpen?: boolean;
controls?: DropdownOption[];
popoverProps?: popoverProps;
onButtonClick?: () => void;
}

View File

@ -65,3 +65,4 @@ export {
} from './block-slot-fill';
export { Label as __experimentalLabel } from './label/label';
export { ButtonWithDropdownMenu as __experimentalButtonWithDropdownMenu } from './button-with-dropdown-menu';

View File

@ -40,6 +40,7 @@
@import "components/checkbox-control/style.scss";
@import "components/add-products-modal/style.scss";
@import "components/advice-card/style.scss";
@import "components/button-with-dropdown-menu/style.scss";
/* Field Blocks */