Răsfoiți Sursa

reocate page-tree feature modules

Yuki Takei 4 luni în urmă
părinte
comite
3eb0889a1b
22 a modificat fișierele cu 208 adăugiri și 167 ștergeri
  1. 0 18
      apps/app/src/client/components/ItemsTree/ItemNode.ts
  2. 1 1
      apps/app/src/client/components/ItemsTree/ItemsTree.tsx
  3. 0 56
      apps/app/src/client/components/ItemsTree/hooks/use-data-loader.ts
  4. 5 2
      apps/app/src/client/components/ItemsTree/index.ts
  5. 1 1
      apps/app/src/client/components/Sidebar/PageTreeItem/CountBadgeForPageTreeItem.tsx
  6. 1 2
      apps/app/src/client/components/Sidebar/PageTreeItem/SimplifiedPageTreeItem.tsx
  7. 1 1
      apps/app/src/client/components/TreeItem/NewPageInput/NewPageInput.module.scss
  8. 1 1
      apps/app/src/client/components/TreeItem/NewPageInput/use-new-page-input.tsx
  9. 8 2
      apps/app/src/client/components/TreeItem/index.ts
  10. 0 0
      apps/app/src/features/page-tree/client/components/SimpleItemContent.module.scss
  11. 0 0
      apps/app/src/features/page-tree/client/components/SimpleItemContent.tsx
  12. 19 14
      apps/app/src/features/page-tree/client/components/SimplifiedItemsTree.tsx
  13. 0 0
      apps/app/src/features/page-tree/client/components/TreeItemLayout.module.scss
  14. 71 68
      apps/app/src/features/page-tree/client/components/TreeItemLayout.tsx
  15. 0 0
      apps/app/src/features/page-tree/client/components/_tree-item-variables.scss
  16. 73 0
      apps/app/src/features/page-tree/client/hooks/use-data-loader.ts
  17. 0 0
      apps/app/src/features/page-tree/client/hooks/use-scroll-to-selected-item.ts
  18. 0 0
      apps/app/src/features/page-tree/client/interfaces/index.ts
  19. 0 0
      apps/app/src/features/page-tree/client/states/page-tree-desc-count-map.ts
  20. 1 1
      apps/app/src/features/page-tree/client/states/page-tree-update.ts
  21. 0 0
      apps/app/src/features/page-tree/constants/index.ts
  22. 26 0
      apps/app/src/features/page-tree/index.ts

+ 0 - 18
apps/app/src/client/components/ItemsTree/ItemNode.ts

@@ -1,18 +0,0 @@
-import type { IPageForItem } from '../../../interfaces/page';
-
-export class ItemNode {
-
-  page: IPageForItem;
-
-  children: ItemNode[];
-
-  constructor(page: IPageForItem, children: ItemNode[] = []) {
-    this.page = page;
-    this.children = children;
-  }
-
-  static generateNodesFromPages(pages: IPageForItem[]): ItemNode[] {
-    return pages.map(page => new ItemNode(page));
-  }
-
-}

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

@@ -16,7 +16,7 @@ import { useGlobalSocket } from '~/states/socket-io';
 import { usePageDeleteModalActions } from '~/states/ui/modal/page-delete';
 import type { IPageForPageDuplicateModal } from '~/states/ui/modal/page-duplicate';
 import { usePageDuplicateModalActions } from '~/states/ui/modal/page-duplicate';
