Просмотр исходного кода

feat(SimplifiedPageTreeItem): implement usePlaceholderRenameEffect hook for managing placeholder renaming

Yuki Takei 4 месяцев назад
Родитель
Сommit
0b6fa15802

+ 8 - 30
apps/app/src/client/components/Sidebar/PageTreeItem/SimplifiedPageTreeItem.tsx

@@ -1,5 +1,5 @@
 import type { FC } from 'react';
 import type { FC } from 'react';
-import { useCallback, useEffect, useRef } from 'react';
+import { useCallback } from 'react';
 
 
 import path from 'path';
 import path from 'path';
 
 
@@ -13,6 +13,7 @@ import { toastSuccess } from '~/client/util/toastr';
 import {
 import {
   CREATING_PAGE_VIRTUAL_ID,
   CREATING_PAGE_VIRTUAL_ID,
   ROOT_PAGE_VIRTUAL_ID, usePageTreeInformationUpdate, usePageRename, usePageCreate,
   ROOT_PAGE_VIRTUAL_ID, usePageTreeInformationUpdate, usePageRename, usePageCreate,
+  usePlaceholderRenameEffect,
   NameInputAlternativeComponent,
   NameInputAlternativeComponent,
 } from '~/features/page-tree';
 } from '~/features/page-tree';
 import type { IPageForItem } from '~/interfaces/page';
 import type { IPageForItem } from '~/interfaces/page';
@@ -118,35 +119,12 @@ export const SimplifiedPageTreeItem: FC<TreeItemProps> = ({
   // Check if this is the creating placeholder node
   // Check if this is the creating placeholder node
   const isCreatingPlaceholder = itemData._id === CREATING_PAGE_VIRTUAL_ID;
   const isCreatingPlaceholder = itemData._id === CREATING_PAGE_VIRTUAL_ID;
 
 
-  // Track if renaming mode was ever activated for this placeholder
-  const wasRenamingRef = useRef(false);
-  const isRenamingNow = item.isRenaming();
-
-  // Start renaming mode on placeholder node to enable getRenameInputProps()
-  useEffect(() => {
-    if (isCreatingPlaceholder && !item.isRenaming()) {
-      item.startRenaming();
-    }
-  }, [isCreatingPlaceholder, item]);
-
-  // Track when renaming becomes active
-  useEffect(() => {
-    if (isCreatingPlaceholder && isRenamingNow) {
-      wasRenamingRef.current = true;
-    }
-  }, [isCreatingPlaceholder, isRenamingNow]);
-
-  // Cancel creating when renaming mode ends on placeholder node (Esc key pressed)
-  useEffect(() => {
-    // Only cancel if renaming was previously active and is now inactive
-    if (isCreatingPlaceholder && wasRenamingRef.current && !isRenamingNow) {
-      cancelCreating();
-      wasRenamingRef.current = false;
-    }
-  }, [isCreatingPlaceholder, isRenamingNow, cancelCreating]);
-
-  // Show CreateInput only when renamingFeature is active (item.isRenaming() is true)
-  const showCreateInput = isCreatingPlaceholder && item.isRenaming();
+  // Manage placeholder renaming mode (auto-start, track, and cancel on Esc)
+  usePlaceholderRenameEffect({
+    item,
+    isPlaceholder: isCreatingPlaceholder,
+    onCancelCreate: cancelCreating,
+  });
 
 
   const itemSelectedHandler = useCallback((page: IPageForItem) => {
   const itemSelectedHandler = useCallback((page: IPageForItem) => {
     if (page.path == null || page._id == null) return;
     if (page.path == null || page._id == null) return;

+ 54 - 0
apps/app/src/features/page-tree/client/hooks/use-placeholder-rename-effect.ts

@@ -0,0 +1,54 @@
+import { useEffect, useRef } from 'react';
+import type { ItemInstance } from '@headless-tree/core';
+
+import type { IPageForItem } from '~/interfaces/page';
+
+type UsePlaceholderRenameEffectParams = {
+  item: ItemInstance<IPageForItem>;
+  isPlaceholder: boolean;
+  onCancelCreate: () => void;
+};
+
+/**
+ * Hook that manages the renaming mode for placeholder nodes.
+ *
+ * When a placeholder node is rendered:
+ * 1. Automatically starts renaming mode to enable the input field
+ * 2. Tracks when renaming mode becomes active
+ * 3. Detects when renaming mode ends (Esc key) and calls onCancelCreate
+ *
+ * This hook separates the placeholder renaming behavior from the component,
+ * keeping the component focused on rendering.
+ */
+export const usePlaceholderRenameEffect = ({
+  item,
+  isPlaceholder,
+  onCancelCreate,
+}: UsePlaceholderRenameEffectParams): void => {
+  // Track if renaming mode was ever activated for this placeholder
+  const wasRenamingRef = useRef(false);
+  const isRenamingNow = item.isRenaming();
+
+  // Start renaming mode on placeholder node to enable getRenameInputProps()
+  useEffect(() => {
+    if (isPlaceholder && !item.isRenaming()) {
+      item.startRenaming();
+    }
+  }, [isPlaceholder, item]);
+
+  // Track when renaming becomes active
+  useEffect(() => {
+    if (isPlaceholder && isRenamingNow) {
+      wasRenamingRef.current = true;
+    }
+  }, [isPlaceholder, isRenamingNow]);
+
+  // Cancel creating when renaming mode ends on placeholder node (Esc key pressed)
+  useEffect(() => {
+    // Only cancel if renaming was previously active and is now inactive
+    if (isPlaceholder && wasRenamingRef.current && !isRenamingNow) {
+      onCancelCreate();
+      wasRenamingRef.current = false;
+    }
+  }, [isPlaceholder, isRenamingNow, onCancelCreate]);
+};

+ 1 - 0
apps/app/src/features/page-tree/index.ts

@@ -10,6 +10,7 @@ export {
 export { useDataLoader } from './client/hooks/use-data-loader';
 export { useDataLoader } from './client/hooks/use-data-loader';
 export { usePageCreate } from './client/hooks/use-page-create';
 export { usePageCreate } from './client/hooks/use-page-create';
 export { usePageRename } from './client/hooks/use-page-rename';
 export { usePageRename } from './client/hooks/use-page-rename';
+export { usePlaceholderRenameEffect } from './client/hooks/use-placeholder-rename-effect';
 export { useScrollToSelectedItem } from './client/hooks/use-scroll-to-selected-item';
 export { useScrollToSelectedItem } from './client/hooks/use-scroll-to-selected-item';
 // Interfaces
 // Interfaces
 export * from './client/interfaces';
 export * from './client/interfaces';