diff --git a/packages/js/product-editor/changelog/update-product-editor-introduce-button-with-dropdown-menu-cmp b/packages/js/product-editor/changelog/update-product-editor-introduce-button-with-dropdown-menu-cmp new file mode 100644 index 00000000000..fc3d53720fe --- /dev/null +++ b/packages/js/product-editor/changelog/update-product-editor-introduce-button-with-dropdown-menu-cmp @@ -0,0 +1,4 @@ +Significance: patch +Type: add + +[Product Block Editor]: Introduce ButtonWithDropdownMenuProps component diff --git a/packages/js/product-editor/src/components/button-with-dropdown-menu/Readme.md b/packages/js/product-editor/src/components/button-with-dropdown-menu/Readme.md new file mode 100644 index 00000000000..3407ec64325 --- /dev/null +++ b/packages/js/product-editor/src/components/button-with-dropdown-menu/Readme.md @@ -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'; + + console.log( 'First option clicked' ). + }, + { + title: 'Second Menu Item Label', + onClick: () => console.log( 'Second option clicked' ). + }, + ] } + onButtonClick={() => console.log( 'Button clicked' ) } +/> +``` \ No newline at end of file diff --git a/packages/js/product-editor/src/components/button-with-dropdown-menu/index.tsx b/packages/js/product-editor/src/components/button-with-dropdown-menu/index.tsx new file mode 100644 index 00000000000..b3d35a64d9d --- /dev/null +++ b/packages/js/product-editor/src/components/button-with-dropdown-menu/index.tsx @@ -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 ( + + + + + + + + + + ); +}; diff --git a/packages/js/product-editor/src/components/button-with-dropdown-menu/stories/index.tsx b/packages/js/product-editor/src/components/button-with-dropdown-menu/stories/index.tsx new file mode 100644 index 00000000000..6b47d4f6856 --- /dev/null +++ b/packages/js/product-editor/src/components/button-with-dropdown-menu/stories/index.tsx @@ -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 ( +
+ +
+ ); +}; + +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 +}; diff --git a/packages/js/product-editor/src/components/button-with-dropdown-menu/style.scss b/packages/js/product-editor/src/components/button-with-dropdown-menu/style.scss new file mode 100644 index 00000000000..ce23eda6738 --- /dev/null +++ b/packages/js/product-editor/src/components/button-with-dropdown-menu/style.scss @@ -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; +} diff --git a/packages/js/product-editor/src/components/button-with-dropdown-menu/types.ts b/packages/js/product-editor/src/components/button-with-dropdown-menu/types.ts new file mode 100644 index 00000000000..73995282d8e --- /dev/null +++ b/packages/js/product-editor/src/components/button-with-dropdown-menu/types.ts @@ -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; +} diff --git a/packages/js/product-editor/src/components/index.ts b/packages/js/product-editor/src/components/index.ts index c0f9581976c..ae1eda29315 100644 --- a/packages/js/product-editor/src/components/index.ts +++ b/packages/js/product-editor/src/components/index.ts @@ -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'; diff --git a/packages/js/product-editor/src/style.scss b/packages/js/product-editor/src/style.scss index 200504cc7c6..b7dc8253b2a 100644 --- a/packages/js/product-editor/src/style.scss +++ b/packages/js/product-editor/src/style.scss @@ -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 */