@rdlabo/ionic-theme-ios27 1.0.4 → 1.1.0-beta.pr224.shac63de393e27b
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-toggle.css +1 -1
- package/dist/css/ionic-theme-ios27.css +1 -1
- package/dist/native/components/searchable-tabs.d.ts.map +1 -1
- package/dist/native/components/searchable-tabs.js +2 -0
- package/dist/native/runtime.d.ts.map +1 -1
- package/dist/native/runtime.js +73 -7
- package/dist/native/shared/crossfade.d.ts +2 -2
- package/dist/native/shared/crossfade.d.ts.map +1 -1
- package/dist/native/shared/crossfade.js +3 -3
- package/dist/segment/index.d.ts.map +1 -1
- package/dist/segment/index.js +7 -0
- package/docs/animation.md +2 -2
- package/docs/native-ui-shell.md +2 -0
- package/package.json +2 -5
- package/src/native/components/searchable-tabs.ts +3 -0
- package/src/native/runtime.ts +81 -6
- package/src/native/shared/crossfade.ts +4 -3
- package/src/segment/index.ts +11 -0
- package/src/styles/components/ion-toggle.scss +8 -2
- package/src/tab-bar-searchable/index.ts +1 -1
- package/node_modules/@rdlabo/ionic-theme-utils/LICENSE +0 -21
- package/node_modules/@rdlabo/ionic-theme-utils/README.md +0 -28
- package/node_modules/@rdlabo/ionic-theme-utils/dist/dom.d.ts +0 -3
- package/node_modules/@rdlabo/ionic-theme-utils/dist/dom.d.ts.map +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/dist/dom.js +0 -13
- package/node_modules/@rdlabo/ionic-theme-utils/dist/dom.js.map +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/dist/focus-controller.d.ts +0 -6
- package/node_modules/@rdlabo/ionic-theme-utils/dist/focus-controller.d.ts.map +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/dist/focus-controller.js +0 -37
- package/node_modules/@rdlabo/ionic-theme-utils/dist/focus-controller.js.map +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/dist/index.d.ts +0 -13
- package/node_modules/@rdlabo/ionic-theme-utils/dist/index.d.ts.map +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/dist/index.js +0 -11
- package/node_modules/@rdlabo/ionic-theme-utils/dist/index.js.map +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/animations/ios.enter.d.ts +0 -3
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/animations/ios.enter.d.ts.map +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/animations/ios.enter.js +0 -196
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/animations/ios.enter.js.map +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/animations/ios.leave.d.ts +0 -3
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/animations/ios.leave.d.ts.map +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/animations/ios.leave.js +0 -80
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/animations/ios.leave.js.map +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/callout-surface.d.ts +0 -2
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/callout-surface.d.ts.map +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/callout-surface.js +0 -45
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/callout-surface.js.map +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/popover-interface.d.ts +0 -38
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/popover-interface.d.ts.map +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/popover-interface.js +0 -2
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/popover-interface.js.map +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/utils.d.ts +0 -38
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/utils.d.ts.map +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/utils.js +0 -378
- package/node_modules/@rdlabo/ionic-theme-utils/dist/popover/utils.js.map +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/dist/sheets-of-glass.d.ts +0 -16
- package/node_modules/@rdlabo/ionic-theme-utils/dist/sheets-of-glass.d.ts.map +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/dist/sheets-of-glass.js +0 -2
- package/node_modules/@rdlabo/ionic-theme-utils/dist/sheets-of-glass.js.map +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/dist/tab-bar-searchable/interfaces.d.ts +0 -41
- package/node_modules/@rdlabo/ionic-theme-utils/dist/tab-bar-searchable/interfaces.d.ts.map +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/dist/tab-bar-searchable/interfaces.js +0 -6
- package/node_modules/@rdlabo/ionic-theme-utils/dist/tab-bar-searchable/interfaces.js.map +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/dist/tab-bar-searchable/utils.d.ts +0 -12
- package/node_modules/@rdlabo/ionic-theme-utils/dist/tab-bar-searchable/utils.d.ts.map +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/dist/tab-bar-searchable/utils.js +0 -61
- package/node_modules/@rdlabo/ionic-theme-utils/dist/tab-bar-searchable/utils.js.map +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/dist/theme.d.ts +0 -15
- package/node_modules/@rdlabo/ionic-theme-utils/dist/theme.d.ts.map +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/dist/theme.js +0 -49
- package/node_modules/@rdlabo/ionic-theme-utils/dist/theme.js.map +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/dist/transition/ios.transition.d.ts +0 -18
- package/node_modules/@rdlabo/ionic-theme-utils/dist/transition/ios.transition.d.ts.map +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/dist/transition/ios.transition.js +0 -412
- package/node_modules/@rdlabo/ionic-theme-utils/dist/transition/ios.transition.js.map +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/package.json +0 -68
- package/node_modules/@rdlabo/ionic-theme-utils/scripts/copy-structured-list.mjs +0 -17
- package/node_modules/@rdlabo/ionic-theme-utils/src/dom.spec.ts +0 -19
- package/node_modules/@rdlabo/ionic-theme-utils/src/dom.ts +0 -16
- package/node_modules/@rdlabo/ionic-theme-utils/src/focus-controller.ts +0 -38
- package/node_modules/@rdlabo/ionic-theme-utils/src/index.ts +0 -59
- package/node_modules/@rdlabo/ionic-theme-utils/src/popover/animations/ios.enter.ts +0 -259
- package/node_modules/@rdlabo/ionic-theme-utils/src/popover/animations/ios.leave.ts +0 -99
- package/node_modules/@rdlabo/ionic-theme-utils/src/popover/callout-surface.ts +0 -54
- package/node_modules/@rdlabo/ionic-theme-utils/src/popover/popover-interface.ts +0 -44
- package/node_modules/@rdlabo/ionic-theme-utils/src/popover/utils.spec.ts +0 -58
- package/node_modules/@rdlabo/ionic-theme-utils/src/popover/utils.ts +0 -698
- package/node_modules/@rdlabo/ionic-theme-utils/src/sheets-of-glass.ts +0 -17
- package/node_modules/@rdlabo/ionic-theme-utils/src/styles/index.scss +0 -1
- package/node_modules/@rdlabo/ionic-theme-utils/src/styles/md-ion-list-inset.scss +0 -20
- package/node_modules/@rdlabo/ionic-theme-utils/src/styles/structured-list.scss +0 -310
- package/node_modules/@rdlabo/ionic-theme-utils/src/tab-bar-searchable/interfaces.ts +0 -28
- package/node_modules/@rdlabo/ionic-theme-utils/src/tab-bar-searchable/utils.spec.ts +0 -56
- package/node_modules/@rdlabo/ionic-theme-utils/src/tab-bar-searchable/utils.ts +0 -75
- package/node_modules/@rdlabo/ionic-theme-utils/src/theme.ts +0 -51
- package/node_modules/@rdlabo/ionic-theme-utils/src/transition/ios.transition.spec.ts +0 -52
- package/node_modules/@rdlabo/ionic-theme-utils/src/transition/ios.transition.ts +0 -542
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"searchable-tabs.d.ts","sourceRoot":"","sources":["../../../src/native/components/searchable-tabs.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAGpE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAA0B,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAmB/E,eAAO,MAAM,mBAAmB,GAAI,KAAK,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,EAAE,UAAU,MAAM,IAAI;sBA8InF,OAAO;;yBAmBJ,SAAS,EAAE,WAAW,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,GAAG,SAAS,EAAE;yBAlJhE,mBAAmB;;
|
|
1
|
+
{"version":3,"file":"searchable-tabs.d.ts","sourceRoot":"","sources":["../../../src/native/components/searchable-tabs.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAGpE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAA0B,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAmB/E,eAAO,MAAM,mBAAmB,GAAI,KAAK,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,EAAE,UAAU,MAAM,IAAI;sBA8InF,OAAO;;yBAmBJ,SAAS,EAAE,WAAW,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,GAAG,SAAS,EAAE;yBAlJhE,mBAAmB;;mBA0U9B,mBAAmB,YAAY,MAAM;uBAKjC,mBAAmB,UAAU,OAAO;qBAUtC,WAAW;gBAGhB,MAAM,EAAE;iBASP,gBAAgB;oBAqCb,mBAAmB;;CAoBtC,CAAC"}
|
|
@@ -284,6 +284,8 @@ export const createSearchSupport = (doc, id, schedule) => {
|
|
|
284
284
|
}
|
|
285
285
|
field.label = '';
|
|
286
286
|
field.accessibilityLabel = bar.getAttribute('aria-label') ?? input.getAttribute('aria-label') ?? 'Search';
|
|
287
|
+
if (!trigger.accessibilityLabel)
|
|
288
|
+
trigger.accessibilityLabel = field.accessibilityLabel;
|
|
287
289
|
state.layout = JSON.stringify([
|
|
288
290
|
innerWidth,
|
|
289
291
|
innerHeight,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/native/runtime.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAGV,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EAEpB,MAAM,eAAe,CAAC;AAkBvB,eAAO,MAAM,aAAa,GACxB,KAAK,QAAQ,EACb,QAAQ,mBAAmB,EAC3B,UAAS,oBAAyB,KACjC,OAAO,CAAC,mBAAmB,
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/native/runtime.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAGV,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EAEpB,MAAM,eAAe,CAAC;AAkBvB,eAAO,MAAM,aAAa,GACxB,KAAK,QAAQ,EACb,QAAQ,mBAAmB,EAC3B,UAAS,oBAAyB,KACjC,OAAO,CAAC,mBAAmB,CA+jB7B,CAAC"}
|
package/dist/native/runtime.js
CHANGED
|
@@ -39,6 +39,11 @@ export const createRuntime = async (doc, plugin, options = {}) => {
|
|
|
39
39
|
let dirty = false;
|
|
40
40
|
let pending = false;
|
|
41
41
|
let stopped = false;
|
|
42
|
+
let tabSwitchHandoff = false;
|
|
43
|
+
let handoffUntil = 0;
|
|
44
|
+
let handoffAcrossPending = false;
|
|
45
|
+
let handoffInstant = false;
|
|
46
|
+
let modalPresentHandoff = false;
|
|
42
47
|
let frame = 0;
|
|
43
48
|
let updates = 0;
|
|
44
49
|
let reason;
|
|
@@ -75,7 +80,7 @@ export const createRuntime = async (doc, plugin, options = {}) => {
|
|
|
75
80
|
search.release(element);
|
|
76
81
|
element.removeAttribute(marker);
|
|
77
82
|
if (!stopped)
|
|
78
|
-
crossfade.play(element, false);
|
|
83
|
+
crossfade.play(element, false, handoffInstant);
|
|
79
84
|
if (element.getAttribute('aria-hidden') === 'true') {
|
|
80
85
|
const previous = sources.get(element);
|
|
81
86
|
if (previous == null)
|
|
@@ -186,6 +191,8 @@ export const createRuntime = async (doc, plugin, options = {}) => {
|
|
|
186
191
|
frame = 0;
|
|
187
192
|
dirty = false;
|
|
188
193
|
pending = true;
|
|
194
|
+
handoffInstant = tabSwitchHandoff || handoffAcrossPending || modalPresentHandoff || win.performance.now() < handoffUntil;
|
|
195
|
+
modalPresentHandoff = false;
|
|
189
196
|
try {
|
|
190
197
|
const size = `${win.innerWidth}:${win.innerHeight}`;
|
|
191
198
|
if (viewport !== size) {
|
|
@@ -208,15 +215,17 @@ export const createRuntime = async (doc, plugin, options = {}) => {
|
|
|
208
215
|
const removed = Array.from(sources.keys()).filter((element) => !retained.has(element));
|
|
209
216
|
if (removed.length) {
|
|
210
217
|
removed.forEach(restore);
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
218
|
+
if (!handoffInstant) {
|
|
219
|
+
await painted();
|
|
220
|
+
if (stopped || dirty)
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
214
223
|
}
|
|
215
224
|
const data = { viewportWidth: win.innerWidth, controls: candidates.map((candidate) => candidate.control) };
|
|
216
225
|
const serialized = JSON.stringify(data);
|
|
217
226
|
if (serialized === lastSnapshot && !forceRefresh)
|
|
218
227
|
return;
|
|
219
|
-
const snapshot = { ...data, revision: ++revision, transitionDuration: crossfade.duration() };
|
|
228
|
+
const snapshot = { ...data, revision: ++revision, transitionDuration: crossfade.duration(handoffInstant) };
|
|
220
229
|
forceRefresh = false;
|
|
221
230
|
updates++;
|
|
222
231
|
updatingRevision = snapshot.revision;
|
|
@@ -255,7 +264,7 @@ export const createRuntime = async (doc, plugin, options = {}) => {
|
|
|
255
264
|
for (const element of accepted.flatMap(candidateSources)) {
|
|
256
265
|
if (!sources.has(element)) {
|
|
257
266
|
sources.set(element, element.getAttribute('aria-hidden'));
|
|
258
|
-
crossfade.play(element, true);
|
|
267
|
+
crossfade.play(element, true, handoffInstant);
|
|
259
268
|
element.setAttribute(marker, '');
|
|
260
269
|
element.setAttribute('aria-hidden', 'true');
|
|
261
270
|
element.dispatchEvent(new CustomEvent('nativeUIShellChange'));
|
|
@@ -278,6 +287,10 @@ export const createRuntime = async (doc, plugin, options = {}) => {
|
|
|
278
287
|
pendingActivations = [];
|
|
279
288
|
if (forceRefresh)
|
|
280
289
|
rejected = new WeakMap();
|
|
290
|
+
if (!stopped && (handoffAcrossPending || (handoffInstant && dirty))) {
|
|
291
|
+
handoffUntil = Math.max(handoffUntil, win.performance.now() + 400);
|
|
292
|
+
}
|
|
293
|
+
handoffAcrossPending = false;
|
|
281
294
|
pending = false;
|
|
282
295
|
if (dirty && !stopped)
|
|
283
296
|
schedule();
|
|
@@ -301,12 +314,56 @@ export const createRuntime = async (doc, plugin, options = {}) => {
|
|
|
301
314
|
getNativeSearchBindings(doc)
|
|
302
315
|
.filter((binding) => page.contains(binding.footer))
|
|
303
316
|
.forEach((binding) => search.retire(binding));
|
|
317
|
+
if (event.type === LIFECYCLE_WILL_LEAVE)
|
|
318
|
+
beginTabSwitchHandoffIfNeeded(page);
|
|
304
319
|
pages.add(page);
|
|
305
320
|
schedule();
|
|
306
321
|
};
|
|
307
322
|
const pageDid = (event) => {
|
|
308
323
|
pages.delete(event.target);
|
|
309
324
|
schedule();
|
|
325
|
+
if (tabSwitchHandoff && pages.size === 0)
|
|
326
|
+
endTabSwitchHandoff();
|
|
327
|
+
};
|
|
328
|
+
const tabOfPath = (tabs, pathname) => {
|
|
329
|
+
let best;
|
|
330
|
+
for (const button of Array.from(tabs.querySelectorAll('ion-tab-button'))) {
|
|
331
|
+
const tab = button.getAttribute('tab');
|
|
332
|
+
const href = button.getAttribute('href')?.split(/[?#]/)[0];
|
|
333
|
+
if (!tab || !href)
|
|
334
|
+
continue;
|
|
335
|
+
if (pathname === href || pathname.startsWith(`${href}/`)) {
|
|
336
|
+
if (!best || href.length > best.length)
|
|
337
|
+
best = { tab, length: href.length };
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return best?.tab;
|
|
341
|
+
};
|
|
342
|
+
const armTabSwitchHandoff = () => {
|
|
343
|
+
tabSwitchHandoff = true;
|
|
344
|
+
handoffUntil = Math.max(handoffUntil, win.performance.now() + 400);
|
|
345
|
+
if (pending)
|
|
346
|
+
handoffAcrossPending = true;
|
|
347
|
+
};
|
|
348
|
+
const beginTabSwitchHandoffIfNeeded = (page) => {
|
|
349
|
+
const tabs = page.closest('ion-tabs');
|
|
350
|
+
if (!tabs)
|
|
351
|
+
return;
|
|
352
|
+
const bar = tabs.querySelector('ion-tab-bar');
|
|
353
|
+
const selected = (bar && 'selectedTab' in bar ? String(bar.selectedTab ?? '') : '') ||
|
|
354
|
+
tabs.querySelector('ion-tab-button.tab-selected')?.getAttribute('tab') ||
|
|
355
|
+
undefined;
|
|
356
|
+
const destination = tabOfPath(tabs, win.location.pathname);
|
|
357
|
+
if (selected && destination && selected !== destination)
|
|
358
|
+
armTabSwitchHandoff();
|
|
359
|
+
};
|
|
360
|
+
const endTabSwitchHandoff = () => {
|
|
361
|
+
win.requestAnimationFrame(() => {
|
|
362
|
+
if (stopped || !tabSwitchHandoff)
|
|
363
|
+
return;
|
|
364
|
+
tabSwitchHandoff = false;
|
|
365
|
+
schedule();
|
|
366
|
+
});
|
|
310
367
|
};
|
|
311
368
|
const motion = (event) => {
|
|
312
369
|
const target = event.target;
|
|
@@ -331,9 +388,19 @@ export const createRuntime = async (doc, plugin, options = {}) => {
|
|
|
331
388
|
on(doc, name, pageWill);
|
|
332
389
|
for (const name of [LIFECYCLE_DID_ENTER, LIFECYCLE_DID_LEAVE])
|
|
333
390
|
on(doc, name, pageDid);
|
|
391
|
+
on(doc, 'ionTabsWillChange', () => {
|
|
392
|
+
armTabSwitchHandoff();
|
|
393
|
+
schedule();
|
|
394
|
+
});
|
|
395
|
+
on(doc, 'ionTabsDidChange', endTabSwitchHandoff);
|
|
334
396
|
for (const name of overlayNames) {
|
|
335
397
|
on(doc, `ion${name}WillPresent`, (event) => {
|
|
336
398
|
presented.add(event.target);
|
|
399
|
+
if (name === 'Modal') {
|
|
400
|
+
modalPresentHandoff = true;
|
|
401
|
+
if (pending)
|
|
402
|
+
handoffInstant = true;
|
|
403
|
+
}
|
|
337
404
|
schedule();
|
|
338
405
|
});
|
|
339
406
|
on(doc, `ion${name}DidDismiss`, (event) => {
|
|
@@ -352,7 +419,6 @@ export const createRuntime = async (doc, plugin, options = {}) => {
|
|
|
352
419
|
for (const name of [
|
|
353
420
|
'ionChange',
|
|
354
421
|
'ionSelect',
|
|
355
|
-
'ionTabsDidChange',
|
|
356
422
|
'ionImgDidLoad',
|
|
357
423
|
CSS_MOTION_EVENTS.transitionEnd,
|
|
358
424
|
CSS_MOTION_EVENTS.animationEnd,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export declare const fadeMarker = "data-native-ui-shell-fading";
|
|
2
2
|
export declare const createCrossfade: (win: Window) => {
|
|
3
|
-
duration: () => 0 | 180;
|
|
4
|
-
play(element: HTMLElement, toNative: boolean): void;
|
|
3
|
+
duration: (instant?: boolean) => 0 | 180;
|
|
4
|
+
play(element: HTMLElement, toNative: boolean, instant?: boolean): void;
|
|
5
5
|
settled(): Promise<void>;
|
|
6
6
|
destroy(): void;
|
|
7
7
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crossfade.d.ts","sourceRoot":"","sources":["../../../src/native/shared/crossfade.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU,gCAAgC,CAAC;AAGxD,eAAO,MAAM,eAAe,GAAI,KAAK,MAAM;;kBAezB,WAAW,YAAY,OAAO;;;
|
|
1
|
+
{"version":3,"file":"crossfade.d.ts","sourceRoot":"","sources":["../../../src/native/shared/crossfade.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU,gCAAgC,CAAC;AAGxD,eAAO,MAAM,eAAe,GAAI,KAAK,MAAM;;kBAezB,WAAW,YAAY,OAAO;;;CA+B/C,CAAC"}
|
|
@@ -15,14 +15,14 @@ export const createCrossfade = (win) => {
|
|
|
15
15
|
};
|
|
16
16
|
reduced.addEventListener('change', cancelAll);
|
|
17
17
|
return {
|
|
18
|
-
duration: () => (reduced.matches ? 0 : 180),
|
|
19
|
-
play(element, toNative) {
|
|
18
|
+
duration: (instant = false) => (reduced.matches || instant ? 0 : 180),
|
|
19
|
+
play(element, toNative, instant = false) {
|
|
20
20
|
const previous = active.get(element);
|
|
21
21
|
const current = Number(win.getComputedStyle(element).opacity);
|
|
22
22
|
previous?.cancel();
|
|
23
23
|
active.delete(element);
|
|
24
24
|
const opacity = Number(win.getComputedStyle(element).opacity);
|
|
25
|
-
if (reduced.matches || !element.isConnected) {
|
|
25
|
+
if (reduced.matches || instant || !element.isConnected) {
|
|
26
26
|
element.removeAttribute(fadeMarker);
|
|
27
27
|
return;
|
|
28
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/segment/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AA+CtE,eAAO,MAAM,qBAAqB,GAAI,eAAe,WAAW,KAAG,gBAAgB,GAAG,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/segment/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AA+CtE,eAAO,MAAM,qBAAqB,GAAI,eAAe,WAAW,KAAG,gBAAgB,GAAG,SA6UrF,CAAC"}
|
package/dist/segment/index.js
CHANGED
|
@@ -102,6 +102,13 @@ export const registerSegmentEffect = (targetElement) => {
|
|
|
102
102
|
animation?.cancel();
|
|
103
103
|
handoff.forEach((effect) => effect.cancel());
|
|
104
104
|
handoff = [];
|
|
105
|
+
const first = frames[0];
|
|
106
|
+
if (first) {
|
|
107
|
+
lens.style.transform = String(first['transform']);
|
|
108
|
+
lens.style.width = String(first['width']);
|
|
109
|
+
lens.style.height = String(first['height']);
|
|
110
|
+
lens.style.backgroundColor = String(first['backgroundColor']);
|
|
111
|
+
}
|
|
105
112
|
segment.classList.add('ios27-animated');
|
|
106
113
|
lens.hidden = false;
|
|
107
114
|
const running = lens.animate(frames, { duration, easing: 'linear', fill: 'forwards' });
|
package/docs/animation.md
CHANGED
|
@@ -78,7 +78,7 @@ Use the following structure inside `ion-tabs` to animate a search button into a
|
|
|
78
78
|
```html
|
|
79
79
|
<ion-content>...</ion-content>
|
|
80
80
|
<ion-fab vertical="bottom" horizontal="end" slot="fixed">
|
|
81
|
-
<ion-fab-button (click)="present($event)">
|
|
81
|
+
<ion-fab-button aria-label="Search" (click)="present($event)">
|
|
82
82
|
<ion-icon name="search"></ion-icon>
|
|
83
83
|
</ion-fab-button>
|
|
84
84
|
</ion-fab>
|
|
@@ -89,7 +89,7 @@ Use the following structure inside `ion-tabs` to animate a search button into a
|
|
|
89
89
|
<ion-button fill="default"><ion-icon slot="icon-only"></ion-icon> </ion-button>
|
|
90
90
|
</ion-buttons>
|
|
91
91
|
<!-- User set `ionChange` or other events. -->
|
|
92
|
-
<ion-searchbar (ionChange)="example($event)"></ion-searchbar>
|
|
92
|
+
<ion-searchbar aria-label="Search" (ionChange)="example($event)"></ion-searchbar>
|
|
93
93
|
</ion-toolbar>
|
|
94
94
|
</ion-footer>
|
|
95
95
|
```
|
package/docs/native-ui-shell.md
CHANGED
|
@@ -118,6 +118,8 @@ Custom host animation or transition declarations on the FAB, list or button keep
|
|
|
118
118
|
|
|
119
119
|
The connection in `src/transition/ios.transition.ts` waits for native retirement before starting the Web animation. Interactive progress and completion/cancellation are queued while that retirement is in progress. Stationary shared tabs are retained. First render and transitions without an animation builder are covered by the startup runtime and Ionic lifecycle events.
|
|
120
120
|
|
|
121
|
+
Tab switches skip the Web/native crossfade so a retiring UIKit snapshot cannot linger over the next tab. Detection uses the router URL versus the still-selected tab on `ionViewWillLeave` (and vanilla `ionTabsWillChange` / `ionTabsDidChange` DOM events). Stack pushes and pops keep the normal 180ms handoff.
|
|
122
|
+
|
|
121
123
|
Standard Ionic overlays suspend native projection until dismissal. Unsupported searchable-tab configurations use the existing Web animation and share this ownership with Web glass gestures. CSS motion of supported containing surfaces also causes temporary Web rendering.
|
|
122
124
|
|
|
123
125
|
During retirement, the source is restored and allowed to paint before its native cover is removed. During acquisition, the source is hidden only after a successful, current native response. Delayed responses are revalidated per control: existing eligible controls retain their native cover while content updates catch up. Only removed or ineligible sources return to Web; newly acquired sources require an exact acknowledgement. Ordinary page mutations never call the global clear operation. UIKit tab instances and items are retained, and equal frames/selections are not reapplied. Duplicate/stale activations are discarded. WebKit and UIKit still render separately: the implementation avoids an intentional blank frame, but does not provide an OS-level atomic compositing guarantee. Validate custom transitions and overlays on the app's supported simulators before rollout; unknown overlay systems are outside the automatic integration contract.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rdlabo/ionic-theme-ios27",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.1.0-beta.pr224.shac63de393e27b",
|
|
5
5
|
"description": "iOS27 Theme for Ionic Framework",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"module": "./dist/index.js",
|
|
@@ -56,11 +56,8 @@
|
|
|
56
56
|
},
|
|
57
57
|
"homepage": "https://docs.rdlabo.dev/projects/ionic-theme-ios27",
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@rdlabo/ionic-theme-utils": "
|
|
59
|
+
"@rdlabo/ionic-theme-utils": "0.1.1"
|
|
60
60
|
},
|
|
61
|
-
"bundleDependencies": [
|
|
62
|
-
"@rdlabo/ionic-theme-utils"
|
|
63
|
-
],
|
|
64
61
|
"devDependencies": {
|
|
65
62
|
"@capacitor/core": "^8.5.2",
|
|
66
63
|
"@ionic/angular": "^9.0.0",
|
|
@@ -310,6 +310,9 @@ export const createSearchSupport = (doc: Document, id: (element: Element) => str
|
|
|
310
310
|
}
|
|
311
311
|
field.label = '';
|
|
312
312
|
field.accessibilityLabel = bar.getAttribute('aria-label') ?? input.getAttribute('aria-label') ?? 'Search';
|
|
313
|
+
// Icon-only search FABs often rely on the searchbar for their accessible
|
|
314
|
+
// name. Carry that semantic name into the independent resting trigger.
|
|
315
|
+
if (!trigger.accessibilityLabel) trigger.accessibilityLabel = field.accessibilityLabel;
|
|
313
316
|
state.layout = JSON.stringify([
|
|
314
317
|
innerWidth,
|
|
315
318
|
innerHeight,
|
package/src/native/runtime.ts
CHANGED
|
@@ -58,6 +58,16 @@ export const createRuntime = async (
|
|
|
58
58
|
let dirty = false;
|
|
59
59
|
let pending = false;
|
|
60
60
|
let stopped = false;
|
|
61
|
+
/** True while a tab-switch handoff should skip crossfade. */
|
|
62
|
+
let tabSwitchHandoff = false;
|
|
63
|
+
/** Keep instant updates until this time — DidLeave often precedes the retire sync. */
|
|
64
|
+
let handoffUntil = 0;
|
|
65
|
+
/** Tab switch armed while a sync was already in flight; extend instant past that sync. */
|
|
66
|
+
let handoffAcrossPending = false;
|
|
67
|
+
/** Captured at the start of each sync so an in-flight update keeps a stable duration. */
|
|
68
|
+
let handoffInstant = false;
|
|
69
|
+
/** Retire native controls immediately as a modal starts covering the page. */
|
|
70
|
+
let modalPresentHandoff = false;
|
|
61
71
|
let frame = 0;
|
|
62
72
|
let updates = 0;
|
|
63
73
|
let reason: string | undefined;
|
|
@@ -91,7 +101,7 @@ export const createRuntime = async (
|
|
|
91
101
|
lastSnapshot = '';
|
|
92
102
|
search.release(element);
|
|
93
103
|
element.removeAttribute(marker);
|
|
94
|
-
if (!stopped) crossfade.play(element, false);
|
|
104
|
+
if (!stopped) crossfade.play(element, false, handoffInstant);
|
|
95
105
|
if (element.getAttribute('aria-hidden') === 'true') {
|
|
96
106
|
const previous = sources.get(element);
|
|
97
107
|
if (previous == null) element.removeAttribute('aria-hidden');
|
|
@@ -197,6 +207,8 @@ export const createRuntime = async (
|
|
|
197
207
|
frame = 0;
|
|
198
208
|
dirty = false;
|
|
199
209
|
pending = true;
|
|
210
|
+
handoffInstant = tabSwitchHandoff || handoffAcrossPending || modalPresentHandoff || win.performance.now() < handoffUntil;
|
|
211
|
+
modalPresentHandoff = false;
|
|
200
212
|
try {
|
|
201
213
|
const size = `${win.innerWidth}:${win.innerHeight}`;
|
|
202
214
|
// WebKit can resize before Ionic's fixed DOM positions catch up.
|
|
@@ -225,13 +237,17 @@ export const createRuntime = async (
|
|
|
225
237
|
if (removed.length) {
|
|
226
238
|
// Restore the source and let WebKit paint before removing its native cover.
|
|
227
239
|
removed.forEach(restore);
|
|
228
|
-
|
|
229
|
-
|
|
240
|
+
// The outgoing tab is no longer visible, so waiting two frames only leaves its
|
|
241
|
+
// native snapshot over the destination. Stack transitions still need the paint.
|
|
242
|
+
if (!handoffInstant) {
|
|
243
|
+
await painted();
|
|
244
|
+
if (stopped || dirty) return;
|
|
245
|
+
}
|
|
230
246
|
}
|
|
231
247
|
const data = { viewportWidth: win.innerWidth, controls: candidates.map((candidate) => candidate.control) };
|
|
232
248
|
const serialized = JSON.stringify(data);
|
|
233
249
|
if (serialized === lastSnapshot && !forceRefresh) return;
|
|
234
|
-
const snapshot: ShellSnapshot = { ...data, revision: ++revision, transitionDuration: crossfade.duration() };
|
|
250
|
+
const snapshot: ShellSnapshot = { ...data, revision: ++revision, transitionDuration: crossfade.duration(handoffInstant) };
|
|
235
251
|
// A native visibility notification during this update must survive its ack.
|
|
236
252
|
forceRefresh = false;
|
|
237
253
|
updates++;
|
|
@@ -272,7 +288,7 @@ export const createRuntime = async (
|
|
|
272
288
|
for (const element of accepted.flatMap(candidateSources)) {
|
|
273
289
|
if (!sources.has(element)) {
|
|
274
290
|
sources.set(element, element.getAttribute('aria-hidden'));
|
|
275
|
-
crossfade.play(element, true);
|
|
291
|
+
crossfade.play(element, true, handoffInstant);
|
|
276
292
|
element.setAttribute(marker, '');
|
|
277
293
|
element.setAttribute('aria-hidden', 'true');
|
|
278
294
|
element.dispatchEvent(new CustomEvent('nativeUIShellChange'));
|
|
@@ -294,6 +310,11 @@ export const createRuntime = async (
|
|
|
294
310
|
pendingActivations = [];
|
|
295
311
|
// A refresh received before the ack must also invalidate that ack's rejects.
|
|
296
312
|
if (forceRefresh) rejected = new WeakMap();
|
|
313
|
+
// A tab switch mid-update (or a dirty follow-up) must keep instant through the retire sync.
|
|
314
|
+
if (!stopped && (handoffAcrossPending || (handoffInstant && dirty))) {
|
|
315
|
+
handoffUntil = Math.max(handoffUntil, win.performance.now() + 400);
|
|
316
|
+
}
|
|
317
|
+
handoffAcrossPending = false;
|
|
297
318
|
pending = false;
|
|
298
319
|
if (dirty && !stopped) schedule();
|
|
299
320
|
else finishWaiters();
|
|
@@ -323,12 +344,55 @@ export const createRuntime = async (
|
|
|
323
344
|
getNativeSearchBindings(doc)
|
|
324
345
|
.filter((binding) => page.contains(binding.footer))
|
|
325
346
|
.forEach((binding) => search.retire(binding));
|
|
347
|
+
// Angular updates the URL before willLeave, but keeps ion-tab-bar.selectedTab on the
|
|
348
|
+
// leaving tab until DidChange. A mismatch means this leave is a tab switch, not a stack push.
|
|
349
|
+
if (event.type === LIFECYCLE_WILL_LEAVE) beginTabSwitchHandoffIfNeeded(page);
|
|
326
350
|
pages.add(page);
|
|
327
351
|
schedule();
|
|
328
352
|
};
|
|
329
353
|
const pageDid: EventListener = (event) => {
|
|
330
354
|
pages.delete(event.target as HTMLElement);
|
|
331
355
|
schedule();
|
|
356
|
+
if (tabSwitchHandoff && pages.size === 0) endTabSwitchHandoff();
|
|
357
|
+
};
|
|
358
|
+
const tabOfPath = (tabs: Element, pathname: string) => {
|
|
359
|
+
let best: { tab: string; length: number } | undefined;
|
|
360
|
+
for (const button of Array.from(tabs.querySelectorAll('ion-tab-button'))) {
|
|
361
|
+
const tab = button.getAttribute('tab');
|
|
362
|
+
const href = button.getAttribute('href')?.split(/[?#]/)[0];
|
|
363
|
+
if (!tab || !href) continue;
|
|
364
|
+
if (pathname === href || pathname.startsWith(`${href}/`)) {
|
|
365
|
+
if (!best || href.length > best.length) best = { tab, length: href.length };
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return best?.tab;
|
|
369
|
+
};
|
|
370
|
+
const armTabSwitchHandoff = () => {
|
|
371
|
+
tabSwitchHandoff = true;
|
|
372
|
+
// Retiring outgoing controls often lands in a later async sync than WillLeave/DidChange.
|
|
373
|
+
handoffUntil = Math.max(handoffUntil, win.performance.now() + 400);
|
|
374
|
+
// The in-flight sync already captured handoffInstant=false; hold instant for the next one.
|
|
375
|
+
if (pending) handoffAcrossPending = true;
|
|
376
|
+
};
|
|
377
|
+
const beginTabSwitchHandoffIfNeeded = (page: HTMLElement) => {
|
|
378
|
+
const tabs = page.closest('ion-tabs');
|
|
379
|
+
if (!tabs) return;
|
|
380
|
+
const bar = tabs.querySelector('ion-tab-bar');
|
|
381
|
+
const selected =
|
|
382
|
+
(bar && 'selectedTab' in bar ? String((bar as HTMLElement & { selectedTab?: string }).selectedTab ?? '') : '') ||
|
|
383
|
+
tabs.querySelector('ion-tab-button.tab-selected')?.getAttribute('tab') ||
|
|
384
|
+
undefined;
|
|
385
|
+
const destination = tabOfPath(tabs, win.location.pathname);
|
|
386
|
+
if (selected && destination && selected !== destination) armTabSwitchHandoff();
|
|
387
|
+
};
|
|
388
|
+
// DidChange / pageDid can land in the same turn as WillLeave. Clear the sticky flag on the
|
|
389
|
+
// next frame; handoffUntil / handoffAcrossPending still cover the async retire sync.
|
|
390
|
+
const endTabSwitchHandoff = () => {
|
|
391
|
+
win.requestAnimationFrame(() => {
|
|
392
|
+
if (stopped || !tabSwitchHandoff) return;
|
|
393
|
+
tabSwitchHandoff = false;
|
|
394
|
+
schedule();
|
|
395
|
+
});
|
|
332
396
|
};
|
|
333
397
|
const motion: EventListener = (event) => {
|
|
334
398
|
const target = event.target as HTMLElement;
|
|
@@ -347,9 +411,21 @@ export const createRuntime = async (
|
|
|
347
411
|
for (const name of Object.values(CSS_MOTION_EVENTS)) on(doc, name, motion);
|
|
348
412
|
for (const name of [LIFECYCLE_WILL_ENTER, LIFECYCLE_WILL_LEAVE]) on(doc, name, pageWill);
|
|
349
413
|
for (const name of [LIFECYCLE_DID_ENTER, LIFECYCLE_DID_LEAVE]) on(doc, name, pageDid);
|
|
414
|
+
on(doc, 'ionTabsWillChange', () => {
|
|
415
|
+
// Vanilla ion-tabs dispatches DOM events; @ionic/angular uses EventEmitters instead.
|
|
416
|
+
armTabSwitchHandoff();
|
|
417
|
+
schedule();
|
|
418
|
+
});
|
|
419
|
+
on(doc, 'ionTabsDidChange', endTabSwitchHandoff);
|
|
350
420
|
for (const name of overlayNames) {
|
|
351
421
|
on(doc, `ion${name}WillPresent`, (event) => {
|
|
352
422
|
presented.add(event.target as HTMLElement);
|
|
423
|
+
if (name === 'Modal') {
|
|
424
|
+
modalPresentHandoff = true;
|
|
425
|
+
// WillPresent may arrive while another bridge update is awaiting its ack.
|
|
426
|
+
// Make that retirement instant too instead of racing the modal animation.
|
|
427
|
+
if (pending) handoffInstant = true;
|
|
428
|
+
}
|
|
353
429
|
schedule();
|
|
354
430
|
});
|
|
355
431
|
on(doc, `ion${name}DidDismiss`, (event) => {
|
|
@@ -368,7 +444,6 @@ export const createRuntime = async (
|
|
|
368
444
|
for (const name of [
|
|
369
445
|
'ionChange',
|
|
370
446
|
'ionSelect',
|
|
371
|
-
'ionTabsDidChange',
|
|
372
447
|
'ionImgDidLoad',
|
|
373
448
|
CSS_MOTION_EVENTS.transitionEnd,
|
|
374
449
|
CSS_MOTION_EVENTS.animationEnd,
|
|
@@ -15,14 +15,15 @@ export const createCrossfade = (win: Window) => {
|
|
|
15
15
|
};
|
|
16
16
|
reduced.addEventListener('change', cancelAll);
|
|
17
17
|
return {
|
|
18
|
-
duration: () => (reduced.matches ? 0 : 180),
|
|
19
|
-
play(element: HTMLElement, toNative: boolean) {
|
|
18
|
+
duration: (instant = false) => (reduced.matches || instant ? 0 : 180),
|
|
19
|
+
play(element: HTMLElement, toNative: boolean, instant = false) {
|
|
20
20
|
const previous = active.get(element);
|
|
21
21
|
const current = Number(win.getComputedStyle(element).opacity);
|
|
22
22
|
previous?.cancel();
|
|
23
23
|
active.delete(element);
|
|
24
24
|
const opacity = Number(win.getComputedStyle(element).opacity);
|
|
25
|
-
|
|
25
|
+
// Tab switches skip the opacity handoff so a retiring native snapshot cannot linger.
|
|
26
|
+
if (reduced.matches || instant || !element.isConnected) {
|
|
26
27
|
element.removeAttribute(fadeMarker);
|
|
27
28
|
return;
|
|
28
29
|
}
|
package/src/segment/index.ts
CHANGED
|
@@ -119,6 +119,17 @@ export const registerSegmentEffect = (targetElement: HTMLElement): registeredEff
|
|
|
119
119
|
animation?.cancel();
|
|
120
120
|
handoff.forEach((effect) => effect.cancel());
|
|
121
121
|
handoff = [];
|
|
122
|
+
// WebKit can paint the newly unhidden element once at its underlying
|
|
123
|
+
// top-left position before the replacement WAAPI effect is sampled.
|
|
124
|
+
// Prime that underlying style so interrupted/reversed selections always
|
|
125
|
+
// hand off from the first frame instead of briefly flashing at (0, 0).
|
|
126
|
+
const first = frames[0];
|
|
127
|
+
if (first) {
|
|
128
|
+
lens.style.transform = String(first['transform']);
|
|
129
|
+
lens.style.width = String(first['width']);
|
|
130
|
+
lens.style.height = String(first['height']);
|
|
131
|
+
lens.style.backgroundColor = String(first['backgroundColor']);
|
|
132
|
+
}
|
|
122
133
|
segment.classList.add('ios27-animated');
|
|
123
134
|
lens.hidden = false;
|
|
124
135
|
const running = lens.animate(frames, { duration, easing: 'linear', fill: 'forwards' });
|
|
@@ -5,7 +5,10 @@ ion-toggle.ios:not(.ios-theme-disabled, .ios26-disabled) {
|
|
|
5
5
|
--handle-max-width: none;
|
|
6
6
|
--handle-max-height: none;
|
|
7
7
|
--border-radius: 14px;
|
|
8
|
-
--track-background-checked: var(--ion-color-
|
|
8
|
+
--track-background-checked: var(--ion-color-primary, #3880ff);
|
|
9
|
+
&.ion-color {
|
|
10
|
+
--track-background-checked: var(--ion-color-base);
|
|
11
|
+
}
|
|
9
12
|
&::part(track) {
|
|
10
13
|
width: 63px;
|
|
11
14
|
height: 28px;
|
|
@@ -48,7 +51,10 @@ ion-toggle.ios:not(.ios-theme-disabled, .ios26-disabled) {
|
|
|
48
51
|
&:not(.ion-color) {
|
|
49
52
|
--track-background: rgba(var(--ion-color-contrast-rgb, var(--ion-text-color-rgb, 0, 0, 0)), 0.23);
|
|
50
53
|
}
|
|
51
|
-
--track-background-checked: var(--ion-color-
|
|
54
|
+
--track-background-checked: var(--ion-color-primary, #3880ff);
|
|
55
|
+
&.ion-color {
|
|
56
|
+
--track-background-checked: var(--ion-color-base);
|
|
57
|
+
}
|
|
52
58
|
// Measured from the iOS 27 UISwitch presentation layer (37 -> 58pt).
|
|
53
59
|
--ios27-toggle-release: linear(
|
|
54
60
|
0,
|
|
@@ -48,7 +48,7 @@ export {
|
|
|
48
48
|
* </ion-button>
|
|
49
49
|
* </ion-buttons>
|
|
50
50
|
* <!-- User set `ionChange` or other events. -->
|
|
51
|
-
* <ion-searchbar (ionChange)="example($event)"></ion-searchbar>
|
|
51
|
+
* <ion-searchbar aria-label="Search" (ionChange)="example($event)"></ion-searchbar>
|
|
52
52
|
* </ion-toolbar>
|
|
53
53
|
* </ion-footer>
|
|
54
54
|
**/
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Masahiko Sakakibara
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
# @rdlabo/ionic-theme-utils
|
|
2
|
-
|
|
3
|
-
Shared, theme-neutral utilities for Rdlabo Ionic themes.
|
|
4
|
-
|
|
5
|
-
TypeScript and Sass sources are exported directly. Consumers are expected to
|
|
6
|
-
compile them as part of an Angular/Ionic application build.
|
|
7
|
-
|
|
8
|
-
```typescript
|
|
9
|
-
import { createIosTransitionAnimation, getPopoverPosition } from '@rdlabo/ionic-theme-utils';
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
```scss
|
|
13
|
-
@use 'pkg:@rdlabo/ionic-theme-utils/styles/structured-list';
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
The package currently contains shared iOS transition construction, popover
|
|
17
|
-
positioning, searchable tab-bar utilities, and structured-list Sass mixins.
|
|
18
|
-
|
|
19
|
-
## Development
|
|
20
|
-
|
|
21
|
-
```shell
|
|
22
|
-
npm install
|
|
23
|
-
npm run build
|
|
24
|
-
npm run lint
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Use `npm link` while developing this package together with a theme repository.
|
|
28
|
-
Theme repositories should use a tagged Git dependency for reproducible installs.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../src/dom.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,cAAc,GAAI,IAAI,WAAW,EAAE,WAAU,WAAgB,6BAEzE,CAAC;AAEF,eAAO,MAAM,GAAG,GAAI,GAAG,oBAAoB,QAQ1C,CAAC"}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export const getElementRoot = (el, fallback = el) => {
|
|
2
|
-
return el.shadowRoot || fallback;
|
|
3
|
-
};
|
|
4
|
-
export const raf = (h) => {
|
|
5
|
-
if (typeof __zone_symbol__requestAnimationFrame === 'function') {
|
|
6
|
-
return __zone_symbol__requestAnimationFrame(h);
|
|
7
|
-
}
|
|
8
|
-
if (typeof requestAnimationFrame === 'function') {
|
|
9
|
-
return requestAnimationFrame(h);
|
|
10
|
-
}
|
|
11
|
-
return setTimeout(h);
|
|
12
|
-
};
|
|
13
|
-
//# sourceMappingURL=dom.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dom.js","sourceRoot":"","sources":["../src/dom.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,EAAe,EAAE,WAAwB,EAAE,EAAE,EAAE;IAC5E,OAAO,EAAE,CAAC,UAAU,IAAI,QAAQ,CAAC;AACnC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,CAAuB,EAAE,EAAE;IAC7C,IAAI,OAAO,oCAAoC,KAAK,UAAU,EAAE,CAAC;QAC/D,OAAO,oCAAoC,CAAC,CAAC,CAAC,CAAC;IACjD,CAAC;IACD,IAAI,OAAO,qBAAqB,KAAK,UAAU,EAAE,CAAC;QAChD,OAAO,qBAAqB,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC;AACvB,CAAC,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"focus-controller.d.ts","sourceRoot":"","sources":["../src/focus-controller.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,eAAe;IAC9B,aAAa,CAAC,WAAW,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC/C,YAAY,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;CAC9C;AAED,eAAO,MAAM,qBAAqB,QAAO,eAuBvC,CAAC"}
|