@rdlabo/ionic-theme-ios27 1.2.1 → 2.0.0-2
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/README.md +24 -279
- package/dist/css/components/ion-toolbar.css +1 -1
- package/dist/css/ionic-theme-ios27.css +1 -1
- package/dist/css/vertical-bars.css +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/layout/index.d.ts +18 -0
- package/dist/layout/index.d.ts.map +1 -0
- package/dist/layout/index.js +26 -0
- package/dist/layout/index.js.map +1 -0
- package/dist/segment/index.js +3 -3
- package/dist/segment/index.js.map +1 -1
- package/dist/sheets-of-glass/index.js +7 -7
- package/dist/sheets-of-glass/index.js.map +1 -1
- package/dist/tab-bar-searchable/dismiss-button.js +53 -3
- package/dist/tab-bar-searchable/dismiss-button.js.map +1 -1
- package/dist/tab-bar-searchable/index.js +18 -3
- package/dist/tab-bar-searchable/index.js.map +1 -1
- package/dist/transition/ios.transition.d.ts.map +1 -1
- package/dist/transition/ios.transition.js +7 -4
- package/dist/transition/ios.transition.js.map +1 -1
- package/dist/transition/native-ui.d.ts +6 -0
- package/dist/transition/native-ui.d.ts.map +1 -0
- package/dist/{native-integration/index.js → transition/native-ui.js} +16 -30
- package/dist/transition/native-ui.js.map +1 -0
- package/docs/adaptive-themes.md +161 -0
- package/docs/add-native-ui.md +53 -0
- package/docs/animation.md +19 -3
- package/docs/eslint.md +3 -1
- package/docs/features.md +9 -5
- package/docs/migration.md +33 -22
- package/docs/setup.md +94 -0
- package/docs/special-markup.md +41 -10
- package/docs/using-ion-item-group.md +2 -2
- package/docs/vertical-bars-layout.md +137 -0
- package/package.json +12 -42
- package/src/index.ts +3 -1
- package/src/layout/index.ts +29 -0
- package/src/segment/index.ts +3 -3
- package/src/sheets-of-glass/index.ts +7 -7
- package/src/styles/components/ion-toolbar.scss +1 -1
- package/src/styles/vertical-bars.scss +15 -18
- package/src/tab-bar-searchable/dismiss-button.ts +73 -4
- package/src/tab-bar-searchable/index.ts +20 -3
- package/src/transition/ios.transition.ts +7 -4
- package/src/{native-integration/index.ts → transition/native-ui.ts} +17 -46
- package/Package.swift +0 -21
- package/dist/_virtual/_rolldown/runtime.js +0 -13
- package/dist/native/components/index.d.ts +0 -19
- package/dist/native/components/index.d.ts.map +0 -1
- package/dist/native/components/index.js +0 -40
- package/dist/native/components/index.js.map +0 -1
- package/dist/native/components/ion-back-button.d.ts +0 -9
- package/dist/native/components/ion-back-button.d.ts.map +0 -1
- package/dist/native/components/ion-back-button.js +0 -20
- package/dist/native/components/ion-back-button.js.map +0 -1
- package/dist/native/components/ion-button.d.ts +0 -10
- package/dist/native/components/ion-button.d.ts.map +0 -1
- package/dist/native/components/ion-button.js +0 -23
- package/dist/native/components/ion-button.js.map +0 -1
- package/dist/native/components/ion-buttons.d.ts +0 -11
- package/dist/native/components/ion-buttons.d.ts.map +0 -1
- package/dist/native/components/ion-buttons.js +0 -30
- package/dist/native/components/ion-buttons.js.map +0 -1
- package/dist/native/components/ion-fab.d.ts +0 -10
- package/dist/native/components/ion-fab.d.ts.map +0 -1
- package/dist/native/components/ion-fab.js +0 -132
- package/dist/native/components/ion-fab.js.map +0 -1
- package/dist/native/components/ion-menu-button.d.ts +0 -13
- package/dist/native/components/ion-menu-button.d.ts.map +0 -1
- package/dist/native/components/ion-menu-button.js +0 -31
- package/dist/native/components/ion-menu-button.js.map +0 -1
- package/dist/native/components/ion-segment.d.ts +0 -11
- package/dist/native/components/ion-segment.d.ts.map +0 -1
- package/dist/native/components/ion-segment.js +0 -30
- package/dist/native/components/ion-segment.js.map +0 -1
- package/dist/native/components/ion-tab-bar.d.ts +0 -11
- package/dist/native/components/ion-tab-bar.d.ts.map +0 -1
- package/dist/native/components/ion-tab-bar.js +0 -50
- package/dist/native/components/ion-tab-bar.js.map +0 -1
- package/dist/native/components/searchable-tabs.d.ts +0 -20
- package/dist/native/components/searchable-tabs.d.ts.map +0 -1
- package/dist/native/components/searchable-tabs.js +0 -383
- package/dist/native/components/searchable-tabs.js.map +0 -1
- package/dist/native/definitions.d.ts +0 -152
- package/dist/native/definitions.d.ts.map +0 -1
- package/dist/native/definitions.js +0 -0
- package/dist/native/foldable/fold-state.d.ts +0 -5
- package/dist/native/foldable/fold-state.d.ts.map +0 -1
- package/dist/native/foldable/fold-state.js +0 -14
- package/dist/native/foldable/fold-state.js.map +0 -1
- package/dist/native/foldable/types.d.ts +0 -12
- package/dist/native/foldable/types.d.ts.map +0 -1
- package/dist/native/foldable/types.js +0 -0
- package/dist/native/index.d.ts +0 -11
- package/dist/native/index.d.ts.map +0 -1
- package/dist/native/index.js +0 -242
- package/dist/native/index.js.map +0 -1
- package/dist/native/prehide.d.ts +0 -7
- package/dist/native/prehide.d.ts.map +0 -1
- package/dist/native/prehide.js +0 -230
- package/dist/native/prehide.js.map +0 -1
- package/dist/native/runtime.d.ts +0 -5
- package/dist/native/runtime.d.ts.map +0 -1
- package/dist/native/runtime.js +0 -640
- package/dist/native/runtime.js.map +0 -1
- package/dist/native/shared/candidate.d.ts +0 -21
- package/dist/native/shared/candidate.d.ts.map +0 -1
- package/dist/native/shared/candidate.js +0 -98
- package/dist/native/shared/candidate.js.map +0 -1
- package/dist/native/shared/crossfade.d.ts +0 -10
- package/dist/native/shared/crossfade.d.ts.map +0 -1
- package/dist/native/shared/crossfade.js +0 -50
- package/dist/native/shared/crossfade.js.map +0 -1
- package/dist/native/shared/dom.d.ts +0 -46
- package/dist/native/shared/dom.d.ts.map +0 -1
- package/dist/native/shared/dom.js +0 -172
- package/dist/native/shared/dom.js.map +0 -1
- package/dist/native/shared/events.d.ts +0 -11
- package/dist/native/shared/events.d.ts.map +0 -1
- package/dist/native/shared/events.js +0 -13
- package/dist/native/shared/events.js.map +0 -1
- package/dist/native/shared/icons.d.ts +0 -8
- package/dist/native/shared/icons.d.ts.map +0 -1
- package/dist/native/shared/icons.js +0 -61
- package/dist/native/shared/icons.js.map +0 -1
- package/dist/native/shared/modal.d.ts +0 -10
- package/dist/native/shared/modal.d.ts.map +0 -1
- package/dist/native/shared/modal.js +0 -160
- package/dist/native/shared/modal.js.map +0 -1
- package/dist/native/vertical-bars-web-search.d.ts +0 -9
- package/dist/native/vertical-bars-web-search.d.ts.map +0 -1
- package/dist/native/vertical-bars-web-search.js +0 -84
- package/dist/native/vertical-bars-web-search.js.map +0 -1
- package/dist/native/vertical-bars-web.d.ts +0 -5
- package/dist/native/vertical-bars-web.d.ts.map +0 -1
- package/dist/native/vertical-bars-web.js +0 -341
- package/dist/native/vertical-bars-web.js.map +0 -1
- package/dist/native-integration/index.d.ts +0 -23
- package/dist/native-integration/index.d.ts.map +0 -1
- package/dist/native-integration/index.js.map +0 -1
- package/dist/native-integration/transition.d.ts +0 -5
- package/dist/native-integration/transition.d.ts.map +0 -1
- package/dist/native-integration/transition.js +0 -16
- package/dist/native-integration/transition.js.map +0 -1
- package/dist/vertical-bars.d.ts +0 -5
- package/dist/vertical-bars.js +0 -4
- package/docs/e2e-testing.md +0 -51
- package/docs/feedback.md +0 -65
- package/docs/iphone-duo-with-original-theme.md +0 -158
- package/docs/iphone-duo.md +0 -150
- package/docs/native-ui-shell.md +0 -285
- package/docs/vertical-bars.md +0 -285
- package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellButton.swift +0 -71
- package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellButtons.swift +0 -24
- package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellComponents.swift +0 -18
- package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellFab.swift +0 -83
- package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellSearchController.swift +0 -432
- package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellSegment.swift +0 -91
- package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellTabBar.swift +0 -221
- package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellVerticalBars.swift +0 -437
- package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellVerticalSearch.swift +0 -118
- package/ios/Sources/IonicNativeUIShellPlugin/IonicNativeUIShellPlugin.swift +0 -396
- package/ios/Sources/IonicNativeUIShellPlugin/Shared/ShellCrossfade.swift +0 -35
- package/ios/Sources/IonicNativeUIShellPlugin/Shared/ShellHost.swift +0 -8
- package/ios/Sources/IonicNativeUIShellPlugin/Shared/ShellRendering.swift +0 -27
- package/ios/Sources/IonicNativeUIShellPlugin/Shared/ShellSnapshot.swift +0 -135
- package/ios/Tests/IonicNativeUIShellPluginTests/ShellSnapshotTests.swift +0 -650
- package/src/native/components/index.ts +0 -53
- package/src/native/components/ion-back-button.ts +0 -19
- package/src/native/components/ion-button.ts +0 -24
- package/src/native/components/ion-buttons.ts +0 -38
- package/src/native/components/ion-fab.ts +0 -151
- package/src/native/components/ion-menu-button.ts +0 -24
- package/src/native/components/ion-segment.ts +0 -27
- package/src/native/components/ion-tab-bar.ts +0 -50
- package/src/native/components/searchable-tabs.ts +0 -459
- package/src/native/definitions.ts +0 -191
- package/src/native/foldable/fold-state.ts +0 -9
- package/src/native/foldable/types.ts +0 -4
- package/src/native/index.ts +0 -281
- package/src/native/prehide.ts +0 -265
- package/src/native/runtime.ts +0 -781
- package/src/native/shared/candidate.ts +0 -150
- package/src/native/shared/crossfade.ts +0 -50
- package/src/native/shared/dom.ts +0 -286
- package/src/native/shared/events.ts +0 -8
- package/src/native/shared/icons.ts +0 -57
- package/src/native/shared/modal.ts +0 -157
- package/src/native/vertical-bars-web-search.ts +0 -80
- package/src/native/vertical-bars-web.ts +0 -411
- package/src/native-integration/transition.ts +0 -15
- package/src/vertical-bars.ts +0 -11
|
@@ -1,341 +0,0 @@
|
|
|
1
|
-
import { VERTICAL_BARS_TRANSITION_CANCELED } from "../native-integration/index.js";
|
|
2
|
-
import { inVerticalBarsSurface, topModal } from "./shared/modal.js";
|
|
3
|
-
import { activateProjectedElement, createVerticalBarsPageState, isExcluded, isShellDisabled, isVerticalBarsToolbarGroup, marker, preferredVerticalBarsBack, prehiddenClass, prehideOnlyMutation, syncToolbarText, unprojected, verticalBarsActionCandidate, verticalBarsBackCandidate, verticalBarsEnteringPage, verticalBarsOwned, verticalBarsToolbarActions, withoutPrehide } from "./shared/dom.js";
|
|
4
|
-
import { createVerticalBarsWebSearch, searchProjectionClass } from "./vertical-bars-web-search.js";
|
|
5
|
-
//#region src/native/vertical-bars-web.ts
|
|
6
|
-
const backProjectionClass = "ios-theme-vertical-bars-back-button-projection";
|
|
7
|
-
const toolbarProjectionClass = "ios-theme-vertical-bars-toolbar-projection";
|
|
8
|
-
const readyClass = "ios-theme-vertical-bars-toolbar-ready";
|
|
9
|
-
const toolbarControlSize = 46;
|
|
10
|
-
const toolbarControlGap = 10;
|
|
11
|
-
const createVerticalBarsWebProjection = (doc, options, enabled = () => true) => {
|
|
12
|
-
const win = doc.defaultView;
|
|
13
|
-
const toolbarEnabled = options.controls === void 0 || options.controls.toolbar === true;
|
|
14
|
-
let root;
|
|
15
|
-
let backSource;
|
|
16
|
-
let backProjection;
|
|
17
|
-
let previousBackAriaHidden = null;
|
|
18
|
-
let toolbarProjections = [];
|
|
19
|
-
let suspended = 0;
|
|
20
|
-
let stopped = false;
|
|
21
|
-
let frame = 0;
|
|
22
|
-
let updates = 0;
|
|
23
|
-
let observingVerticalBars = false;
|
|
24
|
-
const verticalBarsPages = createVerticalBarsPageState();
|
|
25
|
-
let sourceObserver;
|
|
26
|
-
let waiters = [];
|
|
27
|
-
const listeners = new AbortController();
|
|
28
|
-
const verticalBarsRoot = () => doc.querySelector("ion-app.ios-theme-vertical-bars");
|
|
29
|
-
const projectedSources = () => [
|
|
30
|
-
backSource,
|
|
31
|
-
search.source,
|
|
32
|
-
...toolbarProjections.flatMap(({ actions }) => actions.map(({ source }) => source))
|
|
33
|
-
].filter((source) => !!source);
|
|
34
|
-
const isRendered = (element) => withoutPrehide(element, () => {
|
|
35
|
-
const style = getComputedStyle(element);
|
|
36
|
-
const rect = element.getBoundingClientRect();
|
|
37
|
-
return element.isConnected && style.display !== "none" && style.visibility === "visible" && rect.width > 0 && rect.height > 0;
|
|
38
|
-
});
|
|
39
|
-
const search = createVerticalBarsWebSearch(doc, (element) => (options.controls === void 0 || options.controls.tabs === true) && !!verticalBarsRoot()?.contains(element) && inVerticalBarsSurface(element) && !isExcluded(element, verticalBarsEnteringPage(element)) && !isShellDisabled(element) && !verticalBarsPages.isDeparted(element) && isRendered(element), () => {
|
|
40
|
-
schedule();
|
|
41
|
-
});
|
|
42
|
-
const inEligibleToolbar = (element) => !!verticalBarsRoot()?.contains(element) && inVerticalBarsSurface(element) && verticalBarsActionCandidate(element) && !isExcluded(element, verticalBarsEnteringPage(element)) && !verticalBarsPages.isDeparted(element);
|
|
43
|
-
const isEligibleBack = (element) => !!verticalBarsRoot()?.contains(element) && inVerticalBarsSurface(element) && verticalBarsOwned(element) && verticalBarsBackCandidate(element) && !isExcluded(element, verticalBarsEnteringPage(element)) && !verticalBarsPages.isDeparted(element) && unprojected(projectedSources(), () => isRendered(element));
|
|
44
|
-
const pageOrder = (element) => Array.from(doc.querySelectorAll(".ion-page")).indexOf(element.closest(".ion-page"));
|
|
45
|
-
const findBack = () => {
|
|
46
|
-
const candidates = Array.from(doc.querySelectorAll(`ion-back-button:not(.${backProjectionClass})`)).filter(isEligibleBack);
|
|
47
|
-
return preferredVerticalBarsBack(candidates, doc);
|
|
48
|
-
};
|
|
49
|
-
const findToolbarGroups = () => {
|
|
50
|
-
const candidates = Array.from(doc.querySelectorAll(`ion-buttons:not(.${toolbarProjectionClass})`)).flatMap((group) => {
|
|
51
|
-
const actions = verticalBarsToolbarActions(group).filter((action) => unprojected(projectedSources(), () => isRendered(action)));
|
|
52
|
-
if (!actions.length) return [];
|
|
53
|
-
if (!isVerticalBarsToolbarGroup(group)) return actions.filter(inEligibleToolbar).map((action) => ({
|
|
54
|
-
group,
|
|
55
|
-
actions: [action]
|
|
56
|
-
}));
|
|
57
|
-
return inEligibleToolbar(group) && unprojected(projectedSources(), () => isRendered(group)) ? [{
|
|
58
|
-
group,
|
|
59
|
-
actions
|
|
60
|
-
}] : [];
|
|
61
|
-
});
|
|
62
|
-
const highestPage = Math.max(...candidates.map(({ group }) => pageOrder(group)));
|
|
63
|
-
return candidates.filter(({ group }) => pageOrder(group) === highestPage);
|
|
64
|
-
};
|
|
65
|
-
const isCurrentToolbarAction = (source) => findToolbarGroups().some(({ actions }) => actions.includes(source));
|
|
66
|
-
const restore = () => {
|
|
67
|
-
search.restore();
|
|
68
|
-
backProjection?.remove();
|
|
69
|
-
backProjection = void 0;
|
|
70
|
-
if (backSource) {
|
|
71
|
-
backSource.removeAttribute(marker);
|
|
72
|
-
if (previousBackAriaHidden === null) backSource.removeAttribute("aria-hidden");
|
|
73
|
-
else backSource.setAttribute("aria-hidden", previousBackAriaHidden);
|
|
74
|
-
backSource.dispatchEvent(new CustomEvent("nativeUIShellChange"));
|
|
75
|
-
}
|
|
76
|
-
backSource = void 0;
|
|
77
|
-
previousBackAriaHidden = null;
|
|
78
|
-
for (const { projection, actions } of toolbarProjections) {
|
|
79
|
-
projection.remove();
|
|
80
|
-
for (const { source, previousAriaHidden } of actions) {
|
|
81
|
-
source.removeAttribute(marker);
|
|
82
|
-
if (previousAriaHidden === null) source.removeAttribute("aria-hidden");
|
|
83
|
-
else source.setAttribute("aria-hidden", previousAriaHidden);
|
|
84
|
-
source.dispatchEvent(new CustomEvent("nativeUIShellChange"));
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
toolbarProjections = [];
|
|
88
|
-
sourceObserver?.disconnect();
|
|
89
|
-
sourceObserver = void 0;
|
|
90
|
-
root?.classList.remove(readyClass);
|
|
91
|
-
root = void 0;
|
|
92
|
-
};
|
|
93
|
-
const copyAttributes = (target, original) => {
|
|
94
|
-
for (const name of [
|
|
95
|
-
"id",
|
|
96
|
-
"slot",
|
|
97
|
-
marker,
|
|
98
|
-
"aria-hidden"
|
|
99
|
-
]) target.removeAttribute(name);
|
|
100
|
-
for (const attribute of Array.from(target.attributes)) if (!["class", "data-native-ui-shell"].includes(attribute.name) && !original.hasAttribute(attribute.name)) target.removeAttribute(attribute.name);
|
|
101
|
-
for (const attribute of Array.from(original.attributes)) if (![
|
|
102
|
-
"id",
|
|
103
|
-
"slot",
|
|
104
|
-
"data-native-ui-shell",
|
|
105
|
-
"aria-hidden"
|
|
106
|
-
].includes(attribute.name)) target.setAttribute(attribute.name, attribute.value);
|
|
107
|
-
target.classList.remove(prehiddenClass);
|
|
108
|
-
};
|
|
109
|
-
const syncBack = (target, original) => {
|
|
110
|
-
copyAttributes(target, original);
|
|
111
|
-
target.classList.add(backProjectionClass, "ion-cloned-element");
|
|
112
|
-
target.disabled = original.disabled;
|
|
113
|
-
target.defaultHref = original.defaultHref;
|
|
114
|
-
target.icon = original.icon;
|
|
115
|
-
target.color = original.color;
|
|
116
|
-
target.mode = original.mode;
|
|
117
|
-
target.text = "";
|
|
118
|
-
};
|
|
119
|
-
const syncAction = (target, original) => {
|
|
120
|
-
copyAttributes(target, original);
|
|
121
|
-
target.classList.add("ios-theme-vertical-bars-toolbar-action", "ion-cloned-element");
|
|
122
|
-
const label = original.getAttribute("aria-label") ?? original.shadowRoot?.querySelector("[part~=native]")?.getAttribute("aria-label") ?? original.textContent?.trim();
|
|
123
|
-
if (label) target.setAttribute("aria-label", label);
|
|
124
|
-
if ("disabled" in original) target.disabled = original.disabled;
|
|
125
|
-
if (original.matches("ion-button")) {
|
|
126
|
-
const clonedIcon = original.querySelector("ion-icon, svg")?.cloneNode(true);
|
|
127
|
-
clonedIcon?.setAttribute("slot", "icon-only");
|
|
128
|
-
target.replaceChildren(...clonedIcon ? [clonedIcon] : []);
|
|
129
|
-
}
|
|
130
|
-
};
|
|
131
|
-
const sameSources = (back, groups) => back === backSource && groups.length === toolbarProjections.length && groups.every(({ group, actions }, index) => {
|
|
132
|
-
const current = toolbarProjections[index];
|
|
133
|
-
return group === current.source && actions.length === current.actions.length && actions.every((action, actionIndex) => action === current.actions[actionIndex].source);
|
|
134
|
-
});
|
|
135
|
-
const syncExisting = () => {
|
|
136
|
-
if (backSource && backProjection) syncBack(backProjection, backSource);
|
|
137
|
-
let topOffset = backSource ? 56 : 0;
|
|
138
|
-
for (const { projection, source, actions } of toolbarProjections) {
|
|
139
|
-
if (actions.length === 1 && !projection.matches("ion-buttons")) syncAction(projection, actions[0].source);
|
|
140
|
-
else copyAttributes(projection, source);
|
|
141
|
-
projection.classList.add(toolbarProjectionClass, "ion-cloned-element");
|
|
142
|
-
projection.style.setProperty("--ios-theme-vertical-bars-toolbar-offset", `${topOffset}px`);
|
|
143
|
-
if (projection.matches("ion-buttons")) actions.forEach(({ source: action, projection: clone }) => syncAction(clone, action));
|
|
144
|
-
topOffset += actions.length * toolbarControlSize + toolbarControlGap;
|
|
145
|
-
}
|
|
146
|
-
};
|
|
147
|
-
const project = (nextBack, groups) => {
|
|
148
|
-
root = topModal(doc) ?? verticalBarsRoot();
|
|
149
|
-
let topOffset = 0;
|
|
150
|
-
if (nextBack) {
|
|
151
|
-
backSource = nextBack;
|
|
152
|
-
previousBackAriaHidden = nextBack.getAttribute("aria-hidden");
|
|
153
|
-
backProjection = nextBack.cloneNode(false);
|
|
154
|
-
syncBack(backProjection, nextBack);
|
|
155
|
-
backProjection.addEventListener("click", (event) => {
|
|
156
|
-
event.preventDefault();
|
|
157
|
-
event.stopImmediatePropagation();
|
|
158
|
-
if (backSource && backSource === findBack()) activateProjectedElement(backSource);
|
|
159
|
-
}, { capture: true });
|
|
160
|
-
root.append(backProjection);
|
|
161
|
-
nextBack.setAttribute(marker, "");
|
|
162
|
-
nextBack.setAttribute("aria-hidden", "true");
|
|
163
|
-
nextBack.dispatchEvent(new CustomEvent("nativeUIShellChange"));
|
|
164
|
-
topOffset = 56;
|
|
165
|
-
}
|
|
166
|
-
for (const { group, actions: sources } of groups) {
|
|
167
|
-
const projection = (sources.length === 1 ? sources[0] : group).cloneNode(false);
|
|
168
|
-
if (sources.length === 1) syncAction(projection, sources[0]);
|
|
169
|
-
else copyAttributes(projection, group);
|
|
170
|
-
projection.classList.add(toolbarProjectionClass, "ion-cloned-element");
|
|
171
|
-
projection.style.setProperty("--ios-theme-vertical-bars-toolbar-offset", `${topOffset}px`);
|
|
172
|
-
const actions = sources.map((source) => {
|
|
173
|
-
const clone = sources.length === 1 ? projection : source.cloneNode(false);
|
|
174
|
-
if (sources.length > 1) syncAction(clone, source);
|
|
175
|
-
clone.addEventListener("click", (event) => {
|
|
176
|
-
event.preventDefault();
|
|
177
|
-
event.stopImmediatePropagation();
|
|
178
|
-
if (isCurrentToolbarAction(source)) activateProjectedElement(source);
|
|
179
|
-
}, { capture: true });
|
|
180
|
-
if (sources.length > 1) projection.append(clone);
|
|
181
|
-
const previousAriaHidden = source.getAttribute("aria-hidden");
|
|
182
|
-
source.setAttribute(marker, "");
|
|
183
|
-
source.setAttribute("aria-hidden", "true");
|
|
184
|
-
source.dispatchEvent(new CustomEvent("nativeUIShellChange"));
|
|
185
|
-
return {
|
|
186
|
-
source,
|
|
187
|
-
projection: clone,
|
|
188
|
-
previousAriaHidden
|
|
189
|
-
};
|
|
190
|
-
});
|
|
191
|
-
root.append(projection);
|
|
192
|
-
toolbarProjections.push({
|
|
193
|
-
source: group,
|
|
194
|
-
projection,
|
|
195
|
-
actions
|
|
196
|
-
});
|
|
197
|
-
topOffset += actions.length * toolbarControlSize + toolbarControlGap;
|
|
198
|
-
}
|
|
199
|
-
if (nextBack || toolbarProjections.length) root.classList.add(readyClass);
|
|
200
|
-
sourceObserver = new MutationObserver((records) => {
|
|
201
|
-
if (records.some((record) => record.type !== "attributes" || !["data-native-ui-shell", "aria-hidden"].includes(record.attributeName ?? "") && !prehideOnlyMutation(record))) schedule();
|
|
202
|
-
});
|
|
203
|
-
if (nextBack?.shadowRoot) sourceObserver.observe(nextBack.shadowRoot, {
|
|
204
|
-
subtree: true,
|
|
205
|
-
childList: true,
|
|
206
|
-
attributes: true,
|
|
207
|
-
attributeOldValue: true
|
|
208
|
-
});
|
|
209
|
-
for (const { group } of groups) sourceObserver.observe(group, {
|
|
210
|
-
subtree: true,
|
|
211
|
-
childList: true,
|
|
212
|
-
attributes: true,
|
|
213
|
-
attributeOldValue: true
|
|
214
|
-
});
|
|
215
|
-
};
|
|
216
|
-
const performUpdate = () => {
|
|
217
|
-
frame = 0;
|
|
218
|
-
syncToolbarText(doc);
|
|
219
|
-
const currentRoot = verticalBarsRoot();
|
|
220
|
-
if (observingVerticalBars !== !!currentRoot) {
|
|
221
|
-
observingVerticalBars = !!currentRoot;
|
|
222
|
-
observer.disconnect();
|
|
223
|
-
observer.observe(doc.documentElement, {
|
|
224
|
-
subtree: true,
|
|
225
|
-
childList: true,
|
|
226
|
-
characterData: observingVerticalBars,
|
|
227
|
-
attributes: true,
|
|
228
|
-
attributeOldValue: true,
|
|
229
|
-
attributeFilter: observingVerticalBars ? void 0 : ["class"]
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
if (stopped || suspended || !currentRoot || !enabled()) return restore();
|
|
233
|
-
const nextBack = toolbarEnabled ? findBack() : void 0;
|
|
234
|
-
const groups = toolbarEnabled ? findToolbarGroups() : [];
|
|
235
|
-
const projectionRoot = topModal(doc) ?? currentRoot;
|
|
236
|
-
search.update(projectionRoot);
|
|
237
|
-
if (!nextBack && !groups.length && !search.source) return restore();
|
|
238
|
-
if (root === (topModal(doc) ?? currentRoot) && sameSources(nextBack, groups)) return syncExisting();
|
|
239
|
-
restore();
|
|
240
|
-
project(nextBack, groups);
|
|
241
|
-
search.update(projectionRoot);
|
|
242
|
-
updates++;
|
|
243
|
-
};
|
|
244
|
-
const update = () => {
|
|
245
|
-
try {
|
|
246
|
-
performUpdate();
|
|
247
|
-
} catch {
|
|
248
|
-
restore();
|
|
249
|
-
} finally {
|
|
250
|
-
const pending = waiters;
|
|
251
|
-
waiters = [];
|
|
252
|
-
pending.forEach((resolve) => resolve());
|
|
253
|
-
}
|
|
254
|
-
};
|
|
255
|
-
const schedule = () => {
|
|
256
|
-
if (stopped) return Promise.resolve();
|
|
257
|
-
if (!enabled()) restore();
|
|
258
|
-
const done = new Promise((resolve) => waiters.push(resolve));
|
|
259
|
-
if (!frame) frame = win.requestAnimationFrame(update);
|
|
260
|
-
return done;
|
|
261
|
-
};
|
|
262
|
-
const observer = new MutationObserver((records) => {
|
|
263
|
-
const insideProjection = (target) => {
|
|
264
|
-
const element = target instanceof Element ? target : target.parentNode instanceof Element ? target.parentNode : void 0;
|
|
265
|
-
const rootNode = target.getRootNode();
|
|
266
|
-
return !![element, rootNode instanceof ShadowRoot ? rootNode.host : void 0].some((candidate) => candidate?.closest(`.${backProjectionClass}, .${toolbarProjectionClass}, .${searchProjectionClass}`));
|
|
267
|
-
};
|
|
268
|
-
const verticalBarsChanged = records.some((record) => record.type === "attributes" && record.target.matches("ion-app") || record.type === "childList" && Array.from(record.addedNodes).some((node) => node instanceof Element && (node.matches("ion-app.ios-theme-vertical-bars") || !!node.querySelector("ion-app.ios-theme-vertical-bars"))));
|
|
269
|
-
if (observingVerticalBars && records.some((record) => record.attributeName !== "data-native-ui-shell" && record.attributeName !== "data-native-ui-shell-toolbar-text" && !prehideOnlyMutation(record) && !insideProjection(record.target)) || !observingVerticalBars && verticalBarsChanged && records.some((record) => !prehideOnlyMutation(record))) schedule();
|
|
270
|
-
});
|
|
271
|
-
observer.observe(doc.documentElement, {
|
|
272
|
-
subtree: true,
|
|
273
|
-
childList: true,
|
|
274
|
-
attributes: true,
|
|
275
|
-
attributeOldValue: true,
|
|
276
|
-
attributeFilter: ["class"]
|
|
277
|
-
});
|
|
278
|
-
const pageLifecycle = (event) => {
|
|
279
|
-
const page = event.target;
|
|
280
|
-
if (!(page instanceof HTMLElement) || !page.matches(".ion-page")) return;
|
|
281
|
-
if (event.type === "iosThemeVerticalBarsTransitionCanceled") {
|
|
282
|
-
const entering = event.detail?.entering;
|
|
283
|
-
verticalBarsPages.cancel(entering, page);
|
|
284
|
-
} else verticalBarsPages.lifecycle(event);
|
|
285
|
-
if (verticalBarsRoot()) schedule();
|
|
286
|
-
};
|
|
287
|
-
for (const name of [
|
|
288
|
-
"ionViewWillEnter",
|
|
289
|
-
"ionViewWillLeave",
|
|
290
|
-
"ionViewDidEnter",
|
|
291
|
-
"ionViewDidLeave"
|
|
292
|
-
]) doc.addEventListener(name, pageLifecycle, {
|
|
293
|
-
capture: true,
|
|
294
|
-
signal: listeners.signal
|
|
295
|
-
});
|
|
296
|
-
doc.addEventListener(VERTICAL_BARS_TRANSITION_CANCELED, pageLifecycle, {
|
|
297
|
-
capture: true,
|
|
298
|
-
signal: listeners.signal
|
|
299
|
-
});
|
|
300
|
-
for (const name of ["ionModalWillPresent", "ionModalDidDismiss"]) doc.addEventListener(name, schedule, {
|
|
301
|
-
capture: true,
|
|
302
|
-
signal: listeners.signal
|
|
303
|
-
});
|
|
304
|
-
win.addEventListener("resize", schedule, { signal: listeners.signal });
|
|
305
|
-
win.addEventListener("nativeUIShellRefresh", schedule, { signal: listeners.signal });
|
|
306
|
-
schedule();
|
|
307
|
-
return {
|
|
308
|
-
getStatus: () => ({
|
|
309
|
-
state: stopped ? "stopped" : "web",
|
|
310
|
-
projected: Number(!!backSource) + Number(!!search.source) + toolbarProjections.reduce((count, group) => count + group.actions.length, 0),
|
|
311
|
-
updates
|
|
312
|
-
}),
|
|
313
|
-
async suspend() {
|
|
314
|
-
suspended++;
|
|
315
|
-
restore();
|
|
316
|
-
let resumed = false;
|
|
317
|
-
return { async resume() {
|
|
318
|
-
if (resumed) return;
|
|
319
|
-
resumed = true;
|
|
320
|
-
suspended = Math.max(0, suspended - 1);
|
|
321
|
-
if (!suspended) await schedule();
|
|
322
|
-
} };
|
|
323
|
-
},
|
|
324
|
-
async destroy() {
|
|
325
|
-
if (stopped) return;
|
|
326
|
-
stopped = true;
|
|
327
|
-
win.cancelAnimationFrame(frame);
|
|
328
|
-
frame = 0;
|
|
329
|
-
waiters.forEach((resolve) => resolve());
|
|
330
|
-
waiters = [];
|
|
331
|
-
observer.disconnect();
|
|
332
|
-
sourceObserver?.disconnect();
|
|
333
|
-
listeners.abort();
|
|
334
|
-
restore();
|
|
335
|
-
}
|
|
336
|
-
};
|
|
337
|
-
};
|
|
338
|
-
//#endregion
|
|
339
|
-
export { createVerticalBarsWebProjection };
|
|
340
|
-
|
|
341
|
-
//# sourceMappingURL=vertical-bars-web.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"vertical-bars-web.js","names":[],"sources":["../../src/native/vertical-bars-web.ts"],"sourcesContent":["import { createVerticalBarsWebSearch, searchProjectionClass } from './vertical-bars-web-search';\nimport { inVerticalBarsSurface, topModal } from './shared/modal';\nimport type { NativeUIShellHandle, NativeUIShellOptions, NativeUIShellStatus } from './definitions';\nimport { VERTICAL_BARS_TRANSITION_CANCELED } from '../native-integration';\nimport {\n activateProjectedElement,\n createVerticalBarsPageState,\n verticalBarsActionCandidate,\n verticalBarsBackCandidate,\n verticalBarsEnteringPage,\n verticalBarsToolbarActions,\n isExcluded,\n isShellDisabled,\n isVerticalBarsToolbarGroup,\n preferredVerticalBarsBack,\n verticalBarsOwned,\n marker,\n syncToolbarText,\n toolbarTextMarker,\n prehideOnlyMutation,\n prehiddenClass,\n unprojected,\n withoutPrehide,\n} from './shared/dom';\n\nconst backProjectionClass = 'ios-theme-vertical-bars-back-button-projection';\nconst toolbarProjectionClass = 'ios-theme-vertical-bars-toolbar-projection';\nconst readyClass = 'ios-theme-vertical-bars-toolbar-ready';\nconst toolbarControlSize = 46;\nconst toolbarControlGap = 10;\n\ninterface ToolbarProjection {\n source: HTMLIonButtonsElement;\n projection: HTMLElement;\n actions: { source: HTMLElement; projection: HTMLElement; previousAriaHidden: string | null }[];\n}\n\ninterface ToolbarSource {\n group: HTMLIonButtonsElement;\n actions: HTMLElement[];\n}\n\nexport const createVerticalBarsWebProjection = (\n doc: Document,\n options: NativeUIShellOptions,\n enabled: () => boolean = () => true,\n): NativeUIShellHandle => {\n const win = doc.defaultView!;\n const toolbarEnabled = options.controls === undefined || options.controls.toolbar === true;\n let root: HTMLElement | undefined;\n let backSource: HTMLIonBackButtonElement | undefined;\n let backProjection: HTMLIonBackButtonElement | undefined;\n let previousBackAriaHidden: string | null = null;\n let toolbarProjections: ToolbarProjection[] = [];\n let suspended = 0;\n let stopped = false;\n let frame = 0;\n let updates = 0;\n let observingVerticalBars = false;\n const verticalBarsPages = createVerticalBarsPageState();\n let sourceObserver: MutationObserver | undefined;\n let waiters: (() => void)[] = [];\n const listeners = new AbortController();\n const verticalBarsRoot = () => doc.querySelector<HTMLElement>('ion-app.ios-theme-vertical-bars');\n const projectedSources = () =>\n [backSource, search.source, ...toolbarProjections.flatMap(({ actions }) => actions.map(({ source }) => source))].filter(\n (source): source is HTMLElement => !!source,\n );\n const isRendered = (element: HTMLElement) =>\n withoutPrehide(element, () => {\n const style = getComputedStyle(element);\n const rect = element.getBoundingClientRect();\n return element.isConnected && style.display !== 'none' && style.visibility === 'visible' && rect.width > 0 && rect.height > 0;\n });\n const search = createVerticalBarsWebSearch(\n doc,\n (element) =>\n (options.controls === undefined || options.controls.tabs === true) &&\n !!verticalBarsRoot()?.contains(element) &&\n inVerticalBarsSurface(element) &&\n !isExcluded(element, verticalBarsEnteringPage(element)) &&\n !isShellDisabled(element) &&\n !verticalBarsPages.isDeparted(element) &&\n isRendered(element),\n () => {\n void schedule();\n },\n );\n const inEligibleToolbar = (element: HTMLElement) =>\n !!verticalBarsRoot()?.contains(element) &&\n inVerticalBarsSurface(element) &&\n verticalBarsActionCandidate(element) &&\n !isExcluded(element, verticalBarsEnteringPage(element)) &&\n !verticalBarsPages.isDeparted(element);\n const isEligibleBack = (element: HTMLIonBackButtonElement) =>\n !!verticalBarsRoot()?.contains(element) &&\n inVerticalBarsSurface(element) &&\n verticalBarsOwned(element) &&\n verticalBarsBackCandidate(element) &&\n !isExcluded(element, verticalBarsEnteringPage(element)) &&\n !verticalBarsPages.isDeparted(element) &&\n unprojected(projectedSources(), () => isRendered(element));\n const pageOrder = (element: Element) => Array.from(doc.querySelectorAll('.ion-page')).indexOf(element.closest('.ion-page')!);\n const findBack = () => {\n const candidates = Array.from(doc.querySelectorAll<HTMLIonBackButtonElement>(`ion-back-button:not(.${backProjectionClass})`)).filter(\n isEligibleBack,\n );\n return preferredVerticalBarsBack(candidates, doc);\n };\n const findToolbarGroups = () => {\n const candidates = Array.from(doc.querySelectorAll<HTMLIonButtonsElement>(`ion-buttons:not(.${toolbarProjectionClass})`)).flatMap(\n (group): ToolbarSource[] => {\n const actions = verticalBarsToolbarActions(group).filter((action) => unprojected(projectedSources(), () => isRendered(action)));\n if (!actions.length) return [];\n if (!isVerticalBarsToolbarGroup(group)) return actions.filter(inEligibleToolbar).map((action) => ({ group, actions: [action] }));\n return inEligibleToolbar(group) && unprojected(projectedSources(), () => isRendered(group)) ? [{ group, actions }] : [];\n },\n );\n const highestPage = Math.max(...candidates.map(({ group }) => pageOrder(group)));\n return candidates.filter(({ group }) => pageOrder(group) === highestPage);\n };\n const isCurrentToolbarAction = (source: HTMLElement) => findToolbarGroups().some(({ actions }) => actions.includes(source));\n const restore = () => {\n search.restore();\n backProjection?.remove();\n backProjection = undefined;\n if (backSource) {\n backSource.removeAttribute(marker);\n if (previousBackAriaHidden === null) backSource.removeAttribute('aria-hidden');\n else backSource.setAttribute('aria-hidden', previousBackAriaHidden);\n backSource.dispatchEvent(new CustomEvent('nativeUIShellChange'));\n }\n backSource = undefined;\n previousBackAriaHidden = null;\n for (const { projection, actions } of toolbarProjections) {\n projection.remove();\n for (const { source, previousAriaHidden } of actions) {\n source.removeAttribute(marker);\n if (previousAriaHidden === null) source.removeAttribute('aria-hidden');\n else source.setAttribute('aria-hidden', previousAriaHidden);\n source.dispatchEvent(new CustomEvent('nativeUIShellChange'));\n }\n }\n toolbarProjections = [];\n sourceObserver?.disconnect();\n sourceObserver = undefined;\n root?.classList.remove(readyClass);\n root = undefined;\n };\n const copyAttributes = (target: HTMLElement, original: HTMLElement) => {\n for (const name of ['id', 'slot', marker, 'aria-hidden']) target.removeAttribute(name);\n for (const attribute of Array.from(target.attributes))\n if (!['class', marker].includes(attribute.name) && !original.hasAttribute(attribute.name)) target.removeAttribute(attribute.name);\n for (const attribute of Array.from(original.attributes))\n if (!['id', 'slot', marker, 'aria-hidden'].includes(attribute.name)) target.setAttribute(attribute.name, attribute.value);\n target.classList.remove(prehiddenClass);\n };\n const syncBack = (target: HTMLIonBackButtonElement, original: HTMLIonBackButtonElement) => {\n copyAttributes(target, original);\n target.classList.add(backProjectionClass, 'ion-cloned-element');\n target.disabled = original.disabled;\n target.defaultHref = original.defaultHref;\n target.icon = original.icon;\n target.color = original.color;\n target.mode = original.mode;\n target.text = '';\n };\n const syncAction = (target: HTMLElement, original: HTMLElement) => {\n copyAttributes(target, original);\n target.classList.add('ios-theme-vertical-bars-toolbar-action', 'ion-cloned-element');\n const label =\n original.getAttribute('aria-label') ??\n original.shadowRoot?.querySelector('[part~=native]')?.getAttribute('aria-label') ??\n original.textContent?.trim();\n if (label) target.setAttribute('aria-label', label);\n if ('disabled' in original) (target as HTMLIonButtonElement).disabled = (original as HTMLIonButtonElement).disabled;\n if (original.matches('ion-button')) {\n const icon = original.querySelector<HTMLElement>('ion-icon, svg');\n const clonedIcon = icon?.cloneNode(true) as HTMLElement | undefined;\n clonedIcon?.setAttribute('slot', 'icon-only');\n target.replaceChildren(...(clonedIcon ? [clonedIcon] : []));\n }\n };\n const sameSources = (back: HTMLIonBackButtonElement | undefined, groups: ToolbarSource[]) =>\n back === backSource &&\n groups.length === toolbarProjections.length &&\n groups.every(({ group, actions }, index) => {\n const current = toolbarProjections[index];\n return (\n group === current.source &&\n actions.length === current.actions.length &&\n actions.every((action, actionIndex) => action === current.actions[actionIndex].source)\n );\n });\n const syncExisting = () => {\n if (backSource && backProjection) syncBack(backProjection, backSource);\n let topOffset = backSource ? toolbarControlSize + toolbarControlGap : 0;\n for (const { projection, source, actions } of toolbarProjections) {\n if (actions.length === 1 && !projection.matches('ion-buttons')) syncAction(projection, actions[0].source);\n else copyAttributes(projection, source);\n projection.classList.add(toolbarProjectionClass, 'ion-cloned-element');\n projection.style.setProperty('--ios-theme-vertical-bars-toolbar-offset', `${topOffset}px`);\n if (projection.matches('ion-buttons')) actions.forEach(({ source: action, projection: clone }) => syncAction(clone, action));\n topOffset += actions.length * toolbarControlSize + toolbarControlGap;\n }\n };\n const project = (nextBack: HTMLIonBackButtonElement | undefined, groups: ToolbarSource[]) => {\n root = topModal(doc) ?? verticalBarsRoot()!;\n let topOffset = 0;\n if (nextBack) {\n backSource = nextBack;\n previousBackAriaHidden = nextBack.getAttribute('aria-hidden');\n backProjection = nextBack.cloneNode(false) as HTMLIonBackButtonElement;\n syncBack(backProjection, nextBack);\n backProjection.addEventListener(\n 'click',\n (event) => {\n event.preventDefault();\n event.stopImmediatePropagation();\n if (backSource && backSource === findBack()) activateProjectedElement(backSource);\n },\n { capture: true },\n );\n root.append(backProjection);\n nextBack.setAttribute(marker, '');\n nextBack.setAttribute('aria-hidden', 'true');\n nextBack.dispatchEvent(new CustomEvent('nativeUIShellChange'));\n topOffset = toolbarControlSize + toolbarControlGap;\n }\n for (const { group, actions: sources } of groups) {\n const projection = (sources.length === 1 ? sources[0] : group).cloneNode(false) as HTMLElement;\n if (sources.length === 1) syncAction(projection, sources[0]);\n else copyAttributes(projection, group);\n projection.classList.add(toolbarProjectionClass, 'ion-cloned-element');\n projection.style.setProperty('--ios-theme-vertical-bars-toolbar-offset', `${topOffset}px`);\n const actions = sources.map((source) => {\n const clone = sources.length === 1 ? projection : (source.cloneNode(false) as HTMLElement);\n if (sources.length > 1) syncAction(clone, source);\n clone.addEventListener(\n 'click',\n (event) => {\n event.preventDefault();\n event.stopImmediatePropagation();\n if (isCurrentToolbarAction(source)) activateProjectedElement(source);\n },\n { capture: true },\n );\n if (sources.length > 1) projection.append(clone);\n const previousAriaHidden = source.getAttribute('aria-hidden');\n source.setAttribute(marker, '');\n source.setAttribute('aria-hidden', 'true');\n source.dispatchEvent(new CustomEvent('nativeUIShellChange'));\n return { source, projection: clone, previousAriaHidden };\n });\n root.append(projection);\n toolbarProjections.push({ source: group, projection, actions });\n topOffset += actions.length * toolbarControlSize + toolbarControlGap;\n }\n if (nextBack || toolbarProjections.length) root.classList.add(readyClass);\n sourceObserver = new MutationObserver((records) => {\n if (\n records.some(\n (record) =>\n record.type !== 'attributes' || (![marker, 'aria-hidden'].includes(record.attributeName ?? '') && !prehideOnlyMutation(record)),\n )\n )\n schedule();\n });\n if (nextBack?.shadowRoot)\n sourceObserver.observe(nextBack.shadowRoot, { subtree: true, childList: true, attributes: true, attributeOldValue: true });\n for (const { group } of groups)\n sourceObserver.observe(group, { subtree: true, childList: true, attributes: true, attributeOldValue: true });\n };\n const performUpdate = () => {\n frame = 0;\n syncToolbarText(doc);\n const currentRoot = verticalBarsRoot();\n if (observingVerticalBars !== !!currentRoot) {\n observingVerticalBars = !!currentRoot;\n observer.disconnect();\n observer.observe(doc.documentElement, {\n subtree: true,\n childList: true,\n characterData: observingVerticalBars,\n attributes: true,\n attributeOldValue: true,\n attributeFilter: observingVerticalBars ? undefined : ['class'],\n });\n }\n if (stopped || suspended || !currentRoot || !enabled()) return restore();\n const nextBack = toolbarEnabled ? findBack() : undefined;\n const groups = toolbarEnabled ? findToolbarGroups() : [];\n const projectionRoot = topModal(doc) ?? currentRoot;\n search.update(projectionRoot);\n if (!nextBack && !groups.length && !search.source) return restore();\n if (root === (topModal(doc) ?? currentRoot) && sameSources(nextBack, groups)) return syncExisting();\n restore();\n project(nextBack, groups);\n search.update(projectionRoot);\n updates++;\n };\n const update = () => {\n try {\n performUpdate();\n } catch {\n restore();\n } finally {\n const pending = waiters;\n waiters = [];\n pending.forEach((resolve) => resolve());\n }\n };\n const schedule = (): Promise<void> => {\n if (stopped) return Promise.resolve();\n // Release Web ownership before the native runtime can acknowledge its next frame.\n if (!enabled()) restore();\n const done = new Promise<void>((resolve) => waiters.push(resolve));\n if (!frame) frame = win.requestAnimationFrame(update);\n return done;\n };\n const observer = new MutationObserver((records) => {\n const insideProjection = (target: Node) => {\n const element = target instanceof Element ? target : target.parentNode instanceof Element ? target.parentNode : undefined;\n const rootNode = target.getRootNode();\n const shadowHost = rootNode instanceof ShadowRoot ? rootNode.host : undefined;\n return !![element, shadowHost].some((candidate) =>\n candidate?.closest(`.${backProjectionClass}, .${toolbarProjectionClass}, .${searchProjectionClass}`),\n );\n };\n const verticalBarsChanged = records.some(\n (record) =>\n (record.type === 'attributes' && (record.target as Element).matches('ion-app')) ||\n (record.type === 'childList' &&\n Array.from(record.addedNodes).some(\n (node) =>\n node instanceof Element &&\n (node.matches('ion-app.ios-theme-vertical-bars') || !!node.querySelector('ion-app.ios-theme-vertical-bars')),\n )),\n );\n if (\n (observingVerticalBars &&\n records.some(\n (record) =>\n record.attributeName !== marker &&\n record.attributeName !== toolbarTextMarker &&\n !prehideOnlyMutation(record) &&\n !insideProjection(record.target),\n )) ||\n (!observingVerticalBars && verticalBarsChanged && records.some((record) => !prehideOnlyMutation(record)))\n )\n schedule();\n });\n observer.observe(doc.documentElement, {\n subtree: true,\n childList: true,\n attributes: true,\n attributeOldValue: true,\n attributeFilter: ['class'],\n });\n const pageLifecycle = (event: Event) => {\n const page = event.target;\n if (!(page instanceof HTMLElement) || !page.matches('.ion-page')) return;\n if (event.type === VERTICAL_BARS_TRANSITION_CANCELED) {\n const entering = (event as CustomEvent<{ entering?: HTMLElement }>).detail?.entering;\n verticalBarsPages.cancel(entering, page);\n } else verticalBarsPages.lifecycle(event);\n if (verticalBarsRoot()) schedule();\n };\n for (const name of ['ionViewWillEnter', 'ionViewWillLeave', 'ionViewDidEnter', 'ionViewDidLeave'])\n doc.addEventListener(name, pageLifecycle, { capture: true, signal: listeners.signal });\n doc.addEventListener(VERTICAL_BARS_TRANSITION_CANCELED, pageLifecycle, { capture: true, signal: listeners.signal });\n for (const name of ['ionModalWillPresent', 'ionModalDidDismiss'])\n doc.addEventListener(name, schedule, { capture: true, signal: listeners.signal });\n win.addEventListener('resize', schedule, { signal: listeners.signal });\n win.addEventListener('nativeUIShellRefresh', schedule, { signal: listeners.signal });\n schedule();\n\n return {\n getStatus: (): NativeUIShellStatus => ({\n state: stopped ? 'stopped' : 'web',\n projected:\n Number(!!backSource) + Number(!!search.source) + toolbarProjections.reduce((count, group) => count + group.actions.length, 0),\n updates,\n }),\n async suspend() {\n suspended++;\n restore();\n let resumed = false;\n return {\n async resume() {\n if (resumed) return;\n resumed = true;\n suspended = Math.max(0, suspended - 1);\n if (!suspended) await schedule();\n },\n };\n },\n async destroy() {\n if (stopped) return;\n stopped = true;\n win.cancelAnimationFrame(frame);\n frame = 0;\n waiters.forEach((resolve) => resolve());\n waiters = [];\n observer.disconnect();\n sourceObserver?.disconnect();\n listeners.abort();\n restore();\n },\n };\n};\n"],"mappings":"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"}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { Animation } from "@ionic/core/components";
|
|
2
|
-
//#region src/native-integration/index.d.ts
|
|
3
|
-
export interface NativeUIShellIntegration {
|
|
4
|
-
suspend(scopes: HTMLElement[]): Promise<(canceled?: boolean) => void>;
|
|
5
|
-
search?(binding: NativeSearchBinding, active: boolean, focus?: boolean): Promise<boolean>;
|
|
6
|
-
}
|
|
7
|
-
export interface NativeSearchBinding {
|
|
8
|
-
tabBar: HTMLElement;
|
|
9
|
-
trigger: HTMLElement;
|
|
10
|
-
footer: HTMLElement;
|
|
11
|
-
active: boolean;
|
|
12
|
-
focused: boolean;
|
|
13
|
-
}
|
|
14
|
-
export declare const registerNativeSearch: (tabBar: HTMLElement, trigger: HTMLElement, footer: HTMLElement) => NativeSearchBinding;
|
|
15
|
-
export declare const getNativeSearchBindings: (doc: Document) => NativeSearchBinding[];
|
|
16
|
-
export declare const requestNativeSearch: (binding: NativeSearchBinding, active: boolean, focus?: boolean) => Promise<boolean>;
|
|
17
|
-
export declare const VERTICAL_BARS_TRANSITION_CANCELED = "iosThemeVerticalBarsTransitionCanceled";
|
|
18
|
-
export declare const setNativeUIShellIntegration: (doc: Document, runtime?: NativeUIShellIntegration) => void;
|
|
19
|
-
export declare const isNativeUIShell: (element: HTMLElement) => boolean;
|
|
20
|
-
export declare const suspendNativeUIShell: (scopes: HTMLElement[]) => Promise<(canceled?: boolean) => void>;
|
|
21
|
-
export declare const connectNativeUIShellTransition: (animation: Animation, entering: HTMLElement, leaving?: HTMLElement) => void;
|
|
22
|
-
//#endregion
|
|
23
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/native-integration/index.ts"],"mappings":";;iBAGiB;EACf,QAAQ,QAAQ,gBAAgB,SAAS;EACzC,QAAQ,SAAS,qBAAqB,iBAAiB,kBAAkB;;iBAG1D;EACf,QAAQ;EACR,SAAS;EACT,QAAQ;EACR;EACA;;qBAKW,uBAAwB,QAAQ,aAAa,SAAS,aAAa,QAAQ,gBAAc;qBASzF,0BAA2B,KAAK,aAAW;qBAG3C,sBAA6B,SAAS,qBAAqB,iBAAiB,oBAAkB;qBAI9F;qBAEA,8BAA+B,KAAK,UAAU,UAAU;qBAKxD,kBAAmB,SAAS;qBAE5B,uBAA8B,QAAQ,kBAAgB,SAAS;qBAO/D,iCAAkC,WAAW,WAAW,UAAU,aAAa,UAAU"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/native-integration/index.ts"],"sourcesContent":["/// <reference lib=\"es2021.weakref\" />\nimport type { Animation } from '@ionic/core/components';\n\nexport interface NativeUIShellIntegration {\n suspend(scopes: HTMLElement[]): Promise<(canceled?: boolean) => void>;\n search?(binding: NativeSearchBinding, active: boolean, focus?: boolean): Promise<boolean>;\n}\n\nexport interface NativeSearchBinding {\n tabBar: HTMLElement;\n trigger: HTMLElement;\n footer: HTMLElement;\n active: boolean;\n focused: boolean;\n}\n\nconst searches = new WeakMap<Document, WeakRef<NativeSearchBinding>[]>();\n\nexport const registerNativeSearch = (tabBar: HTMLElement, trigger: HTMLElement, footer: HTMLElement): NativeSearchBinding => {\n const binding = { tabBar, trigger, footer, active: false, focused: false };\n const entries = (searches.get(tabBar.ownerDocument) ?? []).filter((entry) => entry.deref() && entry.deref()?.footer !== footer);\n entries.push(new WeakRef(binding));\n searches.set(tabBar.ownerDocument, entries);\n tabBar.ownerDocument.defaultView?.dispatchEvent(new Event('nativeUIShellRefresh'));\n return binding;\n};\n\nexport const getNativeSearchBindings = (doc: Document): NativeSearchBinding[] =>\n (searches.get(doc) ?? []).flatMap((entry) => entry.deref() ?? []);\n\nexport const requestNativeSearch = async (binding: NativeSearchBinding, active: boolean, focus?: boolean): Promise<boolean> =>\n (await runtimes.get(binding.tabBar.ownerDocument)?.search?.(binding, active, focus)) ?? false;\n\nconst runtimes = new WeakMap<Document, NativeUIShellIntegration>();\nexport const VERTICAL_BARS_TRANSITION_CANCELED = 'iosThemeVerticalBarsTransitionCanceled';\n\nexport const setNativeUIShellIntegration = (doc: Document, runtime?: NativeUIShellIntegration) => {\n if (runtime) runtimes.set(doc, runtime);\n else runtimes.delete(doc);\n};\n\nexport const isNativeUIShell = (element: HTMLElement) => element.hasAttribute('data-native-ui-shell');\n\nexport const suspendNativeUIShell = async (scopes: HTMLElement[]): Promise<(canceled?: boolean) => void> =>\n (await runtimes.get(scopes[0]?.ownerDocument)?.suspend(scopes)) ?? (() => {});\n\nconst connectedTransitions = new WeakSet<Animation>();\nconst cancellationTransitions = new WeakSet<Animation>();\n\n/** Ionic write hooks cannot await the bridge. Gate playback, including interactive playback. */\nexport const connectNativeUIShellTransition = (animation: Animation, entering: HTMLElement, leaving?: HTMLElement) => {\n if (leaving && !cancellationTransitions.has(animation)) {\n cancellationTransitions.add(animation);\n animation.onFinish((step) => {\n if (step === 0) leaving.dispatchEvent(new CustomEvent(VERTICAL_BARS_TRANSITION_CANCELED, { bubbles: true, detail: { entering } }));\n });\n }\n if (connectedTransitions.has(animation) || !runtimes.has(entering.ownerDocument)) return;\n connectedTransitions.add(animation);\n const scopes = leaving ? [entering, leaving] : [entering];\n const play = animation.play.bind(animation);\n const progressStart = animation.progressStart.bind(animation);\n const progressStep = animation.progressStep.bind(animation);\n const progressEnd = animation.progressEnd.bind(animation);\n const destroy = animation.destroy.bind(animation);\n let release: ((canceled?: boolean) => void) | undefined;\n let preparation: Promise<void> | undefined;\n let disposed = false;\n let interactiveReady = false;\n let step: number | undefined;\n let end: Parameters<Animation['progressEnd']> | undefined;\n const prepare = () =>\n (preparation ??= suspendNativeUIShell(scopes).then((resume) => {\n if (disposed) resume(true);\n else release = resume;\n }));\n const finish = (canceled = false) => {\n release?.(canceled);\n release = undefined;\n preparation = undefined;\n };\n animation.onFinish((step) => finish(step === 0));\n animation.play = async (options) => {\n await prepare();\n if (disposed) return;\n try {\n await play(options);\n } finally {\n finish();\n }\n };\n animation.progressStart = (...args) => {\n interactiveReady = false;\n step = undefined;\n end = undefined;\n void prepare().then(() => {\n if (disposed) return;\n progressStart(...args);\n interactiveReady = true;\n if (step !== undefined) progressStep(step);\n if (end) progressEnd(...end);\n });\n return animation;\n };\n animation.progressStep = (value) => {\n step = value;\n if (interactiveReady) progressStep(value);\n return animation;\n };\n animation.progressEnd = (...args) => {\n end = args;\n if (interactiveReady) progressEnd(...args);\n return animation;\n };\n animation.destroy = (...args) => {\n disposed = true;\n finish(true);\n return destroy(...args);\n };\n};\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"transition.d.ts","names":[],"sources":["../../src/native-integration/transition.ts"],"mappings":";;qBAQa,8BACV,SAAS,qBAAmB"}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { connectNativeUIShellTransition } from "./index.js";
|
|
2
|
-
//#region src/native-integration/transition.ts
|
|
3
|
-
/**
|
|
4
|
-
* Keeps an existing Ionic navigation animation and coordinates native control handoff.
|
|
5
|
-
* Register the returned builder as navAnimation. Do not use it for overlay animations.
|
|
6
|
-
* The builder must return a fresh Animation for each navigation; Ionic destroys it afterward.
|
|
7
|
-
*/
|
|
8
|
-
const withNativeUIShellTransition = (builder) => (baseEl, opts) => {
|
|
9
|
-
const animation = builder(baseEl, opts);
|
|
10
|
-
if (opts?.enteringEl) connectNativeUIShellTransition(animation, opts.enteringEl, opts.leavingEl);
|
|
11
|
-
return animation;
|
|
12
|
-
};
|
|
13
|
-
//#endregion
|
|
14
|
-
export { withNativeUIShellTransition };
|
|
15
|
-
|
|
16
|
-
//# sourceMappingURL=transition.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"transition.js","names":[],"sources":["../../src/native-integration/transition.ts"],"sourcesContent":["import type { AnimationBuilder } from '@ionic/core/components';\nimport { connectNativeUIShellTransition } from './index';\n\n/**\n * Keeps an existing Ionic navigation animation and coordinates native control handoff.\n * Register the returned builder as navAnimation. Do not use it for overlay animations.\n * The builder must return a fresh Animation for each navigation; Ionic destroys it afterward.\n */\nexport const withNativeUIShellTransition =\n (builder: AnimationBuilder): AnimationBuilder =>\n (baseEl, opts) => {\n const animation = builder(baseEl, opts);\n if (opts?.enteringEl) connectNativeUIShellTransition(animation, opts.enteringEl, opts.leavingEl);\n return animation;\n };\n"],"mappings":";;;;;;;AAQA,MAAa,+BACV,aACA,QAAQ,SAAS;CAChB,MAAM,YAAY,QAAQ,QAAQ,IAAI;CACtC,IAAI,MAAM,YAAY,+BAA+B,WAAW,KAAK,YAAY,KAAK,SAAS;CAC/F,OAAO;AACT"}
|
package/dist/vertical-bars.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { withNativeUIShellTransition } from "./native-integration/transition.js";
|
|
2
|
-
import { NativeUIShellStatus, NativeUIShellSuspension, VerticalBarEdge, VerticalControlAreaHandle, VerticalControlAreaOptions } from "./native/definitions.js";
|
|
3
|
-
import { applyFoldStateClasses } from "./native/foldable/fold-state.js";
|
|
4
|
-
import { IonicNativeUIShell, enableVerticalControlArea, setVerticalControlAreaPlacement } from "./native/index.js";
|
|
5
|
-
export { IonicNativeUIShell, type NativeUIShellStatus, type NativeUIShellSuspension, type VerticalBarEdge, type VerticalControlAreaHandle, type VerticalControlAreaOptions, applyFoldStateClasses, enableVerticalControlArea, setVerticalControlAreaPlacement, withNativeUIShellTransition };
|
package/dist/vertical-bars.js
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { withNativeUIShellTransition } from "./native-integration/transition.js";
|
|
2
|
-
import { IonicNativeUIShell, enableVerticalControlArea, setVerticalControlAreaPlacement } from "./native/index.js";
|
|
3
|
-
import { applyFoldStateClasses } from "./native/foldable/fold-state.js";
|
|
4
|
-
export { IonicNativeUIShell, applyFoldStateClasses, enableVerticalControlArea, setVerticalControlAreaPlacement, withNativeUIShellTransition };
|
package/docs/e2e-testing.md
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# E2E screenshot testing
|
|
2
|
-
|
|
3
|
-
This maintainer guide explains how to run the Playwright visual-regression suite for the iOS26 demo. The suite covers every entry declared in `demo/e2e/screenshot.spec.ts` in both light and dark modes. Overlay variants are generated from the shared arrays in `demo/src/app/overlay-types.ts`.
|
|
4
|
-
|
|
5
|
-
## Run the suite
|
|
6
|
-
|
|
7
|
-
Install the demo dependencies first:
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
cd demo
|
|
11
|
-
npm install
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
Then choose the command that matches the task:
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
npm run test:e2e # Run the suite
|
|
18
|
-
npm run test:e2e:ui # Open Playwright UI mode
|
|
19
|
-
npm run test:e2e:debug # Run with the Playwright debugger
|
|
20
|
-
npm run test:e2e:update # Regenerate intentional baseline changes
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
To reproduce the Linux environment used by CI, run the Docker variants from `demo/`:
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
npm run test:e2e:docker
|
|
27
|
-
npm run test:e2e:docker:update
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
The Docker commands use the Playwright image pinned in `demo/package.json`.
|
|
31
|
-
|
|
32
|
-
## Review a failure
|
|
33
|
-
|
|
34
|
-
A screenshot mismatch can be a regression or an intentional visual change. Before updating a baseline:
|
|
35
|
-
|
|
36
|
-
1. Inspect the actual, expected, and diff images in `demo/test-results/`.
|
|
37
|
-
2. Check the affected route in both light and dark modes.
|
|
38
|
-
3. Confirm that the component change is intentional.
|
|
39
|
-
4. Regenerate the baseline with `npm run test:e2e:update`, or use the Docker variant when matching CI rendering.
|
|
40
|
-
|
|
41
|
-
The HTML report is written to `demo/playwright-report/` and can be opened with:
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
npx playwright show-report
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## Add coverage
|
|
48
|
-
|
|
49
|
-
When adding a demo route or overlay variant, update `demo/e2e/screenshot.spec.ts` and regenerate the relevant baselines. Commit baseline changes only after reviewing the visual diff.
|
|
50
|
-
|
|
51
|
-
Pull requests targeting `main` or `ios26` run the E2E workflow in `.github/workflows/e2e-pull_request.yml`; pushes to either branch run `.github/workflows/e2e-main.yml`. GitHub builds the pull-request merge ref against its target branch, so an `ios26` pull request starts with the iOS 26 snapshots. Snapshot changes intentionally committed by the pull request are then tested as part of that merge result. The `/update-screenshots` command loads its update procedure from the pull request's target branch and commits the regenerated screenshots to the pull request branch.
|
package/docs/feedback.md
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
# Feature requests for Ionic Framework
|
|
2
|
-
|
|
3
|
-
## feat(): change `--knob-handle-size` to `--knob-handle-width` / `--knob-handle-height`
|
|
4
|
-
|
|
5
|
-
Currently, only square sizes are taken into consideration.
|
|
6
|
-
Overwriting the `knob` itself is possible, but `--knob-handle-size` cannot be ignored as it plays a crucial role in determining the `top` and `margin-inline-start` of `div.range-knob-handle`.
|
|
7
|
-
|
|
8
|
-
## feat(): ion-config new property for `collapse`
|
|
9
|
-
|
|
10
|
-
Currently, `collapse` behavior is automatically enabled in iOS mode, but this should be configurable through `ion-config` for better control.
|
|
11
|
-
|
|
12
|
-
ex:
|
|
13
|
-
|
|
14
|
-
```typescript
|
|
15
|
-
export interface IonicConfig {
|
|
16
|
-
...,
|
|
17
|
-
collapseLargeTitle: {
|
|
18
|
-
ios: boolean;
|
|
19
|
-
md: boolean;
|
|
20
|
-
ionic: boolean;
|
|
21
|
-
},
|
|
22
|
-
collapseBackButtonAnimation: {
|
|
23
|
-
ios: boolean;
|
|
24
|
-
md: boolean;
|
|
25
|
-
ionic: boolean;
|
|
26
|
-
},
|
|
27
|
-
}
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## feat(): add native shadow-part for design
|
|
31
|
-
|
|
32
|
-
### native-inner(or item-inner) part to ion-item
|
|
33
|
-
|
|
34
|
-
The styling for `ion-item[lines=inset]` is applied to `.item-inner`, which cannot be styled directly. This limitation means that for iOS 27 styling, I can only modify the border-bottom style through `::part(native)` with padding-right, preventing me from utilizing the full right side of `ion-item`. Adding `::part(native-inner)` would increase styling flexibility.
|
|
35
|
-
|
|
36
|
-
```diff
|
|
37
|
-
<ion-item>
|
|
38
|
-
<button type="button" class="item-native" part="native">
|
|
39
|
-
- <div class="item-inner">
|
|
40
|
-
+ <div class="item-inner" part="native-inner">
|
|
41
|
-
...
|
|
42
|
-
</div>
|
|
43
|
-
</button>
|
|
44
|
-
</ion-item>
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
### native part to ion-toast
|
|
48
|
-
|
|
49
|
-
Resolved: https://github.com/ionic-team/ionic-framework/pull/30992#event-23306774962
|
|
50
|
-
|
|
51
|
-
## docs(): Naming conventions for Ionic theme classes
|
|
52
|
-
|
|
53
|
-
Resolved.
|
|
54
|
-
|
|
55
|
-
### should disable ion-back-button Animation
|
|
56
|
-
|
|
57
|
-
Resolved: by created https://github.com/rdlabo-dev/ionic-theme-ios27/tree/main/src/transition
|
|
58
|
-
|
|
59
|
-
## feat(): ion-content[fullscreen=true] will have .content-fullscreen class
|
|
60
|
-
|
|
61
|
-
Resolved: https://github.com/ionic-team/ionic-framework/pull/30926
|
|
62
|
-
|
|
63
|
-
## feat(): add .range-knob-min and .range-knob-max directly to ion-range
|
|
64
|
-
|
|
65
|
-
Resolved: https://github.com/ionic-team/ionic-framework/pull/30932
|