@ds-mo/ui 1.11.1 → 1.11.3
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-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 +4 -3
- 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 +58 -35
- package/src/wc/components/PanelTools/PanelTools.tsx +5 -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
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
SHELL_GRADIENT_POSITION_PANEL_VAR,
|
|
22
22
|
SHELL_GRADIENT_SIZE_VAR,
|
|
23
23
|
buildShellRadialGradient,
|
|
24
|
+
readShellViewportDimensions,
|
|
24
25
|
shellGradientPositionBar,
|
|
25
26
|
shellGradientPositionPanel,
|
|
26
27
|
shellGradientSize,
|
|
@@ -53,12 +54,21 @@ export class AppShell {
|
|
|
53
54
|
private readonly panelNavTransition = new ChromeTransitionDepth();
|
|
54
55
|
private readonly chromeSyncCoalescer = createRafCoalescer(() => this.syncChrome());
|
|
55
56
|
private panelWidthTokens: PanelNavWidthTokens = { expandedPx: 0, collapsedPx: 0 };
|
|
56
|
-
private
|
|
57
|
-
private
|
|
57
|
+
private cachedViewportWidth = 0;
|
|
58
|
+
private cachedViewportHeight = 0;
|
|
59
|
+
private onWindowResize = () => {
|
|
60
|
+
if (this.panelNavTransition.isActive) return;
|
|
61
|
+
this.scheduleChromeSync();
|
|
62
|
+
};
|
|
63
|
+
private onVisualViewportChange = () => {
|
|
64
|
+
if (this.panelNavTransition.isActive) return;
|
|
65
|
+
this.scheduleChromeSync();
|
|
66
|
+
};
|
|
58
67
|
|
|
59
68
|
componentDidLoad() {
|
|
60
69
|
this.syncSlottedNavStyle();
|
|
61
70
|
this.connectMetricsObserver();
|
|
71
|
+
this.connectViewportListeners();
|
|
62
72
|
this.el.addEventListener(CHROME_TRANSITION_START, this.onChromeTransitionStart);
|
|
63
73
|
this.el.addEventListener(CHROME_TRANSITION_END, this.onChromeTransitionEnd);
|
|
64
74
|
requestAnimationFrame(() => {
|
|
@@ -70,6 +80,7 @@ export class AppShell {
|
|
|
70
80
|
disconnectedCallback() {
|
|
71
81
|
this.resizeObserver?.disconnect();
|
|
72
82
|
this.resizeObserver = null;
|
|
83
|
+
this.disconnectViewportListeners();
|
|
73
84
|
this.chromeSyncCoalescer.cancel();
|
|
74
85
|
this.el.removeEventListener(CHROME_TRANSITION_START, this.onChromeTransitionStart);
|
|
75
86
|
this.el.removeEventListener(CHROME_TRANSITION_END, this.onChromeTransitionEnd);
|
|
@@ -88,8 +99,9 @@ export class AppShell {
|
|
|
88
99
|
if (readChromeTransitionSource(event) !== 'panel-nav') return;
|
|
89
100
|
|
|
90
101
|
this.panelNavTransition.enter();
|
|
91
|
-
|
|
92
|
-
this.
|
|
102
|
+
const viewport = readShellViewportDimensions();
|
|
103
|
+
this.cachedViewportWidth = viewport.width;
|
|
104
|
+
this.cachedViewportHeight = viewport.height;
|
|
93
105
|
this.syncChrome();
|
|
94
106
|
};
|
|
95
107
|
|
|
@@ -130,6 +142,30 @@ export class AppShell {
|
|
|
130
142
|
if (panelWrap) this.resizeObserver.observe(panelWrap);
|
|
131
143
|
}
|
|
132
144
|
|
|
145
|
+
private connectViewportListeners() {
|
|
146
|
+
if (typeof window === 'undefined') return;
|
|
147
|
+
|
|
148
|
+
window.addEventListener('resize', this.onWindowResize, { passive: true });
|
|
149
|
+
|
|
150
|
+
const visual = window.visualViewport;
|
|
151
|
+
if (visual) {
|
|
152
|
+
visual.addEventListener('resize', this.onVisualViewportChange, { passive: true });
|
|
153
|
+
visual.addEventListener('scroll', this.onVisualViewportChange, { passive: true });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
private disconnectViewportListeners() {
|
|
158
|
+
if (typeof window === 'undefined') return;
|
|
159
|
+
|
|
160
|
+
window.removeEventListener('resize', this.onWindowResize);
|
|
161
|
+
|
|
162
|
+
const visual = window.visualViewport;
|
|
163
|
+
if (visual) {
|
|
164
|
+
visual.removeEventListener('resize', this.onVisualViewportChange);
|
|
165
|
+
visual.removeEventListener('scroll', this.onVisualViewportChange);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
133
169
|
private cachePanelWidthTokens() {
|
|
134
170
|
const navRoot = this.el.querySelector('ds-panel-nav .panel-nav') as HTMLElement | null;
|
|
135
171
|
if (!navRoot) return;
|
|
@@ -190,16 +226,16 @@ export class AppShell {
|
|
|
190
226
|
return 0;
|
|
191
227
|
}
|
|
192
228
|
|
|
193
|
-
|
|
194
|
-
|
|
229
|
+
/** Fixed-attachment wash/grid size — always the viewport, never the shell element box. */
|
|
230
|
+
private resolveViewportDimensions(): { width: number; height: number } {
|
|
231
|
+
if (this.panelNavTransition.isActive && this.cachedViewportWidth > 0) {
|
|
195
232
|
return {
|
|
196
|
-
width: this.
|
|
197
|
-
height: this.
|
|
233
|
+
width: this.cachedViewportWidth,
|
|
234
|
+
height: this.cachedViewportHeight,
|
|
198
235
|
};
|
|
199
236
|
}
|
|
200
237
|
|
|
201
|
-
|
|
202
|
-
return { width: rect.width, height: rect.height };
|
|
238
|
+
return readShellViewportDimensions();
|
|
203
239
|
}
|
|
204
240
|
|
|
205
241
|
private chromeLayerActive(): boolean {
|
|
@@ -228,7 +264,7 @@ export class AppShell {
|
|
|
228
264
|
return;
|
|
229
265
|
}
|
|
230
266
|
|
|
231
|
-
const
|
|
267
|
+
const viewport = this.resolveViewportDimensions();
|
|
232
268
|
const panelWidth = this.resolvePanelWidthPx(panelNav);
|
|
233
269
|
|
|
234
270
|
const panelPosition = shellGradientPositionPanel();
|
|
@@ -241,9 +277,8 @@ export class AppShell {
|
|
|
241
277
|
: buildShellRadialGradient();
|
|
242
278
|
|
|
243
279
|
const size = shellGradientSize({
|
|
244
|
-
width:
|
|
245
|
-
height:
|
|
246
|
-
panelWidth,
|
|
280
|
+
width: viewport.width,
|
|
281
|
+
height: viewport.height,
|
|
247
282
|
});
|
|
248
283
|
const opacity = SHELL_GRADIENT_OPACITY;
|
|
249
284
|
|
|
@@ -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',
|
|
@@ -111,12 +112,12 @@ export class BarNav {
|
|
|
111
112
|
private resizeObserver: ResizeObserver | null = null;
|
|
112
113
|
private intrinsicWidthRetryCount = 0;
|
|
113
114
|
private readonly panelNavTransition = new ChromeTransitionDepth();
|
|
115
|
+
private readonly panelToolsTransition = new ChromeTransitionDepth();
|
|
114
116
|
private readonly overflowCoalescer = createRafCoalescer(() => {
|
|
115
117
|
this.updateTabsCollapsed();
|
|
116
118
|
this.updateTriggerLabelTruncation();
|
|
117
119
|
});
|
|
118
120
|
private chromeTransitionShell: HTMLElement | null = null;
|
|
119
|
-
private toolsDrawerOpening = false;
|
|
120
121
|
/** Matches `basePath` once tabs + URL are reconciled for the active section. */
|
|
121
122
|
@State() private committedSection = '';
|
|
122
123
|
/** Section waiting for URL + tabs to catch up after a cross-area navigation. */
|
|
@@ -137,6 +138,17 @@ export class BarNav {
|
|
|
137
138
|
return !!getActiveTab(this.resolvedTabs, this.effectiveValue)?.dot;
|
|
138
139
|
}
|
|
139
140
|
|
|
141
|
+
private digestTabsConfig(tabs: BarNavTab[]): string {
|
|
142
|
+
return tabs.map(t => (isTabDivider(t) ? '|' : t.id)).join(',');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
private resetTabOverflowLayout() {
|
|
146
|
+
this.tabLayoutCommitted = false;
|
|
147
|
+
this.tabsCollapsed = false;
|
|
148
|
+
this.menuOpen = false;
|
|
149
|
+
this.intrinsicWidthRetryCount = 0;
|
|
150
|
+
}
|
|
151
|
+
|
|
140
152
|
@Watch('tabs')
|
|
141
153
|
@Watch('tabsJson')
|
|
142
154
|
@Watch('actions')
|
|
@@ -194,7 +206,7 @@ export class BarNav {
|
|
|
194
206
|
}
|
|
195
207
|
|
|
196
208
|
componentDidRender() {
|
|
197
|
-
if (this.
|
|
209
|
+
if (this.chromeOverflowPaused()) {
|
|
198
210
|
this.syncMenuAnchor();
|
|
199
211
|
return;
|
|
200
212
|
}
|
|
@@ -241,16 +253,17 @@ export class BarNav {
|
|
|
241
253
|
return;
|
|
242
254
|
}
|
|
243
255
|
if (source === 'panel-tools') {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
this.tabsCollapsed = true;
|
|
248
|
-
this.menuOpen = false;
|
|
256
|
+
const phase = readChromeTransitionPhase(event) ?? 'opening';
|
|
257
|
+
if (phase === 'closing') {
|
|
258
|
+
this.panelToolsTransition.enter();
|
|
249
259
|
}
|
|
250
|
-
this.scheduleOverflowCheck();
|
|
251
260
|
}
|
|
252
261
|
};
|
|
253
262
|
|
|
263
|
+
private chromeOverflowPaused(): boolean {
|
|
264
|
+
return this.panelNavTransition.isActive || this.panelToolsTransition.isActive;
|
|
265
|
+
}
|
|
266
|
+
|
|
254
267
|
private onChromeTransitionEnd = (event: Event) => {
|
|
255
268
|
const source = readChromeTransitionSource(event);
|
|
256
269
|
if (source === 'panel-nav') {
|
|
@@ -261,8 +274,7 @@ export class BarNav {
|
|
|
261
274
|
return;
|
|
262
275
|
}
|
|
263
276
|
if (source === 'panel-tools') {
|
|
264
|
-
this.
|
|
265
|
-
this.el.classList.remove('bar-nav--tools-drawer-opening');
|
|
277
|
+
this.panelToolsTransition.exit();
|
|
266
278
|
this.scheduleOverflowCheck();
|
|
267
279
|
}
|
|
268
280
|
};
|
|
@@ -301,14 +313,14 @@ export class BarNav {
|
|
|
301
313
|
if (typeof ResizeObserver === 'undefined' || !this.headerEl) return;
|
|
302
314
|
this.resizeObserver?.disconnect();
|
|
303
315
|
this.resizeObserver = new ResizeObserver(() => {
|
|
304
|
-
if (this.
|
|
316
|
+
if (this.chromeOverflowPaused()) return;
|
|
305
317
|
this.scheduleOverflowCheck();
|
|
306
318
|
});
|
|
307
319
|
this.resizeObserver.observe(this.headerEl);
|
|
308
320
|
}
|
|
309
321
|
|
|
310
322
|
private scheduleOverflowCheck() {
|
|
311
|
-
if (this.
|
|
323
|
+
if (this.chromeOverflowPaused()) return;
|
|
312
324
|
this.overflowCoalescer.schedule();
|
|
313
325
|
}
|
|
314
326
|
|
|
@@ -366,20 +378,7 @@ export class BarNav {
|
|
|
366
378
|
const available =
|
|
367
379
|
this.headerEl.clientWidth - horizontalPadding - actionsWidth - spacing;
|
|
368
380
|
|
|
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);
|
|
381
|
+
return Math.max(0, available);
|
|
383
382
|
}
|
|
384
383
|
|
|
385
384
|
private getTabsIntrinsicWidth(): number {
|
|
@@ -400,12 +399,19 @@ export class BarNav {
|
|
|
400
399
|
this.menuOpen = false;
|
|
401
400
|
}
|
|
402
401
|
this.intrinsicWidthRetryCount = 0;
|
|
402
|
+
this.tabLayoutCommitted = true;
|
|
403
403
|
return;
|
|
404
404
|
}
|
|
405
405
|
|
|
406
406
|
const intrinsicWidth = this.getTabsIntrinsicWidth();
|
|
407
407
|
if (intrinsicWidth === 0) {
|
|
408
|
-
this.
|
|
408
|
+
if (this.intrinsicWidthRetryCount >= BarNav.INTRINSIC_WIDTH_RETRY_MAX) {
|
|
409
|
+
this.intrinsicWidthRetryCount = 0;
|
|
410
|
+
this.tabsCollapsed = false;
|
|
411
|
+
this.tabLayoutCommitted = true;
|
|
412
|
+
} else {
|
|
413
|
+
this.scheduleIntrinsicWidthRetry();
|
|
414
|
+
}
|
|
409
415
|
return;
|
|
410
416
|
}
|
|
411
417
|
this.intrinsicWidthRetryCount = 0;
|
|
@@ -423,6 +429,8 @@ export class BarNav {
|
|
|
423
429
|
this.menuOpen = false;
|
|
424
430
|
}
|
|
425
431
|
}
|
|
432
|
+
|
|
433
|
+
this.tabLayoutCommitted = true;
|
|
426
434
|
}
|
|
427
435
|
|
|
428
436
|
private syncMenuAnchor() {
|
|
@@ -469,6 +477,7 @@ export class BarNav {
|
|
|
469
477
|
this.pendingSection = nextBasePath;
|
|
470
478
|
this.resolvedTabs = [];
|
|
471
479
|
this.resolvedActions = this.incomingActions();
|
|
480
|
+
this.resetTabOverflowLayout();
|
|
472
481
|
return;
|
|
473
482
|
}
|
|
474
483
|
|
|
@@ -486,11 +495,17 @@ export class BarNav {
|
|
|
486
495
|
this.pendingSection = '';
|
|
487
496
|
}
|
|
488
497
|
|
|
489
|
-
|
|
498
|
+
const tabs = this.incomingTabs();
|
|
499
|
+
const tabsConfigChanged =
|
|
500
|
+
this.digestTabsConfig(tabs) !== this.digestTabsConfig(this.resolvedTabs);
|
|
501
|
+
|
|
502
|
+
this.resolvedTabs = tabs;
|
|
490
503
|
this.resolvedActions = this.incomingActions();
|
|
491
504
|
this.syncValueFromUrl();
|
|
492
505
|
this.committedSection = nextBasePath;
|
|
493
|
-
|
|
506
|
+
if (tabsConfigChanged) {
|
|
507
|
+
this.resetTabOverflowLayout();
|
|
508
|
+
}
|
|
494
509
|
this.scheduleOverflowCheck();
|
|
495
510
|
}
|
|
496
511
|
|
|
@@ -593,7 +608,8 @@ export class BarNav {
|
|
|
593
608
|
'bar-nav': true,
|
|
594
609
|
'bar-nav--dashboard': this.navStyle === 'dashboard',
|
|
595
610
|
'bar-nav--settings': this.navStyle === 'settings',
|
|
596
|
-
'bar-nav--tabs-collapsed':
|
|
611
|
+
'bar-nav--tabs-collapsed':
|
|
612
|
+
hasTabs && this.tabLayoutCommitted && this.tabsCollapsed,
|
|
597
613
|
}}
|
|
598
614
|
ref={el => {
|
|
599
615
|
this.headerEl = el as HTMLElement;
|
|
@@ -619,7 +635,7 @@ export class BarNav {
|
|
|
619
635
|
</div>
|
|
620
636
|
)}
|
|
621
637
|
|
|
622
|
-
{hasTabs && !this.tabsCollapsed && (
|
|
638
|
+
{hasTabs && this.tabLayoutCommitted && !this.tabsCollapsed && (
|
|
623
639
|
<div class="bar-nav__left">
|
|
624
640
|
<ds-tab-group-nav
|
|
625
641
|
key={`visible-${tabGroupKey}`}
|
|
@@ -634,11 +650,15 @@ export class BarNav {
|
|
|
634
650
|
</div>
|
|
635
651
|
)}
|
|
636
652
|
|
|
653
|
+
{hasTabs && !this.tabLayoutCommitted && (
|
|
654
|
+
<div class="bar-nav__tabs-pending" aria-hidden="true" />
|
|
655
|
+
)}
|
|
656
|
+
|
|
637
657
|
{!hasTabs && this.heading && (
|
|
638
658
|
<span class="bar-nav__heading text-body-medium-emphasis">{this.heading}</span>
|
|
639
659
|
)}
|
|
640
660
|
|
|
641
|
-
{hasTabs && this.tabsCollapsed && (
|
|
661
|
+
{hasTabs && this.tabLayoutCommitted && this.tabsCollapsed && (
|
|
642
662
|
<button
|
|
643
663
|
type="button"
|
|
644
664
|
class={{
|
|
@@ -697,7 +717,10 @@ export class BarNav {
|
|
|
697
717
|
</button>
|
|
698
718
|
)}
|
|
699
719
|
|
|
700
|
-
{hasTabs &&
|
|
720
|
+
{hasTabs &&
|
|
721
|
+
this.tabLayoutCommitted &&
|
|
722
|
+
this.tabsCollapsed &&
|
|
723
|
+
this.resolvedActions.length > 0 && (
|
|
701
724
|
<div class="bar-nav__between" aria-hidden="true" />
|
|
702
725
|
)}
|
|
703
726
|
|
|
@@ -719,7 +742,7 @@ export class BarNav {
|
|
|
719
742
|
|
|
720
743
|
</header>
|
|
721
744
|
|
|
722
|
-
{hasTabs && this.tabsCollapsed && (
|
|
745
|
+
{hasTabs && this.tabLayoutCommitted && this.tabsCollapsed && (
|
|
723
746
|
<ds-menu
|
|
724
747
|
ref={el => {
|
|
725
748
|
this.menuEl = (el as HTMLDsMenuElement) ?? null;
|
|
@@ -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
|
}
|
|
@@ -182,6 +185,7 @@ export class PanelTools {
|
|
|
182
185
|
'panel-tools__drawer--visible': showDrawerChrome,
|
|
183
186
|
}}
|
|
184
187
|
aria-hidden={showDrawerChrome ? null : 'true'}
|
|
188
|
+
inert={showDrawerChrome ? undefined : true}
|
|
185
189
|
>
|
|
186
190
|
<div class="panel-tools__drawer-surface">
|
|
187
191
|
<header class="panel-tools__header">
|
|
@@ -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":[]}
|