Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: lift some providers #11802

Merged
merged 1 commit into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/mask/content-script/site-adaptor-infra/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ export async function activateSiteAdaptorUIInner(ui_deferred: SiteAdaptorUI.Defe
sampleRate: 0.01,
})
})
setupReactShadowRootEnvironment()
const ui = (activatedSiteAdaptorUI = await loadSiteAdaptorUI(ui_deferred.networkIdentifier))
setupReactShadowRootEnvironment()

sharedUINetworkIdentifier.value = ui_deferred.networkIdentifier
if (ui.customization.sharedComponentOverwrite) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { cloneElement, Suspense } from 'react'
import { QueryClientProvider } from '@tanstack/react-query'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
import { RootWeb3ContextProvider } from '@masknet/web3-hooks-base'
import { DialogStackingProvider, MaskThemeProvider } from '@masknet/theme'
import { i18NextInstance, jsxCompose } from '@masknet/shared-base'
import { queryClient } from '@masknet/shared-base-ui'
import { createPortal } from 'react-dom'
import { i18n } from '@lingui/core'
import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client'
import { queryPersistOptions } from '../../../shared-ui/utils/persistOptions.js'
import { I18NextProviderHMR, LinguiProviderHMR, SharedContextProvider } from '@masknet/shared'
import { useSiteThemeMode } from '@masknet/plugin-infra/content-script'
import { useMaskSiteAdaptorMixedTheme } from '../../components/useMaskSiteAdaptorMixedTheme.js'

export function ContentScriptGlobalProvider(children: React.ReactNode) {
return jsxCompose(
<Suspense />,
<DialogStackingProvider hasGlobalBackdrop={false} />,
<QueryClientProvider client={queryClient} />,
<PersistQueryClientProvider client={queryClient} persistOptions={queryPersistOptions} />,
<RootWeb3ContextProvider />,
<SharedContextProvider />,
<LinguiProviderHMR i18n={i18n} />,
<I18NextProviderHMR i18n={i18NextInstance} />,
<MaskThemeProvider useMaskIconPalette={useSiteThemeMode} useTheme={useMaskSiteAdaptorMixedTheme} />,
)(
cloneElement,
process.env.NODE_ENV === 'development' ?
<>
{/* https://github.com/TanStack/query/issues/5417 */}
{createPortal(<ReactQueryDevtools buttonPosition="bottom-right" />, document.body)}
{children}
</>
: children,
)
}
Original file line number Diff line number Diff line change
@@ -1,28 +1,21 @@
import { Suspense } from 'react'
import { useSiteThemeMode } from '@masknet/plugin-infra/content-script'
import { SharedContextProvider } from '@masknet/shared'
import { CSSVariableInjector, MaskThemeProvider } from '@masknet/theme'
import { ErrorBoundary, queryClient } from '@masknet/shared-base-ui'
import { Sniffings, compose } from '@masknet/shared-base'
import { useMaskSiteAdaptorMixedTheme } from '../../components/useMaskSiteAdaptorMixedTheme.js'
import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client'
import { queryPersistOptions } from '../../../shared-ui/index.js'
import { cloneElement, Suspense } from 'react'
import { CSSVariableInjector, CustomSnackbarProvider } from '@masknet/theme'
import { ErrorBoundary } from '@masknet/shared-base-ui'
import { Sniffings, jsxCompose } from '@masknet/shared-base'

