Fix style panel opening when disabled (#1983)

Closes #1982

When choosing whether to disable the mobile style menu, we now also
check if the select tool is active and whether any shapes have been
selected.

### Change Type

- [x] `patch` — Bug fix
- [ ] `minor` — New feature
- [ ] `major` — Breaking change
- [ ] `dependencies` — Changes to package dependencies[^1]
- [ ] `documentation` — Changes to the documentation only[^2]
- [ ] `tests` — Changes to any test code only[^2]
- [ ] `internal` — Any other changes that don't affect the published
package[^2]
- [ ] I don't know

[^1]: publishes a `patch` release, for devDependencies use `internal`
[^2]: will not publish a new version

### Test Plan

1. On a small screen
2. Choose the select tool
3. Deselect all shapes
4. Click on the disabled style menu button

Expected: Nothing should happen
Actual: The style menu opens

### Release Notes

- When select tool is active, the style menu shouldn't be openable
unless a shape is also selected.

Before/After

<img width="300"
src="https://github.com/tldraw/tldraw/assets/98838967/91ea55c8-0fcc-4f73-b61e-565829a5f25e"
/>
<img width="300"
src="https://github.com/tldraw/tldraw/assets/98838967/ee4070fe-e236-4818-8fb4-43520210102b"
/>

---------

Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
This commit is contained in:
Taha 2023-10-02 15:23:51 +01:00 committed by GitHub
parent f2833b52c9
commit 512696c1ab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 35 deletions

View file

@ -1,5 +1,12 @@
import { DefaultColorStyle, getDefaultColorTheme, useEditor, useValue } from '@tldraw/editor' import {
DefaultColorStyle,
TLDefaultColorStyle,
getDefaultColorTheme,
useEditor,
useValue,
} from '@tldraw/editor'
import { useCallback } from 'react' import { useCallback } from 'react'
import { useRelevantStyles } from '../hooks/useRevelantStyles'
import { useTranslation } from '../hooks/useTranslation/useTranslation' import { useTranslation } from '../hooks/useTranslation/useTranslation'
import { StylePanel } from './StylePanel/StylePanel' import { StylePanel } from './StylePanel/StylePanel'
import { Button } from './primitives/Button' import { Button } from './primitives/Button'
@ -10,17 +17,12 @@ export function MobileStylePanel() {
const editor = useEditor() const editor = useEditor()
const msg = useTranslation() const msg = useTranslation()
const currentColor = useValue( const relevantStyles = useRelevantStyles()
'current color', const color = relevantStyles?.styles.get(DefaultColorStyle)
() => {
const color = editor.sharedStyles.get(DefaultColorStyle)
if (!color) return 'var(--color-muted-1)'
if (color.type === 'mixed') return null
const theme = getDefaultColorTheme({ isDarkMode: editor.user.isDarkMode }) const theme = getDefaultColorTheme({ isDarkMode: editor.user.isDarkMode })
return theme[color.value].solid const currentColor = (
}, color?.type === 'shared' ? theme[color.value as TLDefaultColorStyle] : theme.black
[editor] ).solid
)
const disableStylePanel = useValue( const disableStylePanel = useValue(
'isHandOrEraserToolActive', 'isHandOrEraserToolActive',
@ -43,10 +45,12 @@ export function MobileStylePanel() {
<Button <Button
className="tlui-toolbar__tools__button tlui-toolbar__styles__button" className="tlui-toolbar__tools__button tlui-toolbar__styles__button"
data-testid="mobile.styles" data-testid="mobile.styles"
style={{ color: currentColor ?? 'var(--color-text)' }} style={{
color: disableStylePanel ? 'var(--color-muted-1)' : currentColor,
}}
title={msg('style-panel.title')} title={msg('style-panel.title')}
> >
<Icon icon={currentColor ? 'blob' : 'mixed'} /> <Icon icon={disableStylePanel ? 'blob' : color?.type === 'mixed' ? 'mixed' : 'blob'} />
</Button> </Button>
</PopoverTrigger> </PopoverTrigger>
<PopoverContent side="top" align="end"> <PopoverContent side="top" align="end">

View file

@ -8,18 +8,16 @@ import {
DefaultHorizontalAlignStyle, DefaultHorizontalAlignStyle,
DefaultSizeStyle, DefaultSizeStyle,
DefaultVerticalAlignStyle, DefaultVerticalAlignStyle,
Editor,
GeoShapeGeoStyle, GeoShapeGeoStyle,
LineShapeSplineStyle, LineShapeSplineStyle,
ReadonlySharedStyleMap, ReadonlySharedStyleMap,
SharedStyle, SharedStyle,
SharedStyleMap,
StyleProp, StyleProp,
minBy, minBy,
useEditor, useEditor,
useValue,
} from '@tldraw/editor' } from '@tldraw/editor'
import React, { useCallback } from 'react' import React, { useCallback } from 'react'
import { useRelevantStyles } from '../../hooks/useRevelantStyles'
import { useTranslation } from '../../hooks/useTranslation/useTranslation' import { useTranslation } from '../../hooks/useTranslation/useTranslation'
import { Button } from '../primitives/Button' import { Button } from '../primitives/Button'
import { ButtonPicker } from '../primitives/ButtonPicker' import { ButtonPicker } from '../primitives/ButtonPicker'
@ -32,28 +30,11 @@ interface StylePanelProps {
isMobile?: boolean isMobile?: boolean
} }
const selectToolStyles = [DefaultColorStyle, DefaultDashStyle, DefaultFillStyle, DefaultSizeStyle]
function getRelevantStyles(
editor: Editor
): { styles: ReadonlySharedStyleMap; opacity: SharedStyle<number> } | null {
const styles = new SharedStyleMap(editor.sharedStyles)
const hasShape = editor.selectedShapeIds.length > 0 || !!editor.root.current.value?.shapeType
if (styles.size === 0 && editor.isIn('select') && editor.selectedShapeIds.length === 0) {
for (const style of selectToolStyles) {
styles.applyValue(style, editor.getStyleForNextShape(style))
}
}
if (styles.size === 0 && !hasShape) return null
return { styles, opacity: editor.sharedOpacity }
}
/** @internal */ /** @internal */
export const StylePanel = function StylePanel({ isMobile }: StylePanelProps) { export const StylePanel = function StylePanel({ isMobile }: StylePanelProps) {
const editor = useEditor() const editor = useEditor()
const relevantStyles = useValue('getRelevantStyles', () => getRelevantStyles(editor), [editor]) const relevantStyles = useRelevantStyles()
const handlePointerOut = useCallback(() => { const handlePointerOut = useCallback(() => {
if (!isMobile) { if (!isMobile) {

View file

@ -0,0 +1,37 @@
import {
DefaultColorStyle,
DefaultDashStyle,
DefaultFillStyle,
DefaultSizeStyle,
ReadonlySharedStyleMap,
SharedStyle,
SharedStyleMap,
useEditor,
useValue,
} from '@tldraw/editor'
const selectToolStyles = [DefaultColorStyle, DefaultDashStyle, DefaultFillStyle, DefaultSizeStyle]
export function useRelevantStyles(): {
styles: ReadonlySharedStyleMap
opacity: SharedStyle<number>
} | null {
const editor = useEditor()
return useValue(
'getRelevantStyles',
() => {
const styles = new SharedStyleMap(editor.sharedStyles)
const hasShape = editor.selectedShapeIds.length > 0 || !!editor.root.current.value?.shapeType
if (styles.size === 0 && editor.isIn('select') && editor.selectedShapeIds.length === 0) {
for (const style of selectToolStyles) {
styles.applyValue(style, editor.getStyleForNextShape(style))
}
}
if (styles.size === 0 && !hasShape) return null
return { styles, opacity: editor.sharedOpacity }
},
[editor]
)
}