@ -55,6 +55,7 @@ import { getBoundTextElement, handleBindTextResize } from "./textElement";
import {
import {
isArrowElement ,
isArrowElement ,
isBindableElement ,
isBindableElement ,
isBindingElement ,
isBoundToContainer ,
isBoundToContainer ,
isElbowArrow ,
isElbowArrow ,
isFixedPointBinding ,
isFixedPointBinding ,
@ -1422,7 +1423,7 @@ const getLinearElementEdgeCoors = (
) ;
) ;
} ;
} ;
export const fixBindingsAfterDuplication = (
export const fixDuplicated BindingsAfterDuplication = (
newElements : ExcalidrawElement [ ] ,
newElements : ExcalidrawElement [ ] ,
oldIdToDuplicatedId : Map < ExcalidrawElement [ " id " ] , ExcalidrawElement [ " id " ] > ,
oldIdToDuplicatedId : Map < ExcalidrawElement [ " id " ] , ExcalidrawElement [ " id " ] > ,
duplicatedElementsMap : NonDeletedSceneElementsMap ,
duplicatedElementsMap : NonDeletedSceneElementsMap ,
@ -1493,6 +1494,196 @@ export const fixBindingsAfterDuplication = (
}
}
} ;
} ;
const fixReversedBindingsForBindables = (
original : ExcalidrawBindableElement ,
duplicate : ExcalidrawBindableElement ,
originalElements : Map < string , ExcalidrawElement > ,
elementsWithClones : ExcalidrawElement [ ] ,
oldIdToDuplicatedId : Map < ExcalidrawElement [ " id " ] , ExcalidrawElement [ " id " ] > ,
) = > {
original . boundElements ? . forEach ( ( binding , idx ) = > {
if ( binding . type !== "arrow" ) {
return ;
}
const oldArrow = elementsWithClones . find ( ( el ) = > el . id === binding . id ) ;
if ( ! isBindingElement ( oldArrow ) ) {
return ;
}
if ( originalElements . has ( binding . id ) ) {
// Linked arrow is in the selection, so find the duplicate pair
const newArrowId = oldIdToDuplicatedId . get ( binding . id ) ? ? binding . id ;
const newArrow = elementsWithClones . find (
( el ) = > el . id === newArrowId ,
) ! as ExcalidrawArrowElement ;
mutateElement ( newArrow , {
startBinding :
oldArrow . startBinding ? . elementId === binding . id
? {
. . . oldArrow . startBinding ,
elementId : duplicate.id ,
}
: newArrow . startBinding ,
endBinding :
oldArrow . endBinding ? . elementId === binding . id
? {
. . . oldArrow . endBinding ,
elementId : duplicate.id ,
}
: newArrow . endBinding ,
} ) ;
mutateElement ( duplicate , {
boundElements : [
. . . ( duplicate . boundElements ? ? [ ] ) . filter (
( el ) = > el . id !== binding . id && el . id !== newArrowId ,
) ,
{
type : "arrow" ,
id : newArrowId ,
} ,
] ,
} ) ;
} else {
// Linked arrow is outside the selection,
// so we move the binding to the duplicate
mutateElement ( oldArrow , {
startBinding :
oldArrow . startBinding ? . elementId === original . id
? {
. . . oldArrow . startBinding ,
elementId : duplicate.id ,
}
: oldArrow . startBinding ,
endBinding :
oldArrow . endBinding ? . elementId === original . id
? {
. . . oldArrow . endBinding ,
elementId : duplicate.id ,
}
: oldArrow . endBinding ,
} ) ;
mutateElement ( duplicate , {
boundElements : [
. . . ( duplicate . boundElements ? ? [ ] ) ,
{
type : "arrow" ,
id : oldArrow.id ,
} ,
] ,
} ) ;
mutateElement ( original , {
boundElements :
original . boundElements ? . filter ( ( _ , i ) = > i !== idx ) ? ? null ,
} ) ;
}
} ) ;
} ;
const fixReversedBindingsForArrows = (
original : ExcalidrawArrowElement ,
duplicate : ExcalidrawArrowElement ,
originalElements : Map < string , ExcalidrawElement > ,
bindingProp : "startBinding" | "endBinding" ,
oldIdToDuplicatedId : Map < ExcalidrawElement [ " id " ] , ExcalidrawElement [ " id " ] > ,
elementsWithClones : ExcalidrawElement [ ] ,
) = > {
const oldBindableId = original [ bindingProp ] ? . elementId ;
if ( oldBindableId ) {
if ( originalElements . has ( oldBindableId ) ) {
// Linked element is in the selection
const newBindableId =
oldIdToDuplicatedId . get ( oldBindableId ) ? ? oldBindableId ;
const newBindable = elementsWithClones . find (
( el ) = > el . id === newBindableId ,
) as ExcalidrawBindableElement ;
mutateElement ( duplicate , {
[ bindingProp ] : {
. . . original [ bindingProp ] ,
elementId : newBindableId ,
} ,
} ) ;
mutateElement ( newBindable , {
boundElements : [
. . . ( newBindable . boundElements ? ? [ ] ) . filter (
( el ) = > el . id !== original . id && el . id !== duplicate . id ,
) ,
{
id : duplicate.id ,
type : "arrow" ,
} ,
] ,
} ) ;
} else {
// Linked element is outside the selection
const originalBindable = elementsWithClones . find (
( el ) = > el . id === oldBindableId ,
) ;
if ( originalBindable ) {
mutateElement ( duplicate , {
[ bindingProp ] : original [ bindingProp ] ,
} ) ;
mutateElement ( original , {
[ bindingProp ] : null ,
} ) ;
mutateElement ( originalBindable , {
boundElements : [
. . . ( originalBindable . boundElements ? . filter (
( el ) = > el . id !== original . id ,
) ? ? [ ] ) ,
{
id : duplicate.id ,
type : "arrow" ,
} ,
] ,
} ) ;
}
}
}
} ;
export const fixReversedBindings = (
originalElements : Map < string , ExcalidrawElement > ,
elementsWithClones : ExcalidrawElement [ ] ,
oldIdToDuplicatedId : Map < ExcalidrawElement [ " id " ] , ExcalidrawElement [ " id " ] > ,
) = > {
for ( const original of originalElements . values ( ) ) {
const duplicate = elementsWithClones . find (
( el ) = > el . id === oldIdToDuplicatedId . get ( original . id ) ,
) ! ;
if ( isBindableElement ( original ) && isBindableElement ( duplicate ) ) {
fixReversedBindingsForBindables (
original ,
duplicate ,
originalElements ,
elementsWithClones ,
oldIdToDuplicatedId ,
) ;
} else if ( isArrowElement ( original ) && isArrowElement ( duplicate ) ) {
fixReversedBindingsForArrows (
original ,
duplicate ,
originalElements ,
"startBinding" ,
oldIdToDuplicatedId ,
elementsWithClones ,
) ;
fixReversedBindingsForArrows (
original ,
duplicate ,
originalElements ,
"endBinding" ,
oldIdToDuplicatedId ,
elementsWithClones ,
) ;
}
}
} ;
export const fixBindingsAfterDeletion = (
export const fixBindingsAfterDeletion = (
sceneElements : readonly ExcalidrawElement [ ] ,
sceneElements : readonly ExcalidrawElement [ ] ,
deletedElements : readonly ExcalidrawElement [ ] ,
deletedElements : readonly ExcalidrawElement [ ] ,