@rdlabo/ionic-theme-ios27 1.2.0 → 1.2.1-beta.pr273.shae866fb1dca9f
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/dist/css/components/ion-button.css +1 -1
- 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/native/components/index.js +2 -2
- package/dist/native/components/index.js.map +1 -1
- package/dist/native/definitions.d.ts +32 -0
- package/dist/native/definitions.d.ts.map +1 -1
- package/dist/native/index.d.ts.map +1 -1
- package/dist/native/index.js +23 -6
- package/dist/native/index.js.map +1 -1
- 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 +266 -0
- package/dist/native/overlays/controller.js.map +1 -0
- package/dist/native/overlays/dialog-animation.d.ts +8 -0
- package/dist/native/overlays/dialog-animation.d.ts.map +1 -0
- package/dist/native/overlays/dialog-animation.js +31 -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 +11 -0
- package/dist/native/overlays/popover.d.ts.map +1 -0
- package/dist/native/overlays/popover.js +78 -0
- package/dist/native/overlays/popover.js.map +1 -0
- package/dist/native/overlays/styles.d.ts +9 -0
- package/dist/native/overlays/styles.d.ts.map +1 -0
- package/dist/native/overlays/styles.js +82 -0
- package/dist/native/overlays/styles.js.map +1 -0
- package/dist/native/prehide.d.ts.map +1 -1
- package/dist/native/prehide.js +6 -2
- package/dist/native/prehide.js.map +1 -1
- package/dist/native/runtime.d.ts +4 -1
- package/dist/native/runtime.d.ts.map +1 -1
- package/dist/native/runtime.js +29 -8
- package/dist/native/runtime.js.map +1 -1
- package/dist/native/shared/dom.d.ts +2 -0
- package/dist/native/shared/dom.d.ts.map +1 -1
- package/dist/native/shared/dom.js +5 -1
- package/dist/native/shared/dom.js.map +1 -1
- 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/vertical-bars-web.d.ts.map +1 -1
- package/dist/native/vertical-bars-web.js +4 -2
- package/dist/native/vertical-bars-web.js.map +1 -1
- package/dist/native-integration/index.d.ts +1 -1
- package/dist/native-integration/index.js.map +1 -1
- package/dist/native-integration/transition.d.ts +1 -1
- package/dist/native-integration/transition.js.map +1 -1
- package/dist/sheets-of-glass/animations.d.ts +1 -1
- package/dist/sheets-of-glass/animations.js +1 -1
- package/dist/sheets-of-glass/animations.js.map +1 -1
- package/dist/sheets-of-glass/index.js +1 -1
- package/dist/sheets-of-glass/index.js.map +1 -1
- package/dist/tab-bar-searchable/animations/enter.d.ts +1 -1
- package/dist/tab-bar-searchable/animations/enter.d.ts.map +1 -1
- package/dist/tab-bar-searchable/animations/enter.js +1 -1
- package/dist/tab-bar-searchable/animations/enter.js.map +1 -1
- package/dist/tab-bar-searchable/animations/leave.d.ts +1 -1
- package/dist/tab-bar-searchable/animations/leave.d.ts.map +1 -1
- package/dist/tab-bar-searchable/animations/leave.js +1 -1
- package/dist/tab-bar-searchable/animations/leave.js.map +1 -1
- package/dist/tab-bar-searchable/index.js +1 -1
- package/dist/tab-bar-searchable/index.js.map +1 -1
- package/dist/transition/index.d.ts +1 -1
- package/dist/transition/index.js +1 -1
- package/dist/transition/index.js.map +1 -1
- package/dist/transition/ios.transition.d.ts +1 -1
- package/dist/transition/ios.transition.js.map +1 -1
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js.map +1 -1
- package/docs/native-ui-shell.md +20 -4
- package/docs/vertical-bars.md +3 -1
- package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellSearchController.swift +65 -91
- package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellTabBar.swift +9 -3
- package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellVerticalBars.swift +79 -3
- package/ios/Sources/IonicNativeUIShellPlugin/IonicNativeUIShellPlugin.swift +57 -1
- package/ios/Sources/IonicNativeUIShellPlugin/Overlays/ShellOverlayController.swift +116 -0
- package/ios/Sources/IonicNativeUIShellPlugin/Overlays/ShellOverlayHost.swift +36 -0
- package/ios/Tests/IonicNativeUIShellPluginTests/ShellSnapshotTests.swift +27 -0
- package/package.json +2 -2
- package/src/native/components/index.ts +3 -2
- package/src/native/definitions.ts +27 -1
- package/src/native/index.ts +23 -6
- package/src/native/overlays/content.ts +51 -0
- package/src/native/overlays/controller.ts +322 -0
- package/src/native/overlays/dialog-animation.ts +30 -0
- package/src/native/overlays/dismiss-animation.ts +15 -0
- package/src/native/overlays/focus.ts +64 -0
- package/src/native/overlays/popover.ts +80 -0
- package/src/native/overlays/styles.ts +80 -0
- package/src/native/prehide.ts +6 -1
- package/src/native/runtime.ts +39 -15
- package/src/native/shared/dom.ts +14 -0
- package/src/native/shared/projection-id.ts +2 -0
- package/src/native/vertical-bars-web.ts +11 -1
- package/src/native-integration/index.ts +1 -1
- package/src/native-integration/transition.ts +1 -1
- package/src/sheets-of-glass/animations.ts +2 -2
- package/src/sheets-of-glass/index.ts +2 -2
- package/src/styles/components/ion-button.scss +47 -0
- package/src/styles/components/ion-toolbar.scss +62 -7
- package/src/styles/vertical-bars.scss +23 -0
- package/src/tab-bar-searchable/animations/enter.ts +2 -1
- package/src/tab-bar-searchable/animations/leave.ts +2 -1
- package/src/tab-bar-searchable/index.ts +1 -1
- package/src/transition/index.ts +3 -3
- package/src/transition/ios.transition.ts +1 -1
- package/src/utils.ts +1 -1
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
//#region src/native/overlays/styles.ts
|
|
2
|
+
const sheetText = (sheets) => sheets.flatMap((sheet) => Array.from(sheet.cssRules, (rule) => rule.cssText)).join("\n");
|
|
3
|
+
const relayStyles = (source, destination, overlay) => {
|
|
4
|
+
const base = destination.createElement("base");
|
|
5
|
+
base.href = source.baseURI;
|
|
6
|
+
destination.head.append(base);
|
|
7
|
+
const copies = /* @__PURE__ */ new Map();
|
|
8
|
+
const sheets = destination.createElement("style");
|
|
9
|
+
destination.head.append(sheets);
|
|
10
|
+
const sync = () => {
|
|
11
|
+
sheets.textContent = sheetText(source.adoptedStyleSheets);
|
|
12
|
+
const sources = Array.from(source.querySelectorAll("meta[name=viewport],link[rel=stylesheet],style:not([data-overlay-relay-local])"));
|
|
13
|
+
for (const [node, copy] of copies) if (!sources.includes(node)) {
|
|
14
|
+
copy.remove();
|
|
15
|
+
copies.delete(node);
|
|
16
|
+
}
|
|
17
|
+
for (const node of sources) {
|
|
18
|
+
let copy = copies.get(node);
|
|
19
|
+
if (!copy) {
|
|
20
|
+
copy = node.cloneNode(true);
|
|
21
|
+
copies.set(node, copy);
|
|
22
|
+
} else {
|
|
23
|
+
for (const attribute of Array.from(copy.attributes)) copy.removeAttribute(attribute.name);
|
|
24
|
+
for (const attribute of Array.from(node.attributes)) copy.setAttribute(attribute.name, attribute.value);
|
|
25
|
+
copy.textContent = node.textContent;
|
|
26
|
+
}
|
|
27
|
+
destination.head.append(copy);
|
|
28
|
+
}
|
|
29
|
+
destination.head.append(surface);
|
|
30
|
+
};
|
|
31
|
+
const surface = destination.createElement("style");
|
|
32
|
+
surface.textContent = "html,body{background:transparent!important}";
|
|
33
|
+
const observers = [];
|
|
34
|
+
const mirror = (node, target, flatten = false) => {
|
|
35
|
+
const update = () => {
|
|
36
|
+
for (const attribute of Array.from(target.attributes)) if (!node.hasAttribute(attribute.name)) target.removeAttribute(attribute.name);
|
|
37
|
+
for (const attribute of Array.from(node.attributes)) target.setAttribute(attribute.name, attribute.value);
|
|
38
|
+
if (target.localName === "ion-app") target.classList.remove("ios-theme-vertical-bars");
|
|
39
|
+
if (flatten) target.style.setProperty("display", "contents", "important");
|
|
40
|
+
};
|
|
41
|
+
update();
|
|
42
|
+
const observer = new MutationObserver(update);
|
|
43
|
+
observer.observe(node, { attributes: true });
|
|
44
|
+
observers.push(observer);
|
|
45
|
+
};
|
|
46
|
+
mirror(source.documentElement, destination.documentElement);
|
|
47
|
+
mirror(source.body, destination.body);
|
|
48
|
+
const ancestors = [];
|
|
49
|
+
for (let node = overlay.parentElement; node && node !== source.body; node = node.parentElement) ancestors.unshift(node);
|
|
50
|
+
let parent = destination.body;
|
|
51
|
+
for (const node of ancestors) {
|
|
52
|
+
const shell = destination.createElement(node.localName);
|
|
53
|
+
mirror(node, shell, true);
|
|
54
|
+
parent.append(shell);
|
|
55
|
+
parent = shell;
|
|
56
|
+
}
|
|
57
|
+
sync();
|
|
58
|
+
const ready = Promise.all(Array.from(destination.querySelectorAll("link[rel=stylesheet]"), (link) => {
|
|
59
|
+
if (link.sheet) return Promise.resolve();
|
|
60
|
+
return new Promise((resolve, reject) => {
|
|
61
|
+
link.addEventListener("load", () => resolve(), { once: true });
|
|
62
|
+
link.addEventListener("error", () => reject(/* @__PURE__ */ new Error("Popover stylesheet unavailable")), { once: true });
|
|
63
|
+
});
|
|
64
|
+
})).then(() => void 0);
|
|
65
|
+
const observer = new MutationObserver(sync);
|
|
66
|
+
observer.observe(source.head, {
|
|
67
|
+
subtree: true,
|
|
68
|
+
childList: true,
|
|
69
|
+
characterData: true,
|
|
70
|
+
attributes: true
|
|
71
|
+
});
|
|
72
|
+
observers.push(observer);
|
|
73
|
+
return {
|
|
74
|
+
destination: parent,
|
|
75
|
+
ready,
|
|
76
|
+
stop: () => observers.forEach((item) => item.disconnect())
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
//#endregion
|
|
80
|
+
export { relayStyles, sheetText };
|
|
81
|
+
|
|
82
|
+
//# sourceMappingURL=styles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.js","names":[],"sources":["../../../src/native/overlays/styles.ts"],"sourcesContent":["export const sheetText = (sheets: readonly CSSStyleSheet[]): string =>\n sheets.flatMap((sheet) => Array.from(sheet.cssRules, (rule) => rule.cssText)).join('\\n');\n\nexport const relayStyles = (\n source: Document,\n destination: Document,\n overlay: HTMLElement,\n): { destination: HTMLElement; ready: Promise<void>; stop: () => void } => {\n const base = destination.createElement('base');\n base.href = source.baseURI;\n destination.head.append(base);\n const copies = new Map<Element, Element>();\n const sheets = destination.createElement('style');\n destination.head.append(sheets);\n const sync = () => {\n sheets.textContent = sheetText(source.adoptedStyleSheets);\n const sources = Array.from(source.querySelectorAll('meta[name=viewport],link[rel=stylesheet],style:not([data-overlay-relay-local])'));\n for (const [node, copy] of copies)\n if (!sources.includes(node)) {\n copy.remove();\n copies.delete(node);\n }\n for (const node of sources) {\n let copy = copies.get(node);\n if (!copy) {\n copy = node.cloneNode(true) as Element;\n copies.set(node, copy);\n } else {\n for (const attribute of Array.from(copy.attributes)) copy.removeAttribute(attribute.name);\n for (const attribute of Array.from(node.attributes)) copy.setAttribute(attribute.name, attribute.value);\n copy.textContent = node.textContent;\n }\n destination.head.append(copy);\n }\n destination.head.append(surface);\n };\n const surface = destination.createElement('style');\n surface.textContent = 'html,body{background:transparent!important}';\n const observers: MutationObserver[] = [];\n const mirror = (node: Element, target: HTMLElement, flatten = false) => {\n const update = () => {\n for (const attribute of Array.from(target.attributes)) if (!node.hasAttribute(attribute.name)) target.removeAttribute(attribute.name);\n for (const attribute of Array.from(node.attributes)) target.setAttribute(attribute.name, attribute.value);\n // The popover content must not inherit the source page's rail layout.\n if (target.localName === 'ion-app') target.classList.remove('ios-theme-vertical-bars');\n if (flatten) target.style.setProperty('display', 'contents', 'important');\n };\n update();\n const observer = new MutationObserver(update);\n observer.observe(node, { attributes: true });\n observers.push(observer);\n };\n mirror(source.documentElement, destination.documentElement);\n mirror(source.body, destination.body);\n const ancestors: Element[] = [];\n for (let node = overlay.parentElement; node && node !== source.body; node = node.parentElement) ancestors.unshift(node);\n let parent = destination.body;\n for (const node of ancestors) {\n const shell = destination.createElement(node.localName);\n mirror(node, shell, true);\n parent.append(shell);\n parent = shell;\n }\n sync();\n // A copied external stylesheet can still be loading when Ionic's content is\n // ready. Do not expose an unstyled first native frame (notably button sizes).\n const ready = Promise.all(\n Array.from(destination.querySelectorAll<HTMLLinkElement>('link[rel=stylesheet]'), (link) => {\n if (link.sheet) return Promise.resolve();\n return new Promise<void>((resolve, reject) => {\n link.addEventListener('load', () => resolve(), { once: true });\n link.addEventListener('error', () => reject(new Error('Popover stylesheet unavailable')), { once: true });\n });\n }),\n ).then(() => undefined);\n const observer = new MutationObserver(sync);\n observer.observe(source.head, { subtree: true, childList: true, characterData: true, attributes: true });\n observers.push(observer);\n return { destination: parent, ready, stop: () => observers.forEach((item) => item.disconnect()) };\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prehide.d.ts","names":[],"sources":["../../src/native/prehide.ts"],"mappings":";
|
|
1
|
+
{"version":3,"file":"prehide.d.ts","names":[],"sources":["../../src/native/prehide.ts"],"mappings":";qBAmCa,oCAAqC,KAAK;EAAa;EAA2B"}
|
package/dist/native/prehide.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { VERTICAL_BARS_TRANSITION_CANCELED } from "../native-integration/index.js";
|
|
2
2
|
import { modalUsesVerticalBars } from "./shared/modal.js";
|
|
3
|
-
import { childElements, clearVerticalBarsPlacement, createVerticalBarsPageState, isPermanentlyExcluded, isShellDisabled, isVerticalBarsToolbarActionShape, prehiddenClass, prehideRootClass, setVerticalBarsPlacement, verticalBarsActionCandidate, verticalBarsBackCandidate, verticalBarsBackWebClass, verticalBarsOwned } from "./shared/dom.js";
|
|
4
|
-
import { LIFECYCLE_DID_ENTER, LIFECYCLE_DID_LEAVE, LIFECYCLE_WILL_ENTER, LIFECYCLE_WILL_LEAVE } from "@ionic/core";
|
|
3
|
+
import { childElements, clearVerticalBarsPlacement, createVerticalBarsPageState, isPermanentlyExcluded, isShellDisabled, isVerticalBarsToolbarActionShape, prehiddenClass, prehideRootClass, setVerticalBarsPlacement, syncToolbarText, verticalBarsActionCandidate, verticalBarsBackCandidate, verticalBarsBackWebClass, verticalBarsOwned } from "./shared/dom.js";
|
|
4
|
+
import { LIFECYCLE_DID_ENTER, LIFECYCLE_DID_LEAVE, LIFECYCLE_WILL_ENTER, LIFECYCLE_WILL_LEAVE } from "@ionic/core/components/index.js";
|
|
5
5
|
//#region src/native/prehide.ts
|
|
6
6
|
const overlays = "ion-menu, ion-popover";
|
|
7
7
|
const sourceSelector = "ion-back-button, ion-menu-button, ion-buttons, ion-button";
|
|
@@ -99,6 +99,7 @@ const prehideVerticalBarsToolbarSources = (doc) => {
|
|
|
99
99
|
scopes.set(scope, owned);
|
|
100
100
|
};
|
|
101
101
|
const reconcile = () => {
|
|
102
|
+
syncToolbarText(doc);
|
|
102
103
|
const verticalBars = root();
|
|
103
104
|
if (!verticalBars) {
|
|
104
105
|
Array.from(scopes.keys()).forEach(release);
|
|
@@ -160,6 +161,8 @@ const prehideVerticalBarsToolbarSources = (doc) => {
|
|
|
160
161
|
doc.defaultView?.addEventListener("nativeUIShellRefresh", reconcile, { signal: listeners.signal });
|
|
161
162
|
reconcile();
|
|
162
163
|
const mutationRelevant = (record) => {
|
|
164
|
+
if (record.type === "characterData") return record.target.parentElement?.matches("ion-toolbar") === true;
|
|
165
|
+
if (record.type === "childList" && asElement(record.target)?.matches("ion-toolbar")) return true;
|
|
163
166
|
if (record.type === "childList") return [...Array.from(record.addedNodes), ...Array.from(record.removedNodes)].some((node) => isHtmlElement(node) && (node.matches(`${sourceSelector}, .ion-page, ion-toolbar`) || !!node.querySelector(`${sourceSelector}, .ion-page, ion-toolbar`)));
|
|
164
167
|
if (record.attributeName !== "class") return true;
|
|
165
168
|
const current = record.target.className;
|
|
@@ -183,6 +186,7 @@ const prehideVerticalBarsToolbarSources = (doc) => {
|
|
|
183
186
|
observer.observe(doc.documentElement, {
|
|
184
187
|
subtree: true,
|
|
185
188
|
childList: true,
|
|
189
|
+
characterData: true,
|
|
186
190
|
attributes: true,
|
|
187
191
|
attributeOldValue: true,
|
|
188
192
|
attributeFilter: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prehide.js","names":[],"sources":["../../src/native/prehide.ts"],"sourcesContent":["import { modalUsesVerticalBars } from './shared/modal';\nimport { LIFECYCLE_DID_ENTER, LIFECYCLE_DID_LEAVE, LIFECYCLE_WILL_ENTER, LIFECYCLE_WILL_LEAVE } from '@ionic/core';\nimport { VERTICAL_BARS_TRANSITION_CANCELED } from '../native-integration';\nimport {\n childElements,\n clearVerticalBarsPlacement,\n createVerticalBarsPageState,\n verticalBarsActionCandidate,\n verticalBarsBackCandidate,\n verticalBarsBackWebClass,\n verticalBarsOwned,\n isVerticalBarsToolbarActionShape,\n isPermanentlyExcluded,\n isShellDisabled,\n prehiddenClass,\n prehideRootClass,\n rejectedClass,\n setVerticalBarsPlacement,\n} from './shared/dom';\n\nconst overlays = 'ion-menu, ion-popover';\nconst sourceSelector = 'ion-back-button, ion-menu-button, ion-buttons, ion-button';\n// Realm- and teardown-safe: globals such as Element/HTMLElement may be gone\n// when a queued mutation microtask or a stale listener still runs.\nconst isHtmlElement = (node: unknown): node is HTMLElement => !!node && (node as Node).nodeType === 1;\nconst asElement = (node: Node | EventTarget | null): HTMLElement | undefined => (isHtmlElement(node) ? node : undefined);\nconst backSupported = (element: HTMLElement): boolean => {\n const back = element as HTMLIonBackButtonElement;\n return back.icon === undefined && back.color === undefined && !!back.shadowRoot;\n};\nconst eligibleBack = verticalBarsBackCandidate;\nconst eligible = verticalBarsActionCandidate;\n\n/** Capture toolbar placement once per routed-page epoch, before Ionic paints its transition. */\nexport const prehideVerticalBarsToolbarSources = (doc: Document): { suspend: () => () => void; stop: () => void } => {\n doc.documentElement.classList.add(prehideRootClass);\n const scopes = new Map<HTMLElement, Set<HTMLElement>>();\n const owner = new WeakMap<HTMLElement, HTMLElement>();\n const pendingBacks = new Map<HTMLElement, { scope: HTMLElement; timer: ReturnType<typeof setTimeout> }>();\n const verticalBarsPages = createVerticalBarsPageState();\n const listeners = new AbortController();\n const root = () => doc.querySelector<HTMLElement>('ion-app.ios-theme-vertical-bars');\n let suspended = 0;\n let stopped = false;\n const routedPage = (element: HTMLElement) => element.closest<HTMLElement>('.ion-page:not(ion-app, body)');\n const release = (scope: HTMLElement) => {\n for (const [element, pending] of pendingBacks) {\n if (pending.scope !== scope) continue;\n clearTimeout(pending.timer);\n pendingBacks.delete(element);\n }\n const owned = scopes.get(scope);\n if (!owned) return;\n owned.forEach((element) => {\n if (owner.get(element) !== scope) return;\n owner.delete(element);\n element.classList.remove(prehiddenClass);\n element.classList.remove(verticalBarsBackWebClass);\n clearVerticalBarsPlacement(element);\n });\n scopes.delete(scope);\n };\n const capture = (scope: HTMLElement) => {\n if (!root()?.contains(scope) || scope.closest(overlays) || !modalUsesVerticalBars(scope) || verticalBarsPages.isDeparted(scope)) return;\n const owned = scopes.get(scope) ?? new Set<HTMLElement>();\n const place = (element: HTMLElement, rail: boolean) => {\n if (owned.has(element)) return;\n const previousScope = owner.get(element);\n if (previousScope) scopes.get(previousScope)?.delete(element);\n owner.set(element, scope);\n setVerticalBarsPlacement(element, rail);\n if (element.matches('ion-back-button')) element.classList.toggle(verticalBarsBackWebClass, !rail);\n owned.add(element);\n };\n const sources = scope.matches('ion-back-button') ? [scope] : Array.from(scope.querySelectorAll<HTMLElement>(sourceSelector));\n sources.forEach((element) => {\n // Shell opt-out is temporary; decide initial placement once it is lifted.\n if (isShellDisabled(element)) return;\n if (!modalUsesVerticalBars(element) || element.closest(overlays) || (scope.matches('.ion-page') && routedPage(element) !== scope))\n return;\n if (element.matches('ion-buttons')) {\n const children = childElements(element);\n const actions = children.filter((child) => eligible(child) && isVerticalBarsToolbarActionShape(child));\n const group =\n eligible(element) &&\n actions.length === children.length &&\n (actions.length > 1 || (actions.length === 1 && actions[0].matches('ion-menu-button')));\n const freshGroup = !owned.has(element);\n place(element, group);\n children.forEach((child) => {\n if (!child.matches('ion-back-button')) place(child, freshGroup && actions.includes(child));\n });\n } else if (element.matches('ion-back-button') || !element.parentElement?.matches('ion-buttons')) {\n if (owned.has(element)) return;\n if (\n element.matches('ion-back-button') &&\n eligibleBack(element) &&\n (element as HTMLIonBackButtonElement).icon === undefined &&\n (element as HTMLIonBackButtonElement).color === undefined &&\n !element.shadowRoot &&\n !element.classList.contains('hydrated')\n ) {\n const previousPending = pendingBacks.get(element);\n if (previousPending && previousPending.scope !== scope) {\n clearTimeout(previousPending.timer);\n pendingBacks.delete(element);\n }\n if (!pendingBacks.has(element)) {\n const timer = setTimeout(() => {\n if (pendingBacks.get(element)?.scope !== scope) return;\n pendingBacks.delete(element);\n // A custom element that never hydrates must remain usable on Web.\n place(element, false);\n reconcile();\n }, 1500);\n pendingBacks.set(element, { scope, timer });\n }\n return;\n }\n const pending = pendingBacks.get(element);\n if (pending) {\n clearTimeout(pending.timer);\n pendingBacks.delete(element);\n }\n place(\n element,\n element.matches('ion-back-button')\n ? eligibleBack(element) && backSupported(element)\n : eligible(element) && isVerticalBarsToolbarActionShape(element),\n );\n }\n });\n scopes.set(scope, owned);\n };\n const reconcile = () => {\n const verticalBars = root();\n if (!verticalBars) {\n Array.from(scopes.keys()).forEach(release);\n return;\n }\n for (const scope of scopes.keys()) if (!scope.isConnected || !modalUsesVerticalBars(scope)) release(scope);\n for (const [element, pending] of pendingBacks) if (element.shadowRoot || element.classList.contains('hydrated')) capture(pending.scope);\n // Ionic inserts the destination as invisible before WillEnter. Hide its\n // sources in that same mutation microtask; capture new DOM identities on active pages too.\n verticalBars.querySelectorAll<HTMLElement>('.ion-page:not(ion-app, body, .ion-page-hidden)').forEach(capture);\n // Root toolbars can mount after startup; each new DOM identity is captured once.\n verticalBars.querySelectorAll<HTMLElement>(sourceSelector).forEach((element) => {\n if (routedPage(element) || element.closest(overlays)) return;\n const scope = element.closest<HTMLElement>('ion-toolbar') ?? (element.matches('ion-back-button') ? element : null);\n if (scope) capture(scope);\n });\n for (const owned of scopes.values()) {\n for (const element of owned) {\n const groupOwnsChildren =\n element.parentElement?.matches('ion-buttons') &&\n verticalBarsOwned(element.parentElement) &&\n childElements(element.parentElement).every((child) => verticalBarsOwned(child));\n const hide =\n !suspended &&\n verticalBarsOwned(element) &&\n !groupOwnsChildren &&\n element.isConnected &&\n !element.closest(`.${rejectedClass}`) &&\n !isPermanentlyExcluded(element) &&\n !isShellDisabled(element) &&\n (!element.matches('ion-back-button') || backSupported(element) || !element.classList.contains('hydrated')) &&\n (!element.matches('ion-buttons') || childElements(element).every((child) => verticalBarsOwned(child)));\n element.classList.toggle(prehiddenClass, hide);\n if (element.matches('ion-back-button')) element.classList.toggle(verticalBarsBackWebClass, !hide);\n }\n }\n };\n const onWillEnter = (event: Event) => {\n const page = asElement(event.target);\n if (page?.matches('.ion-page')) {\n verticalBarsPages.lifecycle(event);\n release(page); // Cached pages begin a new placement epoch.\n capture(page);\n reconcile();\n }\n };\n const onPageLifecycle: EventListener = (event) => {\n verticalBarsPages.lifecycle(event);\n if (event.type !== LIFECYCLE_DID_LEAVE) return;\n const page = asElement(event.target);\n if (page) release(page);\n };\n // A canceled transition keeps the leaving page active and abandons the entering one.\n const onTransitionCanceled: EventListener = (event) => {\n const leaving = asElement(event.target);\n if (!leaving) return;\n const entering = (event as CustomEvent<{ entering?: HTMLElement }>).detail?.entering;\n verticalBarsPages.cancel(entering, leaving);\n reconcile();\n };\n doc.addEventListener(LIFECYCLE_WILL_ENTER, onWillEnter, { capture: true, signal: listeners.signal });\n for (const name of [LIFECYCLE_WILL_LEAVE, LIFECYCLE_DID_ENTER, LIFECYCLE_DID_LEAVE])\n doc.addEventListener(name, onPageLifecycle, { capture: true, signal: listeners.signal });\n doc.addEventListener(VERTICAL_BARS_TRANSITION_CANCELED, onTransitionCanceled, { capture: true, signal: listeners.signal });\n doc.defaultView?.addEventListener('nativeUIShellRefresh', reconcile, { signal: listeners.signal });\n reconcile();\n const mutationRelevant = (record: MutationRecord) => {\n if (record.type === 'childList')\n return [...Array.from(record.addedNodes), ...Array.from(record.removedNodes)].some(\n (node) =>\n isHtmlElement(node) &&\n (node.matches(`${sourceSelector}, .ion-page, ion-toolbar`) || !!node.querySelector(`${sourceSelector}, .ion-page, ion-toolbar`)),\n );\n if (record.attributeName !== 'class') return true;\n const current = (record.target as Element).className;\n const previous = record.oldValue ?? '';\n const withoutOwned = (value: string) =>\n value\n .split(/\\s+/)\n .filter((name) => name && ![prehiddenClass, prehideRootClass, verticalBarsBackWebClass].includes(name))\n .join(' ');\n return typeof current !== 'string' || withoutOwned(previous) !== withoutOwned(current);\n };\n let scheduled = false;\n const observer = new (doc.defaultView?.MutationObserver ?? MutationObserver)((records) => {\n if (scheduled || stopped || !records.some(mutationRelevant)) return;\n scheduled = true;\n queueMicrotask(() => {\n scheduled = false;\n if (!stopped) reconcile();\n });\n });\n observer.observe(doc.documentElement, {\n subtree: true,\n childList: true,\n attributes: true,\n attributeOldValue: true,\n attributeFilter: ['class', 'data-shell', 'hidden', 'inert', 'icon', 'color'],\n });\n return {\n suspend: () => {\n if (stopped) return () => {};\n suspended++;\n doc.documentElement.classList.remove(prehideRootClass);\n reconcile();\n let resumed = false;\n return () => {\n if (resumed || stopped) return;\n resumed = true;\n if (--suspended === 0) {\n doc.documentElement.classList.add(prehideRootClass);\n reconcile();\n }\n };\n },\n stop: () => {\n if (stopped) return;\n stopped = true;\n observer.disconnect();\n listeners.abort();\n doc.documentElement.classList.remove(prehideRootClass);\n Array.from(scopes.keys()).forEach(release);\n },\n };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"prehide.js","names":[],"sources":["../../src/native/prehide.ts"],"sourcesContent":["import { modalUsesVerticalBars } from './shared/modal';\nimport { LIFECYCLE_DID_ENTER, LIFECYCLE_DID_LEAVE, LIFECYCLE_WILL_ENTER, LIFECYCLE_WILL_LEAVE } from '@ionic/core/components/index.js';\nimport { VERTICAL_BARS_TRANSITION_CANCELED } from '../native-integration';\nimport {\n childElements,\n clearVerticalBarsPlacement,\n createVerticalBarsPageState,\n verticalBarsActionCandidate,\n verticalBarsBackCandidate,\n verticalBarsBackWebClass,\n verticalBarsOwned,\n isVerticalBarsToolbarActionShape,\n isPermanentlyExcluded,\n isShellDisabled,\n prehiddenClass,\n prehideRootClass,\n rejectedClass,\n setVerticalBarsPlacement,\n syncToolbarText,\n} from './shared/dom';\n\nconst overlays = 'ion-menu, ion-popover';\nconst sourceSelector = 'ion-back-button, ion-menu-button, ion-buttons, ion-button';\n// Realm- and teardown-safe: globals such as Element/HTMLElement may be gone\n// when a queued mutation microtask or a stale listener still runs.\nconst isHtmlElement = (node: unknown): node is HTMLElement => !!node && (node as Node).nodeType === 1;\nconst asElement = (node: Node | EventTarget | null): HTMLElement | undefined => (isHtmlElement(node) ? node : undefined);\nconst backSupported = (element: HTMLElement): boolean => {\n const back = element as HTMLIonBackButtonElement;\n return back.icon === undefined && back.color === undefined && !!back.shadowRoot;\n};\nconst eligibleBack = verticalBarsBackCandidate;\nconst eligible = verticalBarsActionCandidate;\n\n/** Capture toolbar placement once per routed-page epoch, before Ionic paints its transition. */\nexport const prehideVerticalBarsToolbarSources = (doc: Document): { suspend: () => () => void; stop: () => void } => {\n doc.documentElement.classList.add(prehideRootClass);\n const scopes = new Map<HTMLElement, Set<HTMLElement>>();\n const owner = new WeakMap<HTMLElement, HTMLElement>();\n const pendingBacks = new Map<HTMLElement, { scope: HTMLElement; timer: ReturnType<typeof setTimeout> }>();\n const verticalBarsPages = createVerticalBarsPageState();\n const listeners = new AbortController();\n const root = () => doc.querySelector<HTMLElement>('ion-app.ios-theme-vertical-bars');\n let suspended = 0;\n let stopped = false;\n const routedPage = (element: HTMLElement) => element.closest<HTMLElement>('.ion-page:not(ion-app, body)');\n const release = (scope: HTMLElement) => {\n for (const [element, pending] of pendingBacks) {\n if (pending.scope !== scope) continue;\n clearTimeout(pending.timer);\n pendingBacks.delete(element);\n }\n const owned = scopes.get(scope);\n if (!owned) return;\n owned.forEach((element) => {\n if (owner.get(element) !== scope) return;\n owner.delete(element);\n element.classList.remove(prehiddenClass);\n element.classList.remove(verticalBarsBackWebClass);\n clearVerticalBarsPlacement(element);\n });\n scopes.delete(scope);\n };\n const capture = (scope: HTMLElement) => {\n if (!root()?.contains(scope) || scope.closest(overlays) || !modalUsesVerticalBars(scope) || verticalBarsPages.isDeparted(scope)) return;\n const owned = scopes.get(scope) ?? new Set<HTMLElement>();\n const place = (element: HTMLElement, rail: boolean) => {\n if (owned.has(element)) return;\n const previousScope = owner.get(element);\n if (previousScope) scopes.get(previousScope)?.delete(element);\n owner.set(element, scope);\n setVerticalBarsPlacement(element, rail);\n if (element.matches('ion-back-button')) element.classList.toggle(verticalBarsBackWebClass, !rail);\n owned.add(element);\n };\n const sources = scope.matches('ion-back-button') ? [scope] : Array.from(scope.querySelectorAll<HTMLElement>(sourceSelector));\n sources.forEach((element) => {\n // Shell opt-out is temporary; decide initial placement once it is lifted.\n if (isShellDisabled(element)) return;\n if (!modalUsesVerticalBars(element) || element.closest(overlays) || (scope.matches('.ion-page') && routedPage(element) !== scope))\n return;\n if (element.matches('ion-buttons')) {\n const children = childElements(element);\n const actions = children.filter((child) => eligible(child) && isVerticalBarsToolbarActionShape(child));\n const group =\n eligible(element) &&\n actions.length === children.length &&\n (actions.length > 1 || (actions.length === 1 && actions[0].matches('ion-menu-button')));\n const freshGroup = !owned.has(element);\n place(element, group);\n children.forEach((child) => {\n if (!child.matches('ion-back-button')) place(child, freshGroup && actions.includes(child));\n });\n } else if (element.matches('ion-back-button') || !element.parentElement?.matches('ion-buttons')) {\n if (owned.has(element)) return;\n if (\n element.matches('ion-back-button') &&\n eligibleBack(element) &&\n (element as HTMLIonBackButtonElement).icon === undefined &&\n (element as HTMLIonBackButtonElement).color === undefined &&\n !element.shadowRoot &&\n !element.classList.contains('hydrated')\n ) {\n const previousPending = pendingBacks.get(element);\n if (previousPending && previousPending.scope !== scope) {\n clearTimeout(previousPending.timer);\n pendingBacks.delete(element);\n }\n if (!pendingBacks.has(element)) {\n const timer = setTimeout(() => {\n if (pendingBacks.get(element)?.scope !== scope) return;\n pendingBacks.delete(element);\n // A custom element that never hydrates must remain usable on Web.\n place(element, false);\n reconcile();\n }, 1500);\n pendingBacks.set(element, { scope, timer });\n }\n return;\n }\n const pending = pendingBacks.get(element);\n if (pending) {\n clearTimeout(pending.timer);\n pendingBacks.delete(element);\n }\n place(\n element,\n element.matches('ion-back-button')\n ? eligibleBack(element) && backSupported(element)\n : eligible(element) && isVerticalBarsToolbarActionShape(element),\n );\n }\n });\n scopes.set(scope, owned);\n };\n const reconcile = () => {\n syncToolbarText(doc);\n const verticalBars = root();\n if (!verticalBars) {\n Array.from(scopes.keys()).forEach(release);\n return;\n }\n for (const scope of scopes.keys()) if (!scope.isConnected || !modalUsesVerticalBars(scope)) release(scope);\n for (const [element, pending] of pendingBacks) if (element.shadowRoot || element.classList.contains('hydrated')) capture(pending.scope);\n // Ionic inserts the destination as invisible before WillEnter. Hide its\n // sources in that same mutation microtask; capture new DOM identities on active pages too.\n verticalBars.querySelectorAll<HTMLElement>('.ion-page:not(ion-app, body, .ion-page-hidden)').forEach(capture);\n // Root toolbars can mount after startup; each new DOM identity is captured once.\n verticalBars.querySelectorAll<HTMLElement>(sourceSelector).forEach((element) => {\n if (routedPage(element) || element.closest(overlays)) return;\n const scope = element.closest<HTMLElement>('ion-toolbar') ?? (element.matches('ion-back-button') ? element : null);\n if (scope) capture(scope);\n });\n for (const owned of scopes.values()) {\n for (const element of owned) {\n const groupOwnsChildren =\n element.parentElement?.matches('ion-buttons') &&\n verticalBarsOwned(element.parentElement) &&\n childElements(element.parentElement).every((child) => verticalBarsOwned(child));\n const hide =\n !suspended &&\n verticalBarsOwned(element) &&\n !groupOwnsChildren &&\n element.isConnected &&\n !element.closest(`.${rejectedClass}`) &&\n !isPermanentlyExcluded(element) &&\n !isShellDisabled(element) &&\n (!element.matches('ion-back-button') || backSupported(element) || !element.classList.contains('hydrated')) &&\n (!element.matches('ion-buttons') || childElements(element).every((child) => verticalBarsOwned(child)));\n element.classList.toggle(prehiddenClass, hide);\n if (element.matches('ion-back-button')) element.classList.toggle(verticalBarsBackWebClass, !hide);\n }\n }\n };\n const onWillEnter = (event: Event) => {\n const page = asElement(event.target);\n if (page?.matches('.ion-page')) {\n verticalBarsPages.lifecycle(event);\n release(page); // Cached pages begin a new placement epoch.\n capture(page);\n reconcile();\n }\n };\n const onPageLifecycle: EventListener = (event) => {\n verticalBarsPages.lifecycle(event);\n if (event.type !== LIFECYCLE_DID_LEAVE) return;\n const page = asElement(event.target);\n if (page) release(page);\n };\n // A canceled transition keeps the leaving page active and abandons the entering one.\n const onTransitionCanceled: EventListener = (event) => {\n const leaving = asElement(event.target);\n if (!leaving) return;\n const entering = (event as CustomEvent<{ entering?: HTMLElement }>).detail?.entering;\n verticalBarsPages.cancel(entering, leaving);\n reconcile();\n };\n doc.addEventListener(LIFECYCLE_WILL_ENTER, onWillEnter, { capture: true, signal: listeners.signal });\n for (const name of [LIFECYCLE_WILL_LEAVE, LIFECYCLE_DID_ENTER, LIFECYCLE_DID_LEAVE])\n doc.addEventListener(name, onPageLifecycle, { capture: true, signal: listeners.signal });\n doc.addEventListener(VERTICAL_BARS_TRANSITION_CANCELED, onTransitionCanceled, { capture: true, signal: listeners.signal });\n doc.defaultView?.addEventListener('nativeUIShellRefresh', reconcile, { signal: listeners.signal });\n reconcile();\n const mutationRelevant = (record: MutationRecord) => {\n if (record.type === 'characterData') return record.target.parentElement?.matches('ion-toolbar') === true;\n if (record.type === 'childList' && asElement(record.target)?.matches('ion-toolbar')) return true;\n if (record.type === 'childList')\n return [...Array.from(record.addedNodes), ...Array.from(record.removedNodes)].some(\n (node) =>\n isHtmlElement(node) &&\n (node.matches(`${sourceSelector}, .ion-page, ion-toolbar`) || !!node.querySelector(`${sourceSelector}, .ion-page, ion-toolbar`)),\n );\n if (record.attributeName !== 'class') return true;\n const current = (record.target as Element).className;\n const previous = record.oldValue ?? '';\n const withoutOwned = (value: string) =>\n value\n .split(/\\s+/)\n .filter((name) => name && ![prehiddenClass, prehideRootClass, verticalBarsBackWebClass].includes(name))\n .join(' ');\n return typeof current !== 'string' || withoutOwned(previous) !== withoutOwned(current);\n };\n let scheduled = false;\n const observer = new (doc.defaultView?.MutationObserver ?? MutationObserver)((records) => {\n if (scheduled || stopped || !records.some(mutationRelevant)) return;\n scheduled = true;\n queueMicrotask(() => {\n scheduled = false;\n if (!stopped) reconcile();\n });\n });\n observer.observe(doc.documentElement, {\n subtree: true,\n childList: true,\n characterData: true,\n attributes: true,\n attributeOldValue: true,\n attributeFilter: ['class', 'data-shell', 'hidden', 'inert', 'icon', 'color'],\n });\n return {\n suspend: () => {\n if (stopped) return () => {};\n suspended++;\n doc.documentElement.classList.remove(prehideRootClass);\n reconcile();\n let resumed = false;\n return () => {\n if (resumed || stopped) return;\n resumed = true;\n if (--suspended === 0) {\n doc.documentElement.classList.add(prehideRootClass);\n reconcile();\n }\n };\n },\n stop: () => {\n if (stopped) return;\n stopped = true;\n observer.disconnect();\n listeners.abort();\n doc.documentElement.classList.remove(prehideRootClass);\n Array.from(scopes.keys()).forEach(release);\n },\n };\n};\n"],"mappings":"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"}
|
package/dist/native/runtime.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { NativeUIShellHandle, NativeUIShellOptions, NativeUIShellPlugin } from "./definitions.js";
|
|
2
2
|
//#region src/native/runtime.d.ts
|
|
3
|
-
export declare const
|
|
3
|
+
export declare const bounded: <T>(promise: Promise<T>) => Promise<T>;
|
|
4
|
+
export declare const createRuntime: (doc: Document, plugin: NativeUIShellPlugin, options?: NativeUIShellOptions, nativeVerticalBars?: () => boolean, verticalBarsOnly?: boolean) => Promise<NativeUIShellHandle & {
|
|
5
|
+
retain: (deferActivation?: (id: string) => boolean) => () => void;
|
|
6
|
+
}>;
|
|
4
7
|
//#endregion
|
|
5
8
|
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","names":[],"sources":["../../src/native/runtime.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","names":[],"sources":["../../src/native/runtime.ts"],"mappings":";;qBAsCa,UAAW,GAAG,SAAS,QAAQ,OAAK,QAAQ;qBAM5C,gBACX,KAAK,UACL,QAAQ,qBACR,UAAS,sBACT,oCACA,+BACC,QAAQ;EAAwB,SAAS,mBAAmB"}
|
package/dist/native/runtime.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { VERTICAL_BARS_TRANSITION_CANCELED, getNativeSearchBindings, setNativeUIShellIntegration } from "../native-integration/index.js";
|
|
2
|
+
import { projectionIds } from "./shared/projection-id.js";
|
|
2
3
|
import { inVerticalBarsSurface, modalUsesVerticalBars, modalVerticalBarFrame, topModal } from "./shared/modal.js";
|
|
3
4
|
import { createCrossfade, fadeMarker } from "./shared/crossfade.js";
|
|
4
|
-
import { activateProjectedElement, createVerticalBarsPageState, isVerticalBarsSource, marker, preferredVerticalBarsBack, prehideOnlyMutation, rejectedClass, unprojected } from "./shared/dom.js";
|
|
5
|
+
import { activateProjectedElement, createVerticalBarsPageState, isVerticalBarsSource, marker, preferredVerticalBarsBack, prehideOnlyMutation, rejectedClass, syncToolbarText, unprojected } from "./shared/dom.js";
|
|
5
6
|
import { createIconRenderer } from "./shared/icons.js";
|
|
6
7
|
import { createSearchSupport } from "./components/searchable-tabs.js";
|
|
7
8
|
import { isVerticalBarsCandidate, motionSelector, readCandidate, selector, shadowSelector } from "./components/index.js";
|
|
8
9
|
import { CSS_MOTION_EVENTS } from "./shared/events.js";
|
|
9
|
-
import { LIFECYCLE_DID_ENTER, LIFECYCLE_DID_LEAVE, LIFECYCLE_WILL_ENTER, LIFECYCLE_WILL_LEAVE } from "@ionic/core";
|
|
10
|
+
import { LIFECYCLE_DID_ENTER, LIFECYCLE_DID_LEAVE, LIFECYCLE_WILL_ENTER, LIFECYCLE_WILL_LEAVE } from "@ionic/core/components/index.js";
|
|
10
11
|
//#region src/native/runtime.ts
|
|
11
12
|
const overlays = "ion-modal, ion-popover, ion-alert, ion-action-sheet, ion-loading, ion-picker, ion-toast, ion-menu";
|
|
12
13
|
const overlayNames = [
|
|
@@ -54,6 +55,7 @@ const createRuntime = async (doc, plugin, options = {}, nativeVerticalBars = ()
|
|
|
54
55
|
let dirty = false;
|
|
55
56
|
let pending = false;
|
|
56
57
|
let stopped = false;
|
|
58
|
+
const retentions = /* @__PURE__ */ new Set();
|
|
57
59
|
/** True while a tab-switch handoff should skip crossfade. */
|
|
58
60
|
let tabSwitchHandoff = false;
|
|
59
61
|
/** Keep instant updates until this time — DidLeave often precedes the retire sync. */
|
|
@@ -85,6 +87,7 @@ const createRuntime = async (doc, plugin, options = {}, nativeVerticalBars = ()
|
|
|
85
87
|
if (!value) {
|
|
86
88
|
value = `shell-${++nextId}`;
|
|
87
89
|
ids.set(element, value);
|
|
90
|
+
projectionIds.set(element, value);
|
|
88
91
|
}
|
|
89
92
|
return value;
|
|
90
93
|
};
|
|
@@ -240,9 +243,11 @@ const createRuntime = async (doc, plugin, options = {}, nativeVerticalBars = ()
|
|
|
240
243
|
frame = 0;
|
|
241
244
|
dirty = false;
|
|
242
245
|
pending = true;
|
|
246
|
+
syncToolbarText(doc);
|
|
243
247
|
handoffInstant = tabSwitchHandoff || handoffAcrossPending || modalPresentHandoff || win.performance.now() < handoffUntil;
|
|
244
|
-
modalPresentHandoff = false;
|
|
245
248
|
try {
|
|
249
|
+
if (retentions.size && !manualSuspensions.size) return;
|
|
250
|
+
modalPresentHandoff = false;
|
|
246
251
|
const size = `${win.innerWidth}:${win.innerHeight}`;
|
|
247
252
|
if (viewport !== size) {
|
|
248
253
|
viewport = size;
|
|
@@ -256,7 +261,7 @@ const createRuntime = async (doc, plugin, options = {}, nativeVerticalBars = ()
|
|
|
256
261
|
const field = icon.field ?? "icon";
|
|
257
262
|
icon.item[field] = await icons.render(icon.source, field === "icon" ? icon.item.iconWidth : icon.item.closeIconWidth, field === "icon" ? icon.item.iconHeight : icon.item.closeIconHeight);
|
|
258
263
|
}
|
|
259
|
-
if (stopped || dirty) return;
|
|
264
|
+
if (stopped || dirty || retentions.size && !manualSuspensions.size) return;
|
|
260
265
|
const retained = new Set(candidates.flatMap(candidateSources));
|
|
261
266
|
const removed = Array.from(sources.keys()).filter((element) => !retained.has(element));
|
|
262
267
|
if (removed.length) {
|
|
@@ -286,7 +291,7 @@ const createRuntime = async (doc, plugin, options = {}, nativeVerticalBars = ()
|
|
|
286
291
|
updates++;
|
|
287
292
|
updatingRevision = snapshot.revision;
|
|
288
293
|
const result = await bounded(plugin.update(snapshot));
|
|
289
|
-
if (stopped) return;
|
|
294
|
+
if (stopped || retentions.size && !manualSuspensions.size) return;
|
|
290
295
|
if (result.revision !== snapshot.revision) throw new Error("Native UI Shell revision mismatch");
|
|
291
296
|
if (`${win.innerWidth}:${win.innerHeight}` !== size) {
|
|
292
297
|
lastSnapshot = "";
|
|
@@ -372,7 +377,7 @@ const createRuntime = async (doc, plugin, options = {}, nativeVerticalBars = ()
|
|
|
372
377
|
attributeOldValue: true
|
|
373
378
|
};
|
|
374
379
|
const observer = new MutationObserver((records) => {
|
|
375
|
-
if (records.some((record) => record.attributeName !== "data-native-ui-shell" && record.attributeName !== "data-native-ui-shell-fading" && !prehideOnlyMutation(record) && !(record.attributeName === "style" && measuringPointerPages.has(record.target)) && !(record.attributeName === "aria-hidden" && sources.has(record.target) && record.target.getAttribute("aria-hidden") === "true"))) schedule();
|
|
380
|
+
if (records.some((record) => record.attributeName !== "data-native-ui-shell" && record.attributeName !== "data-native-ui-shell-toolbar-text" && record.attributeName !== "data-native-ui-shell-fading" && !prehideOnlyMutation(record) && !(record.attributeName === "style" && measuringPointerPages.has(record.target)) && !(record.attributeName === "aria-hidden" && sources.has(record.target) && record.target.getAttribute("aria-hidden") === "true"))) schedule();
|
|
376
381
|
});
|
|
377
382
|
const resize = new ResizeObserver(schedule);
|
|
378
383
|
const on = (target, name, callback = schedule) => target.addEventListener(name, callback, {
|
|
@@ -518,6 +523,16 @@ const createRuntime = async (doc, plugin, options = {}, nativeVerticalBars = ()
|
|
|
518
523
|
on(win.visualViewport, "scroll");
|
|
519
524
|
}
|
|
520
525
|
const handle = {
|
|
526
|
+
retain(deferActivation) {
|
|
527
|
+
const retention = { accepts: deferActivation };
|
|
528
|
+
retentions.add(retention);
|
|
529
|
+
return () => {
|
|
530
|
+
if (!retentions.delete(retention)) return;
|
|
531
|
+
const activation = retention.activation;
|
|
532
|
+
if (activation && retention.accepts?.(activation.id)) win.queueMicrotask(() => activate(activation));
|
|
533
|
+
schedule();
|
|
534
|
+
};
|
|
535
|
+
},
|
|
521
536
|
getStatus: () => ({
|
|
522
537
|
state: stopped ? "stopped" : sources.size ? "native" : "web",
|
|
523
538
|
projected: sources.size,
|
|
@@ -571,7 +586,13 @@ const createRuntime = async (doc, plugin, options = {}, nativeVerticalBars = ()
|
|
|
571
586
|
}
|
|
572
587
|
};
|
|
573
588
|
const activate = (event) => {
|
|
574
|
-
if (stopped || doc.hidden || event.revision < acceptedRevision || event.revision > revision || event.sequence <= lastSequence
|
|
589
|
+
if (stopped || doc.hidden || event.revision < acceptedRevision || event.revision > revision || event.sequence <= lastSequence) return;
|
|
590
|
+
if (overlayOpen(false, true)) {
|
|
591
|
+
if (!manualSuspensions.size) {
|
|
592
|
+
for (const retention of retentions) if (retention.accepts?.(event.id) && (!retention.activation || event.sequence > retention.activation.sequence)) retention.activation = event;
|
|
593
|
+
}
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
575
596
|
if (event.revision > acceptedRevision && event.revision === updatingRevision) {
|
|
576
597
|
pendingActivations.push(event);
|
|
577
598
|
return;
|
|
@@ -634,6 +655,6 @@ const createRuntime = async (doc, plugin, options = {}, nativeVerticalBars = ()
|
|
|
634
655
|
return handle;
|
|
635
656
|
};
|
|
636
657
|
//#endregion
|
|
637
|
-
export { createRuntime };
|
|
658
|
+
export { bounded, createRuntime };
|
|
638
659
|
|
|
639
660
|
//# sourceMappingURL=runtime.js.map
|