From 3009d729faa7f72d9b3ab678404090bfde34103a Mon Sep 17 00:00:00 2001 From: Garfield Lee Date: Tue, 8 Aug 2023 14:54:31 +0800 Subject: [PATCH] refactor: remove React.FC for affine core (#3617) --- .../components/__debug__/client/editor.tsx | 3 +- .../enable-affine-cloud-modal/index.tsx | 5 +- .../components/affine/language-menu/index.tsx | 19 ++++-- .../delete-leave-workspace/index.tsx | 12 +++- .../new-workspace-setting-detail/export.tsx | 9 ++- .../new-workspace-setting-detail/index.tsx | 10 +-- .../new-workspace-setting-detail/profile.tsx | 8 ++- .../new-workspace-setting-detail/publish.tsx | 42 ++++++------ .../new-workspace-setting-detail/storage.tsx | 8 ++- .../components/affine/onboarding-modal.tsx | 3 +- .../appearance/date-format-setting.tsx | 13 +++- .../setting-modal/general-setting/index.tsx | 19 +++--- .../components/affine/setting-modal/index.tsx | 15 +++-- .../setting-modal/setting-sidebar/index.tsx | 34 ++++++---- .../tmp-disable-affine-cloud-modal/index.tsx | 9 +-- .../index.tsx | 13 ++-- .../block-suite-page-list/index.tsx | 36 +++++----- .../header-right-items/language-menu.tsx | 13 +++- .../blocksuite/workspace-header/header.tsx | 29 ++++---- .../blocksuite/workspace-header/index.tsx | 20 +++--- .../blocksuite/workspace-header/utils.tsx | 3 +- .../src/components/page-detail-editor.tsx | 60 +++++++++-------- .../src/components/pure/file-upload/index.tsx | 12 ++-- .../core/src/components/pure/footer/index.tsx | 5 +- .../pure/quick-search-modal/config.ts | 29 ++++---- .../pure/quick-search-modal/footer.tsx | 10 +-- .../pure/quick-search-modal/index.tsx | 11 ++-- .../pure/quick-search-modal/results.tsx | 12 ++-- .../WorkspaceSelector/workspace-selector.tsx | 8 +-- .../components/pure/workspace-title/index.tsx | 14 ++-- apps/core/src/layouts/workspace-layout.tsx | 66 ++++++++++--------- apps/core/src/providers/modal-provider.tsx | 6 +- 32 files changed, 314 insertions(+), 242 deletions(-) diff --git a/apps/core/src/components/__debug__/client/editor.tsx b/apps/core/src/components/__debug__/client/editor.tsx index 129fc7494..1f104909b 100644 --- a/apps/core/src/components/__debug__/client/editor.tsx +++ b/apps/core/src/components/__debug__/client/editor.tsx @@ -3,7 +3,6 @@ import { WorkspaceFlavour } from '@affine/env/workspace'; import { getOrCreateWorkspace } from '@affine/workspace/manager'; import type { EditorContainer } from '@blocksuite/editor'; import type { Page } from '@blocksuite/store'; -import type React from 'react'; import { useCallback } from 'react'; import { BlockSuiteEditor } from '../../blocksuite/block-suite-editor'; @@ -15,7 +14,7 @@ const blockSuiteWorkspace = getOrCreateWorkspace( const page = blockSuiteWorkspace.createPage({ id: 'page0' }); -const Editor: React.FC = () => { +const Editor = () => { const onLoad = useCallback((page: Page, editor: EditorContainer) => { // @ts-expect-error globalThis.page = page; diff --git a/apps/core/src/components/affine/enable-affine-cloud-modal/index.tsx b/apps/core/src/components/affine/enable-affine-cloud-modal/index.tsx index 73a7af6a1..e99245f8c 100644 --- a/apps/core/src/components/affine/enable-affine-cloud-modal/index.tsx +++ b/apps/core/src/components/affine/enable-affine-cloud-modal/index.tsx @@ -2,7 +2,6 @@ import { Modal, ModalWrapper, Wrapper } from '@affine/component'; import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { CloseIcon } from '@blocksuite/icons'; import { Button, IconButton } from '@toeverything/components/button'; -import type React from 'react'; import { Content, ContentTitle, Header, StyleTips } from './style'; @@ -12,11 +11,11 @@ interface EnableAffineCloudModalProps { onClose: () => void; } -export const EnableAffineCloudModal: React.FC = ({ +export const EnableAffineCloudModal = ({ onConfirm, open, onClose, -}) => { +}: EnableAffineCloudModalProps) => { const t = useAFFiNEI18N(); return ( diff --git a/apps/core/src/components/affine/language-menu/index.tsx b/apps/core/src/components/affine/language-menu/index.tsx index 24eeffb4f..6f072f2e1 100644 --- a/apps/core/src/components/affine/language-menu/index.tsx +++ b/apps/core/src/components/affine/language-menu/index.tsx @@ -2,17 +2,20 @@ import { Menu, MenuItem, MenuTrigger, styled } from '@affine/component'; import { LOCALES } from '@affine/i18n'; import { useI18N } from '@affine/i18n'; import type { ButtonProps } from '@toeverything/components/button'; -import type { FC, ReactElement } from 'react'; +import type { ReactElement } from 'react'; import { useCallback } from 'react'; + export const StyledListItem = styled(MenuItem)(() => ({ width: '132px', height: '38px', textTransform: 'capitalize', })); -const LanguageMenuContent: FC<{ +interface LanguageMenuContentProps { currentLanguage?: string; -}> = ({ currentLanguage }) => { +} + +const LanguageMenuContent = ({ currentLanguage }: LanguageMenuContentProps) => { const i18n = useI18N(); const changeLanguage = useCallback( (event: string) => { @@ -20,6 +23,7 @@ const LanguageMenuContent: FC<{ }, [i18n] ); + return ( <> {LOCALES.map(option => { @@ -41,9 +45,12 @@ const LanguageMenuContent: FC<{ ); }; -export const LanguageMenu: FC<{ triggerProps?: ButtonProps }> = ({ - triggerProps, -}) => { + +interface LanguageMenuProps { + triggerProps?: ButtonProps; +} + +export const LanguageMenu = ({ triggerProps }: LanguageMenuProps) => { const i18n = useI18N(); const currentLanguage = LOCALES.find(item => item.tag === i18n.language); diff --git a/apps/core/src/components/affine/new-workspace-setting-detail/delete-leave-workspace/index.tsx b/apps/core/src/components/affine/new-workspace-setting-detail/delete-leave-workspace/index.tsx index 3fdf71ce0..f635ee13c 100644 --- a/apps/core/src/components/affine/new-workspace-setting-detail/delete-leave-workspace/index.tsx +++ b/apps/core/src/components/affine/new-workspace-setting-detail/delete-leave-workspace/index.tsx @@ -1,23 +1,29 @@ import { SettingRow } from '@affine/component/setting-components'; import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { ArrowRightSmallIcon } from '@blocksuite/icons'; -import { type FC, useState } from 'react'; +import { useState } from 'react'; import type { AffineOfficialWorkspace } from '../../../../shared'; import type { WorkspaceSettingDetailProps } from '../index'; import { WorkspaceDeleteModal } from './delete'; import { WorkspaceLeave } from './leave'; -export const DeleteLeaveWorkspace: FC<{ +interface DeleteLeaveWorkspaceProps { workspace: AffineOfficialWorkspace; onDeleteWorkspace: WorkspaceSettingDetailProps['onDeleteWorkspace']; -}> = ({ workspace, onDeleteWorkspace }) => { +} + +export const DeleteLeaveWorkspace = ({ + workspace, + onDeleteWorkspace, +}: DeleteLeaveWorkspaceProps) => { const t = useAFFiNEI18N(); // fixme: cloud regression const isOwner = true; const [showDelete, setShowDelete] = useState(false); const [showLeave, setShowLeave] = useState(false); + return ( <> = ({ workspace }) => { +} + +export const ExportPanel = ({ workspace }: ExportPanelProps) => { const workspaceId = workspace.id; const t = useAFFiNEI18N(); const onExport = useCallback(async () => { @@ -42,6 +44,7 @@ export const ExportPanel: FC<{ toast(t['Export success']()); } }, [t, workspace, workspaceId]); + return ( <> diff --git a/apps/core/src/components/affine/new-workspace-setting-detail/index.tsx b/apps/core/src/components/affine/new-workspace-setting-detail/index.tsx index e16450af3..8c4fb3b1e 100644 --- a/apps/core/src/components/affine/new-workspace-setting-detail/index.tsx +++ b/apps/core/src/components/affine/new-workspace-setting-detail/index.tsx @@ -9,7 +9,7 @@ import type { } from '@affine/env/workspace'; import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name'; -import { type FC, useMemo } from 'react'; +import { useMemo } from 'react'; import { useWorkspace } from '../../../hooks/use-workspace'; import { DeleteLeaveWorkspace } from './delete-leave-workspace'; @@ -18,7 +18,7 @@ import { ProfilePanel } from './profile'; import { PublishPanel } from './publish'; import { StoragePanel } from './storage'; -export type WorkspaceSettingDetailProps = { +export interface WorkspaceSettingDetailProps { workspaceId: string; onDeleteWorkspace: (id: string) => Promise; onTransferWorkspace: < @@ -29,13 +29,13 @@ export type WorkspaceSettingDetailProps = { to: To, workspace: WorkspaceRegistry[From] ) => void; -}; +} -export const WorkspaceSettingDetail: FC = ({ +export const WorkspaceSettingDetail = ({ workspaceId, onDeleteWorkspace, ...props -}) => { +}: WorkspaceSettingDetailProps) => { const t = useAFFiNEI18N(); const workspace = useWorkspace(workspaceId); const [name] = useBlockSuiteWorkspaceName(workspace.blockSuiteWorkspace); diff --git a/apps/core/src/components/affine/new-workspace-setting-detail/profile.tsx b/apps/core/src/components/affine/new-workspace-setting-detail/profile.tsx index d6eb4dae6..54a793c01 100644 --- a/apps/core/src/components/affine/new-workspace-setting-detail/profile.tsx +++ b/apps/core/src/components/affine/new-workspace-setting-detail/profile.tsx @@ -5,7 +5,7 @@ import { DoneIcon } from '@blocksuite/icons'; import { IconButton } from '@toeverything/components/button'; import { useBlockSuiteWorkspaceAvatarUrl } from '@toeverything/hooks/use-block-suite-workspace-avatar-url'; import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name'; -import { type FC, useCallback, useState } from 'react'; +import { useCallback, useState } from 'react'; import type { AffineOfficialWorkspace } from '../../../shared'; import { Upload } from '../../pure/file-upload'; @@ -30,9 +30,11 @@ const CameraIcon = () => { ); }; -export const ProfilePanel: FC<{ +interface ProfilePanelProps { workspace: AffineOfficialWorkspace; -}> = ({ workspace }) => { +} + +export const ProfilePanel = ({ workspace }: ProfilePanelProps) => { const t = useAFFiNEI18N(); const [, update] = useBlockSuiteWorkspaceAvatarUrl( diff --git a/apps/core/src/components/affine/new-workspace-setting-detail/publish.tsx b/apps/core/src/components/affine/new-workspace-setting-detail/publish.tsx index b244cb16e..652737f76 100644 --- a/apps/core/src/components/affine/new-workspace-setting-detail/publish.tsx +++ b/apps/core/src/components/affine/new-workspace-setting-detail/publish.tsx @@ -9,7 +9,6 @@ import { WorkspaceFlavour } from '@affine/env/workspace'; import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { Button } from '@toeverything/components/button'; import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name'; -import type { FC } from 'react'; import { useCallback, useEffect, useState } from 'react'; import type { AffineOfficialWorkspace } from '../../../shared'; @@ -19,26 +18,20 @@ import { TmpDisableAffineCloudModal } from '../tmp-disable-affine-cloud-modal'; import type { WorkspaceSettingDetailProps } from './index'; import * as style from './style.css'; -export type PublishPanelProps = Omit< - WorkspaceSettingDetailProps, - 'workspaceId' -> & { +export interface PublishPanelProps + extends Omit { workspace: AffineOfficialWorkspace; -}; -export type PublishPanelLocalProps = Omit< - WorkspaceSettingDetailProps, - 'workspaceId' -> & { +} +export interface PublishPanelLocalProps + extends Omit { workspace: LocalWorkspace; -}; -export type PublishPanelAffineProps = Omit< - WorkspaceSettingDetailProps, - 'workspaceId' -> & { +} +export interface PublishPanelAffineProps + extends Omit { workspace: AffineCloudWorkspace; -}; +} -const PublishPanelAffine: FC = props => { +const PublishPanelAffine = (props: PublishPanelAffineProps) => { const { workspace } = props; const t = useAFFiNEI18N(); // const toggleWorkspacePublish = useToggleWorkspacePublish(workspace); @@ -58,6 +51,7 @@ const PublishPanelAffine: FC = props => { await navigator.clipboard.writeText(shareUrl); toast(t['Copied link to clipboard']()); }, [shareUrl, t]); + return ( <> = props => { ); }; -const FakePublishPanelAffine: FC<{ +interface FakePublishPanelAffineProps { workspace: AffineOfficialWorkspace; -}> = () => { +} + +const FakePublishPanelAffine = (_props: FakePublishPanelAffineProps) => { const t = useAFFiNEI18N(); + return ( ); }; -const PublishPanelLocal: FC = ({ + +const PublishPanelLocal = ({ workspace, onTransferWorkspace, -}) => { +}: PublishPanelLocalProps) => { const t = useAFFiNEI18N(); const [name] = useBlockSuiteWorkspaceName(workspace.blockSuiteWorkspace); @@ -167,7 +165,7 @@ const PublishPanelLocal: FC = ({ ); }; -export const PublishPanel: FC = props => { +export const PublishPanel = (props: PublishPanelProps) => { if (props.workspace.flavour === WorkspaceFlavour.AFFINE_CLOUD) { return ; } else if (props.workspace.flavour === WorkspaceFlavour.LOCAL) { diff --git a/apps/core/src/components/affine/new-workspace-setting-detail/storage.tsx b/apps/core/src/components/affine/new-workspace-setting-detail/storage.tsx index f58972f80..0bd66838e 100644 --- a/apps/core/src/components/affine/new-workspace-setting-detail/storage.tsx +++ b/apps/core/src/components/affine/new-workspace-setting-detail/storage.tsx @@ -3,7 +3,7 @@ import { SettingRow } from '@affine/component/setting-components'; import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { Button } from '@toeverything/components/button'; import { useMemo } from 'react'; -import { type FC, useCallback, useEffect, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import type { AffineOfficialWorkspace } from '../../../shared'; import * as style from './style.css'; @@ -31,9 +31,11 @@ const useDBFileSecondaryPath = (workspaceId: string) => { return path; }; -export const StoragePanel: FC<{ +interface StoragePanelProps { workspace: AffineOfficialWorkspace; -}> = ({ workspace }) => { +} + +export const StoragePanel = ({ workspace }: StoragePanelProps) => { const workspaceId = workspace.id; const t = useAFFiNEI18N(); const secondaryPath = useDBFileSecondaryPath(workspaceId); diff --git a/apps/core/src/components/affine/onboarding-modal.tsx b/apps/core/src/components/affine/onboarding-modal.tsx index f8f2ede36..6bfabc114 100644 --- a/apps/core/src/components/affine/onboarding-modal.tsx +++ b/apps/core/src/components/affine/onboarding-modal.tsx @@ -1,12 +1,11 @@ import { TourModal } from '@affine/component/tour-modal'; import { useAtom } from 'jotai'; -import type { FC } from 'react'; import { memo, useCallback } from 'react'; import { openOnboardingModalAtom } from '../../atoms'; import { guideOnboardingAtom } from '../../atoms/guide'; -export const OnboardingModal: FC = memo(function OnboardingModal() { +export const OnboardingModal = memo(function OnboardingModal() { const [open, setOpen] = useAtom(openOnboardingModalAtom); const [guideOpen, setShowOnboarding] = useAtom(guideOnboardingAtom); const onCloseTourModal = useCallback(() => { diff --git a/apps/core/src/components/affine/setting-modal/general-setting/appearance/date-format-setting.tsx b/apps/core/src/components/affine/setting-modal/general-setting/appearance/date-format-setting.tsx index 51bd7e154..844061f81 100644 --- a/apps/core/src/components/affine/setting-modal/general-setting/appearance/date-format-setting.tsx +++ b/apps/core/src/components/affine/setting-modal/general-setting/appearance/date-format-setting.tsx @@ -1,6 +1,6 @@ import { Menu, MenuItem, MenuTrigger } from '@affine/component'; import dayjs from 'dayjs'; -import { type FC, useCallback } from 'react'; +import { useCallback } from 'react'; import { dateFormatOptions, @@ -8,10 +8,15 @@ import { useAppSetting, } from '../../../../../atoms/settings'; -const DateFormatMenuContent: FC<{ +interface DateFormatMenuContentProps { currentOption: DateFormats; onSelect: (option: DateFormats) => void; -}> = ({ onSelect, currentOption }) => { +} + +const DateFormatMenuContent = ({ + onSelect, + currentOption, +}: DateFormatMenuContentProps) => { return ( <> {dateFormatOptions.map(option => { @@ -30,6 +35,7 @@ const DateFormatMenuContent: FC<{ ); }; + export const DateFormatSetting = () => { const [appearanceSettings, setAppSettings] = useAppSetting(); const handleSelect = useCallback( @@ -38,6 +44,7 @@ export const DateFormatSetting = () => { }, [setAppSettings] ); + return ( >; + icon: (props: SVGProps) => ReactElement; testId: string; -}[]; +} + +export type GeneralSettingList = GeneralSettingListItem[]; export const useGeneralSettingList = (): GeneralSettingList => { const t = useAFFiNEI18N(); + return [ { key: 'appearance', @@ -55,11 +58,11 @@ export const useGeneralSettingList = (): GeneralSettingList => { ]; }; -export const GeneralSetting = ({ - generalKey, -}: { +interface GeneralSettingProps { generalKey: GeneralSettingKeys; -}) => { +} + +export const GeneralSetting = ({ generalKey }: GeneralSettingProps) => { switch (generalKey) { case 'shortcuts': return ; diff --git a/apps/core/src/components/affine/setting-modal/index.tsx b/apps/core/src/components/affine/setting-modal/index.tsx index 067eaebee..aa66535bf 100644 --- a/apps/core/src/components/affine/setting-modal/index.tsx +++ b/apps/core/src/components/affine/setting-modal/index.tsx @@ -1,10 +1,9 @@ import { SettingModal as SettingModalBase, - type SettingModalProps, + type SettingModalProps as SettingModalBaseProps, } from '@affine/component/setting-components'; import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { ContactWithUsIcon } from '@blocksuite/icons'; -import type React from 'react'; import { useCallback } from 'react'; import { AccountSetting } from './account-setting'; @@ -18,21 +17,25 @@ import { settingContent } from './style.css'; import { WorkspaceSetting } from './workspace-setting'; type ActiveTab = GeneralSettingKeys | 'workspace' | 'account'; -export type SettingProps = { + +export interface SettingProps { activeTab: ActiveTab; workspaceId: string | null; onSettingClick: (params: { activeTab: ActiveTab; workspaceId: string | null; }) => void; -}; -export const SettingModal: React.FC = ({ +} + +type SettingModalProps = SettingModalBaseProps & SettingProps; + +export const SettingModal = ({ open, setOpen, activeTab = 'appearance', workspaceId = null, onSettingClick, -}) => { +}: SettingModalProps) => { const t = useAFFiNEI18N(); const generalSettingList = useGeneralSettingList(); diff --git a/apps/core/src/components/affine/setting-modal/setting-sidebar/index.tsx b/apps/core/src/components/affine/setting-modal/setting-sidebar/index.tsx index 56c9cd624..3819b2101 100644 --- a/apps/core/src/components/affine/setting-modal/setting-sidebar/index.tsx +++ b/apps/core/src/components/affine/setting-modal/setting-sidebar/index.tsx @@ -11,7 +11,6 @@ import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite- import { useStaticBlockSuiteWorkspace } from '@toeverything/infra/__internal__/react'; import clsx from 'clsx'; import { useAtomValue } from 'jotai'; -import type { FC } from 'react'; import { Suspense } from 'react'; import { useCurrentWorkspace } from '../../../../hooks/current/use-current-workspace'; @@ -28,21 +27,24 @@ import { sidebarTitle, } from './style.css'; -export const SettingSidebar: FC<{ +interface SettingSidebarProps { generalSettingList: GeneralSettingList; onGeneralSettingClick: (key: GeneralSettingKeys) => void; onWorkspaceSettingClick: (workspaceId: string) => void; selectedWorkspaceId: string | null; selectedGeneralKey: string | null; onAccountSettingClick: () => void; -}> = ({ +} + +export const SettingSidebar = ({ generalSettingList, onGeneralSettingClick, onWorkspaceSettingClick, selectedWorkspaceId, selectedGeneralKey, -}) => { +}: SettingSidebarProps) => { const t = useAFFiNEI18N(); + return (
{t['Settings']()}
@@ -88,10 +90,15 @@ export const SettingSidebar: FC<{ ); }; -export const WorkspaceList: FC<{ +interface WorkspaceListProps { onWorkspaceSettingClick: (workspaceId: string) => void; selectedWorkspaceId: string | null; -}> = ({ onWorkspaceSettingClick, selectedWorkspaceId }) => { +} + +export const WorkspaceList = ({ + onWorkspaceSettingClick, + selectedWorkspaceId, +}: WorkspaceListProps) => { const workspaces = useAtomValue(rootWorkspacesMetadataAtom); const [currentWorkspace] = useCurrentWorkspace(); return ( @@ -114,19 +121,22 @@ export const WorkspaceList: FC<{ ); }; +interface WorkspaceListItemProps { + meta: RootWorkspaceMetadata; + onClick: () => void; + isCurrent: boolean; + isActive: boolean; +} + const WorkspaceListItem = ({ meta, onClick, isCurrent, isActive, -}: { - meta: RootWorkspaceMetadata; - onClick: () => void; - isCurrent: boolean; - isActive: boolean; -}) => { +}: WorkspaceListItemProps) => { const workspace = useStaticBlockSuiteWorkspace(meta.id); const [workspaceName] = useBlockSuiteWorkspaceName(workspace); + return (
void; } -export const TmpDisableAffineCloudModal: React.FC< - TmpDisableAffineCloudModalProps -> = ({ open, onClose }) => { +export const TmpDisableAffineCloudModal = ({ + open, + onClose, +}: TmpDisableAffineCloudModalProps) => { const t = useAFFiNEI18N(); + return ( void; onConform: () => void; -}; +} -export const TransformWorkspaceToAffineModal: React.FC< - TransformWorkspaceToAffineModalProps -> = ({ open, onClose, onConform }) => { +export const TransformWorkspaceToAffineModal = ({ + open, + onClose, + onConform, +}: TransformWorkspaceToAffineModalProps) => { const t = useAFFiNEI18N(); return ( diff --git a/apps/core/src/components/blocksuite/block-suite-page-list/index.tsx b/apps/core/src/components/blocksuite/block-suite-page-list/index.tsx index 7b1ec4b3c..bbfdfe253 100644 --- a/apps/core/src/components/blocksuite/block-suite-page-list/index.tsx +++ b/apps/core/src/components/blocksuite/block-suite-page-list/index.tsx @@ -11,7 +11,6 @@ import { useBlockSuitePageMeta } from '@toeverything/hooks/use-block-suite-page- import { useBlockSuitePagePreview } from '@toeverything/hooks/use-block-suite-page-preview'; import { useBlockSuiteWorkspacePage } from '@toeverything/hooks/use-block-suite-workspace-page'; import { useAtom, useAtomValue } from 'jotai'; -import type React from 'react'; import { Suspense, useCallback, useMemo } from 'react'; import { allPageModeSelectAtom } from '../../../atoms'; @@ -23,13 +22,13 @@ import { filterPage } from '../../../utils/filter'; import { emptyDescButton, emptyDescKbd, pageListEmptyStyle } from './index.css'; import { usePageHelper } from './utils'; -export type BlockSuitePageListProps = { +export interface BlockSuitePageListProps { blockSuiteWorkspace: BlockSuiteWorkspace; listType: 'all' | 'trash' | 'shared' | 'public'; - isPublic?: true; + isPublic?: boolean; onOpenPage: (pageId: string, newTab?: boolean) => void; collection?: Collection; -}; +} const filter = { all: (pageMeta: PageMeta) => !pageMeta.trash, @@ -41,13 +40,12 @@ const filter = { shared: (pageMeta: PageMeta) => pageMeta.isPublic && !pageMeta.trash, }; -const PagePreviewInner = ({ - workspace, - pageId, -}: { +interface PagePreviewInnerProps { workspace: Workspace; pageId: string; -}) => { +} + +const PagePreviewInner = ({ workspace, pageId }: PagePreviewInnerProps) => { const page = useBlockSuiteWorkspacePage(workspace, pageId); assertExists(page); const previewAtom = useBlockSuitePagePreview(page); @@ -55,13 +53,12 @@ const PagePreviewInner = ({ return preview; }; -const PagePreview = ({ - workspace, - pageId, -}: { +interface PagePreviewProps { workspace: Workspace; pageId: string; -}) => { +} + +const PagePreview = ({ workspace, pageId }: PagePreviewProps) => { return ( @@ -69,10 +66,12 @@ const PagePreview = ({ ); }; -const PageListEmpty = (props: { +interface PageListEmptyProps { createPage?: ReturnType['createPage']; listType: BlockSuitePageListProps['listType']; -}) => { +} + +const PageListEmpty = (props: PageListEmptyProps) => { const { listType, createPage } = props; const t = useAFFiNEI18N(); @@ -124,13 +123,13 @@ const PageListEmpty = (props: { ); }; -export const BlockSuitePageList: React.FC = ({ +export const BlockSuitePageList = ({ blockSuiteWorkspace, onOpenPage, listType, isPublic = false, collection, -}) => { +}: BlockSuitePageListProps) => { const pageMetas = useBlockSuitePageMeta(blockSuiteWorkspace); const { toggleFavorite, @@ -262,6 +261,7 @@ export const BlockSuitePageList: React.FC = ({ }, }; }); + return ( { +const LanguageMenuContent = () => { const i18n = useI18N(); const changeLanguage = useCallback( (event: string) => { @@ -16,6 +16,7 @@ const LanguageMenuContent: FC = () => { }, [i18n] ); + return ( <> {LOCALES.map(option => { @@ -34,7 +35,8 @@ const LanguageMenuContent: FC = () => { ); }; -export const LanguageMenu: React.FC = () => { + +export const LanguageMenu = () => { const i18n = useI18N(); const currentLanguage = LOCALES.find(item => item.tag === i18n.language); @@ -87,6 +89,7 @@ const StyledContainer = styled('div')(() => { padding: '0 14px', }; }); + const StyledIconContainer = styled('div')(() => { return { width: '20px', @@ -96,6 +99,7 @@ const StyledIconContainer = styled('div')(() => { ...displayFlex('flex-start', 'center'), }; }); + const StyledButtonContainer = styled('div')(() => { return { width: '100%', @@ -107,6 +111,7 @@ const StyledButtonContainer = styled('div')(() => { marginLeft: '12px', }; }); + const StyledButton = styled(Button)(() => { return { width: '100%', @@ -118,6 +123,7 @@ const StyledButton = styled(Button)(() => { padding: '0', }; }); + const StyledArrowDownContainer = styled('div')(() => { return { height: '32px', @@ -128,6 +134,7 @@ const StyledArrowDownContainer = styled('div')(() => { fontSize: '24px', }; }); + const StyledCurrentLanguage = styled('div')(() => { return { marginLeft: '12px', diff --git a/apps/core/src/components/blocksuite/workspace-header/header.tsx b/apps/core/src/components/blocksuite/workspace-header/header.tsx index ae30fa521..39cdfcd01 100644 --- a/apps/core/src/components/blocksuite/workspace-header/header.tsx +++ b/apps/core/src/components/blocksuite/workspace-header/header.tsx @@ -13,7 +13,7 @@ import { } from '@toeverything/infra/__internal__/plugin'; import clsx from 'clsx'; import { useAtom, useAtomValue } from 'jotai'; -import type { FC, HTMLAttributes, PropsWithChildren, ReactNode } from 'react'; +import type { HTMLAttributes, ReactElement, ReactNode } from 'react'; import { forwardRef, startTransition, @@ -32,21 +32,21 @@ import { EditorOptionMenu } from './header-right-items/editor-option-menu'; import * as styles from './styles.css'; import { OSWarningMessage, shouldShowWarning } from './utils'; -export type BaseHeaderProps< +export interface BaseHeaderProps< Workspace extends AffineOfficialWorkspace = AffineOfficialWorkspace, -> = { +> { workspace: Workspace; currentPage: Page | null; isPublic: boolean; leftSlot?: ReactNode; -}; +} export enum HeaderRightItemName { EditorOptionMenu = 'editorOptionMenu', } -type HeaderItem = { - Component: FC; +interface HeaderItem { + Component: (props: BaseHeaderProps) => ReactElement; // todo: public workspace should be one of the flavour availableWhen: ( workspace: AffineOfficialWorkspace, @@ -55,7 +55,7 @@ type HeaderItem = { isPublic: boolean; } ) => boolean; -}; +} const HeaderRightItems: Record = { [HeaderRightItemName.EditorOptionMenu]: { @@ -68,7 +68,6 @@ const HeaderRightItems: Record = { }, }; -export type HeaderProps = BaseHeaderProps; const WindowsAppControls = () => { const handleMinimizeApp = useCallback(() => { window.apis?.ui.handleMinimizeApp().catch(err => { @@ -85,6 +84,7 @@ const WindowsAppControls = () => { console.error(err); }); }, []); + return (
{ const PluginHeader = () => { const headerItem = useAtomValue(pluginHeaderItemAtom); const pluginsRef = useRef([]); + return (
{ ); }; -export const Header = forwardRef< - HTMLDivElement, - PropsWithChildren & HTMLAttributes ->((props, ref) => { +export interface HeaderProps + extends BaseHeaderProps, + HTMLAttributes { + children?: ReactNode; +} + +export const Header = forwardRef((props, ref) => { const [showWarning, setShowWarning] = useState(false); const [showDownloadTip, setShowDownloadTip] = useAtom( guideDownloadClientTipAtom @@ -167,6 +171,7 @@ export const Header = forwardRef< const mode = useAtomValue(currentModeAtom); const isWindowsDesktop = globalThis.platform === 'win32' && isDesktop; + return (
{ + children?: ReactNode; +} -export const BlockSuiteEditorHeader: FC< - PropsWithChildren & HTMLAttributes -> = (props): ReactElement => { +export const BlockSuiteEditorHeader = ( + props: WorkspaceHeaderProps +): ReactElement => { const { workspace, currentPage, children, isPublic } = props; // fixme(himself65): remove this atom and move it to props const setOpenQuickSearch = useSetAtom(openQuickSearchModalAtom); @@ -50,6 +49,7 @@ export const BlockSuiteEditorHeader: FC< const headerRef = useRef(null); assertExists(pageMeta); const title = pageMeta?.title; + return (
{children} diff --git a/apps/core/src/components/blocksuite/workspace-header/utils.tsx b/apps/core/src/components/blocksuite/workspace-header/utils.tsx index a52a67446..e3a704d70 100644 --- a/apps/core/src/components/blocksuite/workspace-header/utils.tsx +++ b/apps/core/src/components/blocksuite/workspace-header/utils.tsx @@ -1,7 +1,6 @@ import { isDesktop } from '@affine/env/constant'; import { Trans } from '@affine/i18n'; import { useAFFiNEI18N } from '@affine/i18n/hooks'; -import type React from 'react'; import { useEffect, useState } from 'react'; const minimumChromeVersion = 102; @@ -23,7 +22,7 @@ export const shouldShowWarning = () => { } }; -export const OSWarningMessage: React.FC = () => { +export const OSWarningMessage = () => { const t = useAFFiNEI18N(); const [notChrome, setNotChrome] = useState(false); const [notGoodVersion, setNotGoodVersion] = useState(false); diff --git a/apps/core/src/components/page-detail-editor.tsx b/apps/core/src/components/page-detail-editor.tsx index 3b8083d6b..62dcf0f6d 100644 --- a/apps/core/src/components/page-detail-editor.tsx +++ b/apps/core/src/components/page-detail-editor.tsx @@ -16,7 +16,7 @@ import { import { contentLayoutAtom, rootStore } from '@toeverything/infra/atom'; import clsx from 'clsx'; import { useAtomValue, useSetAtom } from 'jotai'; -import type { CSSProperties, FC, ReactElement } from 'react'; +import type { CSSProperties, ReactElement } from 'react'; import { memo, Suspense, useCallback, useMemo } from 'react'; import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels'; @@ -27,13 +27,13 @@ import { TrashButtonGroup } from './blocksuite/workspace-header/header-right-ite import * as styles from './page-detail-editor.css'; import { pluginContainer } from './page-detail-editor.css'; -export type PageDetailEditorProps = { +export interface PageDetailEditorProps { isPublic?: boolean; workspace: Workspace; pageId: string; onInit: (page: Page, editor: Readonly) => void; onLoad?: (page: Page, editor: EditorContainer) => () => void; -}; +} const EditorWrapper = memo(function EditorWrapper({ workspace, @@ -128,35 +128,39 @@ const EditorWrapper = memo(function EditorWrapper({ ); }); -const PluginContentAdapter = memo<{ +interface PluginContentAdapterProps { windowItem: (div: HTMLDivElement) => () => void; pluginName: string; -}>(function PluginContentAdapter({ windowItem, pluginName }) { - return ( -
{ - if (ref) { - const div = document.createElement('div'); - const cleanup = windowItem(div); - ref.appendChild(div); - addCleanup(pluginName, () => { - cleanup(); - ref.removeChild(div); - }); - } - }, - [pluginName, windowItem] - )} - /> - ); -}); +} -type LayoutPanelProps = { +const PluginContentAdapter = memo( + function PluginContentAdapter({ windowItem, pluginName }) { + return ( +
{ + if (ref) { + const div = document.createElement('div'); + const cleanup = windowItem(div); + ref.appendChild(div); + addCleanup(pluginName, () => { + cleanup(); + ref.removeChild(div); + }); + } + }, + [pluginName, windowItem] + )} + /> + ); + } +); + +interface LayoutPanelProps { node: LayoutNode; editorProps: PageDetailEditorProps; -}; +} const LayoutPanel = memo(function LayoutPanel( props: LayoutPanelProps @@ -199,7 +203,7 @@ const LayoutPanel = memo(function LayoutPanel( } }); -export const PageDetailEditor: FC = props => { +export const PageDetailEditor = (props: PageDetailEditorProps) => { const { workspace, pageId } = props; const page = useBlockSuiteWorkspacePage(workspace, pageId); if (!page) { diff --git a/apps/core/src/components/pure/file-upload/index.tsx b/apps/core/src/components/pure/file-upload/index.tsx index 525b21d6d..87d9f6081 100644 --- a/apps/core/src/components/pure/file-upload/index.tsx +++ b/apps/core/src/components/pure/file-upload/index.tsx @@ -1,22 +1,21 @@ import { styled } from '@affine/component'; import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { Button } from '@toeverything/components/button'; -import type { ChangeEvent } from 'react'; -import type React from 'react'; +import type { ChangeEvent, PropsWithChildren } from 'react'; import { useRef } from 'react'; -export type UploadProps = React.PropsWithChildren<{ +export interface UploadProps { uploadType?: string; accept?: string; fileChange: (file: File) => void; -}>; +} -export const Upload: React.FC = ({ +export const Upload = ({ fileChange, accept, children, ...props -}) => { +}: PropsWithChildren) => { const t = useAFFiNEI18N(); const input_ref = useRef(null); const _chooseFile = () => { @@ -35,6 +34,7 @@ export const Upload: React.FC = ({ input_ref.current.value = ''; } }; + return ( {children ?? } diff --git a/apps/core/src/components/pure/footer/index.tsx b/apps/core/src/components/pure/footer/index.tsx index 843271af0..b1a104efc 100644 --- a/apps/core/src/components/pure/footer/index.tsx +++ b/apps/core/src/components/pure/footer/index.tsx @@ -1,15 +1,16 @@ import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { CloudWorkspaceIcon } from '@blocksuite/icons'; import { useSetAtom } from 'jotai'; -import { type CSSProperties, type FC, forwardRef } from 'react'; +import { type CSSProperties, forwardRef } from 'react'; import { openDisableCloudAlertModalAtom } from '../../../atoms'; import { stringToColour } from '../../../utils'; import { StyledFooter, StyledSignInButton } from './styles'; -export const Footer: FC = () => { +export const Footer = () => { const t = useAFFiNEI18N(); const setOpen = useSetAtom(openDisableCloudAlertModalAtom); + return ( >; - subPath: WorkspaceSubPath; - } - | { - title: string; - icon: FC>; - onClick: () => void; - }; +type IconComponent = (props: SVGProps) => ReactElement; + +interface ConfigItem { + title: string; + icon: IconComponent; + onClick: () => void; +} + +interface ConfigPathItem { + title: string; + icon: IconComponent; + subPath: WorkspaceSubPath; +} + +export type Config = ConfigItem | ConfigPathItem; export const useSwitchToConfig = (workspaceId: string): Config[] => { const t = useAFFiNEI18N(); const [, setOpenSettingModalAtom] = useAtom(openSettingModalAtom); + return useMemo( () => [ { diff --git a/apps/core/src/components/pure/quick-search-modal/footer.tsx b/apps/core/src/components/pure/quick-search-modal/footer.tsx index ef446d2ee..99e1e73dc 100644 --- a/apps/core/src/components/pure/quick-search-modal/footer.tsx +++ b/apps/core/src/components/pure/quick-search-modal/footer.tsx @@ -6,24 +6,23 @@ import { PlusIcon } from '@blocksuite/icons'; import { nanoid } from '@blocksuite/store'; import { useBlockSuiteWorkspaceHelper } from '@toeverything/hooks/use-block-suite-workspace-helper'; import { Command } from 'cmdk'; -import type React from 'react'; import { useCallback } from 'react'; import { useNavigateHelper } from '../../../hooks/use-navigate-helper'; import type { BlockSuiteWorkspace } from '../../../shared'; import { StyledModalFooterContent } from './style'; -export type FooterProps = { +export interface FooterProps { query: string; onClose: () => void; blockSuiteWorkspace: BlockSuiteWorkspace; -}; +} -export const Footer: React.FC = ({ +export const Footer = ({ query, onClose, blockSuiteWorkspace, -}) => { +}: FooterProps) => { const { createPage } = useBlockSuiteWorkspaceHelper(blockSuiteWorkspace); const t = useAFFiNEI18N(); const { jumpToPage } = useNavigateHelper(); @@ -32,6 +31,7 @@ export const Footer: React.FC = ({ query.length > MAX_QUERY_SHOW_LENGTH ? query.slice(0, MAX_QUERY_SHOW_LENGTH) + '...' : query; + return ( void; -}; +} -export const QuickSearchModal: React.FC = ({ +export const QuickSearchModal = ({ open, setOpen, workspace, -}) => { +}: QuickSearchModalProps) => { const blockSuiteWorkspace = workspace?.blockSuiteWorkspace; const t = useAFFiNEI18N(); const inputRef = useRef(null); @@ -40,6 +40,7 @@ export const QuickSearchModal: React.FC = ({ const handleClose = useCallback(() => { setOpen(false); }, [setOpen]); + // Add ‘⌘+K’ shortcut keys as switches useEffect(() => { const keydown = (e: KeyboardEvent) => { @@ -59,6 +60,7 @@ export const QuickSearchModal: React.FC = ({ return () => document.removeEventListener('keydown', keydown, { capture: true }); }, [open, setOpen, setQuery]); + useEffect(() => { if (open) { // Waiting for DOM rendering @@ -68,6 +70,7 @@ export const QuickSearchModal: React.FC = ({ }); } }, [open]); + return ( void; setShowCreatePage: Dispatch>; -}; -export const Results: FC = ({ +} +export const Results = ({ query, workspace, setShowCreatePage, onClose, -}) => { +}: ResultsProps) => { const blockSuiteWorkspace = workspace.blockSuiteWorkspace; useBlockSuiteWorkspaceHelper(blockSuiteWorkspace); const pageList = useBlockSuitePageMeta(blockSuiteWorkspace); @@ -52,7 +52,9 @@ export const Results: FC = ({ return page.trash !== true; } }); + setShowCreatePage(resultsPageMeta.length === 0); + if (!query) { return ( <> diff --git a/apps/core/src/components/pure/workspace-slider-bar/WorkspaceSelector/workspace-selector.tsx b/apps/core/src/components/pure/workspace-slider-bar/WorkspaceSelector/workspace-selector.tsx index 9be7c01da..43f4f55e5 100644 --- a/apps/core/src/components/pure/workspace-slider-bar/WorkspaceSelector/workspace-selector.tsx +++ b/apps/core/src/components/pure/workspace-slider-bar/WorkspaceSelector/workspace-selector.tsx @@ -14,19 +14,19 @@ import { StyledWorkspaceStatus, } from './styles'; -export type WorkspaceSelectorProps = { +export interface WorkspaceSelectorProps { currentWorkspace: AllWorkspace; onClick: () => void; -}; +} /** * @todo-Doma Co-locate WorkspaceListModal with {@link WorkspaceSelector}, * because it's never used elsewhere. */ -export const WorkspaceSelector: React.FC = ({ +export const WorkspaceSelector = ({ currentWorkspace, onClick, -}) => { +}: WorkspaceSelectorProps) => { const [name] = useBlockSuiteWorkspaceName( currentWorkspace?.blockSuiteWorkspace ); diff --git a/apps/core/src/components/pure/workspace-title/index.tsx b/apps/core/src/components/pure/workspace-title/index.tsx index 7b2346fe1..6c1a9eca0 100644 --- a/apps/core/src/components/pure/workspace-title/index.tsx +++ b/apps/core/src/components/pure/workspace-title/index.tsx @@ -14,17 +14,16 @@ import { Header } from '../../blocksuite/workspace-header/header'; import * as styles from '../../blocksuite/workspace-header/styles.css'; import { QuickSearchButton } from '../quick-search-button'; -export type WorkspaceTitleProps = React.PropsWithChildren< - HeaderProps & { - icon?: ReactNode; - } ->; +export interface WorkspaceTitleProps + extends React.PropsWithChildren { + icon?: ReactNode; +} -export const WorkspaceTitle: React.FC = ({ +export const WorkspaceTitle = ({ icon, children, ...props -}) => { +}: WorkspaceTitleProps) => { const setOpenQuickSearch = useSetAtom(openQuickSearchModalAtom); return (
@@ -50,6 +49,7 @@ export const WorkspaceModeFilterTab = ({ ...props }: WorkspaceTitleProps) => { } setMode(value); }; + return (
diff --git a/apps/core/src/layouts/workspace-layout.tsx b/apps/core/src/layouts/workspace-layout.tsx index 77aba356e..dbffa03e4 100644 --- a/apps/core/src/layouts/workspace-layout.tsx +++ b/apps/core/src/layouts/workspace-layout.tsx @@ -29,7 +29,7 @@ import { import { usePassiveWorkspaceEffect } from '@toeverything/infra/__internal__/react'; import { currentWorkspaceIdAtom } from '@toeverything/infra/atom'; import { useAtom, useAtomValue, useSetAtom } from 'jotai'; -import type { FC, PropsWithChildren, ReactElement } from 'react'; +import type { PropsWithChildren, ReactElement } from 'react'; import { lazy, Suspense, useCallback, useMemo } from 'react'; import { useLocation, useParams } from 'react-router-dom'; @@ -69,15 +69,17 @@ function DefaultProvider({ children }: PropsWithChildren) { return <>{children}; } -export const QuickSearch: FC = () => { +export const QuickSearch = () => { const [currentWorkspace] = useCurrentWorkspace(); const [openQuickSearchModal, setOpenQuickSearchModalAtom] = useAtom( openQuickSearchModalAtom ); const blockSuiteWorkspace = currentWorkspace?.blockSuiteWorkspace; + if (!blockSuiteWorkspace) { return null; } + return ( {children}; }; -export const WorkspaceLayout: FC = - function WorkspacesSuspense({ children }) { - const currentWorkspaceId = useAtomValue(currentWorkspaceIdAtom); - const jotaiWorkspaces = useAtomValue(rootWorkspacesMetadataAtom); - const meta = useMemo( - () => jotaiWorkspaces.find(x => x.id === currentWorkspaceId), - [currentWorkspaceId, jotaiWorkspaces] - ); +export const WorkspaceLayout = function WorkspacesSuspense({ + children, +}: PropsWithChildren) { + const currentWorkspaceId = useAtomValue(currentWorkspaceIdAtom); + const jotaiWorkspaces = useAtomValue(rootWorkspacesMetadataAtom); + const meta = useMemo( + () => jotaiWorkspaces.find(x => x.id === currentWorkspaceId), + [currentWorkspaceId, jotaiWorkspaces] + ); - const Provider = - (meta && WorkspaceAdapters[meta.flavour].UI.Provider) ?? DefaultProvider; - return ( - <> - {/* load all workspaces is costly, do not block the whole UI */} - - - - {/* fixme(himself65): don't re-render whole modals */} - - - + const Provider = + (meta && WorkspaceAdapters[meta.flavour].UI.Provider) ?? DefaultProvider; + + return ( + <> + {/* load all workspaces is costly, do not block the whole UI */} + + - }> - - {children} - - + {/* fixme(himself65): don't re-render whole modals */} + - - ); - }; + + + }> + + {children} + + + + + ); +}; -export const WorkspaceLayoutInner: FC = ({ children }) => { +export const WorkspaceLayoutInner = ({ children }: PropsWithChildren) => { const [currentWorkspace] = useCurrentWorkspace(); const { openPage } = useNavigateHelper(); diff --git a/apps/core/src/providers/modal-provider.tsx b/apps/core/src/providers/modal-provider.tsx index 1e8d812c7..5a527ab92 100644 --- a/apps/core/src/providers/modal-provider.tsx +++ b/apps/core/src/providers/modal-provider.tsx @@ -7,7 +7,7 @@ import { currentWorkspaceIdAtom, } from '@toeverything/infra/atom'; import { useAtom, useAtomValue, useSetAtom } from 'jotai'; -import type { FC, ReactElement } from 'react'; +import type { ReactElement } from 'react'; import { lazy, Suspense, useCallback, useTransition } from 'react'; import type { SettingAtom } from '../atoms'; @@ -52,7 +52,7 @@ const OnboardingModal = lazy(() => })) ); -export const Setting: FC = () => { +export const Setting = () => { const [currentWorkspace] = useCurrentWorkspace(); const [{ open, workspaceId, activeTab }, setOpenSettingModalAtom] = useAtom(openSettingModalAtom); @@ -89,6 +89,7 @@ export function CurrentWorkspaceModals() { const [openDisableCloudAlertModal, setOpenDisableCloudAlertModal] = useAtom( openDisableCloudAlertModalAtom ); + return ( <> @@ -139,6 +140,7 @@ export const AllWorkspaceModals = (): ReactElement => { }, [setOpenSettingModalAtom, setOpenWorkspacesModal] ); + return ( <>