瀏覽代碼

WIP: migrate hooks for modal

refactor
Yuki Takei 7 月之前
父節點
當前提交
57d53679c7
共有 28 個文件被更改,包括 183 次插入131 次删除
  1. 2 2
      apps/app/src/client/components/Bookmarks/BookmarkFolderTree.tsx
  2. 3 2
      apps/app/src/client/components/Hotkeys/Subscribers/ShowShortcutsModal.tsx
  3. 4 4
      apps/app/src/client/components/ItemsTree/ItemsTree.tsx
  4. 8 8
      apps/app/src/client/components/Navbar/GrowiContextualSubNavigation.tsx
  5. 2 2
      apps/app/src/client/components/Navbar/GrowiNavbarBottom.tsx
  6. 3 2
      apps/app/src/client/components/PageAccessoriesModal/PageAccessoriesModal.tsx
  7. 3 2
      apps/app/src/client/components/PageAccessoriesModal/hooks.tsx
  8. 2 2
      apps/app/src/client/components/PageControls/PageControls.tsx
  9. 3 2
      apps/app/src/client/components/PageCreateModal.tsx
  10. 3 2
      apps/app/src/client/components/PageDeleteModal.tsx
  11. 3 2
      apps/app/src/client/components/PageDuplicateModal.tsx
  12. 6 6
      apps/app/src/client/components/PageList/PageListItemL.tsx
  13. 3 2
      apps/app/src/client/components/PageRenameModal.tsx
  14. 2 2
      apps/app/src/client/components/PageSideContents/PageSideContents.tsx
  15. 3 2
      apps/app/src/client/components/PageTags/TagEditModal.tsx
  16. 2 2
      apps/app/src/client/components/SearchPage/SearchPageBase.tsx
  17. 6 6
      apps/app/src/client/components/SearchPage/SearchResultContent.tsx
  18. 3 2
      apps/app/src/client/components/ShortcutsModal.tsx
  19. 2 2
      apps/app/src/client/components/Sidebar/PageCreateButton/PageCreateButton.tsx
  20. 2 2
      apps/app/src/client/components/SystemVersion.tsx
  21. 2 2
      apps/app/src/components/PageView/PageAlerts/TrashPageAlert.tsx
  22. 38 31
      apps/app/src/states/ui/modal/page-accessories.ts
  23. 13 7
      apps/app/src/states/ui/modal/page-create.ts
  24. 13 7
      apps/app/src/states/ui/modal/page-delete.ts
  25. 13 7
      apps/app/src/states/ui/modal/page-duplicate.ts
  26. 13 7
      apps/app/src/states/ui/modal/page-rename.ts
  27. 13 7
      apps/app/src/states/ui/modal/shortcuts.ts
  28. 13 7
      apps/app/src/states/ui/modal/tag-edit.ts

+ 2 - 2
apps/app/src/client/components/Bookmarks/BookmarkFolderTree.tsx

@@ -11,7 +11,7 @@ import { toastSuccess } from '~/client/util/toastr';
 import type { OnDeletedFunction } from '~/interfaces/ui';
 import type { OnDeletedFunction } from '~/interfaces/ui';
 import { useIsReadOnlyUser } from '~/states/context';
 import { useIsReadOnlyUser } from '~/states/context';
 import { useCurrentPageData } from '~/states/page';
 import { useCurrentPageData } from '~/states/page';
-import { usePageDeleteModal } from '~/states/ui/modal/page-delete';
+import { usePageDeleteModalActions } from '~/states/ui/modal/page-delete';
 import {
 import {
   useSWRxUserBookmarks, useSWRMUTxCurrentUserBookmarks,
   useSWRxUserBookmarks, useSWRMUTxCurrentUserBookmarks,
 } from '~/stores/bookmark';
 } from '~/stores/bookmark';
