@@ -124,6 +124,14 @@ export class Datetime implements ComponentInterface {
124124 private destroyCalendarListener ?: ( ) => void ;
125125 private destroyKeyboardMO ?: ( ) => void ;
126126
127+ /**
128+ * Tracks the current visibility state of the datetime component.
129+ * This prevents race conditions when the datetime rapidly becomes visible/hidden
130+ * (e.g., when dragging a modal on iOS), ensuring the datetime-ready class
131+ * accurately reflects the component's current intersection state.
132+ */
133+ private isIntersecting = false ;
134+
127135 // TODO(FW-2832): types (DatetimeParts causes some errors that need untangling)
128136 private minParts ?: any ;
129137 private maxParts ?: any ;
@@ -1148,6 +1156,13 @@ export class Datetime implements ComponentInterface {
11481156 return ;
11491157 }
11501158
1159+ /**
1160+ * Track that the component is now intersecting.
1161+ * This prevents stale writeTask operations from incorrectly
1162+ * removing the datetime-ready class.
1163+ */
1164+ this . isIntersecting = true ;
1165+
11511166 this . initializeListeners ( ) ;
11521167
11531168 /**
@@ -1159,7 +1174,14 @@ export class Datetime implements ComponentInterface {
11591174 * is a better way to handle this?
11601175 */
11611176 writeTask ( ( ) => {
1162- this . el . classList . add ( 'datetime-ready' ) ;
1177+ /**
1178+ * Only add the class if the component is still intersecting.
1179+ * This prevents race conditions when the visibility state changes
1180+ * rapidly (e.g., when dragging a modal on iOS).
1181+ */
1182+ if ( this . isIntersecting ) {
1183+ this . el . classList . add ( 'datetime-ready' ) ;
1184+ }
11631185 } ) ;
11641186 } ;
11651187 const visibleIO = new IntersectionObserver ( visibleCallback , { threshold : 0.01 , root : el } ) ;
@@ -1197,6 +1219,13 @@ export class Datetime implements ComponentInterface {
11971219 return ;
11981220 }
11991221
1222+ /**
1223+ * Track that the component is no longer intersecting.
1224+ * This prevents stale writeTask operations from incorrectly
1225+ * adding the datetime-ready class.
1226+ */
1227+ this . isIntersecting = false ;
1228+
12001229 this . destroyInteractionListeners ( ) ;
12011230
12021231 /**
@@ -1209,7 +1238,14 @@ export class Datetime implements ComponentInterface {
12091238 this . showMonthAndYear = false ;
12101239
12111240 writeTask ( ( ) => {
1212- this . el . classList . remove ( 'datetime-ready' ) ;
1241+ /**
1242+ * Only remove the class if the component is still not intersecting.
1243+ * This prevents race conditions when the visibility state changes
1244+ * rapidly (e.g., when dragging a modal on iOS).
1245+ */
1246+ if ( ! this . isIntersecting ) {
1247+ this . el . classList . remove ( 'datetime-ready' ) ;
1248+ }
12131249 } ) ;
12141250 } ;
12151251 const hiddenIO = new IntersectionObserver ( hiddenCallback , { threshold : 0 , root : el } ) ;
0 commit comments