@ds-mo/ui 1.4.0 → 1.5.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.
@@ -5,6 +5,7 @@
5
5
 
6
6
  /* eslint-disable */
7
7
  export { DsAccordion } from "./ds-accordion.js";
8
+ export { DsAppShell } from "./ds-app-shell.js";
8
9
  export { DsBadge } from "./ds-badge.js";
9
10
  export { DsBanner } from "./ds-banner.js";
10
11
  export { DsBarNavAction } from "./ds-bar-nav-action.js";
@@ -0,0 +1,26 @@
1
+ 'use client';
2
+
3
+ /**
4
+ * This file was automatically generated by the Stencil React Output Target.
5
+ * Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.
6
+ */
7
+
8
+ /* eslint-disable */
9
+
10
+ import type { StencilReactComponent } from '@stencil/react-output-target/runtime';
11
+ import { createComponent } from '@stencil/react-output-target/runtime';
12
+ import React from 'react';
13
+
14
+ import type { Components } from "@ds-mo/ui/dist/components";
15
+ import { DsAppShell as DsAppShellElement, defineCustomElement as defineDsAppShell } from "@ds-mo/ui/dist/components/ds-app-shell.js";
16
+
17
+ export type DsAppShellEvents = NonNullable<unknown>;
18
+
19
+ export const DsAppShell: StencilReactComponent<DsAppShellElement, DsAppShellEvents, Components.DsAppShell> = /*@__PURE__*/ createComponent<DsAppShellElement, DsAppShellEvents, Components.DsAppShell>({
20
+ tagName: 'ds-app-shell',
21
+ elementClass: DsAppShellElement,
22
+ // @ts-ignore - ignore potential React type mismatches between the Stencil Output Target and your project.
23
+ react: React,
24
+ events: {} as DsAppShellEvents,
25
+ defineCustomElement: defineDsAppShell
26
+ });
@@ -0,0 +1,180 @@
1
+ import { Component, Prop, Element, Watch, h, Host } from '@stencil/core';
2
+ import type { NavChromeStyle } from '../../nav/nav-chrome';
3
+ import {
4
+ SHELL_GRADIENT_IMAGE_VAR,
5
+ SHELL_GRADIENT_OPACITY,
6
+ SHELL_GRADIENT_OPACITY_VAR,
7
+ SHELL_GRADIENT_POSITION_BAR_VAR,
8
+ SHELL_GRADIENT_POSITION_PANEL_VAR,
9
+ SHELL_GRADIENT_SIZE_VAR,
10
+ shellGradientImageForStyle,
11
+ shellGradientPositionBar,
12
+ shellGradientPositionPanel,
13
+ shellGradientSize,
14
+ } from '../../nav/shell-gradient';
15
+
16
+ @Component({
17
+ tag: 'ds-app-shell',
18
+ styleUrl: 'AppShell.css',
19
+ scoped: true,
20
+ })
21
+ export class AppShell {
22
+ /** Chrome style propagated to slotted `ds-panel-nav` and `ds-bar-nav`. */
23
+ @Prop({ attribute: 'nav-style', reflect: true }) navStyle: NavChromeStyle = 'navigation';
24
+
25
+ /** When `true`, paints the shared L-shaped radial wash on panel + bar backgrounds. */
26
+ @Prop({ reflect: true }) gradient: boolean = false;
27
+
28
+ /**
29
+ * Optional custom gradient for `background-image` (e.g. SVG URL).
30
+ * When set, overrides the built-in radial wash.
31
+ */
32
+ @Prop() gradientSrc: string = '';
33
+
34
+ @Element() el!: HTMLElement;
35
+
36
+ private resizeObserver: ResizeObserver | null = null;
37
+
38
+ componentDidLoad() {
39
+ this.syncSlottedNavStyle();
40
+ this.connectMetricsObserver();
41
+ this.scheduleGradientVars();
42
+ }
43
+
44
+ private scheduleGradientVars() {
45
+ this.updateGradientVars();
46
+ requestAnimationFrame(() => this.updateGradientVars());
47
+ }
48
+
49
+ disconnectedCallback() {
50
+ this.resizeObserver?.disconnect();
51
+ this.resizeObserver = null;
52
+ }
53
+
54
+ @Watch('navStyle')
55
+ @Watch('gradient')
56
+ @Watch('gradientSrc')
57
+ onShellPropsChange() {
58
+ this.syncSlottedNavStyle();
59
+ this.scheduleGradientVars();
60
+ }
61
+
62
+ private connectMetricsObserver() {
63
+ this.resizeObserver = new ResizeObserver(() => this.scheduleGradientVars());
64
+ this.resizeObserver.observe(this.el);
65
+ const panelWrap = this.el.querySelector('.app-shell__panel');
66
+ const barWrap = this.el.querySelector('.app-shell__bar');
67
+ if (panelWrap) this.resizeObserver.observe(panelWrap);
68
+ if (barWrap) this.resizeObserver.observe(barWrap);
69
+ this.scheduleGradientVars();
70
+ }
71
+
72
+ private applyGradientVars(target: HTMLElement, vars: Record<string, string | null>) {
73
+ const style = target.style;
74
+ for (const [name, value] of Object.entries(vars)) {
75
+ if (value === null) style.removeProperty(name);
76
+ else style.setProperty(name, value);
77
+ }
78
+ }
79
+
80
+ private clearGradientVars(targets: HTMLElement[]) {
81
+ const keys = [
82
+ SHELL_GRADIENT_IMAGE_VAR,
83
+ SHELL_GRADIENT_SIZE_VAR,
84
+ SHELL_GRADIENT_POSITION_PANEL_VAR,
85
+ SHELL_GRADIENT_POSITION_BAR_VAR,
86
+ SHELL_GRADIENT_OPACITY_VAR,
87
+ ];
88
+ for (const target of targets) {
89
+ for (const key of keys) target.style.removeProperty(key);
90
+ }
91
+ }
92
+
93
+ private syncSlottedNavStyle() {
94
+ const panel = this.el.querySelector('ds-panel-nav') as (HTMLElement & { navStyle: NavChromeStyle }) | null;
95
+ const bar = this.el.querySelector('ds-bar-nav') as (HTMLElement & { navStyle: NavChromeStyle }) | null;
96
+ if (panel) {
97
+ panel.setAttribute('nav-style', this.navStyle);
98
+ panel.navStyle = this.navStyle;
99
+ }
100
+ if (bar) {
101
+ bar.setAttribute('nav-style', this.navStyle);
102
+ bar.navStyle = this.navStyle;
103
+ }
104
+ }
105
+
106
+ private updateGradientVars() {
107
+ const panel = this.el.querySelector('ds-panel-nav') as HTMLElement | null;
108
+ const bar = this.el.querySelector('ds-bar-nav') as HTMLElement | null;
109
+ const targets = [this.el, panel, bar].filter((el): el is HTMLElement => el !== null);
110
+
111
+ if (!this.gradient) {
112
+ this.clearGradientVars(targets);
113
+ return;
114
+ }
115
+
116
+ const image = this.gradientSrc.trim()
117
+ ? `url(${this.gradientSrc.trim()})`
118
+ : shellGradientImageForStyle(this.navStyle);
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;
123
+
124
+ const size = shellGradientSize({
125
+ width: shellRect.width,
126
+ height: shellRect.height,
127
+ panelWidth,
128
+ });
129
+ const panelPosition = shellGradientPositionPanel();
130
+ const barPosition = shellGradientPositionBar(panelWidth);
131
+ const opacity = SHELL_GRADIENT_OPACITY;
132
+
133
+ for (const target of targets) {
134
+ if (target === this.el) {
135
+ this.applyGradientVars(target, {
136
+ [SHELL_GRADIENT_IMAGE_VAR]: image,
137
+ [SHELL_GRADIENT_SIZE_VAR]: size,
138
+ [SHELL_GRADIENT_POSITION_PANEL_VAR]: panelPosition,
139
+ [SHELL_GRADIENT_POSITION_BAR_VAR]: barPosition,
140
+ [SHELL_GRADIENT_OPACITY_VAR]: opacity,
141
+ });
142
+ continue;
143
+ }
144
+
145
+ const isBar = target.tagName.toLowerCase() === 'ds-bar-nav';
146
+ this.applyGradientVars(target, {
147
+ [SHELL_GRADIENT_IMAGE_VAR]: image,
148
+ [SHELL_GRADIENT_SIZE_VAR]: size,
149
+ [SHELL_GRADIENT_OPACITY_VAR]: opacity,
150
+ [SHELL_GRADIENT_POSITION_PANEL_VAR]: isBar ? null : panelPosition,
151
+ [SHELL_GRADIENT_POSITION_BAR_VAR]: isBar ? barPosition : null,
152
+ });
153
+ }
154
+ }
155
+
156
+ render() {
157
+ const shellCls: Record<string, boolean> = {
158
+ 'app-shell': true,
159
+ 'app-shell--gradient': this.gradient,
160
+ };
161
+
162
+ return (
163
+ <Host class={shellCls}>
164
+ <div class="app-shell__row">
165
+ <div class="app-shell__panel">
166
+ <slot name="panel" />
167
+ </div>
168
+ <div class="app-shell__main">
169
+ <div class="app-shell__bar">
170
+ <slot name="bar" />
171
+ </div>
172
+ <div class="app-shell__content">
173
+ <slot />
174
+ </div>
175
+ </div>
176
+ </div>
177
+ </Host>
178
+ );
179
+ }
180
+ }
@@ -6,10 +6,10 @@
6
6
  */
