@ionic/core 8.8.9-dev.11780493108.1d8e1a89 → 8.8.9-dev.11780493937.17fe092d
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-content.js +1 -1
- package/components/ion-footer.js +1 -1
- package/components/ion-gallery.js +1 -1
- package/components/ion-header.js +1 -1
- package/components/ion-select-modal.js +1 -1
- package/components/ion-select.js +1 -1
- package/components/p-BF5oFX1I.js +4 -0
- package/components/p-CpFORZud.js +4 -0
- package/components/p-d77Zk1DK.js +4 -0
- package/components/p-hdGd8ben.js +4 -0
- package/dist/cjs/ion-app_8.cjs.entry.js +286 -28
- package/dist/cjs/ion-gallery.cjs.entry.js +7 -26
- package/dist/collection/components/content/content.css +56 -0
- package/dist/collection/components/footer/footer.ios.css +13 -0
- package/dist/collection/components/footer/footer.js +65 -18
- package/dist/collection/components/footer/footer.md.css +13 -0
- package/dist/collection/components/footer/footer.utils.js +9 -0
- package/dist/collection/components/gallery/gallery.js +9 -14
- package/dist/collection/components/header/header.ionic.css +75 -0
- package/dist/collection/components/header/header.ios.css +75 -0
- package/dist/collection/components/header/header.js +41 -11
- package/dist/collection/components/header/header.md.css +75 -0
- package/dist/collection/components/header/header.utils.js +9 -0
- package/dist/collection/utils/css-value-validation.js +0 -14
- package/dist/collection/utils/on-scroll/collapse-hide.utils.js +168 -0
- package/dist/docs.json +18 -10
- package/dist/esm/ion-app_8.entry.js +286 -28
- package/dist/esm/ion-gallery.entry.js +7 -26
- package/dist/html.html-data.json +9 -3
- package/dist/ionic/ionic.esm.js +1 -1
- package/dist/ionic/p-04b5794c.entry.js +4 -0
- package/dist/ionic/p-ad4d0138.entry.js +4 -0
- package/dist/types/components/footer/footer.d.ts +12 -2
- package/dist/types/components/footer/footer.utils.d.ts +1 -0
- package/dist/types/components/gallery/gallery.d.ts +4 -6
- package/dist/types/components/header/header.d.ts +10 -3
- package/dist/types/components/header/header.utils.d.ts +1 -0
- package/dist/types/components.d.ts +12 -12
- package/dist/types/utils/css-value-validation.d.ts +0 -9
- package/dist/types/utils/on-scroll/collapse-hide.utils.d.ts +26 -0
- package/hydrate/index.js +293 -54
- package/hydrate/index.mjs +293 -54
- package/package.json +1 -1
- package/components/p-7kL3tltU.js +0 -4
- package/components/p-BGiYL2RS.js +0 -4
- package/components/p-LB-QPk3e.js +0 -4
- package/dist/ionic/p-290778c1.entry.js +0 -4
- package/dist/ionic/p-70ee89c9.entry.js +0 -4
|
@@ -281,4 +281,60 @@
|
|
|
281
281
|
* still allow the fixed content to appear under the scroll content if specified.
|
|
282
282
|
*/
|
|
283
283
|
transform: translateZ(0);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
:host(.content-header-hide-scroll-partner:not(.content-footer-hide-scroll-partner)) .inner-scroll {
|
|
287
|
+
transform: translateY(0);
|
|
288
|
+
backface-visibility: hidden;
|
|
289
|
+
height: 100%;
|
|
290
|
+
transition: transform 300ms cubic-bezier(0, 0, 0.2, 1), height 300ms cubic-bezier(0, 0, 0.2, 1);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
:host(.content-header-hide-scroll-partner:not(.content-footer-hide-scroll-partner).content-header-hide-scroll-hidden) .inner-scroll {
|
|
294
|
+
transform: translateY(calc(-1 * var(--header-hide-slide-y, 0px)));
|
|
295
|
+
backface-visibility: hidden;
|
|
296
|
+
height: calc(100% + var(--header-hide-slide-y, 0px));
|
|
297
|
+
transition: transform 200ms cubic-bezier(0.4, 0, 1, 1), height 200ms cubic-bezier(0.4, 0, 1, 1);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
:host(.content-footer-hide-scroll-partner:not(.content-header-hide-scroll-partner)) .inner-scroll {
|
|
301
|
+
transform: translateY(0);
|
|
302
|
+
backface-visibility: hidden;
|
|
303
|
+
height: 100%;
|
|
304
|
+
transition: transform 300ms cubic-bezier(0, 0, 0.2, 1), height 300ms cubic-bezier(0, 0, 0.2, 1);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
:host(.content-footer-hide-scroll-partner:not(.content-header-hide-scroll-partner).content-footer-hide-scroll-hidden) .inner-scroll {
|
|
308
|
+
transform: translateY(0);
|
|
309
|
+
backface-visibility: hidden;
|
|
310
|
+
height: calc(100% + var(--footer-hide-slide-y, 0px));
|
|
311
|
+
transition: transform 200ms cubic-bezier(0.4, 0, 1, 1), height 200ms cubic-bezier(0.4, 0, 1, 1);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
:host(.content-header-hide-scroll-partner.content-footer-hide-scroll-partner:not(.content-header-hide-scroll-hidden):not(.content-footer-hide-scroll-hidden)) .inner-scroll {
|
|
315
|
+
transform: translateY(0);
|
|
316
|
+
backface-visibility: hidden;
|
|
317
|
+
height: 100%;
|
|
318
|
+
transition: transform 300ms cubic-bezier(0, 0, 0.2, 1), height 300ms cubic-bezier(0, 0, 0.2, 1);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
:host(.content-header-hide-scroll-partner.content-footer-hide-scroll-partner.content-header-hide-scroll-hidden:not(.content-footer-hide-scroll-hidden)) .inner-scroll {
|
|
322
|
+
transform: translateY(calc(-1 * var(--header-hide-slide-y, 0px)));
|
|
323
|
+
backface-visibility: hidden;
|
|
324
|
+
height: calc(100% + var(--header-hide-slide-y, 0px));
|
|
325
|
+
transition: transform 200ms cubic-bezier(0.4, 0, 1, 1), height 200ms cubic-bezier(0.4, 0, 1, 1);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
:host(.content-header-hide-scroll-partner.content-footer-hide-scroll-partner:not(.content-header-hide-scroll-hidden).content-footer-hide-scroll-hidden) .inner-scroll {
|
|
329
|
+
transform: translateY(0);
|
|
330
|
+
backface-visibility: hidden;
|
|
331
|
+
height: calc(100% + var(--footer-hide-slide-y, 0px));
|
|
332
|
+
transition: transform 200ms cubic-bezier(0.4, 0, 1, 1), height 200ms cubic-bezier(0.4, 0, 1, 1);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
:host(.content-header-hide-scroll-partner.content-footer-hide-scroll-partner.content-header-hide-scroll-hidden.content-footer-hide-scroll-hidden) .inner-scroll {
|
|
336
|
+
transform: translateY(calc(-1 * var(--header-hide-slide-y, 0px)));
|
|
337
|
+
backface-visibility: hidden;
|
|
338
|
+
height: calc(100% + var(--header-hide-slide-y, 0px) + var(--footer-hide-slide-y, 0px));
|
|
339
|
+
transition: transform 200ms cubic-bezier(0.4, 0, 1, 1), height 200ms cubic-bezier(0.4, 0, 1, 1);
|
|
284
340
|
}
|
|
@@ -71,6 +71,19 @@ ion-footer.footer-toolbar-padding ion-toolbar:last-of-type {
|
|
|
71
71
|
padding-bottom: var(--ion-safe-area-bottom, 0);
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
ion-footer.footer-collapse-hide {
|
|
75
|
+
transform: translateY(0);
|
|
76
|
+
transition: transform 300ms cubic-bezier(0, 0, 0.2, 1), opacity 300ms cubic-bezier(0, 0, 0.2, 1);
|
|
77
|
+
opacity: 1;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
ion-footer.footer-collapse-hide.footer-collapse-hide-hidden {
|
|
81
|
+
transform: translateY(var(--footer-hide-slide-y, 0px));
|
|
82
|
+
pointer-events: none;
|
|
83
|
+
transition: transform 200ms cubic-bezier(0.4, 0, 1, 1), opacity 300ms cubic-bezier(0.4, 0, 1, 1);
|
|
84
|
+
opacity: 0;
|
|
85
|
+
}
|
|
86
|
+
|
|
74
87
|
/**
|
|
75
88
|
* Convert a pixels given value into rem
|
|
76
89
|
*
|
|
@@ -6,13 +6,15 @@ import { findIonContent, getScrollElement, printIonContentErrorMsg } from "../..
|
|
|
6
6
|
import { createKeyboardController } from "../../utils/keyboard/keyboard-controller";
|
|
7
7
|
import { config } from "../../global/config";
|
|
8
8
|
import { getIonTheme } from "../../global/ionic-global";
|
|
9
|
-
import { handleFooterFade } from "./footer.utils";
|
|
9
|
+
import { handleFooterFade, createFooterHideInteraction } from "./footer.utils";
|
|
10
10
|
/**
|
|
11
11
|
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
|
|
12
12
|
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
|
|
13
13
|
*/
|
|
14
14
|
export class Footer {
|
|
15
15
|
constructor() {
|
|
16
|
+
this.didLoad = false;
|
|
17
|
+
this.setupToken = 0;
|
|
16
18
|
this.keyboardCtrl = null;
|
|
17
19
|
this.keyboardCtrlPromise = null;
|
|
18
20
|
this.keyboardVisible = false;
|
|
@@ -27,25 +29,45 @@ export class Footer {
|
|
|
27
29
|
this.translucent = false;
|
|
28
30
|
this.checkCollapsibleFooter = () => {
|
|
29
31
|
const theme = getIonTheme(this);
|
|
30
|
-
if (theme !== 'ios') {
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
32
|
const { collapse } = this;
|
|
34
33
|
const hasFade = collapse === 'fade';
|
|
34
|
+
const hasHide = collapse === 'hide';
|
|
35
|
+
const runIosFade = theme === 'ios' && hasFade;
|
|
36
|
+
if (!runIosFade && !hasHide) {
|
|
37
|
+
this.destroyCollapsibleFooter();
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
// Skip teardown/rebuild when the collapse mode and theme have not changed
|
|
41
|
+
// since the last setup — avoids thrashing listeners and resetting scroll
|
|
42
|
+
// accumulators on unrelated re-renders (e.g. keyboardVisible state flips).
|
|
43
|
+
const activeMode = hasHide ? 'hide' : 'fade';
|
|
44
|
+
if (this.appliedCollapse === activeMode && this.appliedTheme === theme) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
35
47
|
this.destroyCollapsibleFooter();
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
48
|
+
const appRootSelector = config.get('appRootSelector', 'ion-app');
|
|
49
|
+
const pageEl = this.el.closest(`${appRootSelector},ion-page,.ion-page,page-inner`);
|
|
50
|
+
const contentEl = pageEl ? findIonContent(pageEl) : null;
|
|
51
|
+
if (!contentEl) {
|
|
52
|
+
printIonContentErrorMsg(this.el);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
this.appliedCollapse = activeMode;
|
|
56
|
+
this.appliedTheme = theme;
|
|
57
|
+
if (runIosFade) {
|
|
44
58
|
this.setupFadeFooter(contentEl);
|
|
45
59
|
}
|
|
60
|
+
else if (hasHide) {
|
|
61
|
+
void this.setupHideFooter(contentEl);
|
|
62
|
+
}
|
|
46
63
|
};
|
|
47
64
|
this.setupFadeFooter = async (contentEl) => {
|
|
48
|
-
const
|
|
65
|
+
const token = ++this.setupToken;
|
|
66
|
+
const scrollEl = await getScrollElement(contentEl);
|
|
67
|
+
if (token !== this.setupToken) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
this.scrollEl = scrollEl;
|
|
49
71
|
/**
|
|
50
72
|
* Handle fading of toolbars on scroll
|
|
51
73
|
*/
|
|
@@ -57,12 +79,18 @@ export class Footer {
|
|
|
57
79
|
};
|
|
58
80
|
}
|
|
59
81
|
componentDidLoad() {
|
|
82
|
+
this.didLoad = true;
|
|
60
83
|
this.checkCollapsibleFooter();
|
|
61
84
|
}
|
|
62
85
|
componentDidUpdate() {
|
|
63
86
|
this.checkCollapsibleFooter();
|
|
64
87
|
}
|
|
65
88
|
async connectedCallback() {
|
|
89
|
+
// On re-attach (didLoad already true but disconnectedCallback ran since),
|
|
90
|
+
// componentDidLoad will not fire again — re-run setup here.
|
|
91
|
+
if (this.didLoad) {
|
|
92
|
+
this.checkCollapsibleFooter();
|
|
93
|
+
}
|
|
66
94
|
const promise = createKeyboardController(async (keyboardOpen, waitForResize) => {
|
|
67
95
|
/**
|
|
68
96
|
* If the keyboard is hiding, then we need to wait
|
|
@@ -90,6 +118,7 @@ export class Footer {
|
|
|
90
118
|
}
|
|
91
119
|
}
|
|
92
120
|
disconnectedCallback() {
|
|
121
|
+
this.destroyCollapsibleFooter();
|
|
93
122
|
if (this.keyboardCtrlPromise) {
|
|
94
123
|
this.keyboardCtrlPromise.then((ctrl) => ctrl.destroy());
|
|
95
124
|
this.keyboardCtrlPromise = null;
|
|
@@ -99,18 +128,36 @@ export class Footer {
|
|
|
99
128
|
this.keyboardCtrl = null;
|
|
100
129
|
}
|
|
101
130
|
}
|
|
131
|
+
async setupHideFooter(contentEl) {
|
|
132
|
+
const token = ++this.setupToken;
|
|
133
|
+
const scrollEl = await getScrollElement(contentEl);
|
|
134
|
+
// A newer checkCollapsibleFooter ran while we were awaiting — abandon.
|
|
135
|
+
if (token !== this.setupToken) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
this.scrollEl = scrollEl;
|
|
139
|
+
this.footerHideCleanup = createFooterHideInteraction(this.el, scrollEl);
|
|
140
|
+
}
|
|
102
141
|
destroyCollapsibleFooter() {
|
|
142
|
+
// Invalidate any in-flight setupHideFooter/setupFadeFooter awaits.
|
|
143
|
+
this.setupToken++;
|
|
144
|
+
if (this.footerHideCleanup) {
|
|
145
|
+
this.footerHideCleanup();
|
|
146
|
+
this.footerHideCleanup = undefined;
|
|
147
|
+
}
|
|
103
148
|
if (this.scrollEl && this.contentScrollCallback) {
|
|
104
149
|
this.scrollEl.removeEventListener('scroll', this.contentScrollCallback);
|
|
105
150
|
this.contentScrollCallback = undefined;
|
|
106
151
|
}
|
|
152
|
+
this.appliedCollapse = undefined;
|
|
153
|
+
this.appliedTheme = undefined;
|
|
107
154
|
}
|
|
108
155
|
render() {
|
|
109
156
|
const { translucent, collapse } = this;
|
|
110
157
|
const theme = getIonTheme(this);
|
|
111
158
|
const tabs = this.el.closest('ion-tabs');
|
|
112
159
|
const tabBar = tabs === null || tabs === void 0 ? void 0 : tabs.querySelector(':scope > ion-tab-bar');
|
|
113
|
-
return (h(Host, { key: '
|
|
160
|
+
return (h(Host, { key: '5df79a31f36febfad49c5858727e93c7ba5734f8', role: "contentinfo", class: {
|
|
114
161
|
[theme]: true,
|
|
115
162
|
// Used internally for styling
|
|
116
163
|
[`footer-${theme}`]: true,
|
|
@@ -118,7 +165,7 @@ export class Footer {
|
|
|
118
165
|
[`footer-translucent-${theme}`]: translucent,
|
|
119
166
|
['footer-toolbar-padding']: !this.keyboardVisible && (!tabBar || tabBar.slot !== 'bottom'),
|
|
120
167
|
[`footer-collapse-${collapse}`]: collapse !== undefined,
|
|
121
|
-
} }, theme === 'ios' && translucent && h("div", { key: '
|
|
168
|
+
} }, theme === 'ios' && translucent && h("div", { key: '9175ae4f6576d82dff2a00a36e91f4b633d8c9ad', class: "footer-background" }), h("slot", { key: 'd6d618cdae4726822d8e82edb782c5c86fc7b77b' })));
|
|
122
169
|
}
|
|
123
170
|
static get is() { return "ion-footer"; }
|
|
124
171
|
static get originalStyleUrls() {
|
|
@@ -141,15 +188,15 @@ export class Footer {
|
|
|
141
188
|
"type": "string",
|
|
142
189
|
"mutable": false,
|
|
143
190
|
"complexType": {
|
|
144
|
-
"original": "'fade'",
|
|
145
|
-
"resolved": "\"fade\" | undefined",
|
|
191
|
+
"original": "'fade' | 'hide'",
|
|
192
|
+
"resolved": "\"fade\" | \"hide\" | undefined",
|
|
146
193
|
"references": {}
|
|
147
194
|
},
|
|
148
195
|
"required": false,
|
|
149
196
|
"optional": true,
|
|
150
197
|
"docs": {
|
|
151
198
|
"tags": [],
|
|
152
|
-
"text": "Describes the scroll effect that will be applied to the footer.\
|
|
199
|
+
"text": "Describes the scroll effect that will be applied to the footer.\n\n- `\"fade\"` only applies when the theme is `\"ios\"`.\n- `\"hide\"` applies to all themes (`\"ios\"`, `\"md\"`, and `\"ionic\"`): the footer\n slides down and fades out after cumulative downward scrolling on the page content,\n and returns on any upward scroll (same behavior as `ion-header[collapse=\"hide\"]`)."
|
|
153
200
|
},
|
|
154
201
|
"getter": false,
|
|
155
202
|
"setter": false,
|
|
@@ -71,6 +71,19 @@ ion-footer.footer-toolbar-padding ion-toolbar:last-of-type {
|
|
|
71
71
|
padding-bottom: var(--ion-safe-area-bottom, 0);
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
ion-footer.footer-collapse-hide {
|
|
75
|
+
transform: translateY(0);
|
|
76
|
+
transition: transform 300ms cubic-bezier(0, 0, 0.2, 1), opacity 300ms cubic-bezier(0, 0, 0.2, 1);
|
|
77
|
+
opacity: 1;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
ion-footer.footer-collapse-hide.footer-collapse-hide-hidden {
|
|
81
|
+
transform: translateY(var(--footer-hide-slide-y, 0px));
|
|
82
|
+
pointer-events: none;
|
|
83
|
+
transition: transform 200ms cubic-bezier(0.4, 0, 1, 1), opacity 300ms cubic-bezier(0.4, 0, 1, 1);
|
|
84
|
+
opacity: 0;
|
|
85
|
+
}
|
|
86
|
+
|
|
74
87
|
/**
|
|
75
88
|
* Convert a pixels given value into rem
|
|
76
89
|
*
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { readTask, writeTask } from "@stencil/core";
|
|
5
5
|
import { clamp } from "../../utils/helpers";
|
|
6
|
+
import { createCollapseHideInteraction } from "../../utils/on-scroll/collapse-hide.utils";
|
|
6
7
|
export const handleFooterFade = (scrollEl, baseEl) => {
|
|
7
8
|
readTask(() => {
|
|
8
9
|
const scrollTop = scrollEl.scrollTop;
|
|
@@ -31,3 +32,11 @@ export const handleFooterFade = (scrollEl, baseEl) => {
|
|
|
31
32
|
});
|
|
32
33
|
});
|
|
33
34
|
};
|
|
35
|
+
export const createFooterHideInteraction = (footerEl, scrollEl) => createCollapseHideInteraction({
|
|
36
|
+
regionEl: footerEl,
|
|
37
|
+
scrollEl,
|
|
38
|
+
slideCssVar: '--footer-hide-slide-y',
|
|
39
|
+
contentPartnerClass: 'content-footer-hide-scroll-partner',
|
|
40
|
+
contentHiddenClass: 'content-footer-hide-scroll-hidden',
|
|
41
|
+
regionHiddenClass: 'footer-collapse-hide-hidden',
|
|
42
|
+
});
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* (C) Ionic http://ionicframework.com - MIT License
|
|
3
3
|
*/
|
|
4
4
|
import { Host, h } from "@stencil/core";
|
|
5
|
-
import {
|
|
5
|
+
import { isValidLengthPercentage } from "../../utils/css-value-validation";
|
|
6
6
|
import { raf } from "../../utils/helpers";
|
|
7
7
|
import { printIonWarning } from "../../utils/logging/index";
|
|
8
8
|
import { getIonTheme } from "../../global/ionic-global";
|
|
@@ -46,8 +46,7 @@ export class Gallery {
|
|
|
46
46
|
/**
|
|
47
47
|
* The space between gallery items. Accepts valid CSS [length-percentage](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/length-percentage)
|
|
48
48
|
* values like `16px`, `1rem`, `20%`, math functions like `calc(10px + 20%)`,
|
|
49
|
-
*
|
|
50
|
-
* values). Can also be set as a breakpoint map
|
|
49
|
+
* or numbers (treated as pixel values). Can also be set as a breakpoint map
|
|
51
50
|
* (e.g. `{ xs: '8px', sm: '1rem', md: '24px' }`). Does not accept
|
|
52
51
|
* space-separated values or CSS keyword values like `inherit`, `auto`, etc.
|
|
53
52
|
*/
|
|
@@ -168,10 +167,9 @@ export class Gallery {
|
|
|
168
167
|
return numericColumns;
|
|
169
168
|
}
|
|
170
169
|
/**
|
|
171
|
-
* Normalize a single gap value (`gap` as a number,
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
* input cannot be interpreted as a valid CSS length or `var()` reference.
|
|
170
|
+
* Normalize a single gap value (`gap` as a number, string, or one entry from
|
|
171
|
+
* a `gap` breakpoint map) to a CSS length string. Returns `undefined` when
|
|
172
|
+
* the input cannot be interpreted as a valid CSS length.
|
|
175
173
|
*/
|
|
176
174
|
sanitizeGap(gap) {
|
|
177
175
|
if (gap === undefined) {
|
|
@@ -188,9 +186,6 @@ export class Gallery {
|
|
|
188
186
|
if (typeof normalizedGap !== 'string') {
|
|
189
187
|
return undefined;
|
|
190
188
|
}
|
|
191
|
-
if (isCssVariable(normalizedGap)) {
|
|
192
|
-
return normalizedGap;
|
|
193
|
-
}
|
|
194
189
|
const isValidCssLength = isValidLengthPercentage(normalizedGap);
|
|
195
190
|
return isValidCssLength ? normalizedGap : undefined;
|
|
196
191
|
}
|
|
@@ -271,7 +266,7 @@ export class Gallery {
|
|
|
271
266
|
if (this.hasWarnedInvalidGap) {
|
|
272
267
|
return;
|
|
273
268
|
}
|
|
274
|
-
printIonWarning(`[ion-gallery] - Invalid "gap" value (${JSON.stringify(gap)}). Expected a non-negative number, CSS length string,
|
|
269
|
+
printIonWarning(`[ion-gallery] - Invalid "gap" value (${JSON.stringify(gap)}). Expected a non-negative number, CSS length string, or breakpoint map object (e.g. { xs: 8, md: "1rem" }).`, this.el);
|
|
275
270
|
this.hasWarnedInvalidGap = true;
|
|
276
271
|
}
|
|
277
272
|
/**
|
|
@@ -457,11 +452,11 @@ export class Gallery {
|
|
|
457
452
|
const { layout } = this;
|
|
458
453
|
const order = this.getOrder();
|
|
459
454
|
const theme = getIonTheme(this);
|
|
460
|
-
return (h(Host, { key: '
|
|
455
|
+
return (h(Host, { key: '1bf2973d22835c0dbddf3214b602f8c08b95e421', class: {
|
|
461
456
|
[theme]: true,
|
|
462
457
|
[`gallery-layout-${layout}`]: true,
|
|
463
458
|
[`gallery-order-${order}`]: layout === 'masonry' && order !== undefined,
|
|
464
|
-
} }, h("slot", { key: '
|
|
459
|
+
} }, h("slot", { key: '0dea31f609f6afdb1d73ecb2d873909ffe49203f', onSlotchange: this.onSlotChange })));
|
|
465
460
|
}
|
|
466
461
|
static get is() { return "ion-gallery"; }
|
|
467
462
|
static get encapsulation() { return "shadow"; }
|
|
@@ -562,7 +557,7 @@ export class Gallery {
|
|
|
562
557
|
"optional": false,
|
|
563
558
|
"docs": {
|
|
564
559
|
"tags": [],
|
|
565
|
-
"text": "The space between gallery items. Accepts valid CSS [length-percentage](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/length-percentage)\nvalues like `16px`, `1rem`, `20%`, math functions like `calc(10px + 20%)`,\
|
|
560
|
+
"text": "The space between gallery items. Accepts valid CSS [length-percentage](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/length-percentage)\nvalues like `16px`, `1rem`, `20%`, math functions like `calc(10px + 20%)`,\nor numbers (treated as pixel values). Can also be set as a breakpoint map\n(e.g. `{ xs: '8px', sm: '1rem', md: '24px' }`). Does not accept\nspace-separated values or CSS keyword values like `inherit`, `auto`, etc."
|
|
566
561
|
},
|
|
567
562
|
"getter": false,
|
|
568
563
|
"setter": false,
|
|
@@ -1,3 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert a pixels given value into rem
|
|
3
|
+
*
|
|
4
|
+
* @param pixels - Value in pixels to be converted (i.e. px)
|
|
5
|
+
* @param context (optional) - Baseline value
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Convert a font size to a dynamic font size.
|
|
9
|
+
* Fonts that participate in Dynamic Type should use
|
|
10
|
+
* dynamic font sizes.
|
|
11
|
+
* @param size - The initial font size including the unit (i.e. px or pt)
|
|
12
|
+
* @param unit (optional) - The unit to convert to. Use this if you want to
|
|
13
|
+
* convert to a unit other than $baselineUnit.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Convert a font size to a dynamic font size but impose
|
|
17
|
+
* a maximum font size.
|
|
18
|
+
* @param size - The initial font size including the unit (i.e. px or pt)
|
|
19
|
+
* @param maxScale - The maximum scale of the font (i.e. 2.5 for a maximum 250% scale).
|
|
20
|
+
* @param unit (optional) - The unit to convert the initial font size to. Use this if you want to
|
|
21
|
+
* convert to a unit other than $baselineUnit.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Convert a font size to a dynamic font size but impose
|
|
25
|
+
* a minimum font size.
|
|
26
|
+
* @param size - The initial font size including the unit (i.e. px or pt)
|
|
27
|
+
* @param minScale - The minimum scale of the font (i.e. 0.8 for a minimum 80% scale).
|
|
28
|
+
* @param unit (optional) - The unit to convert the initial font size to. Use this if you want to
|
|
29
|
+
* convert to a unit other than $baselineUnit.
|
|
30
|
+
*/
|
|
31
|
+
/**
|
|
32
|
+
* Convert a font size to a dynamic font size but impose
|
|
33
|
+
* maximum and minimum font sizes.
|
|
34
|
+
* @param size - The initial font size including the unit (i.e. px or pt)
|
|
35
|
+
* @param minScale - The minimum scale of the font (i.e. 0.8 for a minimum 80% scale).
|
|
36
|
+
* @param maxScale - The maximum scale of the font (i.e. 2.5 for a maximum 250% scale).
|
|
37
|
+
* @param unit (optional) - The unit to convert the initial font size to. Use this if you want to
|
|
38
|
+
* convert to a unit other than $baselineUnit.
|
|
39
|
+
*/
|
|
40
|
+
/**
|
|
41
|
+
* A heuristic that applies CSS to tablet
|
|
42
|
+
* viewports.
|
|
43
|
+
*
|
|
44
|
+
* Usage:
|
|
45
|
+
* @include tablet-viewport() {
|
|
46
|
+
* :host {
|
|
47
|
+
* background-color: green;
|
|
48
|
+
* }
|
|
49
|
+
* }
|
|
50
|
+
*/
|
|
51
|
+
/**
|
|
52
|
+
* A heuristic that applies CSS to mobile
|
|
53
|
+
* viewports (i.e. phones, not tablets).
|
|
54
|
+
*
|
|
55
|
+
* Usage:
|
|
56
|
+
* @include mobile-viewport() {
|
|
57
|
+
* :host {
|
|
58
|
+
* background-color: blue;
|
|
59
|
+
* }
|
|
60
|
+
* }
|
|
61
|
+
*/
|
|
1
62
|
ion-header {
|
|
2
63
|
display: block;
|
|
3
64
|
position: relative;
|
|
@@ -9,6 +70,20 @@ ion-header ion-toolbar:first-of-type {
|
|
|
9
70
|
padding-top: var(--ion-safe-area-top, 0);
|
|
10
71
|
}
|
|
11
72
|
|
|
73
|
+
ion-header.header-collapse-hide {
|
|
74
|
+
transform: translateY(0);
|
|
75
|
+
transition: transform 300ms cubic-bezier(0, 0, 0.2, 1), opacity 300ms cubic-bezier(0, 0, 0.2, 1);
|
|
76
|
+
opacity: 1;
|
|
77
|
+
z-index: 10;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
ion-header.header-collapse-hide.header-collapse-hide-hidden {
|
|
81
|
+
transform: translateY(calc(-1 * var(--header-hide-slide-y, 0px)));
|
|
82
|
+
pointer-events: none;
|
|
83
|
+
transition: transform 200ms cubic-bezier(0.4, 0, 1, 1), opacity 300ms cubic-bezier(0.4, 0, 1, 1);
|
|
84
|
+
opacity: 0;
|
|
85
|
+
}
|
|
86
|
+
|
|
12
87
|
/**
|
|
13
88
|
* A heuristic that applies CSS to tablet
|
|
14
89
|
* viewports.
|
|
@@ -1,3 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert a pixels given value into rem
|
|
3
|
+
*
|
|
4
|
+
* @param pixels - Value in pixels to be converted (i.e. px)
|
|
5
|
+
* @param context (optional) - Baseline value
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Convert a font size to a dynamic font size.
|
|
9
|
+
* Fonts that participate in Dynamic Type should use
|
|
10
|
+
* dynamic font sizes.
|
|
11
|
+
* @param size - The initial font size including the unit (i.e. px or pt)
|
|
12
|
+
* @param unit (optional) - The unit to convert to. Use this if you want to
|
|
13
|
+
* convert to a unit other than $baselineUnit.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Convert a font size to a dynamic font size but impose
|
|
17
|
+
* a maximum font size.
|
|
18
|
+
* @param size - The initial font size including the unit (i.e. px or pt)
|
|
19
|
+
* @param maxScale - The maximum scale of the font (i.e. 2.5 for a maximum 250% scale).
|
|
20
|
+
* @param unit (optional) - The unit to convert the initial font size to. Use this if you want to
|
|
21
|
+
* convert to a unit other than $baselineUnit.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Convert a font size to a dynamic font size but impose
|
|
25
|
+
* a minimum font size.
|
|
26
|
+
* @param size - The initial font size including the unit (i.e. px or pt)
|
|
27
|
+
* @param minScale - The minimum scale of the font (i.e. 0.8 for a minimum 80% scale).
|
|
28
|
+
* @param unit (optional) - The unit to convert the initial font size to. Use this if you want to
|
|
29
|
+
* convert to a unit other than $baselineUnit.
|
|
30
|
+
*/
|
|
31
|
+
/**
|
|
32
|
+
* Convert a font size to a dynamic font size but impose
|
|
33
|
+
* maximum and minimum font sizes.
|
|
34
|
+
* @param size - The initial font size including the unit (i.e. px or pt)
|
|
35
|
+
* @param minScale - The minimum scale of the font (i.e. 0.8 for a minimum 80% scale).
|
|
36
|
+
* @param maxScale - The maximum scale of the font (i.e. 2.5 for a maximum 250% scale).
|
|
37
|
+
* @param unit (optional) - The unit to convert the initial font size to. Use this if you want to
|
|
38
|
+
* convert to a unit other than $baselineUnit.
|
|
39
|
+
*/
|
|
40
|
+
/**
|
|
41
|
+
* A heuristic that applies CSS to tablet
|
|
42
|
+
* viewports.
|
|
43
|
+
*
|
|
44
|
+
* Usage:
|
|
45
|
+
* @include tablet-viewport() {
|
|
46
|
+
* :host {
|
|
47
|
+
* background-color: green;
|
|
48
|
+
* }
|
|
49
|
+
* }
|
|
50
|
+
*/
|
|
51
|
+
/**
|
|
52
|
+
* A heuristic that applies CSS to mobile
|
|
53
|
+
* viewports (i.e. phones, not tablets).
|
|
54
|
+
*
|
|
55
|
+
* Usage:
|
|
56
|
+
* @include mobile-viewport() {
|
|
57
|
+
* :host {
|
|
58
|
+
* background-color: blue;
|
|
59
|
+
* }
|
|
60
|
+
* }
|
|
61
|
+
*/
|
|
1
62
|
ion-header {
|
|
2
63
|
display: block;
|
|
3
64
|
position: relative;
|
|
@@ -9,6 +70,20 @@ ion-header ion-toolbar:first-of-type {
|
|
|
9
70
|
padding-top: var(--ion-safe-area-top, 0);
|
|
10
71
|
}
|
|
11
72
|
|
|
73
|
+
ion-header.header-collapse-hide {
|
|
74
|
+
transform: translateY(0);
|
|
75
|
+
transition: transform 300ms cubic-bezier(0, 0, 0.2, 1), opacity 300ms cubic-bezier(0, 0, 0.2, 1);
|
|
76
|
+
opacity: 1;
|
|
77
|
+
z-index: 10;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
ion-header.header-collapse-hide.header-collapse-hide-hidden {
|
|
81
|
+
transform: translateY(calc(-1 * var(--header-hide-slide-y, 0px)));
|
|
82
|
+
pointer-events: none;
|
|
83
|
+
transition: transform 200ms cubic-bezier(0.4, 0, 1, 1), opacity 300ms cubic-bezier(0.4, 0, 1, 1);
|
|
84
|
+
opacity: 0;
|
|
85
|
+
}
|
|
86
|
+
|
|
12
87
|
/**
|
|
13
88
|
* Convert a pixels given value into rem
|
|
14
89
|
*
|
|
@@ -7,7 +7,7 @@ import { inheritAriaAttributes } from "../../utils/helpers";
|
|
|
7
7
|
import { hostContext } from "../../utils/theme";
|
|
8
8
|
import { config } from "../../global/config";
|
|
9
9
|
import { getIonTheme } from "../../global/ionic-global";
|
|
10
|
-
import { cloneElement, createHeaderIndex, handleContentScroll, handleHeaderFade, handleToolbarIntersection, setHeaderActive, setToolbarBackgroundOpacity, getRoleType, } from "./header.utils";
|
|
10
|
+
import { cloneElement, createHeaderHideInteraction, createHeaderIndex, handleContentScroll, handleHeaderFade, handleToolbarIntersection, setHeaderActive, setToolbarBackgroundOpacity, getRoleType, } from "./header.utils";
|
|
11
11
|
/**
|
|
12
12
|
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
|
|
13
13
|
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
|
|
@@ -15,6 +15,7 @@ import { cloneElement, createHeaderIndex, handleContentScroll, handleHeaderFade,
|
|
|
15
15
|
export class Header {
|
|
16
16
|
constructor() {
|
|
17
17
|
this.inheritedAttributes = {};
|
|
18
|
+
this.didLoad = false;
|
|
18
19
|
/**
|
|
19
20
|
* If `true`, the header will have a line at the bottom.
|
|
20
21
|
* TODO(ROU-10855): add support for this prop on ios/md themes
|
|
@@ -45,25 +46,37 @@ export class Header {
|
|
|
45
46
|
this.inheritedAttributes = inheritAriaAttributes(this.el);
|
|
46
47
|
}
|
|
47
48
|
componentDidLoad() {
|
|
49
|
+
this.didLoad = true;
|
|
48
50
|
this.checkCollapsibleHeader();
|
|
49
51
|
}
|
|
50
52
|
componentDidUpdate() {
|
|
51
53
|
this.checkCollapsibleHeader();
|
|
52
54
|
}
|
|
55
|
+
connectedCallback() {
|
|
56
|
+
// On re-attach (didLoad already true but disconnectedCallback ran since),
|
|
57
|
+
// componentDidLoad will not fire again — re-run setup here.
|
|
58
|
+
if (this.didLoad) {
|
|
59
|
+
this.checkCollapsibleHeader();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
53
62
|
disconnectedCallback() {
|
|
54
63
|
this.destroyCollapsibleHeader();
|
|
55
64
|
}
|
|
56
65
|
async checkCollapsibleHeader() {
|
|
57
66
|
const theme = getIonTheme(this);
|
|
58
|
-
if (theme !== 'ios') {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
67
|
const { collapse } = this;
|
|
62
68
|
const hasCondense = collapse === 'condense';
|
|
63
69
|
const hasFade = collapse === 'fade';
|
|
70
|
+
const hasHide = collapse === 'hide';
|
|
71
|
+
const runIosCollapse = theme === 'ios' && (hasCondense || hasFade);
|
|
72
|
+
const runHide = hasHide;
|
|
73
|
+
if (!runIosCollapse && !runHide) {
|
|
74
|
+
this.destroyCollapsibleHeader();
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
64
77
|
this.destroyCollapsibleHeader();
|
|
65
78
|
const appRootSelector = config.get('appRootSelector', 'ion-app');
|
|
66
|
-
if (hasCondense) {
|
|
79
|
+
if (runIosCollapse && hasCondense) {
|
|
67
80
|
const pageEl = this.el.closest(`${appRootSelector},ion-page,.ion-page,page-inner`);
|
|
68
81
|
const contentEl = pageEl ? findIonContent(pageEl) : null;
|
|
69
82
|
// Cloned elements are always needed in iOS transition
|
|
@@ -74,7 +87,7 @@ export class Header {
|
|
|
74
87
|
});
|
|
75
88
|
await this.setupCondenseHeader(contentEl, pageEl);
|
|
76
89
|
}
|
|
77
|
-
else if (hasFade) {
|
|
90
|
+
else if (runIosCollapse && hasFade) {
|
|
78
91
|
const pageEl = this.el.closest(`${appRootSelector},ion-page,.ion-page,page-inner`);
|
|
79
92
|
const contentEl = pageEl ? findIonContent(pageEl) : null;
|
|
80
93
|
if (!contentEl) {
|
|
@@ -84,12 +97,29 @@ export class Header {
|
|
|
84
97
|
const condenseHeader = contentEl.querySelector('ion-header[collapse="condense"]');
|
|
85
98
|
await this.setupFadeHeader(contentEl, condenseHeader);
|
|
86
99
|
}
|
|
100
|
+
if (runHide) {
|
|
101
|
+
const pageEl = this.el.closest(`${appRootSelector},ion-page,.ion-page,page-inner`);
|
|
102
|
+
const contentEl = pageEl ? findIonContent(pageEl) : null;
|
|
103
|
+
if (!contentEl) {
|
|
104
|
+
printIonContentErrorMsg(this.el);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
await this.setupHideHeader(contentEl);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
async setupHideHeader(contentEl) {
|
|
111
|
+
const scrollEl = (this.scrollEl = await getScrollElement(contentEl));
|
|
112
|
+
this.headerHideCleanup = createHeaderHideInteraction(this.el, scrollEl);
|
|
87
113
|
}
|
|
88
114
|
destroyCollapsibleHeader() {
|
|
89
115
|
if (this.intersectionObserver) {
|
|
90
116
|
this.intersectionObserver.disconnect();
|
|
91
117
|
this.intersectionObserver = undefined;
|
|
92
118
|
}
|
|
119
|
+
if (this.headerHideCleanup) {
|
|
120
|
+
this.headerHideCleanup();
|
|
121
|
+
this.headerHideCleanup = undefined;
|
|
122
|
+
}
|
|
93
123
|
if (this.scrollEl && this.contentScrollCallback) {
|
|
94
124
|
this.scrollEl.removeEventListener('scroll', this.contentScrollCallback);
|
|
95
125
|
this.contentScrollCallback = undefined;
|
|
@@ -156,7 +186,7 @@ export class Header {
|
|
|
156
186
|
const isCondensed = collapse === 'condense';
|
|
157
187
|
// banner role must be at top level, so remove role if inside a menu
|
|
158
188
|
const roleType = getRoleType(hostContext('ion-menu', this.el), isCondensed, theme);
|
|
159
|
-
return (h(Host, Object.assign({ key: '
|
|
189
|
+
return (h(Host, Object.assign({ key: '5cae1ff0bbc5f2035325c128a9394caf7f1459a0', role: roleType, class: {
|
|
160
190
|
[theme]: true,
|
|
161
191
|
// Used internally for styling
|
|
162
192
|
[`header-${theme}`]: true,
|
|
@@ -164,7 +194,7 @@ export class Header {
|
|
|
164
194
|
[`header-collapse-${collapse}`]: true,
|
|
165
195
|
[`header-translucent-${theme}`]: this.translucent,
|
|
166
196
|
['header-divider']: divider,
|
|
167
|
-
} }, inheritedAttributes), theme !== 'md' && translucent && h("div", { key: '
|
|
197
|
+
} }, inheritedAttributes), theme !== 'md' && translucent && h("div", { key: '705f120951a3dd429286b66cd0b511fa267b3702', class: "header-background" }), h("slot", { key: '1c7a9d474083cf92abfe88c02d363f8d420716ca' })));
|
|
168
198
|
}
|
|
169
199
|
static get is() { return "ion-header"; }
|
|
170
200
|
static get originalStyleUrls() {
|
|
@@ -187,15 +217,15 @@ export class Header {
|
|
|
187
217
|
"type": "string",
|
|
188
218
|
"mutable": false,
|
|
189
219
|
"complexType": {
|
|
190
|
-
"original": "'condense' | 'fade'",
|
|
191
|
-
"resolved": "\"condense\" | \"fade\" | undefined",
|
|
220
|
+
"original": "'condense' | 'fade' | 'hide'",
|
|
221
|
+
"resolved": "\"condense\" | \"fade\" | \"hide\" | undefined",
|
|
192
222
|
"references": {}
|
|
193
223
|
},
|
|
194
224
|
"required": false,
|
|
195
225
|
"optional": true,
|
|
196
226
|
"docs": {
|
|
197
227
|
"tags": [],
|
|
198
|
-
"text": "Describes the scroll effect that will be applied to the header.\
|
|
228
|
+
"text": "Describes the scroll effect that will be applied to the header.\n\n- `\"condense\"` and `\"fade\"` only apply when the theme is `\"ios\"`.\n Typically used for [Collapsible Large Titles](https://ionicframework.com/docs/api/title#collapsible-large-titles).\n- `\"hide\"` applies to all themes (`\"ios\"`, `\"md\"`, and `\"ionic\"`): the header\n slides up and fades out after cumulative downward scrolling on the page content,\n and returns on any upward scroll."
|
|
199
229
|
},
|
|
200
230
|
"getter": false,
|
|
201
231
|
"setter": false,
|