-import { usePageTreeDescCountMapAction } from '~/states/ui/page-tree-desc-count-map';
+import { usePageTreeDescCountMapAction } from '~/features/page-tree';
 import { mutateAllPageInfo } from '~/stores/page';
 import {
   useSWRxRootPage, mutatePageTree, mutatePageList,

+ 0 - 56
apps/app/src/client/components/ItemsTree/hooks/use-data-loader.ts

@@ -1,56 +0,0 @@
-import { useCallback } from 'react';
-
-import type { TreeDataLoader } from '@headless-tree/core';
-
-import { apiv3Get } from '~/client/util/apiv3-client';
-import { ROOT_PAGE_VIRTUAL_ID } from '~/constants/page-tree';
-import type { IPageForTreeItem } from '~/interfaces/page';
-
-function constructRootPageForVirtualRoot(rootPageId: string, allPagesCount: number): IPageForTreeItem {
-  return {
-    _id: rootPageId,
-    path: '/',
-    parent: null,
-    descendantCount: allPagesCount,
-    grant: 1,
-    isEmpty: false,
-    wip: false,
-  };
-}
-
-export const useDataLoader = (
-    rootPageId: string,
-    allPagesCount: number,
-): TreeDataLoader<IPageForTreeItem> => {
-  const getItem = useCallback(async (itemId: string): Promise<IPageForTreeItem> => {
-    // Virtual root (should rarely be called since it's provided by getChildrenWithData)
-    if (itemId === ROOT_PAGE_VIRTUAL_ID) {
-      return constructRootPageForVirtualRoot(rootPageId, allPagesCount);
-    }
-
-    // For all pages (including root), use /page-listing/item endpoint
-    // Note: This should rarely be called thanks to getChildrenWithData caching
-    const response = await apiv3Get<{ item: IPageForTreeItem }>('/page-listing/item', { id: itemId });
-    return response.data.item;
-  }, [allPagesCount, rootPageId]);
-
-  const getChildrenWithData = useCallback(async (itemId: string) => {
-    // Virtual root returns root page as its only child
-    // Use actual MongoDB _id as tree item ID to avoid duplicate API calls
-    if (itemId === ROOT_PAGE_VIRTUAL_ID) {
-      return [{
-        id: rootPageId,
-        data: constructRootPageForVirtualRoot(rootPageId, allPagesCount),
-      }];
-    }
-
-    // For all pages (including root), fetch children using their _id
-    const response = await apiv3Get<{ children: IPageForTreeItem[] }>('/page-listing/children', { id: itemId });
-    return response.data.children.map(child => ({
-      id: child._id,
-      data: child,
-    }));
-  }, [allPagesCount, rootPageId]);
-
-  return { getItem, getChildrenWithData };
-};

+ 5 - 2
apps/app/src/client/components/ItemsTree/index.ts

@@ -1,3 +1,6 @@
-export { ItemNode } from './ItemNode';
+// Re-export from features/page-tree (new implementation)
+export { SimplifiedItemsTree } from '~/features/page-tree';
+
+// Legacy exports (for old implementation - will be deprecated)
+export { ItemNode } from '../TreeItem';
 export * from './ItemsTree';
-export * from './SimplifiedItemsTree';

+ 1 - 1
apps/app/src/client/components/Sidebar/PageTreeItem/CountBadgeForPageTreeItem.tsx

@@ -2,7 +2,7 @@ import type { JSX } from 'react';
 
 import CountBadge from '~/client/components/Common/CountBadge';
 import type { TreeItemToolProps } from '~/client/components/TreeItem';
-import { usePageTreeDescCountMap } from '~/states/ui/page-tree-desc-count-map';
+import { usePageTreeDescCountMap } from '~/features/page-tree';
 
 
 export const CountBadgeForPageTreeItem = (props: TreeItemToolProps): JSX.Element => {

+ 1 - 2
apps/app/src/client/components/Sidebar/PageTreeItem/SimplifiedPageTreeItem.tsx

@@ -10,11 +10,10 @@ import { useTranslation } from 'next-i18next';
 import { useRouter } from 'next/router';
 
 import { toastSuccess } from '~/client/util/toastr';
-import { ROOT_PAGE_VIRTUAL_ID } from '~/constants/page-tree';
+import { ROOT_PAGE_VIRTUAL_ID, usePageTreeInformationUpdate } from '~/features/page-tree';
 import type { IPageForItem } from '~/interfaces/page';
 import type { OnDeletedFunction, OnDuplicatedFunction } from '~/interfaces/ui';
 import { useCurrentPagePath, useFetchCurrentPage } from '~/states/page';
-import { usePageTreeInformationUpdate } from '~/states/page-tree-update';
 import { usePageDeleteModalActions } from '~/states/ui/modal/page-delete';
 import type { IPageForPageDuplicateModal } from '~/states/ui/modal/page-duplicate';
 import { usePageDuplicateModalActions } from '~/states/ui/modal/page-duplicate';

+ 1 - 1
apps/app/src/client/components/TreeItem/NewPageInput/NewPageInput.module.scss

@@ -1,4 +1,4 @@
-@use '../tree-item-variables';
+@use '../../../../features/page-tree/client/components/tree-item-variables';
 
 .new-page-input-container {
   width: calc(100% - tree-item-variables.$btn-triangle-min-width);

+ 1 - 1
apps/app/src/client/components/TreeItem/NewPageInput/use-new-page-input.tsx

@@ -16,7 +16,7 @@ import { useCreatePage } from '~/client/services/create-page';
 import { toastWarning, toastError, toastSuccess } from '~/client/util/toastr';
 import type { InputValidationResult } from '~/client/util/use-input-validator';
 import { ValidationTarget, useInputValidator } from '~/client/util/use-input-validator';
-import { usePageTreeDescCountMap } from '~/states/ui/page-tree-desc-count-map';
+import { usePageTreeDescCountMap } from '~/features/page-tree';
 import { mutatePageTree, mutateRecentlyUpdated } from '~/stores/page-listing';
 
 import { shouldCreateWipPage } from '../../../../utils/should-create-wip-page';

+ 8 - 2
apps/app/src/client/components/TreeItem/index.ts

@@ -1,5 +1,11 @@
-export * from './interfaces';
+// Re-export from features/page-tree (new implementation)
+export {
+  TreeItemLayout,
+  SimpleItemContent,
+  type TreeItemProps,
+  type TreeItemToolProps,
+} from '~/features/page-tree';
 
+// Legacy exports (for old implementation - will be deprecated)
 export * from './NewPageInput';
 export * from './ItemNode';
-export * from './TreeItemLayout';

+ 0 - 0
apps/app/src/client/components/TreeItem/SimpleItemContent.module.scss → apps/app/src/features/page-tree/client/components/SimpleItemContent.module.scss


+ 0 - 0
apps/app/src/client/components/TreeItem/SimpleItemContent.tsx → apps/app/src/features/page-tree/client/components/SimpleItemContent.tsx


+ 19 - 14
apps/app/src/client/components/ItemsTree/SimplifiedItemsTree.tsx → apps/app/src/features/page-tree/client/components/SimplifiedItemsTree.tsx

@@ -1,19 +1,20 @@
 import type { FC } from 'react';
 import { useState } from 'react';
-
 import { asyncDataLoaderFeature } from '@headless-tree/core';
 import { useTree } from '@headless-tree/react';
 import { useVirtualizer } from '@tanstack/react-virtual';
 
-import { ROOT_PAGE_VIRTUAL_ID } from '~/constants/page-tree';
 import type { IPageForTreeItem } from '~/interfaces/page';
-import { usePageTreeInformationGeneration, usePageTreeRevalidationEffect } from '~/states/page-tree-update';
 import { useSWRxRootPage } from '~/stores/page-listing';
 
-import type { TreeItemProps } from '../TreeItem';
-
-import { useDataLoader } from './hooks/use-data-loader';
-import { useScrollToSelectedItem } from './hooks/use-scroll-to-selected-item';
+import { ROOT_PAGE_VIRTUAL_ID } from '../../constants';
+import { useDataLoader } from '../hooks/use-data-loader';
+import { useScrollToSelectedItem } from '../hooks/use-scroll-to-selected-item';
+import type { TreeItemProps } from '../interfaces';
+import {
+  usePageTreeInformationGeneration,
+  usePageTreeRevalidationEffect,
+} from '../states/page-tree-update';
 
 type Props = {
   targetPath: string;
@@ -21,16 +22,20 @@ type Props = {
   isWipPageShown?: boolean;
   isEnableActions?: boolean;
   isReadOnlyUser?: boolean;
-  CustomTreeItem: React.FunctionComponent<TreeItemProps>
+  CustomTreeItem: React.FunctionComponent<TreeItemProps>;
   estimateTreeItemSize: () => number;
   scrollerElem?: HTMLElement | null;
 };
 
 export const SimplifiedItemsTree: FC<Props> = (props: Props) => {
   const {
-    targetPath, targetPathOrId,
-    isWipPageShown = true, isEnableActions = false, isReadOnlyUser = false,
-    CustomTreeItem, estimateTreeItemSize,
+    targetPath,
+    targetPathOrId,
+    isWipPageShown = true,
+    isEnableActions = false,
+    isReadOnlyUser = false,
+    CustomTreeItem,
+    estimateTreeItemSize,
     scrollerElem,
   } = props;
 
@@ -45,9 +50,9 @@ export const SimplifiedItemsTree: FC<Props> = (props: Props) => {
 
   const tree = useTree<IPageForTreeItem>({
     rootItemId: ROOT_PAGE_VIRTUAL_ID,
-    getItemName: item => item.getItemData().path || '/',
+    getItemName: (item) => item.getItemData().path || '/',
     initialState: { expandedItems: [ROOT_PAGE_VIRTUAL_ID] },
-    isItemFolder: item => item.getItemData().descendantCount > 0,
+    isItemFolder: (item) => item.getItemData().descendantCount > 0,
     createLoadingItemData: () => ({
       _id: '',
       path: 'Loading...',
@@ -122,7 +127,7 @@ export const SimplifiedItemsTree: FC<Props> = (props: Props) => {
               isReadOnlyUser={isReadOnlyUser}
               onToggle={() => {
                 // Trigger re-render to show/hide children
-                setRebuildTrigger(prev => prev + 1);
+                setRebuildTrigger((prev) => prev + 1);
               }}
             />
           </div>

+ 0 - 0
apps/app/src/client/components/TreeItem/TreeItemLayout.module.scss → apps/app/src/features/page-tree/client/components/TreeItemLayout.module.scss


+ 71 - 68
apps/app/src/client/components/TreeItem/TreeItemLayout.tsx → apps/app/src/features/page-tree/client/components/TreeItemLayout.tsx

@@ -1,19 +1,16 @@
 import {
+  type JSX,
+  type MouseEvent,
   useCallback,
   useEffect,
   useMemo,
   useState,
-  type MouseEvent,
-  type JSX,
 } from 'react';
-
 import { addTrailingSlash } from '@growi/core/dist/utils/path-utils';
 
-import { usePageTreeDescCountMap } from '~/states/ui/page-tree-desc-count-map';
-
+import type { TreeItemProps, TreeItemToolProps } from '../interfaces';
+import { usePageTreeDescCountMap } from '../states/page-tree-desc-count-map';
 import { SimpleItemContent } from './SimpleItemContent';
-import type { TreeItemProps, TreeItemToolProps } from './interfaces';
-
 
 import styles from './TreeItemLayout.module.scss';
 
@@ -21,19 +18,26 @@ const moduleClass = styles['tree-item-layout'] ?? '';
 
 const indentSize = 10; // in px
 
-
 type TreeItemLayoutProps = TreeItemProps & {
-  className?: string,
-}
+  className?: string;
+};
 
 export const TreeItemLayout = (props: TreeItemLayoutProps): JSX.Element => {
   const {
-    className, itemClassName,
+    className,
+    itemClassName,
     item,
-    targetPath, targetPathOrId,
-    isEnableActions, isReadOnlyUser, isWipPageShown = true,
+    targetPath,
+    targetPathOrId,
+    isEnableActions,
+    isReadOnlyUser,
+    isWipPageShown = true,
     showAlternativeContent,
-    onRenamed, onClick, onClickDuplicateMenuItem, onClickDeleteMenuItem, onWheelClick,
+    onRenamed,
+    onClick,
+    onClickDuplicateMenuItem,
+    onClickDeleteMenuItem,
+    onWheelClick,
     onToggle,
   } = props;
 
@@ -45,37 +49,39 @@ export const TreeItemLayout = (props: TreeItemLayoutProps): JSX.Element => {
   const toggleHandler = useCallback(() => {
     if (item.isExpanded()) {
       item.collapse();
-    }
-    else {
+    } else {
       item.expand();
     }
 
     onToggle?.();
   }, [item, onToggle]);
 
-  const itemClickHandler = useCallback((e: MouseEvent) => {
-    // DO NOT handle the event when e.currentTarget and e.target is different
-    if (e.target !== e.currentTarget) {
-      return;
-    }
-
-    onClick?.(page);
-
-  }, [onClick, page]);
-
-  const itemMouseupHandler = useCallback((e: MouseEvent) => {
-    // DO NOT handle the event when e.currentTarget and e.target is different
-    if (e.target !== e.currentTarget) {
-      return;
-    }
+  const itemClickHandler = useCallback(
+    (e: MouseEvent) => {
+      // DO NOT handle the event when e.currentTarget and e.target is different
+      if (e.target !== e.currentTarget) {
+        return;
+      }
 
-    if (e.button === 1) {
-      e.preventDefault();
-      onWheelClick?.(page);
-    }
+      onClick?.(page);
+    },
+    [onClick, page],
+  );
 
-  }, [onWheelClick, page]);
+  const itemMouseupHandler = useCallback(
+    (e: MouseEvent) => {
+      // DO NOT handle the event when e.currentTarget and e.target is different
+      if (e.target !== e.currentTarget) {
+        return;
+      }
 
+      if (e.button === 1) {
+        e.preventDefault();
+        onWheelClick?.(page);
+      }
+    },
+    [onWheelClick, page],
+  );
 
   // descendantCount
   const { getDescCount } = usePageTreeDescCountMap();
@@ -87,9 +93,10 @@ export const TreeItemLayout = (props: TreeItemLayoutProps): JSX.Element => {
   // auto open if targetPath is descendant of this page
   useEffect(() => {
     if (!isAutoOpenerInitialized) {
-      const isPathToTarget = page.path != null
-        && targetPath.startsWith(addTrailingSlash(page.path))
-        && targetPath !== page.path; // Target Page does not need to be opened
+      const isPathToTarget =
+        page.path != null &&
+        targetPath.startsWith(addTrailingSlash(page.path)) &&
+        targetPath !== page.path; // Target Page does not need to be opened
 
       if (page.path === '/' || isPathToTarget) {
         item.expand();
@@ -98,7 +105,6 @@ export const TreeItemLayout = (props: TreeItemLayoutProps): JSX.Element => {
     }
 
     setAutoOpenerInitialized(true);
-
   }, [targetPath, page.path, isAutoOpenerInitialized, item, onToggle]);
 
   const isSelected = useMemo(() => {
@@ -139,7 +145,6 @@ export const TreeItemLayout = (props: TreeItemLayoutProps): JSX.Element => {
         onClick={itemClickHandler}
         onMouseUp={itemMouseupHandler}
       >
-
         <div className="btn-triangle-container d-flex justify-content-center">
           {hasDescendants && (
             <button
@@ -148,38 +153,36 @@ export const TreeItemLayout = (props: TreeItemLayoutProps): JSX.Element => {
               onClick={toggleHandler}
             >
               <div className="d-flex justify-content-center">
-                <span className="material-symbols-outlined fs-5">arrow_right</span>
+                <span className="material-symbols-outlined fs-5">
+                  arrow_right
+                </span>
               </div>
             </button>
           )}
         </div>
 
-        {showAlternativeContent && AlternativeComponents != null
-          ? (
-            AlternativeComponents.map((AlternativeContent, index) => (
-              // eslint-disable-next-line react/no-array-index-key
-              (<AlternativeContent key={index} {...toolProps} />)
-            ))
-          )
-          : (
-            <>
-              <SimpleItemContent page={page} />
-              <div className="d-hover-none">
-                {EndComponents?.map((EndComponent, index) => (
-                  // eslint-disable-next-line react/no-array-index-key
-                  (<EndComponent key={index} {...toolProps} />)
-                ))}
-              </div>
-              <div className="d-none d-hover-flex">
-                {HoveredEndComponents?.map((HoveredEndContent, index) => (
-                  // eslint-disable-next-line react/no-array-index-key
-                  (<HoveredEndContent key={index} {...toolProps} />)
-                ))}
-              </div>
-            </>
-          )
-        }
-
+        {showAlternativeContent && AlternativeComponents != null ? (
+          AlternativeComponents.map((AlternativeContent, index) => (
+            // eslint-disable-next-line react/no-array-index-key
+            <AlternativeContent key={index} {...toolProps} />
+          ))
+        ) : (
+          <>
+            <SimpleItemContent page={page} />
+            <div className="d-hover-none">
+              {EndComponents?.map((EndComponent, index) => (
+                // eslint-disable-next-line react/no-array-index-key
+                <EndComponent key={index} {...toolProps} />
+              ))}
+            </div>
+            <div className="d-none d-hover-flex">
+              {HoveredEndComponents?.map((HoveredEndContent, index) => (
+                // eslint-disable-next-line react/no-array-index-key
+                <HoveredEndContent key={index} {...toolProps} />
+              ))}
+            </div>
+          </>
+        )}
       </li>
     </div>
   );

+ 0 - 0
apps/app/src/client/components/TreeItem/_tree-item-variables.scss → apps/app/src/features/page-tree/client/components/_tree-item-variables.scss


+ 73 - 0
apps/app/src/features/page-tree/client/hooks/use-data-loader.ts

@@ -0,0 +1,73 @@
+import { useCallback } from 'react';
+import type { TreeDataLoader } from '@headless-tree/core';
+
+import { apiv3Get } from '~/client/util/apiv3-client';
+import type { IPageForTreeItem } from '~/interfaces/page';
+
+import { ROOT_PAGE_VIRTUAL_ID } from '../../constants';
+
+function constructRootPageForVirtualRoot(
+  rootPageId: string,
+  allPagesCount: number,
+): IPageForTreeItem {
+  return {
+    _id: rootPageId,
+    path: '/',
+    parent: null,
+    descendantCount: allPagesCount,
+    grant: 1,
+    isEmpty: false,
+    wip: false,
+  };
+}
+
+export const useDataLoader = (
+  rootPageId: string,
+  allPagesCount: number,
+): TreeDataLoader<IPageForTreeItem> => {
+  const getItem = useCallback(
+    async (itemId: string): Promise<IPageForTreeItem> => {
+      // Virtual root (should rarely be called since it's provided by getChildrenWithData)
+      if (itemId === ROOT_PAGE_VIRTUAL_ID) {
+        return constructRootPageForVirtualRoot(rootPageId, allPagesCount);
+      }
+
+      // For all pages (including root), use /page-listing/item endpoint
+      // Note: This should rarely be called thanks to getChildrenWithData caching
+      const response = await apiv3Get<{ item: IPageForTreeItem }>(
+        '/page-listing/item',
+        { id: itemId },
+      );
+      return response.data.item;
+    },
+    [allPagesCount, rootPageId],
+  );
+
+  const getChildrenWithData = useCallback(
+    async (itemId: string) => {
+      // Virtual root returns root page as its only child
+      // Use actual MongoDB _id as tree item ID to avoid duplicate API calls
+      if (itemId === ROOT_PAGE_VIRTUAL_ID) {
+        return [
+          {
+            id: rootPageId,
+            data: constructRootPageForVirtualRoot(rootPageId, allPagesCount),
+          },
+        ];
+      }
+
+      // For all pages (including root), fetch children using their _id
+      const response = await apiv3Get<{ children: IPageForTreeItem[] }>(
+        '/page-listing/children',
+        { id: itemId },
+      );
+      return response.data.children.map((child) => ({
+        id: child._id,
+        data: child,
+      }));
+    },
+    [allPagesCount, rootPageId],
+  );
+
+  return { getItem, getChildrenWithData };
+};

+ 0 - 0
apps/app/src/client/components/ItemsTree/hooks/use-scroll-to-selected-item.ts → apps/app/src/features/page-tree/client/hooks/use-scroll-to-selected-item.ts


+ 0 - 0
apps/app/src/client/components/TreeItem/interfaces/index.ts → apps/app/src/features/page-tree/client/interfaces/index.ts


+ 0 - 0
apps/app/src/states/ui/page-tree-desc-count-map.ts → apps/app/src/features/page-tree/client/states/page-tree-desc-count-map.ts


+ 1 - 1
apps/app/src/states/page-tree-update.ts → apps/app/src/features/page-tree/client/states/page-tree-update.ts

@@ -2,7 +2,7 @@ import { useCallback, useEffect } from 'react';
 import type { TreeInstance } from '@headless-tree/core';
 import { atom, useAtomValue, useSetAtom } from 'jotai';
 
-import { ROOT_PAGE_VIRTUAL_ID } from '~/constants/page-tree';
+import { ROOT_PAGE_VIRTUAL_ID } from '../../constants';
 
 // Update generation number
 const generationAtom = atom<number>(1);

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


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

@@ -0,0 +1,26 @@
+// Components
+
+export { SimpleItemContent } from './client/components/SimpleItemContent';
+export { SimplifiedItemsTree } from './client/components/SimplifiedItemsTree';
+export { TreeItemLayout } from './client/components/TreeItemLayout';
+// Hooks
+export { useDataLoader } from './client/hooks/use-data-loader';
+export { useScrollToSelectedItem } from './client/hooks/use-scroll-to-selected-item';
+// Interfaces
+export * from './client/interfaces';
+export {
+  type PageTreeDescCountMapActions,
+  type PageTreeDescCountMapGetter,
+  type UpdateDescCountData,
+  usePageTreeDescCountMap,
+  usePageTreeDescCountMapAction,
+} from './client/states/page-tree-desc-count-map';
+// States
+export {
+  usePageTreeInformationGeneration,
+  usePageTreeInformationLastUpdatedItemIds,
+  usePageTreeInformationUpdate,
+  usePageTreeRevalidationEffect,
+} from './client/states/page-tree-update';
+// Constants
+export { ROOT_PAGE_VIRTUAL_ID } from './constants';