diff --git a/packages/js/components/changelog/add-34331_popover_to_select_control_dropdown b/packages/js/components/changelog/add-34331_popover_to_select_control_dropdown new file mode 100644 index 00000000000..20f4ddf6ee3 --- /dev/null +++ b/packages/js/components/changelog/add-34331_popover_to_select_control_dropdown @@ -0,0 +1,4 @@ +Significance: minor +Type: update + +Add support in SelectControl for using the popover slot for the popover. diff --git a/packages/js/components/src/experimental-select-control/menu.scss b/packages/js/components/src/experimental-select-control/menu.scss index 3592eec2d9b..7c1f126b447 100644 --- a/packages/js/components/src/experimental-select-control/menu.scss +++ b/packages/js/components/src/experimental-select-control/menu.scss @@ -5,13 +5,25 @@ left: 0; margin-top: $gap-smaller; box-sizing: border-box; - display: none; +} + +.components-popover.woocommerce-experimental-select-control__popover-menu { background: $studio-white; border: 1px solid $studio-gray-5; border-radius: 3px; - z-index: 10; - + display: none; &.is-open.has-results { display: block; } } +.woocommerce-experimental-select-control__popover-menu-container { + margin: 0; + max-height: 300px; + overflow-y: scroll; + + > .category-field-dropdown__item:not( :first-child ) { + .category-field-dropdown__item-content { + border-top: 1px solid $gray-200; + } + } +} diff --git a/packages/js/components/src/experimental-select-control/menu.tsx b/packages/js/components/src/experimental-select-control/menu.tsx index 22e2adb552b..5b5cd8de526 100644 --- a/packages/js/components/src/experimental-select-control/menu.tsx +++ b/packages/js/components/src/experimental-select-control/menu.tsx @@ -1,8 +1,15 @@ /** * External dependencies */ +import { Popover } from '@wordpress/components'; import classnames from 'classnames'; -import { createElement } from '@wordpress/element'; +import { + createElement, + useEffect, + useRef, + useState, + createPortal, +} from '@wordpress/element'; /** * Internal dependencies @@ -22,21 +29,63 @@ export const Menu = ( { isOpen, className, }: MenuProps ) => { + const [ boundingRect, setBoundingRect ] = useState< DOMRect >(); + const selectControlMenuRef = useRef< HTMLDivElement >( null ); + + useEffect( () => { + if ( selectControlMenuRef.current?.parentElement ) { + setBoundingRect( + selectControlMenuRef.current.parentElement.getBoundingClientRect() + ); + } + }, [ selectControlMenuRef.current ] ); + + /* eslint-disable jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/click-events-have-key-events */ + /* Disabled because of the onmouseup on the ul element below. */ return ( - + 0, + } + ) } + position="bottom center" + animate={ false } + > + + + ); + /* eslint-enable jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/click-events-have-key-events */ }; + +export const MenuSlot: React.FC = () => + createPortal( +
+ +
, + document.body + ); diff --git a/packages/js/components/src/experimental-select-control/stories/index.tsx b/packages/js/components/src/experimental-select-control/stories/index.tsx index c36cae46cfd..c13f9c88ebd 100644 --- a/packages/js/components/src/experimental-select-control/stories/index.tsx +++ b/packages/js/components/src/experimental-select-control/stories/index.tsx @@ -1,7 +1,13 @@ /** * External dependencies */ -import { CheckboxControl, Spinner } from '@wordpress/components'; +import { + Button, + CheckboxControl, + Modal, + SlotFillProvider, + Spinner, +} from '@wordpress/components'; import React from 'react'; import { createElement, useState } from '@wordpress/element'; @@ -11,7 +17,7 @@ import { createElement, useState } from '@wordpress/element'; import { SelectedType, DefaultItemType, getItemLabelType } from '../types'; import { MenuItem } from '../menu-item'; import { SelectControl, selectControlStateChangeTypes } from '../'; -import { Menu } from '../menu'; +import { Menu, MenuSlot } from '../menu'; const sampleItems = [ { value: 'apple', label: 'Apple' }, @@ -365,6 +371,45 @@ export const CustomItemType: React.FC = () => { ); }; +export const SingleWithinModalUsingBodyDropdownPlacement: React.FC = () => { + const [ isOpen, setOpen ] = useState( true ); + const [ selected, setSelected ] = + useState< SelectedType< DefaultItemType > >(); + const [ selectedTwo, setSelectedTwo ] = + useState< SelectedType< DefaultItemType > >(); + + return ( + + Selected: { JSON.stringify( selected ) } + + { isOpen && ( + setOpen( false ) } + > + item && setSelected( item ) } + onRemove={ () => setSelected( null ) } + /> + item && setSelectedTwo( item ) } + onRemove={ () => setSelectedTwo( null ) } + /> + + ) } + + + ); +}; + export default { title: 'WooCommerce Admin/experimental/SelectControl', component: SelectControl, diff --git a/packages/js/components/src/index.ts b/packages/js/components/src/index.ts index 19663facc15..a4c2248355f 100644 --- a/packages/js/components/src/index.ts +++ b/packages/js/components/src/index.ts @@ -49,7 +49,10 @@ export { MenuItem as __experimentalSelectControlMenuItem, MenuItemProps as __experimentalSelectControlMenuItemProps, } from './experimental-select-control/menu-item'; -export { Menu as __experimentalSelectControlMenu } from './experimental-select-control/menu'; +export { + Menu as __experimentalSelectControlMenu, + MenuSlot as __experimentalSelectControlMenuSlot, +} from './experimental-select-control/menu'; export { default as ScrollTo } from './scroll-to'; export { Sortable } from './sortable'; export { ListItem } from './list-item';