@ionic/core 7.3.2 → 7.3.3-dev.11693533652.1969cc78

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.
Files changed (189) hide show
  1. package/components/action-sheet.js +8 -16
  2. package/components/alert.js +8 -16
  3. package/components/framework-delegate.js +21 -2
  4. package/components/ion-loading.js +8 -16
  5. package/components/ion-modal.js +21 -29
  6. package/components/ion-picker.js +8 -16
  7. package/components/ion-router-outlet.js +1 -0
  8. package/components/ion-toast.js +8 -16
  9. package/components/label.js +2 -2
  10. package/components/lock-controller.js +38 -0
  11. package/components/popover.js +15 -29
  12. package/dist/cjs/{framework-delegate-e8174951.js → framework-delegate-c0873a6f.js} +21 -2
  13. package/dist/cjs/index.cjs.js +2 -2
  14. package/dist/cjs/ion-action-sheet.cjs.entry.js +10 -18
  15. package/dist/cjs/ion-alert.cjs.entry.js +10 -18
  16. package/dist/cjs/ion-app_8.cjs.entry.js +2 -1
  17. package/dist/cjs/ion-datetime_3.cjs.entry.js +10 -18
  18. package/dist/cjs/ion-item_8.cjs.entry.js +2 -2
  19. package/dist/cjs/ion-loading.cjs.entry.js +10 -18
  20. package/dist/cjs/ion-menu_3.cjs.entry.js +2 -2
  21. package/dist/cjs/ion-modal.cjs.entry.js +23 -31
  22. package/dist/cjs/ion-nav_2.cjs.entry.js +1 -1
  23. package/dist/cjs/ion-popover.cjs.entry.js +17 -31
  24. package/dist/cjs/ion-select_3.cjs.entry.js +2 -2
  25. package/dist/cjs/ion-tab_2.cjs.entry.js +1 -1
  26. package/dist/cjs/ion-toast.cjs.entry.js +10 -18
  27. package/dist/cjs/lock-controller-4ae2eb59.js +40 -0
  28. package/dist/cjs/{overlays-0ea06fcb.js → overlays-5c1706ed.js} +1 -1
  29. package/dist/collection/components/action-sheet/action-sheet.js +8 -16
  30. package/dist/collection/components/alert/alert.js +8 -16
  31. package/dist/collection/components/checkbox/test/color/checkbox.e2e.js +2 -2
  32. package/dist/collection/components/checkbox/test/item/checkbox.e2e.js +4 -4
  33. package/dist/collection/components/checkbox/test/label/checkbox.e2e.js +10 -10
  34. package/dist/collection/components/checkbox/test/legacy/basic/checkbox.e2e.js +1 -1
  35. package/dist/collection/components/checkbox/test/legacy/indeterminate/checkbox.e2e.js +1 -1
  36. package/dist/collection/components/checkbox/test/states/checkbox.e2e.js +4 -4
  37. package/dist/collection/components/datetime/test/custom/datetime.e2e.js +0 -7
  38. package/dist/collection/components/datetime/test/presentation/datetime.e2e.js +48 -17
  39. package/dist/collection/components/input/test/bottom-content/input.e2e.js +7 -7
  40. package/dist/collection/components/input/test/card/input.e2e.js +1 -1
  41. package/dist/collection/components/input/test/color/input.e2e.js +15 -15
  42. package/dist/collection/components/input/test/fill/input.e2e.js +10 -10
  43. package/dist/collection/components/input/test/highlight/input.e2e.js +9 -9
  44. package/dist/collection/components/input/test/item/input.e2e.js +2 -2
  45. package/dist/collection/components/input/test/label-placement/input.e2e.js +16 -16
  46. package/dist/collection/components/input/test/legacy/basic/input.e2e.js +10 -10
  47. package/dist/collection/components/input/test/states/input.e2e.js +2 -2
  48. package/dist/collection/components/label/label.ios.css +2 -4
  49. package/dist/collection/components/label/label.md.css +2 -4
  50. package/dist/collection/components/loading/loading.js +8 -16
  51. package/dist/collection/components/modal/modal.js +21 -29
  52. package/dist/collection/components/picker/picker.js +8 -16
  53. package/dist/collection/components/popover/popover.js +15 -29
  54. package/dist/collection/components/popover/test/async/popover.e2e.js +42 -0
  55. package/dist/collection/components/radio/test/color/radio.e2e.js +2 -2
  56. package/dist/collection/components/radio/test/item/radio.e2e.js +3 -3
  57. package/dist/collection/components/radio/test/label-placement/radio.e2e.js +9 -9
  58. package/dist/collection/components/radio/test/states/radio.e2e.js +4 -4
  59. package/dist/collection/components/range/test/color/range.e2e.js +1 -1
  60. package/dist/collection/components/range/test/custom/range.e2e.js +1 -1
  61. package/dist/collection/components/range/test/item/range.e2e.js +3 -3
  62. package/dist/collection/components/range/test/label/range.e2e.js +12 -12
  63. package/dist/collection/components/range/test/legacy/a11y/range.e2e.js +3 -3
  64. package/dist/collection/components/range/test/legacy/active-bar-start/range.e2e.js +1 -1
  65. package/dist/collection/components/range/test/legacy/basic/range.e2e.js +1 -1
  66. package/dist/collection/components/range/test/states/range.e2e.js +4 -4
  67. package/dist/collection/components/router-outlet/router-outlet.js +1 -0
  68. package/dist/collection/components/select/test/card/select.e2e.js +1 -1
  69. package/dist/collection/components/select/test/color/select.e2e.js +3 -3
  70. package/dist/collection/components/select/test/fill/select.e2e.js +10 -10
  71. package/dist/collection/components/select/test/highlight/select.e2e.js +3 -3
  72. package/dist/collection/components/select/test/item/select.e2e.js +2 -2
  73. package/dist/collection/components/select/test/label/select.e2e.js +20 -20
  74. package/dist/collection/components/select/test/states/select.e2e.js +4 -4
  75. package/dist/collection/components/textarea/test/bottom-content/textarea.e2e.js +6 -6
  76. package/dist/collection/components/textarea/test/card/textarea.e2e.js +1 -1
  77. package/dist/collection/components/textarea/test/color/textarea.e2e.js +15 -15
  78. package/dist/collection/components/textarea/test/fill/textarea.e2e.js +10 -10
  79. package/dist/collection/components/textarea/test/highlight/textarea.e2e.js +9 -9
  80. package/dist/collection/components/textarea/test/item/textarea.e2e.js +2 -2
  81. package/dist/collection/components/textarea/test/label-placement/textarea.e2e.js +21 -21
  82. package/dist/collection/components/textarea/test/legacy/autogrow/textarea.e2e.js +5 -5
  83. package/dist/collection/components/textarea/test/states/textarea.e2e.js +2 -2
  84. package/dist/collection/components/toast/toast.js +8 -16
  85. package/dist/collection/components/toggle/test/color/toggle.e2e.js +2 -2
  86. package/dist/collection/components/toggle/test/item/toggle.e2e.js +4 -4
  87. package/dist/collection/components/toggle/test/label/toggle.e2e.js +9 -9
  88. package/dist/collection/components/toggle/test/legacy/enable-on-off-labels/toggle.e2e.js +2 -2
  89. package/dist/collection/components/toggle/test/legacy/sizes/toggle.e2e.js +1 -1
  90. package/dist/collection/components/toggle/test/states/toggle.e2e.js +3 -3
  91. package/dist/collection/utils/framework-delegate.js +21 -2
  92. package/dist/collection/utils/lock-controller.js +36 -0
  93. package/dist/docs.json +1 -1
  94. package/dist/esm/{framework-delegate-2b76c681.js → framework-delegate-aa433dea.js} +21 -2
  95. package/dist/esm/index.js +2 -2
  96. package/dist/esm/ion-action-sheet.entry.js +10 -18
  97. package/dist/esm/ion-alert.entry.js +10 -18
  98. package/dist/esm/ion-app_8.entry.js +2 -1
  99. package/dist/esm/ion-datetime_3.entry.js +10 -18
  100. package/dist/esm/ion-item_8.entry.js +2 -2
  101. package/dist/esm/ion-loading.entry.js +10 -18
  102. package/dist/esm/ion-menu_3.entry.js +2 -2
  103. package/dist/esm/ion-modal.entry.js +23 -31
  104. package/dist/esm/ion-nav_2.entry.js +1 -1
  105. package/dist/esm/ion-popover.entry.js +17 -31
  106. package/dist/esm/ion-select_3.entry.js +2 -2
  107. package/dist/esm/ion-tab_2.entry.js +1 -1
  108. package/dist/esm/ion-toast.entry.js +10 -18
  109. package/dist/esm/lock-controller-e8c6c051.js +38 -0
  110. package/dist/esm/{overlays-c3387ec0.js → overlays-e1dadfe6.js} +1 -1
  111. package/dist/esm-es5/framework-delegate-aa433dea.js +4 -0
  112. package/dist/esm-es5/index.js +1 -1
  113. package/dist/esm-es5/ion-action-sheet.entry.js +1 -1
  114. package/dist/esm-es5/ion-alert.entry.js +1 -1
  115. package/dist/esm-es5/ion-app_8.entry.js +1 -1
  116. package/dist/esm-es5/ion-datetime_3.entry.js +1 -1
  117. package/dist/esm-es5/ion-item_8.entry.js +1 -1
  118. package/dist/esm-es5/ion-loading.entry.js +1 -1
  119. package/dist/esm-es5/ion-menu_3.entry.js +1 -1
  120. package/dist/esm-es5/ion-modal.entry.js +1 -1
  121. package/dist/esm-es5/ion-nav_2.entry.js +1 -1
  122. package/dist/esm-es5/ion-popover.entry.js +1 -1
  123. package/dist/esm-es5/ion-select_3.entry.js +1 -1
  124. package/dist/esm-es5/ion-tab_2.entry.js +1 -1
  125. package/dist/esm-es5/ion-toast.entry.js +1 -1
  126. package/dist/esm-es5/lock-controller-e8c6c051.js +4 -0
  127. package/dist/esm-es5/{overlays-c3387ec0.js → overlays-e1dadfe6.js} +1 -1
  128. package/dist/ionic/index.esm.js +1 -1
  129. package/dist/ionic/ionic.esm.js +1 -1
  130. package/dist/ionic/{p-958bde76.entry.js → p-091cd81e.entry.js} +1 -1
  131. package/dist/ionic/{p-d1356034.system.entry.js → p-0b68c41d.system.entry.js} +1 -1
  132. package/dist/ionic/p-0cc2bf5a.system.entry.js +4 -0
  133. package/dist/ionic/p-208f640c.entry.js +4 -0
  134. package/dist/ionic/p-2539e967.system.entry.js +4 -0
  135. package/dist/ionic/{p-74bd26b8.system.entry.js → p-28f5715a.system.entry.js} +1 -1
  136. package/dist/ionic/{p-b9312889.entry.js → p-341d5877.entry.js} +1 -1
  137. package/dist/ionic/p-38dd9aec.entry.js +4 -0
  138. package/dist/ionic/p-3ff018da.entry.js +4 -0
  139. package/dist/ionic/{p-8074bdd7.system.entry.js → p-45ee211b.system.entry.js} +1 -1
  140. package/dist/ionic/p-5009cb46.entry.js +4 -0
  141. package/dist/ionic/p-53b2a46f.js +4 -0
  142. package/dist/ionic/{p-5ef91692.js → p-582dc7c1.js} +1 -1
  143. package/dist/ionic/{p-79e30193.system.entry.js → p-5ba27716.system.entry.js} +1 -1
  144. package/dist/ionic/{p-c0d1e5a1.entry.js → p-5c17f888.entry.js} +1 -1
  145. package/dist/ionic/{p-8d9475b5.system.js → p-613d4042.system.js} +1 -1
  146. package/dist/ionic/p-647d15d4.system.entry.js +4 -0
  147. package/dist/ionic/p-653f2fc6.entry.js +4 -0
  148. package/dist/ionic/p-721933ff.system.js +1 -1
  149. package/dist/ionic/p-772f6c84.system.js +4 -0
  150. package/dist/ionic/p-87383d00.system.entry.js +4 -0
  151. package/dist/ionic/{p-db46fc66.system.js → p-8843b046.system.js} +1 -1
  152. package/dist/ionic/p-93e47822.entry.js +4 -0
  153. package/dist/ionic/{p-229df0d8.entry.js → p-98ebc376.entry.js} +1 -1
  154. package/dist/ionic/p-af0bc751.system.entry.js +4 -0
  155. package/dist/ionic/p-b0e9e0b8.system.entry.js +4 -0
  156. package/dist/ionic/p-b287ab05.js +4 -0
  157. package/dist/ionic/{p-81b46714.system.js → p-b32742f3.system.js} +1 -1
  158. package/dist/ionic/p-b3394798.system.entry.js +4 -0
  159. package/dist/ionic/{p-20087c90.entry.js → p-c759a704.entry.js} +1 -1
  160. package/dist/ionic/{p-6b9bf14c.system.entry.js → p-d1d3b740.system.entry.js} +1 -1
  161. package/dist/ionic/{p-8fa43732.system.entry.js → p-d693e765.system.entry.js} +1 -1
  162. package/dist/ionic/{p-5c96dc4e.entry.js → p-f7faa32d.entry.js} +1 -1
  163. package/dist/ionic/p-fabb7294.entry.js +4 -0
  164. package/dist/types/components/action-sheet/action-sheet.d.ts +1 -1
  165. package/dist/types/components/alert/alert.d.ts +1 -1
  166. package/dist/types/components/loading/loading.d.ts +1 -1
  167. package/dist/types/components/modal/modal.d.ts +1 -1
  168. package/dist/types/components/picker/picker.d.ts +1 -1
  169. package/dist/types/components/popover/popover.d.ts +1 -1
  170. package/dist/types/components/toast/toast.d.ts +1 -1
  171. package/dist/types/utils/lock-controller.d.ts +10 -0
  172. package/hydrate/index.js +127 -142
  173. package/package.json +1 -1
  174. package/dist/esm-es5/framework-delegate-2b76c681.js +0 -4
  175. package/dist/ionic/p-06f1f560.system.entry.js +0 -4
  176. package/dist/ionic/p-2936ec7f.system.entry.js +0 -4
  177. package/dist/ionic/p-29b3e70a.entry.js +0 -4
  178. package/dist/ionic/p-2bc49e5d.system.entry.js +0 -4
  179. package/dist/ionic/p-2da3e015.system.entry.js +0 -4
  180. package/dist/ionic/p-423d5a4d.entry.js +0 -4
  181. package/dist/ionic/p-564aaba3.entry.js +0 -4
  182. package/dist/ionic/p-61769039.entry.js +0 -4
  183. package/dist/ionic/p-74723f41.entry.js +0 -4
  184. package/dist/ionic/p-9b3c3564.entry.js +0 -4
  185. package/dist/ionic/p-b34c1ae1.js +0 -4
  186. package/dist/ionic/p-ccea9adc.system.entry.js +0 -4
  187. package/dist/ionic/p-d5db0834.system.entry.js +0 -4
  188. package/dist/ionic/p-d8538837.entry.js +0 -4
  189. package/dist/ionic/p-dd0b6889.system.entry.js +0 -4
