@record-evolution/widget-navbar 1.0.12 → 1.0.13

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.
@@ -1,18 +1,18 @@
1
- import { LitElement as u, css as m, nothing as g, html as a } from "lit";
2
- import { property as l, state as d } from "lit/decorators.js";
3
- import { repeat as f } from "lit/directives/repeat.js";
1
+ import { LitElement as m, css as d, nothing as f, html as l } from "lit";
2
+ import { property as a, state as u } from "lit/decorators.js";
3
+ import { repeat as g } from "lit/directives/repeat.js";
4
4
  import "@material/web/icon/icon";
5
5
  import "@material/web/tabs/tabs";
6
6
  import "@material/web/tabs/primary-tab";
7
7
  import "@material/web/tabs/secondary-tab";
8
- var b = Object.defineProperty, n = (c, t, e, i) => {
9
- for (var s = void 0, o = c.length - 1, p; o >= 0; o--)
10
- (p = c[o]) && (s = p(t, e, s) || s);
11
- return s && b(t, e, s), s;
8
+ var b = Object.defineProperty, n = (p, t, e, i) => {
9
+ for (var r = void 0, o = p.length - 1, c; o >= 0; o--)
10
+ (c = p[o]) && (r = c(t, e, r) || r);
11
+ return r && b(t, e, r), r;
12
12
  };
13
- const h = class h extends u {
13
+ const h = class h extends m {
14
14
  constructor() {
15
- super(...arguments), this.version = "1.0.12";
15
+ super(...arguments), this.version = "1.0.13";
16
16
  }
17
17
  update(t) {
18
18
  t.has("theme") && this.registerTheme(this.theme), super.update(t);
@@ -38,8 +38,18 @@ const h = class h extends u {
38
38
  trimRoute(t) {
39
39
  return t ? "/" + t.split("/").filter(Boolean).join("/") : "";
40
40
  }
41
- addSlashes(t) {
42
- return !t.route?.endsWith("/") && t.trailingSlash && (t.route += "/"), !t.route?.startsWith("/") && t.leadingSlash && (t.route = "/" + t.route), t.route;
41
+ resolveRoute(t) {
42
+ let e = String(t?.route ?? "");
43
+ if (t?.variables)
44
+ for (const i of t.variables)
45
+ i.label && (e = e.split(`{{${i.label}}}`).join(encodeURIComponent(String(i.value ?? ""))));
46
+ if (e.includes("*")) {
47
+ const i = (this.route || "").split("/").filter(Boolean), r = e.split("/").filter(Boolean);
48
+ for (let o = 0; o < r.length; o++)
49
+ r[o] === "*" && (r[o] = i[o] ?? "");
50
+ e = (e.startsWith("/") ? "/" : "") + r.filter(Boolean).join("/");
51
+ }
52
+ return e;
43
53
  }
44
54
  matchesRoute(t) {
45
55
  if (t === void 0) return !1;
@@ -47,11 +57,11 @@ const h = class h extends u {
47
57
  return t.startsWith("/") ? e.startsWith(i) : e.endsWith(i) || e === i;
48
58
  }
49
59
  render() {
50
- const t = this.inputData?.style?.fontSize ?? 16, e = (this.inputData?.style?.fontSize ?? 16) * 1.5, i = this.inputData?.style?.color || this.themeTitleColor || "black", s = this.inputData?.style?.backgroundColor || this.themeBgColor || "white";
51
- return a`
60
+ const t = this.inputData?.style?.fontSize ?? 16, e = (this.inputData?.style?.fontSize ?? 16) * 1.5, i = this.inputData?.style?.color || this.themeTitleColor || "black", r = this.inputData?.style?.backgroundColor || this.themeBgColor || "white";
61
+ return l`
52
62
  <div
53
63
  class="wrapper"
54
- style="background-color: ${s}; color: ${i};
64
+ style="background-color: ${r}; color: ${i};
55
65
  font-weight: ${this.inputData?.style?.fontWeight};
56
66
  font-size: ${t}px;"
57
67
  >
@@ -59,30 +69,35 @@ const h = class h extends u {
59
69
  class="paging"
60
70
  style=${this.inputData?.route ? "cursor: pointer" : ""}
61
71
  ?active=${this.inputData?.title}
62
- @click=${() => this.handleNavItemClick(this.addSlashes(this.inputData))}
72
+ @click=${() => this.handleNavItemClick(
73
+ this.resolveRoute({
74
+ route: this.inputData?.route,
75
+ variables: this.inputData?.variables
76
+ })
77
+ )}
63
78
  >
64
79
  ${this.inputData?.title}
65
80
  </h2>
66
81
  <md-tab class="xnav-list">
67
- ${f(
82
+ ${g(
68
83
  this.inputData?.navItems || [],
69
84
  (o) => o.label,
70
- (o) => a`
85
+ (o) => l`
71
86
  <md-secondary-tab
72
- ?active=${this.matchesRoute(this.addSlashes(o))}
87
+ ?active=${this.matchesRoute(this.resolveRoute(o))}
73
88
  style="font-size: ${t}px;
74
- --md-secondary-tab-container-color: ${s};
89
+ --md-secondary-tab-container-color: ${r};
75
90
  color: ${i};"
76
- @click=${() => this.handleNavItemClick(this.addSlashes(o))}
91
+ @click=${() => this.handleNavItemClick(this.resolveRoute(o))}
77
92
  >
78
- ${o.iconName ? a`
93
+ ${o.iconName ? l`
79
94
  <md-icon
80
95
  slot="icon"
81
96
  style="font-size: ${e}px;width: ${e}px;color: ${i}"
82
97
  >
83
98
  ${o.iconName}
84
99
  </md-icon>
85
- ` : g}
100
+ ` : f}
86
101
  ${o.label}
87
102
  </md-secondary-tab>
88
103
  `
@@ -92,7 +107,7 @@ const h = class h extends u {
92
107
  `;
93
108
  }
94
109
  };
95
- h.styles = m`
110
+ h.styles = d`
96
111
  :host {
97
112
  display: block;
98
113
  font-family: sans-serif;
@@ -109,6 +124,7 @@ h.styles = m`
109
124
  align-items: end;
110
125
  height: 100%;
111
126
  width: 100%;
127
+ padding: 0 16px;
112
128
  box-sizing: border-box;
113
129
  }
114
130
 
@@ -129,24 +145,24 @@ h.styles = m`
129
145
  height: 48px;
130
146
  }
131
147
  `;
132
- let r = h;
148
+ let s = h;
133
149
  n([
134
- l({ type: Object })
135
- ], r.prototype, "inputData");
150
+ a({ type: Object })
151
+ ], s.prototype, "inputData");
136
152
  n([
137
- l({ type: Object })
138
- ], r.prototype, "theme");
153
+ a({ type: Object })
154
+ ], s.prototype, "theme");
139
155
  n([
140
- l({ type: String })
141
- ], r.prototype, "route");
156
+ a({ type: String })
157
+ ], s.prototype, "route");
142
158
  n([
143
- d()
144
- ], r.prototype, "themeBgColor");
159
+ u()
160
+ ], s.prototype, "themeBgColor");
145
161
  n([
146
- d()
147
- ], r.prototype, "themeTitleColor");
148
- window.customElements.define("widget-navbar-1.0.12", r);
162
+ u()
163
+ ], s.prototype, "themeTitleColor");
164
+ window.customElements.define("widget-navbar-1.0.13", s);
149
165
  export {
150
- r as WidgetNavbar
166
+ s as WidgetNavbar
151
167
  };
152
168
  //# sourceMappingURL=widget-navbar.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"widget-navbar.js","sources":["../src/widget-navbar.ts"],"sourcesContent":["import { html, css, LitElement, PropertyValues, nothing } from 'lit'\nimport { property, state } from 'lit/decorators.js'\nimport { repeat } from 'lit/directives/repeat.js'\nimport { InputData } from './definition-schema'\n\nimport '@material/web/icon/icon'\nimport '@material/web/tabs/tabs'\nimport '@material/web/tabs/primary-tab'\nimport '@material/web/tabs/secondary-tab'\n\ntype Theme = {\n theme_name: string\n theme_object: any\n}\nexport class WidgetNavbar extends LitElement {\n @property({ type: Object }) inputData?: InputData\n @property({ type: Object }) theme?: Theme\n @property({ type: String }) route?: string\n\n @state() private themeBgColor?: string\n @state() private themeTitleColor?: string\n\n version: string = 'versionplaceholder'\n\n update(changedProperties: Map<string, any>) {\n if (changedProperties.has('theme')) {\n this.registerTheme(this.theme)\n }\n\n super.update(changedProperties)\n }\n\n protected firstUpdated(_changedProperties: PropertyValues): void {\n this.registerTheme(this.theme)\n }\n\n registerTheme(theme?: Theme) {\n const cssTextColor = getComputedStyle(this).getPropertyValue('--re-text-color').trim()\n const cssBgColor = getComputedStyle(this).getPropertyValue('--re-tile-background-color').trim()\n this.themeBgColor = cssBgColor || this.theme?.theme_object?.backgroundColor\n this.themeTitleColor = cssTextColor || this.theme?.theme_object?.title?.textStyle?.color\n }\n\n handleNavItemClick(route?: string) {\n // console.log('Navigating to:', item.route)\n const event = new CustomEvent('nav-submit', {\n detail: { path: route },\n bubbles: true,\n composed: true\n })\n this.dispatchEvent(event)\n }\n\n normalizeRoute(route?: string) {\n if (!route) return '/'\n return route\n }\n\n static styles = css`\n :host {\n display: block;\n font-family: sans-serif;\n box-sizing: border-box;\n margin: auto;\n }\n\n .paging:not([active]) {\n display: none !important;\n }\n\n .wrapper {\n display: flex;\n align-items: end;\n height: 100%;\n width: 100%;\n box-sizing: border-box;\n }\n\n md-icon {\n font-family: 'Material Symbols Outlined';\n }\n\n .selected {\n font-weight: bold;\n background-color: rgba(0, 0, 0, 0.1);\n }\n\n h2 {\n margin: 0;\n padding: 0px;\n font-size: 1.2em;\n line-height: 2.5;\n height: 48px;\n }\n `\n\n trimRoute(route?: string) {\n if (!route) return ''\n return '/' + route.split('/').filter(Boolean).join('/')\n }\n\n addSlashes(item?: any): string | undefined {\n if (!item.route?.endsWith('/') && item.trailingSlash) {\n item.route += '/'\n }\n if (!item.route?.startsWith('/') && item.leadingSlash) {\n item.route = '/' + item.route\n }\n return item.route\n }\n\n matchesRoute(itemRoute?: string) {\n if (itemRoute === undefined) return false\n const route = this.trimRoute(decodeURIComponent(this.route || '/'))\n const subRoute = this.trimRoute(itemRoute)\n if (itemRoute.startsWith('/')) {\n return route.startsWith(subRoute)\n } else {\n return route.endsWith(subRoute) || route === subRoute\n }\n }\n\n render() {\n const fontSize = this.inputData?.style?.fontSize ?? 16\n const iconFontSize = (this.inputData?.style?.fontSize ?? 16) * 1.5\n const fontColor = this.inputData?.style?.color || this.themeTitleColor || 'black'\n const bgColor = this.inputData?.style?.backgroundColor || this.themeBgColor || 'white'\n return html`\n <div\n class=\"wrapper\"\n style=\"background-color: ${bgColor}; color: ${fontColor};\n font-weight: ${this.inputData?.style?.fontWeight};\n font-size: ${fontSize}px;\"\n >\n <h2\n class=\"paging\"\n style=${this.inputData?.route ? 'cursor: pointer' : ''}\n ?active=${this.inputData?.title}\n @click=${() => this.handleNavItemClick(this.addSlashes(this.inputData))}\n >\n ${this.inputData?.title}\n </h2>\n <md-tab class=\"xnav-list\">\n ${repeat(\n this.inputData?.navItems || [],\n (item) => item.label,\n (item) => html`\n <md-secondary-tab\n ?active=${this.matchesRoute(this.addSlashes(item))}\n style=\"font-size: ${fontSize}px;\n --md-secondary-tab-container-color: ${bgColor};\n color: ${fontColor};\"\n @click=${() => this.handleNavItemClick(this.addSlashes(item))}\n >\n ${item.iconName\n ? html`\n <md-icon\n slot=\"icon\"\n style=\"font-size: ${iconFontSize}px;width: ${iconFontSize}px;color: ${fontColor}\"\n >\n ${item.iconName}\n </md-icon>\n `\n : nothing}\n ${item.label}\n </md-secondary-tab>\n `\n )}\n </md-tab>\n </div>\n `\n }\n}\nwindow.customElements.define('widget-navbar-versionplaceholder', WidgetNavbar)\n"],"names":["_WidgetNavbar","LitElement","changedProperties","_changedProperties","theme","cssTextColor","cssBgColor","route","event","item","itemRoute","subRoute","fontSize","iconFontSize","fontColor","bgColor","html","repeat","nothing","css","WidgetNavbar","__decorateClass","property","state"],"mappings":";;;;;;;;;;;;AAcO,MAAMA,IAAN,MAAMA,UAAqBC,EAAW;AAAA,EAAtC,cAAA;AAAA,UAAA,GAAA,SAAA,GAQH,KAAA,UAAkB;AAAA,EAAA;AAAA,EAElB,OAAOC,GAAqC;AACxC,IAAIA,EAAkB,IAAI,OAAO,KAC7B,KAAK,cAAc,KAAK,KAAK,GAGjC,MAAM,OAAOA,CAAiB;AAAA,EAClC;AAAA,EAEU,aAAaC,GAA0C;AAC7D,SAAK,cAAc,KAAK,KAAK;AAAA,EACjC;AAAA,EAEA,cAAcC,GAAe;AACzB,UAAMC,IAAe,iBAAiB,IAAI,EAAE,iBAAiB,iBAAiB,EAAE,KAAA,GAC1EC,IAAa,iBAAiB,IAAI,EAAE,iBAAiB,4BAA4B,EAAE,KAAA;AACzF,SAAK,eAAeA,KAAc,KAAK,OAAO,cAAc,iBAC5D,KAAK,kBAAkBD,KAAgB,KAAK,OAAO,cAAc,OAAO,WAAW;AAAA,EACvF;AAAA,EAEA,mBAAmBE,GAAgB;AAE/B,UAAMC,IAAQ,IAAI,YAAY,cAAc;AAAA,MACxC,QAAQ,EAAE,MAAMD,EAAA;AAAA,MAChB,SAAS;AAAA,MACT,UAAU;AAAA,IAAA,CACb;AACD,SAAK,cAAcC,CAAK;AAAA,EAC5B;AAAA,EAEA,eAAeD,GAAgB;AAC3B,WAAKA,KAAc;AAAA,EAEvB;AAAA,EAwCA,UAAUA,GAAgB;AACtB,WAAKA,IACE,MAAMA,EAAM,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,IADnC;AAAA,EAEvB;AAAA,EAEA,WAAWE,GAAgC;AACvC,WAAI,CAACA,EAAK,OAAO,SAAS,GAAG,KAAKA,EAAK,kBACnCA,EAAK,SAAS,MAEd,CAACA,EAAK,OAAO,WAAW,GAAG,KAAKA,EAAK,iBACrCA,EAAK,QAAQ,MAAMA,EAAK,QAErBA,EAAK;AAAA,EAChB;AAAA,EAEA,aAAaC,GAAoB;AAC7B,QAAIA,MAAc,OAAW,QAAO;AACpC,UAAMH,IAAQ,KAAK,UAAU,mBAAmB,KAAK,SAAS,GAAG,CAAC,GAC5DI,IAAW,KAAK,UAAUD,CAAS;AACzC,WAAIA,EAAU,WAAW,GAAG,IACjBH,EAAM,WAAWI,CAAQ,IAEzBJ,EAAM,SAASI,CAAQ,KAAKJ,MAAUI;AAAA,EAErD;AAAA,EAEA,SAAS;AACL,UAAMC,IAAW,KAAK,WAAW,OAAO,YAAY,IAC9CC,KAAgB,KAAK,WAAW,OAAO,YAAY,MAAM,KACzDC,IAAY,KAAK,WAAW,OAAO,SAAS,KAAK,mBAAmB,SACpEC,IAAU,KAAK,WAAW,OAAO,mBAAmB,KAAK,gBAAgB;AAC/E,WAAOC;AAAA;AAAA;AAAA,2CAG4BD,CAAO,YAAYD,CAAS;AAAA,+BACxC,KAAK,WAAW,OAAO,UAAU;AAAA,6BACnCF,CAAQ;AAAA;AAAA;AAAA;AAAA,4BAIT,KAAK,WAAW,QAAQ,oBAAoB,EAAE;AAAA,8BAC5C,KAAK,WAAW,KAAK;AAAA,6BACtB,MAAM,KAAK,mBAAmB,KAAK,WAAW,KAAK,SAAS,CAAC,CAAC;AAAA;AAAA,sBAErE,KAAK,WAAW,KAAK;AAAA;AAAA;AAAA,sBAGrBK;AAAA,MACE,KAAK,WAAW,YAAY,CAAA;AAAA,MAC5B,CAACR,MAASA,EAAK;AAAA,MACf,CAACA,MAASO;AAAA;AAAA,0CAEQ,KAAK,aAAa,KAAK,WAAWP,CAAI,CAAC,CAAC;AAAA,oDAC9BG,CAAQ;AAAA,sEACUG,CAAO;AAAA,yCACpCD,CAAS;AAAA,yCACT,MAAM,KAAK,mBAAmB,KAAK,WAAWL,CAAI,CAAC,CAAC;AAAA;AAAA,kCAE3DA,EAAK,WACDO;AAAA;AAAA;AAAA,kEAG4BH,CAAY,aAAaA,CAAY,aAAaC,CAAS;AAAA;AAAA,gDAE7EL,EAAK,QAAQ;AAAA;AAAA,0CAGvBS,CAAO;AAAA,kCACXT,EAAK,KAAK;AAAA;AAAA;AAAA,IAAA,CAGvB;AAAA;AAAA;AAAA;AAAA,EAIjB;AACJ;AAlHIT,EAAO,SAASmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA5Cb,IAAMC,IAANpB;AACyBqB,EAAA;AAAA,EAA3BC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GADjBF,EACmB,WAAA,WAAA;AACAC,EAAA;AAAA,EAA3BC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GAFjBF,EAEmB,WAAA,OAAA;AACAC,EAAA;AAAA,EAA3BC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GAHjBF,EAGmB,WAAA,OAAA;AAEXC,EAAA;AAAA,EAAhBE,EAAA;AAAM,GALEH,EAKQ,WAAA,cAAA;AACAC,EAAA;AAAA,EAAhBE,EAAA;AAAM,GANEH,EAMQ,WAAA,iBAAA;AAyJrB,OAAO,eAAe,OAAO,wBAAoCA,CAAY;"}
1
+ {"version":3,"file":"widget-navbar.js","sources":["../src/widget-navbar.ts"],"sourcesContent":["import { html, css, LitElement, PropertyValues, nothing } from 'lit'\nimport { property, state } from 'lit/decorators.js'\nimport { repeat } from 'lit/directives/repeat.js'\nimport { InputData } from './definition-schema'\n\nimport '@material/web/icon/icon'\nimport '@material/web/tabs/tabs'\nimport '@material/web/tabs/primary-tab'\nimport '@material/web/tabs/secondary-tab'\n\ntype Theme = {\n theme_name: string\n theme_object: any\n}\nexport class WidgetNavbar extends LitElement {\n @property({ type: Object }) inputData?: InputData\n @property({ type: Object }) theme?: Theme\n @property({ type: String }) route?: string\n\n @state() private themeBgColor?: string\n @state() private themeTitleColor?: string\n\n version: string = 'versionplaceholder'\n\n update(changedProperties: Map<string, any>) {\n if (changedProperties.has('theme')) {\n this.registerTheme(this.theme)\n }\n\n super.update(changedProperties)\n }\n\n protected firstUpdated(_changedProperties: PropertyValues): void {\n this.registerTheme(this.theme)\n }\n\n registerTheme(theme?: Theme) {\n const cssTextColor = getComputedStyle(this).getPropertyValue('--re-text-color').trim()\n const cssBgColor = getComputedStyle(this).getPropertyValue('--re-tile-background-color').trim()\n this.themeBgColor = cssBgColor || this.theme?.theme_object?.backgroundColor\n this.themeTitleColor = cssTextColor || this.theme?.theme_object?.title?.textStyle?.color\n }\n\n handleNavItemClick(route?: string) {\n // console.log('Navigating to:', item.route)\n const event = new CustomEvent('nav-submit', {\n detail: { path: route },\n bubbles: true,\n composed: true\n })\n this.dispatchEvent(event)\n }\n\n normalizeRoute(route?: string) {\n if (!route) return '/'\n return route\n }\n\n static styles = css`\n :host {\n display: block;\n font-family: sans-serif;\n box-sizing: border-box;\n margin: auto;\n }\n\n .paging:not([active]) {\n display: none !important;\n }\n\n .wrapper {\n display: flex;\n align-items: end;\n height: 100%;\n width: 100%;\n padding: 0 16px;\n box-sizing: border-box;\n }\n\n md-icon {\n font-family: 'Material Symbols Outlined';\n }\n\n .selected {\n font-weight: bold;\n background-color: rgba(0, 0, 0, 0.1);\n }\n\n h2 {\n margin: 0;\n padding: 0px;\n font-size: 1.2em;\n line-height: 2.5;\n height: 48px;\n }\n `\n\n trimRoute(route?: string) {\n if (!route) return ''\n return '/' + route.split('/').filter(Boolean).join('/')\n }\n\n resolveRoute(item?: any): string | undefined {\n let route = String(item?.route ?? '')\n if (item?.variables) {\n for (const variable of item.variables) {\n if (variable.label) {\n route = route\n .split(`{{${variable.label}}}`)\n .join(encodeURIComponent(String(variable.value ?? '')))\n }\n }\n }\n if (route.includes('*')) {\n const currentSegments = (this.route || '').split('/').filter(Boolean)\n const routeSegments = route.split('/').filter(Boolean)\n for (let i = 0; i < routeSegments.length; i++) {\n if (routeSegments[i] === '*') {\n routeSegments[i] = currentSegments[i] ?? ''\n }\n }\n route = (route.startsWith('/') ? '/' : '') + routeSegments.filter(Boolean).join('/')\n }\n return route\n }\n\n matchesRoute(itemRoute?: string) {\n if (itemRoute === undefined) return false\n const route = this.trimRoute(decodeURIComponent(this.route || '/'))\n const subRoute = this.trimRoute(itemRoute)\n if (itemRoute.startsWith('/')) {\n return route.startsWith(subRoute)\n } else {\n return route.endsWith(subRoute) || route === subRoute\n }\n }\n\n render() {\n const fontSize = this.inputData?.style?.fontSize ?? 16\n const iconFontSize = (this.inputData?.style?.fontSize ?? 16) * 1.5\n const fontColor = this.inputData?.style?.color || this.themeTitleColor || 'black'\n const bgColor = this.inputData?.style?.backgroundColor || this.themeBgColor || 'white'\n return html`\n <div\n class=\"wrapper\"\n style=\"background-color: ${bgColor}; color: ${fontColor};\n font-weight: ${this.inputData?.style?.fontWeight};\n font-size: ${fontSize}px;\"\n >\n <h2\n class=\"paging\"\n style=${this.inputData?.route ? 'cursor: pointer' : ''}\n ?active=${this.inputData?.title}\n @click=${() =>\n this.handleNavItemClick(\n this.resolveRoute({\n route: this.inputData?.route,\n variables: this.inputData?.variables\n })\n )}\n >\n ${this.inputData?.title}\n </h2>\n <md-tab class=\"xnav-list\">\n ${repeat(\n this.inputData?.navItems || [],\n (item) => item.label,\n (item) => html`\n <md-secondary-tab\n ?active=${this.matchesRoute(this.resolveRoute(item))}\n style=\"font-size: ${fontSize}px;\n --md-secondary-tab-container-color: ${bgColor};\n color: ${fontColor};\"\n @click=${() => this.handleNavItemClick(this.resolveRoute(item))}\n >\n ${item.iconName\n ? html`\n <md-icon\n slot=\"icon\"\n style=\"font-size: ${iconFontSize}px;width: ${iconFontSize}px;color: ${fontColor}\"\n >\n ${item.iconName}\n </md-icon>\n `\n : nothing}\n ${item.label}\n </md-secondary-tab>\n `\n )}\n </md-tab>\n </div>\n `\n }\n}\nwindow.customElements.define('widget-navbar-versionplaceholder', WidgetNavbar)\n"],"names":["_WidgetNavbar","LitElement","changedProperties","_changedProperties","theme","cssTextColor","cssBgColor","route","event","item","variable","currentSegments","routeSegments","i","itemRoute","subRoute","fontSize","iconFontSize","fontColor","bgColor","html","repeat","nothing","css","WidgetNavbar","__decorateClass","property","state"],"mappings":"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"}
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Webcomponent widget-navbar following open-wc recommendations",
4
4
  "license": "MIT",
5
5
  "author": "widget-navbar",
6
- "version": "1.0.12",
6
+ "version": "1.0.13",
7
7
  "engines": {
8
8
  "node": ">=24.9.0",
9
9
  "npm": ">=10.0.2"
@@ -10,17 +10,25 @@
10
10
  */
11
11
  export type TitleSettings = string;
12
12
  /**
13
- * The route to navigate to when the title is clicked. Use relative paths (e.g., 'home', 'dashboard') that append to the current base URL, or use leadingSlash for absolute paths.
13
+ * The destination path when the title is clicked. Supports two dynamic substitution mechanisms: (1) Variable placeholders using double curly braces — define variables in the 'Title Navigation Variables' array below and reference them as {{variableName}} in the route string (e.g., '/device/{{deviceId}}/details' where a variable with label 'deviceId' provides the value). (2) Wildcard segments using a single asterisk '*' as a full path segment — each '*' is replaced at runtime by the segment at the same position from the current browser route (e.g., '/* /settings' navigates to the settings page while preserving the first segment of the current URL). The '*' must be the entire segment to be substituted; partial wildcards like 'test*' are treated as literal text. Routes starting with '/' are absolute; routes without a leading slash are relative to the current location.
14
14
  */
15
15
  export type TitleNavigation = string;
16
16
  /**
17
- * When enabled, prepends '/' to the navigation route making it absolute from the root. When disabled, routes are relative to the current location.
17
+ * The variable name used in the route string. Reference this in your route using the {{label}} syntax. Use descriptive names like 'temperature', 'status', 'deviceName'.
18
18
  */
19
- export type AddLeadingSlash = boolean;
19
+ export type Label = string;
20
+ /**
21
+ * The replacement text that will appear in place of {{label}} in the rendered output. Can be a static value or bound to a data column for dynamic updates.
22
+ */
23
+ export type Value = string;
20
24
  /**
21
- * When enabled, appends '/' to the end of the navigation route. Some routing systems require trailing slashes for proper page matching.
25
+ * Array of variable definitions for dynamic route segment substitution. Each variable has a label (used in the route string as {{label}}) and a value (the replacement text). Values can be static or bound to data columns for real-time updates.
22
26
  */
23
- export type AddTraillingSlash = boolean;
27
+ export type TitleNavigationVariables = {
28
+ label?: Label;
29
+ value?: Value;
30
+ [k: string]: unknown;
31
+ }[];
24
32
  /**
25
33
  * Font size in pixels for navigation item labels.
26
34
  */
@@ -32,32 +40,39 @@ export type FontWeight = number;
32
40
  /**
33
41
  * The text displayed for this navigation item. Should be short and descriptive (e.g., 'Dashboard', 'Settings', 'Reports').
34
42
  */
35
- export type Label = string;
43
+ export type Label1 = string;
36
44
  /**
37
45
  * Material icon name to display alongside the label. Find icon names at https://fonts.google.com/icons (e.g., 'home', 'settings', 'dashboard', 'analytics').
38
46
  */
39
47
  export type IconName = string;
40
48
  /**
41
- * The destination path when this item is clicked. Use relative paths that append to the current URL, or enable leadingSlash for absolute paths.
49
+ * The destination path when this item is clicked. Supports two dynamic substitution mechanisms: (1) Variable placeholders using double curly braces — define variables in the 'Variables' array below and reference them as {{variableName}} in the route string (e.g., '/device/{{deviceId}}/details' where a variable with label 'deviceId' provides the value). (2) Wildcard segments using a single asterisk '*' as a full path segment — each '*' is replaced at runtime by the segment at the same position from the current browser route (e.g., '/* /settings' navigates to the settings page while preserving the first segment of the current URL). The '*' must be the entire segment to be substituted; partial wildcards like 'test*' are treated as literal text. Routes starting with '/' are absolute; routes without a leading slash are relative to the current location.
42
50
  */
43
51
  export type NavigationRoute = string;
44
52
  /**
45
- * When enabled, prepends '/' to this item's route making it absolute from the root.
53
+ * The variable name used in the route string. Reference this in your route using the {{label}} syntax. Use descriptive names like 'temperature', 'status', 'deviceName'.
54
+ */
55
+ export type Label2 = string;
56
+ /**
57
+ * The replacement text that will appear in place of {{label}} in the rendered output. Can be a static value or bound to a data column for dynamic updates.
46
58
  */
47
- export type AddLeadingSlash1 = boolean;
59
+ export type Value1 = string;
48
60
  /**
49
- * When enabled, appends '/' to the end of this item's route.
61
+ * Array of variable definitions for dynamic route segment substitution. Each variable has a label (used in the route string as {{label}}) and a value (the replacement text). Values can be static or bound to data columns for real-time updates.
50
62
  */
51
- export type AddTraillingSlash1 = boolean;
63
+ export type NavigationVariables = {
64
+ label?: Label2;
65
+ value?: Value1;
66
+ [k: string]: unknown;
67
+ }[];
52
68
  /**
53
69
  * Array of clickable navigation links displayed in the navigation bar. Each item can have a label, icon, and destination route.
54
70
  */
55
71
  export type NavigationItems = {
56
- label?: Label;
72
+ label?: Label1;
57
73
  iconName?: IconName;
58
74
  route?: NavigationRoute;
59
- leadingSlash?: AddLeadingSlash1;
60
- trailingSlash?: AddTraillingSlash1;
75
+ variables?: NavigationVariables;
61
76
  [k: string]: unknown;
62
77
  }[];
63
78
 
@@ -67,8 +82,7 @@ export type NavigationItems = {
67
82
  export interface InputData {
68
83
  title?: TitleSettings;
69
84
  route?: TitleNavigation;
70
- leadingSlash?: AddLeadingSlash;
71
- trailingSlash?: AddTraillingSlash;
85
+ variables?: TitleNavigationVariables;
72
86
  style?: ItemStyle;
73
87
  navItems?: NavigationItems;
74
88
  [k: string]: unknown;
@@ -12,22 +12,32 @@
12
12
  "route": {
13
13
  "title": "Title Navigation",
14
14
  "order": 3,
15
- "description": "The route to navigate to when the title is clicked. Use relative paths (e.g., 'home', 'dashboard') that append to the current base URL, or use leadingSlash for absolute paths.",
15
+ "description": "The destination path when the title is clicked. Supports two dynamic substitution mechanisms: (1) Variable placeholders using double curly braces — define variables in the 'Title Navigation Variables' array below and reference them as {{variableName}} in the route string (e.g., '/device/{{deviceId}}/details' where a variable with label 'deviceId' provides the value). (2) Wildcard segments using a single asterisk '*' as a full path segment — each '*' is replaced at runtime by the segment at the same position from the current browser route (e.g., '/*/settings' navigates to the settings page while preserving the first segment of the current URL). The '*' must be the entire segment to be substituted; partial wildcards like 'test*' are treated as literal text. Routes starting with '/' are absolute; routes without a leading slash are relative to the current location.",
16
16
  "type": "string"
17
17
  },
18
- "leadingSlash": {
19
- "title": "Add Leading Slash",
20
- "order": 4,
21
- "description": "When enabled, prepends '/' to the navigation route making it absolute from the root. When disabled, routes are relative to the current location.",
22
- "dataDrivenDisabled": true,
23
- "type": "boolean"
24
- },
25
- "trailingSlash": {
26
- "title": "Add Trailling Slash",
27
- "order": 5,
28
- "description": "When enabled, appends '/' to the end of the navigation route. Some routing systems require trailing slashes for proper page matching.",
18
+ "variables": {
19
+ "title": "Title Navigation Variables",
20
+ "description": "Array of variable definitions for dynamic route segment substitution. Each variable has a label (used in the route string as {{label}}) and a value (the replacement text). Values can be static or bound to data columns for real-time updates.",
21
+ "type": "array",
29
22
  "dataDrivenDisabled": true,
30
- "type": "boolean"
23
+ "order": 4,
24
+ "items": {
25
+ "type": "object",
26
+ "properties": {
27
+ "label": {
28
+ "title": "Label",
29
+ "description": "The variable name used in the route string. Reference this in your route using the {{label}} syntax. Use descriptive names like 'temperature', 'status', 'deviceName'.",
30
+ "type": "string",
31
+ "order": 1
32
+ },
33
+ "value": {
34
+ "title": "Value",
35
+ "description": "The replacement text that will appear in place of {{label}} in the rendered output. Can be a static value or bound to a data column for dynamic updates.",
36
+ "type": "string",
37
+ "order": 2
38
+ }
39
+ }
40
+ }
31
41
  },
32
42
  "style": {
33
43
  "title": "Item Style",
@@ -89,22 +99,32 @@
89
99
  "route": {
90
100
  "title": "Navigation Route",
91
101
  "order": 3,
92
- "description": "The destination path when this item is clicked. Use relative paths that append to the current URL, or enable leadingSlash for absolute paths.",
102
+ "description": "The destination path when this item is clicked. Supports two dynamic substitution mechanisms: (1) Variable placeholders using double curly braces — define variables in the 'Variables' array below and reference them as {{variableName}} in the route string (e.g., '/device/{{deviceId}}/details' where a variable with label 'deviceId' provides the value). (2) Wildcard segments using a single asterisk '*' as a full path segment — each '*' is replaced at runtime by the segment at the same position from the current browser route (e.g., '/*/settings' navigates to the settings page while preserving the first segment of the current URL). The '*' must be the entire segment to be substituted; partial wildcards like 'test*' are treated as literal text. Routes starting with '/' are absolute; routes without a leading slash are relative to the current location.",
93
103
  "type": "string"
94
104
  },
95
- "leadingSlash": {
96
- "title": "Add Leading Slash",
97
- "order": 4,
98
- "description": "When enabled, prepends '/' to this item's route making it absolute from the root.",
99
- "dataDrivenDisabled": true,
100
- "type": "boolean"
101
- },
102
- "trailingSlash": {
103
- "title": "Add Trailling Slash",
104
- "order": 5,
105
- "description": "When enabled, appends '/' to the end of this item's route.",
105
+ "variables": {
106
+ "title": "Navigation Variables",
107
+ "description": "Array of variable definitions for dynamic route segment substitution. Each variable has a label (used in the route string as {{label}}) and a value (the replacement text). Values can be static or bound to data columns for real-time updates.",
108
+ "type": "array",
106
109
  "dataDrivenDisabled": true,
107
- "type": "boolean"
110
+ "order": 4,
111
+ "items": {
112
+ "type": "object",
113
+ "properties": {
114
+ "label": {
115
+ "title": "Label",
116
+ "description": "The variable name used in the route string. Reference this in your route using the {{label}} syntax. Use descriptive names like 'temperature', 'status', 'deviceName'.",
117
+ "type": "string",
118
+ "order": 1
119
+ },
120
+ "value": {
121
+ "title": "Value",
122
+ "description": "The replacement text that will appear in place of {{label}} in the rendered output. Can be a static value or bound to a data column for dynamic updates.",
123
+ "type": "string",
124
+ "order": 2
125
+ }
126
+ }
127
+ }
108
128
  }
109
129
  }
110
130
  }
@@ -73,6 +73,7 @@ export class WidgetNavbar extends LitElement {
73
73
  align-items: end;
74
74
  height: 100%;
75
75
  width: 100%;
76
+ padding: 0 16px;
76
77
  box-sizing: border-box;
77
78
  }
78
79
 
@@ -99,14 +100,28 @@ export class WidgetNavbar extends LitElement {
99
100
  return '/' + route.split('/').filter(Boolean).join('/')
100
101
  }
101
102
 
102
- addSlashes(item?: any): string | undefined {
103
- if (!item.route?.endsWith('/') && item.trailingSlash) {
104
- item.route += '/'
103
+ resolveRoute(item?: any): string | undefined {
104
+ let route = String(item?.route ?? '')
105
+ if (item?.variables) {
106
+ for (const variable of item.variables) {
107
+ if (variable.label) {
108
+ route = route
109
+ .split(`{{${variable.label}}}`)
110
+ .join(encodeURIComponent(String(variable.value ?? '')))
111
+ }
112
+ }
105
113
  }
106
- if (!item.route?.startsWith('/') && item.leadingSlash) {
107
- item.route = '/' + item.route
114
+ if (route.includes('*')) {
115
+ const currentSegments = (this.route || '').split('/').filter(Boolean)
116
+ const routeSegments = route.split('/').filter(Boolean)
117
+ for (let i = 0; i < routeSegments.length; i++) {
118
+ if (routeSegments[i] === '*') {
119
+ routeSegments[i] = currentSegments[i] ?? ''
120
+ }
121
+ }
122
+ route = (route.startsWith('/') ? '/' : '') + routeSegments.filter(Boolean).join('/')
108
123
  }
109
- return item.route
124
+ return route
110
125
  }
111
126
 
112
127
  matchesRoute(itemRoute?: string) {
@@ -136,7 +151,13 @@ export class WidgetNavbar extends LitElement {
136
151
  class="paging"
137
152
  style=${this.inputData?.route ? 'cursor: pointer' : ''}
138
153
  ?active=${this.inputData?.title}
139
- @click=${() => this.handleNavItemClick(this.addSlashes(this.inputData))}
154
+ @click=${() =>
155
+ this.handleNavItemClick(
156
+ this.resolveRoute({
157
+ route: this.inputData?.route,
158
+ variables: this.inputData?.variables
159
+ })
160
+ )}
140
161
  >
141
162
  ${this.inputData?.title}
142
163
  </h2>
@@ -146,11 +167,11 @@ export class WidgetNavbar extends LitElement {
146
167
  (item) => item.label,
147
168
  (item) => html`
148
169
  <md-secondary-tab
149
- ?active=${this.matchesRoute(this.addSlashes(item))}
170
+ ?active=${this.matchesRoute(this.resolveRoute(item))}
150
171
  style="font-size: ${fontSize}px;
151
172
  --md-secondary-tab-container-color: ${bgColor};
152
173
  color: ${fontColor};"
153
- @click=${() => this.handleNavItemClick(this.addSlashes(item))}
174
+ @click=${() => this.handleNavItemClick(this.resolveRoute(item))}
154
175
  >
155
176
  ${item.iconName
156
177
  ? html`