@ds-mo/ui 1.11.4 → 2.0.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.
@@ -12,7 +12,7 @@ import {
12
12
  import type { NavChromeStyle } from '../../nav/nav-chrome';
13
13
  import type { MenuItemData } from '../Menu/menu-types';
14
14
  import { isTabDivider } from '../TabGroup/tab-item-utils';
15
- import type { BarNavActionItem, BarNavTab } from './bar-nav-types';
15
+ import type { BarNavTab } from './bar-nav-types';
16
16
  import {
17
17
  deriveBarNavValueFromUrl,
18
18
  parseJsonArrayProp,
@@ -61,15 +61,6 @@ export class BarNav {
61
61
  /** ID of the currently active tab. Overridden when `currentUrl` + `basePath` are set. */
62
62
  @Prop({ mutable: true }) value: string = '';
63
63
 
64
- /**
65
- * Action items rendered in the right section.
66
- * Set via JS property: `el.actions = [...]`. Replace the array reference to update.
67
- */
68
- @Prop() actions: BarNavActionItem[] = [];
69
-
70
- /** JSON fallback for `actions` — useful when framework bindings don't propagate arrays. */
71
- @Prop({ attribute: 'actions-json' }) actionsJson: string = '';
72
-
73
64
  /**
74
65
  * Fallback heading shown when no tabs are provided.
75
66
  * When tabs are present the heading is hidden.
@@ -85,11 +76,7 @@ export class BarNav {
85
76
  /** Emitted when the active tab changes. Detail = tab id. */
86
77
  @Event() dsTabChange!: EventEmitter<string>;
87
78
 
88
- /** Emitted when an action button is toggled. Detail = { id, selected }. */
89
- @Event() dsActionChange!: EventEmitter<{ id: string; selected: boolean }>;
90
-
91
79
  @State() private resolvedTabs: BarNavTab[] = [];
92
- @State() private resolvedActions: BarNavActionItem[] = [];
93
80
  @State() private urlDerivedValue: string = '';
94
81
  @State() private hideTabsForDetailRoute = false;
95
82
  @State() private tabsCollapsed = false;
@@ -154,8 +141,6 @@ export class BarNav {
154
141
 
155
142
  @Watch('tabs')
156
143
  @Watch('tabsJson')
157
- @Watch('actions')
158
- @Watch('actionsJson')
159
144
  @Watch('currentUrl')
160
145
  @Watch('basePath')
161
146
  onHostPropsChange() {
@@ -284,16 +269,7 @@ export class BarNav {
284
269
 
285
270
  /** Re-resolve props assigned by the host after componentWillLoad (Angular ngAfterViewInit). */
286
271
  private syncHostPropsIfNeeded() {
287
- if (
288
- shouldResyncBarNavProps(
289
- this.resolvedTabs,
290
- this.tabs,
291
- this.tabsJson,
292
- this.resolvedActions,
293
- this.actions,
294
- this.actionsJson,
295
- )
296
- ) {
272
+ if (shouldResyncBarNavProps(this.resolvedTabs, this.tabs, this.tabsJson)) {
297
273
  this.applyHostProps();
298
274
  } else if (this.currentUrl && this.basePath) {
299
275
  this.syncValueFromUrl();
@@ -361,27 +337,15 @@ export class BarNav {
361
337
  }
362
338
  }
363
339
 
364
- /** Width left for tabs after actions. */
340
+ /** Width available for the tab row or collapsed trigger. */
365
341
  private getLeftZoneAvailableWidth(): number {
366
342
  if (!this.headerEl) return 0;
367
343
 
368
344
  const headerStyle = getComputedStyle(this.headerEl);
369
- const gap = parseFloat(headerStyle.columnGap || headerStyle.gap || '0') || 0;
370
- const actionsEl = this.headerEl.querySelector('.bar-nav__actions') as HTMLElement | null;
371
- const actionsWidth = actionsEl?.offsetWidth ?? 0;
372
345
  const horizontalPadding =
373
346
  (parseFloat(headerStyle.paddingLeft) || 0) + (parseFloat(headerStyle.paddingRight) || 0);
374
- const spacing = this.tabsCollapsed
375
- ? parseFloat(
376
- getComputedStyle(this.headerEl).getPropertyValue('--dimension-space-100').trim(),
377
- ) || 8
378
- : actionsEl
379
- ? gap
380
- : 0;
381
- const available =
382
- this.headerEl.clientWidth - horizontalPadding - actionsWidth - spacing;
383
347
 
384
- return Math.max(0, available);
348
+ return Math.max(0, this.headerEl.clientWidth - horizontalPadding);
385
349
  }
386
350
 
387
351
  private getTabsIntrinsicWidth(): number {
@@ -474,12 +438,6 @@ export class BarNav {
474
438
  : (this.tabs ?? []);
475
439
  }
476
440
 
477
- private incomingActions(): BarNavActionItem[] {
478
- return this.actionsJson
479
- ? parseJsonArrayProp(this.actionsJson, [])
480
- : (this.actions ?? []);
481
- }
482
-
483
441
  private applyHostProps() {
484
442
  const nextBasePath = this.basePath;
485
443
  const sectionChanged =
@@ -492,7 +450,6 @@ export class BarNav {
492
450
  this.committedSection = '';
493
451
  this.pendingSection = nextBasePath;
494
452
  this.resolvedTabs = [];
495
- this.resolvedActions = this.incomingActions();
496
453
  this.resetTabOverflowLayout();
497
454
  return;
498
455
  }
@@ -516,7 +473,6 @@ export class BarNav {
516
473
  this.digestTabsConfig(tabs) !== this.digestTabsConfig(this.resolvedTabs);
517
474
 
518
475
  this.resolvedTabs = tabs;
519
- this.resolvedActions = this.incomingActions();
520
476
  this.syncValueFromUrl();
521
477
  this.committedSection = nextBasePath;
522
478
  if (tabsConfigChanged) {
@@ -572,11 +528,6 @@ export class BarNav {
572
528
  this.selectTab((e as CustomEvent<string>).detail);
573
529
  }
574
530
 
575
- private handleActionChange(actionId: string, e: Event) {
576
- const selected = (e as CustomEvent<boolean>).detail;
577
- this.dsActionChange.emit({ id: actionId, selected });
578
- }
579
-
580
531
  private toggleTabMenu() {
581
532
  if (this.menuOpen) {
582
533
  this.menuOpen = false;
@@ -736,29 +687,6 @@ export class BarNav {
736
687
  </button>
737
688
  )}
738
689
 
739
- {hasTabs &&
740
- this.tabLayoutCommitted &&
741
- this.tabsCollapsed &&
742
- this.resolvedActions.length > 0 && (
743
- <div class="bar-nav__between" aria-hidden="true" />
744
- )}
745
-
746
- {this.resolvedActions.length > 0 && (
747
- <div class="bar-nav__actions">
748
- {this.resolvedActions.map(action => (
749
- <ds-bar-nav-action
750
- key={action.id}
751
- icon={action.icon}
752
- selected={action.selected ?? false}
753
- dot={action.dot ?? false}
754
- inactive={action.inactive}
755
- aria-label={action.ariaLabel ?? action.id}
756
- onDsChange={(e: Event) => this.handleActionChange(action.id, e)}
757
- />
758
- ))}
759
- </div>
760
- )}
761
-
762
690
  </header>
763
691
 
764
692
  {hasTabs && this.tabLayoutCommitted && this.tabsCollapsed && (
@@ -1,5 +1,5 @@
1
1
  import { getSelectableTabs } from '../TabGroup/tab-item-utils';
2
- import type { BarNavActionItem, BarNavTab } from './bar-nav-types';
2
+ import type { BarNavTab } from './bar-nav-types';
3
3
 
4
4
  export interface BarNavUrlState {
5
5
  /** Tab id derived from the URL, or empty when none applies. */
@@ -44,24 +44,15 @@ export function shouldResyncBarNavProps(
44
44
  resolvedTabs: BarNavTab[],
45
45
  tabs: BarNavTab[],
46
46
  tabsJson: string,
47
- resolvedActions: BarNavActionItem[],
48
- actions: BarNavActionItem[],
49
- actionsJson: string,
50
47
  ): boolean {
51
48
  const tabsIncoming = tabsJson
52
49
  ? parseJsonArrayProp(tabsJson, [])
53
50
  : (tabs ?? []);
54
- const actionsIncoming = actionsJson
55
- ? parseJsonArrayProp(actionsJson, [])
56
- : (actions ?? []);
57
51
 
58
- return (
59
- (resolvedTabs.length === 0 && tabsIncoming.length > 0) ||
60
- (resolvedActions.length === 0 && actionsIncoming.length > 0)
61
- );
52
+ return resolvedTabs.length === 0 && tabsIncoming.length > 0;
62
53
  }
63
54
 
64
- /** Parse tabs/actions from either a JSON attribute string or a JS property array. */
55
+ /** Parse tabs from either a JSON attribute string or a JS property array. */
65
56
  export function parseJsonArrayProp<T>(value: string | T[] | undefined, fallback: T[]): T[] {
66
57
  if (Array.isArray(value)) return value;
67
58
  if (typeof value === 'string' && value !== '') {
@@ -9,7 +9,7 @@ import { AccordionItemData } from "./components/Accordion/Accordion";
9
9
  import { NavChromeStyle } from "./nav/nav-chrome";
10
10
  import { BadgeSurface, BadgeVariant } from "./components/Badge/Badge";
11
11
  import { BannerContrast, BannerIntent } from "./components/Banner/Banner";
12
- import { BarNavActionItem, BarNavTab } from "./components/BarNav/bar-nav-types";
12
+ import { BarNavTab } from "./components/BarNav/bar-nav-types";
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";
@@ -47,7 +47,7 @@ export { AccordionItemData } from "./components/Accordion/Accordion";
47
47
  export { NavChromeStyle } from "./nav/nav-chrome";
48
48
  export { BadgeSurface, BadgeVariant } from "./components/Badge/Badge";
49
49
  export { BannerContrast, BannerIntent } from "./components/Banner/Banner";
50
- export { BarNavActionItem, BarNavTab } from "./components/BarNav/bar-nav-types";
50
+ export { BarNavTab } from "./components/BarNav/bar-nav-types";
51
51
  export { BarNavActionBackground } from "./components/BarNavAction/BarNavAction";
52
52
  export { BreadcrumbItem } from "./components/Breadcrumb/Breadcrumb";
53
53
  export { ButtonBackground, ButtonContrast, ButtonElevation, ButtonIntent, ButtonSize, ButtonVariant } from "./components/Button/Button";
@@ -192,16 +192,6 @@ export namespace Components {
192
192
  "showDismiss": boolean;
193
193
  }
194
194
  interface DsBarNav {
195
- /**
196
- * Action items rendered in the right section. Set via JS property: `el.actions = [...]`. Replace the array reference to update.
197
- * @default []
198
- */
199
- "actions": BarNavActionItem[];
200
- /**
201
- * JSON fallback for `actions` — useful when framework bindings don't propagate arrays.
202
- * @default ''
203
- */
204
- "actionsJson": string;
205
195
  /**
206
196
  * Section base path (e.g. `/dashboard/safety`). Used with `currentUrl` to derive `value`.
207
197
  * @default ''
@@ -1240,7 +1230,6 @@ declare global {
1240
1230
  };
1241
1231
  interface HTMLDsBarNavElementEventMap {
1242
1232
  "dsTabChange": string;
1243
- "dsActionChange": { id: string; selected: boolean };
1244
1233
  }
1245
1234
  interface HTMLDsBarNavElement extends Components.DsBarNav, HTMLStencilElement {
1246
1235
  addEventListener<K extends keyof HTMLDsBarNavElementEventMap>(type: K, listener: (this: HTMLDsBarNavElement, ev: DsBarNavCustomEvent<HTMLDsBarNavElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
@@ -1880,16 +1869,6 @@ declare namespace LocalJSX {
1880
1869
  "showDismiss"?: boolean;
1881
1870
  }
1882
1871
  interface DsBarNav {
1883
- /**
1884
- * Action items rendered in the right section. Set via JS property: `el.actions = [...]`. Replace the array reference to update.
1885
- * @default []
1886
- */
1887
- "actions"?: BarNavActionItem[];
1888
- /**
1889
- * JSON fallback for `actions` — useful when framework bindings don't propagate arrays.
1890
- * @default ''
1891
- */
1892
- "actionsJson"?: string;
1893
1872
  /**
1894
1873
  * Section base path (e.g. `/dashboard/safety`). Used with `currentUrl` to derive `value`.
1895
1874
  * @default ''
@@ -1909,10 +1888,6 @@ declare namespace LocalJSX {
1909
1888
  * @default 'dashboard'
1910
1889
  */
1911
1890
  "navStyle"?: NavChromeStyle;
1912
- /**
1913
- * Emitted when an action button is toggled. Detail = { id, selected }.
1914
- */
1915
- "onDsActionChange"?: (event: DsBarNavCustomEvent<{ id: string; selected: boolean }>) => void;
1916
1891
  /**
1917
1892
  * Emitted when the active tab changes. Detail = tab id.
1918
1893
  */
@@ -2907,7 +2882,6 @@ declare namespace LocalJSX {
2907
2882
  "navStyle": NavChromeStyle;
2908
2883
  "tabsJson": string;
2909
2884
  "value": string;
2910
- "actionsJson": string;
2911
2885
  "heading": string | undefined;
2912
2886
  "basePath": string;
2913
2887
  "currentUrl": string;
@@ -1,2 +0,0 @@
1
- import{g as r}from"./p-BQq26pt9.js";function t(t,e,n){if(!t||!e){return{value:"",hideTabs:false}}if(t!==e&&!t.startsWith(`${e}/`)){return{value:"",hideTabs:false}}const s=t.slice(e.length);const a=s.startsWith("/")?s.slice(1).split("/")[0]:"";const u=r(n);if(!a){return{value:u[0]?.id??"",hideTabs:false}}const i=u.find((r=>r.id===a));if(i){return{value:i.id,hideTabs:false}}return{value:"",hideTabs:true}}function e(r,t,e,s,a,u){const i=e?n(e,[]):t??[];const f=u?n(u,[]):a??[];return r.length===0&&i.length>0||s.length===0&&f.length>0}function n(r,t){if(Array.isArray(r))return r;if(typeof r==="string"&&r!==""){try{const e=JSON.parse(r);return Array.isArray(e)?e:t}catch{return t}}return t}export{t as d,n as p,e as s};
2
- //# sourceMappingURL=p-Dl1GvZQ2.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["deriveBarNavValueFromUrl","path","basePath","tabs","value","hideTabs","startsWith","remainder","slice","length","seg","split","selectableTabs","getSelectableTabs","id","tab","find","t","shouldResyncBarNavProps","resolvedTabs","tabsJson","resolvedActions","actions","actionsJson","tabsIncoming","parseJsonArrayProp","actionsIncoming","fallback","Array","isArray","parsed","JSON","parse"],"sources":["src/wc/components/BarNav/bar-nav-utils.ts"],"sourcesContent":["import { getSelectableTabs } from '../TabGroup/tab-item-utils';\nimport type { BarNavActionItem, BarNavTab } from './bar-nav-types';\n\nexport interface BarNavUrlState {\n /** Tab id derived from the URL, or empty when none applies. */\n value: string;\n /** When true, tabs should be hidden (e.g. non-tab child routes like detail pages). */\n hideTabs: boolean;\n}\n\n/** Derive BarNav tab selection from `currentUrl` relative to `basePath`.\n * Mirrors motive-webapp-lab `resolveBarNavState` tab-selection semantics. */\nexport function deriveBarNavValueFromUrl(\n path: string,\n basePath: string,\n tabs: BarNavTab[],\n): BarNavUrlState {\n if (!path || !basePath) {\n return { value: '', hideTabs: false };\n }\n\n if (path !== basePath && !path.startsWith(`${basePath}/`)) {\n return { value: '', hideTabs: false };\n }\n\n const remainder = path.slice(basePath.length);\n const seg = remainder.startsWith('/') ? remainder.slice(1).split('/')[0] : '';\n const selectableTabs = getSelectableTabs(tabs);\n\n if (!seg) {\n return { value: selectableTabs[0]?.id ?? '', hideTabs: false };\n }\n\n const tab = selectableTabs.find(t => t.id === seg);\n if (tab) {\n return { value: tab.id, hideTabs: false };\n }\n\n return { value: '', hideTabs: true };\n}\n\n/** True when host array/json props have data but resolved internal state is still empty. */\nexport function shouldResyncBarNavProps(\n resolvedTabs: BarNavTab[],\n tabs: BarNavTab[],\n tabsJson: string,\n resolvedActions: BarNavActionItem[],\n actions: BarNavActionItem[],\n actionsJson: string,\n): boolean {\n const tabsIncoming = tabsJson\n ? parseJsonArrayProp(tabsJson, [])\n : (tabs ?? []);\n const actionsIncoming = actionsJson\n ? parseJsonArrayProp(actionsJson, [])\n : (actions ?? []);\n\n return (\n (resolvedTabs.length === 0 && tabsIncoming.length > 0) ||\n (resolvedActions.length === 0 && actionsIncoming.length > 0)\n );\n}\n\n/** Parse tabs/actions from either a JSON attribute string or a JS property array. */\nexport function parseJsonArrayProp<T>(value: string | T[] | undefined, fallback: T[]): T[] {\n if (Array.isArray(value)) return value;\n if (typeof value === 'string' && value !== '') {\n try {\n const parsed = JSON.parse(value);\n return Array.isArray(parsed) ? parsed : fallback;\n } catch {\n return fallback;\n }\n }\n return fallback;\n}\n"],"mappings":"6CAYgBA,EACdC,EACAC,EACAC,GAEA,IAAKF,IAASC,EAAU,CACtB,MAAO,CAAEE,MAAO,GAAIC,SAAU,M,CAGhC,GAAIJ,IAASC,IAAaD,EAAKK,WAAW,GAAGJ,MAAc,CACzD,MAAO,CAAEE,MAAO,GAAIC,SAAU,M,CAGhC,MAAME,EAAYN,EAAKO,MAAMN,EAASO,QACtC,MAAMC,EAAMH,EAAUD,WAAW,KAAOC,EAAUC,MAAM,GAAGG,MAAM,KAAK,GAAK,GAC3E,MAAMC,EAAiBC,EAAkBV,GAEzC,IAAKO,EAAK,CACR,MAAO,CAAEN,MAAOQ,EAAe,IAAIE,IAAM,GAAIT,SAAU,M,CAGzD,MAAMU,EAAMH,EAAeI,MAAKC,GAAKA,EAAEH,KAAOJ,IAC9C,GAAIK,EAAK,CACP,MAAO,CAAEX,MAAOW,EAAID,GAAIT,SAAU,M,CAGpC,MAAO,CAAED,MAAO,GAAIC,SAAU,KAChC,CAGM,SAAUa,EACdC,EACAhB,EACAiB,EACAC,EACAC,EACAC,GAEA,MAAMC,EAAeJ,EACjBK,EAAmBL,EAAU,IAC5BjB,GAAQ,GACb,MAAMuB,EAAkBH,EACpBE,EAAmBF,EAAa,IAC/BD,GAAW,GAEhB,OACGH,EAAaV,SAAW,GAAKe,EAAaf,OAAS,GACnDY,EAAgBZ,SAAW,GAAKiB,EAAgBjB,OAAS,CAE9D,CAGM,SAAUgB,EAAsBrB,EAAiCuB,GACrE,GAAIC,MAAMC,QAAQzB,GAAQ,OAAOA,EACjC,UAAWA,IAAU,UAAYA,IAAU,GAAI,CAC7C,IACE,MAAM0B,EAASC,KAAKC,MAAM5B,GAC1B,OAAOwB,MAAMC,QAAQC,GAAUA,EAASH,C,CACxC,MACA,OAAOA,C,EAGX,OAAOA,CACT,Q","ignoreList":[]}