Browse Source

simplify PageTree components

Yuki Takei 3 weeks ago
parent
commit
a2af60fdbd

+ 3 - 4
apps/app/src/client/components/Sidebar/PageTree/PageTree.tsx

@@ -5,11 +5,10 @@ import { useTranslation } from 'react-i18next';
 import ItemsTreeContentSkeleton from '../../ItemsTree/ItemsTreeContentSkeleton';
 import { PageTreeHeader } from './PageTreeSubstance';
 
-// react-dnd and react-dnd-html5-backend are browser-only; wrapping them with
-// ssr: false keeps both packages out of .next/node_modules/ so they can stay
-// in devDependencies.
+// PageTreeWithDnD uses HTML5Backend which accesses browser APIs on mount;
+// ssr: false prevents it from rendering on the server.
 const PageTreeWithDnD = dynamic(
-  () => import('./PageTreeWithDnD').then((mod) => mod.PageTreeWithDnD),
+  () => import('./PageTreeSubstance').then((mod) => mod.PageTreeWithDnD),
   { ssr: false, loading: ItemsTreeContentSkeleton },
 );
 

+ 60 - 57
apps/app/src/client/components/Sidebar/PageTree/PageTreeSubstance.tsx

@@ -1,5 +1,7 @@
-import React, { memo, useCallback } from 'react';
+import { memo, useCallback, useId } from 'react';
 import { useTranslation } from 'next-i18next';
+import { DndProvider } from 'react-dnd';
+import { HTML5Backend } from 'react-dnd-html5-backend';
 
 import { ItemsTree } from '~/features/page-tree/components';
 import { usePageTreeInformationUpdate } from '~/features/page-tree/states/page-tree-update';
@@ -12,14 +14,11 @@ import {
   useSWRxRootPage,
   useSWRxV5MigrationStatus,
 } from '~/stores/page-listing';
-import loggerFactory from '~/utils/logger';
 
 import { PageTreeItem, pageTreeItemSize } from '../PageTreeItem';
 import { SidebarHeaderReloadButton } from '../SidebarHeaderReloadButton';
 import { PrivateLegacyPagesLink } from './PrivateLegacyPagesLink';
 
