[fix] missing border on group shape when unlocked (#2075)

This PR fixes a bug where the indicator on a locked group (or any
shape!) would not appear when the shape was unlocked. This happens
because the `memo` equality checker filtered out changes to the shape's
locked property if they did not effect any other properties.

![Kapture 2023-10-13 at 14 44
31](https://github.com/tldraw/tldraw/assets/23072548/c40442e0-8d18-4ed0-863c-c2b73da81f28)

### Change Type

- [x] `patch` — Bug fix

### Release Notes

- Fix case where indicator was not shown when unlocking groups
This commit is contained in:
Steve Ruiz 2023-10-13 16:13:47 +01:00 committed by GitHub
parent 22955bb0ec
commit ff9c1655f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 20 additions and 28 deletions

View file

@ -11,7 +11,11 @@ import { OptionalErrorBoundary } from './ErrorBoundary'
class ShapeWithPropsEquality { class ShapeWithPropsEquality {
constructor(public shape: TLShape | undefined) {} constructor(public shape: TLShape | undefined) {}
equals(other: ShapeWithPropsEquality) { equals(other: ShapeWithPropsEquality) {
return this.shape?.props === other?.shape?.props && this.shape?.meta === other?.shape?.meta return (
this.shape?.isLocked === other?.shape?.isLocked &&
this.shape?.props === other?.shape?.props &&
this.shape?.meta === other?.shape?.meta
)
} }
} }

View file

@ -1,15 +1,13 @@
import { useValue } from '@tldraw/state'
import { useEditor } from '../../../hooks/useEditor'
import { Box2d } from '../../../primitives/Box2d' import { Box2d } from '../../../primitives/Box2d'
import { getPerfectDashProps } from '../shared/getPerfectDashProps' import { getPerfectDashProps } from '../shared/getPerfectDashProps'
export function DashedOutlineBox({ export function DashedOutlineBox({ bounds, className }: { bounds: Box2d; className: string }) {
bounds, const editor = useEditor()
zoomLevel,
className, const zoomLevel = useValue('zoom level', () => editor.zoomLevel, [editor])
}: {
bounds: Box2d
zoomLevel: number
className: string
}) {
return ( return (
<g className={className} pointerEvents="none" strokeLinecap="round" strokeLinejoin="round"> <g className={className} pointerEvents="none" strokeLinecap="round" strokeLinejoin="round">
{bounds.sides.map((side, i) => { {bounds.sides.map((side, i) => {

View file

@ -49,15 +49,9 @@ export class GroupShapeUtil extends ShapeUtil<TLGroupShape> {
} }
component(shape: TLGroupShape) { component(shape: TLGroupShape) {
// Not a class component, but eslint can't tell that :( const isErasing = this.editor.erasingShapeIds.includes(shape.id)
const {
erasingShapeIds,
currentPageState: { hintingShapeIds, focusedGroupId },
zoomLevel,
} = this.editor
const isErasing = erasingShapeIds.includes(shape.id)
const { hintingShapeIds } = this.editor.currentPageState
const isHintingOtherGroup = const isHintingOtherGroup =
hintingShapeIds.length > 0 && hintingShapeIds.length > 0 &&
hintingShapeIds.some( hintingShapeIds.some(
@ -66,12 +60,13 @@ export class GroupShapeUtil extends ShapeUtil<TLGroupShape> {
this.editor.isShapeOfType<TLGroupShape>(this.editor.getShape(id)!, 'group') this.editor.isShapeOfType<TLGroupShape>(this.editor.getShape(id)!, 'group')
) )
const isFocused = this.editor.currentPageState.focusedGroupId !== shape.id
if ( if (
// always show the outline while we're erasing the group !isErasing && // always show the outline while we're erasing the group
!isErasing &&
// show the outline while the group is focused unless something outside of the group is being hinted // show the outline while the group is focused unless something outside of the group is being hinted
// this happens dropping shapes from a group onto some outside group // this happens dropping shapes from a group onto some outside group
(shape.id !== focusedGroupId || isHintingOtherGroup) (isFocused || isHintingOtherGroup)
) { ) {
return null return null
} }
@ -80,20 +75,15 @@ export class GroupShapeUtil extends ShapeUtil<TLGroupShape> {
return ( return (
<SVGContainer id={shape.id}> <SVGContainer id={shape.id}>
<DashedOutlineBox className="tl-group" bounds={bounds} zoomLevel={zoomLevel} /> <DashedOutlineBox className="tl-group" bounds={bounds} />
</SVGContainer> </SVGContainer>
) )
} }
indicator(shape: TLGroupShape) { indicator(shape: TLGroupShape) {
// Not a class component, but eslint can't tell that :( // Not a class component, but eslint can't tell that :(
const {
camera: { z: zoomLevel },
} = this.editor
const bounds = this.editor.getShapeGeometry(shape).bounds const bounds = this.editor.getShapeGeometry(shape).bounds
return <DashedOutlineBox className="" bounds={bounds} />
return <DashedOutlineBox className="" bounds={bounds} zoomLevel={zoomLevel} />
} }
override onChildrenChange: TLOnChildrenChangeHandler<TLGroupShape> = (group) => { override onChildrenChange: TLOnChildrenChangeHandler<TLGroupShape> = (group) => {