UNPKG

@wordpress/editor

Version:
210 lines (197 loc) 4.92 kB
/** * External dependencies */ import clsx from 'clsx'; /** * WordPress dependencies */ import { RawHTML, useRef, useState } from '@wordpress/element'; import { __experimentalConfirmDialog as ConfirmDialog, Button, privateApis as componentsPrivateApis, } from '@wordpress/components'; import { __, _x, sprintf } from '@wordpress/i18n'; import { moreVertical, published } from '@wordpress/icons'; /** * Internal dependencies */ import { NoteCard } from './note-card'; import { NoteForm } from './note-form'; import { unlock } from '../../lock-unlock'; const { Menu } = unlock( componentsPrivateApis ); function NoteActionsMenu( { items, buttonRef } ) { return ( <Menu placement="bottom-end"> <Menu.TriggerButton render={ <Button ref={ buttonRef } size="small" icon={ moreVertical } label={ __( 'Actions' ) } disabled={ ! items.length } accessibleWhenDisabled /> } /> <Menu.Popover // The menu popover is rendered in a portal, which causes focus to be // lost and the note to be collapsed unintentionally. To prevent this, // the popover should be rendered as an inline. modal={ false } > { items.map( ( item ) => ( <Menu.Item key={ item.id } onClick={ item.onClick }> <Menu.ItemLabel>{ item.title }</Menu.ItemLabel> </Menu.Item> ) ) } </Menu.Popover> </Menu> ); } export function Note( { note, parentNote, isSelected, onEditNote, onDeleteNote, onResolve, } ) { const [ actionState, setActionState ] = useState( null ); const actionButtonRef = useRef( null ); const canResolve = note.parent === 0; const isResolutionNote = note.type === 'note' && note.meta && ( note.meta._wp_note_status === 'resolved' || note.meta._wp_note_status === 'reopen' ); const menuItems = [ { id: 'edit', title: __( 'Edit' ), isEligible: ( { status } ) => status !== 'approved', onClick: () => setActionState( 'edit' ), }, { id: 'reopen', title: _x( 'Reopen', 'Reopen note' ), isEligible: ( { status } ) => status === 'approved', onClick: () => onEditNote( { id: note.id, status: 'hold' } ), }, { id: 'delete', title: __( 'Delete' ), isEligible: () => true, onClick: () => setActionState( 'delete' ), }, ]; const availableItems = parentNote?.status !== 'approved' ? menuItems.filter( ( item ) => item.isEligible( note ) ) : []; const deleteConfirmMessage = note.parent === 0 ? __( "Are you sure you want to delete this note? This will also delete all of this note's replies." ) : __( 'Are you sure you want to delete this reply?' ); const handleCancel = () => { setActionState( null ); actionButtonRef.current?.focus(); }; let body; if ( actionState === 'edit' ) { body = ( <NoteForm onSubmit={ ( value ) => { onEditNote( { id: note.id, content: value } ); setActionState( null ); actionButtonRef.current?.focus(); } } onCancel={ handleCancel } note={ note } labels={ { submit: _x( 'Update', 'verb' ), input: sprintf( // translators: %1$s: note identifier, %2$s: author name. __( 'Edit note %1$s by %2$s' ), note.id, note.author_name ), } } /> ); } else if ( isResolutionNote ) { const actionText = note.meta._wp_note_status === 'resolved' ? __( 'Marked as resolved' ) : __( 'Reopened' ); const raw = note?.content?.raw; const text = raw && typeof raw === 'string' && raw.trim() !== '' ? sprintf( // translators: %1$s: action label ("Marked as resolved" or "Reopened"); %2$s: note text. __( '%1$s: %2$s' ), actionText, raw ) : actionText; body = ( <RawHTML className={ clsx( 'editor-collab-sidebar-panel__note-content', 'editor-collab-sidebar-panel__resolution-text' ) } > { text } </RawHTML> ); } else { body = ( <RawHTML className="editor-collab-sidebar-panel__note-content"> { note?.content?.rendered } </RawHTML> ); } const actions = isSelected ? ( <> { canResolve && onResolve && ( <Button label={ _x( 'Resolve', 'Mark note as resolved' ) } size="small" icon={ published } disabled={ note.status === 'approved' } accessibleWhenDisabled={ note.status === 'approved' } onClick={ onResolve } /> ) } <NoteActionsMenu items={ availableItems } buttonRef={ actionButtonRef } /> </> ) : null; return ( <NoteCard note={ note } actions={ actions } role={ note.parent !== 0 ? 'treeitem' : undefined } > { body } { actionState === 'delete' && ( <ConfirmDialog isOpen onConfirm={ () => { onDeleteNote( note ); setActionState( null ); } } onCancel={ handleCancel } confirmButtonText={ __( 'Delete' ) } > { deleteConfirmMessage } </ConfirmDialog> ) } </NoteCard> ); }