// Providers added here will be added to ALL ShadowRoots, if you're mean to add a global one, add it in ./SiteUIProvider.tsx
export function ShadowRootAttachPointRoot(children: React.ReactNode) {
return compose(
(children) => <Suspense children={children} />,
(children) => <ErrorBoundary children={children} />,
(children) =>
MaskThemeProvider({
useMaskIconPalette: useSiteThemeMode,
useTheme: useMaskSiteAdaptorMixedTheme,
CustomSnackbarOffsetY: Sniffings.is_facebook_page ? 80 : undefined,
children,
}),
(children) => (
<PersistQueryClientProvider client={queryClient} persistOptions={queryPersistOptions} children={children} />
),
(children) => SharedContextProvider({ children }),
return jsxCompose(
<Suspense />,
<ErrorBoundary />,
<CustomSnackbarProvider
disableWindowBlurListener={false}
anchorOrigin={{ vertical: 'top', horizontal: 'right' }}
children={null!}
offsetY={Sniffings.is_facebook_page ? 80 : undefined}
/>,
)(
cloneElement,
<>
<CSSVariableInjector />
{children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
usePortalShadowRoot,
} from '@masknet/theme'
import { Flags } from '@masknet/flags'
import { SiteUIProvider } from '@masknet/shared'
import { ContentScriptGlobalProvider } from './ContentScriptGlobalProvider.js'
import { ShadowRootAttachPointRoot } from './ShadowRootAttachPointRoot.js'

const captureEvents: Array<keyof HTMLElementEventMap> = [
Expand All @@ -23,7 +23,11 @@ const captureEvents: Array<keyof HTMLElementEventMap> = [
'change',
]
export function setupReactShadowRootEnvironment() {
const shadow = setupReactShadowRootEnvironmentUpper(Flags.shadowRootInit, captureEvents, SiteUIProvider)
const shadow = setupReactShadowRootEnvironmentUpper(
Flags.shadowRootInit,
captureEvents,
ContentScriptGlobalProvider,
)
// Inject variable for Portals
attachReactTreeWithContainer(shadow, { key: 'css-vars' }).render(<CSSVariableInjector />)
}
Expand Down
30 changes: 16 additions & 14 deletions packages/mask/dashboard/Dashboard.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect } from 'react'
import { cloneElement, useEffect } from 'react'
import { CssBaseline, ThemeProvider, StyledEngineProvider, GlobalStyles } from '@mui/material'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
import {
Expand All @@ -12,7 +12,7 @@ import {
import { I18NextProviderHMR, LinguiProviderHMR, PersonaContext, SharedContextProvider, Modals } from '@masknet/shared'
import { ErrorBoundary } from '@masknet/shared-base-ui'
import { RootWeb3ContextProvider } from '@masknet/web3-hooks-base'
import { DashboardRoutes, i18NextInstance, compose } from '@masknet/shared-base'
import { DashboardRoutes, i18NextInstance, jsxCompose } from '@masknet/shared-base'

import { Pages } from './pages/routes.js'
import { UserContext, useAppearance } from '../shared-ui/index.js'
Expand Down Expand Up @@ -52,18 +52,20 @@ export default function Dashboard() {
}, [appearance])
// #endregion

return compose(
(children) => <RootWeb3ContextProvider enforceEVM children={children} />,
(children) => <I18NextProviderHMR i18n={i18NextInstance} children={children} />,
(children) => <LinguiProviderHMR i18n={i18n} children={children} />,
(children) => <StyledEngineProvider injectFirst children={children} />,
(children) => <ThemeProvider theme={theme} children={children} />,
(children) => <DialogStackingProvider children={children} />,
(children) => <UserContext.Provider children={children} />,
(children) => <PersonaContext.Provider initialState={PersonaContextIO} children={children} />,
(children) => <ErrorBoundary children={children} />,
(children) => <CustomSnackbarProvider children={children} />,
(children) => <SharedContextProvider children={children} />,
return jsxCompose(
<RootWeb3ContextProvider enforceEVM />,
<I18NextProviderHMR i18n={i18NextInstance} />,
<LinguiProviderHMR i18n={i18n} />,
<StyledEngineProvider injectFirst />,
<ThemeProvider theme={theme} />,
<DialogStackingProvider />,
<UserContext.Provider />,
<PersonaContext.Provider initialState={PersonaContextIO} />,
<ErrorBoundary />,
<CustomSnackbarProvider children={null!} />,
<SharedContextProvider />,
)(
cloneElement,
<>
<CssBaseline />
{GlobalCss}
Expand Down
36 changes: 14 additions & 22 deletions packages/mask/popups/Popup.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { PageUIProvider, PersonaContext } from '@masknet/shared'
import { MaskMessages, PopupRoutes } from '@masknet/shared-base'
import { jsxCompose, MaskMessages, PopupRoutes } from '@masknet/shared-base'
import { PopupSnackbarProvider } from '@masknet/theme'
import { EVMWeb3ContextProvider } from '@masknet/web3-hooks-base'
import { ProviderType } from '@masknet/web3-shared-evm'
import { Box } from '@mui/material'
import { Suspense, lazy, memo, useEffect, useMemo, useState, type ReactNode } from 'react'
import { Suspense, cloneElement, lazy, memo, useEffect, useMemo, useState, type ReactNode } from 'react'
import { useIdleTimer } from 'react-idle-timer'
import {
createHashRouter,
Expand Down Expand Up @@ -106,30 +106,22 @@ export default function Popups() {
throttle: 10000,
})

return (
<PersistQueryClientProvider client={queryClient} persistOptions={queryPersistOptions}>
return jsxCompose(
<PersistQueryClientProvider client={queryClient} persistOptions={queryPersistOptions} />,
<PageUIProvider useTheme={usePopupTheme} />,
<PopupSnackbarProvider children={null!} />,
<EVMWeb3ContextProvider providerType={ProviderType.MaskWallet} />,
<PopupContext />,
<PageTitleContext value={titleContext} />,
)(
cloneElement,
<>
{/* https://github.com/TanStack/query/issues/5417 */}
{process.env.NODE_ENV === 'development' ?
<ReactQueryDevtools buttonPosition="bottom-right" />
: null}
{PageUIProvider(
usePopupTheme,
<PopupSnackbarProvider>
<EVMWeb3ContextProvider providerType={ProviderType.MaskWallet}>
<PopupContext>
<PageTitleContext value={titleContext}>
<RouterProvider
router={router}
fallbackElement={pending}
future={{ v7_startTransition: true }}
/>
</PageTitleContext>
</PopupContext>
</EVMWeb3ContextProvider>
</PopupSnackbarProvider>,
null,
)}
</PersistQueryClientProvider>
<RouterProvider router={router} fallbackElement={pending} future={{ v7_startTransition: true }} />
</>,
)
}

Expand Down
7 changes: 6 additions & 1 deletion packages/shared-base/src/helpers/compose.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
export function compose<T>(...args: [...composer: Array<((arg: T) => T) | null | false>, init: T]) {
function compose<T>(...args: [...composer: Array<((arg: T) => T) | null | false>, init: T]) {
if (args.length === 0) throw new TypeError()
const last = args.pop() as T

return (args as Array<((arg: T) => T) | null>).filter(Boolean).reduceRight((prev, fn) => fn!(prev), last)
}

export function jsxCompose<JSX>(...jsx: JSX[]) {
return <ReactNode>(cloneElement: (jsx: JSX, props: any, children: ReactNode) => ReactNode, element: ReactNode) =>
compose(...jsx.map((jsx) => (children: ReactNode) => cloneElement(jsx, undefined, children)), element)
}
64 changes: 31 additions & 33 deletions packages/shared/src/UI/contexts/PageUIProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,42 @@
import { Suspense } from 'react'
import React, { cloneElement, Suspense } from 'react'
import { StyledEngineProvider, type Theme } from '@mui/material'
import { RootWeb3ContextProvider } from '@masknet/web3-hooks-base'
import { CSSVariableInjector, DialogStackingProvider, MaskThemeProvider } from '@masknet/theme'
import { CSSVariableInjector, CustomSnackbarProvider, DialogStackingProvider, MaskThemeProvider } from '@masknet/theme'
import { I18NextProviderHMR, LinguiProviderHMR, SharedContextProvider } from '@masknet/shared'
import { compose, i18NextInstance } from '@masknet/shared-base'
import { jsxCompose, i18NextInstance } from '@masknet/shared-base'
import { ErrorBoundary } from '@masknet/shared-base-ui'
import { i18n } from '@lingui/core'

export function PageUIProvider(useTheme: () => Theme, children: React.ReactNode, fallback?: React.ReactNode) {
return compose(
// Avoid the crash due to unhandled suspense
(children) => <Suspense children={children} />,
// Provide the minimal environment (i18n context) for CrashUI in page mode
(children) => <I18NextProviderHMR i18n={i18NextInstance} children={children} />,
(children) => <LinguiProviderHMR i18n={i18n} children={children} />,
(children) => StyledEngineProvider({ injectFirst: true, children }),
(children) => <ErrorBoundary children={children} />,
(children) => <MaskUIRoot useTheme={useTheme} fallback={fallback} children={children} />,
<>{children}</>,
)
}

interface MaskUIRootProps extends React.PropsWithChildren {
useTheme(): Theme
export interface PageUIProviderProps {
useTheme: () => Theme
children?: React.ReactNode
fallback?: React.ReactNode
}
export function PageUIProvider({ children, useTheme, fallback }: PageUIProviderProps) {
return jsxCompose(
// Avoid the crash due to unhandled suspense
<Suspense />,
// Provide the minimal environment (i18n context) for CrashUI in page mode
<I18NextProviderHMR i18n={i18NextInstance} />,
<LinguiProviderHMR i18n={i18n} />,
<StyledEngineProvider injectFirst />,
<ErrorBoundary />,

function MaskUIRoot({ children, useTheme, fallback }: MaskUIRootProps) {
return (
<DialogStackingProvider hasGlobalBackdrop={false}>
<MaskThemeProvider useMaskIconPalette={(theme) => theme.palette.mode} useTheme={useTheme}>
<RootWeb3ContextProvider>
<SharedContextProvider>
<Suspense fallback={fallback}>
<CSSVariableInjector />
{children}
</Suspense>
</SharedContextProvider>
</RootWeb3ContextProvider>
</MaskThemeProvider>
</DialogStackingProvider>
<Suspense fallback={fallback} />,
<DialogStackingProvider hasGlobalBackdrop={false} />,
<MaskThemeProvider useMaskIconPalette={(theme) => theme.palette.mode} useTheme={useTheme} />,
<RootWeb3ContextProvider />,
<SharedContextProvider />,
<CustomSnackbarProvider
children={null!}
disableWindowBlurListener={false}
anchorOrigin={{ vertical: 'top', horizontal: 'right' }}
/>,
)(
cloneElement,
<>
<CSSVariableInjector />
{children}
</>,
)
}
37 changes: 0 additions & 37 deletions packages/shared/src/UI/contexts/SiteUIProvider.tsx

This file was deleted.

1 change: 0 additions & 1 deletion packages/shared/src/UI/contexts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,3 @@ export * from './base/index.js'
export * from './components/index.js'
export * from './SharedContextProvider.js'
export * from './PageUIProvider.js'
export * from './SiteUIProvider.js'
2 changes: 1 addition & 1 deletion packages/theme/src/ShadowRoot/ShadowRootSetup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ let globalContainer: HTMLElement
* This container is prepared for all the Modals.
*/
let portalContainer: ShadowRoot
export type WrapJSX = ((jsx: React.ReactNode) => JSX.Element) | undefined
export type WrapJSX = ((jsx: React.ReactNode) => React.ReactNode) | undefined
/** @internal */
export const shadowEnvironmentMountingRoots = new ObservableMap<any, JSX.Element>()

Expand Down
Loading
Loading