-const logger = loggerFactory('growi:cli:PageTreeSubstance');
-
 type HeaderProps = {
   isWipPageShown: boolean;
   onWipPageShownChange?: () => void;
@@ -28,6 +27,7 @@ type HeaderProps = {
 export const PageTreeHeader = memo(
   ({ isWipPageShown, onWipPageShownChange }: HeaderProps) => {
     const { t } = useTranslation();
+    const wipToggleId = useId();
 
     const { mutate: mutateRootPage } = useSWRxRootPage({ suspense: true });
     useSWRxV5MigrationStatus({ suspense: true });
@@ -66,7 +66,7 @@ export const PageTreeHeader = memo(
               >
                 <div className="form-check form-switch">
                   <input
-                    id="page-tree-wip-toggle"
+                    id={wipToggleId}
                     className="form-check-input pe-none"
                     type="checkbox"
                     checked={isWipPageShown}
@@ -74,7 +74,7 @@ export const PageTreeHeader = memo(
                   />
                   <label
                     className="form-check-label pe-none"
-                    htmlFor="page-tree-wip-toggle"
+                    htmlFor={wipToggleId}
                   >
                     {t('sidebar_header.show_wip_page')}
                   </label>
@@ -106,63 +106,66 @@ type PageTreeContentProps = {
   isWipPageShown: boolean;
 };
 
-export const PageTreeContent = memo(
-  ({ isWipPageShown }: PageTreeContentProps) => {
-    const isGuestUser = useIsGuestUser();
-    const isReadOnlyUser = useIsReadOnlyUser();
-    const currentPath = useCurrentPagePath();
-    const targetId = useCurrentPageId();
+const PageTreeContent = memo(({ isWipPageShown }: PageTreeContentProps) => {
+  const isGuestUser = useIsGuestUser();
+  const isReadOnlyUser = useIsReadOnlyUser();
+  const currentPath = useCurrentPagePath();
+  const targetId = useCurrentPageId();
 
-    const { data: migrationStatus } = useSWRxV5MigrationStatus({
-      suspense: true,
-    });
+  const { data: migrationStatus } = useSWRxV5MigrationStatus({
+    suspense: true,
+  });
 
-    const targetPathOrId = targetId || currentPath;
-    const path = currentPath || '/';
+  const targetPathOrId = targetId || currentPath;
+  const path = currentPath || '/';
 
-    const sidebarScrollerElem = useSidebarScrollerElem();
+  const sidebarScrollerElem = useSidebarScrollerElem();
 
-    const estimateTreeItemSize = useCallback(() => pageTreeItemSize, []);
+  const estimateTreeItemSize = useCallback(() => pageTreeItemSize, []);
 
-    if (!migrationStatus?.isV5Compatible) {
-      return <PageTreeUnavailable />;
-    }
+  if (!migrationStatus?.isV5Compatible) {
+    return <PageTreeUnavailable />;
+  }
 
-    /*
-     * dependencies
-     */
-    if (isGuestUser == null) {
-      return null;
-    }
+  /*
+   * dependencies
+   */
+  if (isGuestUser == null) {
+    return null;
+  }
 
-    return (
-      <div className="pt-4">
-        <ItemsTree
-          enableRenaming
-          enableDragAndDrop
-          isEnableActions={!isGuestUser}
-          isReadOnlyUser={!!isReadOnlyUser}
-          isWipPageShown={isWipPageShown}
-          targetPath={path}
-          targetPathOrId={targetPathOrId}
-          CustomTreeItem={PageTreeItem}
-          estimateTreeItemSize={estimateTreeItemSize}
-          scrollerElem={sidebarScrollerElem}
-        />
-
-        {!isGuestUser &&
-          !isReadOnlyUser &&
-          migrationStatus?.migratablePagesCount != null &&
-          migrationStatus.migratablePagesCount !== 0 && (
-            <div className="grw-pagetree-footer border-top mt-4 py-2 w-100">
-              <div className="private-legacy-pages-link px-3 py-2">
-                <PrivateLegacyPagesLink />
-              </div>
+  return (
+    <div className="pt-4">
+      <ItemsTree
+        enableRenaming
+        enableDragAndDrop
+        isEnableActions={!isGuestUser}
+        isReadOnlyUser={!!isReadOnlyUser}
+        isWipPageShown={isWipPageShown}
+        targetPath={path}
+        targetPathOrId={targetPathOrId}
+        CustomTreeItem={PageTreeItem}
+        estimateTreeItemSize={estimateTreeItemSize}
+        scrollerElem={sidebarScrollerElem}
+      />
+
+      {!isGuestUser &&
+        !isReadOnlyUser &&
+        migrationStatus?.migratablePagesCount != null &&
+        migrationStatus.migratablePagesCount !== 0 && (
+          <div className="grw-pagetree-footer border-top mt-4 py-2 w-100">
+            <div className="private-legacy-pages-link px-3 py-2">
+              <PrivateLegacyPagesLink />
             </div>
-          )}
-      </div>
-    );
-  },
-);
-
+          </div>
+        )}
+    </div>
+  );
+});
 PageTreeContent.displayName = 'PageTreeContent';
+
+export const PageTreeWithDnD = ({ isWipPageShown }: PageTreeContentProps) => (
+  <DndProvider backend={HTML5Backend}>
+    <PageTreeContent isWipPageShown={isWipPageShown} />
+  </DndProvider>
+);

+ 0 - 18
apps/app/src/client/components/Sidebar/PageTree/PageTreeWithDnD.tsx

@@ -1,18 +0,0 @@
-import type { JSX } from 'react';
-import { DndProvider } from 'react-dnd';
-import { HTML5Backend } from 'react-dnd-html5-backend';
-
-import { PageTreeContent } from './PageTreeSubstance';
-
-type Props = {
-  isWipPageShown: boolean;
-};
-
-// Wraps PageTreeContent with the DnD provider.
-// This file is loaded via dynamic({ ssr: false }) so that react-dnd and
-// react-dnd-html5-backend stay out of SSR bundles (and devDependencies).
-export const PageTreeWithDnD = ({ isWipPageShown }: Props): JSX.Element => (
-  <DndProvider backend={HTML5Backend}>
-    <PageTreeContent isWipPageShown={isWipPageShown} />
-  </DndProvider>
-);