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:
parent
f2833b52c9
commit
512696c1ab
3 changed files with 57 additions and 35 deletions
|
@ -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">
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
37
packages/tldraw/src/lib/ui/hooks/useRevelantStyles.ts
Normal file
37
packages/tldraw/src/lib/ui/hooks/useRevelantStyles.ts
Normal 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]
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in a new issue