7
7
  import { HTMLStencilElement, JSXBase } from "@stencil/core/internal";
8
8
  import { AccordionItemData } from "./components/Accordion/Accordion";
9
+ import { NavChromeStyle } from "./nav/nav-chrome";
9
10
  import { BadgeSurface, BadgeVariant } from "./components/Badge/Badge";
10
11
  import { BannerContrast, BannerIntent } from "./components/Banner/Banner";
11
12
  import { BarNavActionItem, BarNavTab } from "./components/BarNav/bar-nav-types";
12
- import { NavChromeStyle } from "./nav/nav-chrome";
13
13
  import { BarNavActionBackground } from "./components/BarNavAction/BarNavAction";
14
14
  import { BreadcrumbItem } from "./components/Breadcrumb/Breadcrumb";
15
15
  import { ButtonBackground, ButtonContrast, ButtonElevation, ButtonIntent, ButtonSize, ButtonVariant } from "./components/Button/Button";
@@ -42,10 +42,10 @@ import { ToggleButtonBackground, ToggleButtonElevation, ToggleButtonSize } from
42
42
  import { ToggleGroupBackground, ToggleGroupElevation, ToggleGroupItem, ToggleGroupSize } from "./components/ToggleButtonGroup/ToggleButtonGroup";
43
43
  import { TooltipAlign, TooltipSide } from "./components/Tooltip/Tooltip";
