@ds-mo/ui 1.8.0 → 1.9.0
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-badge.js +1 -1
- package/dist/components/ds-banner.js +1 -1
- package/dist/components/ds-bar-nav-action.js +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-fade.js +1 -1
- package/dist/components/ds-fade.js.map +1 -1
- package/dist/components/ds-menu.js +1 -1
- package/dist/components/ds-modal.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-select.js +1 -1
- package/dist/components/ds-slider.js +1 -1
- package/dist/components/ds-slider.js.map +1 -1
- package/dist/components/ds-tab-group-nav.js +1 -1
- package/dist/components/ds-tab-group.js +1 -1
- package/dist/components/ds-toast-provider.js +1 -1
- package/dist/components/ds-toggle.js +1 -1
- package/dist/components/ds-tooltip.js +1 -1
- package/dist/components/{p-BvmooLHV.js → p-C1cBr-Ri.js} +2 -2
- package/dist/components/{p-DrvpsLK6.js → p-CCZFMcLe.js} +2 -2
- package/dist/components/p-CiEc8Nwx.js +2 -0
- package/dist/components/p-CiEc8Nwx.js.map +1 -0
- package/dist/components/{p-C4VSrrAB.js → p-CuuuDjJJ.js} +2 -2
- package/dist/components/p-Dl1GvZQ2.js +2 -0
- package/dist/components/p-Dl1GvZQ2.js.map +1 -0
- package/dist/components/{p-DZDXwEMg.js → p-DlsexsFg.js} +2 -2
- package/dist/components/p-g6MCxfm4.js +2 -0
- package/dist/components/p-g6MCxfm4.js.map +1 -0
- package/dist/types/components/AppShell/AppShell.d.ts +7 -5
- package/dist/types/components/BarNav/BarNav.d.ts +2 -4
- package/dist/types/components/PanelNav/PanelNav.d.ts +4 -13
- package/dist/types/components/PanelNav/index.d.ts +1 -1
- package/dist/types/components/PanelNav/panel-nav-utils.d.ts +0 -9
- package/dist/types/components/PanelTools/PanelTools.d.ts +29 -11
- package/dist/types/components/PanelTools/index.d.ts +2 -2
- package/dist/types/components/PanelTools/panel-tools-types.d.ts +15 -2
- package/dist/types/components/PanelTools/panel-tools-utils.d.ts +4 -0
- package/dist/types/components.d.ts +67 -21
- package/dist/types/nav/badge-gradient-ring.d.ts +1 -1
- package/dist/types/nav/index.d.ts +1 -1
- package/dist/types/nav/nav-chrome.d.ts +4 -8
- package/dist/types/nav/shell-gradient.d.ts +6 -3
- package/package.json +2 -2
- package/src/angular/proxies.ts +12 -3
- package/src/react/ds-panel-tools.ts +4 -3
- package/src/wc/components/AppShell/AppShell.tsx +54 -38
- package/src/wc/components/Badge/Badge.tsx +3 -12
- package/src/wc/components/BarNav/BarNav.tsx +6 -18
- package/src/wc/components/PanelNav/PanelNav.tsx +23 -103
- package/src/wc/components/PanelNav/index.ts +0 -1
- package/src/wc/components/PanelNav/panel-nav-utils.ts +0 -13
- package/src/wc/components/PanelTools/PanelTools.tsx +162 -80
- package/src/wc/components/PanelTools/index.ts +6 -2
- package/src/wc/components/PanelTools/panel-tools-types.ts +18 -3
- package/src/wc/components/PanelTools/panel-tools-utils.ts +31 -0
- package/src/wc/components.d.ts +67 -21
- package/src/wc/nav/badge-gradient-ring.ts +3 -8
- package/src/wc/nav/index.ts +3 -1
- package/src/wc/nav/nav-chrome.ts +19 -17
- package/src/wc/nav/shell-gradient.ts +9 -4
- package/src/wc/nav/shell-view-transition.ts +13 -6
- package/dist/components/p-B8VZmH43.js +0 -2
- package/dist/components/p-B8VZmH43.js.map +0 -1
- package/dist/components/p-BucV1U6A.js +0 -2
- package/dist/components/p-BucV1U6A.js.map +0 -1
- package/dist/components/p-CX7-_qOW.js +0 -2
- package/dist/components/p-CX7-_qOW.js.map +0 -1
- package/dist/components/p-TtnqbcnR.js +0 -2
- package/dist/components/p-TtnqbcnR.js.map +0 -1
- /package/dist/components/{p-BvmooLHV.js.map → p-C1cBr-Ri.js.map} +0 -0
- /package/dist/components/{p-DrvpsLK6.js.map → p-CCZFMcLe.js.map} +0 -0
- /package/dist/components/{p-C4VSrrAB.js.map → p-CuuuDjJJ.js.map} +0 -0
- /package/dist/components/{p-DZDXwEMg.js.map → p-DlsexsFg.js.map} +0 -0
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
SHELL_GRADIENT_POSITION_BAR_VAR,
|
|
8
8
|
SHELL_GRADIENT_POSITION_PANEL_VAR,
|
|
9
9
|
SHELL_GRADIENT_SIZE_VAR,
|
|
10
|
-
|
|
10
|
+
buildShellRadialGradient,
|
|
11
11
|
shellGradientPositionBar,
|
|
12
12
|
shellGradientPositionPanel,
|
|
13
13
|
shellGradientSize,
|
|
@@ -20,9 +20,9 @@ import {
|
|
|
20
20
|
})
|
|
21
21
|
export class AppShell {
|
|
22
22
|
/** Chrome style propagated to slotted `ds-panel-nav` and `ds-bar-nav`. */
|
|
23
|
-
@Prop({ attribute: 'nav-style', reflect: true }) navStyle: NavChromeStyle = '
|
|
23
|
+
@Prop({ attribute: 'nav-style', reflect: true }) navStyle: NavChromeStyle = 'dashboard';
|
|
24
24
|
|
|
25
|
-
/** When `true`, paints the shared
|
|
25
|
+
/** When `true`, paints the shared chrome surface (bg + wash + grid) behind panel, bar, and tools. */
|
|
26
26
|
@Prop({ reflect: true }) gradient: boolean = false;
|
|
27
27
|
|
|
28
28
|
/**
|
|
@@ -38,12 +38,12 @@ export class AppShell {
|
|
|
38
38
|
componentDidLoad() {
|
|
39
39
|
this.syncSlottedNavStyle();
|
|
40
40
|
this.connectMetricsObserver();
|
|
41
|
-
this.
|
|
41
|
+
this.scheduleChromeSync();
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
private
|
|
45
|
-
this.
|
|
46
|
-
requestAnimationFrame(() => this.
|
|
44
|
+
private scheduleChromeSync() {
|
|
45
|
+
this.syncChrome();
|
|
46
|
+
requestAnimationFrame(() => this.syncChrome());
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
disconnectedCallback() {
|
|
@@ -56,17 +56,28 @@ export class AppShell {
|
|
|
56
56
|
@Watch('gradientSrc')
|
|
57
57
|
onShellPropsChange() {
|
|
58
58
|
this.syncSlottedNavStyle();
|
|
59
|
-
this.
|
|
59
|
+
this.scheduleChromeSync();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private syncSlottedNavStyle() {
|
|
63
|
+
const panel = this.el.querySelector('ds-panel-nav') as (HTMLElement & { navStyle: NavChromeStyle }) | null;
|
|
64
|
+
const bar = this.el.querySelector('ds-bar-nav') as (HTMLElement & { navStyle: NavChromeStyle }) | null;
|
|
65
|
+
if (panel) {
|
|
66
|
+
panel.setAttribute('nav-style', this.navStyle);
|
|
67
|
+
panel.navStyle = this.navStyle;
|
|
68
|
+
}
|
|
69
|
+
if (bar) {
|
|
70
|
+
bar.setAttribute('nav-style', this.navStyle);
|
|
71
|
+
bar.navStyle = this.navStyle;
|
|
72
|
+
}
|
|
60
73
|
}
|
|
61
74
|
|
|
62
75
|
private connectMetricsObserver() {
|
|
63
|
-
this.resizeObserver = new ResizeObserver(() => this.
|
|
76
|
+
this.resizeObserver = new ResizeObserver(() => this.scheduleChromeSync());
|
|
64
77
|
this.resizeObserver.observe(this.el);
|
|
65
78
|
const panelWrap = this.el.querySelector('.app-shell__panel');
|
|
66
|
-
const barWrap = this.el.querySelector('.app-shell__bar');
|
|
67
79
|
if (panelWrap) this.resizeObserver.observe(panelWrap);
|
|
68
|
-
|
|
69
|
-
this.scheduleGradientVars();
|
|
80
|
+
this.scheduleChromeSync();
|
|
70
81
|
}
|
|
71
82
|
|
|
72
83
|
private applyGradientVars(target: HTMLElement, vars: Record<string, string | null>) {
|
|
@@ -77,12 +88,10 @@ export class AppShell {
|
|
|
77
88
|
}
|
|
78
89
|
}
|
|
79
90
|
|
|
80
|
-
private
|
|
91
|
+
private clearGradientPaintVars(targets: HTMLElement[]) {
|
|
81
92
|
const keys = [
|
|
82
93
|
SHELL_GRADIENT_IMAGE_VAR,
|
|
83
94
|
SHELL_GRADIENT_SIZE_VAR,
|
|
84
|
-
SHELL_GRADIENT_POSITION_PANEL_VAR,
|
|
85
|
-
SHELL_GRADIENT_POSITION_BAR_VAR,
|
|
86
95
|
SHELL_GRADIENT_OPACITY_VAR,
|
|
87
96
|
];
|
|
88
97
|
for (const target of targets) {
|
|
@@ -90,44 +99,49 @@ export class AppShell {
|
|
|
90
99
|
}
|
|
91
100
|
}
|
|
92
101
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
102
|
+
/** Panel/bar wash offsets for scroll fades and badge rings. */
|
|
103
|
+
private syncChromeLayoutVars(
|
|
104
|
+
panel: HTMLElement | null,
|
|
105
|
+
bar: HTMLElement | null,
|
|
106
|
+
panelPosition: string,
|
|
107
|
+
barPosition: string,
|
|
108
|
+
) {
|
|
96
109
|
if (panel) {
|
|
97
|
-
panel.
|
|
98
|
-
panel.navStyle = this.navStyle;
|
|
110
|
+
panel.style.setProperty(SHELL_GRADIENT_POSITION_PANEL_VAR, panelPosition);
|
|
99
111
|
}
|
|
100
112
|
if (bar) {
|
|
101
|
-
bar.
|
|
102
|
-
bar.navStyle = this.navStyle;
|
|
113
|
+
bar.style.setProperty(SHELL_GRADIENT_POSITION_BAR_VAR, barPosition);
|
|
103
114
|
}
|
|
104
115
|
}
|
|
105
116
|
|
|
106
|
-
private
|
|
117
|
+
private syncChrome() {
|
|
107
118
|
const panel = this.el.querySelector('ds-panel-nav') as HTMLElement | null;
|
|
108
119
|
const bar = this.el.querySelector('ds-bar-nav') as HTMLElement | null;
|
|
109
120
|
const targets = [this.el, panel, bar].filter((el): el is HTMLElement => el !== null);
|
|
110
121
|
|
|
122
|
+
const shellRect = this.el.getBoundingClientRect();
|
|
123
|
+
const panelWrap = this.el.querySelector('.app-shell__panel') as HTMLElement | null;
|
|
124
|
+
const panelWidth = panelWrap?.getBoundingClientRect().width ?? 0;
|
|
125
|
+
|
|
126
|
+
const panelPosition = shellGradientPositionPanel();
|
|
127
|
+
const barPosition = shellGradientPositionBar(panelWidth);
|
|
128
|
+
|
|
129
|
+
this.syncChromeLayoutVars(panel, bar, panelPosition, barPosition);
|
|
130
|
+
|
|
111
131
|
if (!this.gradient) {
|
|
112
|
-
this.
|
|
132
|
+
this.clearGradientPaintVars(targets);
|
|
113
133
|
return;
|
|
114
134
|
}
|
|
115
135
|
|
|
116
136
|
const image = this.gradientSrc.trim()
|
|
117
137
|
? `url(${this.gradientSrc.trim()})`
|
|
118
|
-
:
|
|
119
|
-
|
|
120
|
-
const shellRect = this.el.getBoundingClientRect();
|
|
121
|
-
const panelWrap = this.el.querySelector('.app-shell__panel') as HTMLElement | null;
|
|
122
|
-
const panelWidth = panelWrap?.getBoundingClientRect().width ?? 0;
|
|
138
|
+
: buildShellRadialGradient();
|
|
123
139
|
|
|
124
140
|
const size = shellGradientSize({
|
|
125
141
|
width: shellRect.width,
|
|
126
142
|
height: shellRect.height,
|
|
127
143
|
panelWidth,
|
|
128
144
|
});
|
|
129
|
-
const panelPosition = shellGradientPositionPanel();
|
|
130
|
-
const barPosition = shellGradientPositionBar(panelWidth);
|
|
131
145
|
const opacity = SHELL_GRADIENT_OPACITY;
|
|
132
146
|
|
|
133
147
|
for (const target of targets) {
|
|
@@ -157,25 +171,27 @@ export class AppShell {
|
|
|
157
171
|
const shellCls: Record<string, boolean> = {
|
|
158
172
|
'app-shell': true,
|
|
159
173
|
'app-shell--gradient': this.gradient,
|
|
174
|
+
[`app-shell--${this.navStyle}`]: true,
|
|
160
175
|
};
|
|
161
176
|
|
|
162
177
|
return (
|
|
163
178
|
<Host class={shellCls}>
|
|
164
179
|
<div class="app-shell__row">
|
|
180
|
+
{this.gradient ? <div class="app-shell__chrome" aria-hidden="true" /> : null}
|
|
165
181
|
<div class="app-shell__panel">
|
|
166
182
|
<slot name="panel" />
|
|
167
183
|
</div>
|
|
168
184
|
<div class="app-shell__main">
|
|
169
|
-
<div class="app-
|
|
170
|
-
<
|
|
171
|
-
|
|
172
|
-
|
|
185
|
+
<div class="app-shell__stack">
|
|
186
|
+
<div class="app-shell__bar">
|
|
187
|
+
<slot name="bar" />
|
|
188
|
+
</div>
|
|
173
189
|
<div class="app-shell__content">
|
|
174
190
|
<slot />
|
|
175
191
|
</div>
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
192
|
+
</div>
|
|
193
|
+
<div class="app-shell__tools">
|
|
194
|
+
<slot name="tools" />
|
|
179
195
|
</div>
|
|
180
196
|
</div>
|
|
181
197
|
</div>
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { Component, Prop, Element, State, Watch, h, Host } from '@stencil/core';
|
|
2
2
|
import {
|
|
3
3
|
BADGE_GRADIENT_POSITION_VAR,
|
|
4
|
-
badgeGradientPosition,
|
|
5
|
-
findGradientSurface,
|
|
6
4
|
isShellGradientActive,
|
|
7
|
-
readShellGradientPosition,
|
|
8
5
|
} from '../../nav/badge-gradient-ring';
|
|
9
6
|
|
|
10
7
|
export type BadgeVariant = 'counter' | 'dot';
|
|
@@ -137,16 +134,10 @@ export class Badge {
|
|
|
137
134
|
void this.gradientLayoutVersion;
|
|
138
135
|
|
|
139
136
|
const style: Record<string, string> = { '--_badge-ring': ring };
|
|
140
|
-
if (!this.gradientBackground) return style;
|
|
137
|
+
if (!this.gradientBackground || !isShellGradientActive(this.el)) return style;
|
|
141
138
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
style[BADGE_GRADIENT_POSITION_VAR] = badgeGradientPosition(
|
|
146
|
-
this.el,
|
|
147
|
-
surface,
|
|
148
|
-
readShellGradientPosition(surface),
|
|
149
|
-
);
|
|
139
|
+
/* Shell chrome wash uses background-attachment: fixed at viewport origin. */
|
|
140
|
+
style[BADGE_GRADIENT_POSITION_VAR] = '0 0';
|
|
150
141
|
return style;
|
|
151
142
|
}
|
|
152
143
|
|
|
@@ -9,10 +9,8 @@ import {
|
|
|
9
9
|
h,
|
|
10
10
|
Host,
|
|
11
11
|
} from '@stencil/core';
|
|
12
|
-
import type { MenuItemData } from '../Menu/menu-types';
|
|
13
|
-
import type { BarNavActionBackground } from '../BarNavAction/BarNavAction';
|
|
14
12
|
import type { NavChromeStyle } from '../../nav/nav-chrome';
|
|
15
|
-
import {
|
|
13
|
+
import type { MenuItemData } from '../Menu/menu-types';
|
|
16
14
|
import type { BarNavActionItem, BarNavTab } from './bar-nav-types';
|
|
17
15
|
import {
|
|
18
16
|
deriveBarNavValueFromUrl,
|
|
@@ -37,6 +35,9 @@ import {
|
|
|
37
35
|
scoped: true,
|
|
38
36
|
})
|
|
39
37
|
export class BarNav {
|
|
38
|
+
/** Style slot: `dashboard` or `settings`. Colors match for now. */
|
|
39
|
+
@Prop({ attribute: 'nav-style', reflect: true }) navStyle: NavChromeStyle = 'dashboard';
|
|
40
|
+
|
|
40
41
|
@Element() el!: HTMLElement;
|
|
41
42
|
|
|
42
43
|
/**
|
|
@@ -66,10 +67,6 @@ export class BarNav {
|
|
|
66
67
|
*/
|
|
67
68
|
@Prop() heading: string | undefined;
|
|
68
69
|
|
|
69
|
-
/** Chrome style: `navigation` = navigation tokens, `default` = app tokens.
|
|
70
|
-
* Property: `navStyle`. HTML attribute: `nav-style`. */
|
|
71
|
-
@Prop({ attribute: 'nav-style', reflect: true }) navStyle: NavChromeStyle = 'default';
|
|
72
|
-
|
|
73
70
|
/** Section base path (e.g. `/dashboard/safety`). Used with `currentUrl` to derive `value`. */
|
|
74
71
|
@Prop() basePath: string = '';
|
|
75
72
|
|
|
@@ -494,16 +491,11 @@ export class BarNav {
|
|
|
494
491
|
}
|
|
495
492
|
}
|
|
496
493
|
|
|
497
|
-
private get tabSurface(): BarNavActionBackground | undefined {
|
|
498
|
-
return this.navStyle === 'navigation' ? 'navigation' : undefined;
|
|
499
|
-
}
|
|
500
|
-
|
|
501
494
|
render() {
|
|
502
495
|
const sectionReady =
|
|
503
496
|
this.basePath !== '' && this.committedSection === this.basePath;
|
|
504
497
|
const hasTabs =
|
|
505
498
|
sectionReady && this.resolvedTabs.length > 0 && !this.hideTabsForDetailRoute;
|
|
506
|
-
const tabSurface = this.tabSurface;
|
|
507
499
|
const tabGroupKey = this.basePath || 'no-section';
|
|
508
500
|
|
|
509
501
|
return (
|
|
@@ -511,11 +503,10 @@ export class BarNav {
|
|
|
511
503
|
<header
|
|
512
504
|
class={{
|
|
513
505
|
'bar-nav': true,
|
|
514
|
-
'bar-nav--
|
|
515
|
-
'bar-nav--
|
|
506
|
+
'bar-nav--dashboard': this.navStyle === 'dashboard',
|
|
507
|
+
'bar-nav--settings': this.navStyle === 'settings',
|
|
516
508
|
'bar-nav--tabs-collapsed': hasTabs && this.tabsCollapsed,
|
|
517
509
|
}}
|
|
518
|
-
style={{ viewTransitionName: SHELL_BAR_NAV_VT_NAME }}
|
|
519
510
|
ref={el => {
|
|
520
511
|
this.headerEl = el as HTMLElement;
|
|
521
512
|
if (el && !this.resizeObserver) {
|
|
@@ -536,7 +527,6 @@ export class BarNav {
|
|
|
536
527
|
}}
|
|
537
528
|
tabs={this.resolvedTabs}
|
|
538
529
|
value={this.effectiveValue}
|
|
539
|
-
background={tabSurface}
|
|
540
530
|
/>
|
|
541
531
|
</div>
|
|
542
532
|
)}
|
|
@@ -551,7 +541,6 @@ export class BarNav {
|
|
|
551
541
|
}}
|
|
552
542
|
tabs={this.resolvedTabs}
|
|
553
543
|
value={this.effectiveValue}
|
|
554
|
-
background={tabSurface}
|
|
555
544
|
onDsChange={(e: Event) => this.handleTabChange(e)}
|
|
556
545
|
/>
|
|
557
546
|
</div>
|
|
@@ -634,7 +623,6 @@ export class BarNav {
|
|
|
634
623
|
dot={action.dot ?? false}
|
|
635
624
|
inactive={action.inactive}
|
|
636
625
|
aria-label={action.ariaLabel ?? action.id}
|
|
637
|
-
background={tabSurface}
|
|
638
626
|
onDsChange={(e: Event) => this.handleActionChange(action.id, e)}
|
|
639
627
|
/>
|
|
640
628
|
))}
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
import { Component, Prop, Event, EventEmitter, Watch, State, Element, h, Host } from '@stencil/core';
|
|
2
2
|
import type { NavChromeStyle } from '../../nav/nav-chrome';
|
|
3
|
-
import {
|
|
4
|
-
animateShellNavRadialReveal,
|
|
5
|
-
ensureShellNavVtStyle,
|
|
6
|
-
resolveShellNavRevealOrigin,
|
|
7
|
-
setShellNavRevealOriginVars,
|
|
8
|
-
} from '../../nav/shell-view-transition';
|
|
9
3
|
import {
|
|
10
4
|
deriveActiveIdFromUrl,
|
|
11
5
|
parsePanelNavGroups,
|
|
@@ -22,18 +16,6 @@ import {
|
|
|
22
16
|
type PanelNavUserActionDetail,
|
|
23
17
|
} from './panel-nav-types';
|
|
24
18
|
|
|
25
|
-
// Module-level WeakMaps
|
|
26
|
-
interface ViewTransition {
|
|
27
|
-
finished: Promise<void>;
|
|
28
|
-
skipTransition: () => void;
|
|
29
|
-
}
|
|
30
|
-
type DocumentWithViewTransition = Document & {
|
|
31
|
-
startViewTransition?: (callback: () => void | Promise<void>) => ViewTransition;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const vtTransitions = new WeakMap<object, ViewTransition>();
|
|
35
|
-
const vtResolvers = new WeakMap<object, () => void>();
|
|
36
|
-
|
|
37
19
|
@Component({
|
|
38
20
|
tag: 'ds-panel-nav',
|
|
39
21
|
styleUrl: 'PanelNav.css',
|
|
@@ -41,14 +23,11 @@ const vtResolvers = new WeakMap<object, () => void>();
|
|
|
41
23
|
scoped: true,
|
|
42
24
|
})
|
|
43
25
|
export class PanelNav {
|
|
44
|
-
/**
|
|
45
|
-
* Property: `navStyle`.
|
|
46
|
-
@Prop({ attribute: 'nav-style', reflect: true }) navStyle: NavChromeStyle = '
|
|
47
|
-
|
|
48
|
-
/** When `true`,
|
|
49
|
-
* change — it just updates the rendered surface synchronously. Use this when
|
|
50
|
-
* the host app orchestrates the page transition itself (e.g. Angular Router's
|
|
51
|
-
* `withViewTransitions`), so the two don't fight or nest. */
|
|
26
|
+
/** Style slot: `dashboard` or `settings`. Colors match for now;
|
|
27
|
+
* class hooks reserved for texture/glyph layers. Property: `navStyle`. Attribute: `nav-style`. */
|
|
28
|
+
@Prop({ attribute: 'nav-style', reflect: true }) navStyle: NavChromeStyle = 'dashboard';
|
|
29
|
+
|
|
30
|
+
/** When `true`, style changes apply synchronously — host app owns view transitions. */
|
|
52
31
|
@Prop() disableViewTransition: boolean = false;
|
|
53
32
|
|
|
54
33
|
/** Nav groups — set via JS property (`el.groups = [...]`) or JSON string attribute. */
|
|
@@ -98,10 +77,7 @@ export class PanelNav {
|
|
|
98
77
|
|
|
99
78
|
@Element() el!: HTMLElement;
|
|
100
79
|
|
|
101
|
-
|
|
102
|
-
* View Transition captures a clean before/after snapshot. */
|
|
103
|
-
@State() private renderedStyle: NavChromeStyle = 'navigation';
|
|
104
|
-
|
|
80
|
+
@State() private renderedStyle: NavChromeStyle = 'dashboard';
|
|
105
81
|
@State() private parsedGroups: PanelNavGroup[] = [];
|
|
106
82
|
@State() private atBottom = false;
|
|
107
83
|
@State() private isAnimating = false;
|
|
@@ -131,7 +107,6 @@ export class PanelNav {
|
|
|
131
107
|
return this.urlDerivedActiveId || this.activeId;
|
|
132
108
|
}
|
|
133
109
|
|
|
134
|
-
/** Host may set `disable-view-transition` as an attribute before the JS prop lands. */
|
|
135
110
|
private get effectiveDisableViewTransition(): boolean {
|
|
136
111
|
return resolvePanelNavDisableVt(
|
|
137
112
|
this.disableViewTransition,
|
|
@@ -170,46 +145,8 @@ export class PanelNav {
|
|
|
170
145
|
}
|
|
171
146
|
|
|
172
147
|
@Watch('navStyle')
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
// just reflect the new surface so the app's transition captures it.
|
|
176
|
-
if (this.effectiveDisableViewTransition) {
|
|
177
|
-
this.renderedStyle = newVal;
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// Skip any in-progress transition immediately so rapid style changes never leave the nav stuck.
|
|
182
|
-
vtTransitions.get(this)?.skipTransition();
|
|
183
|
-
vtTransitions.delete(this);
|
|
184
|
-
|
|
185
|
-
const doc = document as DocumentWithViewTransition;
|
|
186
|
-
if (typeof doc.startViewTransition !== 'function') {
|
|
187
|
-
this.renderedStyle = newVal;
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
ensureShellNavVtStyle();
|
|
192
|
-
const origin = resolveShellNavRevealOrigin(
|
|
193
|
-
this.el.querySelector('.panel-nav__footer-btn') as HTMLElement | null,
|
|
194
|
-
);
|
|
195
|
-
setShellNavRevealOriginVars(origin);
|
|
196
|
-
|
|
197
|
-
const transition = doc.startViewTransition(() =>
|
|
198
|
-
new Promise<void>(resolve => {
|
|
199
|
-
vtResolvers.set(this, resolve);
|
|
200
|
-
this.renderedStyle = newVal;
|
|
201
|
-
})
|
|
202
|
-
);
|
|
203
|
-
|
|
204
|
-
vtTransitions.set(this, transition);
|
|
205
|
-
transition.finished.finally(() => {
|
|
206
|
-
if (vtTransitions.get(this) === transition) vtTransitions.delete(this);
|
|
207
|
-
vtResolvers.delete(this);
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
transition.ready
|
|
211
|
-
.then(() => animateShellNavRadialReveal(origin))
|
|
212
|
-
.catch(() => { /* transition was skipped or aborted */ });
|
|
148
|
+
onNavStyleChange(newVal: NavChromeStyle) {
|
|
149
|
+
this.renderedStyle = newVal;
|
|
213
150
|
}
|
|
214
151
|
|
|
215
152
|
componentWillLoad() {
|
|
@@ -231,16 +168,6 @@ export class PanelNav {
|
|
|
231
168
|
if (this.breakpoint > 0) this.connectResizeObserver();
|
|
232
169
|
}
|
|
233
170
|
|
|
234
|
-
componentDidRender() {
|
|
235
|
-
// If a view transition callback is waiting for the render to complete,
|
|
236
|
-
// resolve it now so the "after" snapshot is taken at exactly the right moment.
|
|
237
|
-
const resolve = vtResolvers.get(this);
|
|
238
|
-
if (resolve) {
|
|
239
|
-
vtResolvers.delete(this);
|
|
240
|
-
resolve();
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
171
|
disconnectedCallback() {
|
|
245
172
|
this.disconnectResizeObserver();
|
|
246
173
|
this.clearEdgeOverlayTimer();
|
|
@@ -292,7 +219,9 @@ export class PanelNav {
|
|
|
292
219
|
|
|
293
220
|
/** Re-parse props assigned by the host after componentWillLoad (Angular ngAfterViewInit). */
|
|
294
221
|
private syncHostPropsIfNeeded() {
|
|
295
|
-
this.
|
|
222
|
+
if (shouldResyncPanelNavStyle(this.renderedStyle, this.navStyle)) {
|
|
223
|
+
this.renderedStyle = this.navStyle;
|
|
224
|
+
}
|
|
296
225
|
|
|
297
226
|
if (shouldResyncPanelNavGroups(this.parsedGroups, this.groups)) {
|
|
298
227
|
this.onGroupsChange(this.groups);
|
|
@@ -301,19 +230,6 @@ export class PanelNav {
|
|
|
301
230
|
}
|
|
302
231
|
}
|
|
303
232
|
|
|
304
|
-
/** Align `renderedStyle` with `style` when host bindings land after first paint. */
|
|
305
|
-
private syncRenderedStyleIfNeeded() {
|
|
306
|
-
if (!shouldResyncPanelNavStyle(this.renderedStyle, this.navStyle)) return;
|
|
307
|
-
|
|
308
|
-
if (this.effectiveDisableViewTransition) {
|
|
309
|
-
vtTransitions.get(this)?.skipTransition();
|
|
310
|
-
vtTransitions.delete(this);
|
|
311
|
-
this.renderedStyle = this.navStyle;
|
|
312
|
-
} else {
|
|
313
|
-
void this.onNavStyleChange(this.navStyle);
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
233
|
/** Poll across animation frames — host props may land without triggering @Watch. */
|
|
318
234
|
private scheduleDeferredHostPropSync() {
|
|
319
235
|
let remaining = PanelNav.HOST_PROP_SYNC_BUDGET;
|
|
@@ -507,14 +423,16 @@ export class PanelNav {
|
|
|
507
423
|
}
|
|
508
424
|
|
|
509
425
|
render() {
|
|
510
|
-
const
|
|
426
|
+
const chromeStyle = this.renderedStyle;
|
|
427
|
+
const isDashboardChrome = chromeStyle === 'dashboard';
|
|
428
|
+
const isDashboard = this.navStyle === 'dashboard';
|
|
511
429
|
const collapsed = this.collapsed || this.viewportNarrow;
|
|
512
430
|
const { userName, userInitial } = this;
|
|
513
431
|
|
|
514
432
|
const navCls: Record<string, boolean> = {
|
|
515
433
|
'panel-nav': true,
|
|
516
|
-
'panel-nav--
|
|
517
|
-
'panel-nav--
|
|
434
|
+
'panel-nav--dashboard': isDashboard,
|
|
435
|
+
'panel-nav--settings': !isDashboard,
|
|
518
436
|
'panel-nav--collapsed': collapsed,
|
|
519
437
|
'panel-nav--animating': this.isAnimating,
|
|
520
438
|
'panel-nav--at-bottom': this.atBottom,
|
|
@@ -522,7 +440,10 @@ export class PanelNav {
|
|
|
522
440
|
|
|
523
441
|
return (
|
|
524
442
|
<Host style={{ display: 'block', position: 'relative' }}>
|
|
525
|
-
<nav
|
|
443
|
+
<nav
|
|
444
|
+
class={navCls}
|
|
445
|
+
aria-label={isDashboardChrome ? 'Dashboard navigation' : 'Settings navigation'}
|
|
446
|
+
>
|
|
526
447
|
|
|
527
448
|
{/* ── Header: Motive logo, reveals collapse toggle on hover ── */}
|
|
528
449
|
<div class="panel-nav__header">
|
|
@@ -581,15 +502,14 @@ export class PanelNav {
|
|
|
581
502
|
|
|
582
503
|
{/* ── Footer ── */}
|
|
583
504
|
<div class="panel-nav__footer">
|
|
584
|
-
{/* Left icon button — Gear in navigation style, Dashboard in default style */}
|
|
585
505
|
<button
|
|
586
506
|
type="button"
|
|
587
507
|
class="panel-nav__footer-btn"
|
|
588
|
-
title={
|
|
589
|
-
aria-label={
|
|
508
|
+
title={isDashboardChrome ? 'Settings' : 'Dashboard'}
|
|
509
|
+
aria-label={isDashboardChrome ? 'Open settings' : 'Go to dashboard'}
|
|
590
510
|
onClick={() => this.handleFooterAction()}
|
|
591
511
|
>
|
|
592
|
-
<ds-icon name={
|
|
512
|
+
<ds-icon name={isDashboardChrome ? 'Gear' : 'Dashboard'} size="md" color="inherit" />
|
|
593
513
|
</button>
|
|
594
514
|
|
|
595
515
|
{/* Right user — label fades like nav items; right icon cross-fades chevron ↔ circle+initial */}
|
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
setNavStyleHint,
|
|
8
8
|
shouldResyncNavChromeStyle,
|
|
9
9
|
} from '../../nav/nav-chrome';
|
|
10
|
-
import { ensureShellNavVtStyle } from '../../nav/shell-view-transition';
|
|
11
10
|
|
|
12
11
|
export type { NavChromeStyle } from '../../nav/nav-chrome';
|
|
13
12
|
export {
|
|
@@ -19,18 +18,6 @@ export {
|
|
|
19
18
|
shouldResyncNavChromeStyle as shouldResyncPanelNavStyle,
|
|
20
19
|
};
|
|
21
20
|
|
|
22
|
-
/** @deprecated Use `setNavStyleHint` */
|
|
23
|
-
export const setPanelNavStyleHint = setNavStyleHint;
|
|
24
|
-
|
|
25
|
-
/** @deprecated Use `clearNavStyleHint` */
|
|
26
|
-
export const clearPanelNavStyleHint = clearNavStyleHint;
|
|
27
|
-
|
|
28
|
-
/** @deprecated Use `NAV_STYLE_HINT_ATTR` */
|
|
29
|
-
export const PANEL_NAV_STYLE_HINT_ATTR = NAV_STYLE_HINT_ATTR;
|
|
30
|
-
|
|
31
|
-
/** @deprecated Use `ensureShellNavVtStyle` */
|
|
32
|
-
export const ensurePanelNavVtStyle = ensureShellNavVtStyle;
|
|
33
|
-
|
|
34
21
|
/** Whether `path` matches `href` at a segment boundary (exact or child path). */
|
|
35
22
|
export function hrefMatchesPath(path: string, href: string): boolean {
|
|
36
23
|
return path === href || path.startsWith(`${href}/`);
|