addons/isl/src/AppWrapper.tsxblame
View source
b69ab311/**
b69ab312 * Copyright (c) Meta Platforms, Inc. and affiliates.
b69ab313 *
b69ab314 * This source code is licensed under the MIT license found in the
b69ab315 * LICENSE file in the root directory of this source tree.
b69ab316 */
b69ab317
b69ab318import type {ReactNode} from 'react';
b69ab319
b69ab3110import {ErrorBoundary} from 'isl-components/ErrorNotice';
b69ab3111import {ThemedComponentsRoot} from 'isl-components/ThemedComponentsRoot';
b69ab3112import {ViewportOverlayRoot} from 'isl-components/ViewportOverlay';
b69ab3113import {Provider, useAtomValue, useStore} from 'jotai';
b69ab3114import React from 'react';
b69ab3115import {ContextMenus} from 'shared/ContextMenu';
b69ab3116import {ISLCommandContext} from './ISLShortcuts';
b69ab3117import {SuspenseBoundary} from './SuspenseBoundary';
b69ab3118import {TopLevelToast} from './TopLevelToast';
b69ab3119import {enableReactTools, enableReduxTools} from './atoms/debugToolAtoms';
b69ab3120import {I18nSupport} from './i18n';
b69ab3121import {setJotaiStore} from './jotaiUtils';
b69ab3122import platform from './platform';
b69ab3123import {DEFAULT_RESET_CSS} from './resetStyle';
b69ab3124import {zoomUISettingAtom} from './responsive';
b69ab3125import {themeState} from './theme';
b69ab3126import {ModalContainer} from './useModal';
b69ab3127import {usePromise} from './usePromise';
b69ab3128import {isDev, isTest} from './utils';
b69ab3129
b69ab3130export function AllProviders({children}: {children: ReactNode}) {
b69ab3131 return (
b69ab3132 <React.StrictMode>
b69ab3133 <ResetStyle />
b69ab3134 <I18nSupport>
b69ab3135 <MaybeWithJotaiRoot>
b69ab3136 <ISLRoot>
b69ab3137 <ISLCommandContext>
b69ab3138 <ErrorBoundary>
b69ab3139 {children}
b69ab3140 <ViewportOverlayRoot />
b69ab3141 <ModalContainer />
b69ab3142 <ContextMenus />
b69ab3143 <TopLevelToast />
b69ab3144 </ErrorBoundary>
b69ab3145 </ISLCommandContext>
b69ab3146 </ISLRoot>
b69ab3147 </MaybeWithJotaiRoot>
b69ab3148 </I18nSupport>
b69ab3149 </React.StrictMode>
b69ab3150 );
b69ab3151}
b69ab3152
b69ab3153function ResetStyle() {
b69ab3154 const resetCSS = platform.theme?.resetCSS ?? DEFAULT_RESET_CSS;
b69ab3155 return resetCSS.length > 0 ? <style>{resetCSS}</style> : null;
b69ab3156}
b69ab3157
b69ab3158function ISLRoot({children}: {children: ReactNode}) {
b69ab3159 const theme = useAtomValue(themeState);
b69ab3160 useAtomValue(zoomUISettingAtom);
b69ab3161 return (
b69ab3162 <div onDragEnter={handleDragAndDrop} onDragOver={handleDragAndDrop}>
b69ab3163 <ThemedComponentsRoot className="isl-root" theme={theme}>
b69ab3164 {children}
b69ab3165 </ThemedComponentsRoot>
b69ab3166 </div>
b69ab3167 );
b69ab3168}
b69ab3169
b69ab3170function handleDragAndDrop(e: React.DragEvent<HTMLDivElement>) {
b69ab3171 // VS Code tries to capture drag & drop events to open files. But if you're dragging
b69ab3172 // on ISL, you probably want to do an ImageUpload. Prevent this event from propagating to vscode.
b69ab3173 if (e.dataTransfer?.types?.some(t => t === 'Files')) {
b69ab3174 e.stopPropagation();
b69ab3175 e.preventDefault();
b69ab3176 e.dataTransfer.dropEffect = 'copy';
b69ab3177 }
b69ab3178}
b69ab3179
b69ab3180function MaybeWithJotaiRoot({children}: {children: JSX.Element}) {
b69ab3181 if (isTest) {
b69ab3182 // Use a new store when re-mounting so each test (that calls `render(<App />)`)
b69ab3183 // starts with a clean state.
b69ab3184 return (
b69ab3185 <Provider>
b69ab3186 <AccessJotaiRoot />
b69ab3187 {children}
b69ab3188 </Provider>
b69ab3189 );
b69ab3190 } else if (isDev) {
b69ab3191 return <MaybeJotaiDebugTools>{children}</MaybeJotaiDebugTools>;
b69ab3192 } else {
b69ab3193 // Such scoped Provider or store complexity is not needed outside tests or dev.
b69ab3194 return children;
b69ab3195 }
b69ab3196}
b69ab3197const jotaiDevtools = import('./third-party/jotai-devtools/utils');
b69ab3198
b69ab3199function MaybeJotaiDebugTools({children}: {children: JSX.Element}) {
b69ab31100 const enabledRedux = useAtomValue(enableReduxTools);
b69ab31101 const enabledReact = useAtomValue(enableReactTools);
b69ab31102 return enabledRedux || enabledReact ? (
b69ab31103 <SuspenseBoundary>
b69ab31104 {enabledRedux ? <AtomsDevtools>{children}</AtomsDevtools> : children}
b69ab31105 {enabledReact && <DebugAtoms />}
b69ab31106 </SuspenseBoundary>
b69ab31107 ) : (
b69ab31108 children
b69ab31109 );
b69ab31110}
b69ab31111
b69ab31112function AtomsDevtools({children}: {children: JSX.Element}) {
b69ab31113 const {useAtomsDevtools} = usePromise(jotaiDevtools);
b69ab31114 useAtomsDevtools('jotai');
b69ab31115 return children;
b69ab31116}
b69ab31117
b69ab31118function DebugAtoms() {
b69ab31119 const {useAtomsDebugValue} = usePromise(jotaiDevtools);
b69ab31120 useAtomsDebugValue();
b69ab31121 return null;
b69ab31122}
b69ab31123
b69ab31124function AccessJotaiRoot() {
b69ab31125 const store = useStore();
b69ab31126 setJotaiStore(store);
b69ab31127 return null;
b69ab31128}