diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/components/ButtonAddChildDoc.tsx b/src/frontend/apps/impress/src/features/docs/doc-tree/components/ButtonAddChildDoc.tsx new file mode 100644 index 00000000..522905f6 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-tree/components/ButtonAddChildDoc.tsx @@ -0,0 +1,76 @@ +import { useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { BoxButton, Icon } from '@/components'; + +type ButtonAddChildDocProps = { + onCreateChild: (params: { parentId: string }) => void; + parentId: string; + title?: string | null; +}; + +export const ButtonAddChildDoc = ({ + onCreateChild, + parentId, + title, +}: ButtonAddChildDocProps) => { + const { t } = useTranslation(); + + const preventDefaultAndStopPropagation = useCallback( + (e: React.MouseEvent | React.KeyboardEvent) => { + e.stopPropagation(); + e.preventDefault(); + }, + [], + ); + + const isValidKeyEvent = useCallback((e: React.KeyboardEvent) => { + return e.key === 'Enter' || e.key === ' '; + }, []); + + const handleClick = useCallback( + (e: React.MouseEvent) => { + preventDefaultAndStopPropagation(e); + void onCreateChild({ parentId }); + }, + [onCreateChild, parentId, preventDefaultAndStopPropagation], + ); + + const handleKeyDown = useCallback( + (e: React.KeyboardEvent) => { + if (isValidKeyEvent(e)) { + preventDefaultAndStopPropagation(e); + void onCreateChild({ parentId }); + } + }, + [ + onCreateChild, + parentId, + preventDefaultAndStopPropagation, + isValidKeyEvent, + ], + ); + + return ( + + + ); +}; diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/components/ButtonMoreOptions.tsx b/src/frontend/apps/impress/src/features/docs/doc-tree/components/ButtonMoreOptions.tsx new file mode 100644 index 00000000..73a38a79 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-tree/components/ButtonMoreOptions.tsx @@ -0,0 +1,73 @@ +import { useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; +import { css } from 'styled-components'; + +import { Icon } from '@/components'; + +type ButtonMoreOptionsProps = { + isOpen?: boolean; + onOpenChange?: (isOpen: boolean) => void; + title?: string | null; + className?: string; +}; + +export const ButtonMoreOptions = ({ + isOpen, + onOpenChange, + title, + className = 'icon-button', +}: ButtonMoreOptionsProps) => { + const { t } = useTranslation(); + + const preventDefaultAndStopPropagation = useCallback( + (e: React.MouseEvent | React.KeyboardEvent) => { + e.stopPropagation(); + e.preventDefault(); + }, + [], + ); + + const isValidKeyEvent = useCallback((e: React.KeyboardEvent) => { + return e.key === 'Enter' || e.key === ' '; + }, []); + + const handleClick = useCallback( + (e: React.MouseEvent) => { + preventDefaultAndStopPropagation(e); + onOpenChange?.(!isOpen); + }, + [isOpen, onOpenChange, preventDefaultAndStopPropagation], + ); + + const handleKeyDown = useCallback( + (e: React.KeyboardEvent) => { + if (isValidKeyEvent(e)) { + preventDefaultAndStopPropagation(e); + onOpenChange?.(!isOpen); + } + }, + [isOpen, onOpenChange, preventDefaultAndStopPropagation, isValidKeyEvent], + ); + + return ( + + ); +}; diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTreeItemActions.tsx b/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTreeItemActions.tsx index 0ceaa192..1c1e3ccb 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTreeItemActions.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTreeItemActions.tsx @@ -8,9 +8,7 @@ import { useRouter } from 'next/router'; import { useTranslation } from 'react-i18next'; import { css } from 'styled-components'; -import { Box, BoxButton, Icon } from '@/components'; -import { useDocTreeItemHandlers } from '@/features/docs/doc-tree/hooks/useDocTreeItemHandlers'; -import { useDropdownFocusManagement } from '@/features/docs/doc-tree/hooks/useDropdownFocusManagement'; +import { Box, Icon } from '@/components'; import { Doc, ModalRemoveDoc, @@ -19,6 +17,9 @@ import { useCreateChildDoc, useDuplicateDoc, } from '@/docs/doc-management'; +import { ButtonAddChildDoc } from '@/features/docs/doc-tree/components/ButtonAddChildDoc'; +import { ButtonMoreOptions } from '@/features/docs/doc-tree/components/ButtonMoreOptions'; +import { useDropdownFocusManagement } from '@/features/docs/doc-tree/hooks/useDropdownFocusManagement'; import { useDetachDoc } from '../api/useDetach'; import MoveDocIcon from '../assets/doc-extract-bold.svg'; @@ -149,18 +150,6 @@ export const DocTreeItemActions = ({ } }; - const { - handleMoreOptionsClick, - handleMoreOptionsKeyDown, - handleAddChildClick, - handleAddChildKeyDown, - } = useDocTreeItemHandlers({ - isOpen, - onOpenChange, - createChildDoc, - docId: doc.id, - }); - useDropdownFocusManagement({ isOpen: isOpen || false, docId: doc.id, @@ -202,45 +191,18 @@ export const DocTreeItemActions = ({ isOpen={isOpen} onOpenChange={onOpenChange} > - {doc.abilities.children_create && ( - - + )} {deleteModal.isOpen && ( diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/hooks/useDocTreeItemHandlers.ts b/src/frontend/apps/impress/src/features/docs/doc-tree/hooks/useDocTreeItemHandlers.ts deleted file mode 100644 index b22b7026..00000000 --- a/src/frontend/apps/impress/src/features/docs/doc-tree/hooks/useDocTreeItemHandlers.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { useCallback } from 'react'; - -interface UseDocTreeItemHandlersProps { - isOpen?: boolean; - onOpenChange?: (isOpen: boolean) => void; - createChildDoc: (params: { parentId: string }) => void; - docId: string; -} - -export const useDocTreeItemHandlers = ({ - isOpen, - onOpenChange, - createChildDoc, - docId, -}: UseDocTreeItemHandlersProps) => { - const preventDefaultAndStopPropagation = useCallback( - (e: React.MouseEvent | React.KeyboardEvent) => { - e.stopPropagation(); - e.preventDefault(); - }, - [], - ); - - const isValidKeyEvent = useCallback((e: React.KeyboardEvent) => { - return e.key === 'Enter' || e.key === ' '; - }, []); - - const handleMoreOptionsClick = useCallback( - (e: React.MouseEvent) => { - preventDefaultAndStopPropagation(e); - onOpenChange?.(!isOpen); - }, - [isOpen, onOpenChange, preventDefaultAndStopPropagation], - ); - - const handleMoreOptionsKeyDown = useCallback( - (e: React.KeyboardEvent) => { - if (isValidKeyEvent(e)) { - preventDefaultAndStopPropagation(e); - onOpenChange?.(!isOpen); - } - }, - [isOpen, onOpenChange, preventDefaultAndStopPropagation, isValidKeyEvent], - ); - - const handleAddChildClick = useCallback( - (e: React.MouseEvent) => { - preventDefaultAndStopPropagation(e); - void createChildDoc({ - parentId: docId, - }); - }, - [createChildDoc, docId, preventDefaultAndStopPropagation], - ); - - const handleAddChildKeyDown = useCallback( - (e: React.KeyboardEvent) => { - if (isValidKeyEvent(e)) { - preventDefaultAndStopPropagation(e); - void createChildDoc({ - parentId: docId, - }); - } - }, - [createChildDoc, docId, preventDefaultAndStopPropagation, isValidKeyEvent], - ); - - return { - handleMoreOptionsClick, - handleMoreOptionsKeyDown, - handleAddChildClick, - handleAddChildKeyDown, - }; -};