@@ -5,27 +5,90 @@ const TARGET_LINE_HALF_HEIGHT = 25
5
5
const TEXT_BOX_HORIZONTAL_PADDING = - 24
6
6
const DEBUG = false
7
7
8
+ let animationTimer = 0
9
+
8
10
export function setTargetLine (
9
11
offsetWidth : string ,
10
12
offsetLeft : number ,
11
13
targetLineElem : HTMLElement ,
12
14
targetBlockElem : HTMLElement ,
13
- lastTargetBlockElem : HTMLElement | null ,
15
+ lastTargetBlock : {
16
+ boundingBox ?: DOMRect
17
+ elem : HTMLElement | null
18
+ isBelow : boolean
19
+ } ,
14
20
mouseY : number ,
15
21
anchorElem : HTMLElement ,
16
22
event : DragEvent ,
17
23
debugHighlightRef : React . RefObject < HTMLDivElement > ,
18
24
isFoundNodeEmptyParagraph : boolean = false ,
19
25
) {
20
26
const { height : targetBlockElemHeight , top : targetBlockElemTop } =
21
- getBoundingClientRectWithoutTransform ( targetBlockElem )
27
+ targetBlockElem . getBoundingClientRect ( ) // used to be getBoundingClientRectWithoutTransform. Not sure what's better, but the normal getBoundingClientRect seems to work fine
22
28
const { top : anchorTop , width : anchorWidth } = anchorElem . getBoundingClientRect ( )
23
29
24
30
const { marginBottom, marginTop } = getCollapsedMargins ( targetBlockElem )
25
31
let lineTop = targetBlockElemTop
26
32
27
33
const isBelow = mouseY >= targetBlockElemTop + targetBlockElemHeight / 2 + window . scrollY
34
+
35
+ let willStayInSamePosition = false
36
+
37
+ /**
38
+ * Do not run any transform or changes if the actual new line position would be the same (even if it's now inserted BEFORE rather than AFTER - position would still be the same)
39
+ * This prevents unnecessary flickering.
40
+ *
41
+ * We still need to let it run even if the position (IGNORING the transform) would not change, as the transform animation is not finished yet. This is what animationTimer does. Otherwise, the positioning will be inaccurate
42
+ */
43
+ if ( lastTargetBlock ?. elem ) {
44
+ if ( targetBlockElem !== lastTargetBlock ?. elem ) {
45
+ if (
46
+ isBelow &&
47
+ lastTargetBlock ?. elem &&
48
+ lastTargetBlock ?. elem === targetBlockElem . nextElementSibling
49
+ ) {
50
+ animationTimer ++
51
+
52
+ if ( animationTimer < 200 ) {
53
+ willStayInSamePosition = true
54
+ }
55
+ } else if (
56
+ ! isBelow &&
57
+ lastTargetBlock ?. elem &&
58
+ lastTargetBlock ?. elem === targetBlockElem . previousElementSibling
59
+ ) {
60
+ animationTimer ++
61
+ if ( animationTimer < 200 ) {
62
+ willStayInSamePosition = true
63
+ }
64
+ }
65
+ } else {
66
+ animationTimer ++
67
+
68
+ const lastBoundingBoxPosition = lastTargetBlock ?. boundingBox ?. y
69
+ const currentBoundingBoxPosition = targetBlockElem . getBoundingClientRect ( ) . y
70
+
71
+ if (
72
+ ( isBelow === lastTargetBlock ?. isBelow &&
73
+ lastBoundingBoxPosition === currentBoundingBoxPosition ) ||
74
+ animationTimer < 200
75
+ ) {
76
+ willStayInSamePosition = false
77
+ }
78
+ }
79
+ }
80
+ if ( willStayInSamePosition ) {
81
+ return {
82
+ isBelow,
83
+ willStayInSamePosition,
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Paragraphs need no isBelow/above handling,
89
+ */
28
90
if ( ! isFoundNodeEmptyParagraph ) {
91
+ //if (!isFoundNodeEmptyParagraph) {
29
92
if ( isBelow ) {
30
93
// below targetBlockElem
31
94
lineTop += targetBlockElemHeight + marginBottom / 2
@@ -37,7 +100,6 @@ export function setTargetLine(
37
100
lineTop += targetBlockElemHeight / 2
38
101
}
39
102
40
- const targetElemTranslate = 0
41
103
let targetElemTranslate2 = 0
42
104
43
105
if ( ! isFoundNodeEmptyParagraph ) {
@@ -48,43 +110,55 @@ export function setTargetLine(
48
110
}
49
111
}
50
112
51
- let top = lineTop - anchorTop + targetElemTranslate2
52
- if ( ! isBelow ) {
53
- top -= TARGET_LINE_HALF_HEIGHT * 2
54
- }
113
+ const top = lineTop - anchorTop + targetElemTranslate2
114
+
55
115
const left = TEXT_BOX_HORIZONTAL_PADDING - offsetLeft
56
116
57
- targetLineElem . style . transform = `translate(${ left } px, ${ top } px)`
58
117
targetLineElem . style . width = `calc(${ anchorWidth } px - ${ offsetWidth } )`
59
118
targetLineElem . style . opacity = '.4'
60
119
61
120
/**
62
- * Move around element below or above the line (= the target / targetBlockElem)
121
+ * Move around element below or above the line (= the target / targetBlockElem). Creates "space" for the targetLineElem
122
+ *
123
+ * Not needed for empty paragraphs, as an empty paragraph is enough space for the targetLineElem anyways.
63
124
*/
64
125
//targetBlockElem.style.opacity = '0.4'
126
+ const buffer = 12 // creates more spacing/padding so target line is not directly next to the targetBlockElem
65
127
if ( ! isFoundNodeEmptyParagraph ) {
66
- // move lastTargetBlockElem down 50px to make space for targetLineElem (which is 50px height)
67
- targetBlockElem . style . transform = `translate(0, ${ targetElemTranslate } px)`
68
128
if ( isBelow ) {
69
- // add to existing marginBottom plus the height of targetLineElem
70
- targetBlockElem . style . marginBottom = TARGET_LINE_HALF_HEIGHT * 2 + 'px'
129
+ targetBlockElem . style . marginBottom = TARGET_LINE_HALF_HEIGHT * 2 + buffer + 'px'
130
+ targetLineElem . style . transform = `translate( ${ left } px, calc( ${ top } px - ${ '0px' } ))`
71
131
} else {
72
- targetBlockElem . style . marginTop = TARGET_LINE_HALF_HEIGHT * 2 + 'px'
132
+ targetBlockElem . style . marginTop = TARGET_LINE_HALF_HEIGHT * 2 + buffer + 'px'
133
+ targetLineElem . style . transform = `translate(${ left } px, calc(${ top - TARGET_LINE_HALF_HEIGHT * 2 } px - ${ '0px' } ))`
73
134
}
135
+ } else {
136
+ targetLineElem . style . transform = `translate(${ left } px, ${ top - TARGET_LINE_HALF_HEIGHT } px)`
74
137
}
75
138
76
139
if ( DEBUG ) {
77
140
//targetBlockElem.style.border = '3px solid red'
78
141
highlightElemOriginalPosition ( debugHighlightRef , targetBlockElem , anchorElem )
79
142
}
80
143
81
- if ( lastTargetBlockElem && lastTargetBlockElem !== targetBlockElem ) {
82
- lastTargetBlockElem . style . opacity = ''
83
- lastTargetBlockElem . style . transform = ''
144
+ /**
145
+ * Properly reset previous targetBlockElem styles
146
+ */
147
+ lastTargetBlock . elem . style . opacity = ''
84
148
85
- // Delete marginBottom and marginTop values we set
86
- lastTargetBlockElem . style . marginBottom = ''
87
- lastTargetBlockElem . style . marginTop = ''
88
- //lastTargetBlockElem.style.border = 'none'
149
+ if ( lastTargetBlock ?. elem === targetBlockElem ) {
150
+ if ( isBelow ) {
151
+ lastTargetBlock . elem . style . marginTop = ''
152
+ } else {
153
+ lastTargetBlock . elem . style . marginBottom = ''
154
+ }
155
+ } else {
156
+ lastTargetBlock . elem . style . marginBottom = ''
157
+ lastTargetBlock . elem . style . marginTop = ''
158
+ }
159
+ animationTimer = 0
160
+ return {
161
+ isBelow,
162
+ willStayInSamePosition,
89
163
}
90
164
}
0 commit comments