@@ -48,7 +48,7 @@ export const BookmarkFolderTree: React.FC<Props> = (props: Props) => {
   const { data: userBookmarks, mutate: mutateUserBookmarks } = useSWRxUserBookmarks(userId ?? null);
   const { data: userBookmarks, mutate: mutateUserBookmarks } = useSWRxUserBookmarks(userId ?? null);
   const { trigger: mutatePageInfo } = useSWRMUTxPageInfo(currentPage?._id ?? null);
   const { trigger: mutatePageInfo } = useSWRMUTxPageInfo(currentPage?._id ?? null);
   const { trigger: mutateCurrentUserBookmarks } = useSWRMUTxCurrentUserBookmarks();
   const { trigger: mutateCurrentUserBookmarks } = useSWRMUTxCurrentUserBookmarks();
-  const { open: openDeleteModal } = usePageDeleteModal();
+  const { open: openDeleteModal } = usePageDeleteModalActions();
 
 
   const bookmarkFolderTreeMutation = useCallback(() => {
   const bookmarkFolderTreeMutation = useCallback(() => {
     mutateUserBookmarks();
     mutateUserBookmarks();

+ 3 - 2
apps/app/src/client/components/Hotkeys/Subscribers/ShowShortcutsModal.tsx

@@ -1,13 +1,14 @@
 import React, { useEffect, type JSX } from 'react';
 import React, { useEffect, type JSX } from 'react';
 
 
-import { useShortcutsModal } from '~/states/ui/modal/shortcuts';
+import { useShortcutsModal, useShortcutsModalActions } from '~/states/ui/modal/shortcuts';
 
 
 type Props = {
 type Props = {
   onDeleteRender: () => void,
   onDeleteRender: () => void,
 }
 }
 const ShowShortcutsModal = (props: Props): JSX.Element => {
 const ShowShortcutsModal = (props: Props): JSX.Element => {
 
 
-  const { data: status, open } = useShortcutsModal();
+  const status = useShortcutsModal();
+  const { open } = useShortcutsModalActions();
 
 
   const { onDeleteRender } = props;
   const { onDeleteRender } = props;
 
 

+ 4 - 4
apps/app/src/client/components/ItemsTree/ItemsTree.tsx

@@ -13,9 +13,9 @@ import type { OnDuplicatedFunction, OnDeletedFunction } from '~/interfaces/ui';
 import type { UpdateDescCountData, UpdateDescCountRawData } from '~/interfaces/websocket';
 import type { UpdateDescCountData, UpdateDescCountRawData } from '~/interfaces/websocket';
 import { SocketEventName } from '~/interfaces/websocket';
 import { SocketEventName } from '~/interfaces/websocket';
 import { useCurrentPagePath, useFetchCurrentPage } from '~/states/page';
 import { useCurrentPagePath, useFetchCurrentPage } from '~/states/page';
-import { usePageDeleteModal } from '~/states/ui/modal/page-delete';
+import { usePageDeleteModalActions } from '~/states/ui/modal/page-delete';
 import type { IPageForPageDuplicateModal } from '~/states/ui/modal/page-duplicate';
 import type { IPageForPageDuplicateModal } from '~/states/ui/modal/page-duplicate';
-import { usePageDuplicateModal } from '~/states/ui/modal/page-duplicate';
+import { usePageDuplicateModalActions } from '~/states/ui/modal/page-duplicate';
 import { mutateAllPageInfo } from '~/stores/page';
 import { mutateAllPageInfo } from '~/stores/page';
 import {
 import {
   useSWRxRootPage, mutatePageTree, mutatePageList,
   useSWRxRootPage, mutatePageTree, mutatePageList,
@@ -57,8 +57,8 @@ export const ItemsTree = (props: ItemsTreeProps): JSX.Element => {
 
 
   const { data: rootPageResult, error } = useSWRxRootPage({ suspense: true });
   const { data: rootPageResult, error } = useSWRxRootPage({ suspense: true });
   const currentPagePath = useCurrentPagePath();
   const currentPagePath = useCurrentPagePath();
-  const { open: openDuplicateModal } = usePageDuplicateModal();
-  const { open: openDeleteModal } = usePageDeleteModal();
+  const { open: openDuplicateModal } = usePageDuplicateModalActions();
+  const { open: openDeleteModal } = usePageDeleteModalActions();
 
 
   const { data: socket } = useGlobalSocket();
   const { data: socket } = useGlobalSocket();
   const { data: ptDescCountMap, update: updatePtDescCountMap } = usePageTreeDescCountMap();
   const { data: ptDescCountMap, update: updatePtDescCountMap } = usePageTreeDescCountMap();

+ 8 - 8
apps/app/src/client/components/Navbar/GrowiContextualSubNavigation.tsx

@@ -36,10 +36,10 @@ import {
   isUploadEnabledAtom,
   isUploadEnabledAtom,
 } from '~/states/server-configurations';
 } from '~/states/server-configurations';
 import { useEditorMode } from '~/states/ui/editor';
 import { useEditorMode } from '~/states/ui/editor';
-import { PageAccessoriesModalContents, usePageAccessoriesModal } from '~/states/ui/modal/page-accessories';
-import { usePageDeleteModal } from '~/states/ui/modal/page-delete';
-import { usePageDuplicateModal, type IPageForPageDuplicateModal } from '~/states/ui/modal/page-duplicate';
-import { usePageRenameModal } from '~/states/ui/modal/page-rename';
+import { PageAccessoriesModalContents, usePageAccessoriesModalActions } from '~/states/ui/modal/page-accessories';
+import { usePageDeleteModalActions } from '~/states/ui/modal/page-delete';
+import { usePageDuplicateModalActions, type IPageForPageDuplicateModal } from '~/states/ui/modal/page-duplicate';
+import { usePageRenameModalActions } from '~/states/ui/modal/page-rename';
 import { usePagePresentationModal } from '~/stores/modal';
 import { usePagePresentationModal } from '~/stores/modal';
 import {
 import {
   useSWRxPageInfo,
   useSWRxPageInfo,
@@ -90,7 +90,7 @@ const PageOperationMenuItems = (props: PageOperationMenuItemsProps): JSX.Element
   const isUploadEnabled = useAtomValue(isUploadEnabledAtom);
   const isUploadEnabled = useAtomValue(isUploadEnabledAtom);
 
 
   const { open: openPresentationModal } = usePagePresentationModal();
   const { open: openPresentationModal } = usePagePresentationModal();
-  const { open: openAccessoriesModal } = usePageAccessoriesModal();
+  const { open: openAccessoriesModal } = usePageAccessoriesModalActions();
   const { open: openPageBulkExportSelectModal } = usePageBulkExportSelectModal();
   const { open: openPageBulkExportSelectModal } = usePageBulkExportSelectModal();
 
 
   const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.MAIN);
   const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.MAIN);
@@ -283,9 +283,9 @@ const GrowiContextualSubNavigation = (props: GrowiContextualSubNavigationProps):
   const { data: isAbleToChangeEditorMode } = useIsAbleToChangeEditorMode();
   const { data: isAbleToChangeEditorMode } = useIsAbleToChangeEditorMode();
   const { data: isDeviceLargerThanMd } = useIsDeviceLargerThanMd();
   const { data: isDeviceLargerThanMd } = useIsDeviceLargerThanMd();
 
 
-  const { open: openDuplicateModal } = usePageDuplicateModal();
-  const { open: openRenameModal } = usePageRenameModal();
-  const { open: openDeleteModal } = usePageDeleteModal();
+  const { open: openDuplicateModal } = usePageDuplicateModalActions();
+  const { open: openRenameModal } = usePageRenameModalActions();
+  const { open: openDeleteModal } = usePageDeleteModalActions();
   const { mutate: mutatePageInfo } = useSWRxPageInfo(pageId);
   const { mutate: mutatePageInfo } = useSWRxPageInfo(pageId);
 
 
   const [isStickyActive, setStickyActive] = useState(false);
   const [isStickyActive, setStickyActive] = useState(false);

+ 2 - 2
apps/app/src/client/components/Navbar/GrowiNavbarBottom.tsx

@@ -4,7 +4,7 @@ import { GroundGlassBar } from '~/components/Navbar/GroundGlassBar';
 import { useSearchModal } from '~/features/search/client/stores/search';
 import { useSearchModal } from '~/features/search/client/stores/search';
 import { useIsSearchPage } from '~/states/context';
 import { useIsSearchPage } from '~/states/context';
 import { useCurrentPagePath } from '~/states/page';
 import { useCurrentPagePath } from '~/states/page';
-import { usePageCreateModal } from '~/states/ui/modal/page-create';
+import { usePageCreateModalActions } from '~/states/ui/modal/page-create';
 import { useDrawerOpened } from '~/states/ui/sidebar';
 import { useDrawerOpened } from '~/states/ui/sidebar';
 
 
 import styles from './GrowiNavbarBottom.module.scss';
 import styles from './GrowiNavbarBottom.module.scss';
@@ -13,7 +13,7 @@ import styles from './GrowiNavbarBottom.module.scss';
 export const GrowiNavbarBottom = (): JSX.Element => {
 export const GrowiNavbarBottom = (): JSX.Element => {
 
 
   const [isDrawerOpened, setIsDrawerOpened] = useDrawerOpened();
   const [isDrawerOpened, setIsDrawerOpened] = useDrawerOpened();
-  const { open: openCreateModal } = usePageCreateModal();
+  const { open: openCreateModal } = usePageCreateModalActions();
   const currentPagePath = useCurrentPagePath();
   const currentPagePath = useCurrentPagePath();
   const isSearchPage = useIsSearchPage();
   const isSearchPage = useIsSearchPage();
   const { open: openSearchModal } = useSearchModal();
   const { open: openSearchModal } = useSearchModal();

+ 3 - 2
apps/app/src/client/components/PageAccessoriesModal/PageAccessoriesModal.tsx

@@ -9,7 +9,7 @@ import {
 
 
 import { useIsGuestUser, useIsReadOnlyUser, useIsSharedUser } from '~/states/context';
 import { useIsGuestUser, useIsReadOnlyUser, useIsSharedUser } from '~/states/context';
 import { disableLinkSharingAtom } from '~/states/server-configurations';
 import { disableLinkSharingAtom } from '~/states/server-configurations';
-import { usePageAccessoriesModal, PageAccessoriesModalContents } from '~/states/ui/modal/page-accessories';
+import { usePageAccessoriesModal, usePageAccessoriesModalActions, PageAccessoriesModalContents } from '~/states/ui/modal/page-accessories';
 import { useIsDeviceLargerThanLg } from '~/stores/ui';
 import { useIsDeviceLargerThanLg } from '~/stores/ui';
 
 
 import { CustomNavDropdown, CustomNavTab } from '../CustomNavigation/CustomNav';
 import { CustomNavDropdown, CustomNavTab } from '../CustomNavigation/CustomNav';
@@ -38,7 +38,8 @@ export const PageAccessoriesModal = (): JSX.Element => {
   const isLinkSharingDisabled = useAtomValue(disableLinkSharingAtom);
   const isLinkSharingDisabled = useAtomValue(disableLinkSharingAtom);
   const { data: isDeviceLargerThanLg } = useIsDeviceLargerThanLg();
   const { data: isDeviceLargerThanLg } = useIsDeviceLargerThanLg();
 
 
-  const { data: status, close, selectContents } = usePageAccessoriesModal();
+  const status = usePageAccessoriesModal();
+  const { close, selectContents } = usePageAccessoriesModalActions();
 
 
   useAutoOpenModalByQueryParam();
   useAutoOpenModalByQueryParam();
 
 

+ 3 - 2
apps/app/src/client/components/PageAccessoriesModal/hooks.tsx

@@ -1,6 +1,6 @@
 import { useEffect, useState } from 'react';
 import { useEffect, useState } from 'react';
 
 
-import { usePageAccessoriesModal, PageAccessoriesModalContents } from '~/states/ui/modal/page-accessories';
+import { usePageAccessoriesModal, usePageAccessoriesModalActions, PageAccessoriesModalContents } from '~/states/ui/modal/page-accessories';
 
 
 function getURLQueryParamValue(key: string) {
 function getURLQueryParamValue(key: string) {
 // window.location.href is page URL;
 // window.location.href is page URL;
@@ -15,7 +15,8 @@ const queryCompareFormat = /^([0-9a-f]{24})...([0-9a-f]{24})$/i;
 export const useAutoOpenModalByQueryParam = (): void => {
 export const useAutoOpenModalByQueryParam = (): void => {
   const [isArleadyMounted, setIsArleadyMounted] = useState(false);
   const [isArleadyMounted, setIsArleadyMounted] = useState(false);
 
 
-  const { data: status, open: openPageAccessories } = usePageAccessoriesModal();
+  const status = usePageAccessoriesModal();
+  const { open: openPageAccessories } = usePageAccessoriesModalActions();
 
 
   useEffect(() => {
   useEffect(() => {
     if (isArleadyMounted) {
     if (isArleadyMounted) {

+ 2 - 2
apps/app/src/client/components/PageControls/PageControls.tsx

@@ -26,7 +26,7 @@ import {
   EditorMode, useEditorMode,
   EditorMode, useEditorMode,
 } from '~/states/ui/editor';
 } from '~/states/ui/editor';
 import { type IPageForPageDuplicateModal } from '~/states/ui/modal/page-duplicate';
 import { type IPageForPageDuplicateModal } from '~/states/ui/modal/page-duplicate';
-import { useTagEditModal } from '~/states/ui/modal/tag-edit';
+import { useTagEditModalActions } from '~/states/ui/modal/tag-edit';
 import { useSetPageControlsX } from '~/states/ui/page';
 import { useSetPageControlsX } from '~/states/ui/page';
 import { useIsDeviceLargerThanMd } from '~/stores/ui';
 import { useIsDeviceLargerThanMd } from '~/stores/ui';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
@@ -380,7 +380,7 @@ export const PageControls = memo((props: PageControlsProps): JSX.Element => {
 
 
   const { data: pageInfo, error } = useSWRxPageInfo(pageId ?? null, shareLinkId);
   const { data: pageInfo, error } = useSWRxPageInfo(pageId ?? null, shareLinkId);
   const { data: tagsInfoData } = useSWRxTagsInfo(pageId);
   const { data: tagsInfoData } = useSWRxTagsInfo(pageId);
-  const { open: openTagEditModal } = useTagEditModal();
+  const { open: openTagEditModal } = useTagEditModalActions();
 
 
   const onClickEditTagsButton = useCallback(() => {
   const onClickEditTagsButton = useCallback(() => {
     if (tagsInfoData == null || revisionId == null) {
     if (tagsInfoData == null || revisionId == null) {

+ 3 - 2
apps/app/src/client/components/PageCreateModal.tsx

@@ -21,7 +21,7 @@ import { useCreatePage } from '~/client/services/create-page/use-create-page';
 import { useToastrOnError } from '~/client/services/use-toastr-on-error';
 import { useToastrOnError } from '~/client/services/use-toastr-on-error';
 import { useCurrentUser } from '~/states/global';
 import { useCurrentUser } from '~/states/global';
 import { isSearchServiceReachableAtom } from '~/states/server-configurations';
 import { isSearchServiceReachableAtom } from '~/states/server-configurations';
-import { usePageCreateModal } from '~/states/ui/modal/page-create';
+import { usePageCreateModal, usePageCreateModalActions } from '~/states/ui/modal/page-create';
 
 
 import PagePathAutoComplete from './PagePathAutoComplete';
 import PagePathAutoComplete from './PagePathAutoComplete';
 
 
@@ -36,7 +36,8 @@ const PageCreateModal: React.FC = () => {
 
 
   const currentUser = useCurrentUser();
   const currentUser = useCurrentUser();
 
 
-  const { data: pageCreateModalData, close: closeCreateModal } = usePageCreateModal();
+  const pageCreateModalData = usePageCreateModal();
+  const { close: closeCreateModal } = usePageCreateModalActions();
 
 
   const isOpened = pageCreateModalData?.isOpened ?? false;
   const isOpened = pageCreateModalData?.isOpened ?? false;
 
 

+ 3 - 2
apps/app/src/client/components/PageDeleteModal.tsx

@@ -16,7 +16,7 @@ import {
 import { apiPost } from '~/client/util/apiv1-client';
 import { apiPost } from '~/client/util/apiv1-client';
 import { apiv3Post } from '~/client/util/apiv3-client';
 import { apiv3Post } from '~/client/util/apiv3-client';
 import type { IDeleteSinglePageApiv1Result, IDeleteManyPageApiv3Result } from '~/interfaces/page';
 import type { IDeleteSinglePageApiv1Result, IDeleteManyPageApiv3Result } from '~/interfaces/page';
-import { usePageDeleteModal } from '~/states/ui/modal/page-delete';
+import { usePageDeleteModal, usePageDeleteModalActions } from '~/states/ui/modal/page-delete';
 import { useSWRxPageInfoForList } from '~/stores/page-listing';
 import { useSWRxPageInfoForList } from '~/stores/page-listing';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 
@@ -50,7 +50,8 @@ const isIPageInfoForEntityForDeleteModal = (pageInfo: any | undefined): pageInfo
 const PageDeleteModal: FC = () => {
 const PageDeleteModal: FC = () => {
   const { t } = useTranslation();
   const { t } = useTranslation();
 
 
-  const { data: deleteModalData, close: closeDeleteModal } = usePageDeleteModal();
+  const deleteModalData = usePageDeleteModal();
+  const { close: closeDeleteModal } = usePageDeleteModalActions();
 
 
   const isOpened = deleteModalData?.isOpened ?? false;
   const isOpened = deleteModalData?.isOpened ?? false;
 
 

+ 3 - 2
apps/app/src/client/components/PageDuplicateModal.tsx

@@ -13,7 +13,7 @@ import { apiv3Get, apiv3Post } from '~/client/util/apiv3-client';
 import { toastError } from '~/client/util/toastr';
 import { toastError } from '~/client/util/toastr';
 import { useSiteUrl } from '~/states/global';
 import { useSiteUrl } from '~/states/global';
 import { isSearchServiceReachableAtom } from '~/states/server-configurations';
 import { isSearchServiceReachableAtom } from '~/states/server-configurations';
-import { usePageDuplicateModal } from '~/states/ui/modal/page-duplicate';
+import { usePageDuplicateModal, usePageDuplicateModalActions } from '~/states/ui/modal/page-duplicate';
 
 
 import DuplicatePathsTable from './DuplicatedPathsTable';
 import DuplicatePathsTable from './DuplicatedPathsTable';
 import ApiErrorMessageList from './PageManagement/ApiErrorMessageList';
 import ApiErrorMessageList from './PageManagement/ApiErrorMessageList';
@@ -26,7 +26,8 @@ const PageDuplicateModal = (): JSX.Element => {
   const siteUrl = useSiteUrl();
   const siteUrl = useSiteUrl();
   const isReachable = useAtomValue(isSearchServiceReachableAtom);
   const isReachable = useAtomValue(isSearchServiceReachableAtom);
 
 
-  const { data: duplicateModalData, close: closeDuplicateModal } = usePageDuplicateModal();
+  const duplicateModalData = usePageDuplicateModal();
+  const { close: closeDuplicateModal } = usePageDuplicateModalActions();
 
 
   const isOpened = duplicateModalData?.isOpened ?? false;
   const isOpened = duplicateModalData?.isOpened ?? false;
   const page = duplicateModalData?.page;
   const page = duplicateModalData?.page;

+ 6 - 6
apps/app/src/client/components/PageList/PageListItemL.tsx

@@ -25,9 +25,9 @@ import type {
   OnDuplicatedFunction, OnRenamedFunction, OnDeletedFunction, OnPutBackedFunction,
   OnDuplicatedFunction, OnRenamedFunction, OnDeletedFunction, OnPutBackedFunction,
 } from '~/interfaces/ui';
 } from '~/interfaces/ui';
 import LinkedPagePath from '~/models/linked-page-path';
 import LinkedPagePath from '~/models/linked-page-path';
-import { usePageDeleteModal } from '~/states/ui/modal/page-delete';
-import { usePageDuplicateModal } from '~/states/ui/modal/page-duplicate';
-import { usePageRenameModal } from '~/states/ui/modal/page-rename';
+import { usePageDeleteModalActions } from '~/states/ui/modal/page-delete';
+import { usePageDuplicateModalActions } from '~/states/ui/modal/page-duplicate';
+import { usePageRenameModalActions } from '~/states/ui/modal/page-rename';
 import { useSWRMUTxCurrentUserBookmarks } from '~/stores/bookmark';
 import { useSWRMUTxCurrentUserBookmarks } from '~/stores/bookmark';
 import { usePutBackPageModal } from '~/stores/modal';
 import { usePutBackPageModal } from '~/stores/modal';
 import { useIsDeviceLargerThanLg } from '~/stores/ui';
 import { useIsDeviceLargerThanLg } from '~/stores/ui';
@@ -86,9 +86,9 @@ const PageListItemLSubstance: ForwardRefRenderFunction<ISelectable, Props> = (pr
   }));
   }));
 
 
   const { data: isDeviceLargerThanLg } = useIsDeviceLargerThanLg();
   const { data: isDeviceLargerThanLg } = useIsDeviceLargerThanLg();
-  const { open: openDuplicateModal } = usePageDuplicateModal();
-  const { open: openRenameModal } = usePageRenameModal();
-  const { open: openDeleteModal } = usePageDeleteModal();
+  const { open: openDuplicateModal } = usePageDuplicateModalActions();
+  const { open: openRenameModal } = usePageRenameModalActions();
+  const { open: openDeleteModal } = usePageDeleteModalActions();
   const { open: openPutBackPageModal } = usePutBackPageModal();
   const { open: openPutBackPageModal } = usePutBackPageModal();
 
 
   const shouldFetch = isSelected && (pageData != null || pageMeta != null);
   const shouldFetch = isSelected && (pageData != null || pageMeta != null);

+ 3 - 2
apps/app/src/client/components/PageRenameModal.tsx

@@ -15,7 +15,7 @@ import { apiv3Get, apiv3Put } from '~/client/util/apiv3-client';
 import { toastError } from '~/client/util/toastr';
 import { toastError } from '~/client/util/toastr';
 import { useSiteUrl } from '~/states/global';
 import { useSiteUrl } from '~/states/global';
 import { isSearchServiceReachableAtom } from '~/states/server-configurations';
 import { isSearchServiceReachableAtom } from '~/states/server-configurations';
-import { usePageRenameModal } from '~/states/ui/modal/page-rename';
+import { usePageRenameModal, usePageRenameModalActions } from '~/states/ui/modal/page-rename';
 import { useSWRxPageInfo } from '~/stores/page';
 import { useSWRxPageInfo } from '~/stores/page';
 
 
 import DuplicatedPathsTable from './DuplicatedPathsTable';
 import DuplicatedPathsTable from './DuplicatedPathsTable';
@@ -32,7 +32,8 @@ const PageRenameModal = (): JSX.Element => {
 
 
   const { isUsersHomepage } = pagePathUtils;
   const { isUsersHomepage } = pagePathUtils;
   const siteUrl = useSiteUrl();
   const siteUrl = useSiteUrl();
-  const { data: renameModalData, close: closeRenameModal } = usePageRenameModal();
+  const renameModalData = usePageRenameModal();
+  const { close: closeRenameModal } = usePageRenameModalActions();
   const isReachable = useAtomValue(isSearchServiceReachableAtom);
   const isReachable = useAtomValue(isSearchServiceReachableAtom);
 
 
   const isOpened = renameModalData?.isOpened ?? false;
   const isOpened = renameModalData?.isOpened ?? false;

+ 2 - 2
apps/app/src/client/components/PageSideContents/PageSideContents.tsx

@@ -14,7 +14,7 @@ import { scroller } from 'react-scroll';
 
 
 import { useIsGuestUser, useIsReadOnlyUser } from '~/states/context';
 import { useIsGuestUser, useIsReadOnlyUser } from '~/states/context';
 import { showPageSideAuthorsAtom } from '~/states/server-configurations';
 import { showPageSideAuthorsAtom } from '~/states/server-configurations';
-import { useTagEditModal } from '~/states/ui/modal/tag-edit';
+import { useTagEditModalActions } from '~/states/ui/modal/tag-edit';
 import { useDescendantsPageListModal } from '~/stores/modal';
 import { useDescendantsPageListModal } from '~/stores/modal';
 import { useSWRxPageInfo, useSWRxTagsInfo } from '~/stores/page';
 import { useSWRxPageInfo, useSWRxTagsInfo } from '~/stores/page';
 import { useIsAbleToShowTagLabel } from '~/stores/ui';
 import { useIsAbleToShowTagLabel } from '~/stores/ui';
@@ -51,7 +51,7 @@ const Tags = (props: TagsProps): JSX.Element => {
   const { data: showTagLabel } = useIsAbleToShowTagLabel();
   const { data: showTagLabel } = useIsAbleToShowTagLabel();
   const isGuestUser = useIsGuestUser();
   const isGuestUser = useIsGuestUser();
   const isReadOnlyUser = useIsReadOnlyUser();
   const isReadOnlyUser = useIsReadOnlyUser();
-  const { open: openTagEditModal } = useTagEditModal();
+  const { open: openTagEditModal } = useTagEditModalActions();
 
 
   const onClickEditTagsButton = useCallback(() => {
   const onClickEditTagsButton = useCallback(() => {
     if (tagsInfoData == null) {
     if (tagsInfoData == null) {

+ 3 - 2
apps/app/src/client/components/PageTags/TagEditModal.tsx

@@ -10,7 +10,7 @@ import {
 import { useUpdateStateAfterSave } from '~/client/services/page-operation';
 import { useUpdateStateAfterSave } from '~/client/services/page-operation';
 import { apiPost } from '~/client/util/apiv1-client';
 import { apiPost } from '~/client/util/apiv1-client';
 import { toastError, toastSuccess } from '~/client/util/toastr';
 import { toastError, toastSuccess } from '~/client/util/toastr';
-import { useTagEditModal, type TagEditModalStatus } from '~/states/ui/modal/tag-edit';
+import { useTagEditModal, useTagEditModalActions, type TagEditModalStatus } from '~/states/ui/modal/tag-edit';
 
 
 import { TagsInput } from './TagsInput';
 import { TagsInput } from './TagsInput';
 
 
@@ -69,7 +69,8 @@ const TagEditModalSubstance: React.FC<TagEditModalSubstanceProps> = (props: TagE
 };
 };
 
 
 export const TagEditModal: React.FC = () => {
 export const TagEditModal: React.FC = () => {
-  const { data: tagEditModalData, close: closeTagEditModal } = useTagEditModal();
+  const tagEditModalData = useTagEditModal();
+  const { close: closeTagEditModal } = useTagEditModalActions();
 
 
   if (!tagEditModalData?.isOpen) {
   if (!tagEditModalData?.isOpen) {
     return <></>;
     return <></>;

+ 2 - 2
apps/app/src/client/components/SearchPage/SearchPageBase.tsx

@@ -14,7 +14,7 @@ import type { IFormattedSearchResult, IPageWithSearchMeta } from '~/interfaces/s
 import type { OnDeletedFunction } from '~/interfaces/ui';
 import type { OnDeletedFunction } from '~/interfaces/ui';
 import { useIsGuestUser, useIsReadOnlyUser } from '~/states/context';
 import { useIsGuestUser, useIsReadOnlyUser } from '~/states/context';
 import { isSearchServiceConfiguredAtom, isSearchServiceReachableAtom } from '~/states/server-configurations';
 import { isSearchServiceConfiguredAtom, isSearchServiceReachableAtom } from '~/states/server-configurations';
-import { usePageDeleteModal } from '~/states/ui/modal/page-delete';
+import { usePageDeleteModalActions } from '~/states/ui/modal/page-delete';
 import { mutatePageTree, mutateRecentlyUpdated } from '~/stores/page-listing';
 import { mutatePageTree, mutateRecentlyUpdated } from '~/stores/page-listing';
 
 
 import type { ForceHideMenuItems } from '../Common/Dropdown/PageItemControl';
 import type { ForceHideMenuItems } from '../Common/Dropdown/PageItemControl';
@@ -243,7 +243,7 @@ export const usePageDeleteModalForBulkDeletion = (
 
 
   const { t } = useTranslation();
   const { t } = useTranslation();
 
 
-  const { open: openDeleteModal } = usePageDeleteModal();
+  const { open: openDeleteModal } = usePageDeleteModalActions();
 
 
   return () => {
   return () => {
     if (data == null) {
     if (data == null) {

+ 6 - 6
apps/app/src/client/components/SearchPage/SearchResultContent.tsx

@@ -18,9 +18,9 @@ import type { IPageWithSearchMeta } from '~/interfaces/search';
 import type { OnDuplicatedFunction, OnRenamedFunction, OnDeletedFunction } from '~/interfaces/ui';
 import type { OnDuplicatedFunction, OnRenamedFunction, OnDeletedFunction } from '~/interfaces/ui';
 import { useShouldExpandContent } from '~/services/layout/use-should-expand-content';
 import { useShouldExpandContent } from '~/services/layout/use-should-expand-content';
 import { useCurrentUser } from '~/states/global';
 import { useCurrentUser } from '~/states/global';
-import { usePageDeleteModal } from '~/states/ui/modal/page-delete';
-import { usePageDuplicateModal } from '~/states/ui/modal/page-duplicate';
-import { usePageRenameModal } from '~/states/ui/modal/page-rename';
+import { usePageDeleteModalActions } from '~/states/ui/modal/page-delete';
+import { usePageDuplicateModalActions } from '~/states/ui/modal/page-duplicate';
+import { usePageRenameModalActions } from '~/states/ui/modal/page-rename';
 import { mutatePageList, mutatePageTree, mutateRecentlyUpdated } from '~/stores/page-listing';
 import { mutatePageList, mutatePageTree, mutateRecentlyUpdated } from '~/stores/page-listing';
 import { useSearchResultOptions } from '~/stores/renderer';
 import { useSearchResultOptions } from '~/stores/renderer';
 import { mutateSearching } from '~/stores/search';
 import { mutateSearching } from '~/stores/search';
@@ -121,9 +121,9 @@ export const SearchResultContent: FC<Props> = (props: Props) => {
   const { t } = useTranslation();
   const { t } = useTranslation();
 
 
   const page = pageWithMeta.data;
   const page = pageWithMeta.data;
-  const { open: openDuplicateModal } = usePageDuplicateModal();
-  const { open: openRenameModal } = usePageRenameModal();
-  const { open: openDeleteModal } = usePageDeleteModal();
+  const { open: openDuplicateModal } = usePageDuplicateModalActions();
+  const { open: openRenameModal } = usePageRenameModalActions();
+  const { open: openDeleteModal } = usePageDeleteModalActions();
   const { data: rendererOptions } = useSearchResultOptions(pageWithMeta.data.path, highlightKeywords);
   const { data: rendererOptions } = useSearchResultOptions(pageWithMeta.data.path, highlightKeywords);
   const currentUser = useCurrentUser();
   const currentUser = useCurrentUser();
 
 

+ 3 - 2
apps/app/src/client/components/ShortcutsModal.tsx

@@ -3,7 +3,7 @@ import React, { type JSX } from 'react';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import { Modal, ModalHeader, ModalBody } from 'reactstrap';
 import { Modal, ModalHeader, ModalBody } from 'reactstrap';
 
 
-import { useShortcutsModal } from '~/states/ui/modal/shortcuts';
+import { useShortcutsModal, useShortcutsModalActions } from '~/states/ui/modal/shortcuts';
 
 
 import styles from './ShortcutsModal.module.scss';
 import styles from './ShortcutsModal.module.scss';
 
 
@@ -11,7 +11,8 @@ import styles from './ShortcutsModal.module.scss';
 const ShortcutsModal = (): JSX.Element => {
 const ShortcutsModal = (): JSX.Element => {
   const { t } = useTranslation();
   const { t } = useTranslation();
 
 
-  const { data: status, close } = useShortcutsModal();
+  const status = useShortcutsModal();
+  const { close } = useShortcutsModalActions();
 
 
   const bodyContent = () => {
   const bodyContent = () => {
     if (status == null || !status.isOpened) {
     if (status == null || !status.isOpened) {

+ 2 - 2
apps/app/src/client/components/Sidebar/PageCreateButton/PageCreateButton.tsx

@@ -5,7 +5,7 @@ import { Dropdown } from 'reactstrap';
 import { useCreateTemplatePage } from '~/client/services/create-page';
 import { useCreateTemplatePage } from '~/client/services/create-page';
 import { useToastrOnError } from '~/client/services/use-toastr-on-error';
 import { useToastrOnError } from '~/client/services/use-toastr-on-error';
 import { useCurrentPagePath } from '~/states/page';
 import { useCurrentPagePath } from '~/states/page';
-import { usePageCreateModal } from '~/states/ui/modal/page-create';
+import { usePageCreateModalActions } from '~/states/ui/modal/page-create';
 
 
 import { CreateButton } from './CreateButton';
 import { CreateButton } from './CreateButton';
 import { DropendMenu } from './DropendMenu';
 import { DropendMenu } from './DropendMenu';
@@ -18,7 +18,7 @@ export const PageCreateButton = React.memo((): JSX.Element => {
 
 
   const [dropdownOpen, setDropdownOpen] = useState(false);
   const [dropdownOpen, setDropdownOpen] = useState(false);
 
 
-  const { open: openPageCreateModal } = usePageCreateModal();
+  const { open: openPageCreateModal } = usePageCreateModalActions();
   const currentPagePath = useCurrentPagePath();
   const currentPagePath = useCurrentPagePath();
 
 
   const { createNewPage, isCreating: isNewPageCreating } = useCreateNewPage();
   const { createNewPage, isCreating: isNewPageCreating } = useCreateNewPage();

+ 2 - 2
apps/app/src/client/components/SystemVersion.tsx

@@ -1,7 +1,7 @@
 import React, { type JSX } from 'react';
 import React, { type JSX } from 'react';
 
 
 import { useGrowiVersion } from '~/states/global';
 import { useGrowiVersion } from '~/states/global';
-import { useShortcutsModal } from '~/states/ui/modal/shortcuts';
+import { useShortcutsModalActions } from '~/states/ui/modal/shortcuts';
 
 
 import styles from './SystemVersion.module.scss';
 import styles from './SystemVersion.module.scss';
 
 
@@ -13,7 +13,7 @@ type Props = {
 const SystemVersion = (props: Props): JSX.Element => {
 const SystemVersion = (props: Props): JSX.Element => {
   const { showShortcutsButton } = props;
   const { showShortcutsButton } = props;
 
 
-  const { open: openShortcutsModal } = useShortcutsModal();
+  const { open: openShortcutsModal } = useShortcutsModalActions();
 
 
   const growiVersion = useGrowiVersion();
   const growiVersion = useGrowiVersion();
   // add classes to cmd-key by OS
   // add classes to cmd-key by OS

+ 2 - 2
apps/app/src/components/PageView/PageAlerts/TrashPageAlert.tsx

@@ -8,7 +8,7 @@ import { useTranslation } from 'react-i18next';
 import {
 import {
   useCurrentPageData, useCurrentPagePath, useIsTrashPage, useFetchCurrentPage,
   useCurrentPageData, useCurrentPagePath, useIsTrashPage, useFetchCurrentPage,
 } from '~/states/page';
 } from '~/states/page';
-import { usePageDeleteModal } from '~/states/ui/modal/page-delete';
+import { usePageDeleteModalActions } from '~/states/ui/modal/page-delete';
 import { usePutBackPageModal } from '~/stores/modal';
 import { usePutBackPageModal } from '~/stores/modal';
 import { useSWRxPageInfo } from '~/stores/page';
 import { useSWRxPageInfo } from '~/stores/page';
 import { mutateRecentlyUpdated } from '~/stores/page-listing';
 import { mutateRecentlyUpdated } from '~/stores/page-listing';
@@ -34,7 +34,7 @@ export const TrashPageAlert = (): JSX.Element => {
   const pagePath = pageData?.path;
   const pagePath = pageData?.path;
   const { data: pageInfo } = useSWRxPageInfo(pageId ?? null);
   const { data: pageInfo } = useSWRxPageInfo(pageId ?? null);
 
 
-  const { open: openDeleteModal } = usePageDeleteModal();
+  const { open: openDeleteModal } = usePageDeleteModalActions();
   const { open: openPutBackPageModal } = usePutBackPageModal();
   const { open: openPutBackPageModal } = usePutBackPageModal();
   const currentPagePath = useCurrentPagePath();
   const currentPagePath = useCurrentPagePath();
 
 

+ 38 - 31
apps/app/src/states/ui/modal/page-accessories.ts

@@ -1,4 +1,4 @@
-import { atom, useAtom } from 'jotai';
+import { atom, useAtomValue, useSetAtom } from 'jotai';
 import { useCallback } from 'react';
 import { useCallback } from 'react';
 
 
 // Constants to match the original implementation
 // Constants to match the original implementation
@@ -16,7 +16,7 @@ export type PageAccessoriesModalStatus = {
   activatedContents?: PageAccessoriesModalContents;
   activatedContents?: PageAccessoriesModalContents;
 };
 };
 
 
-export type PageAccessoriesModalUtils = {
+export type PageAccessoriesModalActions = {
   open: (activatedContents: PageAccessoriesModalContents) => void;
   open: (activatedContents: PageAccessoriesModalContents) => void;
   close: () => void;
   close: () => void;
   selectContents: (activatedContents: PageAccessoriesModalContents) => void;
   selectContents: (activatedContents: PageAccessoriesModalContents) => void;
@@ -29,34 +29,41 @@ const pageAccessoriesModalAtom = atom<PageAccessoriesModalStatus>({
 
 
 /**
 /**
  * Hook for managing page accessories modal state
  * Hook for managing page accessories modal state
+ * Returns read-only modal status for optimal performance
  */
  */
-export const usePageAccessoriesModal = (): {
-  data: PageAccessoriesModalStatus;
-} & PageAccessoriesModalUtils => {
-  const [status, setStatus] = useAtom(pageAccessoriesModalAtom);
-
-  const open = useCallback(
-    (activatedContents: PageAccessoriesModalContents) => {
-      setStatus({ isOpened: true, activatedContents });
-    },
-    [setStatus],
-  );
-
-  const close = useCallback(() => {
-    setStatus({ isOpened: false });
-  }, [setStatus]);
-
-  const selectContents = useCallback(
-    (activatedContents: PageAccessoriesModalContents) => {
-      setStatus((current) => ({ ...current, activatedContents }));
-    },
-    [setStatus],
-  );
-
-  return {
-    data: status,
-    open,
-    close,
-    selectContents,
-  };
+export const usePageAccessoriesModal = (): PageAccessoriesModalStatus => {
+  return useAtomValue(pageAccessoriesModalAtom);
 };
 };
+
+/**
+ * Hook for managing page accessories modal actions
+ * Returns actions for opening, closing, and selecting contents
+ */
+export const usePageAccessoriesModalActions =
+  (): PageAccessoriesModalActions => {
+    const setStatus = useSetAtom(pageAccessoriesModalAtom);
+
+    const open = useCallback(
+      (activatedContents: PageAccessoriesModalContents) => {
+        setStatus({ isOpened: true, activatedContents });
+      },
+      [setStatus],
+    );
+
+    const close = useCallback(() => {
+      setStatus({ isOpened: false });
+    }, [setStatus]);
+
+    const selectContents = useCallback(
+      (activatedContents: PageAccessoriesModalContents) => {
+        setStatus((current) => ({ ...current, activatedContents }));
+      },
+      [setStatus],
+    );
+
+    return {
+      open,
+      close,
+      selectContents,
+    };
+  };

+ 13 - 7
apps/app/src/states/ui/modal/page-create.ts

@@ -1,4 +1,4 @@
-import { atom, useAtom } from 'jotai';
+import { atom, useAtomValue, useSetAtom } from 'jotai';
 import { useCallback } from 'react';
 import { useCallback } from 'react';
 
 
 // Type definitions
 // Type definitions
@@ -7,7 +7,7 @@ export type CreateModalStatus = {
   path?: string;
   path?: string;
 };
 };
 
 
-export type CreateModalUtils = {
+export type CreateModalActions = {
   open: (path?: string) => void;
   open: (path?: string) => void;
   close: () => void;
   close: () => void;
 };
 };
@@ -17,12 +17,19 @@ const pageCreateModalAtom = atom<CreateModalStatus>({ isOpened: false });
 
 
 /**
 /**
  * Hook for managing page create modal state
  * Hook for managing page create modal state
+ * Returns read-only modal status for optimal performance
  * Used for creating new pages with optional path specification
  * Used for creating new pages with optional path specification
  */
  */
-export const usePageCreateModal = (): {
-  data: CreateModalStatus;
-} & CreateModalUtils => {
-  const [status, setStatus] = useAtom(pageCreateModalAtom);
+export const usePageCreateModal = (): CreateModalStatus => {
+  return useAtomValue(pageCreateModalAtom);
+};
+
+/**
+ * Hook for managing page create modal actions
+ * Returns actions for opening and closing the modal
+ */
+export const usePageCreateModalActions = (): CreateModalActions => {
+  const setStatus = useSetAtom(pageCreateModalAtom);
 
 
   const open = useCallback(
   const open = useCallback(
     (path?: string) => {
     (path?: string) => {
@@ -36,7 +43,6 @@ export const usePageCreateModal = (): {
   }, [setStatus]);
   }, [setStatus]);
 
 
   return {
   return {
-    data: status,
     open,
     open,
     close,
     close,
   };
   };

+ 13 - 7
apps/app/src/states/ui/modal/page-delete.ts

@@ -1,5 +1,5 @@
 import type { IPageToDeleteWithMeta } from '@growi/core';
 import type { IPageToDeleteWithMeta } from '@growi/core';
-import { atom, useAtom } from 'jotai';
+import { atom, useAtomValue, useSetAtom } from 'jotai';
 import { useCallback } from 'react';
 import { useCallback } from 'react';
 
 
 import type { OnDeletedFunction } from '../../../interfaces/ui';
 import type { OnDeletedFunction } from '../../../interfaces/ui';
@@ -15,7 +15,7 @@ export type DeleteModalStatus = {
   opts?: IDeleteModalOption;
   opts?: IDeleteModalOption;
 };
 };
 
 
-export type DeleteModalUtils = {
+export type DeleteModalActions = {
   open: (pages?: IPageToDeleteWithMeta[], opts?: IDeleteModalOption) => void;
   open: (pages?: IPageToDeleteWithMeta[], opts?: IDeleteModalOption) => void;
   close: () => void;
   close: () => void;
 };
 };
@@ -28,12 +28,19 @@ const pageDeleteModalAtom = atom<DeleteModalStatus>({
 
 
 /**
 /**
  * Hook for managing page delete modal state
  * Hook for managing page delete modal state
+ * Returns read-only modal status for optimal performance
  * Used for deleting single or multiple pages
  * Used for deleting single or multiple pages
  */
  */
-export const usePageDeleteModal = (): {
-  data: DeleteModalStatus;
-} & DeleteModalUtils => {
-  const [status, setStatus] = useAtom(pageDeleteModalAtom);
+export const usePageDeleteModal = (): DeleteModalStatus => {
+  return useAtomValue(pageDeleteModalAtom);
+};
+
+/**
+ * Hook for managing page delete modal actions
+ * Returns actions for opening and closing the modal
+ */
+export const usePageDeleteModalActions = (): DeleteModalActions => {
+  const setStatus = useSetAtom(pageDeleteModalAtom);
 
 
   const open = useCallback(
   const open = useCallback(
     (pages?: IPageToDeleteWithMeta[], opts?: IDeleteModalOption) => {
     (pages?: IPageToDeleteWithMeta[], opts?: IDeleteModalOption) => {
@@ -47,7 +54,6 @@ export const usePageDeleteModal = (): {
   }, [setStatus]);
   }, [setStatus]);
 
 
   return {
   return {
-    data: status,
     open,
     open,
     close,
     close,
   };
   };

+ 13 - 7
apps/app/src/states/ui/modal/page-duplicate.ts

@@ -1,4 +1,4 @@
-import { atom, useAtom } from 'jotai';
+import { atom, useAtomValue, useSetAtom } from 'jotai';
 import { useCallback } from 'react';
 import { useCallback } from 'react';
 
 
 import type { OnDuplicatedFunction } from '../../../interfaces/ui';
 import type { OnDuplicatedFunction } from '../../../interfaces/ui';
@@ -19,7 +19,7 @@ export type DuplicateModalStatus = {
   opts?: IDuplicateModalOption;
   opts?: IDuplicateModalOption;
 };
 };
 
 
-export type DuplicateModalUtils = {
+export type DuplicateModalActions = {
   open: (
   open: (
     page?: IPageForPageDuplicateModal,
     page?: IPageForPageDuplicateModal,
     opts?: IDuplicateModalOption,
     opts?: IDuplicateModalOption,
@@ -34,11 +34,18 @@ const pageDuplicateModalAtom = atom<DuplicateModalStatus>({
 
 
 /**
 /**
  * Hook for managing page duplicate modal state
  * Hook for managing page duplicate modal state
+ * Returns read-only modal status for optimal performance
  */
  */
-export const usePageDuplicateModal = (): {
-  data: DuplicateModalStatus;
-} & DuplicateModalUtils => {
-  const [status, setStatus] = useAtom(pageDuplicateModalAtom);
+export const usePageDuplicateModal = (): DuplicateModalStatus => {
+  return useAtomValue(pageDuplicateModalAtom);
+};
+
+/**
+ * Hook for managing page duplicate modal actions
+ * Returns actions for opening and closing the modal
+ */
+export const usePageDuplicateModalActions = (): DuplicateModalActions => {
+  const setStatus = useSetAtom(pageDuplicateModalAtom);
 
 
   const open = useCallback(
   const open = useCallback(
     (page?: IPageForPageDuplicateModal, opts?: IDuplicateModalOption) => {
     (page?: IPageForPageDuplicateModal, opts?: IDuplicateModalOption) => {
@@ -52,7 +59,6 @@ export const usePageDuplicateModal = (): {
   }, [setStatus]);
   }, [setStatus]);
 
 
   return {
   return {
-    data: status,
     open,
     open,
     close,
     close,
   };
   };

+ 13 - 7
apps/app/src/states/ui/modal/page-rename.ts

@@ -1,5 +1,5 @@
 import type { IPageToRenameWithMeta } from '@growi/core';
 import type { IPageToRenameWithMeta } from '@growi/core';
-import { atom, useAtom } from 'jotai';
+import { atom, useAtomValue, useSetAtom } from 'jotai';
 import { useCallback } from 'react';
 import { useCallback } from 'react';
 
 
 import type { OnRenamedFunction } from '../../../interfaces/ui';
 import type { OnRenamedFunction } from '../../../interfaces/ui';
@@ -15,7 +15,7 @@ export type RenameModalStatus = {
   opts?: IRenameModalOption;
   opts?: IRenameModalOption;
 };
 };
 
 
-export type RenameModalUtils = {
+export type RenameModalActions = {
   open: (page?: IPageToRenameWithMeta, opts?: IRenameModalOption) => void;
   open: (page?: IPageToRenameWithMeta, opts?: IRenameModalOption) => void;
   close: () => void;
   close: () => void;
 };
 };
@@ -27,11 +27,18 @@ const pageRenameModalAtom = atom<RenameModalStatus>({
 
 
 /**
 /**
  * Hook for managing page rename modal state
  * Hook for managing page rename modal state
+ * Returns read-only modal status for optimal performance
  */
  */
-export const usePageRenameModal = (): {
-  data: RenameModalStatus;
-} & RenameModalUtils => {
-  const [status, setStatus] = useAtom(pageRenameModalAtom);
+export const usePageRenameModal = (): RenameModalStatus => {
+  return useAtomValue(pageRenameModalAtom);
+};
+
+/**
+ * Hook for managing page rename modal actions
+ * Returns actions for opening and closing the modal
+ */
+export const usePageRenameModalActions = (): RenameModalActions => {
+  const setStatus = useSetAtom(pageRenameModalAtom);
 
 
   const open = useCallback(
   const open = useCallback(
     (page?: IPageToRenameWithMeta, opts?: IRenameModalOption) => {
     (page?: IPageToRenameWithMeta, opts?: IRenameModalOption) => {
@@ -45,7 +52,6 @@ export const usePageRenameModal = (): {
   }, [setStatus]);
   }, [setStatus]);
 
 
   return {
   return {
-    data: status,
     open,
     open,
     close,
     close,
   };
   };

+ 13 - 7
apps/app/src/states/ui/modal/shortcuts.ts

@@ -1,4 +1,4 @@
-import { atom, useAtom } from 'jotai';
+import { atom, useAtomValue, useSetAtom } from 'jotai';
 import { useCallback } from 'react';
 import { useCallback } from 'react';
 
 
 // Type definitions
 // Type definitions
@@ -6,7 +6,7 @@ export type ShortcutsModalStatus = {
   isOpened: boolean;
   isOpened: boolean;
 };
 };
 
 
-export type ShortcutsModalUtils = {
+export type ShortcutsModalActions = {
   open: () => void;
   open: () => void;
   close: () => void;
   close: () => void;
 };
 };
@@ -18,11 +18,18 @@ const shortcutsModalAtom = atom<ShortcutsModalStatus>({
 
 
 /**
 /**
  * Hook for managing shortcuts modal state
  * Hook for managing shortcuts modal state
+ * Returns read-only modal status for optimal performance
  */
  */
-export const useShortcutsModal = (): {
-  data: ShortcutsModalStatus;
-} & ShortcutsModalUtils => {
-  const [status, setStatus] = useAtom(shortcutsModalAtom);
+export const useShortcutsModal = (): ShortcutsModalStatus => {
+  return useAtomValue(shortcutsModalAtom);
+};
+
+/**
+ * Hook for managing shortcuts modal actions
+ * Returns actions for opening and closing the modal
+ */
+export const useShortcutsModalActions = (): ShortcutsModalActions => {
+  const setStatus = useSetAtom(shortcutsModalAtom);
 
 
   const open = useCallback(() => {
   const open = useCallback(() => {
     setStatus({ isOpened: true });
     setStatus({ isOpened: true });
@@ -33,7 +40,6 @@ export const useShortcutsModal = (): {
   }, [setStatus]);
   }, [setStatus]);
 
 
   return {
   return {
-    data: status,
     open,
     open,
     close,
     close,
   };
   };

+ 13 - 7
apps/app/src/states/ui/modal/tag-edit.ts

@@ -1,4 +1,4 @@
-import { atom, useAtom } from 'jotai';
+import { atom, useAtomValue, useSetAtom } from 'jotai';
 import { useCallback } from 'react';
 import { useCallback } from 'react';
 
 
 // Type definitions to match the original implementation
 // Type definitions to match the original implementation
@@ -9,7 +9,7 @@ export type TagEditModalStatus = {
   revisionId: string;
   revisionId: string;
 };
 };
 
 
-export type TagEditModalUtils = {
+export type TagEditModalActions = {
   open: (tags: string[], pageId: string, revisionId: string) => void;
   open: (tags: string[], pageId: string, revisionId: string) => void;
   close: () => void;
   close: () => void;
 };
 };
@@ -24,11 +24,18 @@ const tagEditModalAtom = atom<TagEditModalStatus>({
 
 
 /**
 /**
  * Hook for managing tag edit modal state
  * Hook for managing tag edit modal state
+ * Returns read-only modal status for optimal performance
  */
  */
-export const useTagEditModal = (): {
-  data: TagEditModalStatus;
-} & TagEditModalUtils => {
-  const [status, setStatus] = useAtom(tagEditModalAtom);
+export const useTagEditModal = (): TagEditModalStatus => {
+  return useAtomValue(tagEditModalAtom);
+};
+
+/**
+ * Hook for managing tag edit modal actions
+ * Returns actions for opening and closing the modal
+ */
+export const useTagEditModalActions = (): TagEditModalActions => {
+  const setStatus = useSetAtom(tagEditModalAtom);
 
 
   const open = useCallback(
   const open = useCallback(
     (tags: string[], pageId: string, revisionId: string) => {
     (tags: string[], pageId: string, revisionId: string) => {
@@ -42,7 +49,6 @@ export const useTagEditModal = (): {
   }, [setStatus]);
   }, [setStatus]);
 
 
   return {
   return {
-    data: status,
     open,
     open,
     close,
     close,
   };
   };