@rdlabo/ionic-theme-ios27 0.1.0 → 0.2.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/README.md +10 -2
- package/dist/css/components/ion-button.css +1 -1
- package/dist/css/components/ion-fab.css +1 -1
- package/dist/css/components/ion-list.css +1 -1
- package/dist/css/components/ion-menu.css +1 -1
- package/dist/css/components/ion-searchbar.css +1 -1
- package/dist/css/components/ion-tabs.css +1 -1
- package/dist/css/components/ion-toolbar.css +1 -1
- package/dist/css/ionic-theme-ios27.css +1 -1
- package/dist/css/md-ion-list-inset.css +1 -1
- package/dist/css/utils/translucent.css +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/native/definitions.d.ts +19 -0
- package/dist/native/definitions.d.ts.map +1 -1
- package/dist/native/index.d.ts +4 -3
- package/dist/native/index.d.ts.map +1 -1
- package/dist/native/index.js +22 -9
- package/dist/native/lifecycle.d.ts +4 -0
- package/dist/native/lifecycle.d.ts.map +1 -0
- package/dist/native/lifecycle.js +34 -0
- package/dist/native/runtime.d.ts +2 -2
- package/dist/native/runtime.d.ts.map +1 -1
- package/dist/native/runtime.js +43 -4
- 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/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/index.d.ts +2 -2
- package/dist/tab-bar-searchable/index.d.ts.map +1 -1
- package/dist/tab-bar-searchable/index.js +2 -3
- package/dist/transition/ios.transition.d.ts +6 -1
- package/dist/transition/ios.transition.d.ts.map +1 -1
- package/dist/transition/ios.transition.js +10 -385
- package/docs/features.md +3 -1
- package/docs/native-ui-shell.md +113 -0
- package/ios/Sources/IonicNativeUIShellPlugin/IonicNativeUIShellPlugin.swift +28 -0
- package/node_modules/@rdlabo/ionic-theme-utils/LICENSE +21 -0
- package/node_modules/@rdlabo/ionic-theme-utils/README.md +28 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/dom.d.ts +3 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/dom.d.ts.map +1 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/dom.js +13 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/dom.js.map +1 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/focus-controller.d.ts +6 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/focus-controller.d.ts.map +1 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/focus-controller.js +37 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/focus-controller.js.map +1 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/index.d.ts +13 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/index.d.ts.map +1 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/index.js +11 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/index.js.map +1 -0
- package/{dist → node_modules/@rdlabo/ionic-theme-utils/dist}/popover/animations/ios.enter.d.ts +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/animations/ios.enter.d.ts.map +1 -0
- package/{dist → node_modules/@rdlabo/ionic-theme-utils/dist}/popover/animations/ios.enter.js +8 -5
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/animations/ios.enter.js.map +1 -0
- package/{dist → node_modules/@rdlabo/ionic-theme-utils/dist}/popover/animations/ios.leave.d.ts.map +1 -1
- package/{dist → node_modules/@rdlabo/ionic-theme-utils/dist}/popover/animations/ios.leave.js +11 -5
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/animations/ios.leave.js.map +1 -0
- package/{dist → node_modules/@rdlabo/ionic-theme-utils/dist}/popover/callout-surface.js +1 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/callout-surface.js.map +1 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/popover-interface.js +2 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/popover-interface.js.map +1 -0
- package/{dist → node_modules/@rdlabo/ionic-theme-utils/dist}/popover/utils.d.ts +1 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/utils.d.ts.map +1 -0
- package/{dist → node_modules/@rdlabo/ionic-theme-utils/dist}/popover/utils.js +3 -2
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/utils.js.map +1 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/sheets-of-glass.d.ts +16 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/sheets-of-glass.d.ts.map +1 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/sheets-of-glass.js +2 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/sheets-of-glass.js.map +1 -0
- package/{dist → node_modules/@rdlabo/ionic-theme-utils/dist}/tab-bar-searchable/interfaces.js +1 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/tab-bar-searchable/interfaces.js.map +1 -0
- package/{dist → node_modules/@rdlabo/ionic-theme-utils/dist}/tab-bar-searchable/utils.js +1 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/tab-bar-searchable/utils.js.map +1 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/theme.d.ts +15 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/theme.d.ts.map +1 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/theme.js +49 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/theme.js.map +1 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/transition/ios.transition.d.ts +18 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/transition/ios.transition.d.ts.map +1 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/transition/ios.transition.js +412 -0
- package/node_modules/@rdlabo/ionic-theme-utils/dist/transition/ios.transition.js.map +1 -0
- package/node_modules/@rdlabo/ionic-theme-utils/package.json +64 -0
- package/node_modules/@rdlabo/ionic-theme-utils/src/dom.spec.ts +19 -0
- package/node_modules/@rdlabo/ionic-theme-utils/src/dom.ts +16 -0
- package/node_modules/@rdlabo/ionic-theme-utils/src/focus-controller.ts +38 -0
- package/node_modules/@rdlabo/ionic-theme-utils/src/index.ts +59 -0
- package/{src → node_modules/@rdlabo/ionic-theme-utils/src}/popover/animations/ios.enter.ts +7 -5
- package/{src → node_modules/@rdlabo/ionic-theme-utils/src}/popover/animations/ios.leave.ts +14 -5
- package/node_modules/@rdlabo/ionic-theme-utils/src/popover/utils.spec.ts +58 -0
- package/{src → node_modules/@rdlabo/ionic-theme-utils/src}/popover/utils.ts +4 -2
- package/node_modules/@rdlabo/ionic-theme-utils/src/sheets-of-glass.ts +17 -0
- package/node_modules/@rdlabo/ionic-theme-utils/src/styles/index.scss +1 -0
- package/node_modules/@rdlabo/ionic-theme-utils/src/styles/md-ion-list-inset.scss +20 -0
- package/node_modules/@rdlabo/ionic-theme-utils/src/styles/structured-list.scss +310 -0
- package/node_modules/@rdlabo/ionic-theme-utils/src/tab-bar-searchable/utils.spec.ts +56 -0
- package/node_modules/@rdlabo/ionic-theme-utils/src/theme.ts +51 -0
- package/node_modules/@rdlabo/ionic-theme-utils/src/transition/ios.transition.spec.ts +52 -0
- package/node_modules/@rdlabo/ionic-theme-utils/src/transition/ios.transition.ts +542 -0
- package/package.json +13 -5
- package/src/index.ts +4 -2
- package/src/native/definitions.ts +34 -0
- package/src/native/index.ts +38 -11
- package/src/native/lifecycle.ts +38 -0
- package/src/native/runtime.ts +49 -4
- package/src/styles/components/ion-button.scss +21 -10
- package/src/styles/components/ion-fab.scss +10 -4
- package/src/styles/components/ion-list.scss +12 -3
- package/src/styles/components/ion-menu.scss +17 -10
- package/src/styles/components/ion-searchbar.scss +1 -1
- package/src/styles/components/ion-tabs.scss +14 -10
- package/src/styles/components/ion-toolbar.scss +9 -10
- package/src/styles/md-ion-list-inset.scss +2 -2
- package/src/styles/utils/dark/ion-list.scss +1 -1
- package/src/styles/utils/translucent.scss +44 -0
- package/src/tab-bar-searchable/animations/enter.ts +1 -2
- package/src/tab-bar-searchable/animations/leave.ts +1 -2
- package/src/tab-bar-searchable/index.ts +12 -4
- package/src/transition/ios.transition.ts +14 -473
- package/dist/css/utils/structured-list.css +0 -1
- package/dist/popover/animations/ios.enter.d.ts.map +0 -1
- package/dist/popover/popover-interface.js +0 -1
- package/dist/popover/utils.d.ts.map +0 -1
- package/src/styles/utils/structured-list.scss +0 -223
- /package/{dist → node_modules/@rdlabo/ionic-theme-utils/dist}/popover/animations/ios.leave.d.ts +0 -0
- /package/{dist → node_modules/@rdlabo/ionic-theme-utils/dist}/popover/callout-surface.d.ts +0 -0
- /package/{dist → node_modules/@rdlabo/ionic-theme-utils/dist}/popover/callout-surface.d.ts.map +0 -0
- /package/{dist → node_modules/@rdlabo/ionic-theme-utils/dist}/popover/popover-interface.d.ts +0 -0
- /package/{dist → node_modules/@rdlabo/ionic-theme-utils/dist}/popover/popover-interface.d.ts.map +0 -0
- /package/{dist → node_modules/@rdlabo/ionic-theme-utils/dist}/tab-bar-searchable/interfaces.d.ts +0 -0
- /package/{dist → node_modules/@rdlabo/ionic-theme-utils/dist}/tab-bar-searchable/interfaces.d.ts.map +0 -0
- /package/{dist → node_modules/@rdlabo/ionic-theme-utils/dist}/tab-bar-searchable/utils.d.ts +0 -0
- /package/{dist → node_modules/@rdlabo/ionic-theme-utils/dist}/tab-bar-searchable/utils.d.ts.map +0 -0
- /package/{src → node_modules/@rdlabo/ionic-theme-utils/src}/popover/callout-surface.ts +0 -0
- /package/{src → node_modules/@rdlabo/ionic-theme-utils/src}/popover/popover-interface.ts +0 -0
- /package/{src → node_modules/@rdlabo/ionic-theme-utils/src}/tab-bar-searchable/interfaces.ts +0 -0
- /package/{src → node_modules/@rdlabo/ionic-theme-utils/src}/tab-bar-searchable/utils.ts +0 -0
package/src/native/index.ts
CHANGED
|
@@ -1,32 +1,59 @@
|
|
|
1
1
|
import { Capacitor, registerPlugin } from '@capacitor/core';
|
|
2
|
-
import
|
|
2
|
+
import { setConfig } from '../transition/ios.transition';
|
|
3
|
+
import type { NativeUIShellHandle, NativeUIShellOptions, NativeUIShellPlugin, WebViewMetrics } from './definitions';
|
|
4
|
+
import { bindMetricsLifecycle } from './lifecycle';
|
|
3
5
|
import { createRuntime } from './runtime';
|
|
4
|
-
export type {
|
|
6
|
+
export type {
|
|
7
|
+
NativeUIShellComponent,
|
|
8
|
+
NativeUIShellControls,
|
|
9
|
+
NativeUIShellHandle,
|
|
10
|
+
NativeUIShellOptions,
|
|
11
|
+
NativeUIShellStatus,
|
|
12
|
+
NativeUIShellSuspension,
|
|
13
|
+
WebViewMetrics,
|
|
14
|
+
} from './definitions';
|
|
5
15
|
|
|
6
16
|
const plugin = registerPlugin<NativeUIShellPlugin>('IonicNativeUIShell');
|
|
7
17
|
let active: Promise<NativeUIShellHandle> | undefined;
|
|
8
18
|
const web = (reason: string): NativeUIShellHandle => ({
|
|
9
19
|
getStatus: () => ({ state: 'web', projected: 0, updates: 0, reason }),
|
|
20
|
+
suspend: async () => ({ resume: async () => {} }),
|
|
10
21
|
destroy: async () => {},
|
|
11
22
|
});
|
|
12
23
|
|
|
24
|
+
/** Reads the current native WebView geometry and applies it to page transitions. */
|
|
25
|
+
export const configureNativeTransition = async (): Promise<WebViewMetrics> => {
|
|
26
|
+
const metrics = typeof document !== 'undefined' && Capacitor.getPlatform() === 'ios' ? await plugin.getWebViewMetrics() : { radius: 0 };
|
|
27
|
+
setConfig({ radius: metrics.radius });
|
|
28
|
+
return metrics;
|
|
29
|
+
};
|
|
30
|
+
|
|
13
31
|
/** Call once at application startup. Ionic markup remains the source of truth. */
|
|
14
|
-
export const enableNativeUIShell = (): Promise<NativeUIShellHandle> => {
|
|
32
|
+
export const enableNativeUIShell = (options: NativeUIShellOptions = {}): Promise<NativeUIShellHandle> => {
|
|
33
|
+
if (options.enabled === false) {
|
|
34
|
+
const current = active;
|
|
35
|
+
active = undefined;
|
|
36
|
+
return current
|
|
37
|
+
? current.then(async (handle) => {
|
|
38
|
+
await handle.destroy();
|
|
39
|
+
return web('Disabled');
|
|
40
|
+
})
|
|
41
|
+
: Promise.resolve(web('Disabled'));
|
|
42
|
+
}
|
|
15
43
|
if (typeof document === 'undefined' || Capacitor.getPlatform() !== 'ios') return Promise.resolve(web('Requires Capacitor iOS'));
|
|
16
44
|
return (active ??= (async () => {
|
|
17
45
|
try {
|
|
46
|
+
await configureNativeTransition().catch(() => undefined);
|
|
18
47
|
if (!(await plugin.configure()).supported) {
|
|
19
48
|
active = undefined;
|
|
20
49
|
return web('Requires iOS 26 or later');
|
|
21
50
|
}
|
|
22
|
-
const runtime = await createRuntime(document, plugin);
|
|
23
|
-
return
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
},
|
|
29
|
-
};
|
|
51
|
+
const runtime = await createRuntime(document, plugin, options);
|
|
52
|
+
return await bindMetricsLifecycle(
|
|
53
|
+
runtime,
|
|
54
|
+
() => plugin.addListener('webViewMetricsChange', (metrics) => setConfig({ radius: metrics.radius })),
|
|
55
|
+
() => (active = undefined),
|
|
56
|
+
);
|
|
30
57
|
} catch (error) {
|
|
31
58
|
active = undefined;
|
|
32
59
|
return web(error instanceof Error ? error.message : String(error));
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { PluginListenerHandle } from '@capacitor/core';
|
|
2
|
+
import type { NativeUIShellHandle } from './definitions';
|
|
3
|
+
|
|
4
|
+
export const bindMetricsLifecycle = async (
|
|
5
|
+
runtime: NativeUIShellHandle,
|
|
6
|
+
listen: () => Promise<PluginListenerHandle>,
|
|
7
|
+
deactivate: () => void,
|
|
8
|
+
): Promise<NativeUIShellHandle> => {
|
|
9
|
+
let listener: PluginListenerHandle;
|
|
10
|
+
try {
|
|
11
|
+
listener = await listen();
|
|
12
|
+
} catch (error) {
|
|
13
|
+
await runtime.destroy();
|
|
14
|
+
throw error;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let destroying: Promise<void> | undefined;
|
|
18
|
+
return {
|
|
19
|
+
getStatus: runtime.getStatus,
|
|
20
|
+
suspend: runtime.suspend,
|
|
21
|
+
destroy() {
|
|
22
|
+
return (destroying ??= (async () => {
|
|
23
|
+
let removalError: unknown;
|
|
24
|
+
try {
|
|
25
|
+
await listener.remove();
|
|
26
|
+
} catch (error) {
|
|
27
|
+
removalError = error;
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
await runtime.destroy();
|
|
31
|
+
} finally {
|
|
32
|
+
deactivate();
|
|
33
|
+
}
|
|
34
|
+
if (removalError) throw removalError;
|
|
35
|
+
})());
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
};
|
package/src/native/runtime.ts
CHANGED
|
@@ -2,7 +2,14 @@ import type { PluginListenerHandle } from '@capacitor/core';
|
|
|
2
2
|
import { LIFECYCLE_WILL_ENTER, LIFECYCLE_WILL_LEAVE, LIFECYCLE_DID_ENTER, LIFECYCLE_DID_LEAVE } from '@ionic/core';
|
|
3
3
|
import { getNativeSearchBindings, setNativeUIShellIntegration } from '../native-integration';
|
|
4
4
|
import { createSearchSupport } from './components/searchable-tabs';
|
|
5
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
ShellActivation,
|
|
7
|
+
ShellSnapshot,
|
|
8
|
+
NativeUIShellHandle,
|
|
9
|
+
NativeUIShellOptions,
|
|
10
|
+
NativeUIShellPlugin,
|
|
11
|
+
NativeUIShellStatus,
|
|
12
|
+
} from './definitions';
|
|
6
13
|
import { readCandidate, selector, shadowSelector, motionSelector } from './components';
|
|
7
14
|
import { marker, unprojected } from './shared/dom';
|
|
8
15
|
import { createIconRenderer } from './shared/icons';
|
|
@@ -20,7 +27,11 @@ const bounded = <T>(promise: Promise<T>): Promise<T> =>
|
|
|
20
27
|
promise.then(resolve, reject).finally(() => clearTimeout(timer));
|
|
21
28
|
});
|
|
22
29
|
|
|
23
|
-
export const createRuntime = async (
|
|
30
|
+
export const createRuntime = async (
|
|
31
|
+
doc: Document,
|
|
32
|
+
plugin: NativeUIShellPlugin,
|
|
33
|
+
options: NativeUIShellOptions = {},
|
|
34
|
+
): Promise<NativeUIShellHandle> => {
|
|
24
35
|
const win = doc.defaultView!;
|
|
25
36
|
const icons = createIconRenderer();
|
|
26
37
|
const crossfade = createCrossfade(win);
|
|
@@ -30,6 +41,7 @@ export const createRuntime = async (doc: Document, plugin: NativeUIShellPlugin):
|
|
|
30
41
|
const suspended = new Set<HTMLElement[]>();
|
|
31
42
|
const pages = new Set<HTMLElement>();
|
|
32
43
|
const presented = new Set<HTMLElement>();
|
|
44
|
+
const manualSuspensions = new Set<symbol>();
|
|
33
45
|
const moving = new Map<HTMLElement, Set<string>>();
|
|
34
46
|
const observed = new Set<Element | ShadowRoot>();
|
|
35
47
|
const listeners = new AbortController();
|
|
@@ -52,6 +64,16 @@ export const createRuntime = async (doc: Document, plugin: NativeUIShellPlugin):
|
|
|
52
64
|
let listener: PluginListenerHandle | undefined;
|
|
53
65
|
let searchListener: PluginListenerHandle | undefined;
|
|
54
66
|
let waiters: (() => void)[] = [];
|
|
67
|
+
const control = (kind: Candidate['control']['kind']): keyof NonNullable<NativeUIShellOptions['controls']> => {
|
|
68
|
+
if (kind === 'ion-tab-bar') return 'tabs';
|
|
69
|
+
if (kind === 'ion-segment') return 'segment';
|
|
70
|
+
if (kind === 'ion-fab') return 'fab';
|
|
71
|
+
return 'toolbar';
|
|
72
|
+
};
|
|
73
|
+
const controlEnabled = (candidate: Candidate) => {
|
|
74
|
+
const controls = options.controls;
|
|
75
|
+
return controls === undefined || controls[control(candidate.control.kind)] === true;
|
|
76
|
+
};
|
|
55
77
|
const id = (element: Element) => {
|
|
56
78
|
let value = ids.get(element);
|
|
57
79
|
if (!value) {
|
|
@@ -91,6 +113,10 @@ export const createRuntime = async (doc: Document, plugin: NativeUIShellPlugin):
|
|
|
91
113
|
};
|
|
92
114
|
const search = createSearchSupport(doc, id, schedule);
|
|
93
115
|
const candidateSources = (candidate: Candidate) => candidate.sources ?? [candidate.element];
|
|
116
|
+
const readEnabledCandidate = (element: HTMLElement): Candidate | undefined => {
|
|
117
|
+
const candidate = readCandidate(element, id);
|
|
118
|
+
return candidate && controlEnabled(candidate) ? candidate : undefined;
|
|
119
|
+
};
|
|
94
120
|
const flush = async () => {
|
|
95
121
|
if (stopped) return;
|
|
96
122
|
schedule();
|
|
@@ -108,6 +134,7 @@ export const createRuntime = async (doc: Document, plugin: NativeUIShellPlugin):
|
|
|
108
134
|
const overlayOpen = () => {
|
|
109
135
|
for (const element of presented) if (!element.isConnected) presented.delete(element);
|
|
110
136
|
return (
|
|
137
|
+
manualSuspensions.size > 0 ||
|
|
111
138
|
presented.size > 0 ||
|
|
112
139
|
Array.from(doc.querySelectorAll(overlays)).some(
|
|
113
140
|
(element) => (element as Element & { presented?: boolean }).presented || element.classList.contains('show-menu'),
|
|
@@ -128,7 +155,7 @@ export const createRuntime = async (doc: Document, plugin: NativeUIShellPlugin):
|
|
|
128
155
|
.decorate(
|
|
129
156
|
Array.from(doc.querySelectorAll<HTMLElement>(selector))
|
|
130
157
|
.filter((element) => !blocked(element))
|
|
131
|
-
.map(
|
|
158
|
+
.map(readEnabledCandidate)
|
|
132
159
|
.filter((candidate): candidate is Candidate => !!candidate),
|
|
133
160
|
blocked,
|
|
134
161
|
)
|
|
@@ -375,6 +402,23 @@ export const createRuntime = async (doc: Document, plugin: NativeUIShellPlugin):
|
|
|
375
402
|
updates,
|
|
376
403
|
reason,
|
|
377
404
|
}),
|
|
405
|
+
async suspend() {
|
|
406
|
+
const token = Symbol();
|
|
407
|
+
let resumed = false;
|
|
408
|
+
if (!stopped) {
|
|
409
|
+
manualSuspensions.add(token);
|
|
410
|
+
getNativeSearchBindings(doc).forEach((binding) => search.retire(binding));
|
|
411
|
+
await flush();
|
|
412
|
+
}
|
|
413
|
+
return {
|
|
414
|
+
async resume() {
|
|
415
|
+
if (resumed) return;
|
|
416
|
+
resumed = true;
|
|
417
|
+
if (stopped || !manualSuspensions.delete(token)) return;
|
|
418
|
+
await flush();
|
|
419
|
+
},
|
|
420
|
+
};
|
|
421
|
+
},
|
|
378
422
|
async destroy() {
|
|
379
423
|
if (stopped) return;
|
|
380
424
|
stopped = true;
|
|
@@ -399,6 +443,7 @@ export const createRuntime = async (doc: Document, plugin: NativeUIShellPlugin):
|
|
|
399
443
|
icons.clear();
|
|
400
444
|
pages.clear();
|
|
401
445
|
presented.clear();
|
|
446
|
+
manualSuspensions.clear();
|
|
402
447
|
moving.clear();
|
|
403
448
|
suspended.clear();
|
|
404
449
|
await listener?.remove().catch(() => {});
|
|
@@ -427,7 +472,7 @@ export const createRuntime = async (doc: Document, plugin: NativeUIShellPlugin):
|
|
|
427
472
|
if (!element) return;
|
|
428
473
|
const owner = Array.from(sources.keys()).find((source) => source === element || source.contains(element));
|
|
429
474
|
if (!owner) return;
|
|
430
|
-
const direct = !blocked(owner) && unprojected(sources.keys(), () =>
|
|
475
|
+
const direct = !blocked(owner) && unprojected(sources.keys(), () => readEnabledCandidate(owner));
|
|
431
476
|
const candidate = direct || read().find((candidate) => candidate.actions.has(event.id));
|
|
432
477
|
const item = candidate?.control.items.find((item) => item.id === event.id);
|
|
433
478
|
const searchAction =
|
|
@@ -13,6 +13,9 @@ $scaleup-default-icon-only: api.$button-scaleup-default-icon-only;
|
|
|
13
13
|
$scaleup-large: 1.12;
|
|
14
14
|
$scaleup-large-icon-only: api.$button-scaleup-large-icon-only;
|
|
15
15
|
|
|
16
|
+
// Fit to the iOS 27 glass button's expansion: a small overshoot, settling at 380ms.
|
|
17
|
+
$press-transition: transform var(--ios-theme-button-press-duration, 380ms) cubic-bezier(0.37, 0.36, 0.03, 1.34);
|
|
18
|
+
|
|
16
19
|
@mixin theme-buttons {
|
|
17
20
|
@include api.glass-control-background;
|
|
18
21
|
border-radius: 25px;
|
|
@@ -24,14 +27,17 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only;
|
|
|
24
27
|
/**
|
|
25
28
|
* compare .header-collapse-main ion-toolbar.in-toolbar ion-title, .header-collapse-main ion-toolbar.in-toolbar ion-buttons
|
|
26
29
|
*/
|
|
27
|
-
transition:
|
|
30
|
+
transition: $press-transition;
|
|
28
31
|
|
|
29
32
|
z-index: 0;
|
|
30
33
|
|
|
31
34
|
&:has(.ion-activated) {
|
|
32
35
|
z-index: 5;
|
|
33
36
|
@include api.glass-background-button-activated;
|
|
37
|
+
}
|
|
34
38
|
|
|
39
|
+
// Follow the actual press so a short tap reverses before reaching full scale.
|
|
40
|
+
&:has(ion-button:active:not(.button-disabled), ion-menu-button:active:not([disabled])) {
|
|
35
41
|
// Hardware acceleration optimization for scale transforms
|
|
36
42
|
transform: scale($scaleup-default-icon-only) translateZ(0);
|
|
37
43
|
-webkit-transform: scale($scaleup-default-icon-only) translateZ(0);
|
|
@@ -141,7 +147,7 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only;
|
|
|
141
147
|
}
|
|
142
148
|
|
|
143
149
|
transition:
|
|
144
|
-
|
|
150
|
+
$press-transition,
|
|
145
151
|
color 50ms ease;
|
|
146
152
|
|
|
147
153
|
&.in-toolbar:not(.ion-color):not(.in-toolbar-color) {
|
|
@@ -247,8 +253,10 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only;
|
|
|
247
253
|
inset 0 -0.5px 0 rgba(255, 255, 255, 0.48),
|
|
248
254
|
0 0.5px 1px rgba(0, 0, 0, 0.12);
|
|
249
255
|
}
|
|
250
|
-
|
|
251
|
-
|
|
256
|
+
}
|
|
257
|
+
&:active:not(.button-disabled) {
|
|
258
|
+
&.button-has-icon-only,
|
|
259
|
+
&.back-button-has-icon-only {
|
|
252
260
|
transform: scale($scaleup-default-icon-only);
|
|
253
261
|
&.button-small {
|
|
254
262
|
transform: scale($scaleup-small-icon-only);
|
|
@@ -332,8 +340,10 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only;
|
|
|
332
340
|
&.ion-color {
|
|
333
341
|
--color: rgba(var(--ion-color-base-rgb, var(--ion-text-color-rgb, 0, 0, 0)), 0.1);
|
|
334
342
|
}
|
|
335
|
-
|
|
336
|
-
|
|
343
|
+
}
|
|
344
|
+
&:active:not(.button-disabled) {
|
|
345
|
+
&.button-has-icon-only,
|
|
346
|
+
&.back-button-has-icon-only {
|
|
337
347
|
transform: scale($scaleup-default-icon-only);
|
|
338
348
|
&.button-small {
|
|
339
349
|
transform: scale($scaleup-small-icon-only);
|
|
@@ -401,17 +411,18 @@ ion-buttons.ios:not(.ios-theme-disabled, .ios26-disabled):not(
|
|
|
401
411
|
ion-buttons.ios:not(.ios-theme-disabled, .ios26-disabled):not(
|
|
402
412
|
:has(ion-back-button, ion-button:not(.button-clear), ion-menu-button.menu-button-hidden)
|
|
403
413
|
) {
|
|
404
|
-
transition:
|
|
414
|
+
transition: $press-transition;
|
|
405
415
|
}
|
|
406
416
|
|
|
407
417
|
ion-buttons.ios:not(.ios-theme-disabled, .ios26-disabled):not(:has(ion-back-button, ion-button.button-clear)) {
|
|
408
418
|
ion-button {
|
|
409
|
-
margin: 0
|
|
419
|
+
margin-block: 0;
|
|
420
|
+
margin-inline: 6px;
|
|
410
421
|
&:first-child {
|
|
411
|
-
margin-
|
|
422
|
+
margin-inline-start: 0;
|
|
412
423
|
}
|
|
413
424
|
&:last-child {
|
|
414
|
-
margin-
|
|
425
|
+
margin-inline-end: 0;
|
|
415
426
|
}
|
|
416
427
|
&:only-child {
|
|
417
428
|
margin: 0;
|
|
@@ -6,7 +6,13 @@ $scaleup-default-icon-only: api.$button-scaleup-default-icon-only;
|
|
|
6
6
|
$scaleup-large-icon-only: api.$button-scaleup-large-icon-only;
|
|
7
7
|
|
|
8
8
|
ion-fab.ios:not(.ios-theme-disabled, .ios26-disabled) {
|
|
9
|
+
--ios-theme-safe-area-inline-start: var(--ion-safe-area-left, 0px);
|
|
10
|
+
--ios-theme-safe-area-inline-end: var(--ion-safe-area-right, 0px);
|
|
9
11
|
--transform-value: 2.5px;
|
|
12
|
+
&:dir(rtl) {
|
|
13
|
+
--ios-theme-safe-area-inline-start: var(--ion-safe-area-right, 0px);
|
|
14
|
+
--ios-theme-safe-area-inline-end: var(--ion-safe-area-left, 0px);
|
|
15
|
+
}
|
|
10
16
|
&:has(> ion-fab-button.fab-button-small) {
|
|
11
17
|
--transform-value: 4px;
|
|
12
18
|
}
|
|
@@ -85,20 +91,20 @@ ion-fab.ios:not(.ios-theme-disabled, .ios26-disabled) {
|
|
|
85
91
|
}
|
|
86
92
|
|
|
87
93
|
&.fab-horizontal-start {
|
|
88
|
-
|
|
94
|
+
inset-inline-start: calc(16px + var(--ios-theme-menu-width, var(--ios26-menu-width, var(--ios-theme-safe-area-inline-start))));
|
|
89
95
|
}
|
|
90
96
|
|
|
91
97
|
&.fab-horizontal-end {
|
|
92
|
-
|
|
98
|
+
inset-inline-end: calc(16px + var(--ios-theme-safe-area-inline-end));
|
|
93
99
|
}
|
|
94
100
|
|
|
95
101
|
&:has(.fab-button-small) {
|
|
96
102
|
&.fab-horizontal-start {
|
|
97
|
-
|
|
103
|
+
inset-inline-start: calc(10px + var(--ios-theme-menu-width, var(--ios26-menu-width, var(--ios-theme-safe-area-inline-start))));
|
|
98
104
|
}
|
|
99
105
|
|
|
100
106
|
&.fab-horizontal-end {
|
|
101
|
-
|
|
107
|
+
inset-inline-end: calc(10px + var(--ios-theme-safe-area-inline-end));
|
|
102
108
|
}
|
|
103
109
|
}
|
|
104
110
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
@use '
|
|
1
|
+
@use 'pkg:@rdlabo/ionic-theme-utils/styles/structured-list';
|
|
2
2
|
|
|
3
3
|
ion-list.ios:not(.ios-theme-disabled, .ios26-disabled) {
|
|
4
4
|
--ion-border-color: var(--ion-color-step-100, var(--ion-background-color-step-100, #e8e8e8));
|
|
@@ -11,7 +11,7 @@ ion-list.ios:not(.ios-theme-disabled, .ios26-disabled) {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
ion-list.list-inset.ios:not(.ios-theme-disabled, .ios26-disabled) {
|
|
14
|
-
@include structured-list.layout(20px, 28px);
|
|
14
|
+
@include structured-list.layout(20px, 28px, $variant: ios27);
|
|
15
15
|
|
|
16
16
|
ion-radio-group,
|
|
17
17
|
ion-reorder-group {
|
|
@@ -23,13 +23,22 @@ ion-list.list-inset.ios:not(.ios-theme-disabled, .ios26-disabled) {
|
|
|
23
23
|
padding-inline-end: calc(var(--ion-safe-area-right, 0) + 20px);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
&:dir(rtl) ion-radio-group > .radio-group-top {
|
|
27
|
+
padding-inline-start: calc(var(--ion-safe-area-right, 0) + 20px);
|
|
28
|
+
padding-inline-end: calc(var(--ion-safe-area-left, 0) + 20px);
|
|
29
|
+
}
|
|
30
|
+
|
|
26
31
|
> :is(#{structured-list.$groups}) {
|
|
27
32
|
ion-item {
|
|
28
33
|
// To draw lines inside
|
|
29
34
|
--inner-padding-end: 0;
|
|
30
35
|
|
|
31
36
|
&::part(native) {
|
|
32
|
-
padding-
|
|
37
|
+
padding-inline-end: calc(var(--ion-safe-area-right, 0px) + 18px);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
&:dir(rtl)::part(native) {
|
|
41
|
+
padding-inline-end: calc(var(--ion-safe-area-left, 0px) + 18px);
|
|
33
42
|
}
|
|
34
43
|
|
|
35
44
|
--min-height: 52px;
|
|
@@ -6,13 +6,13 @@ ion-split-pane.ios:not(.ios-theme-disabled, .ios26-disabled).split-pane-visible:
|
|
|
6
6
|
.split-pane-main {
|
|
7
7
|
ion-tab-bar.ios:not(.ios-theme-disabled, .ios26-disabled) {
|
|
8
8
|
width: calc(
|
|
9
|
-
100% - calc(18px + var(--ion-safe-area-left, 0px)) - calc(18px + var(--ion-safe-area-
|
|
9
|
+
100% - calc(18px + var(--ion-safe-area-left, 0px)) - calc(18px + var(--ion-safe-area-right, 0px)) - 60px -
|
|
10
10
|
12px - var(--ios-theme-menu-width, var(--ios26-menu-width))
|
|
11
11
|
);
|
|
12
12
|
|
|
13
13
|
&:has(:nth-child(5)) {
|
|
14
14
|
width: calc(
|
|
15
|
-
100% - calc(18px + var(--ion-safe-area-left, 0px)) - calc(18px + var(--ion-safe-area-
|
|
15
|
+
100% - calc(18px + var(--ion-safe-area-left, 0px)) - calc(18px + var(--ion-safe-area-right, 0px)) - var(
|
|
16
16
|
--ios-theme-menu-width,
|
|
17
17
|
var(--ios26-menu-width)
|
|
18
18
|
)
|
|
@@ -31,7 +31,7 @@ ion-split-pane.ios:not(.ios-theme-disabled, .ios26-disabled).split-pane-visible:
|
|
|
31
31
|
/*
|
|
32
32
|
* 90px: https://github.com/ionic-team/ionic-framework/blob/main/core/src/components/title/title.ios.scss#L8
|
|
33
33
|
*/
|
|
34
|
-
padding-
|
|
34
|
+
padding-inline-start: calc(90px + var(--ios-theme-menu-width, var(--ios26-menu-width)));
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
ion-content {
|
|
@@ -45,7 +45,10 @@ ion-split-pane.ios:not(.ios-theme-disabled, .ios26-disabled).split-pane-visible:
|
|
|
45
45
|
}
|
|
46
46
|
ion-tab-bar.ios:not(.ios-theme-disabled, .ios26-disabled) {
|
|
47
47
|
&[slot='bottom'] {
|
|
48
|
-
|
|
48
|
+
inset-inline-start: calc(16px + var(--ion-safe-area-left, 0px) + var(--ios-theme-menu-width, var(--ios26-menu-width)));
|
|
49
|
+
&:dir(rtl) {
|
|
50
|
+
inset-inline-start: calc(16px + var(--ion-safe-area-right, 0px) + var(--ios-theme-menu-width, var(--ios26-menu-width)));
|
|
51
|
+
}
|
|
49
52
|
}
|
|
50
53
|
}
|
|
51
54
|
}
|
|
@@ -62,7 +65,7 @@ ion-split-pane.ios:not(.ios-theme-disabled, .ios26-disabled).split-pane-visible:
|
|
|
62
65
|
/*
|
|
63
66
|
* 90px: https://github.com/ionic-team/ionic-framework/blob/main/core/src/components/title/title.ios.scss#L8
|
|
64
67
|
*/
|
|
65
|
-
padding-
|
|
68
|
+
padding-inline-end: calc(90px + var(--ios-theme-menu-width, var(--ios26-menu-width)));
|
|
66
69
|
}
|
|
67
70
|
}
|
|
68
71
|
ion-content {
|
|
@@ -88,10 +91,10 @@ ion-menu.ios:not(.ios-theme-disabled, .ios26-disabled) {
|
|
|
88
91
|
z-index: 999;
|
|
89
92
|
|
|
90
93
|
&.menu-side-start {
|
|
91
|
-
|
|
94
|
+
inset-inline-start: 0;
|
|
92
95
|
}
|
|
93
96
|
&.menu-side-end {
|
|
94
|
-
|
|
97
|
+
inset-inline-end: 0;
|
|
95
98
|
}
|
|
96
99
|
|
|
97
100
|
&::part(backdrop) {
|
|
@@ -119,9 +122,13 @@ ion-menu.ios:not(.ios-theme-disabled, .ios26-disabled) {
|
|
|
119
122
|
--ios-theme-content-box-shadow-rgb: var(--ios26-content-box-shadow-rgb);
|
|
120
123
|
|
|
121
124
|
&::part(scroll) {
|
|
122
|
-
margin: calc(var(--ios-theme-floating-safe-area-top, var(--ios26-floating-safe-area-top)) + 6px)
|
|
123
|
-
|
|
124
|
-
|
|
125
|
+
margin-block: calc(var(--ios-theme-floating-safe-area-top, var(--ios26-floating-safe-area-top)) + 6px)
|
|
126
|
+
var(--ios-theme-floating-safe-area-bottom, var(--ios26-floating-safe-area-bottom));
|
|
127
|
+
margin-inline: calc(12px + var(--ion-safe-area-left, 0px)) calc(16px + var(--ion-safe-area-right, 0px));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
&:dir(rtl)::part(scroll) {
|
|
131
|
+
margin-inline: calc(12px + var(--ion-safe-area-right, 0px)) calc(16px + var(--ion-safe-area-left, 0px));
|
|
125
132
|
}
|
|
126
133
|
}
|
|
127
134
|
}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
@use '../utils/api';
|
|
2
2
|
|
|
3
3
|
ion-tab-bar.ios:not(.ios-theme-disabled, .ios26-disabled) {
|
|
4
|
+
--ios-theme-safe-area-inline-start: var(--ion-safe-area-left, 0px);
|
|
5
|
+
--ios-theme-safe-area-inline-end: var(--ion-safe-area-right, 0px);
|
|
6
|
+
&:dir(rtl) {
|
|
7
|
+
--ios-theme-safe-area-inline-start: var(--ion-safe-area-right, 0px);
|
|
8
|
+
--ios-theme-safe-area-inline-end: var(--ion-safe-area-left, 0px);
|
|
9
|
+
}
|
|
4
10
|
// Ionic forces content-box on the host. Keep the Glass border in a
|
|
5
11
|
// separate layer so its physical-pixel rounding cannot resize the bar.
|
|
6
12
|
border: 0;
|
|
@@ -29,26 +35,24 @@ ion-tab-bar.ios:not(.ios-theme-disabled, .ios26-disabled) {
|
|
|
29
35
|
&[slot='top'] {
|
|
30
36
|
position: absolute;
|
|
31
37
|
top: var(--ios-theme-floating-safe-area-top, var(--ios26-floating-safe-area-top));
|
|
32
|
-
|
|
38
|
+
inset-inline-end: calc(16px + var(--ios-theme-safe-area-inline-end));
|
|
33
39
|
}
|
|
34
40
|
|
|
35
41
|
&[slot='bottom'] {
|
|
36
42
|
position: absolute;
|
|
37
43
|
bottom: var(--ios-theme-floating-safe-area-bottom, var(--ios26-floating-safe-area-bottom));
|
|
38
|
-
|
|
44
|
+
inset-inline-start: calc(16px + var(--ios-theme-safe-area-inline-start));
|
|
39
45
|
}
|
|
40
46
|
|
|
41
|
-
&.tab-bar-position-start
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
right: auto;
|
|
47
|
+
&.tab-bar-position-start {
|
|
48
|
+
inset-inline-start: calc(16px + var(--ios-theme-safe-area-inline-start));
|
|
49
|
+
inset-inline-end: auto;
|
|
45
50
|
margin-inline: 0;
|
|
46
51
|
}
|
|
47
52
|
|
|
48
|
-
&.tab-bar-position-end
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
right: calc(16px + var(--ion-safe-area-right, 0px));
|
|
53
|
+
&.tab-bar-position-end {
|
|
54
|
+
inset-inline-start: auto;
|
|
55
|
+
inset-inline-end: calc(16px + var(--ios-theme-safe-area-inline-end));
|
|
52
56
|
margin-inline: 0;
|
|
53
57
|
}
|
|
54
58
|
|
|
@@ -57,27 +57,29 @@ ion-toolbar.ios:not(.ios-theme-disabled, .ios26-disabled).toolbar-searchbar {
|
|
|
57
57
|
}
|
|
58
58
|
&:has(ion-buttons[slot='start']) {
|
|
59
59
|
ion-buttons[slot='start'] {
|
|
60
|
-
margin-
|
|
60
|
+
margin-inline-end: 6px;
|
|
61
61
|
}
|
|
62
62
|
ion-searchbar.ios:not(.ios-theme-disabled, .ios26-disabled) {
|
|
63
63
|
&:not(.searchbar-classic) {
|
|
64
64
|
padding-inline: 6px 12px;
|
|
65
65
|
}
|
|
66
66
|
&.searchbar-classic .searchbar-input-container {
|
|
67
|
-
margin: 0
|
|
67
|
+
margin-block: 0;
|
|
68
|
+
margin-inline: 6px 12px;
|
|
68
69
|
}
|
|
69
70
|
}
|
|
70
71
|
}
|
|
71
72
|
&:has(ion-buttons[slot='end']) {
|
|
72
73
|
ion-buttons[slot='end'] {
|
|
73
|
-
margin-
|
|
74
|
+
margin-inline-start: 6px;
|
|
74
75
|
}
|
|
75
76
|
ion-searchbar.ios:not(.ios-theme-disabled, .ios26-disabled) {
|
|
76
77
|
&:not(.searchbar-classic) {
|
|
77
78
|
padding-inline: 12px 6px;
|
|
78
79
|
}
|
|
79
80
|
&.searchbar-classic .searchbar-input-container {
|
|
80
|
-
margin: 0
|
|
81
|
+
margin-block: 0;
|
|
82
|
+
margin-inline: 12px 6px;
|
|
81
83
|
}
|
|
82
84
|
}
|
|
83
85
|
}
|
|
@@ -85,15 +87,12 @@ ion-toolbar.ios:not(.ios-theme-disabled, .ios26-disabled).toolbar-searchbar {
|
|
|
85
87
|
|
|
86
88
|
ion-toolbar.ios:not(.ios-theme-disabled, .ios26-disabled) {
|
|
87
89
|
ion-buttons {
|
|
88
|
-
margin-
|
|
89
|
-
margin-right: 12px;
|
|
90
|
+
margin-inline: 12px;
|
|
90
91
|
}
|
|
91
92
|
ion-back-button {
|
|
92
|
-
margin-
|
|
93
|
-
margin-right: 12px;
|
|
93
|
+
margin-inline: 12px;
|
|
94
94
|
}
|
|
95
95
|
ion-buttons > ion-back-button {
|
|
96
|
-
margin-
|
|
97
|
-
margin-right: 0;
|
|
96
|
+
margin-inline: 0;
|
|
98
97
|
}
|
|
99
98
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
@use 'utils/structured-list';
|
|
1
|
+
@use 'pkg:@rdlabo/ionic-theme-utils/styles/structured-list';
|
|
2
2
|
|
|
3
3
|
ion-list.md {
|
|
4
4
|
@include structured-list.support-text;
|
|
5
5
|
|
|
6
6
|
&.list-inset {
|
|
7
|
-
@include structured-list.layout(8px, 16px);
|
|
7
|
+
@include structured-list.layout(8px, 16px, $variant: ios27);
|
|
8
8
|
:is(#{structured-list.$groups}) ion-item {
|
|
9
9
|
& > ion-input[labelplacement='floating'] {
|
|
10
10
|
transition: transform 200ms ease;
|
|
@@ -20,6 +20,18 @@ ion-footer.ios:not(.ios-theme-disabled, .ios26-disabled).footer-translucent {
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
.ion-page:has(> ion-content.ios.content-fullscreen) > ion-header.ios:not(.ios-theme-disabled, .ios26-disabled):not(.header-translucent),
|
|
24
|
+
.ion-page:has(> ion-content.ios.content-fullscreen) > ion-footer.ios:not(.ios-theme-disabled, .ios26-disabled):not(.footer-translucent) {
|
|
25
|
+
ion-toolbar.ios:not(.ios-theme-disabled, .ios26-disabled) {
|
|
26
|
+
--background: transparent;
|
|
27
|
+
--opacity: 1;
|
|
28
|
+
|
|
29
|
+
&::part(background) {
|
|
30
|
+
--opacity: 0;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
23
35
|
ion-header.ios:not(.ios-theme-disabled, .ios26-disabled).header-translucent:not(.header-collapse-condense) {
|
|
24
36
|
&:has(> ion-toolbar.ios:not(.ios-theme-disabled, .ios26-disabled) > *)::before {
|
|
25
37
|
height: 100%;
|
|
@@ -40,6 +52,27 @@ ion-header.ios:not(.ios-theme-disabled, .ios26-disabled).header-translucent:not(
|
|
|
40
52
|
}
|
|
41
53
|
}
|
|
42
54
|
|
|
55
|
+
.ion-page:has(> ion-content.ios.content-fullscreen) > ion-footer.ios:not(.ios-theme-disabled, .ios26-disabled).footer-translucent {
|
|
56
|
+
&:has(> ion-toolbar.ios:not(.ios-theme-disabled, .ios26-disabled) > *)::before {
|
|
57
|
+
bottom: 0;
|
|
58
|
+
height: 100%;
|
|
59
|
+
background: rgba(
|
|
60
|
+
var(--ion-color-base-rgb, var(--ios-theme-content-box-shadow-rgb, var(--ios26-content-box-shadow-rgb))),
|
|
61
|
+
calc(0.2 * var(--opacity-scale, 1))
|
|
62
|
+
);
|
|
63
|
+
backdrop-filter: blur(8px);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
&:not(.ion-no-border) > ion-toolbar.ios:not(.ios-theme-disabled, .ios26-disabled):has(> *):first-of-type {
|
|
67
|
+
--border-width: 0.5px 0 0;
|
|
68
|
+
--border-color: var(--ion-toolbar-border-color, rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.08));
|
|
69
|
+
&::part(background) {
|
|
70
|
+
--opacity: 1;
|
|
71
|
+
background: transparent;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
43
76
|
ion-header.ios:not(.ios-theme-disabled, .ios26-disabled).header-collapse-main ion-toolbar.in-toolbar ion-title {
|
|
44
77
|
transition:
|
|
45
78
|
opacity 0.5s ease-in-out,
|
|
@@ -58,6 +91,8 @@ ion-header.ios:not(.ios-theme-disabled, .ios26-disabled).header-collapse-condens
|
|
|
58
91
|
|
|
59
92
|
ion-header.ios:not(.ios-theme-disabled, .ios26-disabled).header-translucent::before,
|
|
60
93
|
ion-header.ios:not(.ios-theme-disabled, .ios26-disabled).header-translucent::after,
|
|
94
|
+
.ion-page:has(> ion-content.ios.content-fullscreen) > ion-footer.ios:not(.ios-theme-disabled, .ios26-disabled).footer-translucent::before,
|
|
95
|
+
.ion-page:has(> ion-content.ios.content-fullscreen) > ion-footer.ios:not(.ios-theme-disabled, .ios26-disabled).footer-translucent::after,
|
|
61
96
|
ion-content.ios:not(.ios-theme-disabled, .ios26-disabled).content-fullscreen::part(background)::before {
|
|
62
97
|
content: '';
|
|
63
98
|
position: absolute;
|
|
@@ -84,6 +119,15 @@ ion-header.ios:not(.ios-theme-disabled, .ios26-disabled).header-translucent::aft
|
|
|
84
119
|
mask-composite: intersect;
|
|
85
120
|
}
|
|
86
121
|
|
|
122
|
+
.ion-page:has(> ion-content.ios.content-fullscreen) > ion-footer.ios:not(.ios-theme-disabled, .ios26-disabled).footer-translucent::after {
|
|
123
|
+
z-index: 2;
|
|
124
|
+
bottom: 0;
|
|
125
|
+
height: 100%;
|
|
126
|
+
backdrop-filter: blur(2px);
|
|
127
|
+
mask-image: linear-gradient(rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 20%);
|
|
128
|
+
mask-composite: intersect;
|
|
129
|
+
}
|
|
130
|
+
|
|
87
131
|
/**
|
|
88
132
|
* ここから下は、ion-content::beforeが content:'' を持たない限り表示されない
|
|
89
133
|
*/
|