@@ -10,7 +10,7 @@ configs().forEach(({ title, screenshot, config }) => {
10
10
  <ion-input label="Email" value="example@ionic.io" label-placement="start"></ion-input>
11
11
  `, config);
12
12
  const input = page.locator('ion-input');
13
- expect(await input.screenshot()).toMatchSnapshot(screenshot(`input-placement-start`));
13
+ await expect(input).toHaveScreenshot(screenshot(`input-placement-start`));
14
14
  });
15
15
  });
16
16
  test.describe(title('input: label placement end'), () => {
@@ -19,7 +19,7 @@ configs().forEach(({ title, screenshot, config }) => {
19
19
  <ion-input label="Email" value="example@ionic.io" label-placement="end"></ion-input>
20
20
  `, config);
21
21
  const input = page.locator('ion-input');
22
- expect(await input.screenshot()).toMatchSnapshot(screenshot(`input-placement-end`));
22
+ await expect(input).toHaveScreenshot(screenshot(`input-placement-end`));
23
23
  });
24
24
  });
25
25
  test.describe(title('input: label placement fixed'), () => {
@@ -28,7 +28,7 @@ configs().forEach(({ title, screenshot, config }) => {
28
28
  <ion-input label="Email Email Email Email Email Email" value="example@ionic.io" label-placement="fixed"></ion-input>
29
29
  `, config);
30
30
  const input = page.locator('ion-input');
31
- expect(await input.screenshot()).toMatchSnapshot(screenshot(`input-placement-fixed`));
31
+ await expect(input).toHaveScreenshot(screenshot(`input-placement-fixed`));
32
32
  });
33
33
  });
34
34
  test.describe(title('input: label placement stacked'), () => {
@@ -37,21 +37,21 @@ configs().forEach(({ title, screenshot, config }) => {
37
37
  <ion-input label="Email" value="example@ionic.io" label-placement="stacked"></ion-input>
38
38
  `, config);
39
39
  const input = page.locator('ion-input');
40
- expect(await input.screenshot()).toMatchSnapshot(screenshot(`input-placement-stacked-value`));
40
+ await expect(input).toHaveScreenshot(screenshot(`input-placement-stacked-value`));
41
41
  });
42
42
  test('label should appear above the input when there is a no value', async ({ page }) => {
43
43
  await page.setContent(`
44
44
  <ion-input label="Email" label-placement="stacked"></ion-input>
45
45
  `, config);
46
46
  const input = page.locator('ion-input');
47
- expect(await input.screenshot()).toMatchSnapshot(screenshot(`input-placement-stacked-no-value`));
47
+ await expect(input).toHaveScreenshot(screenshot(`input-placement-stacked-no-value`));
48
48
  });
49
49
  test('long label should truncate', async ({ page }) => {
50
50
  await page.setContent(`
51
51
  <ion-input label="Email Email Email Email Email Email Email Email Email Email Email Email" value="example@ionic.io" label-placement="stacked"></ion-input>
52
52
  `, config);
53
53
  const input = page.locator('ion-input');
54
- expect(await input.screenshot()).toMatchSnapshot(screenshot(`input-placement-stacked-long-label`));
54
+ await expect(input).toHaveScreenshot(screenshot(`input-placement-stacked-long-label`));
55
55
  });
56
56
  });
