/**
* External dependencies
*/
import type { ReactNode, Ref, PropsWithoutRef, RefAttributes } from 'react';
/**
* WordPress dependencies
*/
import { __, isRTL } from '@wordpress/i18n';
import { arrowLeft, arrowRight, unseen, funnel } from '@wordpress/icons';
import {
Button,
Icon,
privateApis as componentsPrivateApis,
} from '@wordpress/components';
import { forwardRef, Children, Fragment, useContext } from '@wordpress/element';
/**
* Internal dependencies
*/
import { unlock } from '../../../lock-unlock';
import { SORTING_DIRECTIONS, sortArrows, sortLabels } from '../../../constants';
import type {
NormalizedField,
SortDirection,
ViewTable as ViewTableType,
ViewPickerTable as ViewPickerTableType,
Operator,
} from '../../../types';
import DataViewsContext from '../../dataviews-context';
import getHideableFields from '../../../utils/get-hideable-fields';
const { Menu } = unlock( componentsPrivateApis );
interface HeaderMenuProps< Item > {
fieldId: string;
view: ViewTableType | ViewPickerTableType;
fields: NormalizedField< Item >[];
onChangeView: ( view: ViewTableType | ViewPickerTableType ) => void;
onHide: ( field: NormalizedField< Item > ) => void;
setOpenedFilter: ( fieldId: string ) => void;
canMove?: boolean;
canInsertLeft?: boolean;
canInsertRight?: boolean;
}
function WithMenuSeparators( { children }: { children: ReactNode } ) {
return Children.toArray( children )
.filter( Boolean )
.map( ( child, i ) => (
{ i > 0 && }
{ child }
) );
}
const _HeaderMenu = forwardRef( function HeaderMenu< Item >(
{
fieldId,
view,
fields,
onChangeView,
onHide,
setOpenedFilter,
canMove = true,
canInsertLeft = true,
canInsertRight = true,
}: HeaderMenuProps< Item >,
ref: Ref< HTMLButtonElement >
) {
const visibleFieldIds = view.fields ?? [];
const index = visibleFieldIds?.indexOf( fieldId ) as number;
const isSorted = view.sort?.field === fieldId;
let isHidable = false;
let isSortable = false;
let canAddFilter = false;
let operators: Operator[] = [];
const field = fields.find( ( f ) => f.id === fieldId );
const { setIsShowingFilter } = useContext( DataViewsContext );
if ( ! field ) {
// No combined or regular field found.
return null;
}
isHidable = field.enableHiding !== false;
isSortable = field.enableSorting !== false;
const header = field.header;
operators = ( !! field.filterBy && field.filterBy?.operators ) || [];
// Filter can be added if:
//
// 1. The field is not already part of a view's filters.
// 2. The field has elements or Edit property.
// 3. The field does not opt-out of filtering.
// 4. The filter is not primary (if it is, it is already visible).
canAddFilter =
! view.filters?.some( ( _filter ) => fieldId === _filter.field ) &&
!! ( field.hasElements || field.Edit ) &&
field.filterBy !== false &&
! field.filterBy?.isPrimary;
if ( ! isSortable && ! canMove && ! isHidable && ! canAddFilter ) {
return header;
}
const hiddenFields = getHideableFields( view, fields ).filter(
( f ) => ! visibleFieldIds.includes( f.id )
);
const canInsert =
( canInsertLeft || canInsertRight ) && !! hiddenFields.length;
const isRtl = isRTL();
return (
);
} );
// @ts-expect-error Lift the `Item` type argument through the forwardRef.
const ColumnHeaderMenu: < Item >(
props: PropsWithoutRef< HeaderMenuProps< Item > > &
RefAttributes< HTMLButtonElement >
) => ReturnType< typeof _HeaderMenu > = _HeaderMenu;
export default ColumnHeaderMenu;