@ionic/core 8.7.13-dev.11765552290.11441928 → 8.7.13-dev.11765560568.1a8772e8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/ion-datetime.js +74 -49
- package/dist/cjs/ion-datetime_3.cjs.entry.js +74 -49
- package/dist/collection/components/datetime/datetime.js +74 -49
- package/dist/docs.json +1 -1
- package/dist/esm/ion-datetime_3.entry.js +74 -49
- package/dist/ionic/ionic.esm.js +1 -1
- package/dist/ionic/p-ebcfc1d2.entry.js +4 -0
- package/dist/types/components/datetime/datetime.d.ts +11 -0
- package/hydrate/index.js +74 -49
- package/hydrate/index.mjs +74 -49
- package/package.json +1 -1
- package/dist/ionic/p-2ccaee5c.entry.js +0 -4
|
@@ -1071,78 +1071,103 @@ const Datetime = /*@__PURE__*/ proxyCustomElement(class Datetime extends HTMLEle
|
|
|
1071
1071
|
this.resizeObserver.disconnect();
|
|
1072
1072
|
this.resizeObserver = undefined;
|
|
1073
1073
|
}
|
|
1074
|
+
if (this.destroyOverlayListeners) {
|
|
1075
|
+
this.destroyOverlayListeners();
|
|
1076
|
+
this.destroyOverlayListeners = undefined;
|
|
1077
|
+
}
|
|
1074
1078
|
}
|
|
1075
1079
|
initializeListeners() {
|
|
1076
1080
|
this.initializeCalendarListener();
|
|
1077
1081
|
this.initializeKeyboardListeners();
|
|
1078
1082
|
}
|
|
1079
|
-
|
|
1083
|
+
/**
|
|
1084
|
+
* Sets up visibility detection for the datetime component.
|
|
1085
|
+
*
|
|
1086
|
+
* Uses multiple strategies to reliably detect when the datetime becomes
|
|
1087
|
+
* visible, which is necessary for proper initialization of scrollable areas:
|
|
1088
|
+
* 1. ResizeObserver - detects dimension changes
|
|
1089
|
+
* 2. Overlay event listeners - for datetime inside modals/popovers
|
|
1090
|
+
* 3. Polling fallback - for browsers where observers are unreliable (WebKit)
|
|
1091
|
+
*/
|
|
1092
|
+
initializeVisibilityObserver() {
|
|
1080
1093
|
const { el } = this;
|
|
1094
|
+
const markReady = () => {
|
|
1095
|
+
if (el.classList.contains('datetime-ready')) {
|
|
1096
|
+
return;
|
|
1097
|
+
}
|
|
1098
|
+
this.initializeListeners();
|
|
1099
|
+
writeTask(() => {
|
|
1100
|
+
el.classList.add('datetime-ready');
|
|
1101
|
+
});
|
|
1102
|
+
};
|
|
1103
|
+
const markHidden = () => {
|
|
1104
|
+
this.destroyInteractionListeners();
|
|
1105
|
+
this.showMonthAndYear = false;
|
|
1106
|
+
writeTask(() => {
|
|
1107
|
+
el.classList.remove('datetime-ready');
|
|
1108
|
+
});
|
|
1109
|
+
startVisibilityPolling();
|
|
1110
|
+
};
|
|
1081
1111
|
/**
|
|
1082
|
-
*
|
|
1083
|
-
*
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1112
|
+
* FW-6931: Poll for visibility as a fallback for browsers where
|
|
1113
|
+
* ResizeObserver doesn't fire reliably (e.g., WebKit).
|
|
1114
|
+
*/
|
|
1115
|
+
const startVisibilityPolling = () => {
|
|
1116
|
+
let pollCount = 0;
|
|
1117
|
+
const poll = () => {
|
|
1118
|
+
if (el.classList.contains('datetime-ready') || pollCount++ >= 60) {
|
|
1119
|
+
return;
|
|
1120
|
+
}
|
|
1121
|
+
const { width, height } = el.getBoundingClientRect();
|
|
1122
|
+
if (width > 0 && height > 0) {
|
|
1123
|
+
markReady();
|
|
1124
|
+
}
|
|
1125
|
+
else {
|
|
1126
|
+
raf(poll);
|
|
1127
|
+
}
|
|
1128
|
+
};
|
|
1129
|
+
raf(poll);
|
|
1130
|
+
};
|
|
1131
|
+
/**
|
|
1132
|
+
* FW-6931: Listen for overlay present/dismiss events when datetime
|
|
1133
|
+
* is inside a modal or popover.
|
|
1092
1134
|
*/
|
|
1135
|
+
const parentOverlay = el.closest('ion-modal, ion-popover');
|
|
1136
|
+
if (parentOverlay) {
|
|
1137
|
+
const handlePresent = () => markReady();
|
|
1138
|
+
const handleDismiss = () => markHidden();
|
|
1139
|
+
parentOverlay.addEventListener('didPresent', handlePresent);
|
|
1140
|
+
parentOverlay.addEventListener('didDismiss', handleDismiss);
|
|
1141
|
+
this.destroyOverlayListeners = () => {
|
|
1142
|
+
parentOverlay.removeEventListener('didPresent', handlePresent);
|
|
1143
|
+
parentOverlay.removeEventListener('didDismiss', handleDismiss);
|
|
1144
|
+
};
|
|
1145
|
+
}
|
|
1093
1146
|
if (typeof ResizeObserver !== 'undefined') {
|
|
1094
1147
|
this.resizeObserver = new ResizeObserver((entries) => {
|
|
1095
|
-
const
|
|
1096
|
-
const { width, height } = entry.contentRect;
|
|
1148
|
+
const { width, height } = entries[0].contentRect;
|
|
1097
1149
|
const isVisible = width > 0 && height > 0;
|
|
1098
1150
|
const isReady = el.classList.contains('datetime-ready');
|
|
1099
1151
|
if (isVisible && !isReady) {
|
|
1100
|
-
|
|
1101
|
-
/**
|
|
1102
|
-
* TODO FW-2793: Datetime needs a frame to ensure that it
|
|
1103
|
-
* can properly scroll contents into view. As a result
|
|
1104
|
-
* we hide the scrollable content until after that frame
|
|
1105
|
-
* so users do not see the content quickly shifting. The downside
|
|
1106
|
-
* is that the content will pop into view a frame after. Maybe there
|
|
1107
|
-
* is a better way to handle this?
|
|
1108
|
-
*/
|
|
1109
|
-
writeTask(() => {
|
|
1110
|
-
el.classList.add('datetime-ready');
|
|
1111
|
-
});
|
|
1152
|
+
markReady();
|
|
1112
1153
|
}
|
|
1113
1154
|
else if (!isVisible && isReady) {
|
|
1114
|
-
|
|
1115
|
-
* Clean up listeners when hidden so we can properly
|
|
1116
|
-
* reinitialize scroll positions on re-presentation.
|
|
1117
|
-
*/
|
|
1118
|
-
this.destroyInteractionListeners();
|
|
1119
|
-
/**
|
|
1120
|
-
* Close month/year picker when hidden, otherwise
|
|
1121
|
-
* it will be open when re-presented with a 0-height
|
|
1122
|
-
* scroll area, showing the wrong month.
|
|
1123
|
-
*/
|
|
1124
|
-
this.showMonthAndYear = false;
|
|
1125
|
-
writeTask(() => {
|
|
1126
|
-
el.classList.remove('datetime-ready');
|
|
1127
|
-
});
|
|
1155
|
+
markHidden();
|
|
1128
1156
|
}
|
|
1129
1157
|
});
|
|
1130
|
-
|
|
1131
|
-
* Use raf to avoid a race condition between the component loading and
|
|
1132
|
-
* its display animation starting (such as when shown in a modal).
|
|
1133
|
-
*/
|
|
1158
|
+
// Use raf to avoid race condition with modal/popover animations
|
|
1134
1159
|
raf(() => { var _a; return (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.observe(el); });
|
|
1160
|
+
startVisibilityPolling();
|
|
1135
1161
|
}
|
|
1136
1162
|
else {
|
|
1137
|
-
|
|
1138
|
-
* Fallback for test environments where ResizeObserver is not available.
|
|
1139
|
-
* Just mark as ready without initializing scroll/keyboard listeners
|
|
1140
|
-
* since those also require browser APIs not available in Jest.
|
|
1141
|
-
*/
|
|
1163
|
+
// Test environment fallback - mark ready immediately
|
|
1142
1164
|
writeTask(() => {
|
|
1143
1165
|
el.classList.add('datetime-ready');
|
|
1144
1166
|
});
|
|
1145
1167
|
}
|
|
1168
|
+
}
|
|
1169
|
+
componentDidLoad() {
|
|
1170
|
+
this.initializeVisibilityObserver();
|
|
1146
1171
|
/**
|
|
1147
1172
|
* Datetime uses Ionic components that emit
|
|
1148
1173
|
* ionFocus and ionBlur. These events are
|
|
@@ -1871,7 +1896,7 @@ const Datetime = /*@__PURE__*/ proxyCustomElement(class Datetime extends HTMLEle
|
|
|
1871
1896
|
const hasDatePresentation = presentation === 'date' || presentation === 'date-time' || presentation === 'time-date';
|
|
1872
1897
|
const hasWheelVariant = hasDatePresentation && preferWheel;
|
|
1873
1898
|
renderHiddenInput(true, el, name, formatValue(value), disabled);
|
|
1874
|
-
return (h(Host, { key: '
|
|
1899
|
+
return (h(Host, { key: '2fb2938db507a134622a3feac44804f11071c589', "aria-disabled": disabled ? 'true' : null, onFocus: this.onFocus, onBlur: this.onBlur, class: Object.assign({}, createColorClasses(color, {
|
|
1875
1900
|
[mode]: true,
|
|
1876
1901
|
['datetime-readonly']: readonly,
|
|
1877
1902
|
['datetime-disabled']: disabled,
|
|
@@ -1067,78 +1067,103 @@ const Datetime = class {
|
|
|
1067
1067
|
this.resizeObserver.disconnect();
|
|
1068
1068
|
this.resizeObserver = undefined;
|
|
1069
1069
|
}
|
|
1070
|
+
if (this.destroyOverlayListeners) {
|
|
1071
|
+
this.destroyOverlayListeners();
|
|
1072
|
+
this.destroyOverlayListeners = undefined;
|
|
1073
|
+
}
|
|
1070
1074
|
}
|
|
1071
1075
|
initializeListeners() {
|
|
1072
1076
|
this.initializeCalendarListener();
|
|
1073
1077
|
this.initializeKeyboardListeners();
|
|
1074
1078
|
}
|
|
1075
|
-
|
|
1079
|
+
/**
|
|
1080
|
+
* Sets up visibility detection for the datetime component.
|
|
1081
|
+
*
|
|
1082
|
+
* Uses multiple strategies to reliably detect when the datetime becomes
|
|
1083
|
+
* visible, which is necessary for proper initialization of scrollable areas:
|
|
1084
|
+
* 1. ResizeObserver - detects dimension changes
|
|
1085
|
+
* 2. Overlay event listeners - for datetime inside modals/popovers
|
|
1086
|
+
* 3. Polling fallback - for browsers where observers are unreliable (WebKit)
|
|
1087
|
+
*/
|
|
1088
|
+
initializeVisibilityObserver() {
|
|
1076
1089
|
const { el } = this;
|
|
1090
|
+
const markReady = () => {
|
|
1091
|
+
if (el.classList.contains('datetime-ready')) {
|
|
1092
|
+
return;
|
|
1093
|
+
}
|
|
1094
|
+
this.initializeListeners();
|
|
1095
|
+
index.writeTask(() => {
|
|
1096
|
+
el.classList.add('datetime-ready');
|
|
1097
|
+
});
|
|
1098
|
+
};
|
|
1099
|
+
const markHidden = () => {
|
|
1100
|
+
this.destroyInteractionListeners();
|
|
1101
|
+
this.showMonthAndYear = false;
|
|
1102
|
+
index.writeTask(() => {
|
|
1103
|
+
el.classList.remove('datetime-ready');
|
|
1104
|
+
});
|
|
1105
|
+
startVisibilityPolling();
|
|
1106
|
+
};
|
|
1077
1107
|
/**
|
|
1078
|
-
*
|
|
1079
|
-
*
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1108
|
+
* FW-6931: Poll for visibility as a fallback for browsers where
|
|
1109
|
+
* ResizeObserver doesn't fire reliably (e.g., WebKit).
|
|
1110
|
+
*/
|
|
1111
|
+
const startVisibilityPolling = () => {
|
|
1112
|
+
let pollCount = 0;
|
|
1113
|
+
const poll = () => {
|
|
1114
|
+
if (el.classList.contains('datetime-ready') || pollCount++ >= 60) {
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
1117
|
+
const { width, height } = el.getBoundingClientRect();
|
|
1118
|
+
if (width > 0 && height > 0) {
|
|
1119
|
+
markReady();
|
|
1120
|
+
}
|
|
1121
|
+
else {
|
|
1122
|
+
helpers.raf(poll);
|
|
1123
|
+
}
|
|
1124
|
+
};
|
|
1125
|
+
helpers.raf(poll);
|
|
1126
|
+
};
|
|
1127
|
+
/**
|
|
1128
|
+
* FW-6931: Listen for overlay present/dismiss events when datetime
|
|
1129
|
+
* is inside a modal or popover.
|
|
1088
1130
|
*/
|
|
1131
|
+
const parentOverlay = el.closest('ion-modal, ion-popover');
|
|
1132
|
+
if (parentOverlay) {
|
|
1133
|
+
const handlePresent = () => markReady();
|
|
1134
|
+
const handleDismiss = () => markHidden();
|
|
1135
|
+
parentOverlay.addEventListener('didPresent', handlePresent);
|
|
1136
|
+
parentOverlay.addEventListener('didDismiss', handleDismiss);
|
|
1137
|
+
this.destroyOverlayListeners = () => {
|
|
1138
|
+
parentOverlay.removeEventListener('didPresent', handlePresent);
|
|
1139
|
+
parentOverlay.removeEventListener('didDismiss', handleDismiss);
|
|
1140
|
+
};
|
|
1141
|
+
}
|
|
1089
1142
|
if (typeof ResizeObserver !== 'undefined') {
|
|
1090
1143
|
this.resizeObserver = new ResizeObserver((entries) => {
|
|
1091
|
-
const
|
|
1092
|
-
const { width, height } = entry.contentRect;
|
|
1144
|
+
const { width, height } = entries[0].contentRect;
|
|
1093
1145
|
const isVisible = width > 0 && height > 0;
|
|
1094
1146
|
const isReady = el.classList.contains('datetime-ready');
|
|
1095
1147
|
if (isVisible && !isReady) {
|
|
1096
|
-
|
|
1097
|
-
/**
|
|
1098
|
-
* TODO FW-2793: Datetime needs a frame to ensure that it
|
|
1099
|
-
* can properly scroll contents into view. As a result
|
|
1100
|
-
* we hide the scrollable content until after that frame
|
|
1101
|
-
* so users do not see the content quickly shifting. The downside
|
|
1102
|
-
* is that the content will pop into view a frame after. Maybe there
|
|
1103
|
-
* is a better way to handle this?
|
|
1104
|
-
*/
|
|
1105
|
-
index.writeTask(() => {
|
|
1106
|
-
el.classList.add('datetime-ready');
|
|
1107
|
-
});
|
|
1148
|
+
markReady();
|
|
1108
1149
|
}
|
|
1109
1150
|
else if (!isVisible && isReady) {
|
|
1110
|
-
|
|
1111
|
-
* Clean up listeners when hidden so we can properly
|
|
1112
|
-
* reinitialize scroll positions on re-presentation.
|
|
1113
|
-
*/
|
|
1114
|
-
this.destroyInteractionListeners();
|
|
1115
|
-
/**
|
|
1116
|
-
* Close month/year picker when hidden, otherwise
|
|
1117
|
-
* it will be open when re-presented with a 0-height
|
|
1118
|
-
* scroll area, showing the wrong month.
|
|
1119
|
-
*/
|
|
1120
|
-
this.showMonthAndYear = false;
|
|
1121
|
-
index.writeTask(() => {
|
|
1122
|
-
el.classList.remove('datetime-ready');
|
|
1123
|
-
});
|
|
1151
|
+
markHidden();
|
|
1124
1152
|
}
|
|
1125
1153
|
});
|
|
1126
|
-
|
|
1127
|
-
* Use raf to avoid a race condition between the component loading and
|
|
1128
|
-
* its display animation starting (such as when shown in a modal).
|
|
1129
|
-
*/
|
|
1154
|
+
// Use raf to avoid race condition with modal/popover animations
|
|
1130
1155
|
helpers.raf(() => { var _a; return (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.observe(el); });
|
|
1156
|
+
startVisibilityPolling();
|
|
1131
1157
|
}
|
|
1132
1158
|
else {
|
|
1133
|
-
|
|
1134
|
-
* Fallback for test environments where ResizeObserver is not available.
|
|
1135
|
-
* Just mark as ready without initializing scroll/keyboard listeners
|
|
1136
|
-
* since those also require browser APIs not available in Jest.
|
|
1137
|
-
*/
|
|
1159
|
+
// Test environment fallback - mark ready immediately
|
|
1138
1160
|
index.writeTask(() => {
|
|
1139
1161
|
el.classList.add('datetime-ready');
|
|
1140
1162
|
});
|
|
1141
1163
|
}
|
|
1164
|
+
}
|
|
1165
|
+
componentDidLoad() {
|
|
1166
|
+
this.initializeVisibilityObserver();
|
|
1142
1167
|
/**
|
|
1143
1168
|
* Datetime uses Ionic components that emit
|
|
1144
1169
|
* ionFocus and ionBlur. These events are
|
|
@@ -1867,7 +1892,7 @@ const Datetime = class {
|
|
|
1867
1892
|
const hasDatePresentation = presentation === 'date' || presentation === 'date-time' || presentation === 'time-date';
|
|
1868
1893
|
const hasWheelVariant = hasDatePresentation && preferWheel;
|
|
1869
1894
|
helpers.renderHiddenInput(true, el, name, data.formatValue(value), disabled);
|
|
1870
|
-
return (index.h(index.Host, { key: '
|
|
1895
|
+
return (index.h(index.Host, { key: '2fb2938db507a134622a3feac44804f11071c589', "aria-disabled": disabled ? 'true' : null, onFocus: this.onFocus, onBlur: this.onBlur, class: Object.assign({}, theme.createColorClasses(color, {
|
|
1871
1896
|
[mode]: true,
|
|
1872
1897
|
['datetime-readonly']: readonly,
|
|
1873
1898
|
['datetime-disabled']: disabled,
|
|
@@ -866,78 +866,103 @@ export class Datetime {
|
|
|
866
866
|
this.resizeObserver.disconnect();
|
|
867
867
|
this.resizeObserver = undefined;
|
|
868
868
|
}
|
|
869
|
+
if (this.destroyOverlayListeners) {
|
|
870
|
+
this.destroyOverlayListeners();
|
|
871
|
+
this.destroyOverlayListeners = undefined;
|
|
872
|
+
}
|
|
869
873
|
}
|
|
870
874
|
initializeListeners() {
|
|
871
875
|
this.initializeCalendarListener();
|
|
872
876
|
this.initializeKeyboardListeners();
|
|
873
877
|
}
|
|
874
|
-
|
|
878
|
+
/**
|
|
879
|
+
* Sets up visibility detection for the datetime component.
|
|
880
|
+
*
|
|
881
|
+
* Uses multiple strategies to reliably detect when the datetime becomes
|
|
882
|
+
* visible, which is necessary for proper initialization of scrollable areas:
|
|
883
|
+
* 1. ResizeObserver - detects dimension changes
|
|
884
|
+
* 2. Overlay event listeners - for datetime inside modals/popovers
|
|
885
|
+
* 3. Polling fallback - for browsers where observers are unreliable (WebKit)
|
|
886
|
+
*/
|
|
887
|
+
initializeVisibilityObserver() {
|
|
875
888
|
const { el } = this;
|
|
889
|
+
const markReady = () => {
|
|
890
|
+
if (el.classList.contains('datetime-ready')) {
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
this.initializeListeners();
|
|
894
|
+
writeTask(() => {
|
|
895
|
+
el.classList.add('datetime-ready');
|
|
896
|
+
});
|
|
897
|
+
};
|
|
898
|
+
const markHidden = () => {
|
|
899
|
+
this.destroyInteractionListeners();
|
|
900
|
+
this.showMonthAndYear = false;
|
|
901
|
+
writeTask(() => {
|
|
902
|
+
el.classList.remove('datetime-ready');
|
|
903
|
+
});
|
|
904
|
+
startVisibilityPolling();
|
|
905
|
+
};
|
|
876
906
|
/**
|
|
877
|
-
*
|
|
878
|
-
*
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
907
|
+
* FW-6931: Poll for visibility as a fallback for browsers where
|
|
908
|
+
* ResizeObserver doesn't fire reliably (e.g., WebKit).
|
|
909
|
+
*/
|
|
910
|
+
const startVisibilityPolling = () => {
|
|
911
|
+
let pollCount = 0;
|
|
912
|
+
const poll = () => {
|
|
913
|
+
if (el.classList.contains('datetime-ready') || pollCount++ >= 60) {
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
916
|
+
const { width, height } = el.getBoundingClientRect();
|
|
917
|
+
if (width > 0 && height > 0) {
|
|
918
|
+
markReady();
|
|
919
|
+
}
|
|
920
|
+
else {
|
|
921
|
+
raf(poll);
|
|
922
|
+
}
|
|
923
|
+
};
|
|
924
|
+
raf(poll);
|
|
925
|
+
};
|
|
926
|
+
/**
|
|
927
|
+
* FW-6931: Listen for overlay present/dismiss events when datetime
|
|
928
|
+
* is inside a modal or popover.
|
|
887
929
|
*/
|
|
930
|
+
const parentOverlay = el.closest('ion-modal, ion-popover');
|
|
931
|
+
if (parentOverlay) {
|
|
932
|
+
const handlePresent = () => markReady();
|
|
933
|
+
const handleDismiss = () => markHidden();
|
|
934
|
+
parentOverlay.addEventListener('didPresent', handlePresent);
|
|
935
|
+
parentOverlay.addEventListener('didDismiss', handleDismiss);
|
|
936
|
+
this.destroyOverlayListeners = () => {
|
|
937
|
+
parentOverlay.removeEventListener('didPresent', handlePresent);
|
|
938
|
+
parentOverlay.removeEventListener('didDismiss', handleDismiss);
|
|
939
|
+
};
|
|
940
|
+
}
|
|
888
941
|
if (typeof ResizeObserver !== 'undefined') {
|
|
889
942
|
this.resizeObserver = new ResizeObserver((entries) => {
|
|
890
|
-
const
|
|
891
|
-
const { width, height } = entry.contentRect;
|
|
943
|
+
const { width, height } = entries[0].contentRect;
|
|
892
944
|
const isVisible = width > 0 && height > 0;
|
|
893
945
|
const isReady = el.classList.contains('datetime-ready');
|
|
894
946
|
if (isVisible && !isReady) {
|
|
895
|
-
|
|
896
|
-
/**
|
|
897
|
-
* TODO FW-2793: Datetime needs a frame to ensure that it
|
|
898
|
-
* can properly scroll contents into view. As a result
|
|
899
|
-
* we hide the scrollable content until after that frame
|
|
900
|
-
* so users do not see the content quickly shifting. The downside
|
|
901
|
-
* is that the content will pop into view a frame after. Maybe there
|
|
902
|
-
* is a better way to handle this?
|
|
903
|
-
*/
|
|
904
|
-
writeTask(() => {
|
|
905
|
-
el.classList.add('datetime-ready');
|
|
906
|
-
});
|
|
947
|
+
markReady();
|
|
907
948
|
}
|
|
908
949
|
else if (!isVisible && isReady) {
|
|
909
|
-
|
|
910
|
-
* Clean up listeners when hidden so we can properly
|
|
911
|
-
* reinitialize scroll positions on re-presentation.
|
|
912
|
-
*/
|
|
913
|
-
this.destroyInteractionListeners();
|
|
914
|
-
/**
|
|
915
|
-
* Close month/year picker when hidden, otherwise
|
|
916
|
-
* it will be open when re-presented with a 0-height
|
|
917
|
-
* scroll area, showing the wrong month.
|
|
918
|
-
*/
|
|
919
|
-
this.showMonthAndYear = false;
|
|
920
|
-
writeTask(() => {
|
|
921
|
-
el.classList.remove('datetime-ready');
|
|
922
|
-
});
|
|
950
|
+
markHidden();
|
|
923
951
|
}
|
|
924
952
|
});
|
|
925
|
-
|
|
926
|
-
* Use raf to avoid a race condition between the component loading and
|
|
927
|
-
* its display animation starting (such as when shown in a modal).
|
|
928
|
-
*/
|
|
953
|
+
// Use raf to avoid race condition with modal/popover animations
|
|
929
954
|
raf(() => { var _a; return (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.observe(el); });
|
|
955
|
+
startVisibilityPolling();
|
|
930
956
|
}
|
|
931
957
|
else {
|
|
932
|
-
|
|
933
|
-
* Fallback for test environments where ResizeObserver is not available.
|
|
934
|
-
* Just mark as ready without initializing scroll/keyboard listeners
|
|
935
|
-
* since those also require browser APIs not available in Jest.
|
|
936
|
-
*/
|
|
958
|
+
// Test environment fallback - mark ready immediately
|
|
937
959
|
writeTask(() => {
|
|
938
960
|
el.classList.add('datetime-ready');
|
|
939
961
|
});
|
|
940
962
|
}
|
|
963
|
+
}
|
|
964
|
+
componentDidLoad() {
|
|
965
|
+
this.initializeVisibilityObserver();
|
|
941
966
|
/**
|
|
942
967
|
* Datetime uses Ionic components that emit
|
|
943
968
|
* ionFocus and ionBlur. These events are
|
|
@@ -1666,7 +1691,7 @@ export class Datetime {
|
|
|
1666
1691
|
const hasDatePresentation = presentation === 'date' || presentation === 'date-time' || presentation === 'time-date';
|
|
1667
1692
|
const hasWheelVariant = hasDatePresentation && preferWheel;
|
|
1668
1693
|
renderHiddenInput(true, el, name, formatValue(value), disabled);
|
|
1669
|
-
return (h(Host, { key: '
|
|
1694
|
+
return (h(Host, { key: '2fb2938db507a134622a3feac44804f11071c589', "aria-disabled": disabled ? 'true' : null, onFocus: this.onFocus, onBlur: this.onBlur, class: Object.assign({}, createColorClasses(color, {
|
|
1670
1695
|
[mode]: true,
|
|
1671
1696
|
['datetime-readonly']: readonly,
|
|
1672
1697
|
['datetime-disabled']: disabled,
|
package/dist/docs.json
CHANGED
|
@@ -1065,78 +1065,103 @@ const Datetime = class {
|
|
|
1065
1065
|
this.resizeObserver.disconnect();
|
|
1066
1066
|
this.resizeObserver = undefined;
|
|
1067
1067
|
}
|
|
1068
|
+
if (this.destroyOverlayListeners) {
|
|
1069
|
+
this.destroyOverlayListeners();
|
|
1070
|
+
this.destroyOverlayListeners = undefined;
|
|
1071
|
+
}
|
|
1068
1072
|
}
|
|
1069
1073
|
initializeListeners() {
|
|
1070
1074
|
this.initializeCalendarListener();
|
|
1071
1075
|
this.initializeKeyboardListeners();
|
|
1072
1076
|
}
|
|
1073
|
-
|
|
1077
|
+
/**
|
|
1078
|
+
* Sets up visibility detection for the datetime component.
|
|
1079
|
+
*
|
|
1080
|
+
* Uses multiple strategies to reliably detect when the datetime becomes
|
|
1081
|
+
* visible, which is necessary for proper initialization of scrollable areas:
|
|
1082
|
+
* 1. ResizeObserver - detects dimension changes
|
|
1083
|
+
* 2. Overlay event listeners - for datetime inside modals/popovers
|
|
1084
|
+
* 3. Polling fallback - for browsers where observers are unreliable (WebKit)
|
|
1085
|
+
*/
|
|
1086
|
+
initializeVisibilityObserver() {
|
|
1074
1087
|
const { el } = this;
|
|
1088
|
+
const markReady = () => {
|
|
1089
|
+
if (el.classList.contains('datetime-ready')) {
|
|
1090
|
+
return;
|
|
1091
|
+
}
|
|
1092
|
+
this.initializeListeners();
|
|
1093
|
+
writeTask(() => {
|
|
1094
|
+
el.classList.add('datetime-ready');
|
|
1095
|
+
});
|
|
1096
|
+
};
|
|
1097
|
+
const markHidden = () => {
|
|
1098
|
+
this.destroyInteractionListeners();
|
|
1099
|
+
this.showMonthAndYear = false;
|
|
1100
|
+
writeTask(() => {
|
|
1101
|
+
el.classList.remove('datetime-ready');
|
|
1102
|
+
});
|
|
1103
|
+
startVisibilityPolling();
|
|
1104
|
+
};
|
|
1075
1105
|
/**
|
|
1076
|
-
*
|
|
1077
|
-
*
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1106
|
+
* FW-6931: Poll for visibility as a fallback for browsers where
|
|
1107
|
+
* ResizeObserver doesn't fire reliably (e.g., WebKit).
|
|
1108
|
+
*/
|
|
1109
|
+
const startVisibilityPolling = () => {
|
|
1110
|
+
let pollCount = 0;
|
|
1111
|
+
const poll = () => {
|
|
1112
|
+
if (el.classList.contains('datetime-ready') || pollCount++ >= 60) {
|
|
1113
|
+
return;
|
|
1114
|
+
}
|
|
1115
|
+
const { width, height } = el.getBoundingClientRect();
|
|
1116
|
+
if (width > 0 && height > 0) {
|
|
1117
|
+
markReady();
|
|
1118
|
+
}
|
|
1119
|
+
else {
|
|
1120
|
+
raf(poll);
|
|
1121
|
+
}
|
|
1122
|
+
};
|
|
1123
|
+
raf(poll);
|
|
1124
|
+
};
|
|
1125
|
+
/**
|
|
1126
|
+
* FW-6931: Listen for overlay present/dismiss events when datetime
|
|
1127
|
+
* is inside a modal or popover.
|
|
1086
1128
|
*/
|
|
1129
|
+
const parentOverlay = el.closest('ion-modal, ion-popover');
|
|
1130
|
+
if (parentOverlay) {
|
|
1131
|
+
const handlePresent = () => markReady();
|
|
1132
|
+
const handleDismiss = () => markHidden();
|
|
1133
|
+
parentOverlay.addEventListener('didPresent', handlePresent);
|
|
1134
|
+
parentOverlay.addEventListener('didDismiss', handleDismiss);
|
|
1135
|
+
this.destroyOverlayListeners = () => {
|
|
1136
|
+
parentOverlay.removeEventListener('didPresent', handlePresent);
|
|
1137
|
+
parentOverlay.removeEventListener('didDismiss', handleDismiss);
|
|
1138
|
+
};
|
|
1139
|
+
}
|
|
1087
1140
|
if (typeof ResizeObserver !== 'undefined') {
|
|
1088
1141
|
this.resizeObserver = new ResizeObserver((entries) => {
|
|
1089
|
-
const
|
|
1090
|
-
const { width, height } = entry.contentRect;
|
|
1142
|
+
const { width, height } = entries[0].contentRect;
|
|
1091
1143
|
const isVisible = width > 0 && height > 0;
|
|
1092
1144
|
const isReady = el.classList.contains('datetime-ready');
|
|
1093
1145
|
if (isVisible && !isReady) {
|
|
1094
|
-
|
|
1095
|
-
/**
|
|
1096
|
-
* TODO FW-2793: Datetime needs a frame to ensure that it
|
|
1097
|
-
* can properly scroll contents into view. As a result
|
|
1098
|
-
* we hide the scrollable content until after that frame
|
|
1099
|
-
* so users do not see the content quickly shifting. The downside
|
|
1100
|
-
* is that the content will pop into view a frame after. Maybe there
|
|
1101
|
-
* is a better way to handle this?
|
|
1102
|
-
*/
|
|
1103
|
-
writeTask(() => {
|
|
1104
|
-
el.classList.add('datetime-ready');
|
|
1105
|
-
});
|
|
1146
|
+
markReady();
|
|
1106
1147
|
}
|
|
1107
1148
|
else if (!isVisible && isReady) {
|
|
1108
|
-
|
|
1109
|
-
* Clean up listeners when hidden so we can properly
|
|
1110
|
-
* reinitialize scroll positions on re-presentation.
|
|
1111
|
-
*/
|
|
1112
|
-
this.destroyInteractionListeners();
|
|
1113
|
-
/**
|
|
1114
|
-
* Close month/year picker when hidden, otherwise
|
|
1115
|
-
* it will be open when re-presented with a 0-height
|
|
1116
|
-
* scroll area, showing the wrong month.
|
|
1117
|
-
*/
|
|
1118
|
-
this.showMonthAndYear = false;
|
|
1119
|
-
writeTask(() => {
|
|
1120
|
-
el.classList.remove('datetime-ready');
|
|
1121
|
-
});
|
|
1149
|
+
markHidden();
|
|
1122
1150
|
}
|
|
1123
1151
|
});
|
|
1124
|
-
|
|
1125
|
-
* Use raf to avoid a race condition between the component loading and
|
|
1126
|
-
* its display animation starting (such as when shown in a modal).
|
|
1127
|
-
*/
|
|
1152
|
+
// Use raf to avoid race condition with modal/popover animations
|
|
1128
1153
|
raf(() => { var _a; return (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.observe(el); });
|
|
1154
|
+
startVisibilityPolling();
|
|
1129
1155
|
}
|
|
1130
1156
|
else {
|
|
1131
|
-
|
|
1132
|
-
* Fallback for test environments where ResizeObserver is not available.
|
|
1133
|
-
* Just mark as ready without initializing scroll/keyboard listeners
|
|
1134
|
-
* since those also require browser APIs not available in Jest.
|
|
1135
|
-
*/
|
|
1157
|
+
// Test environment fallback - mark ready immediately
|
|
1136
1158
|
writeTask(() => {
|
|
1137
1159
|
el.classList.add('datetime-ready');
|
|
1138
1160
|
});
|
|
1139
1161
|
}
|
|
1162
|
+
}
|
|
1163
|
+
componentDidLoad() {
|
|
1164
|
+
this.initializeVisibilityObserver();
|
|
1140
1165
|
/**
|
|
1141
1166
|
* Datetime uses Ionic components that emit
|
|
1142
1167
|
* ionFocus and ionBlur. These events are
|
|
@@ -1865,7 +1890,7 @@ const Datetime = class {
|
|
|
1865
1890
|
const hasDatePresentation = presentation === 'date' || presentation === 'date-time' || presentation === 'time-date';
|
|
1866
1891
|
const hasWheelVariant = hasDatePresentation && preferWheel;
|
|
1867
1892
|
renderHiddenInput(true, el, name, formatValue(value), disabled);
|
|
1868
|
-
return (h(Host, { key: '
|
|
1893
|
+
return (h(Host, { key: '2fb2938db507a134622a3feac44804f11071c589', "aria-disabled": disabled ? 'true' : null, onFocus: this.onFocus, onBlur: this.onBlur, class: Object.assign({}, createColorClasses(color, {
|
|
1869
1894
|
[mode]: true,
|
|
1870
1895
|
['datetime-readonly']: readonly,
|
|
1871
1896
|
['datetime-disabled']: disabled,
|