Skip to content

Commit e63841c

Browse files
committed
test(modal): add content-height preview test
1 parent 4e8ecc2 commit e63841c

1 file changed

Lines changed: 353 additions & 0 deletions

File tree

  • core/src/components/modal/test/content-height
Lines changed: 353 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,353 @@
1+
<!DOCTYPE html>
2+
<html lang="en" dir="ltr">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<title>Modal - Content Height</title>
6+
<meta name="apple-mobile-web-app-capable" content="yes" />
7+
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
8+
<meta
9+
name="viewport"
10+
content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
11+
/>
12+
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
13+
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
14+
<script src="../../../../../scripts/testing/scripts.js"></script>
15+
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
16+
<script>
17+
/* Page two is taller than page one, to show the modal resize on navigation. */
18+
class NavPageOne extends HTMLElement {
19+
connectedCallback() {
20+
this.innerHTML = `
21+
<ion-header>
22+
<ion-toolbar>
23+
<ion-title>Page One</ion-title>
24+
</ion-toolbar>
25+
</ion-header>
26+
<ion-content class="ion-padding">
27+
<p>Short first page.</p>
28+
<ion-nav-link router-direction="forward" component="nav-page-two">
29+
<ion-button id="go-page-two" expand="block">Go to Page Two</ion-button>
30+
</ion-nav-link>
31+
</ion-content>
32+
`;
33+
}
34+
}
35+
36+
class NavPageTwo extends HTMLElement {
37+
connectedCallback() {
38+
this.innerHTML = `
39+
<ion-header>
40+
<ion-toolbar>
41+
<ion-buttons slot="start">
42+
<ion-back-button></ion-back-button>
43+
</ion-buttons>
44+
<ion-title>Page Two</ion-title>
45+
</ion-toolbar>
46+
</ion-header>
47+
<ion-content class="ion-padding">
48+
<div id="tall-block" style="height: 320px; background: #d0e6ff"></div>
49+
</ion-content>
50+
`;
51+
}
52+
}
53+
54+
class NavHost extends HTMLElement {
55+
connectedCallback() {
56+
this.innerHTML = `
57+
<ion-content>
58+
<ion-nav root="nav-page-one"></ion-nav>
59+
</ion-content>
60+
`;
61+
}
62+
}
63+
64+
customElements.define('nav-page-one', NavPageOne);
65+
customElements.define('nav-page-two', NavPageTwo);
66+
customElements.define('nav-host', NavHost);
67+
</script>
68+
69+
<style>
70+
/*
71+
* Shared modal styles. Only the height differs
72+
* between the modal examples.
73+
*/
74+
ion-modal {
75+
--width: fit-content;
76+
--min-width: 250px;
77+
--border-radius: 6px;
78+
--box-shadow: 0 28px 48px rgba(0, 0, 0, 0.4);
79+
}
80+
81+
/* Each of these sizes the modal from its contents. */
82+
ion-modal#fit-content-modal {
83+
--height: fit-content;
84+
}
85+
86+
ion-modal#auto-modal {
87+
--height: auto;
88+
}
89+
90+
ion-modal#min-content-modal {
91+
--height: min-content;
92+
}
93+
94+
ion-modal#max-content-modal {
95+
--height: max-content;
96+
}
97+
98+
/**
99+
* Controls. A definite height is not content-sized, so `content-sizing`
100+
* must not apply: the content fills the 300px and scrolls the overflow
101+
* the way it always has.
102+
*/
103+
ion-modal#px-modal {
104+
--height: 300px;
105+
}
106+
107+
/**
108+
* Taller than the overlay. The default `--max-height: 100%` clamps this,
109+
* where before it would run off screen.
110+
*/
111+
ion-modal#px-tall-modal {
112+
--height: 2000px;
113+
}
114+
115+
/**
116+
* Known gap: `part="content"` is the same element that `--height` sizes,
117+
* so this collapses exactly like the others, but the height keyword is
118+
* not readable from the custom property and is therefore not detected.
119+
* Expect a modal displaying only a header here.
120+
*/
121+
ion-modal#part-modal::part(content) {
122+
height: fit-content;
123+
}
124+
125+
/**
126+
* A content-sized modal is clamped by the default `--max-height: 100%`,
127+
* so a long list scrolls inside the overlay rather than running off
128+
* screen.
129+
*/
130+
ion-modal#long-modal {
131+
--height: fit-content;
132+
}
133+
134+
/* The same long list with a max height. */
135+
ion-modal#long-max-height-modal {
136+
--height: fit-content;
137+
--max-height: 50%;
138+
}
139+
140+
/**
141+
* A content-sized modal containing an `ion-nav` must be handled
142+
* differently because a nav uses `position: absolute` by default.
143+
*/
144+
ion-modal#nav-modal {
145+
--height: fit-content;
146+
}
147+
148+
/**
149+
* No `ion-content` at all. This does not require any special handling,
150+
* but we want to make sure it did not regress.
151+
*/
152+
ion-modal#no-content-modal {
153+
--height: fit-content;
154+
}
155+
156+
ion-modal#no-content-modal h1 {
157+
margin: 20px 20px 10px 20px;
158+
}
159+
</style>
160+
</head>
161+
162+
<body>
163+
<ion-app>
164+
<div class="ion-page">
165+
<ion-header>
166+
<ion-toolbar>
167+
<ion-title>Modal - Content Height</ion-title>
168+
</ion-toolbar>
169+
</ion-header>
170+
171+
<ion-content class="ion-padding">
172+
<ion-button id="open-fit-content" expand="block">--height: fit-content</ion-button>
173+
<ion-button id="open-auto" expand="block">--height: auto</ion-button>
174+
<ion-button id="open-min-content" expand="block">--height: min-content</ion-button>
175+
<ion-button id="open-max-content" expand="block">--height: max-content</ion-button>
176+
<ion-button id="open-default" expand="block" color="medium">default height</ion-button>
177+
<ion-button id="open-px" expand="block" color="medium">--height: 300px</ion-button>
178+
<ion-button id="open-px-tall" expand="block" color="medium">--height: 2000px (taller than screen)</ion-button>
179+
<ion-button id="open-part" expand="block" color="danger">::part(content) (failing)</ion-button>
180+
<ion-button id="open-long" expand="block" color="tertiary">--height: fit-content, overflowing</ion-button>
181+
<ion-button id="open-long-max-height" expand="block" color="tertiary"
182+
>--height: fit-content, overflowing, max height</ion-button
183+
>
184+
<ion-button id="open-nav" expand="block" color="tertiary">--height: fit-content, ion-nav</ion-button>
185+
<ion-button id="open-no-content" expand="block" color="tertiary"
186+
>--height: fit-content, no ion-content</ion-button
187+
>
188+
189+
<ion-modal id="fit-content-modal" trigger="open-fit-content">
190+
<ion-header>
191+
<ion-toolbar>
192+
<ion-title>fit-content</ion-title>
193+
</ion-toolbar>
194+
</ion-header>
195+
<ion-content>
196+
<div class="wrapper"><ion-list class="short" lines="none"></ion-list></div>
197+
</ion-content>
198+
</ion-modal>
199+
200+
<ion-modal id="auto-modal" trigger="open-auto">
201+
<ion-header>
202+
<ion-toolbar>
203+
<ion-title>auto</ion-title>
204+
</ion-toolbar>
205+
</ion-header>
206+
<ion-content>
207+
<div class="wrapper"><ion-list class="short" lines="none"></ion-list></div>
208+
</ion-content>
209+
</ion-modal>
210+
211+
<ion-modal id="min-content-modal" trigger="open-min-content">
212+
<ion-header>
213+
<ion-toolbar>
214+
<ion-title>min-content</ion-title>
215+
</ion-toolbar>
216+
</ion-header>
217+
<ion-content>
218+
<div class="wrapper"><ion-list class="short" lines="none"></ion-list></div>
219+
</ion-content>
220+
</ion-modal>
221+
222+
<ion-modal id="max-content-modal" trigger="open-max-content">
223+
<ion-header>
224+
<ion-toolbar>
225+
<ion-title>max-content</ion-title>
226+
</ion-toolbar>
227+
</ion-header>
228+
<ion-content>
229+
<div class="wrapper"><ion-list class="short" lines="none"></ion-list></div>
230+
</ion-content>
231+
</ion-modal>
232+
233+
<!-- Control: the default modal must fill the screen height. -->
234+
<ion-modal id="default-modal" trigger="open-default">
235+
<ion-header>
236+
<ion-toolbar>
237+
<ion-title>default height</ion-title>
238+
</ion-toolbar>
239+
</ion-header>
240+
<ion-content>
241+
<div class="wrapper"><ion-list class="short" lines="none"></ion-list></div>
242+
</ion-content>
243+
</ion-modal>
244+
245+
<ion-modal id="px-modal" trigger="open-px">
246+
<ion-header>
247+
<ion-toolbar>
248+
<ion-title>300px</ion-title>
249+
</ion-toolbar>
250+
</ion-header>
251+
<ion-content>
252+
<div class="wrapper"><ion-list class="long" lines="none"></ion-list></div>
253+
</ion-content>
254+
</ion-modal>
255+
256+
<ion-modal id="px-tall-modal" trigger="open-px-tall">
257+
<ion-header>
258+
<ion-toolbar>
259+
<ion-title>2000px</ion-title>
260+
</ion-toolbar>
261+
</ion-header>
262+
<ion-content>
263+
<div class="wrapper"><ion-list class="long" lines="none"></ion-list></div>
264+
</ion-content>
265+
</ion-modal>
266+
267+
<ion-modal id="part-modal" trigger="open-part">
268+
<ion-header>
269+
<ion-toolbar>
270+
<ion-title>::part(content)</ion-title>
271+
</ion-toolbar>
272+
</ion-header>
273+
<ion-content>
274+
<div class="wrapper"><ion-list class="short" lines="none"></ion-list></div>
275+
</ion-content>
276+
</ion-modal>
277+
278+
<ion-modal id="long-modal" trigger="open-long">
279+
<ion-header>
280+
<ion-toolbar>
281+
<ion-title>fit-content</ion-title>
282+
</ion-toolbar>
283+
</ion-header>
284+
<ion-content>
285+
<div class="wrapper"><ion-list class="long" lines="none"></ion-list></div>
286+
</ion-content>
287+
</ion-modal>
288+
289+
<ion-modal id="long-max-height-modal" trigger="open-long-max-height">
290+
<ion-header>
291+
<ion-toolbar>
292+
<ion-title>fit-content, max-height</ion-title>
293+
</ion-toolbar>
294+
</ion-header>
295+
<ion-content>
296+
<div class="wrapper"><ion-list class="long" lines="none"></ion-list></div>
297+
</ion-content>
298+
</ion-modal>
299+
300+
<ion-modal id="nav-modal" trigger="open-nav"></ion-modal>
301+
302+
<!-- A modal built without ion-content, sized entirely by its markup. -->
303+
<ion-modal id="no-content-modal" trigger="open-no-content">
304+
<div class="wrapper">
305+
<h1>Modal header</h1>
306+
<ion-list class="short" lines="none"></ion-list>
307+
</div>
308+
</ion-modal>
309+
</ion-content>
310+
</div>
311+
</ion-app>
312+
313+
<script>
314+
function fillList(list, count) {
315+
for (let i = 0; i < count; i++) {
316+
const item = document.createElement('ion-item');
317+
item.setAttribute('button', 'true');
318+
item.setAttribute('detail', 'false');
319+
320+
const icon = document.createElement('ion-icon');
321+
icon.setAttribute('name', 'person-circle');
322+
icon.setAttribute('slot', 'start');
323+
324+
const label = document.createElement('ion-label');
325+
label.textContent = `Item ${i + 1}`;
326+
327+
item.appendChild(icon);
328+
item.appendChild(label);
329+
list.appendChild(item);
330+
}
331+
}
332+
333+
/**
334+
* Passing an element rather than a tag name reuses one nav host. With
335+
* `component="nav-host"` the delegate creates another one on every
336+
* present and never removes the last, so they pile up.
337+
*/
338+
document.querySelector('ion-modal#nav-modal').component = document.createElement('nav-host');
339+
340+
document.querySelectorAll('ion-list.short').forEach((list) => fillList(list, 3));
341+
document.querySelectorAll('ion-list.long').forEach((list) => fillList(list, 30));
342+
343+
// Selecting an item dismisses the modal it belongs to.
344+
document.querySelectorAll('ion-modal').forEach((modal) => {
345+
modal.addEventListener('click', (ev) => {
346+
if (ev.target.closest('ion-item') !== null) {
347+
modal.dismiss();
348+
}
349+
});
350+
});
351+
</script>
352+
</body>
353+
</html>

0 commit comments

Comments
 (0)