@ds-mo/ui 1.11.2 → 1.11.4
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/.build-stamp +1 -1
- package/dist/components/ds-app-shell.js +1 -1
- package/dist/components/ds-app-shell.js.map +1 -1
- package/dist/components/ds-bar-nav.js +1 -1
- package/dist/components/ds-bar-nav.js.map +1 -1
- package/dist/components/ds-checkbox.js +1 -1
- package/dist/components/ds-field.js +1 -1
- package/dist/components/ds-panel-nav.js +1 -1
- package/dist/components/ds-panel-nav.js.map +1 -1
- package/dist/components/ds-panel-tools.js +1 -1
- package/dist/components/ds-panel-tools.js.map +1 -1
- package/dist/components/ds-slider.js +1 -1
- package/dist/components/ds-toggle.js +1 -1
- package/dist/components/p-BiM6QBTF.js +2 -0
- package/dist/components/p-BiM6QBTF.js.map +1 -0
- package/dist/types/components/AppShell/AppShell.d.ts +8 -3
- package/dist/types/components/BarNav/BarNav.d.ts +7 -3
- package/dist/types/components/PanelNav/PanelNav.d.ts +3 -1
- package/dist/types/nav/chrome-transition.d.ts +3 -0
- package/dist/types/nav/index.d.ts +3 -3
- package/dist/types/nav/shell-gradient.d.ts +12 -1
- package/package.json +1 -1
- package/src/wc/components/AppShell/AppShell.tsx +49 -14
- package/src/wc/components/BarNav/BarNav.tsx +79 -37
- package/src/wc/components/PanelNav/PanelNav.tsx +27 -4
- package/src/wc/components/PanelTools/PanelTools.tsx +4 -1
- package/src/wc/nav/chrome-transition.ts +6 -0
- package/src/wc/nav/index.ts +3 -1
- package/src/wc/nav/shell-gradient.ts +23 -1
- package/dist/components/p-1HlgCxGN.js +0 -2
- package/dist/components/p-1HlgCxGN.js.map +0 -1
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
} from '@stencil/core';
|
|
12
12
|
import type { NavChromeStyle } from '../../nav/nav-chrome';
|
|
13
13
|
import type { MenuItemData } from '../Menu/menu-types';
|
|
14
|
+
import { isTabDivider } from '../TabGroup/tab-item-utils';
|
|
14
15
|
import type { BarNavActionItem, BarNavTab } from './bar-nav-types';
|
|
15
16
|
import {
|
|
16
17
|
deriveBarNavValueFromUrl,
|
|
@@ -34,8 +35,8 @@ import {
|
|
|
34
35
|
ChromeTransitionDepth,
|
|
35
36
|
createRafCoalescer,
|
|
36
37
|
readChromeTransitionSource,
|
|
38
|
+
readChromeTransitionPhase,
|
|
37
39
|
} from '../../nav/chrome-transition';
|
|
38
|
-
import { readCssVarWidthPx } from '../../nav/shell-chrome-metrics';
|
|
39
40
|
|
|
40
41
|
@Component({
|
|
41
42
|
tag: 'ds-bar-nav',
|
|
@@ -99,6 +100,7 @@ export class BarNav {
|
|
|
99
100
|
|
|
100
101
|
private static readonly HOST_PROP_SYNC_BUDGET = 8;
|
|
101
102
|
private static readonly INTRINSIC_WIDTH_RETRY_MAX = 3;
|
|
103
|
+
private static readonly TAB_LAYOUT_COMMIT_MAX_FRAMES = 16;
|
|
102
104
|
private static readonly OVERFLOW_HYSTERESIS_PX = 8;
|
|
103
105
|
|
|
104
106
|
private headerEl: HTMLElement | null = null;
|
|
@@ -110,13 +112,14 @@ export class BarNav {
|
|
|
110
112
|
private probeTabGroupEl: QueryableHost | null = null;
|
|
111
113
|
private resizeObserver: ResizeObserver | null = null;
|
|
112
114
|
private intrinsicWidthRetryCount = 0;
|
|
115
|
+
private tabLayoutPendingFrames = 0;
|
|
113
116
|
private readonly panelNavTransition = new ChromeTransitionDepth();
|
|
117
|
+
private readonly panelToolsTransition = new ChromeTransitionDepth();
|
|
114
118
|
private readonly overflowCoalescer = createRafCoalescer(() => {
|
|
115
119
|
this.updateTabsCollapsed();
|
|
116
120
|
this.updateTriggerLabelTruncation();
|
|
117
121
|
});
|
|
118
122
|
private chromeTransitionShell: HTMLElement | null = null;
|
|
119
|
-
private toolsDrawerOpening = false;
|
|
120
123
|
/** Matches `basePath` once tabs + URL are reconciled for the active section. */
|
|
121
124
|
@State() private committedSection = '';
|
|
122
125
|
/** Section waiting for URL + tabs to catch up after a cross-area navigation. */
|
|
@@ -137,6 +140,18 @@ export class BarNav {
|
|
|
137
140
|
return !!getActiveTab(this.resolvedTabs, this.effectiveValue)?.dot;
|
|
138
141
|
}
|
|
139
142
|
|
|
143
|
+
private digestTabsConfig(tabs: BarNavTab[]): string {
|
|
144
|
+
return tabs.map(t => (isTabDivider(t) ? '|' : t.id)).join(',');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
private resetTabOverflowLayout() {
|
|
148
|
+
this.tabLayoutCommitted = false;
|
|
149
|
+
this.tabsCollapsed = false;
|
|
150
|
+
this.menuOpen = false;
|
|
151
|
+
this.intrinsicWidthRetryCount = 0;
|
|
152
|
+
this.tabLayoutPendingFrames = 0;
|
|
153
|
+
}
|
|
154
|
+
|
|
140
155
|
@Watch('tabs')
|
|
141
156
|
@Watch('tabsJson')
|
|
142
157
|
@Watch('actions')
|
|
@@ -194,7 +209,7 @@ export class BarNav {
|
|
|
194
209
|
}
|
|
195
210
|
|
|
196
211
|
componentDidRender() {
|
|
197
|
-
if (this.
|
|
212
|
+
if (this.chromeOverflowPaused()) {
|
|
198
213
|
this.syncMenuAnchor();
|
|
199
214
|
return;
|
|
200
215
|
}
|
|
@@ -241,16 +256,17 @@ export class BarNav {
|
|
|
241
256
|
return;
|
|
242
257
|
}
|
|
243
258
|
if (source === 'panel-tools') {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
this.tabsCollapsed = true;
|
|
248
|
-
this.menuOpen = false;
|
|
259
|
+
const phase = readChromeTransitionPhase(event) ?? 'opening';
|
|
260
|
+
if (phase === 'closing') {
|
|
261
|
+
this.panelToolsTransition.enter();
|
|
249
262
|
}
|
|
250
|
-
this.scheduleOverflowCheck();
|
|
251
263
|
}
|
|
252
264
|
};
|
|
253
265
|
|
|
266
|
+
private chromeOverflowPaused(): boolean {
|
|
267
|
+
return this.panelNavTransition.isActive || this.panelToolsTransition.isActive;
|
|
268
|
+
}
|
|
269
|
+
|
|
254
270
|
private onChromeTransitionEnd = (event: Event) => {
|
|
255
271
|
const source = readChromeTransitionSource(event);
|
|
256
272
|
if (source === 'panel-nav') {
|
|
@@ -261,8 +277,7 @@ export class BarNav {
|
|
|
261
277
|
return;
|
|
262
278
|
}
|
|
263
279
|
if (source === 'panel-tools') {
|
|
264
|
-
this.
|
|
265
|
-
this.el.classList.remove('bar-nav--tools-drawer-opening');
|
|
280
|
+
this.panelToolsTransition.exit();
|
|
266
281
|
this.scheduleOverflowCheck();
|
|
267
282
|
}
|
|
268
283
|
};
|
|
@@ -301,14 +316,14 @@ export class BarNav {
|
|
|
301
316
|
if (typeof ResizeObserver === 'undefined' || !this.headerEl) return;
|
|
302
317
|
this.resizeObserver?.disconnect();
|
|
303
318
|
this.resizeObserver = new ResizeObserver(() => {
|
|
304
|
-
if (this.
|
|
319
|
+
if (this.chromeOverflowPaused()) return;
|
|
305
320
|
this.scheduleOverflowCheck();
|
|
306
321
|
});
|
|
307
322
|
this.resizeObserver.observe(this.headerEl);
|
|
308
323
|
}
|
|
309
324
|
|
|
310
325
|
private scheduleOverflowCheck() {
|
|
311
|
-
if (this.
|
|
326
|
+
if (this.chromeOverflowPaused()) return;
|
|
312
327
|
this.overflowCoalescer.schedule();
|
|
313
328
|
}
|
|
314
329
|
|
|
@@ -366,20 +381,7 @@ export class BarNav {
|
|
|
366
381
|
const available =
|
|
367
382
|
this.headerEl.clientWidth - horizontalPadding - actionsWidth - spacing;
|
|
368
383
|
|
|
369
|
-
return Math.max(0, available
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
/** While the tools drawer is opening, reserve width not yet claimed by flex shrink. */
|
|
373
|
-
private toolsDrawerOpeningReservePx(): number {
|
|
374
|
-
if (!this.toolsDrawerOpening) return 0;
|
|
375
|
-
|
|
376
|
-
const tools = this.el.closest('ds-app-shell')?.querySelector('ds-panel-tools') as HTMLElement | null;
|
|
377
|
-
if (!tools) return 0;
|
|
378
|
-
|
|
379
|
-
const drawerTarget = readCssVarWidthPx(tools, '--_panel-tools-drawer-width');
|
|
380
|
-
const drawerNow =
|
|
381
|
-
tools.querySelector('.panel-tools__drawer')?.getBoundingClientRect().width ?? 0;
|
|
382
|
-
return Math.max(0, drawerTarget - drawerNow);
|
|
384
|
+
return Math.max(0, available);
|
|
383
385
|
}
|
|
384
386
|
|
|
385
387
|
private getTabsIntrinsicWidth(): number {
|
|
@@ -393,6 +395,16 @@ export class BarNav {
|
|
|
393
395
|
requestAnimationFrame(() => this.scheduleOverflowCheck());
|
|
394
396
|
}
|
|
395
397
|
|
|
398
|
+
private forceTabLayoutCommit(fallbackCollapsed: boolean) {
|
|
399
|
+
this.intrinsicWidthRetryCount = 0;
|
|
400
|
+
this.tabLayoutPendingFrames = 0;
|
|
401
|
+
this.tabsCollapsed = fallbackCollapsed;
|
|
402
|
+
if (!fallbackCollapsed) {
|
|
403
|
+
this.menuOpen = false;
|
|
404
|
+
}
|
|
405
|
+
this.tabLayoutCommitted = true;
|
|
406
|
+
}
|
|
407
|
+
|
|
396
408
|
private updateTabsCollapsed() {
|
|
397
409
|
if (!this.headerEl || this.resolvedTabs.length === 0 || this.hideTabsForDetailRoute) {
|
|
398
410
|
if (this.tabsCollapsed) {
|
|
@@ -400,15 +412,25 @@ export class BarNav {
|
|
|
400
412
|
this.menuOpen = false;
|
|
401
413
|
}
|
|
402
414
|
this.intrinsicWidthRetryCount = 0;
|
|
415
|
+
this.tabLayoutPendingFrames = 0;
|
|
416
|
+
this.tabLayoutCommitted = true;
|
|
403
417
|
return;
|
|
404
418
|
}
|
|
405
419
|
|
|
406
420
|
const intrinsicWidth = this.getTabsIntrinsicWidth();
|
|
407
421
|
if (intrinsicWidth === 0) {
|
|
408
|
-
this.
|
|
422
|
+
this.tabLayoutPendingFrames += 1;
|
|
423
|
+
if (this.intrinsicWidthRetryCount >= BarNav.INTRINSIC_WIDTH_RETRY_MAX) {
|
|
424
|
+
this.forceTabLayoutCommit(false);
|
|
425
|
+
} else if (this.tabLayoutPendingFrames >= BarNav.TAB_LAYOUT_COMMIT_MAX_FRAMES) {
|
|
426
|
+
this.forceTabLayoutCommit(false);
|
|
427
|
+
} else {
|
|
428
|
+
this.scheduleIntrinsicWidthRetry();
|
|
429
|
+
}
|
|
409
430
|
return;
|
|
410
431
|
}
|
|
411
432
|
this.intrinsicWidthRetryCount = 0;
|
|
433
|
+
this.tabLayoutPendingFrames = 0;
|
|
412
434
|
|
|
413
435
|
const shouldCollapse = tabsOverflowContainer(
|
|
414
436
|
intrinsicWidth,
|
|
@@ -423,6 +445,8 @@ export class BarNav {
|
|
|
423
445
|
this.menuOpen = false;
|
|
424
446
|
}
|
|
425
447
|
}
|
|
448
|
+
|
|
449
|
+
this.tabLayoutCommitted = true;
|
|
426
450
|
}
|
|
427
451
|
|
|
428
452
|
private syncMenuAnchor() {
|
|
@@ -469,6 +493,7 @@ export class BarNav {
|
|
|
469
493
|
this.pendingSection = nextBasePath;
|
|
470
494
|
this.resolvedTabs = [];
|
|
471
495
|
this.resolvedActions = this.incomingActions();
|
|
496
|
+
this.resetTabOverflowLayout();
|
|
472
497
|
return;
|
|
473
498
|
}
|
|
474
499
|
|
|
@@ -486,11 +511,17 @@ export class BarNav {
|
|
|
486
511
|
this.pendingSection = '';
|
|
487
512
|
}
|
|
488
513
|
|
|
489
|
-
|
|
514
|
+
const tabs = this.incomingTabs();
|
|
515
|
+
const tabsConfigChanged =
|
|
516
|
+
this.digestTabsConfig(tabs) !== this.digestTabsConfig(this.resolvedTabs);
|
|
517
|
+
|
|
518
|
+
this.resolvedTabs = tabs;
|
|
490
519
|
this.resolvedActions = this.incomingActions();
|
|
491
520
|
this.syncValueFromUrl();
|
|
492
521
|
this.committedSection = nextBasePath;
|
|
493
|
-
|
|
522
|
+
if (tabsConfigChanged) {
|
|
523
|
+
this.resetTabOverflowLayout();
|
|
524
|
+
}
|
|
494
525
|
this.scheduleOverflowCheck();
|
|
495
526
|
}
|
|
496
527
|
|
|
@@ -593,7 +624,8 @@ export class BarNav {
|
|
|
593
624
|
'bar-nav': true,
|
|
594
625
|
'bar-nav--dashboard': this.navStyle === 'dashboard',
|
|
595
626
|
'bar-nav--settings': this.navStyle === 'settings',
|
|
596
|
-
'bar-nav--tabs-collapsed':
|
|
627
|
+
'bar-nav--tabs-collapsed':
|
|
628
|
+
hasTabs && this.tabLayoutCommitted && this.tabsCollapsed,
|
|
597
629
|
}}
|
|
598
630
|
ref={el => {
|
|
599
631
|
this.headerEl = el as HTMLElement;
|
|
@@ -607,9 +639,12 @@ export class BarNav {
|
|
|
607
639
|
<ds-tab-group-nav
|
|
608
640
|
key={`probe-${tabGroupKey}`}
|
|
609
641
|
ref={el => {
|
|
610
|
-
|
|
611
|
-
if (
|
|
642
|
+
const next = el ?? null;
|
|
643
|
+
if (next === this.probeTabGroupEl) return;
|
|
644
|
+
this.probeTabGroupEl = next;
|
|
645
|
+
if (next) {
|
|
612
646
|
this.intrinsicWidthRetryCount = 0;
|
|
647
|
+
this.tabLayoutPendingFrames = 0;
|
|
613
648
|
this.scheduleOverflowCheck();
|
|
614
649
|
}
|
|
615
650
|
}}
|
|
@@ -619,7 +654,7 @@ export class BarNav {
|
|
|
619
654
|
</div>
|
|
620
655
|
)}
|
|
621
656
|
|
|
622
|
-
{hasTabs && !this.tabsCollapsed && (
|
|
657
|
+
{hasTabs && this.tabLayoutCommitted && !this.tabsCollapsed && (
|
|
623
658
|
<div class="bar-nav__left">
|
|
624
659
|
<ds-tab-group-nav
|
|
625
660
|
key={`visible-${tabGroupKey}`}
|
|
@@ -634,11 +669,15 @@ export class BarNav {
|
|
|
634
669
|
</div>
|
|
635
670
|
)}
|
|
636
671
|
|
|
672
|
+
{hasTabs && !this.tabLayoutCommitted && (
|
|
673
|
+
<div class="bar-nav__tabs-pending" aria-hidden="true" />
|
|
674
|
+
)}
|
|
675
|
+
|
|
637
676
|
{!hasTabs && this.heading && (
|
|
638
677
|
<span class="bar-nav__heading text-body-medium-emphasis">{this.heading}</span>
|
|
639
678
|
)}
|
|
640
679
|
|
|
641
|
-
{hasTabs && this.tabsCollapsed && (
|
|
680
|
+
{hasTabs && this.tabLayoutCommitted && this.tabsCollapsed && (
|
|
642
681
|
<button
|
|
643
682
|
type="button"
|
|
644
683
|
class={{
|
|
@@ -697,7 +736,10 @@ export class BarNav {
|
|
|
697
736
|
</button>
|
|
698
737
|
)}
|
|
699
738
|
|
|
700
|
-
{hasTabs &&
|
|
739
|
+
{hasTabs &&
|
|
740
|
+
this.tabLayoutCommitted &&
|
|
741
|
+
this.tabsCollapsed &&
|
|
742
|
+
this.resolvedActions.length > 0 && (
|
|
701
743
|
<div class="bar-nav__between" aria-hidden="true" />
|
|
702
744
|
)}
|
|
703
745
|
|
|
@@ -719,7 +761,7 @@ export class BarNav {
|
|
|
719
761
|
|
|
720
762
|
</header>
|
|
721
763
|
|
|
722
|
-
{hasTabs && this.tabsCollapsed && (
|
|
764
|
+
{hasTabs && this.tabLayoutCommitted && this.tabsCollapsed && (
|
|
723
765
|
<ds-menu
|
|
724
766
|
ref={el => {
|
|
725
767
|
this.menuEl = (el as HTMLDsMenuElement) ?? null;
|
|
@@ -123,8 +123,14 @@ export class PanelNav {
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
@Watch('collapsed')
|
|
126
|
+
onCollapsedChange(_next: boolean, prev: boolean | undefined) {
|
|
127
|
+
if (prev === undefined) return;
|
|
128
|
+
this.startCollapseAnimation();
|
|
129
|
+
}
|
|
130
|
+
|
|
126
131
|
@Watch('viewportNarrow')
|
|
127
|
-
|
|
132
|
+
onViewportNarrowChange(_next: boolean, prev: boolean | undefined) {
|
|
133
|
+
if (prev === undefined) return;
|
|
128
134
|
this.startCollapseAnimation();
|
|
129
135
|
}
|
|
130
136
|
|
|
@@ -191,17 +197,34 @@ export class PanelNav {
|
|
|
191
197
|
this.isAnimating = true;
|
|
192
198
|
this.dsChromeTransitionStart.emit({ source: 'panel-nav' });
|
|
193
199
|
const panel = this.el.querySelector('.panel-nav') as HTMLElement | null;
|
|
200
|
+
const widthBefore = panel?.getBoundingClientRect().width ?? 0;
|
|
194
201
|
if (this.transitionEndHandler) {
|
|
195
202
|
panel?.removeEventListener('transitionend', this.transitionEndHandler);
|
|
196
203
|
}
|
|
197
204
|
this.transitionEndHandler = (e: TransitionEvent) => {
|
|
198
205
|
if (e.propertyName === 'width') {
|
|
199
|
-
this.
|
|
200
|
-
this.dsChromeTransitionEnd.emit({ source: 'panel-nav' });
|
|
201
|
-
panel?.removeEventListener('transitionend', this.transitionEndHandler!);
|
|
206
|
+
this.finishCollapseAnimation(panel);
|
|
202
207
|
}
|
|
203
208
|
};
|
|
204
209
|
panel?.addEventListener('transitionend', this.transitionEndHandler);
|
|
210
|
+
requestAnimationFrame(() => {
|
|
211
|
+
requestAnimationFrame(() => {
|
|
212
|
+
if (!this.isAnimating) return;
|
|
213
|
+
const widthAfter = panel?.getBoundingClientRect().width ?? 0;
|
|
214
|
+
if (Math.abs(widthAfter - widthBefore) < 1) {
|
|
215
|
+
this.finishCollapseAnimation(panel);
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
private finishCollapseAnimation(panel: HTMLElement | null) {
|
|
222
|
+
if (!this.isAnimating) return;
|
|
223
|
+
this.isAnimating = false;
|
|
224
|
+
this.dsChromeTransitionEnd.emit({ source: 'panel-nav' });
|
|
225
|
+
if (this.transitionEndHandler) {
|
|
226
|
+
panel?.removeEventListener('transitionend', this.transitionEndHandler);
|
|
227
|
+
}
|
|
205
228
|
}
|
|
206
229
|
|
|
207
230
|
private connectResizeObserver() {
|
|
@@ -82,7 +82,10 @@ export class PanelTools {
|
|
|
82
82
|
openChanged(isOpen: boolean, wasOpen?: boolean) {
|
|
83
83
|
if (this.readyForMotion && wasOpen !== undefined && wasOpen !== isOpen) {
|
|
84
84
|
this.motion = isOpen ? 'opening' : 'closing';
|
|
85
|
-
this.dsChromeTransitionStart.emit({
|
|
85
|
+
this.dsChromeTransitionStart.emit({
|
|
86
|
+
source: 'panel-tools',
|
|
87
|
+
phase: isOpen ? 'opening' : 'closing',
|
|
88
|
+
});
|
|
86
89
|
}
|
|
87
90
|
this.deferMotionEnable();
|
|
88
91
|
}
|
|
@@ -7,6 +7,8 @@ export type ChromeTransitionSource = 'panel-nav' | 'panel-tools';
|
|
|
7
7
|
|
|
8
8
|
export interface ChromeTransitionDetail {
|
|
9
9
|
source: ChromeTransitionSource;
|
|
10
|
+
/** Panel-tools drawer motion direction; omitted for panel-nav. */
|
|
11
|
+
phase?: 'opening' | 'closing';
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
/** Reference-counted gate — used while panel-nav width is transitioning. */
|
|
@@ -54,3 +56,7 @@ export function createRafCoalescer(onFrame: () => void): RafCoalescer {
|
|
|
54
56
|
export function readChromeTransitionSource(event: Event): ChromeTransitionSource | undefined {
|
|
55
57
|
return (event as CustomEvent<ChromeTransitionDetail>).detail?.source;
|
|
56
58
|
}
|
|
59
|
+
|
|
60
|
+
export function readChromeTransitionPhase(event: Event): ChromeTransitionDetail['phase'] {
|
|
61
|
+
return (event as CustomEvent<ChromeTransitionDetail>).detail?.phase;
|
|
62
|
+
}
|
package/src/wc/nav/index.ts
CHANGED
|
@@ -34,8 +34,9 @@ export {
|
|
|
34
34
|
shellGradientPositionBar,
|
|
35
35
|
shellChromeSurfacePosition,
|
|
36
36
|
shellChromeLayerActive,
|
|
37
|
+
readShellViewportDimensions,
|
|
37
38
|
} from './shell-gradient';
|
|
38
|
-
export type { ShellGradientLayout } from './shell-gradient';
|
|
39
|
+
export type { ShellGradientLayout, ShellViewportDimensions } from './shell-gradient';
|
|
39
40
|
export type { ChromeTransitionDetail, ChromeTransitionSource } from './chrome-transition';
|
|
40
41
|
export {
|
|
41
42
|
CHROME_TRANSITION_END,
|
|
@@ -43,6 +44,7 @@ export {
|
|
|
43
44
|
ChromeTransitionDepth,
|
|
44
45
|
createRafCoalescer,
|
|
45
46
|
readChromeTransitionSource,
|
|
47
|
+
readChromeTransitionPhase,
|
|
46
48
|
} from './chrome-transition';
|
|
47
49
|
export {
|
|
48
50
|
barGradientPositionFromPanelWidth,
|
|
@@ -30,13 +30,35 @@ export function shellGradientImage(): string {
|
|
|
30
30
|
return buildShellRadialGradient();
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
export interface ShellViewportDimensions {
|
|
34
|
+
width: number;
|
|
35
|
+
height: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Viewport size for shell chrome with `background-attachment: fixed`.
|
|
40
|
+
* Must not use the `ds-app-shell` element box — the shell can be shorter or
|
|
41
|
+
* taller than the viewport when host height chains break or content overflows.
|
|
42
|
+
*/
|
|
43
|
+
export function readShellViewportDimensions(win?: Window): ShellViewportDimensions {
|
|
44
|
+
const w = win ?? (typeof globalThis.window !== 'undefined' ? globalThis.window : undefined);
|
|
45
|
+
if (!w) return { width: 0, height: 0 };
|
|
46
|
+
|
|
47
|
+
const visual = w.visualViewport;
|
|
48
|
+
return {
|
|
49
|
+
width: Math.round(visual?.width ?? w.innerWidth),
|
|
50
|
+
height: Math.round(visual?.height ?? w.innerHeight),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
33
54
|
export interface ShellGradientLayout {
|
|
34
55
|
width: number;
|
|
35
56
|
height: number;
|
|
36
57
|
panelWidth: number;
|
|
37
58
|
}
|
|
38
59
|
|
|
39
|
-
|
|
60
|
+
/** Pixel `background-size` for the fixed-attachment radial wash. */
|
|
61
|
+
export function shellGradientSize(layout: Pick<ShellGradientLayout, 'width' | 'height'>): string {
|
|
40
62
|
return `${Math.round(layout.width)}px ${Math.round(layout.height)}px`;
|
|
41
63
|
}
|
|
42
64
|
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const t="dsChromeTransitionStart";const n="dsChromeTransitionEnd";class e{constructor(){this.depth=0}enter(){this.depth+=1}exit(){this.depth=Math.max(0,this.depth-1)}get isActive(){return this.depth>0}}function i(t){let n=0;return{schedule(){if(n!==0)return;n=requestAnimationFrame((()=>{n=0;t()}))},cancel(){if(n!==0){cancelAnimationFrame(n);n=0}}}}function r(t){return t.detail?.source}function s(t,n){if(typeof document==="undefined")return 0;const e=document.createElement("div");e.style.cssText="position:absolute;visibility:hidden;pointer-events:none;height:0;width:var("+n+");";t.appendChild(e);const i=e.getBoundingClientRect().width;t.removeChild(e);return i}function a(t){return{expandedPx:s(t,"--_nav-width"),collapsedPx:s(t,"--_nav-width-collapsed")}}function o(t,n){if(n?.classList.contains("panel-nav--collapsed"))return true;const e=t?.collapsed;return e===true}function c(t,n){return n?t.collapsedPx:t.expandedPx}export{e as C,t as a,n as b,i as c,a as d,s as e,o as i,c as p,r};
|
|
2
|
-
//# sourceMappingURL=p-1HlgCxGN.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":["CHROME_TRANSITION_START","CHROME_TRANSITION_END","ChromeTransitionDepth","constructor","this","depth","enter","exit","Math","max","isActive","createRafCoalescer","onFrame","rafId","schedule","requestAnimationFrame","cancel","cancelAnimationFrame","readChromeTransitionSource","event","detail","source","readCssVarWidthPx","context","cssVarName","document","probe","createElement","style","cssText","appendChild","width","getBoundingClientRect","removeChild","readPanelNavWidthTokens","navRoot","expandedPx","collapsedPx","isPanelNavCollapsed","panelNavHost","classList","contains","collapsedProp","collapsed","panelWidthPxFromTokens","tokens"],"sources":["src/wc/nav/chrome-transition.ts","src/wc/nav/shell-chrome-metrics.ts"],"sourcesContent":["/** Bubbling/composed events — `ds-app-shell` and `ds-bar-nav` coordinate during width motion. */\n\nexport const CHROME_TRANSITION_START = 'dsChromeTransitionStart';\nexport const CHROME_TRANSITION_END = 'dsChromeTransitionEnd';\n\nexport type ChromeTransitionSource = 'panel-nav' | 'panel-tools';\n\nexport interface ChromeTransitionDetail {\n source: ChromeTransitionSource;\n}\n\n/** Reference-counted gate — used while panel-nav width is transitioning. */\nexport class ChromeTransitionDepth {\n private depth = 0;\n\n enter(): void {\n this.depth += 1;\n }\n\n exit(): void {\n this.depth = Math.max(0, this.depth - 1);\n }\n\n get isActive(): boolean {\n return this.depth > 0;\n }\n}\n\nexport interface RafCoalescer {\n schedule(): void;\n cancel(): void;\n}\n\n/** Coalesce bursty layout work (ResizeObserver, prop churn) to one callback per frame. */\nexport function createRafCoalescer(onFrame: () => void): RafCoalescer {\n let rafId = 0;\n return {\n schedule() {\n if (rafId !== 0) return;\n rafId = requestAnimationFrame(() => {\n rafId = 0;\n onFrame();\n });\n },\n cancel() {\n if (rafId !== 0) {\n cancelAnimationFrame(rafId);\n rafId = 0;\n }\n },\n };\n}\n\nexport function readChromeTransitionSource(event: Event): ChromeTransitionSource | undefined {\n return (event as CustomEvent<ChromeTransitionDetail>).detail?.source;\n}\n","import { shellGradientPositionBar } from './shell-gradient';\n\n/** Read a `var(--token)` width in px using a hidden probe (works with calc() tokens). */\nexport function readCssVarWidthPx(context: HTMLElement, cssVarName: string): number {\n if (typeof document === 'undefined') return 0;\n\n const probe = document.createElement('div');\n probe.style.cssText =\n 'position:absolute;visibility:hidden;pointer-events:none;height:0;width:var(' +\n cssVarName +\n ');';\n context.appendChild(probe);\n const width = probe.getBoundingClientRect().width;\n context.removeChild(probe);\n return width;\n}\n\nexport interface PanelNavWidthTokens {\n expandedPx: number;\n collapsedPx: number;\n}\n\n/** Resolve panel-nav expanded/collapsed widths from scoped CSS vars on `.panel-nav`. */\nexport function readPanelNavWidthTokens(navRoot: HTMLElement): PanelNavWidthTokens {\n return {\n expandedPx: readCssVarWidthPx(navRoot, '--_nav-width'),\n collapsedPx: readCssVarWidthPx(navRoot, '--_nav-width-collapsed'),\n };\n}\n\nexport function isPanelNavCollapsed(\n panelNavHost: HTMLElement | null,\n navRoot: HTMLElement | null,\n): boolean {\n if (navRoot?.classList.contains('panel-nav--collapsed')) return true;\n const collapsedProp = (panelNavHost as (HTMLElement & { collapsed?: boolean }) | null)?.collapsed;\n return collapsedProp === true;\n}\n\nexport function panelWidthPxFromTokens(\n tokens: PanelNavWidthTokens,\n collapsed: boolean,\n): number {\n return collapsed ? tokens.collapsedPx : tokens.expandedPx;\n}\n\nexport function barGradientPositionFromPanelWidth(panelWidthPx: number): string {\n return shellGradientPositionBar(panelWidthPx);\n}\n"],"mappings":"AAEO,MAAMA,EAA0B,0BAChC,MAAMC,EAAwB,wB,MASxBC,EAAb,WAAAC,GACUC,KAAAC,MAAQ,C,CAEhB,KAAAC,GACEF,KAAKC,OAAS,C,CAGhB,IAAAE,GACEH,KAAKC,MAAQG,KAAKC,IAAI,EAAGL,KAAKC,MAAQ,E,CAGxC,YAAIK,GACF,OAAON,KAAKC,MAAQ,C,EAUlB,SAAUM,EAAmBC,GACjC,IAAIC,EAAQ,EACZ,MAAO,CACL,QAAAC,GACE,GAAID,IAAU,EAAG,OACjBA,EAAQE,uBAAsB,KAC5BF,EAAQ,EACRD,GAAS,G,EAGb,MAAAI,GACE,GAAIH,IAAU,EAAG,CACfI,qBAAqBJ,GACrBA,EAAQ,C,GAIhB,CAEM,SAAUK,EAA2BC,GACzC,OAAQA,EAA8CC,QAAQC,MAChE,CCpDM,SAAUC,EAAkBC,EAAsBC,GACtD,UAAWC,WAAa,YAAa,OAAO,EAE5C,MAAMC,EAAQD,SAASE,cAAc,OACrCD,EAAME,MAAMC,QACV,8EACAL,EACA,KACFD,EAAQO,YAAYJ,GACpB,MAAMK,EAAQL,EAAMM,wBAAwBD,MAC5CR,EAAQU,YAAYP,GACpB,OAAOK,CACT,CAQM,SAAUG,EAAwBC,GACtC,MAAO,CACLC,WAAYd,EAAkBa,EAAS,gBACvCE,YAAaf,EAAkBa,EAAS,0BAE5C,CAEM,SAAUG,EACdC,EACAJ,GAEA,GAAIA,GAASK,UAAUC,SAAS,wBAAyB,OAAO,KAChE,MAAMC,EAAiBH,GAAiEI,UACxF,OAAOD,IAAkB,IAC3B,CAEM,SAAUE,EACdC,EACAF,GAEA,OAAOA,EAAYE,EAAOR,YAAcQ,EAAOT,UACjD,Q","ignoreList":[]}
|