57
57
  test.describe(title('input: label placement floating'), () => {
@@ -60,14 +60,14 @@ configs().forEach(({ title, screenshot, config }) => {
60
60
  <ion-input label="Email" value="example@ionic.io" label-placement="floating"></ion-input>
61
61
  `, config);
62
62
  const input = page.locator('ion-input');
63
- expect(await input.screenshot()).toMatchSnapshot(screenshot(`input-placement-floating-value`));
63
+ await expect(input).toHaveScreenshot(screenshot(`input-placement-floating-value`));
64
64
  });
65
65
  test('label should appear on top of the input and hide the input when there is a no value', async ({ page }) => {
66
66
  await page.setContent(`
67
67
  <ion-input label="Email" label-placement="floating" placeholder="example@ionic.io"></ion-input>
68
68
  `, config);
69
69
  const input = page.locator('ion-input');
70
- expect(await input.screenshot()).toMatchSnapshot(screenshot(`input-placement-floating-no-value`));
70
+ await expect(input).toHaveScreenshot(screenshot(`input-placement-floating-no-value`));
71
71
  });
72
72
  test('label should appear on top of the input when the input is focused', async ({ page }) => {
73
73
  await page.setContent(`
@@ -77,14 +77,14 @@ configs().forEach(({ title, screenshot, config }) => {
77
77
  const nativeInput = input.locator('input');
78
78
  await nativeInput.click();
79
79
  await page.waitForChanges();
80
- expect(await input.screenshot({ animations: 'disabled' })).toMatchSnapshot(screenshot(`input-focused-placement-floating-no-value`));
80
+ await expect(input).toHaveScreenshot(screenshot(`input-focused-placement-floating-no-value`));
81
81
  });
82
82
  test('long label should truncate', async ({ page }) => {
83
83
  await page.setContent(`
84
84
  <ion-input label="Email Email Email Email Email Email Email Email Email Email Email Email" value="example@ionic.io" label-placement="floating"></ion-input>
85
85
  `, config);
86
86
  const input = page.locator('ion-input');
87
- expect(await input.screenshot()).toMatchSnapshot(screenshot(`input-placement-floating-long-label`));
87
+ await expect(input).toHaveScreenshot(screenshot(`input-placement-floating-long-label`));
88
88
  });
89
89
  });
90
90
  });
