From fcf5d5602d429600099c695abb88fdff46bb208a Mon Sep 17 00:00:00 2001 From: Himself65 Date: Mon, 3 Apr 2023 04:32:52 -0500 Subject: [PATCH] feat: init `@toeverything/hooks` package (#1788) --- apps/web/package.json | 1 + .../panel/general/delete/index.tsx | 2 +- .../panel/general/index.tsx | 2 +- .../panel/sync/index.tsx | 2 +- .../web/src/components/page-detail-editor.tsx | 2 +- .../components/pure/workspace-card/index.tsx | 2 +- .../WorkspaceSelector/WorkspaceSelector.tsx | 2 +- apps/web/src/hooks/__tests__/index.spec.tsx | 16 ----- .../pages/public-workspace/[workspaceId].tsx | 2 +- .../[workspaceId]/[pageId].tsx | 2 +- packages/hooks/package.json | 7 +++ packages/hooks/src/__tests__/index.spec.ts | 62 +++++++++++++++++++ .../src}/use-blocksuite-workspace-name.ts | 5 +- .../use-blocksuite-workspace-page-title.ts | 9 ++- packages/hooks/tsconfig.json | 4 ++ tsconfig.json | 6 +- yarn.lock | 7 +++ 17 files changed, 100 insertions(+), 33 deletions(-) create mode 100644 packages/hooks/package.json create mode 100644 packages/hooks/src/__tests__/index.spec.ts rename {apps/web/src/hooks => packages/hooks/src}/use-blocksuite-workspace-name.ts (89%) rename {apps/web/src/hooks => packages/hooks/src}/use-blocksuite-workspace-page-title.ts (77%) create mode 100644 packages/hooks/tsconfig.json diff --git a/apps/web/package.json b/apps/web/package.json index ab6492dae7..27be625bb6 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -27,6 +27,7 @@ "@emotion/styled": "^11.10.6", "@mui/material": "^5.11.15", "@sentry/nextjs": "^7.46.0", + "@toeverything/hooks": "workspace:*", "cmdk": "^0.2.0", "css-spring": "^4.1.0", "dayjs": "^1.11.7", diff --git a/apps/web/src/components/affine/workspace-setting-detail/panel/general/delete/index.tsx b/apps/web/src/components/affine/workspace-setting-detail/panel/general/delete/index.tsx index fe2d4925e3..fef0fd0745 100644 --- a/apps/web/src/components/affine/workspace-setting-detail/panel/general/delete/index.tsx +++ b/apps/web/src/components/affine/workspace-setting-detail/panel/general/delete/index.tsx @@ -1,9 +1,9 @@ import { Button, Input, Modal, ModalCloseButton } from '@affine/component'; import { Trans, useTranslation } from '@affine/i18n'; import { WorkspaceFlavour } from '@affine/workspace/type'; +import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-blocksuite-workspace-name'; import { useCallback, useState } from 'react'; -import { useBlockSuiteWorkspaceName } from '../../../../../../hooks/use-blocksuite-workspace-name'; import type { AffineOfficialWorkspace } from '../../../../../../shared'; import { StyledButtonContent, diff --git a/apps/web/src/components/affine/workspace-setting-detail/panel/general/index.tsx b/apps/web/src/components/affine/workspace-setting-detail/panel/general/index.tsx index ed2be56acb..9c5c548a49 100644 --- a/apps/web/src/components/affine/workspace-setting-detail/panel/general/index.tsx +++ b/apps/web/src/components/affine/workspace-setting-detail/panel/general/index.tsx @@ -1,12 +1,12 @@ import { Button, FlexWrapper, MuiFade } from '@affine/component'; import { useTranslation } from '@affine/i18n'; import { WorkspaceFlavour } from '@affine/workspace/type'; +import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-blocksuite-workspace-name'; import type React from 'react'; import { useState } from 'react'; import { useIsWorkspaceOwner } from '../../../../../hooks/affine/use-is-workspace-owner'; import { useBlockSuiteWorkspaceAvatarUrl } from '../../../../../hooks/use-blocksuite-workspace-avatar-url'; -import { useBlockSuiteWorkspaceName } from '../../../../../hooks/use-blocksuite-workspace-name'; import { Upload } from '../../../../pure/file-upload'; import { CloudWorkspaceIcon, diff --git a/apps/web/src/components/affine/workspace-setting-detail/panel/sync/index.tsx b/apps/web/src/components/affine/workspace-setting-detail/panel/sync/index.tsx index 12d6d16419..19ade733a3 100644 --- a/apps/web/src/components/affine/workspace-setting-detail/panel/sync/index.tsx +++ b/apps/web/src/components/affine/workspace-setting-detail/panel/sync/index.tsx @@ -1,11 +1,11 @@ import { Content, FlexWrapper, styled } from '@affine/component'; import { Trans, useTranslation } from '@affine/i18n'; import { WorkspaceFlavour } from '@affine/workspace/type'; +import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-blocksuite-workspace-name'; import type React from 'react'; import { useCurrentUser } from '../../../../../hooks/current/use-current-user'; import { useBlockSuiteWorkspaceAvatarUrl } from '../../../../../hooks/use-blocksuite-workspace-avatar-url'; -import { useBlockSuiteWorkspaceName } from '../../../../../hooks/use-blocksuite-workspace-name'; import { WorkspaceAvatar } from '../../../../pure/footer'; import type { PanelProps } from '../../index'; diff --git a/apps/web/src/components/page-detail-editor.tsx b/apps/web/src/components/page-detail-editor.tsx index 3e4d4aa4aa..83c44678c9 100644 --- a/apps/web/src/components/page-detail-editor.tsx +++ b/apps/web/src/components/page-detail-editor.tsx @@ -1,6 +1,7 @@ import type { EditorContainer } from '@blocksuite/editor'; import type { Page } from '@blocksuite/store'; import { assertExists } from '@blocksuite/store'; +import { useBlockSuiteWorkspacePageTitle } from '@toeverything/hooks/use-blocksuite-workspace-page-title'; import { useAtomValue, useSetAtom } from 'jotai'; import dynamic from 'next/dynamic'; import Head from 'next/head'; @@ -8,7 +9,6 @@ import type React from 'react'; import { useCallback } from 'react'; import { currentEditorAtom, workspacePreferredModeAtom } from '../atoms'; -import { useBlockSuiteWorkspacePageTitle } from '../hooks/use-blocksuite-workspace-page-title'; import { usePageMeta } from '../hooks/use-page-meta'; import type { BlockSuiteWorkspace } from '../shared'; import { PageNotFoundError } from './affine/affine-error-eoundary'; diff --git a/apps/web/src/components/pure/workspace-card/index.tsx b/apps/web/src/components/pure/workspace-card/index.tsx index 990d9d15f2..763c1be9da 100644 --- a/apps/web/src/components/pure/workspace-card/index.tsx +++ b/apps/web/src/components/pure/workspace-card/index.tsx @@ -2,10 +2,10 @@ import { useTranslation } from '@affine/i18n'; import { PermissionType } from '@affine/workspace/affine/api'; import { WorkspaceFlavour } from '@affine/workspace/type'; import { SettingsIcon } from '@blocksuite/icons'; +import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-blocksuite-workspace-name'; import type React from 'react'; import { useCallback } from 'react'; -import { useBlockSuiteWorkspaceName } from '../../../hooks/use-blocksuite-workspace-name'; import type { AllWorkspace } from '../../../shared'; import { CloudWorkspaceIcon, diff --git a/apps/web/src/components/pure/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx b/apps/web/src/components/pure/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx index 5a42094b3b..ee34a83114 100644 --- a/apps/web/src/components/pure/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx +++ b/apps/web/src/components/pure/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx @@ -1,8 +1,8 @@ import { CloudWorkspaceIcon, LocalWorkspaceIcon } from '@blocksuite/icons'; +import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-blocksuite-workspace-name'; import type React from 'react'; import { useCurrentWorkspace } from '../../../../hooks/current/use-current-workspace'; -import { useBlockSuiteWorkspaceName } from '../../../../hooks/use-blocksuite-workspace-name'; import type { AllWorkspace } from '../../../../shared'; import { WorkspaceAvatar } from '../../workspace-avatar'; import { diff --git a/apps/web/src/hooks/__tests__/index.spec.tsx b/apps/web/src/hooks/__tests__/index.spec.tsx index 9a02b4d3dd..7f72307661 100644 --- a/apps/web/src/hooks/__tests__/index.spec.tsx +++ b/apps/web/src/hooks/__tests__/index.spec.tsx @@ -37,7 +37,6 @@ import { currentWorkspaceAtom, useCurrentWorkspace, } from '../current/use-current-workspace'; -import { useBlockSuiteWorkspaceName } from '../use-blocksuite-workspace-name'; import { usePageMeta, usePageMetaHelper } from '../use-page-meta'; import { REDIRECT_TIMEOUT, @@ -302,21 +301,6 @@ describe('useSyncRouterWithCurrentWorkspaceAndPage', () => { }); }); -describe('useBlockSuiteWorkspaceName', () => { - test('basic', async () => { - blockSuiteWorkspace.meta.setName('test 1'); - const workspaceNameHook = renderHook(() => - useBlockSuiteWorkspaceName(blockSuiteWorkspace) - ); - expect(workspaceNameHook.result.current[0]).toBe('test 1'); - blockSuiteWorkspace.meta.setName('test 2'); - workspaceNameHook.rerender(); - expect(workspaceNameHook.result.current[0]).toBe('test 2'); - workspaceNameHook.result.current[1]('test 3'); - expect(blockSuiteWorkspace.meta.name).toBe('test 3'); - }); -}); - describe('useRecentlyViewed', () => { test('basic', async () => { const { ProviderWrapper, store } = await getJotaiContext(); diff --git a/apps/web/src/pages/public-workspace/[workspaceId].tsx b/apps/web/src/pages/public-workspace/[workspaceId].tsx index 4a8e042bde..c1d166cdd3 100644 --- a/apps/web/src/pages/public-workspace/[workspaceId].tsx +++ b/apps/web/src/pages/public-workspace/[workspaceId].tsx @@ -1,5 +1,6 @@ import { Breadcrumbs, IconButton, ListSkeleton } from '@affine/component'; import { SearchIcon } from '@blocksuite/icons'; +import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-blocksuite-workspace-name'; import { useAtomValue, useSetAtom } from 'jotai'; import dynamic from 'next/dynamic'; import { useRouter } from 'next/router'; @@ -16,7 +17,6 @@ import { StyledTableContainer } from '../../components/blocksuite/block-suite-pa import { WorkspaceAvatar } from '../../components/pure/footer'; import { PageLoading } from '../../components/pure/loading'; import { useBlockSuiteWorkspaceAvatarUrl } from '../../hooks/use-blocksuite-workspace-avatar-url'; -import { useBlockSuiteWorkspaceName } from '../../hooks/use-blocksuite-workspace-name'; import { PublicWorkspaceLayout } from '../../layouts/public-workspace-layout'; import type { NextPageWithLayout } from '../../shared'; import { NavContainer, StyledBreadcrumbs } from './[workspaceId]/[pageId]'; diff --git a/apps/web/src/pages/public-workspace/[workspaceId]/[pageId].tsx b/apps/web/src/pages/public-workspace/[workspaceId]/[pageId].tsx index fda7f25b76..7209e8cccf 100644 --- a/apps/web/src/pages/public-workspace/[workspaceId]/[pageId].tsx +++ b/apps/web/src/pages/public-workspace/[workspaceId]/[pageId].tsx @@ -1,6 +1,7 @@ import { Breadcrumbs, displayFlex, styled } from '@affine/component'; import { useTranslation } from '@affine/i18n'; import { PageIcon } from '@blocksuite/icons'; +import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-blocksuite-workspace-name'; import { useAtomValue, useSetAtom } from 'jotai'; import Link from 'next/link'; import { useRouter } from 'next/router'; @@ -16,7 +17,6 @@ import { PageDetailEditor } from '../../../components/page-detail-editor'; import { WorkspaceAvatar } from '../../../components/pure/footer'; import { PageLoading } from '../../../components/pure/loading'; import { useBlockSuiteWorkspaceAvatarUrl } from '../../../hooks/use-blocksuite-workspace-avatar-url'; -import { useBlockSuiteWorkspaceName } from '../../../hooks/use-blocksuite-workspace-name'; import { PublicWorkspaceLayout } from '../../../layouts/public-workspace-layout'; import type { NextPageWithLayout } from '../../../shared'; import { initPage } from '../../../utils'; diff --git a/packages/hooks/package.json b/packages/hooks/package.json new file mode 100644 index 0000000000..464b57b85e --- /dev/null +++ b/packages/hooks/package.json @@ -0,0 +1,7 @@ +{ + "name": "@toeverything/hooks", + "exports": { + "./*": "./src/*" + }, + "private": true +} diff --git a/packages/hooks/src/__tests__/index.spec.ts b/packages/hooks/src/__tests__/index.spec.ts new file mode 100644 index 0000000000..a81ff8afd9 --- /dev/null +++ b/packages/hooks/src/__tests__/index.spec.ts @@ -0,0 +1,62 @@ +/** + * @vitest-environment happy-dom + */ +import 'fake-indexeddb/auto'; + +import { __unstableSchemas, AffineSchemas } from '@blocksuite/blocks/models'; +import type { Page } from '@blocksuite/store'; +import { assertExists } from '@blocksuite/store'; +import { Workspace as BlockSuiteWorkspace } from '@blocksuite/store'; +import { renderHook } from '@testing-library/react'; +import { useBlockSuiteWorkspacePageTitle } from '@toeverything/hooks/use-blocksuite-workspace-page-title'; +import { describe, expect, test } from 'vitest'; +import { beforeEach } from 'vitest'; + +import { useBlockSuiteWorkspaceName } from '../use-blocksuite-workspace-name'; + +let blockSuiteWorkspace: BlockSuiteWorkspace; + +beforeEach(async () => { + blockSuiteWorkspace = new BlockSuiteWorkspace({ id: 'test' }) + .register(AffineSchemas) + .register(__unstableSchemas); + const initPage = (page: Page) => { + expect(page).not.toBeNull(); + assertExists(page); + const pageBlockId = page.addBlock('affine:page', { + title: new page.Text(''), + }); + const frameId = page.addBlock('affine:frame', {}, pageBlockId); + page.addBlock('affine:paragraph', {}, frameId); + }; + initPage(blockSuiteWorkspace.createPage('page0')); + initPage(blockSuiteWorkspace.createPage('page1')); + initPage(blockSuiteWorkspace.createPage('page2')); +}); + +describe('useBlockSuiteWorkspaceName', () => { + test('basic', async () => { + blockSuiteWorkspace.meta.setName('test 1'); + const workspaceNameHook = renderHook(() => + useBlockSuiteWorkspaceName(blockSuiteWorkspace) + ); + expect(workspaceNameHook.result.current[0]).toBe('test 1'); + blockSuiteWorkspace.meta.setName('test 2'); + workspaceNameHook.rerender(); + expect(workspaceNameHook.result.current[0]).toBe('test 2'); + workspaceNameHook.result.current[1]('test 3'); + expect(blockSuiteWorkspace.meta.name).toBe('test 3'); + }); +}); + +describe('useBlockSuiteWorkspacePageTitle', () => { + test('basic', async () => { + const pageTitleHook = renderHook(() => + useBlockSuiteWorkspacePageTitle(blockSuiteWorkspace, 'page0') + ); + expect(pageTitleHook.result.current).toBe('Untitled'); + blockSuiteWorkspace.setPageMeta('page0', { title: '1' }); + pageTitleHook.rerender(); + expect(pageTitleHook.result.current).toBe('1'); + }); +}); diff --git a/apps/web/src/hooks/use-blocksuite-workspace-name.ts b/packages/hooks/src/use-blocksuite-workspace-name.ts similarity index 89% rename from apps/web/src/hooks/use-blocksuite-workspace-name.ts rename to packages/hooks/src/use-blocksuite-workspace-name.ts index 76c81969fd..6c4c231848 100644 --- a/apps/web/src/hooks/use-blocksuite-workspace-name.ts +++ b/packages/hooks/src/use-blocksuite-workspace-name.ts @@ -1,11 +1,10 @@ import { UNTITLED_WORKSPACE_NAME } from '@affine/env'; +import type { Workspace } from '@blocksuite/store'; import { assertExists } from '@blocksuite/store'; import { useCallback, useEffect, useState } from 'react'; -import type { BlockSuiteWorkspace } from '../shared'; - export function useBlockSuiteWorkspaceName( - blockSuiteWorkspace: BlockSuiteWorkspace | null + blockSuiteWorkspace: Workspace | null ) { const [name, set] = useState( () => blockSuiteWorkspace?.meta.name ?? UNTITLED_WORKSPACE_NAME diff --git a/apps/web/src/hooks/use-blocksuite-workspace-page-title.ts b/packages/hooks/src/use-blocksuite-workspace-page-title.ts similarity index 77% rename from apps/web/src/hooks/use-blocksuite-workspace-page-title.ts rename to packages/hooks/src/use-blocksuite-workspace-page-title.ts index a8d4700c42..e4dfffb24f 100644 --- a/apps/web/src/hooks/use-blocksuite-workspace-page-title.ts +++ b/packages/hooks/src/use-blocksuite-workspace-page-title.ts @@ -1,21 +1,20 @@ +import type { Workspace } from '@blocksuite/store'; import { assertExists } from '@blocksuite/store'; import { useEffect, useState } from 'react'; -import type { BlockSuiteWorkspace } from '../shared'; - export function useBlockSuiteWorkspacePageTitle( - blockSuiteWorkspace: BlockSuiteWorkspace, + blockSuiteWorkspace: Workspace, pageId: string ) { const page = blockSuiteWorkspace.getPage(pageId); const [title, setTitle] = useState(() => page?.meta.title || 'AFFiNE'); useEffect(() => { const page = blockSuiteWorkspace.getPage(pageId); - setTitle(page?.meta.title || 'AFFiNE'); + setTitle(page?.meta.title || 'Untitled'); const dispose = blockSuiteWorkspace.meta.pageMetasUpdated.on(() => { const page = blockSuiteWorkspace.getPage(pageId); assertExists(page); - setTitle(page?.meta.title || 'AFFiNE'); + setTitle(page?.meta.title || 'Untitled'); }); return () => { dispose.dispose(); diff --git a/packages/hooks/tsconfig.json b/packages/hooks/tsconfig.json new file mode 100644 index 0000000000..7513033f03 --- /dev/null +++ b/packages/hooks/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.json", + "include": ["./src"] +} diff --git a/tsconfig.json b/tsconfig.json index 3b529f655c..c3d272068e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -28,7 +28,8 @@ "@affine/utils": ["./packages/utils"], "@affine/workspace/*": ["./packages/workspace/src/*"], "@affine-test/fixtures/*": ["./tests/fixtures/*"], - "@toeverything/y-indexeddb": ["./packages/y-indexeddb/src"] + "@toeverything/y-indexeddb": ["./packages/y-indexeddb/src"], + "@toeverything/hooks/*": ["./packages/hooks/src/*"] } }, "references": [ @@ -44,6 +45,9 @@ { "path": "./packages/component" }, + { + "path": "./packages/hooks" + }, { "path": "./packages/i18n" }, diff --git a/yarn.lock b/yarn.lock index 67cbfbf213..bac34476b0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -203,6 +203,7 @@ __metadata: "@sentry/nextjs": ^7.46.0 "@swc-jotai/debug-label": ^0.0.9 "@swc-jotai/react-refresh": ^0.0.7 + "@toeverything/hooks": "workspace:*" "@types/react": ^18.0.31 "@types/react-dom": ^18.0.11 "@types/webpack-env": ^1.18.0 @@ -6148,6 +6149,12 @@ __metadata: languageName: node linkType: hard +"@toeverything/hooks@workspace:*, @toeverything/hooks@workspace:packages/hooks": + version: 0.0.0-use.local + resolution: "@toeverything/hooks@workspace:packages/hooks" + languageName: unknown + linkType: soft + "@toeverything/y-indexeddb@workspace:*, @toeverything/y-indexeddb@workspace:packages/y-indexeddb": version: 0.0.0-use.local resolution: "@toeverything/y-indexeddb@workspace:packages/y-indexeddb"