[feature] wrap mode (#2938)
By default, tldraw's brushing mode will select when the box intersects an shape's geometry. A user can hold Command / Ctrl to require that the selection box fully contain a shape's bounds instead. Some people really prefer the opposite. Three years! Three years I've been saying "no no no". This PR adds a user preference to flip the logic. When `isWrapMode` is true, selection requires that the box completely contain a shape before it's added to the list of selecting shapes; and ctrl flips back to intersection instead. ### Change Type - [x] `minor` — New feature ### Test Plan 1. Turn on wrap mode in the user preferences menu. 2. Select stuff. 3. Use the ctrl key to except the behavior back to intersection. - [x] Unit Tests ### Release Notes - Added `isWrapMode` to user preferences. - Added Wrap Mode toggle to user preferences menu.
This commit is contained in:
parent
adc53afbe3
commit
4f07e696e8
16 changed files with 234 additions and 10 deletions
|
@ -82,6 +82,8 @@
|
||||||
"action.toggle-auto-size": "Toggle auto size",
|
"action.toggle-auto-size": "Toggle auto size",
|
||||||
"action.toggle-dark-mode.menu": "Dark mode",
|
"action.toggle-dark-mode.menu": "Dark mode",
|
||||||
"action.toggle-dark-mode": "Toggle dark mode",
|
"action.toggle-dark-mode": "Toggle dark mode",
|
||||||
|
"action.toggle-wrap-mode.menu": "Select on wrap",
|
||||||
|
"action.toggle-wrap-mode": "Toggle Select on wrap",
|
||||||
"action.toggle-reduce-motion.menu": "Reduce motion",
|
"action.toggle-reduce-motion.menu": "Reduce motion",
|
||||||
"action.toggle-reduce-motion": "Toggle reduce motion",
|
"action.toggle-reduce-motion": "Toggle reduce motion",
|
||||||
"action.toggle-edge-scrolling.menu": "Edge scrolling",
|
"action.toggle-edge-scrolling.menu": "Edge scrolling",
|
||||||
|
|
|
@ -502,6 +502,7 @@ export const defaultUserPreferences: Readonly<{
|
||||||
edgeScrollSpeed: 1;
|
edgeScrollSpeed: 1;
|
||||||
animationSpeed: 0 | 1;
|
animationSpeed: 0 | 1;
|
||||||
isSnapMode: false;
|
isSnapMode: false;
|
||||||
|
isWrapMode: false;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
// @public
|
// @public
|
||||||
|
@ -2590,6 +2591,8 @@ export interface TLUserPreferences {
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
isSnapMode?: boolean | null;
|
isSnapMode?: boolean | null;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
|
isWrapMode?: boolean | null;
|
||||||
|
// (undocumented)
|
||||||
locale?: null | string;
|
locale?: null | string;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
name?: null | string;
|
name?: null | string;
|
||||||
|
|
|
@ -6826,7 +6826,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"kind": "Content",
|
"kind": "Content",
|
||||||
"text": "<{\n name: \"New User\";\n locale: \"ar\" | \"ca\" | \"cs\" | \"da\" | \"de\" | \"en\" | \"es\" | \"fa\" | \"fi\" | \"fr\" | \"gl\" | \"he\" | \"hi-in\" | \"hr\" | \"hu\" | \"it\" | \"ja\" | \"ko-kr\" | \"ku\" | \"my\" | \"ne\" | \"no\" | \"pl\" | \"pt-br\" | \"pt-pt\" | \"ro\" | \"ru\" | \"sl\" | \"sv\" | \"te\" | \"th\" | \"tr\" | \"uk\" | \"vi\" | \"zh-cn\" | \"zh-tw\";\n color: \"#02B1CC\" | \"#11B3A3\" | \"#39B178\" | \"#55B467\" | \"#7B66DC\" | \"#9D5BD2\" | \"#BD54C6\" | \"#E34BA9\" | \"#EC5E41\" | \"#F04F88\" | \"#F2555A\" | \"#FF802B\";\n isDarkMode: false;\n edgeScrollSpeed: 1;\n animationSpeed: 0 | 1;\n isSnapMode: false;\n}>"
|
"text": "<{\n name: \"New User\";\n locale: \"ar\" | \"ca\" | \"cs\" | \"da\" | \"de\" | \"en\" | \"es\" | \"fa\" | \"fi\" | \"fr\" | \"gl\" | \"he\" | \"hi-in\" | \"hr\" | \"hu\" | \"it\" | \"ja\" | \"ko-kr\" | \"ku\" | \"my\" | \"ne\" | \"no\" | \"pl\" | \"pt-br\" | \"pt-pt\" | \"ro\" | \"ru\" | \"sl\" | \"sv\" | \"te\" | \"th\" | \"tr\" | \"uk\" | \"vi\" | \"zh-cn\" | \"zh-tw\";\n color: \"#02B1CC\" | \"#11B3A3\" | \"#39B178\" | \"#55B467\" | \"#7B66DC\" | \"#9D5BD2\" | \"#BD54C6\" | \"#E34BA9\" | \"#EC5E41\" | \"#F04F88\" | \"#F2555A\" | \"#FF802B\";\n isDarkMode: false;\n edgeScrollSpeed: 1;\n animationSpeed: 0 | 1;\n isSnapMode: false;\n isWrapMode: false;\n}>"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"fileUrlPath": "packages/editor/src/lib/config/TLUserPreferences.ts",
|
"fileUrlPath": "packages/editor/src/lib/config/TLUserPreferences.ts",
|
||||||
|
@ -41650,6 +41650,33 @@
|
||||||
"endIndex": 2
|
"endIndex": 2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"kind": "PropertySignature",
|
||||||
|
"canonicalReference": "@tldraw/editor!TLUserPreferences#isWrapMode:member",
|
||||||
|
"docComment": "",
|
||||||
|
"excerptTokens": [
|
||||||
|
{
|
||||||
|
"kind": "Content",
|
||||||
|
"text": "isWrapMode?: "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "Content",
|
||||||
|
"text": "boolean | null"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "Content",
|
||||||
|
"text": ";"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isReadonly": false,
|
||||||
|
"isOptional": true,
|
||||||
|
"releaseTag": "Public",
|
||||||
|
"name": "isWrapMode",
|
||||||
|
"propertyTypeTokenRange": {
|
||||||
|
"startIndex": 1,
|
||||||
|
"endIndex": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"kind": "PropertySignature",
|
"kind": "PropertySignature",
|
||||||
"canonicalReference": "@tldraw/editor!TLUserPreferences#locale:member",
|
"canonicalReference": "@tldraw/editor!TLUserPreferences#locale:member",
|
||||||
|
|
|
@ -16,10 +16,11 @@ export interface TLUserPreferences {
|
||||||
name?: string | null
|
name?: string | null
|
||||||
locale?: string | null
|
locale?: string | null
|
||||||
color?: string | null
|
color?: string | null
|
||||||
isDarkMode?: boolean | null
|
|
||||||
animationSpeed?: number | null
|
animationSpeed?: number | null
|
||||||
edgeScrollSpeed?: number | null
|
edgeScrollSpeed?: number | null
|
||||||
|
isDarkMode?: boolean | null
|
||||||
isSnapMode?: boolean | null
|
isSnapMode?: boolean | null
|
||||||
|
isWrapMode?: boolean | null
|
||||||
}
|
}
|
||||||
|
|
||||||
interface UserDataSnapshot {
|
interface UserDataSnapshot {
|
||||||
|
@ -42,6 +43,7 @@ const userTypeValidator: T.Validator<TLUserPreferences> = T.object<TLUserPrefere
|
||||||
animationSpeed: T.number.nullable().optional(),
|
animationSpeed: T.number.nullable().optional(),
|
||||||
edgeScrollSpeed: T.number.nullable().optional(),
|
edgeScrollSpeed: T.number.nullable().optional(),
|
||||||
isSnapMode: T.boolean.nullable().optional(),
|
isSnapMode: T.boolean.nullable().optional(),
|
||||||
|
isWrapMode: T.boolean.nullable().optional(),
|
||||||
})
|
})
|
||||||
|
|
||||||
const Versions = {
|
const Versions = {
|
||||||
|
@ -49,10 +51,11 @@ const Versions = {
|
||||||
AddIsSnapMode: 2,
|
AddIsSnapMode: 2,
|
||||||
MakeFieldsNullable: 3,
|
MakeFieldsNullable: 3,
|
||||||
AddEdgeScrollSpeed: 4,
|
AddEdgeScrollSpeed: 4,
|
||||||
|
AddExcalidrawSelectMode: 5,
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
const userMigrations = defineMigrations({
|
const userMigrations = defineMigrations({
|
||||||
currentVersion: Versions.AddEdgeScrollSpeed,
|
currentVersion: Versions.AddExcalidrawSelectMode,
|
||||||
migrators: {
|
migrators: {
|
||||||
[Versions.AddAnimationSpeed]: {
|
[Versions.AddAnimationSpeed]: {
|
||||||
up: (user) => {
|
up: (user) => {
|
||||||
|
@ -83,9 +86,10 @@ const userMigrations = defineMigrations({
|
||||||
name: user.name ?? defaultUserPreferences.name,
|
name: user.name ?? defaultUserPreferences.name,
|
||||||
locale: user.locale ?? defaultUserPreferences.locale,
|
locale: user.locale ?? defaultUserPreferences.locale,
|
||||||
color: user.color ?? defaultUserPreferences.color,
|
color: user.color ?? defaultUserPreferences.color,
|
||||||
isDarkMode: user.isDarkMode ?? defaultUserPreferences.isDarkMode,
|
|
||||||
animationSpeed: user.animationSpeed ?? defaultUserPreferences.animationSpeed,
|
animationSpeed: user.animationSpeed ?? defaultUserPreferences.animationSpeed,
|
||||||
|
isDarkMode: user.isDarkMode ?? defaultUserPreferences.isDarkMode,
|
||||||
isSnapMode: user.isSnapMode ?? defaultUserPreferences.isSnapMode,
|
isSnapMode: user.isSnapMode ?? defaultUserPreferences.isSnapMode,
|
||||||
|
isWrapMode: user.isWrapMode ?? defaultUserPreferences.isWrapMode,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -100,6 +104,14 @@ const userMigrations = defineMigrations({
|
||||||
return user
|
return user
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
[Versions.AddExcalidrawSelectMode]: {
|
||||||
|
up: (user: TLUserPreferences) => {
|
||||||
|
return { ...user, isWrapMode: false }
|
||||||
|
},
|
||||||
|
down: ({ isWrapMode: _, ...user }: TLUserPreferences) => {
|
||||||
|
return user
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -148,6 +160,7 @@ export const defaultUserPreferences = Object.freeze({
|
||||||
edgeScrollSpeed: 1,
|
edgeScrollSpeed: 1,
|
||||||
animationSpeed: userPrefersReducedMotion() ? 0 : 1,
|
animationSpeed: userPrefersReducedMotion() ? 0 : 1,
|
||||||
isSnapMode: false,
|
isSnapMode: false,
|
||||||
|
isWrapMode: false,
|
||||||
}) satisfies Readonly<Omit<TLUserPreferences, 'id'>>
|
}) satisfies Readonly<Omit<TLUserPreferences, 'id'>>
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
|
|
|
@ -24,9 +24,10 @@ export class UserPreferencesManager {
|
||||||
name: this.getName(),
|
name: this.getName(),
|
||||||
locale: this.getLocale(),
|
locale: this.getLocale(),
|
||||||
color: this.getColor(),
|
color: this.getColor(),
|
||||||
isDarkMode: this.getIsDarkMode(),
|
|
||||||
animationSpeed: this.getAnimationSpeed(),
|
animationSpeed: this.getAnimationSpeed(),
|
||||||
isSnapMode: this.getIsSnapMode(),
|
isSnapMode: this.getIsSnapMode(),
|
||||||
|
isDarkMode: this.getIsDarkMode(),
|
||||||
|
isWrapMode: this.getIsWrapMode(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@computed getIsDarkMode() {
|
@computed getIsDarkMode() {
|
||||||
|
@ -66,4 +67,8 @@ export class UserPreferencesManager {
|
||||||
@computed getIsSnapMode() {
|
@computed getIsSnapMode() {
|
||||||
return this.user.userPreferences.get().isSnapMode ?? defaultUserPreferences.isSnapMode
|
return this.user.userPreferences.get().isSnapMode ?? defaultUserPreferences.isSnapMode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@computed getIsWrapMode() {
|
||||||
|
return this.user.userPreferences.get().isWrapMode ?? defaultUserPreferences.isWrapMode
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -226,6 +226,7 @@ export {
|
||||||
ToggleSnapModeItem,
|
ToggleSnapModeItem,
|
||||||
ToggleToolLockItem,
|
ToggleToolLockItem,
|
||||||
ToggleTransparentBgMenuItem,
|
ToggleTransparentBgMenuItem,
|
||||||
|
ToggleWrapModeItem,
|
||||||
UngroupMenuItem,
|
UngroupMenuItem,
|
||||||
UnlockAllMenuItem,
|
UnlockAllMenuItem,
|
||||||
ZoomTo100MenuItem,
|
ZoomTo100MenuItem,
|
||||||
|
|
|
@ -28,6 +28,7 @@ export class Brushing extends StateNode {
|
||||||
brush = new Box()
|
brush = new Box()
|
||||||
initialSelectedShapeIds: TLShapeId[] = []
|
initialSelectedShapeIds: TLShapeId[] = []
|
||||||
excludedShapeIds = new Set<TLShapeId>()
|
excludedShapeIds = new Set<TLShapeId>()
|
||||||
|
isWrapMode = false
|
||||||
|
|
||||||
// The shape that the brush started on
|
// The shape that the brush started on
|
||||||
initialStartShape: TLShape | null = null
|
initialStartShape: TLShape | null = null
|
||||||
|
@ -35,6 +36,8 @@ export class Brushing extends StateNode {
|
||||||
override onEnter = (info: TLPointerEventInfo & { target: 'canvas' }) => {
|
override onEnter = (info: TLPointerEventInfo & { target: 'canvas' }) => {
|
||||||
const { altKey, currentPagePoint } = this.editor.inputs
|
const { altKey, currentPagePoint } = this.editor.inputs
|
||||||
|
|
||||||
|
this.isWrapMode = this.editor.user.getIsWrapMode()
|
||||||
|
|
||||||
if (altKey) {
|
if (altKey) {
|
||||||
this.parent.transition('scribble_brushing', info)
|
this.parent.transition('scribble_brushing', info)
|
||||||
return
|
return
|
||||||
|
@ -123,7 +126,9 @@ export class Brushing extends StateNode {
|
||||||
// We'll be testing the corners of the brush against the shapes
|
// We'll be testing the corners of the brush against the shapes
|
||||||
const { corners } = this.brush
|
const { corners } = this.brush
|
||||||
|
|
||||||
const { excludedShapeIds } = this
|
const { excludedShapeIds, isWrapMode } = this
|
||||||
|
|
||||||
|
const isWrapping = isWrapMode ? !ctrlKey : ctrlKey
|
||||||
|
|
||||||
testAllShapes: for (let i = 0, n = currentPageShapes.length; i < n; i++) {
|
testAllShapes: for (let i = 0, n = currentPageShapes.length; i < n; i++) {
|
||||||
shape = currentPageShapes[i]
|
shape = currentPageShapes[i]
|
||||||
|
@ -142,7 +147,7 @@ export class Brushing extends StateNode {
|
||||||
// Should we even test for a single segment intersections? Only if
|
// Should we even test for a single segment intersections? Only if
|
||||||
// we're not holding the ctrl key for alternate selection mode
|
// we're not holding the ctrl key for alternate selection mode
|
||||||
// (only wraps count!), or if the shape is a frame.
|
// (only wraps count!), or if the shape is a frame.
|
||||||
if (ctrlKey || this.editor.isShapeOfType<TLFrameShape>(shape, 'frame')) {
|
if (isWrapping || this.editor.isShapeOfType<TLFrameShape>(shape, 'frame')) {
|
||||||
continue testAllShapes
|
continue testAllShapes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ import {
|
||||||
ToggleSnapModeItem,
|
ToggleSnapModeItem,
|
||||||
ToggleToolLockItem,
|
ToggleToolLockItem,
|
||||||
ToggleTransparentBgMenuItem,
|
ToggleTransparentBgMenuItem,
|
||||||
|
ToggleWrapModeItem,
|
||||||
UngroupMenuItem,
|
UngroupMenuItem,
|
||||||
UnlockAllMenuItem,
|
UnlockAllMenuItem,
|
||||||
ZoomTo100MenuItem,
|
ZoomTo100MenuItem,
|
||||||
|
@ -186,6 +187,7 @@ export function PreferencesGroup() {
|
||||||
<ToggleSnapModeItem />
|
<ToggleSnapModeItem />
|
||||||
<ToggleToolLockItem />
|
<ToggleToolLockItem />
|
||||||
<ToggleGridItem />
|
<ToggleGridItem />
|
||||||
|
<ToggleWrapModeItem />
|
||||||
<ToggleDarkModeItem />
|
<ToggleDarkModeItem />
|
||||||
<ToggleFocusModeItem />
|
<ToggleFocusModeItem />
|
||||||
<ToggleEdgeScrollingItem />
|
<ToggleEdgeScrollingItem />
|
||||||
|
|
|
@ -492,6 +492,15 @@ export function ToggleGridItem() {
|
||||||
const isGridMode = useValue('isGridMode', () => editor.getInstanceState().isGridMode, [editor])
|
const isGridMode = useValue('isGridMode', () => editor.getInstanceState().isGridMode, [editor])
|
||||||
return <TldrawUiMenuCheckboxItem {...actions['toggle-grid']} checked={isGridMode} />
|
return <TldrawUiMenuCheckboxItem {...actions['toggle-grid']} checked={isGridMode} />
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @public */
|
||||||
|
export function ToggleWrapModeItem() {
|
||||||
|
const actions = useActions()
|
||||||
|
const editor = useEditor()
|
||||||
|
const isWrapMode = useValue('isWrapMode', () => editor.user.getIsWrapMode(), [editor])
|
||||||
|
return <TldrawUiMenuCheckboxItem {...actions['toggle-wrap-mode']} checked={isWrapMode} />
|
||||||
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function ToggleDarkModeItem() {
|
export function ToggleDarkModeItem() {
|
||||||
const actions = useActions()
|
const actions = useActions()
|
||||||
|
|
|
@ -1057,6 +1057,21 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
||||||
},
|
},
|
||||||
checkbox: true,
|
checkbox: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'toggle-wrap-mode',
|
||||||
|
label: {
|
||||||
|
default: 'action.toggle-wrap-mode',
|
||||||
|
menu: 'action.toggle-wrap-mode.menu',
|
||||||
|
},
|
||||||
|
readonlyOk: true,
|
||||||
|
onSelect(source) {
|
||||||
|
trackEvent('toggle-wrap-mode', { source })
|
||||||
|
editor.user.updateUserPreferences({
|
||||||
|
isWrapMode: !editor.user.getIsWrapMode(),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
checkbox: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'toggle-reduce-motion',
|
id: 'toggle-reduce-motion',
|
||||||
label: {
|
label: {
|
||||||
|
|
|
@ -84,6 +84,7 @@ export interface TLUiEventMap {
|
||||||
'toggle-tool-lock': null
|
'toggle-tool-lock': null
|
||||||
'toggle-grid-mode': null
|
'toggle-grid-mode': null
|
||||||
'toggle-dark-mode': null
|
'toggle-dark-mode': null
|
||||||
|
'toggle-wrap-mode': null
|
||||||
'toggle-focus-mode': null
|
'toggle-focus-mode': null
|
||||||
'toggle-debug-mode': null
|
'toggle-debug-mode': null
|
||||||
'toggle-lock': null
|
'toggle-lock': null
|
||||||
|
|
|
@ -86,6 +86,8 @@ export type TLUiTranslationKey =
|
||||||
| 'action.toggle-auto-size'
|
| 'action.toggle-auto-size'
|
||||||
| 'action.toggle-dark-mode.menu'
|
| 'action.toggle-dark-mode.menu'
|
||||||
| 'action.toggle-dark-mode'
|
| 'action.toggle-dark-mode'
|
||||||
|
| 'action.toggle-wrap-mode.menu'
|
||||||
|
| 'action.toggle-wrap-mode'
|
||||||
| 'action.toggle-reduce-motion.menu'
|
| 'action.toggle-reduce-motion.menu'
|
||||||
| 'action.toggle-reduce-motion'
|
| 'action.toggle-reduce-motion'
|
||||||
| 'action.toggle-edge-scrolling.menu'
|
| 'action.toggle-edge-scrolling.menu'
|
||||||
|
|
|
@ -86,6 +86,8 @@ export const DEFAULT_TRANSLATION = {
|
||||||
'action.toggle-auto-size': 'Toggle auto size',
|
'action.toggle-auto-size': 'Toggle auto size',
|
||||||
'action.toggle-dark-mode.menu': 'Dark mode',
|
'action.toggle-dark-mode.menu': 'Dark mode',
|
||||||
'action.toggle-dark-mode': 'Toggle dark mode',
|
'action.toggle-dark-mode': 'Toggle dark mode',
|
||||||
|
'action.toggle-wrap-mode.menu': 'Select on wrap',
|
||||||
|
'action.toggle-wrap-mode': 'Toggle Select on wrap',
|
||||||
'action.toggle-reduce-motion.menu': 'Reduce motion',
|
'action.toggle-reduce-motion.menu': 'Reduce motion',
|
||||||
'action.toggle-reduce-motion': 'Toggle reduce motion',
|
'action.toggle-reduce-motion': 'Toggle reduce motion',
|
||||||
'action.toggle-edge-scrolling.menu': 'Edge scrolling',
|
'action.toggle-edge-scrolling.menu': 'Edge scrolling',
|
||||||
|
|
|
@ -119,6 +119,77 @@ describe('Hovering shapes', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('brushing', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
editor.createShapes([{ id: ids.box1, type: 'geo', props: { fill: 'solid', w: 50, h: 50 } }])
|
||||||
|
editor.user.updateUserPreferences({ isWrapMode: false })
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
editor.user.updateUserPreferences({ isWrapMode: false })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('brushes on wrap', () => {
|
||||||
|
editor.pointerMove(-50, -50)
|
||||||
|
editor.pointerDown()
|
||||||
|
editor.pointerMove(100, 100)
|
||||||
|
expect(editor.getSelectedShapeIds().length).toBe(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('brushes on intersection', () => {
|
||||||
|
editor.pointerMove(-50, -50)
|
||||||
|
editor.pointerDown()
|
||||||
|
editor.pointerMove(10, 10)
|
||||||
|
expect(editor.getSelectedShapeIds().length).toBe(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('brushes only on wrap when ctrl key is down', () => {
|
||||||
|
editor.pointerMove(-50, -50)
|
||||||
|
editor.pointerDown()
|
||||||
|
editor.pointerMove(10, 10)
|
||||||
|
editor.keyDown('Control')
|
||||||
|
expect(editor.getSelectedShapeIds().length).toBe(0)
|
||||||
|
editor.pointerMove(100, 100)
|
||||||
|
expect(editor.getSelectedShapeIds().length).toBe(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('brushing with wrap mode on', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
editor.createShapes([{ id: ids.box1, type: 'geo', props: { fill: 'solid', w: 50, h: 50 } }])
|
||||||
|
editor.user.updateUserPreferences({ isWrapMode: true })
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
editor.user.updateUserPreferences({ isWrapMode: false })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('brushes on wrap', () => {
|
||||||
|
editor.pointerMove(-50, -50)
|
||||||
|
editor.pointerDown()
|
||||||
|
editor.pointerMove(100, 100)
|
||||||
|
expect(editor.getSelectedShapeIds().length).toBe(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not brush on intersection', () => {
|
||||||
|
editor.pointerMove(-50, -50)
|
||||||
|
editor.pointerDown()
|
||||||
|
editor.pointerMove(10, 10)
|
||||||
|
expect(editor.getSelectedShapeIds().length).toBe(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('brushes on intersection when ctrl key is down', () => {
|
||||||
|
editor.pointerMove(-50, -50)
|
||||||
|
editor.pointerDown()
|
||||||
|
editor.pointerMove(10, 10)
|
||||||
|
expect(editor.getSelectedShapeIds().length).toBe(0)
|
||||||
|
editor.keyDown('Control')
|
||||||
|
expect(editor.getSelectedShapeIds().length).toBe(1)
|
||||||
|
editor.pointerMove(100, 100)
|
||||||
|
expect(editor.getSelectedShapeIds().length).toBe(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('when shape is filled', () => {
|
describe('when shape is filled', () => {
|
||||||
let box1: TLGeoShape
|
let box1: TLGeoShape
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -684,8 +755,8 @@ describe('when a frame has multiple children', () => {
|
||||||
editor.pointerDown()
|
editor.pointerDown()
|
||||||
editor.pointerMove(30, 30)
|
editor.pointerMove(30, 30)
|
||||||
editor.expectToBeIn('select.brushing')
|
editor.expectToBeIn('select.brushing')
|
||||||
editor.pointerUp()
|
|
||||||
expect(editor.getSelectedShapeIds()).toEqual([ids.box1])
|
expect(editor.getSelectedShapeIds()).toEqual([ids.box1])
|
||||||
|
editor.pointerUp()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('brush selects shapes when containing them in a drag from outside of the frame', () => {
|
it('brush selects shapes when containing them in a drag from outside of the frame', () => {
|
||||||
|
@ -1473,6 +1544,7 @@ describe('When double clicking an editable shape', () => {
|
||||||
|
|
||||||
describe('shift brushes to add to the selection', () => {
|
describe('shift brushes to add to the selection', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
editor.user.updateUserPreferences({ isWrapMode: false })
|
||||||
editor
|
editor
|
||||||
.createShapes([
|
.createShapes([
|
||||||
{ id: ids.box1, type: 'geo', x: 0, y: 0 },
|
{ id: ids.box1, type: 'geo', x: 0, y: 0 },
|
||||||
|
|
Loading…
Reference in a new issue