@@ -98,14 +98,14 @@ configs({ modes: ['md'] }).forEach(({ title, screenshot, config }) => {
98
98
  <ion-input fill="outline" label="Email Email Email Email Email Email Email Email Email Email Email Email" value="example@ionic.io" label-placement="floating"></ion-input>
99
99
  `, config);
100
100
  const input = page.locator('ion-input');
101
- expect(await input.screenshot()).toMatchSnapshot(screenshot(`input-placement-floating-long-label-outline`));
101
+ await expect(input).toHaveScreenshot(screenshot(`input-placement-floating-long-label-outline`));
102
102
  });
103
103
  test('long label should truncate with solid', async ({ page }) => {
104
104
  await page.setContent(`
105
105
  <ion-input fill="solid" label="Email Email Email Email Email Email Email Email Email Email Email Email" value="example@ionic.io" label-placement="floating"></ion-input>
106
106
  `, config);
107
107
  const input = page.locator('ion-input');
108
- expect(await input.screenshot()).toMatchSnapshot(screenshot(`input-placement-floating-long-label-solid`));
108
+ await expect(input).toHaveScreenshot(screenshot(`input-placement-floating-long-label-solid`));
109
109
  });
110
110
  });
111
111
  });
@@ -116,7 +116,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, co
116
116
  <ion-input label="Label Label Label Label Label" placeholder="Text Input"></ion-input>
117
117
  `, config);
118
118
  const input = page.locator('ion-input');
119
- expect(await input.screenshot()).toMatchSnapshot(screenshot(`input-label-truncate`));
119
+ await expect(input).toHaveScreenshot(screenshot(`input-label-truncate`));
120
120
  });
121
121
  test('label slot should be truncated with an ellipsis', async ({ page }) => {
122
122
  await page.setContent(`
@@ -125,7 +125,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, co
125
125
  </ion-input>
126
126
  `, config);
127
127
  const input = page.locator('ion-input');
128
- expect(await input.screenshot()).toMatchSnapshot(screenshot(`input-label-slot-truncate`));
128
+ await expect(input).toHaveScreenshot(screenshot(`input-label-slot-truncate`));
129
129
  });
130
130
  });
131
131
  test.describe(title('input: async label'), () => {
@@ -141,7 +141,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, co
141
141
  el.appendChild(labelEl);
142
142
  });
143
143
  await page.waitForChanges();
144
- expect(await input.screenshot()).toMatchSnapshot(screenshot(`input-async-label`));
144
+ await expect(input).toHaveScreenshot(screenshot(`input-async-label`));
145
145
  });
146
146
  });
147
147
  test.describe(title('input: floating/stacked label layering'), () => {
@@ -159,7 +159,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, co
159
159
  <ion-input class="custom-input" label="My Label" label-placement="stacked"></ion-input>
160
160
  `, config);
161
161
  const input = page.locator('ion-input');
162
- expect(await input.screenshot()).toMatchSnapshot(screenshot(`input-label-layering`));
162
+ await expect(input).toHaveScreenshot(screenshot(`input-label-layering`));
163
163
  });
164
164
  });
165
165
  });
@@ -18,7 +18,7 @@ configs().forEach(({ title, screenshot, config }) => {
18
18
  `, config);
19
19
  const item = page.locator('ion-item');
20
20
  // Validates the display of an input where text extends off the edge of the component.
21
- expect(await item.screenshot()).toMatchSnapshot(screenshot(`input-with-text-overflow`));
21
+ await expect(item).toHaveScreenshot(screenshot(`input-with-text-overflow`));
22
22
  });
23
23
  });
