diff --git a/apps/executeJS/src/features/tab/ui/tab-button.tsx b/apps/executeJS/src/features/tab/ui/tab-button.tsx index 725f47a..34ff793 100644 --- a/apps/executeJS/src/features/tab/ui/tab-button.tsx +++ b/apps/executeJS/src/features/tab/ui/tab-button.tsx @@ -4,7 +4,7 @@ import { useRef, useState } from 'react'; import { Tab } from '@/features/playground'; import { useClickOutside } from '@/shared'; import { TabContextMenu } from '@/pages/playground'; -import { TabTitleModal } from './tab-title-mdal'; +import { TabTitleModal } from './tab-title-modal'; import { FormProvider, useForm } from 'react-hook-form'; interface TabButtonProps { @@ -58,13 +58,16 @@ export const TabButton: React.FC = ({ onClick={() => onActiveTab(id)} onContextMenu={(event) => onContextMenu(event, id)} className={`group-hover:text-gray-50 w-40 pl-3 pr-2 truncate text-left cursor-pointer select-none ${isActive ? 'text-gray-50' : 'text-gray-500'}`} + aria-label={`Tab: ${title}`} > {title} - - - { - return ( - - ); - }} - /> - - - - - ); -}; diff --git a/apps/executeJS/src/features/tab/ui/tab-title-modal.tsx b/apps/executeJS/src/features/tab/ui/tab-title-modal.tsx new file mode 100644 index 0000000..c4d1491 --- /dev/null +++ b/apps/executeJS/src/features/tab/ui/tab-title-modal.tsx @@ -0,0 +1,88 @@ +import { Tab, usePlaygroundStore } from '@/features/playground'; +import { Cross1Icon } from '@radix-ui/react-icons'; +import { Controller, SubmitHandler, useFormContext } from 'react-hook-form'; + +interface TabTitleModalProps { + open: boolean; + onClose: () => void; +} + +export const TabTitleModal: React.FC = ({ + open, + onClose, +}) => { + const { setTabTitle } = usePlaygroundStore(); + + const { control, handleSubmit } = useFormContext>(); + + const handleChangeTabTitle: SubmitHandler> = ({ + id, + title, + }) => { + const trimmedTitle = title.trim(); + if (trimmedTitle.length === 0) { + return; + } + setTabTitle({ tabId: id, title: trimmedTitle }); + onClose(); + }; + + if (!open) return null; + + return ( +
+
+ +
+
+ + Change tab title + + +
+ +
+ { + return ( + + ); + }} + /> + + + +
+
+ ); +}; diff --git a/apps/executeJS/src/shared/hooks/use-click-outside.ts b/apps/executeJS/src/shared/hooks/use-click-outside.ts index 5053fbf..4bd1e8d 100644 --- a/apps/executeJS/src/shared/hooks/use-click-outside.ts +++ b/apps/executeJS/src/shared/hooks/use-click-outside.ts @@ -1,20 +1,23 @@ -import { useEffect, RefObject } from 'react'; +import { useEffect, useCallback, RefObject } from 'react'; export const useClickOutside = ( ref: RefObject, onClickOutside: () => void ) => { - useEffect(() => { - function handleClickOutside(event: MouseEvent) { + const handleClickOutside = useCallback( + (event: MouseEvent) => { if (ref.current && !ref.current.contains(event.target as Node)) { onClickOutside(); } - } + }, + [ref, onClickOutside] + ); + useEffect(() => { document.addEventListener('click', handleClickOutside); return () => { document.removeEventListener('click', handleClickOutside); }; - }, [ref, onClickOutside]); + }, [handleClickOutside]); };