Cleanup page state commands (#1800)

This PR cleans up some APIs around the editor's current page state:

- `setEditingShapeId` -> `setEditingShape`
- `setHoveredShapeId` -> `setHoveredShape`
- `setCroppingShapeId` -> `setCroppingShape`
- `setFocusedGroupId` -> `setFocusedGroup`
- `setErasingShapeIds` -> `setErasingShapes`
- `setHintingShapeIds` -> `setHintingShapes`

It also adds some additional computed getters, e.g.
`Editor.croppingShape`.

It also adds some errors around `setCroppingShape`.

### Change Type

- [x] `major` — Breaking change

### Test Plan

- [x] Unit Tests
This commit is contained in:
Steve Ruiz 2023-08-06 13:05:35 +01:00 committed by GitHub
parent eabb0d52f8
commit 13ef8be58d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 252 additions and 125 deletions

View file

@ -627,9 +627,11 @@ export class Editor extends EventEmitter<TLEventMap> {
duplicateShapes(shapes: TLShape[], offset?: VecLike): this;
// (undocumented)
duplicateShapes(ids: TLShapeId[], offset?: VecLike): this;
get editingShape(): TLShape | undefined;
get editingShapeId(): null | TLShapeId;
readonly environment: EnvironmentManager;
get erasingShapeIds(): TLShapeId[];
get erasingShapes(): NonNullable<TLShape | undefined>[];
// @internal (undocumented)
externalAssetContentHandlers: {
[K in TLExternalAssetContent_2['type']]: {
@ -655,6 +657,7 @@ export class Editor extends EventEmitter<TLEventMap> {
flipShapes(shapes: TLShape[], operation: 'horizontal' | 'vertical'): this;
// (undocumented)
flipShapes(ids: TLShapeId[], operation: 'horizontal' | 'vertical'): this;
get focusedGroup(): TLShape | undefined;
get focusedGroupId(): TLPageId | TLShapeId;
getAncestorPageId(shape?: TLShape): TLPageId | undefined;
// (undocumented)
@ -773,8 +776,9 @@ export class Editor extends EventEmitter<TLEventMap> {
// (undocumented)
hasAncestor(shapeId: TLShapeId | undefined, ancestorId: TLShapeId): boolean;
get hintingShapeIds(): TLShapeId[];
get hintingShapes(): NonNullable<TLShape | undefined>[];
readonly history: HistoryManager<this>;
get hoveredShape(): TLUnknownShape | undefined;
get hoveredShape(): TLShape | undefined;
get hoveredShapeId(): null | TLShapeId;
inputs: {
originPagePoint: Vec2d;
@ -843,7 +847,7 @@ export class Editor extends EventEmitter<TLEventMap> {
};
pan(offset: VecLike, animation?: TLAnimationOptions): this;
panZoomIntoView(ids: TLShapeId[], animation?: TLAnimationOptions): this;
popFocusLayer(): this;
popFocusedGroupId(): this;
putContentOntoCurrentPage(content: TLContent, options?: {
point?: VecLike;
select?: boolean;
@ -907,17 +911,29 @@ export class Editor extends EventEmitter<TLEventMap> {
// (undocumented)
sendToBack(ids: TLShapeId[]): this;
setCamera(point: VecLike, animation?: TLAnimationOptions): this;
setCroppingShapeId(id: null | TLShapeId): this;
setCroppingShape(shape: null | TLShape): this;
// (undocumented)
setCroppingShape(id: null | TLShapeId): this;
setCurrentPage(page: TLPage, historyOptions?: TLCommandHistoryOptions): this;
// (undocumented)
setCurrentPage(pageId: TLPageId, historyOptions?: TLCommandHistoryOptions): this;
setCurrentTool(id: string, info?: {}): this;
setCursor: (cursor: Partial<TLCursor>) => this;
setEditingShapeId(id: null | TLShapeId): this;
setErasingShapeIds(ids: TLShapeId[]): this;
setFocusedGroupId(next: null | TLShapeId): this;
setHintingIds(ids: TLShapeId[]): this;
setHoveredShapeId(id: null | TLShapeId): this;
setEditingShape(shape: null | TLShape): this;
// (undocumented)
setEditingShape(id: null | TLShapeId): this;
setErasingShapes(shapes: TLShape[]): this;
// (undocumented)
setErasingShapes(ids: TLShapeId[]): this;
setFocusedGroup(shape: null | TLGroupShape): this;
// (undocumented)
setFocusedGroup(id: null | TLShapeId): this;
setHintingShapes(shapes: TLShape[]): this;
// (undocumented)
setHintingShapes(ids: TLShapeId[]): this;
setHoveredShape(shape: null | TLShape): this;
// (undocumented)
setHoveredShape(id: null | TLShapeId): this;
setOpacity(opacity: number, historyOptions?: TLCommandHistoryOptions): this;
setSelectedShapeIds(ids: TLShapeId[], historyOptions?: TLCommandHistoryOptions): this;
setStyle<T>(style: StyleProp<T>, value: T, historyOptions?: TLCommandHistoryOptions): this;

View file

@ -1677,26 +1677,54 @@ export class Editor extends EventEmitter<TLEventMap> {
return boxFromRotatedVertices
}
// Focus Layer Id
// Focus Group
/**
* The shape id of the current focus layer. Null when the focus layer id is the current page.
* The current focused group id.
*
* @public
*/
get focusedGroupId(): TLShapeId | TLPageId {
@computed get focusedGroupId(): TLShapeId | TLPageId {
return this.currentPageState.focusedGroupId ?? this.currentPageId
}
/**
* Set the current focus layer id.
*
* @param next - The shape id (or page id) to set as the focus layer id.
* The current focused group.
*
* @public
*/
setFocusedGroupId(next: TLShapeId | null): this {
this._setFocusedGroupId(next)
@computed get focusedGroup(): TLShape | undefined {
const { focusedGroupId } = this
return focusedGroupId ? this.getShape(focusedGroupId) : undefined
}
/**
* Set the current focused group shape.
*
* @param shape - The group shape id (or group shape's id) to set as the focused group shape.
*
* @public
*/
setFocusedGroup(shape: TLGroupShape | null): this
setFocusedGroup(id: TLShapeId | null): this
setFocusedGroup(arg: TLShapeId | TLGroupShape | null): this {
const id = typeof arg === 'string' ? arg : arg?.id ?? null
if (id !== null) {
const shape = typeof arg === 'string' ? this.getShape(arg) : arg
if (!shape) {
throw Error(`Editor.setFocusedGroup: Shape with id ${id} does not exist`)
}
if (!this.isShapeOfType<TLGroupShape>(shape, 'group')) {
throw Error(
`Editor.setFocusedGroup: Cannot set focused group to shape of type ${shape.type}`
)
}
}
if (id === this.focusedGroupId) return this
this._setFocusedGroupId(id)
return this
}
@ -1704,11 +1732,8 @@ export class Editor extends EventEmitter<TLEventMap> {
private _setFocusedGroupId = this.history.createCommand(
'setFocusedGroupId',
(next: TLShapeId | null) => {
// When we first click an empty canvas we don't want this to show up in the undo stack
if (!next && !this.canUndo) {
return
}
const prev = this.currentPageState.focusedGroupId
if (prev === next) return
return {
data: {
prev,
@ -1732,25 +1757,24 @@ export class Editor extends EventEmitter<TLEventMap> {
)
/**
* Exit the current focus layer, moving up to the next group if there is one.
* Exit the current focused group, moving up to the next parent group if there is one.
*
* @public
*/
popFocusLayer(): this {
const current = this.currentPageState.focusedGroupId
const focusedShape = current && this.getShape(current)
popFocusedGroupId(): this {
const { focusedGroup } = this
if (focusedShape) {
if (focusedGroup) {
// If we have a focused layer, look for an ancestor of the focused shape that is a group
const match = this.findShapeAncestor(focusedShape, (shape) =>
const match = this.findShapeAncestor(focusedGroup, (shape) =>
this.isShapeOfType<TLGroupShape>(shape, 'group')
)
// If we have an ancestor that can become a focused layer, set it as the focused layer
this.setFocusedGroupId(match?.id ?? null)
this.select(focusedShape.id)
this.setFocusedGroup(match?.id ?? null)
this.select(focusedGroup.id)
} else {
// If there's no focused shape, then clear the focus layer and clear selection
this.setFocusedGroupId(null)
// If there's no parent focused group, then clear the focus layer and clear selection
this.setFocusedGroup(null)
this.selectNone()
}
@ -1762,18 +1786,37 @@ export class Editor extends EventEmitter<TLEventMap> {
*
* @public
*/
get editingShapeId() {
@computed get editingShapeId() {
return this.currentPageState.editingShapeId
}
/**
* Set the current editing shape id.
*
* @param id - The shape id to set as editing.
* The current editing shape.
*
* @public
*/
setEditingShapeId(id: TLShapeId | null): this {
@computed get editingShape(): TLShape | undefined {
const { editingShapeId } = this
return editingShapeId ? this.getShape(editingShapeId) : undefined
}
/**
* Set the current editing shape.
*
* @example
* ```ts
* editor.setEditingShape(myShape)
* editor.setEditingShape(myShape.id)
* ```
*
* @param shapes - The shape (or shape id) to set as editing.
*
* @public
*/
setEditingShape(shape: TLShape | null): this
setEditingShape(id: TLShapeId | null): this
setEditingShape(arg: TLShapeId | TLShape | null): this {
const id = typeof arg === 'string' ? arg : arg?.id ?? null
if (!id) {
this._setInstancePageState({ editingShapeId: null })
} else {
@ -1788,7 +1831,7 @@ export class Editor extends EventEmitter<TLEventMap> {
return this
}
// Hovered Id
// Hovered
/**
* The current hovered shape id.
@ -1801,28 +1844,38 @@ export class Editor extends EventEmitter<TLEventMap> {
}
/**
* Set the editor's current hovered shape id.
*
* @param id - The shape id to set as hovered.
* The current hovered shape.
*
* @public
*/
setHoveredShapeId(id: TLShapeId | null): this {
if (id === this.currentPageState.hoveredShapeId) return this
@computed get hoveredShape(): TLShape | undefined {
const { hoveredShapeId } = this
return hoveredShapeId ? this.getShape(hoveredShapeId) : undefined
}
/**
* Set the editor's current hovered shape.
*
* @example
* ```ts
* editor.setHoveredShape(myShape)
* editor.setHoveredShape(myShape.id)
* ```
*
* @param shapes - The shape (or shape id) to set as hovered.
*
* @public
*/
setHoveredShape(shape: TLShape | null): this
setHoveredShape(id: TLShapeId | null): this
setHoveredShape(arg: TLShapeId | TLShape | null): this {
const id = typeof arg === 'string' ? arg : arg?.id ?? null
if (id === this.hoveredShapeId) return this
this.updateCurrentPageState({ hoveredShapeId: id }, { ephemeral: true })
return this
}
/**
* The editor's current hovered shape.
*
* @public
*/
@computed get hoveredShape() {
return this.hoveredShapeId ? this.getShape(this.hoveredShapeId) : undefined
}
// Hinting ids
// Hinting
/**
* The editor's current hinting shape ids.
@ -1834,18 +1887,42 @@ export class Editor extends EventEmitter<TLEventMap> {
}
/**
* Set the editor's current hinting shape ids.
*
* @param ids - The shape ids to set as hinting.
* The editor's current hinting shapes.
*
* @public
*/
setHintingIds(ids: TLShapeId[]): this {
@computed get hintingShapes() {
const { hintingShapeIds } = this
return compact(hintingShapeIds.map((id) => this.getShape(id)))
}
/**
* Set the editor's current hinting shapes.
*
* @example
* ```ts
* editor.setHintingShapes([myShape])
* editor.setHintingShapes([myShape.id])
* ```
*
* @param shapes - The shapes (or shape ids) to set as hinting.
*
* @public
*/
setHintingShapes(shapes: TLShape[]): this
setHintingShapes(ids: TLShapeId[]): this
setHintingShapes(arg: TLShapeId[] | TLShape[]): this {
const ids =
typeof arg[0] === 'string'
? (arg as TLShapeId[])
: (arg as TLShape[]).map((shape) => shape.id)
// always ephemeral
this.updateCurrentPageState({ hintingShapeIds: dedupe(ids) }, { ephemeral: true })
return this
}
// Erasing
/**
* The editor's current erasing ids.
*
@ -1856,13 +1933,35 @@ export class Editor extends EventEmitter<TLEventMap> {
}
/**
* Set the editor's current erasing shape ids.
*
* @param ids - The shape ids to set as erasing.
* The editor's current hinting shapes.
*
* @public
*/
setErasingShapeIds(ids: TLShapeId[]): this {
@computed get erasingShapes() {
const { erasingShapeIds } = this
return compact(erasingShapeIds.map((id) => this.getShape(id)))
}
/**
* Set the editor's current erasing shapes.
*
* @example
* ```ts
* editor.setErasingShapes([myShape])
* editor.setErasingShapes([myShape.id])
* ```
*
* @param shapes - The shapes (or shape ids) to set as hinting.
*
* @public
*/
setErasingShapes(shapes: TLShape[]): this
setErasingShapes(ids: TLShapeId[]): this
setErasingShapes(arg: TLShapeId[] | TLShape[]): this {
const ids =
typeof arg[0] === 'string'
? (arg as TLShapeId[])
: (arg as TLShape[]).map((shape) => shape.id)
ids.sort() // sort the incoming ids
const { erasingShapeIds } = this
if (ids.length === erasingShapeIds.length) {
@ -1883,6 +1982,8 @@ export class Editor extends EventEmitter<TLEventMap> {
return this
}
// Cropping
/**
* The current cropping shape's id.
*
@ -1893,13 +1994,23 @@ export class Editor extends EventEmitter<TLEventMap> {
}
/**
* Set the current cropping shape id.
* Set the current cropping shape.
*
* @param id - The shape id to set as cropping.
* @example
* ```ts
* editor.setCroppingShape(myShape)
* editor.setCroppingShape(myShape.id)
* ```
*
*
* @param shape - The shape (or shape id) to set as cropping.
*
* @public
*/
setCroppingShapeId(id: TLShapeId | null): this {
setCroppingShape(shape: TLShape | null): this
setCroppingShape(id: TLShapeId | null): this
setCroppingShape(arg: TLShapeId | TLShape | null): this {
const id = typeof arg === 'string' ? arg : arg?.id ?? null
if (id !== this.croppingShapeId) {
if (!id) {
this.updateCurrentPageState({ croppingShapeId: null })
@ -5252,7 +5363,7 @@ export class Editor extends EventEmitter<TLEventMap> {
// Put the shape content onto the new page; parents and indices will
// be taken care of by the putContent method; make sure to pop any focus
// layers so that the content will be put onto the page.
this.setFocusedGroupId(null)
this.setFocusedGroup(null)
this.selectNone()
this.putContentOntoCurrentPage(content, {
select: true,

View file

@ -101,13 +101,13 @@ export class GroupShapeUtil extends ShapeUtil<TLGroupShape> {
const children = this.editor.getSortedChildIdsForParent(group.id)
if (children.length === 0) {
if (this.editor.currentPageState.focusedGroupId === group.id) {
this.editor.popFocusLayer()
this.editor.popFocusedGroupId()
}
this.editor.deleteShapes([group.id])
return
} else if (children.length === 1) {
if (this.editor.currentPageState.focusedGroupId === group.id) {
this.editor.popFocusLayer()
this.editor.popFocusedGroupId()
}
this.editor.reparentShapes(children, group.parentId)
this.editor.deleteShapes([group.id])

View file

@ -19,7 +19,7 @@ export class Pointing extends StateNode {
if (!target) {
this.createArrowShape()
} else {
this.editor.setHintingIds([target.id])
this.editor.setHintingShapes([target.id])
}
this.startPreciseTimeout()
@ -27,7 +27,7 @@ export class Pointing extends StateNode {
override onExit = () => {
this.shape = undefined
this.editor.setHintingIds([])
this.editor.setHintingShapes([])
this.clearPreciseTimeout()
}
@ -71,7 +71,7 @@ export class Pointing extends StateNode {
// the arrow might not have been created yet!
this.editor.bailToMark(this.markId)
}
this.editor.setHintingIds([])
this.editor.setHintingShapes([])
this.parent.transition('idle', {})
}
@ -108,7 +108,7 @@ export class Pointing extends StateNode {
if (change) {
const startTerminal = change.props?.start
if (startTerminal?.type === 'binding') {
this.editor.setHintingIds([startTerminal.boundShapeId])
this.editor.setHintingShapes([startTerminal.boundShapeId])
}
this.editor.updateShapes([change], { squashing: true })
}
@ -138,7 +138,7 @@ export class Pointing extends StateNode {
if (change) {
const endTerminal = change.props?.end
if (endTerminal?.type === 'binding') {
this.editor.setHintingIds([endTerminal.boundShapeId])
this.editor.setHintingShapes([endTerminal.boundShapeId])
}
this.editor.updateShapes([change], { squashing: true })
}

View file

@ -15,7 +15,7 @@ export const FrameLabelInput = forwardRef<
// and sending us back into edit mode
e.stopPropagation()
e.currentTarget.blur()
editor.setEditingShapeId(null)
editor.setEditingShape(null)
}
},
[editor]

View file

@ -17,7 +17,7 @@ export class Idle extends StateNode {
if (shape && this.editor.isShapeOfType<TLGeoShape>(shape, 'geo')) {
// todo: ensure that this only works with the most recently created shape, not just any geo shape that happens to be selected at the time
this.editor.mark('editing shape')
this.editor.setEditingShapeId(shape.id)
this.editor.setEditingShape(shape.id)
this.editor.setCurrentTool('select.editing_shape', {
...info,
target: 'shape',

View file

@ -65,7 +65,7 @@ export class Pointing extends StateNode {
if (this.editor.instanceState.isToolLocked) {
this.parent.transition('idle', {})
} else {
this.editor.setEditingShapeId(this.shape.id)
this.editor.setEditingShape(this.shape.id)
this.editor.setCurrentTool('select.editing_shape', {
...this.info,
target: 'shape',

View file

@ -211,8 +211,8 @@ export function useEditableText<T extends Extract<TLShape, { props: { text: stri
(e: React.PointerEvent) => {
if (isEditableFromHover) {
transact(() => {
editor.setEditingShapeId(id)
editor.setHoveredShapeId(id)
editor.setEditingShape(id)
editor.setHoveredShape(id)
editor.setSelectedShapeIds([id])
})
}

View file

@ -23,7 +23,7 @@ export class Idle extends StateNode {
if (this.editor.isShapeOfType<TLTextShape>(hitShape, 'text')) {
requestAnimationFrame(() => {
this.editor.setSelectedShapeIds([hitShape.id])
this.editor.setEditingShapeId(hitShape.id)
this.editor.setEditingShape(hitShape.id)
this.editor.setCurrentTool('select.editing_shape', {
...info,
target: 'shape',
@ -46,7 +46,7 @@ export class Idle extends StateNode {
const shape = this.editor.selectedShapes[0]
if (shape && this.editor.isShapeOfType<TLGeoShape>(shape, 'geo')) {
this.editor.setCurrentTool('select')
this.editor.setEditingShapeId(shape.id)
this.editor.setEditingShape(shape.id)
this.editor.root.current.value!.transition('editing_shape', {
...info,
target: 'shape',

View file

@ -8,7 +8,7 @@ export class Pointing extends StateNode {
markId = ''
override onExit = () => {
this.editor.setHintingIds([])
this.editor.setHintingShapes([])
}
override onPointerMove: TLEventHandlers['onPointerMove'] = (info) => {
@ -88,7 +88,7 @@ export class Pointing extends StateNode {
])
.select(id)
this.editor.setEditingShapeId(id)
this.editor.setEditingShape(id)
this.editor.setCurrentTool('select')
this.editor.root.current.value?.transition('editing_shape', {})
}

View file

@ -129,17 +129,17 @@ export class Erasing extends StateNode {
// Remove the hit shapes, except if they're in the list of excluded shapes
// (these excluded shapes will be any frames or groups the pointer was inside of
// when the user started erasing)
this.editor.setErasingShapeIds([...erasing].filter((id) => !excludedShapeIds.has(id)))
this.editor.setErasingShapes([...erasing].filter((id) => !excludedShapeIds.has(id)))
}
complete() {
this.editor.deleteShapes(this.editor.currentPageState.erasingShapeIds)
this.editor.setErasingShapeIds([])
this.editor.setErasingShapes([])
this.parent.transition('idle', {})
}
cancel() {
this.editor.setErasingShapeIds([])
this.editor.setErasingShapes([])
this.editor.bailToMark(this.markId)
this.parent.transition('idle', this.info)
}

View file

@ -46,7 +46,7 @@ export class Pointing extends StateNode {
}
}
this.editor.setErasingShapeIds([...erasing])
this.editor.setErasingShapes([...erasing])
}
override onPointerMove: TLEventHandlers['onPointerMove'] = (info) => {
@ -79,12 +79,12 @@ export class Pointing extends StateNode {
this.editor.deleteShapes(erasingShapeIds)
}
this.editor.setErasingShapeIds([])
this.editor.setErasingShapes([])
this.parent.transition('idle', {})
}
cancel() {
this.editor.setErasingShapeIds([])
this.editor.setErasingShapes([])
this.parent.transition('idle', {})
}
}

View file

@ -72,11 +72,11 @@ export class DragAndDropManager {
.onDragShapesOver?.(nextDroppingShape, movingShapes)
if (res && res.shouldHint) {
this.editor.setHintingIds([nextDroppingShape.id])
this.editor.setHintingShapes([nextDroppingShape.id])
}
} else {
// If we're dropping onto the page, then clear hinting ids
this.editor.setHintingIds([])
this.editor.setHintingShapes([])
}
cb?.()
@ -103,7 +103,7 @@ export class DragAndDropManager {
}
this.droppingNodeTimer = null
this.editor.setHintingIds([])
this.editor.setHintingShapes([])
}
dispose = () => {

View file

@ -43,7 +43,7 @@ export class SelectTool extends StateNode {
override onExit = () => {
if (this.editor.currentPageState.editingShapeId) {
this.editor.setEditingShapeId(null)
this.editor.setEditingShape(null)
}
}
}

View file

@ -20,7 +20,7 @@ export class Idle extends StateNode {
if (onlySelectedShape) {
this.editor.mark('crop')
this.editor.setCroppingShapeId(onlySelectedShape.id)
this.editor.setCroppingShape(onlySelectedShape.id)
}
}
@ -34,7 +34,7 @@ export class Idle extends StateNode {
}
override onCancel: TLEventHandlers['onCancel'] = () => {
this.editor.setCroppingShapeId(null)
this.editor.setCroppingShape(null)
this.editor.setCurrentTool('select.idle', {})
}
@ -71,7 +71,7 @@ export class Idle extends StateNode {
return
} else {
if (this.editor.getShapeUtil(info.shape)?.canCrop(info.shape)) {
this.editor.setCroppingShapeId(info.shape.id)
this.editor.setCroppingShape(info.shape.id)
this.editor.setSelectedShapeIds([info.shape.id])
this.editor.setCurrentTool('select.crop.pointing_crop', info)
} else {
@ -152,7 +152,7 @@ export class Idle extends StateNode {
override onKeyUp: TLEventHandlers['onKeyUp'] = (info) => {
switch (info.code) {
case 'Enter': {
this.editor.setCroppingShapeId(null)
this.editor.setCroppingShape(null)
this.editor.setCurrentTool('select.idle', {})
break
}
@ -160,7 +160,7 @@ export class Idle extends StateNode {
}
private cancel() {
this.editor.setCroppingShapeId(null)
this.editor.setCroppingShape(null)
this.editor.setCurrentTool('select.idle', {})
}

View file

@ -208,7 +208,7 @@ export class Cropping extends StateNode {
if (this.info.onInteractionEnd) {
this.editor.setCurrentTool(this.info.onInteractionEnd, this.info)
} else {
this.editor.setCroppingShapeId(null)
this.editor.setCroppingShape(null)
this.parent.transition('idle', {})
}
}
@ -218,7 +218,7 @@ export class Cropping extends StateNode {
if (this.info.onInteractionEnd) {
this.editor.setCurrentTool(this.info.onInteractionEnd, this.info)
} else {
this.editor.setCroppingShapeId(null)
this.editor.setCroppingShape(null)
this.parent.transition('idle', {})
}
}

View file

@ -96,7 +96,7 @@ export class DraggingHandle extends StateNode {
this.isPrecise = false
if (initialTerminal?.type === 'binding') {
this.editor.setHintingIds([initialTerminal.boundShapeId])
this.editor.setHintingShapes([initialTerminal.boundShapeId])
this.isPrecise = !Vec2d.Equals(initialTerminal.normalizedAnchor, { x: 0.5, y: 0.5 })
if (this.isPrecise) {
@ -105,7 +105,7 @@ export class DraggingHandle extends StateNode {
this.resetExactTimeout()
}
} else {
this.editor.setHintingIds([])
this.editor.setHintingShapes([])
}
// -->
@ -167,7 +167,7 @@ export class DraggingHandle extends StateNode {
override onExit = () => {
this.parent.currentToolIdMask = undefined
this.editor.setHintingIds([])
this.editor.setHintingShapes([])
this.editor.snaps.clear()
this.editor.updateInstanceState(
{ cursor: { type: 'default', rotation: 0 } },
@ -284,7 +284,7 @@ export class DraggingHandle extends StateNode {
if (bindingAfter?.type === 'binding') {
if (hintingShapeIds[0] !== bindingAfter.boundShapeId) {
editor.setHintingIds([bindingAfter.boundShapeId])
editor.setHintingShapes([bindingAfter.boundShapeId])
this.pointingId = bindingAfter.boundShapeId
this.isPrecise = pointerVelocity.len() < 0.5 || altKey
this.isPreciseId = this.isPrecise ? bindingAfter.boundShapeId : null
@ -292,7 +292,7 @@ export class DraggingHandle extends StateNode {
}
} else {
if (hintingShapeIds.length > 0) {
editor.setHintingIds([])
editor.setHintingShapes([])
this.pointingId = null
this.isPrecise = false
this.isPreciseId = null

View file

@ -19,7 +19,7 @@ export class EditingShape extends StateNode {
if (!editingShapeId) return
// Clear the editing shape
this.editor.setEditingShapeId(null)
this.editor.setEditingShape(null)
const shape = this.editor.getShape(editingShapeId)!
const util = this.editor.getShapeUtil(shape)

View file

@ -349,7 +349,7 @@ export class Idle extends StateNode {
this.editor.focusedGroupId !== this.editor.currentPageId &&
this.editor.selectedShapeIds.length > 0
) {
this.editor.popFocusLayer()
this.editor.popFocusedGroupId()
} else {
this.editor.mark('clearing selection')
this.editor.selectNone()
@ -441,7 +441,7 @@ export class Idle extends StateNode {
private startEditingShape(shape: TLShape, info: TLClickEventInfo | TLKeyboardEventInfo) {
if (this.editor.isShapeOrAncestorLocked(shape) && shape.type !== 'embed') return
this.editor.mark('editing shape')
this.editor.setEditingShapeId(shape.id)
this.editor.setEditingShape(shape.id)
this.parent.transition('editing_shape', info)
}
@ -470,7 +470,7 @@ export class Idle extends StateNode {
const shape = this.editor.getShape(id)
if (!shape) return
this.editor.setEditingShapeId(id)
this.editor.setEditingShape(id)
this.editor.select(id)
this.parent.transition('editing_shape', info)
}

View file

@ -29,7 +29,7 @@ export class PointingCropHandle extends StateNode {
if (!selectedShape) return
this.updateCursor(selectedShape)
this.editor.setCroppingShapeId(selectedShape.id)
this.editor.setCroppingShape(selectedShape.id)
}
override onExit = () => {
@ -55,7 +55,7 @@ export class PointingCropHandle extends StateNode {
if (this.info.onInteractionEnd) {
this.editor.setCurrentTool(this.info.onInteractionEnd, this.info)
} else {
this.editor.setCroppingShapeId(null)
this.editor.setCroppingShape(null)
this.parent.transition('idle', {})
}
}
@ -76,7 +76,7 @@ export class PointingCropHandle extends StateNode {
if (this.info.onInteractionEnd) {
this.editor.setCurrentTool(this.info.onInteractionEnd, this.info)
} else {
this.editor.setCroppingShapeId(null)
this.editor.setCroppingShape(null)
this.parent.transition('idle', {})
}
}

View file

@ -11,7 +11,7 @@ export class PointingHandle extends StateNode {
const initialTerminal = (info.shape as TLArrowShape).props[info.handle.id as 'start' | 'end']
if (initialTerminal?.type === 'binding') {
this.editor.setHintingIds([initialTerminal.boundShapeId])
this.editor.setHintingShapes([initialTerminal.boundShapeId])
}
this.editor.updateInstanceState(
@ -21,7 +21,7 @@ export class PointingHandle extends StateNode {
}
override onExit = () => {
this.editor.setHintingIds([])
this.editor.setHintingShapes([])
this.editor.updateInstanceState(
{ cursor: { type: 'default', rotation: 0 } },
{ ephemeral: true }

View file

@ -94,7 +94,7 @@ export class PointingShape extends StateNode {
this.editor.mark('clearing shape ids')
this.editor.setSelectedShapeIds([])
} else {
this.editor.popFocusLayer()
this.editor.popFocusedGroupId()
}
this.parent.transition('idle', info)
return

View file

@ -108,7 +108,7 @@ export class Resizing extends StateNode {
this.handleResizeEnd()
if (this.editAfterComplete && this.editor.onlySelectedShape) {
this.editor.setEditingShapeId(this.editor.onlySelectedShape.id)
this.editor.setEditingShape(this.editor.onlySelectedShape.id)
this.editor.setCurrentTool('select')
this.editor.root.current.value!.transition('editing_shape', {})
return

View file

@ -152,7 +152,7 @@ export class Translating extends StateNode {
if (this.editAfterComplete) {
const onlySelected = this.editor.onlySelectedShape
if (onlySelected) {
this.editor.setEditingShapeId(onlySelected.id)
this.editor.setEditingShape(onlySelected.id)
this.editor.setCurrentTool('select')
this.editor.root.current.value!.transition('editing_shape', {})
}

View file

@ -83,7 +83,7 @@ export function selectOnCanvasPointerUp(editor: Editor) {
if (isShapeId(focusedGroupId)) {
const groupShape = editor.getShape(focusedGroupId)!
if (!editor.isPointInShape(groupShape, currentPagePoint, { margin: 0, hitInside: true })) {
editor.setFocusedGroupId(null)
editor.setFocusedGroup(null)
}
}
}

View file

@ -7,7 +7,7 @@ export function updateHoveredId(editor: Editor) {
margin: HIT_TEST_MARGIN / editor.zoomLevel,
})
if (!hitShape) return editor.setHoveredShapeId(null)
if (!hitShape) return editor.setHoveredShape(null)
let shapeToHover: TLShape | undefined = undefined
@ -26,5 +26,5 @@ export function updateHoveredId(editor: Editor) {
}
}
return editor.setHoveredShapeId(shapeToHover.id)
return editor.setHoveredShape(shapeToHover.id)
}

View file

@ -45,7 +45,7 @@ const moveShapesToPage2 = () => {
describe('shapes that are moved to another page', () => {
it("should be excluded from the previous page's focusedGroupId", () => {
editor.setFocusedGroupId(ids.group1)
editor.setFocusedGroup(ids.group1)
expect(editor.focusedGroupId).toBe(ids.group1)
moveShapesToPage2()
expect(editor.focusedGroupId).toBe(editor.currentPageId)
@ -53,13 +53,13 @@ describe('shapes that are moved to another page', () => {
describe("should be excluded from the previous page's hintingShapeIds", () => {
test('[boxes]', () => {
editor.setHintingIds([ids.box1, ids.box2, ids.box3])
editor.setHintingShapes([ids.box1, ids.box2, ids.box3])
expect(editor.hintingShapeIds).toEqual([ids.box1, ids.box2, ids.box3])
moveShapesToPage2()
expect(editor.hintingShapeIds).toEqual([])
})
test('[frame that does not move]', () => {
editor.setHintingIds([ids.frame1])
editor.setHintingShapes([ids.frame1])
expect(editor.hintingShapeIds).toEqual([ids.frame1])
moveShapesToPage2()
expect(editor.hintingShapeIds).toEqual([ids.frame1])
@ -68,25 +68,25 @@ describe('shapes that are moved to another page', () => {
describe("should be excluded from the previous page's editingShapeId", () => {
test('[root shape]', () => {
editor.setEditingShapeId(ids.box1)
editor.setEditingShape(ids.box1)
expect(editor.editingShapeId).toBe(ids.box1)
moveShapesToPage2()
expect(editor.editingShapeId).toBe(null)
})
test('[child of frame]', () => {
editor.setEditingShapeId(ids.box2)
editor.setEditingShape(ids.box2)
expect(editor.editingShapeId).toBe(ids.box2)
moveShapesToPage2()
expect(editor.editingShapeId).toBe(null)
})
test('[child of group]', () => {
editor.setEditingShapeId(ids.box3)
editor.setEditingShape(ids.box3)
expect(editor.editingShapeId).toBe(ids.box3)
moveShapesToPage2()
expect(editor.editingShapeId).toBe(null)
})
test('[frame that doesnt move]', () => {
editor.setEditingShapeId(ids.frame1)
editor.setEditingShape(ids.frame1)
expect(editor.editingShapeId).toBe(ids.frame1)
moveShapesToPage2()
expect(editor.editingShapeId).toBe(ids.frame1)
@ -95,13 +95,13 @@ describe('shapes that are moved to another page', () => {
describe("should be excluded from the previous page's erasingShapeIds", () => {
test('[boxes]', () => {
editor.setErasingShapeIds([ids.box1, ids.box2, ids.box3])
editor.setErasingShapes([ids.box1, ids.box2, ids.box3])
expect(editor.erasingShapeIds).toEqual([ids.box1, ids.box2, ids.box3])
moveShapesToPage2()
expect(editor.erasingShapeIds).toEqual([])
})
test('[frame that does not move]', () => {
editor.setErasingShapeIds([ids.frame1])
editor.setErasingShapes([ids.frame1])
expect(editor.erasingShapeIds).toEqual([ids.frame1])
moveShapesToPage2()
expect(editor.erasingShapeIds).toEqual([ids.frame1])