diff --git a/packages/tldraw/src/lib/tools/SelectTool/childStates/Brushing.ts b/packages/tldraw/src/lib/tools/SelectTool/childStates/Brushing.ts index 28e094c6efca..9cec0a067c4c 100644 --- a/packages/tldraw/src/lib/tools/SelectTool/childStates/Brushing.ts +++ b/packages/tldraw/src/lib/tools/SelectTool/childStates/Brushing.ts @@ -24,6 +24,9 @@ export class Brushing extends StateNode { excludedShapeIds = new Set() isWrapMode = false + selectionOrder = new Map() + private orderCounter = 0 + viewportDidChange = false cleanupViewportChangeReactor() { void null @@ -62,6 +65,8 @@ export class Brushing extends StateNode { this.info = info this.initialSelectedShapeIds = editor.getSelectedShapeIds().slice() + this.selectionOrder.clear() + this.orderCounter = 0 this.hitTestShapes() isInitialCheck = false } @@ -166,10 +171,7 @@ export class Brushing extends StateNode { editor.updateInstanceState({ brush: { ...brush.toJson() } }) } - const current = editor.getSelectedShapeIds() - if (current.length !== results.size || current.some((id) => !results.has(id))) { - editor.setSelectedShapes(Array.from(results)) - } + this.setOrderedSelectedShapes(results) return } @@ -225,9 +227,30 @@ export class Brushing extends StateNode { editor.updateInstanceState({ brush: { ...brush.toJson() } }) } - const current = editor.getSelectedShapeIds() - if (current.length !== results.size || current.some((id) => !results.has(id))) { - editor.setSelectedShapes(Array.from(results)) + this.setOrderedSelectedShapes(results) + } + + private setOrderedSelectedShapes(results: Set) { + // Track entry order for newly selected shapes + for (const id of results) { + if (!this.selectionOrder.has(id)) { + this.selectionOrder.set(id, this.orderCounter++) + } + } + // Remove shapes that left the selection + for (const id of this.selectionOrder.keys()) { + if (!results.has(id)) { + this.selectionOrder.delete(id) + } + } + + const ordered = Array.from(results).sort( + (a, b) => (this.selectionOrder.get(a) ?? 0) - (this.selectionOrder.get(b) ?? 0) + ) + + const current = this.editor.getSelectedShapeIds() + if (current.length !== ordered.length || current.some((id, i) => id !== ordered[i])) { + this.editor.setSelectedShapes(ordered) } }