From 9db195108ce82fa44f3dd72b0515d8a94d480048 Mon Sep 17 00:00:00 2001 From: Stephen Zhou Date: Sat, 13 Jan 2024 09:35:18 +0800 Subject: [PATCH] feat: add position option (#118) * feat: add className and position option * fix: remove className option * fix: remove className * chore: add test update readme * chore: update --- README.md | 2 + __tests__/devtools/basic.test.tsx | 18 +++++++ src/DevTools/DevTools.tsx | 80 ++++++++++++++++------------ src/DevTools/Extension/Extension.tsx | 19 +------ 4 files changed, 68 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index 4dc3726d..5dcd629c 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,8 @@ type DevToolsProps = { store?: Store; // Defaults to light theme?: 'dark' | 'light'; + // Defaults to 'bottom-left' + position?: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left'; // Custom nonce to allowlist jotai-devtools specific inline styles via CSP nonce?: string; // We recommend keeping these options static. i.e. set it only once. Avoid connecting it to re-renderable state diff --git a/__tests__/devtools/basic.test.tsx b/__tests__/devtools/basic.test.tsx index a3f29cc2..251fb3bd 100644 --- a/__tests__/devtools/basic.test.tsx +++ b/__tests__/devtools/basic.test.tsx @@ -27,6 +27,24 @@ describe('DevTools - basic', () => { ).toBeInTheDocument(); }); + it('should be placed on the bottom left by default', async () => { + customRender(); + expect(screen.getByTitle('Open Jotai Devtools')).toHaveStyle({ + bottom: '0.2rem', + left: '0.2rem', + }); + }); + + it('should respect the position prop', async () => { + customRender(); + expect(screen.getByTitle('Open Jotai Devtools')).toHaveStyle({ + top: '0.2rem', + right: '0.2rem', + bottom: 'unset', + left: 'unset', + }); + }); + it('should resize the devtools upon dragging the resize bar', async () => { customRender(); diff --git a/src/DevTools/DevTools.tsx b/src/DevTools/DevTools.tsx index 7a5e9aae..205e8277 100644 --- a/src/DevTools/DevTools.tsx +++ b/src/DevTools/DevTools.tsx @@ -15,41 +15,15 @@ import { import { Extension, ExtensionProps, - shellTriggerButtonStyles, + shellTriggerButtonClassName, } from './Extension'; import { fontCss } from './fonts'; import { InternalDevToolsContext } from './internal-jotai-store'; import { createMemoizedEmotionCache } from './utils'; -const theme: MantineThemeOverride = { - primaryColor: 'dark', - activeStyles: { transform: 'scale(1)' }, - fontFamily: 'Inter, -apple-system, BlinkMacSystemFont, Segoe, sans-serif', - fontFamilyMonospace: - 'JetBrains Mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace', - headings: { - fontFamily: - 'Inter, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji', - }, - defaultRadius: 'md', - globalStyles: (theme) => ({ - '.jotai-devtools-shell': { - '*, *::before, *::after': { - boxSizing: 'border-box', - }, - ...theme.fn.fontStyles(), - color: theme.colorScheme === 'dark' ? theme.white : theme.black, - lineHeight: theme.lineHeight, - WebkitFontSmoothing: 'antialiased', - MozOsxFontSmoothing: 'grayscale', - fontSize: theme.fontSizes.md, - }, - ...shellTriggerButtonStyles, - }), -}; - export type DevToolsProps = ExtensionProps & { theme?: 'dark' | 'light'; + position?: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left'; nonce?: string; options?: DevToolsOptions; }; @@ -58,6 +32,7 @@ const DevToolsMain = ({ store, isInitialOpen = false, theme: userColorScheme = 'light', + position = 'bottom-left', nonce, options, }: DevToolsProps): JSX.Element => { @@ -83,10 +58,49 @@ const DevToolsMain = ({ setDevToolsOptions(options); }, [setDevToolsOptions, options]); - const theme_ = { - ...theme, - colorScheme, - }; + const theme: MantineThemeOverride = React.useMemo(() => { + return { + primaryColor: 'dark', + activeStyles: { transform: 'scale(1)' }, + fontFamily: 'Inter, -apple-system, BlinkMacSystemFont, Segoe, sans-serif', + fontFamilyMonospace: + 'JetBrains Mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace', + headings: { + fontFamily: + 'Inter, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji', + }, + defaultRadius: 'md', + globalStyles: (theme) => ({ + '.jotai-devtools-shell': { + '*, *::before, *::after': { + boxSizing: 'border-box', + }, + ...theme.fn.fontStyles(), + color: theme.colorScheme === 'dark' ? theme.white : theme.black, + lineHeight: theme.lineHeight, + WebkitFontSmoothing: 'antialiased', + MozOsxFontSmoothing: 'grayscale', + fontSize: theme.fontSizes.md, + }, + [`.${shellTriggerButtonClassName}`]: { + position: 'fixed', + borderRadius: '50%', + borderWidth: 0, + width: '4rem', + height: '4rem', + zIndex: 99999, + img: { + height: '2rem', + }, + left: position.includes('left') ? '0.2rem' : 'unset', + right: position.includes('right') ? '0.2rem' : 'unset', + top: position.includes('top') ? '0.2rem' : 'unset', + bottom: position.includes('bottom') ? '0.2rem' : 'unset', + }, + }), + colorScheme, + }; + }, [colorScheme, position]); return ( @@ -95,7 +109,7 @@ const DevToolsMain = ({ toggleColorScheme={toggleColorScheme} > diff --git a/src/DevTools/Extension/Extension.tsx b/src/DevTools/Extension/Extension.tsx index 8524cde0..24dde7e5 100644 --- a/src/DevTools/Extension/Extension.tsx +++ b/src/DevTools/Extension/Extension.tsx @@ -1,6 +1,5 @@ import * as React from 'react'; import { ActionIcon } from '@mantine/core'; -import type { CSSObject } from '@mantine/core'; import { useAtom, useSetAtom } from 'jotai/react'; import { Store } from '../../types'; import { isShellOpenAtom } from '../atoms/is-shell-open-atom'; @@ -11,23 +10,7 @@ import { logo } from './assets/logo'; import { Shell } from './components/Shell'; import useSyncSnapshotHistory from './components/Shell/components/TimeTravel/useSyncSnapshotHistory'; -const shellTriggerButtonClassName = 'jotai-devtools-trigger-button'; - -export const shellTriggerButtonStyles: CSSObject = { - [`.${shellTriggerButtonClassName}`]: { - position: 'fixed', - left: 10, - bottom: 10, - borderRadius: '50%', - borderWidth: 0, - width: '4rem', - height: '4rem', - zIndex: 99999, - img: { - height: '2rem', - }, - }, -}; +export const shellTriggerButtonClassName = 'jotai-devtools-trigger-button'; const ShellTriggerButton = React.forwardRef((_, ref) => { const setIsShellOpen = useSetAtom(