24
24
  test.describe('input with placeholder', () => {
@@ -34,7 +34,7 @@ configs().forEach(({ title, screenshot, config }) => {
34
34
  `, config);
35
35
  const item = page.locator('ion-item');
36
36
  // Validates the display of an input with a placeholder.
37
- expect(await item.screenshot()).toMatchSnapshot(screenshot(`input-with-placeholder`));
37
+ await expect(item).toHaveScreenshot(screenshot(`input-with-placeholder`));
38
38
  });
39
39
  });
40
40
  test.describe('input disabled', () => {
@@ -50,7 +50,7 @@ configs().forEach(({ title, screenshot, config }) => {
50
50
  `, config);
51
51
  const item = page.locator('ion-item');
52
52
  // Validates the display of an input in a disabled state.
53
- expect(await item.screenshot()).toMatchSnapshot(screenshot(`input-disabled`));
53
+ await expect(item).toHaveScreenshot(screenshot(`input-disabled`));
54
54
  });
55
55
  });
56
56
  test.describe('input with lines="full"', () => {
@@ -67,12 +67,12 @@ configs().forEach(({ title, screenshot, config }) => {
67
67
  const item = page.locator('ion-item');
68
68
  const input = page.locator('ion-input');
69
69
  // Validates the display of an input with an ion-item using lines="full".
70
- expect(await item.screenshot({ animations: 'disabled' })).toMatchSnapshot(screenshot(`input-with-lines-full`));
70
+ await expect(item).toHaveScreenshot(screenshot(`input-with-lines-full`));
71
71
  await input.click();
72
72
  // Verifies that the parent item receives .item-has-focus when the input is focused.
73
73
  await expect(item).toHaveClass(/item-has-focus/);
74
74
  // Validates the display of an input with an ion-item using lines="full" when focused.
75
- expect(await item.screenshot({ animations: 'disabled' })).toMatchSnapshot(screenshot(`input-with-lines-full-focused`));
75
+ await expect(item).toHaveScreenshot(screenshot(`input-with-lines-full-focused`));
76
76
  });
77
77
  });
78
78
  test.describe('input with lines="inset"', () => {
@@ -89,12 +89,12 @@ configs().forEach(({ title, screenshot, config }) => {
89
89
  const item = page.locator('ion-item');
90
90
  const input = page.locator('ion-input');
91
91
  // Validates the display of an input with an ion-item using lines="inset".
92
- expect(await item.screenshot({ animations: 'disabled' })).toMatchSnapshot(screenshot(`input-with-lines-inset`));
92
+ await expect(item).toHaveScreenshot(screenshot(`input-with-lines-inset`));
93
93
  await input.click();
94
94
  // Verifies that the parent item receives .item-has-focus when the input is focused.
95
95
  await expect(item).toHaveClass(/item-has-focus/);
96
96
  // Validates the display of an input with an ion-item using lines="inset" when focused.
97
- expect(await item.screenshot({ animations: 'disabled' })).toMatchSnapshot(screenshot(`input-with-lines-inset-focused`));
97
+ await expect(item).toHaveScreenshot(screenshot(`input-with-lines-inset-focused`));
98
98
  });
99
99
  });
100
100
  test.describe('input with lines="none"', () => {
@@ -111,12 +111,12 @@ configs().forEach(({ title, screenshot, config }) => {
111
111
  const item = page.locator('ion-item');
112
112
  const input = page.locator('ion-input');
113
113
  // Validates the display of an input with an ion-item using lines="none".
114
- expect(await item.screenshot({ animations: 'disabled' })).toMatchSnapshot(screenshot(`input-with-lines-none`));
114
+ await expect(item).toHaveScreenshot(screenshot(`input-with-lines-none`));
115
115
  await input.click();
116
116
  // Verifies that the parent item receives .item-has-focus when the input is focused.
117
117
  await expect(item).toHaveClass(/item-has-focus/);
118
118
  // Validates the display of an input with an ion-item using lines="none" when focused.
119
- expect(await item.screenshot({ animations: 'disabled' })).toMatchSnapshot(screenshot(`input-with-lines-none-focused`));
119
+ await expect(item).toHaveScreenshot(screenshot(`input-with-lines-none-focused`));
120
120
  });
121
121
  });
122
122
  test.describe('input with clear button', () => {
@@ -137,7 +137,7 @@ configs().forEach(({ title, screenshot, config }) => {
137
137
  `, config);
138
138
  const item = page.locator('ion-item');
139
139
  // Validates the display of an input with a clear button.
140
- expect(await item.screenshot()).toMatchSnapshot(screenshot(`input-with-clear-button`));
140
+ await expect(item).toHaveScreenshot(screenshot(`input-with-clear-button`));
141
141
  });
142
142
  });
143
143
  });
@@ -10,14 +10,14 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
10
10
  <ion-input label="Email" value="hi@ionic.io" readonly="true"></ion-input>
11
11
  `, config);
12
12
  const input = page.locator('ion-input');
13
- expect(await input.screenshot()).toMatchSnapshot(screenshot(`input-readonly`));
13
+ await expect(input).toHaveScreenshot(screenshot(`input-readonly`));
14
14
  });
15
15
  test('should render disabled input correctly', async ({ page }) => {
16
16
  await page.setContent(`
17
17
  <ion-input label="Email" value="hi@ionic.io" disabled="true"></ion-input>
18
18
  `, config);
19
19
  const input = page.locator('ion-input');
20
- expect(await input.screenshot()).toMatchSnapshot(screenshot(`input-disabled`));
20
+ await expect(input).toHaveScreenshot(screenshot(`input-disabled`));
21
21
  });
22
22
  });
23
23
  });
@@ -17,8 +17,7 @@
17
17
  color: var(--ion-color-base);
18
18
  }
19
19
 
20
- :host(.ion-text-wrap),
21
- :host([text-wrap]) {
20
+ :host(.ion-text-wrap) {
22
21
  white-space: normal;
23
22
  }
24
23
 
@@ -67,8 +66,7 @@
67
66
  overflow: inherit;
68
67
  }
69
68
 
70
- :host(.ion-text-wrap),
71
- :host([text-wrap]) {
69
+ :host(.ion-text-wrap) {
72
70
  font-size: 14px;
73
71
  line-height: 1.5;
74
72
  }
@@ -17,8 +17,7 @@
17
17
  color: var(--ion-color-base);
18
18
  }
