@rdlabo/capacitor-native-ui 0.0.0-stage → 2.0.0-1
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/LICENSE +21 -0
- package/Package.swift +23 -0
- package/README.md +66 -2
- package/RdlaboCapacitorNativeUi.podspec +17 -0
- package/android/build.gradle +69 -0
- package/android/proguard-rules.pro +0 -0
- package/android/src/main/AndroidManifest.xml +1 -0
- package/android/src/main/java/dev/rdlabo/capacitor/nativeui/NativeUI.kt +51 -0
- package/android/src/main/java/dev/rdlabo/capacitor/nativeui/NativeUIPlugin.kt +192 -0
- package/android/src/main/java/dev/rdlabo/capacitor/nativeui/NativeUISnapshot.kt +57 -0
- package/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/core.d.ts +4 -0
- package/dist/core.js +3 -0
- package/dist/native/activation.d.ts +14 -0
- package/dist/native/activation.d.ts.map +1 -0
- package/dist/native/activation.js +305 -0
- package/dist/native/activation.js.map +1 -0
- package/dist/native/components/index.d.ts +19 -0
- package/dist/native/components/index.d.ts.map +1 -0
- package/dist/native/components/index.js +38 -0
- package/dist/native/components/index.js.map +1 -0
- package/dist/native/components/ion-back-button.d.ts +10 -0
- package/dist/native/components/ion-back-button.d.ts.map +1 -0
- package/dist/native/components/ion-back-button.js +21 -0
- package/dist/native/components/ion-back-button.js.map +1 -0
- package/dist/native/components/ion-button.d.ts +10 -0
- package/dist/native/components/ion-button.d.ts.map +1 -0
- package/dist/native/components/ion-button.js +25 -0
- package/dist/native/components/ion-button.js.map +1 -0
- package/dist/native/components/ion-buttons.d.ts +11 -0
- package/dist/native/components/ion-buttons.d.ts.map +1 -0
- package/dist/native/components/ion-buttons.js +30 -0
- package/dist/native/components/ion-buttons.js.map +1 -0
- package/dist/native/components/ion-fab.d.ts +10 -0
- package/dist/native/components/ion-fab.d.ts.map +1 -0
- package/dist/native/components/ion-fab.js +132 -0
- package/dist/native/components/ion-fab.js.map +1 -0
- package/dist/native/components/ion-menu-button.d.ts +13 -0
- package/dist/native/components/ion-menu-button.d.ts.map +1 -0
- package/dist/native/components/ion-menu-button.js +44 -0
- package/dist/native/components/ion-menu-button.js.map +1 -0
- package/dist/native/components/ion-segment.d.ts +11 -0
- package/dist/native/components/ion-segment.d.ts.map +1 -0
- package/dist/native/components/ion-segment.js +30 -0
- package/dist/native/components/ion-segment.js.map +1 -0
- package/dist/native/components/ion-tab-bar.d.ts +11 -0
- package/dist/native/components/ion-tab-bar.d.ts.map +1 -0
- package/dist/native/components/ion-tab-bar.js +50 -0
- package/dist/native/components/ion-tab-bar.js.map +1 -0
- package/dist/native/components/searchable-tabs.d.ts +20 -0
- package/dist/native/components/searchable-tabs.d.ts.map +1 -0
- package/dist/native/components/searchable-tabs.js +413 -0
- package/dist/native/components/searchable-tabs.js.map +1 -0
- package/dist/native/definitions.d.ts +237 -0
- package/dist/native/definitions.d.ts.map +1 -0
- package/dist/native/definitions.js +0 -0
- package/dist/native/extensions.d.ts +31 -0
- package/dist/native/extensions.d.ts.map +1 -0
- package/dist/native/extensions.js +122 -0
- package/dist/native/extensions.js.map +1 -0
- package/dist/native/foldable/fold-state.d.ts +5 -0
- package/dist/native/foldable/fold-state.d.ts.map +1 -0
- package/dist/native/foldable/fold-state.js +15 -0
- package/dist/native/foldable/fold-state.js.map +1 -0
- package/dist/native/foldable/types.d.ts +12 -0
- package/dist/native/foldable/types.d.ts.map +1 -0
- package/dist/native/foldable/types.js +0 -0
- package/dist/native/html.d.ts +9 -0
- package/dist/native/html.d.ts.map +1 -0
- package/dist/native/html.js +197 -0
- package/dist/native/html.js.map +1 -0
- package/dist/native/index.d.ts +10 -0
- package/dist/native/index.d.ts.map +1 -0
- package/dist/native/index.js +19 -0
- package/dist/native/index.js.map +1 -0
- package/dist/native/legacy-layout.d.ts +5 -0
- package/dist/native/legacy-layout.d.ts.map +1 -0
- package/dist/native/legacy-layout.js +27 -0
- package/dist/native/legacy-layout.js.map +1 -0
- package/dist/native/overlays/content.d.ts +4 -0
- package/dist/native/overlays/content.d.ts.map +1 -0
- package/dist/native/overlays/content.js +51 -0
- package/dist/native/overlays/content.js.map +1 -0
- package/dist/native/overlays/controller.d.ts +8 -0
- package/dist/native/overlays/controller.d.ts.map +1 -0
- package/dist/native/overlays/controller.js +285 -0
- package/dist/native/overlays/controller.js.map +1 -0
- package/dist/native/overlays/dialog-animation.d.ts +9 -0
- package/dist/native/overlays/dialog-animation.d.ts.map +1 -0
- package/dist/native/overlays/dialog-animation.js +53 -0
- package/dist/native/overlays/dialog-animation.js.map +1 -0
- package/dist/native/overlays/dismiss-animation.d.ts +4 -0
- package/dist/native/overlays/dismiss-animation.d.ts.map +1 -0
- package/dist/native/overlays/dismiss-animation.js +18 -0
- package/dist/native/overlays/dismiss-animation.js.map +1 -0
- package/dist/native/overlays/focus.d.ts +5 -0
- package/dist/native/overlays/focus.d.ts.map +1 -0
- package/dist/native/overlays/focus.js +59 -0
- package/dist/native/overlays/focus.js.map +1 -0
- package/dist/native/overlays/popover.d.ts +12 -0
- package/dist/native/overlays/popover.d.ts.map +1 -0
- package/dist/native/overlays/popover.js +110 -0
- package/dist/native/overlays/popover.js.map +1 -0
- package/dist/native/overlays/styles.d.ts +11 -0
- package/dist/native/overlays/styles.d.ts.map +1 -0
- package/dist/native/overlays/styles.js +167 -0
- package/dist/native/overlays/styles.js.map +1 -0
- package/dist/native/prehide.d.ts +8 -0
- package/dist/native/prehide.d.ts.map +1 -0
- package/dist/native/prehide.js +238 -0
- package/dist/native/prehide.js.map +1 -0
- package/dist/native/runtime.d.ts +7 -0
- package/dist/native/runtime.d.ts.map +1 -0
- package/dist/native/runtime.js +776 -0
- package/dist/native/runtime.js.map +1 -0
- package/dist/native/shared/bridge.d.ts +6 -0
- package/dist/native/shared/bridge.d.ts.map +1 -0
- package/dist/native/shared/bridge.js +18 -0
- package/dist/native/shared/bridge.js.map +1 -0
- package/dist/native/shared/candidate.d.ts +25 -0
- package/dist/native/shared/candidate.d.ts.map +1 -0
- package/dist/native/shared/candidate.js +106 -0
- package/dist/native/shared/candidate.js.map +1 -0
- package/dist/native/shared/clipping.d.ts +5 -0
- package/dist/native/shared/clipping.d.ts.map +1 -0
- package/dist/native/shared/clipping.js +26 -0
- package/dist/native/shared/clipping.js.map +1 -0
- package/dist/native/shared/control-options.d.ts +6 -0
- package/dist/native/shared/control-options.d.ts.map +1 -0
- package/dist/native/shared/control-options.js +17 -0
- package/dist/native/shared/control-options.js.map +1 -0
- package/dist/native/shared/crossfade.d.ts +12 -0
- package/dist/native/shared/crossfade.d.ts.map +1 -0
- package/dist/native/shared/crossfade.js +67 -0
- package/dist/native/shared/crossfade.js.map +1 -0
- package/dist/native/shared/diagnostics.d.ts +4 -0
- package/dist/native/shared/diagnostics.d.ts.map +1 -0
- package/dist/native/shared/diagnostics.js +18 -0
- package/dist/native/shared/diagnostics.js.map +1 -0
- package/dist/native/shared/dom.d.ts +46 -0
- package/dist/native/shared/dom.d.ts.map +1 -0
- package/dist/native/shared/dom.js +180 -0
- package/dist/native/shared/dom.js.map +1 -0
- package/dist/native/shared/events.d.ts +15 -0
- package/dist/native/shared/events.d.ts.map +1 -0
- package/dist/native/shared/events.js +17 -0
- package/dist/native/shared/events.js.map +1 -0
- package/dist/native/shared/icons.d.ts +8 -0
- package/dist/native/shared/icons.d.ts.map +1 -0
- package/dist/native/shared/icons.js +61 -0
- package/dist/native/shared/icons.js.map +1 -0
- package/dist/native/shared/modal.d.ts +10 -0
- package/dist/native/shared/modal.d.ts.map +1 -0
- package/dist/native/shared/modal.js +160 -0
- package/dist/native/shared/modal.js.map +1 -0
- package/dist/native/shared/projection-id.d.ts +4 -0
- package/dist/native/shared/projection-id.d.ts.map +1 -0
- package/dist/native/shared/projection-id.js +7 -0
- package/dist/native/shared/projection-id.js.map +1 -0
- package/dist/native/shared/toolbar-options.d.ts +13 -0
- package/dist/native/shared/toolbar-options.d.ts.map +1 -0
- package/dist/native/shared/toolbar-options.js +28 -0
- package/dist/native/shared/toolbar-options.js.map +1 -0
- package/dist/native/shared/vertical-bars-geometry.d.ts +10 -0
- package/dist/native/shared/vertical-bars-geometry.d.ts.map +1 -0
- package/dist/native/shared/vertical-bars-geometry.js +85 -0
- package/dist/native/shared/vertical-bars-geometry.js.map +1 -0
- package/dist/native/startup.d.ts +8 -0
- package/dist/native/startup.d.ts.map +1 -0
- package/dist/native/startup.js +70 -0
- package/dist/native/startup.js.map +1 -0
- package/dist/native/vertical-bars-web-search.d.ts +10 -0
- package/dist/native/vertical-bars-web-search.d.ts.map +1 -0
- package/dist/native/vertical-bars-web-search.js +90 -0
- package/dist/native/vertical-bars-web-search.js.map +1 -0
- package/dist/native/vertical-bars-web.d.ts +5 -0
- package/dist/native/vertical-bars-web.d.ts.map +1 -0
- package/dist/native/vertical-bars-web.js +422 -0
- package/dist/native/vertical-bars-web.js.map +1 -0
- package/dist/native-integration/index.d.ts +25 -0
- package/dist/native-integration/index.d.ts.map +1 -0
- package/dist/native-integration/index.js +33 -0
- package/dist/native-integration/index.js.map +1 -0
- package/dist/vertical-bars.d.ts +6 -0
- package/dist/vertical-bars.js +5 -0
- package/docs/appearance.md +45 -0
- package/docs/configuration.md +219 -0
- package/docs/framework-independent.md +107 -0
- package/docs/ionic-vertical-bars.md +173 -0
- package/docs/migration.md +184 -0
- package/docs/native-ui-extensions.md +394 -0
- package/docs/native-ui.md +528 -0
- package/docs/setup.md +224 -0
- package/docs/vertical-bars.md +431 -0
- package/ios/Sources/NativeUIPlugin/Components/NativeUIButton.swift +71 -0
- package/ios/Sources/NativeUIPlugin/Components/NativeUIButtons.swift +24 -0
- package/ios/Sources/NativeUIPlugin/Components/NativeUIComponents.swift +19 -0
- package/ios/Sources/NativeUIPlugin/Components/NativeUIFab.swift +80 -0
- package/ios/Sources/NativeUIPlugin/Components/NativeUISearchController.swift +439 -0
- package/ios/Sources/NativeUIPlugin/Components/NativeUISegment.swift +91 -0
- package/ios/Sources/NativeUIPlugin/Components/NativeUITabBar.swift +218 -0
- package/ios/Sources/NativeUIPlugin/Components/NativeUIVerticalBars.swift +590 -0
- package/ios/Sources/NativeUIPlugin/Components/NativeUIVerticalSearch.swift +118 -0
- package/ios/Sources/NativeUIPlugin/Extensions/NativeUI.swift +178 -0
- package/ios/Sources/NativeUIPlugin/Extensions/NativeUIRendering.swift +38 -0
- package/ios/Sources/NativeUIPlugin/NativeUIPlugin.swift +615 -0
- package/ios/Sources/NativeUIPlugin/Overlays/NativeUIOverlayController.swift +119 -0
- package/ios/Sources/NativeUIPlugin/Overlays/NativeUIOverlayHost.swift +75 -0
- package/ios/Sources/NativeUIPlugin/Shared/NativeUIControlRendering.swift +21 -0
- package/ios/Sources/NativeUIPlugin/Shared/NativeUICrossfade.swift +35 -0
- package/ios/Sources/NativeUIPlugin/Shared/NativeUIHost.swift +8 -0
- package/ios/Sources/NativeUIPlugin/Shared/NativeUISnapshot.swift +161 -0
- package/ios/Sources/NativeUIPlugin/Shared/NativeUIVerticalBarsGeometry.swift +52 -0
- package/ios/Tests/NativeUIPluginTests/NativeUIExtensionTests.swift +165 -0
- package/ios/Tests/NativeUIPluginTests/NativeUISnapshotTests.swift +805 -0
- package/package.json +89 -4
- package/src/core.ts +14 -0
- package/src/native/activation.ts +385 -0
- package/src/native/components/index.ts +45 -0
- package/src/native/components/ion-back-button.ts +22 -0
- package/src/native/components/ion-button.ts +25 -0
- package/src/native/components/ion-buttons.ts +37 -0
- package/src/native/components/ion-fab.ts +151 -0
- package/src/native/components/ion-menu-button.ts +37 -0
- package/src/native/components/ion-segment.ts +27 -0
- package/src/native/components/ion-tab-bar.ts +50 -0
- package/src/native/components/searchable-tabs.ts +499 -0
- package/src/native/definitions.ts +274 -0
- package/src/native/extensions.ts +176 -0
- package/src/native/foldable/fold-state.ts +10 -0
- package/src/native/foldable/types.ts +4 -0
- package/src/native/html.ts +199 -0
- package/src/native/index.ts +32 -0
- package/src/native/legacy-layout.ts +21 -0
- package/src/native/overlays/content.ts +51 -0
- package/src/native/overlays/controller.ts +349 -0
- package/src/native/overlays/dialog-animation.ts +53 -0
- package/src/native/overlays/dismiss-animation.ts +15 -0
- package/src/native/overlays/focus.ts +64 -0
- package/src/native/overlays/popover.ts +120 -0
- package/src/native/overlays/styles.ts +181 -0
- package/src/native/prehide.ts +285 -0
- package/src/native/runtime.ts +979 -0
- package/src/native/shared/bridge.ts +18 -0
- package/src/native/shared/candidate.ts +162 -0
- package/src/native/shared/clipping.ts +24 -0
- package/src/native/shared/control-options.ts +20 -0
- package/src/native/shared/crossfade.ts +67 -0
- package/src/native/shared/diagnostics.ts +13 -0
- package/src/native/shared/dom.ts +304 -0
- package/src/native/shared/events.ts +14 -0
- package/src/native/shared/icons.ts +57 -0
- package/src/native/shared/modal.ts +157 -0
- package/src/native/shared/projection-id.ts +2 -0
- package/src/native/shared/toolbar-options.ts +49 -0
- package/src/native/shared/vertical-bars-geometry.ts +80 -0
- package/src/native/startup.ts +68 -0
- package/src/native/vertical-bars-web-search.ts +86 -0
- package/src/native/vertical-bars-web.ts +500 -0
- package/src/native-integration/index.ts +49 -0
- package/src/vertical-bars.ts +12 -0
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
import { controlSelected } from "./shared/control-options.js";
|
|
2
|
+
import { inVerticalBarsSurface, topModal } from "./shared/modal.js";
|
|
3
|
+
import { createCrossfade } from "./shared/crossfade.js";
|
|
4
|
+
import { activateProjectedElement, createVerticalBarsPageState, isExcluded, isNativeUIDisabled, isVerticalBarsToolbarGroup, marker, preferredVerticalBarsBack, prehiddenClass, prehideOnlyMutation, syncToolbarText, unprojected, verticalBarsActionCandidate, verticalBarsBackCandidate, verticalBarsEnteringPage, verticalBarsOwned, verticalBarsToolbarActions, withoutPrehide } from "./shared/dom.js";
|
|
5
|
+
import { VERTICAL_BARS_TRANSITION_CANCELED } from "../native-integration/index.js";
|
|
6
|
+
import { alignVerticalBarClone, verticalBarFrame } from "./shared/vertical-bars-geometry.js";
|
|
7
|
+
import { createVerticalBarsWebSearch, searchProjectionClass } from "./vertical-bars-web-search.js";
|
|
8
|
+
//#region src/native/vertical-bars-web.ts
|
|
9
|
+
const backProjectionClass = "ios-theme-vertical-bars-back-button-projection";
|
|
10
|
+
const toolbarProjectionClass = "ios-theme-vertical-bars-toolbar-projection";
|
|
11
|
+
const readyClass = "ios-theme-vertical-bars-toolbar-ready";
|
|
12
|
+
const toolbarControlSize = 46;
|
|
13
|
+
const toolbarControlGap = 10;
|
|
14
|
+
const createVerticalBarsWebProjection = (doc, options, enabled = () => true) => {
|
|
15
|
+
const win = doc.defaultView;
|
|
16
|
+
const crossfade = createCrossfade(win);
|
|
17
|
+
let incomingInstant;
|
|
18
|
+
const toolbarEnabled = options.ionic?.auto !== false;
|
|
19
|
+
let root;
|
|
20
|
+
let backSource;
|
|
21
|
+
let backProjection;
|
|
22
|
+
let previousBackAriaHidden = null;
|
|
23
|
+
let toolbarProjections = [];
|
|
24
|
+
let suspended = 0;
|
|
25
|
+
let stopped = false;
|
|
26
|
+
let frame = 0;
|
|
27
|
+
let updates = 0;
|
|
28
|
+
let observingVerticalBars = false;
|
|
29
|
+
const verticalBarsPages = createVerticalBarsPageState();
|
|
30
|
+
let sourceObserver;
|
|
31
|
+
let waiters = [];
|
|
32
|
+
const listeners = new AbortController();
|
|
33
|
+
const verticalBarsRoot = () => doc.querySelector("ion-app.ios-theme-vertical-bars");
|
|
34
|
+
const projectedSources = () => [
|
|
35
|
+
backSource,
|
|
36
|
+
search.source,
|
|
37
|
+
...toolbarProjections.flatMap(({ actions }) => actions.map(({ source }) => source))
|
|
38
|
+
].filter((source) => !!source);
|
|
39
|
+
const isRendered = (element) => withoutPrehide(element, () => {
|
|
40
|
+
const style = getComputedStyle(element);
|
|
41
|
+
const rect = element.getBoundingClientRect();
|
|
42
|
+
return element.isConnected && style.display !== "none" && style.visibility === "visible" && rect.width > 0 && rect.height > 0;
|
|
43
|
+
});
|
|
44
|
+
const search = createVerticalBarsWebSearch(doc, (element) => options.ionic?.auto !== false && controlSelected(element, options, "tabs", true) && !!verticalBarsRoot()?.contains(element) && (!options.root || options.root.contains(element)) && !element.closest("[data-native-ui-placement=\"element\"]") && inVerticalBarsSurface(element) && !isExcluded(element, verticalBarsEnteringPage(element)) && !isNativeUIDisabled(element) && !verticalBarsPages.isDeparted(element) && isRendered(element), () => {
|
|
45
|
+
schedule();
|
|
46
|
+
});
|
|
47
|
+
const inEligibleToolbar = (element) => !!verticalBarsRoot()?.contains(element) && (!options.root || options.root.contains(element)) && !element.closest("[data-native-ui-placement=\"element\"]") && inVerticalBarsSurface(element) && verticalBarsActionCandidate(element) && !isExcluded(element, verticalBarsEnteringPage(element)) && !verticalBarsPages.isDeparted(element);
|
|
48
|
+
const isEligibleBack = (element) => !!verticalBarsRoot()?.contains(element) && (!options.root || options.root.contains(element)) && !element.closest("[data-native-ui-placement=\"element\"]") && inVerticalBarsSurface(element) && verticalBarsOwned(element) && verticalBarsBackCandidate(element) && !isExcluded(element, verticalBarsEnteringPage(element)) && !verticalBarsPages.isDeparted(element) && unprojected(projectedSources(), () => isRendered(element));
|
|
49
|
+
const pageOrder = (element) => Array.from(doc.querySelectorAll(".ion-page")).indexOf(element.closest(".ion-page"));
|
|
50
|
+
const findBack = () => {
|
|
51
|
+
const candidates = Array.from(doc.querySelectorAll(`ion-back-button:not(.${backProjectionClass})`)).filter(isEligibleBack);
|
|
52
|
+
return preferredVerticalBarsBack(candidates, doc);
|
|
53
|
+
};
|
|
54
|
+
const findToolbarGroups = () => {
|
|
55
|
+
const candidates = Array.from(doc.querySelectorAll(`ion-buttons:not(.${toolbarProjectionClass})`)).flatMap((group) => {
|
|
56
|
+
const actions = verticalBarsToolbarActions(group).filter((action) => unprojected(projectedSources(), () => isRendered(action)));
|
|
57
|
+
if (!actions.length) return [];
|
|
58
|
+
if (!isVerticalBarsToolbarGroup(group)) return actions.filter(inEligibleToolbar).map((action) => ({
|
|
59
|
+
group,
|
|
60
|
+
actions: [action]
|
|
61
|
+
}));
|
|
62
|
+
return inEligibleToolbar(group) && unprojected(projectedSources(), () => isRendered(group)) ? [{
|
|
63
|
+
group,
|
|
64
|
+
actions
|
|
65
|
+
}] : [];
|
|
66
|
+
});
|
|
67
|
+
for (const action of Array.from(doc.querySelectorAll("ion-button, ion-menu-button"))) {
|
|
68
|
+
if (action.closest("ion-buttons") || !verticalBarsOwned(action) || !inEligibleToolbar(action)) continue;
|
|
69
|
+
if (unprojected(projectedSources(), () => isRendered(action))) candidates.push({
|
|
70
|
+
group: action,
|
|
71
|
+
actions: [action]
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
const highestPage = Math.max(...candidates.map(({ group }) => pageOrder(group)));
|
|
75
|
+
return candidates.filter(({ group }) => pageOrder(group) === highestPage);
|
|
76
|
+
};
|
|
77
|
+
const isCurrentToolbarAction = (source) => findToolbarGroups().some(({ actions }) => actions.includes(source));
|
|
78
|
+
const restore = (retire) => {
|
|
79
|
+
search.restore(retire);
|
|
80
|
+
if (backProjection) {
|
|
81
|
+
if (retire) retire(backProjection);
|
|
82
|
+
else backProjection.remove();
|
|
83
|
+
}
|
|
84
|
+
backProjection = void 0;
|
|
85
|
+
if (backSource) {
|
|
86
|
+
backSource.removeAttribute(marker);
|
|
87
|
+
if (previousBackAriaHidden === null) backSource.removeAttribute("aria-hidden");
|
|
88
|
+
else backSource.setAttribute("aria-hidden", previousBackAriaHidden);
|
|
89
|
+
backSource.dispatchEvent(new CustomEvent("nativeUIChange"));
|
|
90
|
+
}
|
|
91
|
+
backSource = void 0;
|
|
92
|
+
previousBackAriaHidden = null;
|
|
93
|
+
for (const { projection, actions } of toolbarProjections) {
|
|
94
|
+
if (retire) retire(projection);
|
|
95
|
+
else projection.remove();
|
|
96
|
+
for (const { source, previousAriaHidden } of actions) {
|
|
97
|
+
source.removeAttribute(marker);
|
|
98
|
+
if (previousAriaHidden === null) source.removeAttribute("aria-hidden");
|
|
99
|
+
else source.setAttribute("aria-hidden", previousAriaHidden);
|
|
100
|
+
source.dispatchEvent(new CustomEvent("nativeUIChange"));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
toolbarProjections = [];
|
|
104
|
+
sourceObserver?.disconnect();
|
|
105
|
+
sourceObserver = void 0;
|
|
106
|
+
root?.classList.remove(readyClass);
|
|
107
|
+
root = void 0;
|
|
108
|
+
};
|
|
109
|
+
const copyAttributes = (target, original) => {
|
|
110
|
+
for (const name of [
|
|
111
|
+
"id",
|
|
112
|
+
"slot",
|
|
113
|
+
marker,
|
|
114
|
+
"aria-hidden"
|
|
115
|
+
]) target.removeAttribute(name);
|
|
116
|
+
for (const attribute of Array.from(target.attributes)) if (![
|
|
117
|
+
"class",
|
|
118
|
+
"data-native-ui-projected",
|
|
119
|
+
"data-native-ui-fading"
|
|
120
|
+
].includes(attribute.name) && !original.hasAttribute(attribute.name)) target.removeAttribute(attribute.name);
|
|
121
|
+
for (const attribute of Array.from(original.attributes)) if (![
|
|
122
|
+
"id",
|
|
123
|
+
"slot",
|
|
124
|
+
"data-native-ui-projected",
|
|
125
|
+
"aria-hidden"
|
|
126
|
+
].includes(attribute.name)) target.setAttribute(attribute.name, attribute.value);
|
|
127
|
+
target.classList.remove(prehiddenClass);
|
|
128
|
+
};
|
|
129
|
+
const syncBack = (target, original) => {
|
|
130
|
+
copyAttributes(target, original);
|
|
131
|
+
target.classList.add(backProjectionClass, "ion-cloned-element");
|
|
132
|
+
target.disabled = original.disabled;
|
|
133
|
+
target.defaultHref = original.defaultHref;
|
|
134
|
+
target.icon = original.icon;
|
|
135
|
+
target.color = original.color;
|
|
136
|
+
target.mode = original.mode;
|
|
137
|
+
target.text = "";
|
|
138
|
+
if (root) alignVerticalBarClone(target, original, root);
|
|
139
|
+
};
|
|
140
|
+
const syncAction = (target, original) => {
|
|
141
|
+
copyAttributes(target, original);
|
|
142
|
+
target.classList.add("ios-theme-vertical-bars-toolbar-action", "ion-cloned-element");
|
|
143
|
+
const label = original.getAttribute("aria-label") ?? original.shadowRoot?.querySelector("[part~=native]")?.getAttribute("aria-label") ?? original.textContent?.trim();
|
|
144
|
+
if (label) target.setAttribute("aria-label", label);
|
|
145
|
+
if ("disabled" in original) target.disabled = original.disabled;
|
|
146
|
+
if (original.matches("ion-button")) {
|
|
147
|
+
const clonedIcon = original.querySelector("ion-icon, svg")?.cloneNode(true);
|
|
148
|
+
clonedIcon?.setAttribute("slot", "icon-only");
|
|
149
|
+
target.replaceChildren(...clonedIcon ? [clonedIcon] : [document.createTextNode(original.textContent?.trim() || label || "")]);
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
const sameSources = (back, groups) => back === backSource && groups.length === toolbarProjections.length && groups.every(({ group, actions }, index) => {
|
|
153
|
+
const current = toolbarProjections[index];
|
|
154
|
+
return group === current.source && actions.length === current.actions.length && actions.every((action, actionIndex) => action === current.actions[actionIndex].source);
|
|
155
|
+
});
|
|
156
|
+
const syncExisting = () => {
|
|
157
|
+
if (backSource && backProjection) syncBack(backProjection, backSource);
|
|
158
|
+
let topOffset = backSource ? 56 : 0;
|
|
159
|
+
for (const { projection, source, actions } of toolbarProjections) {
|
|
160
|
+
if (actions.length === 1 && !projection.matches("ion-buttons")) syncAction(projection, actions[0].source);
|
|
161
|
+
else copyAttributes(projection, source);
|
|
162
|
+
projection.classList.add(toolbarProjectionClass, "ion-cloned-element");
|
|
163
|
+
projection.style.setProperty("--ios-theme-vertical-bars-toolbar-offset", `${topOffset}px`);
|
|
164
|
+
if (projection.matches("ion-buttons")) actions.forEach(({ source: action, projection: clone }) => syncAction(clone, action));
|
|
165
|
+
const frames = actions.map(({ source }) => verticalBarFrame(source));
|
|
166
|
+
if (root && frames.every((frame) => !!frame)) {
|
|
167
|
+
if (actions.length === 1) alignVerticalBarClone(projection, actions[0].source, root);
|
|
168
|
+
else {
|
|
169
|
+
const left = Math.min(...frames.map((frame) => frame.x));
|
|
170
|
+
const top = Math.min(...frames.map((frame) => frame.y));
|
|
171
|
+
const right = Math.max(...frames.map((frame) => frame.x + frame.width));
|
|
172
|
+
const bottom = Math.max(...frames.map((frame) => frame.y + frame.height));
|
|
173
|
+
const origin = root.getBoundingClientRect();
|
|
174
|
+
Object.assign(projection.style, {
|
|
175
|
+
left: `${left - origin.left}px`,
|
|
176
|
+
top: `${top - origin.top}px`,
|
|
177
|
+
right: "auto",
|
|
178
|
+
bottom: "auto",
|
|
179
|
+
width: `${right - left}px`,
|
|
180
|
+
height: `${bottom - top}px`,
|
|
181
|
+
padding: "0"
|
|
182
|
+
});
|
|
183
|
+
actions.forEach(({ source, projection: clone }) => alignVerticalBarClone(clone, source, projection));
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
topOffset += actions.length * toolbarControlSize + toolbarControlGap;
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
const project = (nextBack, groups) => {
|
|
190
|
+
root = topModal(doc) ?? verticalBarsRoot();
|
|
191
|
+
let topOffset = 0;
|
|
192
|
+
if (nextBack) {
|
|
193
|
+
backSource = nextBack;
|
|
194
|
+
previousBackAriaHidden = nextBack.getAttribute("aria-hidden");
|
|
195
|
+
backProjection = nextBack.cloneNode(false);
|
|
196
|
+
syncBack(backProjection, nextBack);
|
|
197
|
+
backProjection.addEventListener("click", (event) => {
|
|
198
|
+
event.preventDefault();
|
|
199
|
+
event.stopImmediatePropagation();
|
|
200
|
+
if (backSource && backSource === findBack()) activateProjectedElement(backSource);
|
|
201
|
+
}, { capture: true });
|
|
202
|
+
root.append(backProjection);
|
|
203
|
+
nextBack.setAttribute(marker, "");
|
|
204
|
+
nextBack.setAttribute("aria-hidden", "true");
|
|
205
|
+
nextBack.dispatchEvent(new CustomEvent("nativeUIChange"));
|
|
206
|
+
topOffset = 56;
|
|
207
|
+
}
|
|
208
|
+
for (const { group, actions: sources } of groups) {
|
|
209
|
+
const projection = (sources.length === 1 ? sources[0] : group).cloneNode(false);
|
|
210
|
+
if (sources.length === 1) syncAction(projection, sources[0]);
|
|
211
|
+
else copyAttributes(projection, group);
|
|
212
|
+
projection.classList.add(toolbarProjectionClass, "ion-cloned-element");
|
|
213
|
+
projection.style.setProperty("--ios-theme-vertical-bars-toolbar-offset", `${topOffset}px`);
|
|
214
|
+
const actions = sources.map((source) => {
|
|
215
|
+
const clone = sources.length === 1 ? projection : source.cloneNode(false);
|
|
216
|
+
if (sources.length > 1) syncAction(clone, source);
|
|
217
|
+
clone.addEventListener("click", (event) => {
|
|
218
|
+
event.preventDefault();
|
|
219
|
+
event.stopImmediatePropagation();
|
|
220
|
+
if (isCurrentToolbarAction(source)) activateProjectedElement(source);
|
|
221
|
+
}, { capture: true });
|
|
222
|
+
if (sources.length > 1) projection.append(clone);
|
|
223
|
+
const previousAriaHidden = source.getAttribute("aria-hidden");
|
|
224
|
+
source.setAttribute(marker, "");
|
|
225
|
+
source.setAttribute("aria-hidden", "true");
|
|
226
|
+
source.dispatchEvent(new CustomEvent("nativeUIChange"));
|
|
227
|
+
return {
|
|
228
|
+
source,
|
|
229
|
+
projection: clone,
|
|
230
|
+
previousAriaHidden
|
|
231
|
+
};
|
|
232
|
+
});
|
|
233
|
+
root.append(projection);
|
|
234
|
+
toolbarProjections.push({
|
|
235
|
+
source: group,
|
|
236
|
+
projection,
|
|
237
|
+
actions
|
|
238
|
+
});
|
|
239
|
+
topOffset += actions.length * toolbarControlSize + toolbarControlGap;
|
|
240
|
+
}
|
|
241
|
+
syncExisting();
|
|
242
|
+
if (nextBack || toolbarProjections.length) root.classList.add(readyClass);
|
|
243
|
+
sourceObserver = new MutationObserver((records) => {
|
|
244
|
+
if (records.some((record) => record.type !== "attributes" || !["data-native-ui-projected", "aria-hidden"].includes(record.attributeName ?? "") && !prehideOnlyMutation(record))) schedule();
|
|
245
|
+
});
|
|
246
|
+
if (nextBack?.shadowRoot) sourceObserver.observe(nextBack.shadowRoot, {
|
|
247
|
+
subtree: true,
|
|
248
|
+
childList: true,
|
|
249
|
+
attributes: true,
|
|
250
|
+
attributeOldValue: true
|
|
251
|
+
});
|
|
252
|
+
for (const { group } of groups) sourceObserver.observe(group, {
|
|
253
|
+
subtree: true,
|
|
254
|
+
childList: true,
|
|
255
|
+
attributes: true,
|
|
256
|
+
attributeOldValue: true
|
|
257
|
+
});
|
|
258
|
+
};
|
|
259
|
+
const reveal = () => {
|
|
260
|
+
if (incomingInstant === void 0) return;
|
|
261
|
+
for (const surface of [
|
|
262
|
+
backProjection,
|
|
263
|
+
...toolbarProjections.map(({ projection }) => projection),
|
|
264
|
+
search.surface
|
|
265
|
+
]) if (surface) crossfade.play(surface, false, incomingInstant);
|
|
266
|
+
incomingInstant = void 0;
|
|
267
|
+
};
|
|
268
|
+
const performUpdate = () => {
|
|
269
|
+
frame = 0;
|
|
270
|
+
syncToolbarText(doc);
|
|
271
|
+
const currentRoot = verticalBarsRoot();
|
|
272
|
+
if (observingVerticalBars !== !!currentRoot) {
|
|
273
|
+
observingVerticalBars = !!currentRoot;
|
|
274
|
+
observer.disconnect();
|
|
275
|
+
observer.observe(doc.documentElement, {
|
|
276
|
+
subtree: true,
|
|
277
|
+
childList: true,
|
|
278
|
+
characterData: observingVerticalBars,
|
|
279
|
+
attributes: true,
|
|
280
|
+
attributeOldValue: true,
|
|
281
|
+
attributeFilter: observingVerticalBars ? void 0 : ["class"]
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
if (stopped || suspended || !currentRoot || !enabled()) return restore();
|
|
285
|
+
const nextBack = toolbarEnabled ? findBack() : void 0;
|
|
286
|
+
const groups = toolbarEnabled ? findToolbarGroups() : [];
|
|
287
|
+
const projectionRoot = topModal(doc) ?? currentRoot;
|
|
288
|
+
search.update(projectionRoot);
|
|
289
|
+
if (!nextBack && !groups.length && !search.source) return restore();
|
|
290
|
+
if (root === (topModal(doc) ?? currentRoot) && sameSources(nextBack, groups)) {
|
|
291
|
+
syncExisting();
|
|
292
|
+
reveal();
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
restore();
|
|
296
|
+
project(nextBack, groups);
|
|
297
|
+
search.update(projectionRoot);
|
|
298
|
+
reveal();
|
|
299
|
+
updates++;
|
|
300
|
+
};
|
|
301
|
+
const update = () => {
|
|
302
|
+
try {
|
|
303
|
+
performUpdate();
|
|
304
|
+
} catch {
|
|
305
|
+
restore();
|
|
306
|
+
} finally {
|
|
307
|
+
const pending = waiters;
|
|
308
|
+
waiters = [];
|
|
309
|
+
pending.forEach((resolve) => resolve());
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
const schedule = () => {
|
|
313
|
+
if (stopped) return Promise.resolve();
|
|
314
|
+
if (!enabled()) restore();
|
|
315
|
+
const done = new Promise((resolve) => waiters.push(resolve));
|
|
316
|
+
if (!frame) frame = win.requestAnimationFrame(update);
|
|
317
|
+
return done;
|
|
318
|
+
};
|
|
319
|
+
const observer = new MutationObserver((records) => {
|
|
320
|
+
const insideProjection = (target) => {
|
|
321
|
+
const element = target instanceof Element ? target : target.parentNode instanceof Element ? target.parentNode : void 0;
|
|
322
|
+
const rootNode = target.getRootNode();
|
|
323
|
+
return !![element, rootNode instanceof ShadowRoot ? rootNode.host : void 0].some((candidate) => candidate?.closest(`.${backProjectionClass}, .${toolbarProjectionClass}, .${searchProjectionClass}`));
|
|
324
|
+
};
|
|
325
|
+
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"))));
|
|
326
|
+
if (observingVerticalBars && records.some((record) => record.attributeName !== "data-native-ui-projected" && record.attributeName !== "data-native-ui-toolbar-text" && !prehideOnlyMutation(record) && !insideProjection(record.target)) || !observingVerticalBars && verticalBarsChanged && records.some((record) => !prehideOnlyMutation(record))) schedule();
|
|
327
|
+
});
|
|
328
|
+
observer.observe(doc.documentElement, {
|
|
329
|
+
subtree: true,
|
|
330
|
+
childList: true,
|
|
331
|
+
attributes: true,
|
|
332
|
+
attributeOldValue: true,
|
|
333
|
+
attributeFilter: ["class"]
|
|
334
|
+
});
|
|
335
|
+
const pageLifecycle = (event) => {
|
|
336
|
+
const page = event.target;
|
|
337
|
+
if (!(page instanceof HTMLElement) || !page.matches(".ion-page")) return;
|
|
338
|
+
if (event.type === "iosThemeVerticalBarsTransitionCanceled") {
|
|
339
|
+
const entering = event.detail?.entering;
|
|
340
|
+
verticalBarsPages.cancel(entering, page);
|
|
341
|
+
} else verticalBarsPages.lifecycle(event);
|
|
342
|
+
if (verticalBarsRoot()) schedule();
|
|
343
|
+
};
|
|
344
|
+
for (const name of [
|
|
345
|
+
"ionViewWillEnter",
|
|
346
|
+
"ionViewWillLeave",
|
|
347
|
+
"ionViewDidEnter",
|
|
348
|
+
"ionViewDidLeave"
|
|
349
|
+
]) doc.addEventListener(name, pageLifecycle, {
|
|
350
|
+
capture: true,
|
|
351
|
+
signal: listeners.signal
|
|
352
|
+
});
|
|
353
|
+
doc.addEventListener(VERTICAL_BARS_TRANSITION_CANCELED, pageLifecycle, {
|
|
354
|
+
capture: true,
|
|
355
|
+
signal: listeners.signal
|
|
356
|
+
});
|
|
357
|
+
for (const name of ["ionModalWillPresent", "ionModalDidDismiss"]) doc.addEventListener(name, schedule, {
|
|
358
|
+
capture: true,
|
|
359
|
+
signal: listeners.signal
|
|
360
|
+
});
|
|
361
|
+
win.addEventListener("nativeUIVerticalBarsAcquire", (event) => {
|
|
362
|
+
const instant = event.detail?.instant ?? true;
|
|
363
|
+
incomingInstant = void 0;
|
|
364
|
+
restore((surface) => {
|
|
365
|
+
const box = surface.getBoundingClientRect();
|
|
366
|
+
surface.style.setProperty("position", "fixed", "important");
|
|
367
|
+
surface.style.setProperty("display", "block", "important");
|
|
368
|
+
surface.style.setProperty("left", `${box.left}px`, "important");
|
|
369
|
+
surface.style.setProperty("top", `${box.top}px`, "important");
|
|
370
|
+
surface.style.setProperty("right", "auto", "important");
|
|
371
|
+
surface.style.setProperty("bottom", "auto", "important");
|
|
372
|
+
surface.style.setProperty("width", `${box.width}px`, "important");
|
|
373
|
+
surface.style.setProperty("height", `${box.height}px`, "important");
|
|
374
|
+
crossfade.retire(surface, instant);
|
|
375
|
+
});
|
|
376
|
+
}, { signal: listeners.signal });
|
|
377
|
+
win.addEventListener("nativeUIVerticalBarsRelease", (event) => {
|
|
378
|
+
incomingInstant = event.detail.instant;
|
|
379
|
+
schedule();
|
|
380
|
+
}, { signal: listeners.signal });
|
|
381
|
+
win.addEventListener("resize", schedule, { signal: listeners.signal });
|
|
382
|
+
win.addEventListener("nativeUIRefresh", schedule, { signal: listeners.signal });
|
|
383
|
+
schedule();
|
|
384
|
+
return {
|
|
385
|
+
markForCheck: () => {
|
|
386
|
+
schedule();
|
|
387
|
+
},
|
|
388
|
+
getStatus: () => ({
|
|
389
|
+
state: stopped ? "stopped" : "web",
|
|
390
|
+
projected: Number(!!backSource) + Number(!!search.source) + toolbarProjections.reduce((count, group) => count + group.actions.length, 0),
|
|
391
|
+
updates
|
|
392
|
+
}),
|
|
393
|
+
async suspend() {
|
|
394
|
+
suspended++;
|
|
395
|
+
restore();
|
|
396
|
+
let resumed = false;
|
|
397
|
+
return { async resume() {
|
|
398
|
+
if (resumed) return;
|
|
399
|
+
resumed = true;
|
|
400
|
+
suspended = Math.max(0, suspended - 1);
|
|
401
|
+
if (!suspended) await schedule();
|
|
402
|
+
} };
|
|
403
|
+
},
|
|
404
|
+
async destroy() {
|
|
405
|
+
if (stopped) return;
|
|
406
|
+
stopped = true;
|
|
407
|
+
win.cancelAnimationFrame(frame);
|
|
408
|
+
frame = 0;
|
|
409
|
+
waiters.forEach((resolve) => resolve());
|
|
410
|
+
waiters = [];
|
|
411
|
+
observer.disconnect();
|
|
412
|
+
sourceObserver?.disconnect();
|
|
413
|
+
listeners.abort();
|
|
414
|
+
crossfade.destroy();
|
|
415
|
+
restore();
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
};
|
|
419
|
+
//#endregion
|
|
420
|
+
export { createVerticalBarsWebProjection };
|
|
421
|
+
|
|
422
|
+
//# sourceMappingURL=vertical-bars-web.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vertical-bars-web.js","names":[],"sources":["../../src/native/vertical-bars-web.ts"],"sourcesContent":["import { controlSelected } from './shared/control-options';\nimport { createCrossfade, fadeMarker } from './shared/crossfade';\nimport { alignVerticalBarClone, verticalBarFrame } from './shared/vertical-bars-geometry';\nimport { createVerticalBarsWebSearch, searchProjectionClass } from './vertical-bars-web-search';\nimport { inVerticalBarsSurface, topModal } from './shared/modal';\nimport type { NativeUIRuntimeHandle, NativeUIOptions, NativeUIStatus } 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 isNativeUIDisabled,\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: HTMLElement;\n projection: HTMLElement;\n actions: { source: HTMLElement; projection: HTMLElement; previousAriaHidden: string | null }[];\n}\n\ninterface ToolbarSource {\n group: HTMLElement;\n actions: HTMLElement[];\n}\n\nexport const createVerticalBarsWebProjection = (\n doc: Document,\n options: NativeUIOptions,\n enabled: () => boolean = () => true,\n): NativeUIRuntimeHandle => {\n const win = doc.defaultView!;\n const crossfade = createCrossfade(win);\n let incomingInstant: boolean | undefined;\n const toolbarEnabled = options.ionic?.auto !== false;\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.ionic?.auto !== false &&\n controlSelected(element, options, 'tabs', true) &&\n !!verticalBarsRoot()?.contains(element) &&\n (!options.root || options.root.contains(element)) &&\n !element.closest('[data-native-ui-placement=\"element\"]') &&\n inVerticalBarsSurface(element) &&\n !isExcluded(element, verticalBarsEnteringPage(element)) &&\n !isNativeUIDisabled(element) &&\n !verticalBarsPages.isDeparted(element) &&\n isRendered(element),\n () => {\n void schedule();\n },\n );\n const inEligibleToolbar = (element: HTMLElement) =>\n !!verticalBarsRoot()?.contains(element) &&\n (!options.root || options.root.contains(element)) &&\n !element.closest('[data-native-ui-placement=\"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 (!options.root || options.root.contains(element)) &&\n !element.closest('[data-native-ui-placement=\"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 for (const action of Array.from(doc.querySelectorAll<HTMLElement>('ion-button, ion-menu-button'))) {\n if (action.closest('ion-buttons') || !verticalBarsOwned(action) || !inEligibleToolbar(action)) continue;\n if (unprojected(projectedSources(), () => isRendered(action))) candidates.push({ group: action, actions: [action] });\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 = (retire?: (surface: HTMLElement) => void) => {\n search.restore(retire);\n if (backProjection) {\n if (retire) retire(backProjection);\n else backProjection.remove();\n }\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('nativeUIChange'));\n }\n backSource = undefined;\n previousBackAriaHidden = null;\n for (const { projection, actions } of toolbarProjections) {\n if (retire) retire(projection);\n else 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('nativeUIChange'));\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, fadeMarker].includes(attribute.name) && !original.hasAttribute(attribute.name))\n 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 if (root) alignVerticalBarClone(target, original, root);\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] : [document.createTextNode(original.textContent?.trim() || label || '')]));\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 const frames = actions.map(({ source }) => verticalBarFrame(source));\n if (root && frames.every((frame) => !!frame)) {\n if (actions.length === 1) alignVerticalBarClone(projection, actions[0].source, root);\n else {\n const left = Math.min(...frames.map((frame) => frame!.x));\n const top = Math.min(...frames.map((frame) => frame!.y));\n const right = Math.max(...frames.map((frame) => frame!.x + frame!.width));\n const bottom = Math.max(...frames.map((frame) => frame!.y + frame!.height));\n const origin = root.getBoundingClientRect();\n Object.assign(projection.style, {\n left: `${left - origin.left}px`,\n top: `${top - origin.top}px`,\n right: 'auto',\n bottom: 'auto',\n width: `${right - left}px`,\n height: `${bottom - top}px`,\n padding: '0',\n });\n actions.forEach(({ source, projection: clone }) => alignVerticalBarClone(clone, source, projection));\n }\n }\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('nativeUIChange'));\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('nativeUIChange'));\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 syncExisting();\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 reveal = () => {\n if (incomingInstant === undefined) return;\n for (const surface of [backProjection, ...toolbarProjections.map(({ projection }) => projection), search.surface])\n if (surface) crossfade.play(surface, false, incomingInstant);\n incomingInstant = undefined;\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)) {\n syncExisting();\n reveal();\n return;\n }\n restore();\n project(nextBack, groups);\n search.update(projectionRoot);\n reveal();\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(\n 'nativeUIVerticalBarsAcquire',\n (event) => {\n const instant = (event as CustomEvent<{ instant: boolean }>).detail?.instant ?? true;\n incomingInstant = undefined;\n restore((surface) => {\n // Keep only the outgoing visual at its last rectangle after Web ownership\n // is released. The native acknowledgement transfers input exactly once.\n const box = surface.getBoundingClientRect();\n surface.style.setProperty('position', 'fixed', 'important');\n surface.style.setProperty('display', 'block', 'important');\n surface.style.setProperty('left', `${box.left}px`, 'important');\n surface.style.setProperty('top', `${box.top}px`, 'important');\n surface.style.setProperty('right', 'auto', 'important');\n surface.style.setProperty('bottom', 'auto', 'important');\n surface.style.setProperty('width', `${box.width}px`, 'important');\n surface.style.setProperty('height', `${box.height}px`, 'important');\n crossfade.retire(surface, instant);\n });\n },\n { signal: listeners.signal },\n );\n win.addEventListener(\n 'nativeUIVerticalBarsRelease',\n (event) => {\n incomingInstant = (event as CustomEvent<{ instant: boolean }>).detail.instant;\n void schedule();\n },\n { signal: listeners.signal },\n );\n win.addEventListener('resize', schedule, { signal: listeners.signal });\n win.addEventListener('nativeUIRefresh', schedule, { signal: listeners.signal });\n schedule();\n\n return {\n markForCheck: () => {\n void schedule();\n },\n getStatus: (): NativeUIStatus => ({\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 crossfade.destroy();\n restore();\n },\n };\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//#region src/native-integration/index.d.ts
|
|
2
|
+
export interface NativeUIIntegration {
|
|
3
|
+
suspend(scopes: HTMLElement[]): Promise<(canceled?: boolean) => void>;
|
|
4
|
+
search?(binding: NativeSearchBinding, active: boolean, focus?: boolean): Promise<boolean>;
|
|
5
|
+
}
|
|
6
|
+
export interface NativeSearchBinding {
|
|
7
|
+
tabBar: HTMLElement;
|
|
8
|
+
trigger: HTMLElement;
|
|
9
|
+
footer: HTMLElement;
|
|
10
|
+
active: boolean;
|
|
11
|
+
focused: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare const registerNativeSearch: (tabBar: HTMLElement, trigger: HTMLElement, footer: HTMLElement) => NativeSearchBinding;
|
|
14
|
+
export declare const getNativeSearchBindings: (doc: Document) => NativeSearchBinding[];
|
|
15
|
+
export declare const requestNativeSearch: (binding: NativeSearchBinding, active: boolean, focus?: boolean) => Promise<boolean>;
|
|
16
|
+
export declare const VERTICAL_BARS_TRANSITION_CANCELED = "iosThemeVerticalBarsTransitionCanceled";
|
|
17
|
+
export declare const setNativeUIIntegration: (doc: Document, runtime?: NativeUIIntegration) => void;
|
|
18
|
+
export declare const hasNativeUIIntegration: (doc: Document) => boolean;
|
|
19
|
+
export declare const isNativeUI: (element: HTMLElement) => boolean;
|
|
20
|
+
export declare const suspendNativeUI: (scopes: HTMLElement[]) => Promise<(canceled?: boolean) => void>;
|
|
21
|
+
export declare const nativeWebViewMetrics: {
|
|
22
|
+
radius: number;
|
|
23
|
+
};
|
|
24
|
+
//#endregion
|
|
25
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/native-integration/index.ts"],"mappings":";iBAEiB;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,yBAA0B,KAAK,UAAU,UAAU;qBAKnD,yBAA0B,KAAK;qBAE/B,aAAc,SAAS;qBAEvB,kBAAyB,QAAQ,kBAAgB,SAAS;qBAI1D;EAAA"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/native-integration/index.ts
|
|
2
|
+
const searches = /* @__PURE__ */ new WeakMap();
|
|
3
|
+
const registerNativeSearch = (tabBar, trigger, footer) => {
|
|
4
|
+
const binding = {
|
|
5
|
+
tabBar,
|
|
6
|
+
trigger,
|
|
7
|
+
footer,
|
|
8
|
+
active: false,
|
|
9
|
+
focused: false
|
|
10
|
+
};
|
|
11
|
+
const entries = (searches.get(tabBar.ownerDocument) ?? []).filter((entry) => entry.deref() && entry.deref()?.footer !== footer);
|
|
12
|
+
entries.push(new WeakRef(binding));
|
|
13
|
+
searches.set(tabBar.ownerDocument, entries);
|
|
14
|
+
tabBar.ownerDocument.defaultView?.dispatchEvent(new Event("nativeUIRefresh"));
|
|
15
|
+
return binding;
|
|
16
|
+
};
|
|
17
|
+
const getNativeSearchBindings = (doc) => (searches.get(doc) ?? []).flatMap((entry) => entry.deref() ?? []);
|
|
18
|
+
const requestNativeSearch = async (binding, active, focus) => await runtimes.get(binding.tabBar.ownerDocument)?.search?.(binding, active, focus) ?? false;
|
|
19
|
+
const runtimes = /* @__PURE__ */ new WeakMap();
|
|
20
|
+
const VERTICAL_BARS_TRANSITION_CANCELED = "iosThemeVerticalBarsTransitionCanceled";
|
|
21
|
+
const setNativeUIIntegration = (doc, runtime) => {
|
|
22
|
+
if (runtime) runtimes.set(doc, runtime);
|
|
23
|
+
else runtimes.delete(doc);
|
|
24
|
+
};
|
|
25
|
+
const hasNativeUIIntegration = (doc) => runtimes.has(doc);
|
|
26
|
+
const isNativeUI = (element) => element.hasAttribute("data-native-ui-projected");
|
|
27
|
+
const suspendNativeUI = async (scopes) => await runtimes.get(scopes[0]?.ownerDocument)?.suspend(scopes) ?? (() => {});
|
|
28
|
+
/** Shared geometry used by the theme's transition adapter; no theme import in the plugin. */
|
|
29
|
+
const nativeWebViewMetrics = { radius: 0 };
|
|
30
|
+
//#endregion
|
|
31
|
+
export { VERTICAL_BARS_TRANSITION_CANCELED, getNativeSearchBindings, hasNativeUIIntegration, isNativeUI, nativeWebViewMetrics, registerNativeSearch, requestNativeSearch, setNativeUIIntegration, suspendNativeUI };
|
|
32
|
+
|
|
33
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/native-integration/index.ts"],"sourcesContent":["/// <reference lib=\"es2021.weakref\" />\n\nexport interface NativeUIIntegration {\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('nativeUIRefresh'));\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, NativeUIIntegration>();\nexport const VERTICAL_BARS_TRANSITION_CANCELED = 'iosThemeVerticalBarsTransitionCanceled';\n\nexport const setNativeUIIntegration = (doc: Document, runtime?: NativeUIIntegration) => {\n if (runtime) runtimes.set(doc, runtime);\n else runtimes.delete(doc);\n};\n\nexport const hasNativeUIIntegration = (doc: Document): boolean => runtimes.has(doc);\n\nexport const isNativeUI = (element: HTMLElement) => element.hasAttribute('data-native-ui-projected');\n\nexport const suspendNativeUI = async (scopes: HTMLElement[]): Promise<(canceled?: boolean) => void> =>\n (await runtimes.get(scopes[0]?.ownerDocument)?.suspend(scopes)) ?? (() => {});\n\n/** Shared geometry used by the theme's transition adapter; no theme import in the plugin. */\nexport const nativeWebViewMetrics = { radius: 0 };\n"],"mappings":";AAeA,MAAM,2BAAW,IAAI,QAAkD;AAEvE,MAAa,wBAAwB,QAAqB,SAAsB,WAA6C;CAC3H,MAAM,UAAU;EAAE;EAAQ;EAAS;EAAQ,QAAQ;EAAO,SAAS;CAAM;CACzE,MAAM,WAAW,SAAS,IAAI,OAAO,aAAa,KAAK,CAAC,EAAA,CAAG,QAAQ,UAAU,MAAM,MAAM,KAAK,MAAM,MAAM,CAAC,EAAE,WAAW,MAAM;CAC9H,QAAQ,KAAK,IAAI,QAAQ,OAAO,CAAC;CACjC,SAAS,IAAI,OAAO,eAAe,OAAO;CAC1C,OAAO,cAAc,aAAa,cAAc,IAAI,MAAM,iBAAiB,CAAC;CAC5E,OAAO;AACT;AAEA,MAAa,2BAA2B,SACrC,SAAS,IAAI,GAAG,KAAK,CAAC,EAAA,CAAG,SAAS,UAAU,MAAM,MAAM,KAAK,CAAC,CAAC;AAElE,MAAa,sBAAsB,OAAO,SAA8B,QAAiB,UACtF,MAAM,SAAS,IAAI,QAAQ,OAAO,aAAa,CAAC,EAAE,SAAS,SAAS,QAAQ,KAAK,KAAM;AAE1F,MAAM,2BAAW,IAAI,QAAuC;AAC5D,MAAa,oCAAoC;AAEjD,MAAa,0BAA0B,KAAe,YAAkC;CACtF,IAAI,SAAS,SAAS,IAAI,KAAK,OAAO;MACjC,SAAS,OAAO,GAAG;AAC1B;AAEA,MAAa,0BAA0B,QAA2B,SAAS,IAAI,GAAG;AAElF,MAAa,cAAc,YAAyB,QAAQ,aAAa,0BAA0B;AAEnG,MAAa,kBAAkB,OAAO,WACnC,MAAM,SAAS,IAAI,OAAO,EAAE,EAAE,aAAa,CAAC,EAAE,QAAQ,MAAM,YAAa,CAAC;;AAG7E,MAAa,uBAAuB,EAAE,QAAQ,EAAE"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ControlProjection, NativeUIControls, NativeUIStatus, NativeUISuspension, VerticalBarEdge, VerticalControlAreaHandle, VerticalControlAreaOptions } from "./native/definitions.js";
|
|
2
|
+
import { NativeUI } from "./native/activation.js";
|
|
3
|
+
import { applyFoldStateClasses } from "./native/foldable/fold-state.js";
|
|
4
|
+
import { setVerticalControlAreaPlacement } from "./native/legacy-layout.js";
|
|
5
|
+
import { enableVerticalControlArea } from "./native/index.js";
|
|
6
|
+
export { type ControlProjection, NativeUI, type NativeUIControls, type NativeUIStatus, type NativeUISuspension, type VerticalBarEdge, type VerticalControlAreaHandle, type VerticalControlAreaOptions, applyFoldStateClasses, enableVerticalControlArea, setVerticalControlAreaPlacement };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { NativeUI } from "./native/activation.js";
|
|
2
|
+
import { setVerticalControlAreaPlacement } from "./native/legacy-layout.js";
|
|
3
|
+
import { enableVerticalControlArea } from "./native/index.js";
|
|
4
|
+
import { applyFoldStateClasses } from "./native/foldable/fold-state.js";
|
|
5
|
+
export { NativeUI, applyFoldStateClasses, enableVerticalControlArea, setVerticalControlAreaPlacement };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Light and dark appearance
|
|
2
|
+
|
|
3
|
+
Native UI reads the computed style of each projected source element and sends its light/dark appearance to the native renderer. Configure appearance in your Web CSS; there is no separate native dark-mode startup option.
|
|
4
|
+
|
|
5
|
+
## How appearance is resolved
|
|
6
|
+
|
|
7
|
+
The first applicable row wins:
|
|
8
|
+
|
|
9
|
+
| Priority | Computed source style | Result |
|
|
10
|
+
| -------- | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
11
|
+
| 1 | Theme-provided `--ios27-color-scheme` is non-empty | `dark` selects dark; other values select light. The iOS 27 theme supplies this marker through its light and dark stylesheets. |
|
|
12
|
+
| 2 | `--ion-background-color-rgb` supplies three RGB channels | Infers dark or light from the background brightness. |
|
|
13
|
+
| 3 | CSS `color-scheme` contains only `dark` or only `light` | Uses that scheme. `light dark` does not select a single appearance. |
|
|
14
|
+
| 4 | None of the above | Uses the system's `prefers-color-scheme: dark` setting. |
|
|
15
|
+
|
|
16
|
+
Theme markers and Ionic background values take precedence over `color-scheme`. Changing only an arbitrary CSS background or text color does not select native light/dark appearance.
|
|
17
|
+
|
|
18
|
+
## Match your Web theme
|
|
19
|
+
|
|
20
|
+
| Web setup | What to configure |
|
|
21
|
+
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
22
|
+
| iOS 27 theme | Load the matching [System, Class or Always dark-mode pair](../../theme-ios27/docs/setup.md#choose-one-dark-mode-pair). The theme supplies the appearance marker. |
|
|
23
|
+
| Ionic with an existing theme | Keep `--ion-background-color-rgb` consistent with the active palette; native appearance uses it when no theme marker is present. |
|
|
24
|
+
| HTML without those theme variables | Set `color-scheme: light` or `color-scheme: dark` to match the active Web theme. |
|
|
25
|
+
| System-managed HTML appearance | Use system-responsive CSS; when no single scheme is selected, native appearance falls back to the system setting. |
|
|
26
|
+
|
|
27
|
+
For example, a plain HTML app with a manual dark-mode class can declare:
|
|
28
|
+
|
|
29
|
+
```css
|
|
30
|
+
:root {
|
|
31
|
+
color-scheme: light;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
:root.app-dark {
|
|
35
|
+
color-scheme: dark;
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Use the same class for your application's dark palette. This example assumes neither of the higher-priority theme variables is supplied. Class/style mutations and system appearance changes trigger re-evaluation while the runtime is active. For style changes without an observed DOM mutation, call `shell.markForCheck()` after applying them.
|
|
40
|
+
|
|
41
|
+
## Shared Vertical Bars appearance
|
|
42
|
+
|
|
43
|
+
Ordinary controls resolve appearance from their own source styles. Vertical Bars shares one native rail appearance: **if any projected control is dark, the whole rail uses dark appearance**. It does not render separate light and dark rail regions. Keep sources projected into the same rail on a consistent Web palette.
|
|
44
|
+
|
|
45
|
+
Native light/dark appearance selects the system material and control appearance; it does not reproduce arbitrary application CSS. Vertical button fill and tint remain governed by the separate [button appearance settings](vertical-bars.md#choose-button-appearance).
|