@@ -102,9 +102,23 @@ const PopupInner = React.forwardRef<PopupInnerRef, PopupInnerProps>(
102
102
const [ status , goNextStatus ] = useVisibleStatus ( visible , doMeasure ) ;
103
103
104
104
// ======================== Aligns ========================
105
- const [ alignInfo , setAlignInfo ] = useState < AlignType > ( null ) ;
105
+ /**
106
+ * `alignedClassName` may modify `source` size,
107
+ * which means one time align may not move to the correct position at once.
108
+ *
109
+ * We will reset `alignTimes` for each status switch to `alignPre`
110
+ * and let `rc-align` to align for multiple times to ensure get final stable place.
111
+ * Currently we mark `alignTimes < 2` repeat align, it will increase if user report for align issue.
112
+ */
113
+ const [ alignTimes , setAlignTimes ] = useState ( 0 ) ;
106
114
const prepareResolveRef = useRef < ( value ?: unknown ) => void > ( ) ;
107
115
116
+ useLayoutEffect ( ( ) => {
117
+ if ( status === 'alignPre' ) {
118
+ setAlignTimes ( 0 ) ;
119
+ }
120
+ } , [ status ] ) ;
121
+
108
122
// `target` on `rc-align` can accept as a function to get the bind element or a point.
109
123
// ref: https://www.npmjs.com/package/rc-align
110
124
function getAlignTarget ( ) {
@@ -120,11 +134,13 @@ const PopupInner = React.forwardRef<PopupInnerRef, PopupInnerProps>(
120
134
121
135
function onInternalAlign ( popupDomNode : HTMLElement , matchAlign : AlignType ) {
122
136
const nextAlignedClassName = getClassNameFromAlign ( matchAlign ) ;
137
+
123
138
if ( alignedClassName !== nextAlignedClassName ) {
124
139
setAlignedClassName ( nextAlignedClassName ) ;
125
140
}
126
141
127
- setAlignInfo ( matchAlign ) ;
142
+ // We will retry multi times to make sure that the element has been align in the right position.
143
+ setAlignTimes ( ( val ) => val + 1 ) ;
128
144
129
145
if ( status === 'align' ) {
130
146
onAlign ?.( popupDomNode , matchAlign ) ;
@@ -133,19 +149,17 @@ const PopupInner = React.forwardRef<PopupInnerRef, PopupInnerProps>(
133
149
134
150
// Delay to go to next status
135
151
useLayoutEffect ( ( ) => {
136
- if ( alignInfo && status === 'align' ) {
137
- const nextAlignedClassName = getClassNameFromAlign ( alignInfo ) ;
138
-
152
+ if ( status === 'align' ) {
139
153
// Repeat until not more align needed
140
- if ( alignedClassName !== nextAlignedClassName ) {
154
+ if ( alignTimes < 2 ) {
141
155
forceAlign ( ) ;
142
156
} else {
143
157
goNextStatus ( function ( ) {
144
158
prepareResolveRef . current ?.( ) ;
145
159
} ) ;
146
160
}
147
161
}
148
- } , [ alignInfo ] ) ;
162
+ } , [ alignTimes ] ) ;
149
163
150
164
// ======================== Motion ========================
151
165
const motion = { ...getMotion ( props ) } ;
0 commit comments