44
44
  export { AccordionItemData } from "./components/Accordion/Accordion";
45
+ export { NavChromeStyle } from "./nav/nav-chrome";
45
46
  export { BadgeSurface, BadgeVariant } from "./components/Badge/Badge";
46
47
  export { BannerContrast, BannerIntent } from "./components/Banner/Banner";
47
48
  export { BarNavActionItem, BarNavTab } from "./components/BarNav/bar-nav-types";
48
- export { NavChromeStyle } from "./nav/nav-chrome";
49
49
  export { BarNavActionBackground } from "./components/BarNavAction/BarNavAction";
50
50
  export { BreadcrumbItem } from "./components/Breadcrumb/Breadcrumb";
51
51
  export { ButtonBackground, ButtonContrast, ButtonElevation, ButtonIntent, ButtonSize, ButtonVariant } from "./components/Button/Button";
@@ -93,6 +93,23 @@ export namespace Components {
93
93
  */
94
94
  "multiple": boolean;
95
95
  }
96
+ interface DsAppShell {
97
+ /**
98
+ * When `true`, paints the shared L-shaped radial wash on panel + bar backgrounds.
99
+ * @default false
100
+ */
101
+ "gradient": boolean;
102
+ /**
103
+ * Optional custom gradient for `background-image` (e.g. SVG URL). When set, overrides the built-in radial wash.
104
+ * @default ''
105
+ */
106
+ "gradientSrc": string;
107
+ /**
108
+ * Chrome style propagated to slotted `ds-panel-nav` and `ds-bar-nav`.
109
+ * @default 'navigation'
110
+ */
111
+ "navStyle": NavChromeStyle;
112
+ }
96
113
  interface DsBadge {
97
114
  /**
98
115
  * Direct ring background override for component-local surfaces.
@@ -1169,6 +1186,12 @@ declare global {
1169
1186
  prototype: HTMLDsAccordionElement;
1170
1187
  new (): HTMLDsAccordionElement;
1171
1188
  };
1189
+ interface HTMLDsAppShellElement extends Components.DsAppShell, HTMLStencilElement {
1190
+ }
1191
+ var HTMLDsAppShellElement: {
1192
+ prototype: HTMLDsAppShellElement;
1193
+ new (): HTMLDsAppShellElement;
1194
+ };
1172
1195
  interface HTMLDsBadgeElement extends Components.DsBadge, HTMLStencilElement {
1173
1196
  }
1174
1197
  var HTMLDsBadgeElement: {
@@ -1671,6 +1694,7 @@ declare global {
1671
1694
  };
1672
1695
  interface HTMLElementTagNameMap {
1673
1696
  "ds-accordion": HTMLDsAccordionElement;
1697
+ "ds-app-shell": HTMLDsAppShellElement;
1674
1698
  "ds-badge": HTMLDsBadgeElement;
1675
1699
  "ds-banner": HTMLDsBannerElement;
1676
1700
  "ds-bar-nav": HTMLDsBarNavElement;
@@ -1731,6 +1755,23 @@ declare namespace LocalJSX {
1731
1755
  "multiple"?: boolean;
1732
1756
  "onDsExpandedChange"?: (event: DsAccordionCustomEvent<string[]>) => void;
1733
1757
  }
1758
+ interface DsAppShell {
1759
+ /**
1760
+ * When `true`, paints the shared L-shaped radial wash on panel + bar backgrounds.
1761
+ * @default false
1762
+ */
1763
+ "gradient"?: boolean;
1764
+ /**
1765
+ * Optional custom gradient for `background-image` (e.g. SVG URL). When set, overrides the built-in radial wash.
1766
+ * @default ''
1767
+ */
1768
+ "gradientSrc"?: string;
1769
+ /**
1770
+ * Chrome style propagated to slotted `ds-panel-nav` and `ds-bar-nav`.
1771
+ * @default 'navigation'
1772
+ */
1773
+ "navStyle"?: NavChromeStyle;
1774
+ }
1734
1775
  interface DsBadge {
1735
1776
  /**
1736
1777
  * Direct ring background override for component-local surfaces.
@@ -2774,6 +2815,11 @@ declare namespace LocalJSX {
2774
2815
  "multiple": boolean;
2775
2816
  "expandedIds": string;
2776
2817
  }
2818
+ interface DsAppShellAttributes {
2819
+ "navStyle": NavChromeStyle;
2820
+ "gradient": boolean;
2821
+ "gradientSrc": string;
2822
+ }
2777
2823
  interface DsBadgeAttributes {
2778
2824
  "variant": BadgeVariant;
2779
2825
  "count": number;
@@ -3080,6 +3126,7 @@ declare namespace LocalJSX {
3080
3126
 
3081
3127
  interface IntrinsicElements {
3082
3128
  "ds-accordion": Omit<DsAccordion, keyof DsAccordionAttributes> & { [K in keyof DsAccordion & keyof DsAccordionAttributes]?: DsAccordion[K] } & { [K in keyof DsAccordion & keyof DsAccordionAttributes as `attr:${K}`]?: DsAccordionAttributes[K] } & { [K in keyof DsAccordion & keyof DsAccordionAttributes as `prop:${K}`]?: DsAccordion[K] };
3129
+ "ds-app-shell": Omit<DsAppShell, keyof DsAppShellAttributes> & { [K in keyof DsAppShell & keyof DsAppShellAttributes]?: DsAppShell[K] } & { [K in keyof DsAppShell & keyof DsAppShellAttributes as `attr:${K}`]?: DsAppShellAttributes[K] } & { [K in keyof DsAppShell & keyof DsAppShellAttributes as `prop:${K}`]?: DsAppShell[K] };
3083
3130
  "ds-badge": Omit<DsBadge, keyof DsBadgeAttributes> & { [K in keyof DsBadge & keyof DsBadgeAttributes]?: DsBadge[K] } & { [K in keyof DsBadge & keyof DsBadgeAttributes as `attr:${K}`]?: DsBadgeAttributes[K] } & { [K in keyof DsBadge & keyof DsBadgeAttributes as `prop:${K}`]?: DsBadge[K] };
3084
3131
  "ds-banner": Omit<DsBanner, keyof DsBannerAttributes> & { [K in keyof DsBanner & keyof DsBannerAttributes]?: DsBanner[K] } & { [K in keyof DsBanner & keyof DsBannerAttributes as `attr:${K}`]?: DsBannerAttributes[K] } & { [K in keyof DsBanner & keyof DsBannerAttributes as `prop:${K}`]?: DsBanner[K] };
3085
3132
  "ds-bar-nav": Omit<DsBarNav, keyof DsBarNavAttributes> & { [K in keyof DsBarNav & keyof DsBarNavAttributes]?: DsBarNav[K] } & { [K in keyof DsBarNav & keyof DsBarNavAttributes as `attr:${K}`]?: DsBarNavAttributes[K] } & { [K in keyof DsBarNav & keyof DsBarNavAttributes as `prop:${K}`]?: DsBarNav[K] };
@@ -3126,6 +3173,7 @@ declare module "@stencil/core" {
3126
3173
  export namespace JSX {
3127
3174
  interface IntrinsicElements {
3128
3175
  "ds-accordion": LocalJSX.IntrinsicElements["ds-accordion"] & JSXBase.HTMLAttributes<HTMLDsAccordionElement>;
3176
+ "ds-app-shell": LocalJSX.IntrinsicElements["ds-app-shell"] & JSXBase.HTMLAttributes<HTMLDsAppShellElement>;
3129
3177
  "ds-badge": LocalJSX.IntrinsicElements["ds-badge"] & JSXBase.HTMLAttributes<HTMLDsBadgeElement>;
3130
3178
  "ds-banner": LocalJSX.IntrinsicElements["ds-banner"] & JSXBase.HTMLAttributes<HTMLDsBannerElement>;
3131
3179
  "ds-bar-nav": LocalJSX.IntrinsicElements["ds-bar-nav"] & JSXBase.HTMLAttributes<HTMLDsBarNavElement>;
@@ -17,3 +17,17 @@ export {
17
17
  runShellNavStyleRevealOnReady,
18
18
  } from './shell-view-transition';
19
19
  export type { ShellNavRevealOrigin } from './shell-view-transition';
20
+ export {
21
+ SHELL_GRADIENT_IMAGE_VAR,
22
+ SHELL_GRADIENT_SIZE_VAR,
23
+ SHELL_GRADIENT_POSITION_PANEL_VAR,
24
+ SHELL_GRADIENT_POSITION_BAR_VAR,
25
+ SHELL_GRADIENT_OPACITY_VAR,
26
+ SHELL_GRADIENT_OPACITY,
27
+ buildShellRadialGradient,
28
+ shellGradientImageForStyle,
29
+ shellGradientSize,
30
+ shellGradientPositionPanel,
31
+ shellGradientPositionBar,
32
+ } from './shell-gradient';
33
+ export type { ShellGradientLayout } from './shell-gradient';
@@ -0,0 +1,44 @@
1
+ import type { NavChromeStyle } from './nav-chrome';
2
+
3
+ /** CSS var names consumed by `ds-panel-nav` / `ds-bar-nav` inside `ds-app-shell`. */
4
+ export const SHELL_GRADIENT_IMAGE_VAR = '--ds-shell-gradient-image';
5
+ export const SHELL_GRADIENT_SIZE_VAR = '--ds-shell-gradient-size';
6
+ export const SHELL_GRADIENT_POSITION_PANEL_VAR = '--ds-shell-gradient-position-panel';
7
+ export const SHELL_GRADIENT_POSITION_BAR_VAR = '--ds-shell-gradient-position-bar';
8
+ export const SHELL_GRADIENT_OPACITY_VAR = '--ds-shell-gradient-opacity';
9
+
10
+ /** Layer opacity for the nav gradient wash. */
11
+ export const SHELL_GRADIENT_OPACITY = '0.1';
12
+
13
+ const GRADIENT_GEOMETRY = '128.57% 141.42% at 0% 0%';
14
+
15
+ /**
16
+ * Unified shell radial — same wash for all nav chrome styles.
17
+ * Tokens follow `data-theme` (light/dark blue intent).
18
+ */
19
+ export function buildShellRadialGradient(): string {
20
+ return `radial-gradient(${GRADIENT_GEOMETRY}, var(--color-background-transparent) 0%, var(--color-color-intent-blue-medium-background) 50%, var(--color-color-intent-blue-strong-background) 100%)`;
21
+ }
22
+
23
+ /** Built-in radial image (optional `gradientSrc` on shell overrides). */
24
+ export function shellGradientImageForStyle(_style: NavChromeStyle): string {
25
+ return buildShellRadialGradient();
26
+ }
27
+
28
+ export interface ShellGradientLayout {
29
+ width: number;
30
+ height: number;
31
+ panelWidth: number;
32
+ }
33
+
34
+ export function shellGradientSize(layout: ShellGradientLayout): string {
35
+ return `${Math.round(layout.width)}px ${Math.round(layout.height)}px`;
36
+ }
37
+
38
+ export function shellGradientPositionPanel(): string {
39
+ return '0 0';
40
+ }
41
+
42
+ export function shellGradientPositionBar(panelWidth: number): string {
43
+ return `${-Math.round(panelWidth)}px 0`;
44
+ }