19
19
 
20
- :host(.ion-text-wrap),
21
- :host([text-wrap]) {
20
+ :host(.ion-text-wrap) {
22
21
  white-space: normal;
23
22
  }
24
23
 
@@ -67,8 +66,7 @@
67
66
  overflow: inherit;
68
67
  }
69
68
 
70
- :host(.ion-text-wrap),
71
- :host([text-wrap]) {
69
+ :host(.ion-text-wrap) {
72
70
  line-height: 1.5;
73
71
  }
74
72
 
@@ -4,6 +4,7 @@
4
4
  import { Host, h } from "@stencil/core";
5
5
  import { ENABLE_HTML_CONTENT_DEFAULT } from "../../utils/config";
6
6
  import { raf } from "../../utils/helpers";
7
+ import { createLockController } from "../../utils/lock-controller";
7
8
  import { BACKDROP, dismiss, eventMethod, prepareOverlay, present, createDelegateController, createTriggerController, setOverlayId, } from "../../utils/overlays";
8
9
  import { sanitizeDOMString } from "../../utils/sanitization/index";
9
10
  import { getClassMap } from "../../utils/theme";
@@ -20,6 +21,7 @@ import { mdLeaveAnimation } from "./animations/md.leave";
20
21
  export class Loading {
21
22
  constructor() {
22
23
  this.delegateController = createDelegateController(this);
24
+ this.lockController = createLockController();
23
25
  this.triggerController = createTriggerController();
24
26
  this.customHTMLEnabled = config.get('innerHTMLTemplatesEnabled', ENABLE_HTML_CONTENT_DEFAULT);
25
27
  this.presented = false;
@@ -85,24 +87,13 @@ export class Loading {
85
87
  * Present the loading overlay after it has been created.
86
88
  */
87
89
  async present() {
88
- /**
89
- * When using an inline loading indicator
90
- * and dismissing a loading indicator it is possible to
91
- * quickly present the loading indicator while it is
92
- * dismissing. We need to await any current
93
- * transition to allow the dismiss to finish
94
- * before presenting again.
95
- */
96
- if (this.currentTransition !== undefined) {
97
- await this.currentTransition;
98
- }
90
+ const unlock = await this.lockController.lock();
99
91
  await this.delegateController.attachViewToDom();
100
- this.currentTransition = present(this, 'loadingEnter', iosEnterAnimation, mdEnterAnimation);
101
- await this.currentTransition;
92
+ await present(this, 'loadingEnter', iosEnterAnimation, mdEnterAnimation);
102
93
  if (this.duration > 0) {
103
94
  this.durationTimeout = setTimeout(() => this.dismiss(), this.duration + 10);
104
95
  }
105
- this.currentTransition = undefined;
96
+ unlock();
106
97
  }
107
98
  /**
108
99
  * Dismiss the loading overlay after it has been presented.
@@ -114,14 +105,15 @@ export class Loading {
114
105
  * Some examples include: ``"cancel"`, `"destructive"`, "selected"`, and `"backdrop"`.
115
106
  */
116
107
  async dismiss(data, role) {
108
+ const unlock = await this.lockController.lock();
117
109
  if (this.durationTimeout) {
118
110
  clearTimeout(this.durationTimeout);
119
111
  }
120
- this.currentTransition = dismiss(this, data, role, 'loadingLeave', iosLeaveAnimation, mdLeaveAnimation);
121
- const dismissed = await this.currentTransition;
112
+ const dismissed = await dismiss(this, data, role, 'loadingLeave', iosLeaveAnimation, mdLeaveAnimation);
122
113
  if (dismissed) {
123
114
  this.delegateController.removeViewFromDom();
124
115
  }
116
+ unlock();
125
117
  return dismissed;
126
118
  }
127
119
  /**
@@ -5,6 +5,7 @@ import { Host, h, writeTask } from "@stencil/core";
5
5
  import { findIonContent, printIonContentErrorMsg } from "../../utils/content/index";
6
6
  import { CoreDelegate, attachComponent, detachComponent } from "../../utils/framework-delegate";
7
7
  import { raf, inheritAttributes, hasLazyBuild } from "../../utils/helpers";
8
+ import { createLockController } from "../../utils/lock-controller";
8
9
  import { printIonWarning } from "../../utils/logging/index";
9
10
  import { Style as StatusBarStyle, StatusBar } from "../../utils/native/status-bar";
10
11
  import { GESTURE, BACKDROP, activeAnimations, dismiss, eventMethod, prepareOverlay, present, createTriggerController, setOverlayId, } from "../../utils/overlays";
@@ -32,6 +33,7 @@ import { setCardStatusBarDark, setCardStatusBarDefault } from "./utils";
32
33
  */
33
34
  export class Modal {
34
35
  constructor() {
36
+ this.lockController = createLockController();
35
37
  this.triggerController = createTriggerController();
36
38
  this.coreDelegate = CoreDelegate();
37
39
  this.isSheetModal = false;
@@ -196,29 +198,25 @@ export class Modal {
196
198
  * Present the modal overlay after it has been created.
197
199
  */
198
200
  async present() {
201
+ const unlock = await this.lockController.lock();
199
202
  if (this.presented) {
203
+ unlock();
200
204
  return;
201
205
  }
202
206
  const { presentingElement, el } = this;
203
- /**
204
- * When using an inline modal
205
- * and dismissing a modal it is possible to
206
- * quickly present the modal while it is
207
- * dismissing. We need to await any current
208
- * transition to allow the dismiss to finish
209
- * before presenting again.
210
- */
211
- if (this.currentTransition !== undefined) {
212
- await this.currentTransition;
213
- }
214
207
  /**
215
208
  * If the modal is presented multiple times (inline modals), we
216
209
  * need to reset the current breakpoint to the initial breakpoint.
217
210
  */
218
211
  this.currentBreakpoint = this.initialBreakpoint;
219
212
  const { inline, delegate } = this.getDelegate(true);
220
- this.usersElement = await attachComponent(delegate, el, this.component, ['ion-page'], this.componentProps, inline);
213
+ /**
214
+ * Emit ionMount so JS Frameworks have an opportunity
215
+ * to add the child component to the DOM. The child
216
+ * component will be assigned to this.usersElement below.
217
+ */
221
218
  this.ionMount.emit();
219
+ this.usersElement = await attachComponent(delegate, el, this.component, ['ion-page'], this.componentProps, inline);
222
220
  /**
223
221
  * When using the lazy loaded build of Stencil, we need to wait
224
222
  * for every Stencil component instance to be ready before presenting
@@ -242,7 +240,7 @@ export class Modal {
242
240
  await waitForMount();
243
241
  }
244
242
  writeTask(() => this.el.classList.add('show-modal'));
245
- this.currentTransition = present(this, 'modalEnter', iosEnterAnimation, mdEnterAnimation, {
243
+ await present(this, 'modalEnter', iosEnterAnimation, mdEnterAnimation, {
246
244
  presentingEl: presentingElement,
247
245
  currentBreakpoint: this.initialBreakpoint,
248
246
  backdropBreakpoint: this.backdropBreakpoint,
@@ -289,14 +287,13 @@ export class Modal {
289
287
  this.statusBarStyle = await StatusBar.getStyle();
290
288
  setCardStatusBarDark();
291
289
  }
292
- await this.currentTransition;
293
290
  if (this.isSheetModal) {
294
291
  this.initSheetGesture();
295
292
  }
296
293
  else if (hasCardModal) {
297
294
  this.initSwipeToClose();
298
295
  }
299
- this.currentTransition = undefined;
296
+ unlock();
300
297
  }
301
298
  initSwipeToClose() {
302
299
  var _a;
@@ -386,12 +383,19 @@ export class Modal {
386
383
  if (this.gestureAnimationDismissing && role !== GESTURE) {
387
384
  return false;
388
385
  }
386
+ /**
387
+ * Because the canDismiss check below is async,
388
+ * we need to claim a lock before the check happens,
389
+ * in case the dismiss transition does run.
390
+ */
391
+ const unlock = await this.lockController.lock();
389
392
  /**
390
393
  * If a canDismiss handler is responsible
391
394
  * for calling the dismiss method, we should
392
395
  * not run the canDismiss check again.
393
396
  */
394
397
  if (role !== 'handler' && !(await this.checkCanDismiss(data, role))) {
398
+ unlock();
395
399
  return false;
396
400
  }
397
401
  const { presentingElement } = this;
@@ -409,24 +413,12 @@ export class Modal {
409
413
  window.removeEventListener(KEYBOARD_DID_OPEN, this.keyboardOpenCallback);
410
414
  this.keyboardOpenCallback = undefined;
411
415
  }
412
- /**
413
- * When using an inline modal
414
- * and presenting a modal it is possible to
415
- * quickly dismiss the modal while it is
416
- * presenting. We need to await any current
417
- * transition to allow the present to finish
418
- * before dismissing again.
419
- */
420
- if (this.currentTransition !== undefined) {
421
- await this.currentTransition;
422
- }
423
416
  const enteringAnimation = activeAnimations.get(this) || [];
424
- this.currentTransition = dismiss(this, data, role, 'modalLeave', iosLeaveAnimation, mdLeaveAnimation, {
417
+ const dismissed = await dismiss(this, data, role, 'modalLeave', iosLeaveAnimation, mdLeaveAnimation, {
425
418
  presentingEl: presentingElement,
426
419
  currentBreakpoint: (_a = this.currentBreakpoint) !== null && _a !== void 0 ? _a : this.initialBreakpoint,
427
420
  backdropBreakpoint: this.backdropBreakpoint,
428
421
  });
429
- const dismissed = await this.currentTransition;
430
422
  if (dismissed) {
431
423
  const { delegate } = this.getDelegate();
432
424
  await detachComponent(delegate, this.usersElement);
@@ -440,8 +432,8 @@ export class Modal {
440
432
  enteringAnimation.forEach((ani) => ani.destroy());
441
433
  }
442
434
  this.currentBreakpoint = undefined;
443
- this.currentTransition = undefined;
444
435
  this.animation = undefined;
436
+ unlock();
445
437
  return dismissed;
446
438
  }
447
439
  /**
@@ -3,6 +3,7 @@
3
3
  */
4
4
  import { Host, h } from "@stencil/core";
5
5
  import { raf } from "../../utils/helpers";
6
+ import { createLockController } from "../../utils/lock-controller";
6
7
  import { createDelegateController, createTriggerController, BACKDROP, dismiss, eventMethod, isCancel, prepareOverlay, present, safeCall, setOverlayId, } from "../../utils/overlays";
7
8
  import { getClassMap } from "../../utils/theme";
8
9
  import { getIonMode } from "../../global/ionic-global";
@@ -15,6 +16,7 @@ import { iosLeaveAnimation } from "./animations/ios.leave";
15
16
  export class Picker {
16
17
  constructor() {
17
18
  this.delegateController = createDelegateController(this);
19
+ this.lockController = createLockController();
18
20
  this.triggerController = createTriggerController();
19
21
  this.onBackdropTap = () => {
20
22
  this.dismiss(undefined, BACKDROP);
@@ -81,24 +83,13 @@ export class Picker {
81
83
  * Present the picker overlay after it has been created.
82
84
  */
83
85
  async present() {
84
- /**
85
- * When using an inline picker
86
- * and dismissing an picker it is possible to
87
- * quickly present the picker while it is
88
- * dismissing. We need to await any current
89
- * transition to allow the dismiss to finish
90
- * before presenting again.
91
- */
92
- if (this.currentTransition !== undefined) {
93
- await this.currentTransition;
94
- }
86
+ const unlock = await this.lockController.lock();
95
87
  await this.delegateController.attachViewToDom();
96
- this.currentTransition = present(this, 'pickerEnter', iosEnterAnimation, iosEnterAnimation, undefined);
97
- await this.currentTransition;
98
- this.currentTransition = undefined;
88
+ await present(this, 'pickerEnter', iosEnterAnimation, iosEnterAnimation, undefined);
99
89
  if (this.duration > 0) {
100
90
  this.durationTimeout = setTimeout(() => this.dismiss(), this.duration);
101
91
  }
92
+ unlock();
102
93
  }
103
94
  /**
104
95
  * Dismiss the picker overlay after it has been presented.
@@ -110,14 +101,15 @@ export class Picker {
110
101
  * Some examples include: ``"cancel"`, `"destructive"`, "selected"`, and `"backdrop"`.
111
102
  */
112
103
  async dismiss(data, role) {
104
+ const unlock = await this.lockController.lock();
113
105
  if (this.durationTimeout) {
114
106
  clearTimeout(this.durationTimeout);
115
107
  }
116
- this.currentTransition = dismiss(this, data, role, 'pickerLeave', iosLeaveAnimation, iosLeaveAnimation);
117
- const dismissed = await this.currentTransition;
108
+ const dismissed = await dismiss(this, data, role, 'pickerLeave', iosLeaveAnimation, iosLeaveAnimation);
118
109
  if (dismissed) {
119
110
  this.delegateController.removeViewFromDom();
120
111
  }
112
+ unlock();
121
113
  return dismissed;
122
114
  }
123
115
  /**
@@ -4,6 +4,7 @@
4
4
  import { Host, h } from "@stencil/core";
5
5
  import { CoreDelegate, attachComponent, detachComponent } from "../../utils/framework-delegate";
6
6
  import { addEventListener, raf, hasLazyBuild } from "../../utils/helpers";
7
+ import { createLockController } from "../../utils/lock-controller";
7
8
  import { printIonWarning } from "../../utils/logging/index";
8
9
  import { BACKDROP, dismiss, eventMethod, focusFirstDescendant, prepareOverlay, present, setOverlayId, } from "../../utils/overlays";
9
10
  import { isPlatform } from "../../utils/platform";
@@ -29,6 +30,7 @@ export class Popover {
29
30
  constructor() {
30
31
  this.parentPopover = null;
31
32
  this.coreDelegate = CoreDelegate();
33
+ this.lockController = createLockController();
32
34
  this.inline = false;
33
35
  this.focusDescendantOnPresent = false;
34
36
  this.onBackdropTap = () => {
@@ -202,28 +204,24 @@ export class Popover {
202
204
  * was dispatched.
203
205
  */
204
206
  async present(event) {
207
+ const unlock = await this.lockController.lock();
205
208
  if (this.presented) {
209
+ unlock();
206
210
  return;
207
211
  }
208
- /**
209
- * When using an inline popover
210
- * and dismissing a popover it is possible to
211
- * quickly present the popover while it is
212
- * dismissing. We need to await any current
213
- * transition to allow the dismiss to finish
214
- * before presenting again.
215
- */
216
- if (this.currentTransition !== undefined) {
217
- await this.currentTransition;
218
- }
219
212
  const { el } = this;
220
213
  const { inline, delegate } = this.getDelegate(true);
214
+ /**
215
+ * Emit ionMount so JS Frameworks have an opportunity
216
+ * to add the child component to the DOM. The child
217
+ * component will be assigned to this.usersElement below.
218
+ */
219
+ this.ionMount.emit();
221
220
  this.usersElement = await attachComponent(delegate, el, this.component, ['popover-viewport'], this.componentProps, inline);
222
221
  if (!this.keyboardEvents) {
223
222
  this.configureKeyboardInteraction();
224
223
  }
225
224
  this.configureDismissInteraction();
226
- this.ionMount.emit();
227
225
  /**
228
226
  * When using the lazy loaded build of Stencil, we need to wait
229
227
  * for every Stencil component instance to be ready before presenting
@@ -246,7 +244,7 @@ export class Popover {
246
244
  else if (!this.keepContentsMounted) {
247
245
  await waitForMount();
248
246
  }
249
- this.currentTransition = present(this, 'popoverEnter', iosEnterAnimation, mdEnterAnimation, {
247
+ await present(this, 'popoverEnter', iosEnterAnimation, mdEnterAnimation, {
250
248
  event: event || this.event,
251
249
  size: this.size,
252
250
  trigger: this.triggerEl,
@@ -254,8 +252,6 @@ export class Popover {
254
252
  side: this.side,
255
253
  align: this.alignment,
256
254
  });
257
- await this.currentTransition;
258
- this.currentTransition = undefined;
259
255
  /**
260
256
  * If popover is nested and was
261
257
  * presented using the "Right" arrow key,
@@ -265,6 +261,7 @@ export class Popover {
265
261
  if (this.focusDescendantOnPresent) {
266
262
  focusFirstDescendant(this.el, this.el);
267
263
  }
264
+ unlock();
268
265
  }
269
266
  /**
270
267
  * Dismiss the popover overlay after it has been presented.
@@ -275,23 +272,12 @@ export class Popover {
275
272
  * a parent popover if this popover is nested. Defaults to `true`.
276
273
  */
277
274
  async dismiss(data, role, dismissParentPopover = true) {
278
- /**
279
- * When using an inline popover
280
- * and presenting a popover it is possible to
281
- * quickly dismiss the popover while it is
282
- * presenting. We need to await any current
283
- * transition to allow the present to finish
284
- * before dismissing again.
285
- */
286
- if (this.currentTransition !== undefined) {
287
- await this.currentTransition;
288
- }
275
+ const unlock = await this.lockController.lock();
289
276
  const { destroyKeyboardInteraction, destroyDismissInteraction } = this;
290
277
  if (dismissParentPopover && this.parentPopover) {
291
278
  this.parentPopover.dismiss(data, role, dismissParentPopover);
292
279
  }
293
- this.currentTransition = dismiss(this, data, role, 'popoverLeave', iosLeaveAnimation, mdLeaveAnimation, this.event);
294
- const shouldDismiss = await this.currentTransition;
280
+ const shouldDismiss = await dismiss(this, data, role, 'popoverLeave', iosLeaveAnimation, mdLeaveAnimation, this.event);
295
281
  if (shouldDismiss) {
296
282
  if (destroyKeyboardInteraction) {
297
283
  destroyKeyboardInteraction();
@@ -309,7 +295,7 @@ export class Popover {
309
295
  const { delegate } = this.getDelegate();
310
296
  await detachComponent(delegate, this.usersElement);
311
297
  }
312
- this.currentTransition = undefined;
298
+ unlock();
313
299
  return shouldDismiss;
314
300
  }
315
301
  /**