@record-evolution/widget-navbar 1.0.14 → 1.0.15

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,22 @@
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";
1
+ import { LitElement as f, css as u, nothing as p, html as c } from "lit";
2
+ import { property as d, state as h } from "lit/decorators.js";
3
+ import { repeat as m } from "lit/directives/repeat.js";
4
4
  import "@material/web/icon/icon";
5
- import "@material/web/tabs/tabs";
6
- import "@material/web/tabs/primary-tab";
7
5
  import "@material/web/tabs/secondary-tab";
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;
6
+ var b = Object.defineProperty, l = (s, t, e, a) => {
7
+ for (var o = void 0, r = s.length - 1, n; r >= 0; r--)
8
+ (n = s[r]) && (o = n(t, e, o) || o);
9
+ return o && b(t, e, o), o;
12
10
  };
13
- const h = class h extends m {
11
+ const g = (s) => {
12
+ if (!s) return !0;
13
+ const t = s.trim().toLowerCase();
14
+ if (t === "transparent") return !0;
15
+ const e = t.match(/^(?:rgba|hsla)\([^)]*[,/]\s*([\d.]+%?)\s*\)$/);
16
+ return e ? parseFloat(e[1]) === 0 : /^#[0-9a-f]{8}$/.test(t) ? t.slice(7) === "00" : /^#[0-9a-f]{4}$/.test(t) ? t[4] === "0" : !1;
17
+ }, v = class v extends f {
14
18
  constructor() {
15
- super(...arguments), this.version = "1.0.14";
19
+ super(...arguments), this.version = "1.0.15";
16
20
  }
17
21
  update(t) {
18
22
  t.has("theme") && this.registerTheme(this.theme), super.update(t);
@@ -21,8 +25,8 @@ const h = class h extends m {
21
25
  this.registerTheme(this.theme);
22
26
  }
23
27
  registerTheme(t) {
24
- const e = getComputedStyle(this).getPropertyValue("--re-text-color").trim(), i = getComputedStyle(this).getPropertyValue("--re-tile-background-color").trim();
25
- this.themeBgColor = i || this.theme?.theme_object?.backgroundColor, this.themeTitleColor = e || this.theme?.theme_object?.title?.textStyle?.color;
28
+ const e = getComputedStyle(this).getPropertyValue("--re-text-color").trim(), a = getComputedStyle(this).getPropertyValue("--re-tile-background-color").trim(), o = t?.theme_object?.backgroundColor;
29
+ this.themeBgColor = a || (g(o) ? void 0 : o), this.themeTitleColor = e || t?.theme_object?.title?.textStyle?.color;
26
30
  }
27
31
  handleNavItemClick(t) {
28
32
  const e = new CustomEvent("nav-submit", {
@@ -41,29 +45,29 @@ const h = class h extends m {
41
45
  resolveRoute(t) {
42
46
  let e = String(t?.route ?? "");
43
47
  if (t?.variables)
44
- for (const i of t.variables)
45
- i.label && (e = e.split(`{{${i.label}}}`).join(encodeURIComponent(String(i.value ?? ""))));
48
+ for (const a of t.variables)
49
+ a.label && (e = e.split(`{{${a.label}}}`).join(encodeURIComponent(String(a.value ?? ""))));
46
50
  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
+ const a = (this.route || "").split("/").filter(Boolean), o = e.split("/").filter(Boolean);
52
+ for (let r = 0; r < o.length; r++)
53
+ o[r] === "*" && (o[r] = a[r] ?? "");
54
+ e = (e.startsWith("/") ? "/" : "") + o.filter(Boolean).join("/");
51
55
  }
52
56
  return e;
53
57
  }
54
58
  matchesRoute(t) {
55
59
  if (t === void 0) return !1;
56
- const e = this.trimRoute(decodeURIComponent(this.route || "/")), i = this.trimRoute(t);
57
- return t.startsWith("/") ? e.startsWith(i) : e.endsWith(i) || e === i;
60
+ const e = this.trimRoute(decodeURIComponent(this.route || "/")), a = this.trimRoute(t);
61
+ return t.startsWith("/") ? e.startsWith(a) : e.endsWith(a) || e === a;
58
62
  }
59
63
  render() {
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`
64
+ const t = this.inputData?.style?.fontSize ?? 16, e = this.inputData?.style?.fontWeight ?? 400, a = t * 1.5, o = this.inputData?.style?.color || this.themeTitleColor || "black", r = this.inputData?.style?.backgroundColor || this.themeBgColor || "white";
65
+ return c`
62
66
  <div
63
67
  class="wrapper"
64
- style="background-color: ${r}; color: ${i};
65
- font-weight: ${this.inputData?.style?.fontWeight};
66
- font-size: ${t}px;"
68
+ style="--nav-bg: ${r}; --nav-fg: ${o};
69
+ --nav-font-size: ${t}px; --nav-font-weight: ${e};
70
+ --nav-icon-size: ${a}px;"
67
71
  >
68
72
  <h2
69
73
  class="paging"
@@ -78,36 +82,26 @@ const h = class h extends m {
78
82
  >
79
83
  ${this.inputData?.title}
80
84
  </h2>
81
- <md-tab class="xnav-list">
82
- ${g(
85
+ <div class="nav-list" role="tablist">
86
+ ${m(
83
87
  this.inputData?.navItems || [],
84
- (o) => o.label,
85
- (o) => l`
88
+ (n) => n.label,
89
+ (n) => c`
86
90
  <md-secondary-tab
87
- ?active=${this.matchesRoute(this.resolveRoute(o))}
88
- style="font-size: ${t}px;
89
- --md-secondary-tab-container-color: ${r};
90
- color: ${i};"
91
- @click=${() => this.handleNavItemClick(this.resolveRoute(o))}
91
+ ?active=${this.matchesRoute(this.resolveRoute(n))}
92
+ @click=${() => this.handleNavItemClick(this.resolveRoute(n))}
92
93
  >
93
- ${o.iconName ? l`
94
- <md-icon
95
- slot="icon"
96
- style="font-size: ${e}px;width: ${e}px;color: ${i}"
97
- >
98
- ${o.iconName}
99
- </md-icon>
100
- ` : f}
101
- ${o.label}
94
+ ${n.iconName ? c`<md-icon slot="icon">${n.iconName}</md-icon>` : p}
95
+ ${n.label}
102
96
  </md-secondary-tab>
103
97
  `
104
98
  )}
105
- </md-tab>
99
+ </div>
106
100
  </div>
107
101
  `;
108
102
  }
109
103
  };
110
- h.styles = d`
104
+ v.styles = u`
111
105
  :host {
112
106
  display: block;
113
107
  font-family: sans-serif;
@@ -122,47 +116,103 @@ h.styles = d`
122
116
  .wrapper {
123
117
  display: flex;
124
118
  align-items: end;
119
+ gap: 8px;
125
120
  height: 100%;
126
121
  width: 100%;
127
122
  padding: 0 16px;
128
123
  box-sizing: border-box;
124
+ background-color: var(--nav-bg);
125
+ color: var(--nav-fg);
126
+ font-size: var(--nav-font-size);
127
+ font-weight: var(--nav-font-weight);
129
128
  }
130
129
 
131
- md-icon {
132
- font-family: 'Material Symbols Outlined';
130
+ /* One scrollable row. Without this the tabs wrap onto several lines and
131
+ spill outside the coloured bar as soon as they don't fit. */
132
+ .nav-list {
133
+ display: flex;
134
+ align-items: end;
135
+ flex: 1;
136
+ min-width: 0;
137
+ overflow-x: auto;
138
+ scrollbar-width: none;
139
+ }
140
+
141
+ .nav-list::-webkit-scrollbar {
142
+ display: none;
133
143
  }
134
144
 
135
- .selected {
136
- font-weight: bold;
137
- background-color: rgba(0, 0, 0, 0.1);
145
+ /* Material's tab tokens default to the M3 palette (purple indicator,
146
+ near-black labels), which ignores the widget's configured colours.
147
+ Map every colour token onto the nav colours. */
148
+ md-secondary-tab {
149
+ flex: none;
150
+ --md-secondary-tab-container-color: var(--nav-bg);
151
+ --md-secondary-tab-label-text-size: var(--nav-font-size);
152
+ --md-secondary-tab-label-text-weight: var(--nav-font-weight);
153
+ --md-secondary-tab-icon-size: var(--nav-icon-size);
154
+ --md-secondary-tab-label-text-color: var(--nav-fg);
155
+ --md-secondary-tab-hover-label-text-color: var(--nav-fg);
156
+ --md-secondary-tab-focus-label-text-color: var(--nav-fg);
157
+ --md-secondary-tab-pressed-label-text-color: var(--nav-fg);
158
+ --md-secondary-tab-active-label-text-color: var(--nav-fg);
159
+ --md-secondary-tab-active-hover-label-text-color: var(--nav-fg);
160
+ --md-secondary-tab-active-focus-label-text-color: var(--nav-fg);
161
+ --md-secondary-tab-active-pressed-label-text-color: var(--nav-fg);
162
+ --md-secondary-tab-icon-color: var(--nav-fg);
163
+ --md-secondary-tab-hover-icon-color: var(--nav-fg);
164
+ --md-secondary-tab-focus-icon-color: var(--nav-fg);
165
+ --md-secondary-tab-pressed-icon-color: var(--nav-fg);
166
+ --md-secondary-tab-active-icon-color: var(--nav-fg);
167
+ --md-secondary-tab-active-hover-icon-color: var(--nav-fg);
168
+ --md-secondary-tab-active-focus-icon-color: var(--nav-fg);
169
+ --md-secondary-tab-active-pressed-icon-color: var(--nav-fg);
170
+ --md-secondary-tab-active-indicator-color: var(--nav-fg);
171
+ --md-secondary-tab-hover-state-layer-color: var(--nav-fg);
172
+ --md-secondary-tab-pressed-state-layer-color: var(--nav-fg);
173
+ --md-secondary-tab-active-hover-state-layer-color: var(--nav-fg);
174
+ --md-secondary-tab-active-pressed-state-layer-color: var(--nav-fg);
175
+ }
176
+
177
+ md-icon {
178
+ font-family: 'Material Symbols Outlined';
179
+ font-size: var(--nav-icon-size);
180
+ width: var(--nav-icon-size);
181
+ height: var(--nav-icon-size);
182
+ color: var(--nav-fg);
138
183
  }
139
184
 
140
185
  h2 {
141
186
  margin: 0;
142
187
  padding: 0px;
188
+ flex: none;
189
+ display: flex;
190
+ align-items: center;
191
+ min-height: 48px;
143
192
  font-size: 1.2em;
144
- line-height: 2.5;
145
- height: 48px;
193
+ /* the UA stylesheet forces bold, which would ignore the
194
+ configured font weight */
195
+ font-weight: inherit;
146
196
  }
147
197
  `;
148
- let s = h;
149
- n([
150
- a({ type: Object })
151
- ], s.prototype, "inputData");
152
- n([
153
- a({ type: Object })
154
- ], s.prototype, "theme");
155
- n([
156
- a({ type: String })
157
- ], s.prototype, "route");
158
- n([
159
- u()
160
- ], s.prototype, "themeBgColor");
161
- n([
162
- u()
163
- ], s.prototype, "themeTitleColor");
164
- window.customElements.define("widget-navbar-1.0.14", s);
198
+ let i = v;
199
+ l([
200
+ d({ type: Object })
201
+ ], i.prototype, "inputData");
202
+ l([
203
+ d({ type: Object })
204
+ ], i.prototype, "theme");
205
+ l([
206
+ d({ type: String })
207
+ ], i.prototype, "route");
208
+ l([
209
+ h()
210
+ ], i.prototype, "themeBgColor");
211
+ l([
212
+ h()
213
+ ], i.prototype, "themeTitleColor");
214
+ window.customElements.define("widget-navbar-1.0.15", i);
165
215
  export {
166
- s as WidgetNavbar
216
+ i as WidgetNavbar
167
217
  };
168
218
  //# 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 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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"}
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/secondary-tab'\n\ntype Theme = {\n theme_name: string\n theme_object: any\n}\n\n/**\n * ECharts themes describe a *chart canvas*, and most of them set\n * `backgroundColor` to a fully transparent colour (the light theme uses\n * `rgba(0, 0, 0, 0)`). That is a valid, truthy colour string, so using it\n * verbatim as the navbar background paints nothing at all. Treat any\n * fully transparent theme colour as \"no colour\" so the fallback kicks in.\n */\nconst isTransparent = (color?: string) => {\n if (!color) return true\n const value = color.trim().toLowerCase()\n if (value === 'transparent') return true\n const functional = value.match(/^(?:rgba|hsla)\\([^)]*[,/]\\s*([\\d.]+%?)\\s*\\)$/)\n if (functional) return parseFloat(functional[1]) === 0\n // #rrggbbaa / #rgba\n if (/^#[0-9a-f]{8}$/.test(value)) return value.slice(7) === '00'\n if (/^#[0-9a-f]{4}$/.test(value)) return value[4] === '0'\n return false\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 const themeBgColor = theme?.theme_object?.backgroundColor\n this.themeBgColor = cssBgColor || (isTransparent(themeBgColor) ? undefined : themeBgColor)\n this.themeTitleColor = cssTextColor || 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 gap: 8px;\n height: 100%;\n width: 100%;\n padding: 0 16px;\n box-sizing: border-box;\n background-color: var(--nav-bg);\n color: var(--nav-fg);\n font-size: var(--nav-font-size);\n font-weight: var(--nav-font-weight);\n }\n\n /* One scrollable row. Without this the tabs wrap onto several lines and\n spill outside the coloured bar as soon as they don't fit. */\n .nav-list {\n display: flex;\n align-items: end;\n flex: 1;\n min-width: 0;\n overflow-x: auto;\n scrollbar-width: none;\n }\n\n .nav-list::-webkit-scrollbar {\n display: none;\n }\n\n /* Material's tab tokens default to the M3 palette (purple indicator,\n near-black labels), which ignores the widget's configured colours.\n Map every colour token onto the nav colours. */\n md-secondary-tab {\n flex: none;\n --md-secondary-tab-container-color: var(--nav-bg);\n --md-secondary-tab-label-text-size: var(--nav-font-size);\n --md-secondary-tab-label-text-weight: var(--nav-font-weight);\n --md-secondary-tab-icon-size: var(--nav-icon-size);\n --md-secondary-tab-label-text-color: var(--nav-fg);\n --md-secondary-tab-hover-label-text-color: var(--nav-fg);\n --md-secondary-tab-focus-label-text-color: var(--nav-fg);\n --md-secondary-tab-pressed-label-text-color: var(--nav-fg);\n --md-secondary-tab-active-label-text-color: var(--nav-fg);\n --md-secondary-tab-active-hover-label-text-color: var(--nav-fg);\n --md-secondary-tab-active-focus-label-text-color: var(--nav-fg);\n --md-secondary-tab-active-pressed-label-text-color: var(--nav-fg);\n --md-secondary-tab-icon-color: var(--nav-fg);\n --md-secondary-tab-hover-icon-color: var(--nav-fg);\n --md-secondary-tab-focus-icon-color: var(--nav-fg);\n --md-secondary-tab-pressed-icon-color: var(--nav-fg);\n --md-secondary-tab-active-icon-color: var(--nav-fg);\n --md-secondary-tab-active-hover-icon-color: var(--nav-fg);\n --md-secondary-tab-active-focus-icon-color: var(--nav-fg);\n --md-secondary-tab-active-pressed-icon-color: var(--nav-fg);\n --md-secondary-tab-active-indicator-color: var(--nav-fg);\n --md-secondary-tab-hover-state-layer-color: var(--nav-fg);\n --md-secondary-tab-pressed-state-layer-color: var(--nav-fg);\n --md-secondary-tab-active-hover-state-layer-color: var(--nav-fg);\n --md-secondary-tab-active-pressed-state-layer-color: var(--nav-fg);\n }\n\n md-icon {\n font-family: 'Material Symbols Outlined';\n font-size: var(--nav-icon-size);\n width: var(--nav-icon-size);\n height: var(--nav-icon-size);\n color: var(--nav-fg);\n }\n\n h2 {\n margin: 0;\n padding: 0px;\n flex: none;\n display: flex;\n align-items: center;\n min-height: 48px;\n font-size: 1.2em;\n /* the UA stylesheet forces bold, which would ignore the\n configured font weight */\n font-weight: inherit;\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 fontWeight = this.inputData?.style?.fontWeight ?? 400\n const iconFontSize = fontSize * 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=\"--nav-bg: ${bgColor}; --nav-fg: ${fontColor};\n --nav-font-size: ${fontSize}px; --nav-font-weight: ${fontWeight};\n --nav-icon-size: ${iconFontSize}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 <div class=\"nav-list\" role=\"tablist\">\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 @click=${() => this.handleNavItemClick(this.resolveRoute(item))}\n >\n ${item.iconName\n ? html`<md-icon slot=\"icon\">${item.iconName}</md-icon>`\n : nothing}\n ${item.label}\n </md-secondary-tab>\n `\n )}\n </div>\n </div>\n `\n }\n}\nwindow.customElements.define('widget-navbar-versionplaceholder', WidgetNavbar)\n"],"names":["isTransparent","color","value","functional","_WidgetNavbar","LitElement","changedProperties","_changedProperties","theme","cssTextColor","cssBgColor","themeBgColor","route","event","item","variable","currentSegments","routeSegments","i","itemRoute","subRoute","fontSize","fontWeight","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.14",
6
+ "version": "1.0.15",
7
7
  "engines": {
8
8
  "node": ">=24.9.0",
9
9
  "npm": ">=10.0.2"
@@ -29,7 +29,7 @@
29
29
  },
30
30
  "dependencies": {
31
31
  "@material/web": "^2.4.1",
32
- "lit": "^3.3.2",
32
+ "lit": "^3.3.3",
33
33
  "tslib": "^2.8.1"
34
34
  },
35
35
  "devDependencies": {
@@ -69,7 +69,7 @@
69
69
  "backgroundColor": {
70
70
  "title": "Background Color",
71
71
  "description": "Background color of the navigation bar.",
72
- "order": 4,
72
+ "order": 5,
73
73
  "type": "color",
74
74
  "dataDrivenDisabled": true
75
75
  }
@@ -4,14 +4,31 @@ import { repeat } from 'lit/directives/repeat.js'
4
4
  import { InputData } from './definition-schema'
5
5
 
6
6
  import '@material/web/icon/icon'
7
- import '@material/web/tabs/tabs'
8
- import '@material/web/tabs/primary-tab'
9
7
  import '@material/web/tabs/secondary-tab'
10
8
 
11
9
  type Theme = {
12
10
  theme_name: string
13
11
  theme_object: any
14
12
  }
13
+
14
+ /**
15
+ * ECharts themes describe a *chart canvas*, and most of them set
16
+ * `backgroundColor` to a fully transparent colour (the light theme uses
17
+ * `rgba(0, 0, 0, 0)`). That is a valid, truthy colour string, so using it
18
+ * verbatim as the navbar background paints nothing at all. Treat any
19
+ * fully transparent theme colour as "no colour" so the fallback kicks in.
20
+ */
21
+ const isTransparent = (color?: string) => {
22
+ if (!color) return true
23
+ const value = color.trim().toLowerCase()
24
+ if (value === 'transparent') return true
25
+ const functional = value.match(/^(?:rgba|hsla)\([^)]*[,/]\s*([\d.]+%?)\s*\)$/)
26
+ if (functional) return parseFloat(functional[1]) === 0
27
+ // #rrggbbaa / #rgba
28
+ if (/^#[0-9a-f]{8}$/.test(value)) return value.slice(7) === '00'
29
+ if (/^#[0-9a-f]{4}$/.test(value)) return value[4] === '0'
30
+ return false
31
+ }
15
32
  export class WidgetNavbar extends LitElement {
16
33
  @property({ type: Object }) inputData?: InputData
17
34
  @property({ type: Object }) theme?: Theme
@@ -37,8 +54,9 @@ export class WidgetNavbar extends LitElement {
37
54
  registerTheme(theme?: Theme) {
38
55
  const cssTextColor = getComputedStyle(this).getPropertyValue('--re-text-color').trim()
39
56
  const cssBgColor = getComputedStyle(this).getPropertyValue('--re-tile-background-color').trim()
40
- this.themeBgColor = cssBgColor || this.theme?.theme_object?.backgroundColor
41
- this.themeTitleColor = cssTextColor || this.theme?.theme_object?.title?.textStyle?.color
57
+ const themeBgColor = theme?.theme_object?.backgroundColor
58
+ this.themeBgColor = cssBgColor || (isTransparent(themeBgColor) ? undefined : themeBgColor)
59
+ this.themeTitleColor = cssTextColor || theme?.theme_object?.title?.textStyle?.color
42
60
  }
43
61
 
44
62
  handleNavItemClick(route?: string) {
@@ -71,27 +89,83 @@ export class WidgetNavbar extends LitElement {
71
89
  .wrapper {
72
90
  display: flex;
73
91
  align-items: end;
92
+ gap: 8px;
74
93
  height: 100%;
75
94
  width: 100%;
76
95
  padding: 0 16px;
77
96
  box-sizing: border-box;
97
+ background-color: var(--nav-bg);
98
+ color: var(--nav-fg);
99
+ font-size: var(--nav-font-size);
100
+ font-weight: var(--nav-font-weight);
78
101
  }
79
102
 
80
- md-icon {
81
- font-family: 'Material Symbols Outlined';
103
+ /* One scrollable row. Without this the tabs wrap onto several lines and
104
+ spill outside the coloured bar as soon as they don't fit. */
105
+ .nav-list {
106
+ display: flex;
107
+ align-items: end;
108
+ flex: 1;
109
+ min-width: 0;
110
+ overflow-x: auto;
111
+ scrollbar-width: none;
82
112
  }
83
113
 
84
- .selected {
85
- font-weight: bold;
86
- background-color: rgba(0, 0, 0, 0.1);
114
+ .nav-list::-webkit-scrollbar {
115
+ display: none;
116
+ }
117
+
118
+ /* Material's tab tokens default to the M3 palette (purple indicator,
119
+ near-black labels), which ignores the widget's configured colours.
120
+ Map every colour token onto the nav colours. */
121
+ md-secondary-tab {
122
+ flex: none;
123
+ --md-secondary-tab-container-color: var(--nav-bg);
124
+ --md-secondary-tab-label-text-size: var(--nav-font-size);
125
+ --md-secondary-tab-label-text-weight: var(--nav-font-weight);
126
+ --md-secondary-tab-icon-size: var(--nav-icon-size);
127
+ --md-secondary-tab-label-text-color: var(--nav-fg);
128
+ --md-secondary-tab-hover-label-text-color: var(--nav-fg);
129
+ --md-secondary-tab-focus-label-text-color: var(--nav-fg);
130
+ --md-secondary-tab-pressed-label-text-color: var(--nav-fg);
131
+ --md-secondary-tab-active-label-text-color: var(--nav-fg);
132
+ --md-secondary-tab-active-hover-label-text-color: var(--nav-fg);
133
+ --md-secondary-tab-active-focus-label-text-color: var(--nav-fg);
134
+ --md-secondary-tab-active-pressed-label-text-color: var(--nav-fg);
135
+ --md-secondary-tab-icon-color: var(--nav-fg);
136
+ --md-secondary-tab-hover-icon-color: var(--nav-fg);
137
+ --md-secondary-tab-focus-icon-color: var(--nav-fg);
138
+ --md-secondary-tab-pressed-icon-color: var(--nav-fg);
139
+ --md-secondary-tab-active-icon-color: var(--nav-fg);
140
+ --md-secondary-tab-active-hover-icon-color: var(--nav-fg);
141
+ --md-secondary-tab-active-focus-icon-color: var(--nav-fg);
142
+ --md-secondary-tab-active-pressed-icon-color: var(--nav-fg);
143
+ --md-secondary-tab-active-indicator-color: var(--nav-fg);
144
+ --md-secondary-tab-hover-state-layer-color: var(--nav-fg);
145
+ --md-secondary-tab-pressed-state-layer-color: var(--nav-fg);
146
+ --md-secondary-tab-active-hover-state-layer-color: var(--nav-fg);
147
+ --md-secondary-tab-active-pressed-state-layer-color: var(--nav-fg);
148
+ }
149
+
150
+ md-icon {
151
+ font-family: 'Material Symbols Outlined';
152
+ font-size: var(--nav-icon-size);
153
+ width: var(--nav-icon-size);
154
+ height: var(--nav-icon-size);
155
+ color: var(--nav-fg);
87
156
  }
88
157
 
89
158
  h2 {
90
159
  margin: 0;
91
160
  padding: 0px;
161
+ flex: none;
162
+ display: flex;
163
+ align-items: center;
164
+ min-height: 48px;
92
165
  font-size: 1.2em;
93
- line-height: 2.5;
94
- height: 48px;
166
+ /* the UA stylesheet forces bold, which would ignore the
167
+ configured font weight */
168
+ font-weight: inherit;
95
169
  }
96
170
  `
97
171
 
@@ -137,15 +211,16 @@ export class WidgetNavbar extends LitElement {
137
211
 
138
212
  render() {
139
213
  const fontSize = this.inputData?.style?.fontSize ?? 16
140
- const iconFontSize = (this.inputData?.style?.fontSize ?? 16) * 1.5
214
+ const fontWeight = this.inputData?.style?.fontWeight ?? 400
215
+ const iconFontSize = fontSize * 1.5
141
216
  const fontColor = this.inputData?.style?.color || this.themeTitleColor || 'black'
142
217
  const bgColor = this.inputData?.style?.backgroundColor || this.themeBgColor || 'white'
143
218
  return html`
144
219
  <div
145
220
  class="wrapper"
146
- style="background-color: ${bgColor}; color: ${fontColor};
147
- font-weight: ${this.inputData?.style?.fontWeight};
148
- font-size: ${fontSize}px;"
221
+ style="--nav-bg: ${bgColor}; --nav-fg: ${fontColor};
222
+ --nav-font-size: ${fontSize}px; --nav-font-weight: ${fontWeight};
223
+ --nav-icon-size: ${iconFontSize}px;"
149
224
  >
150
225
  <h2
151
226
  class="paging"
@@ -161,33 +236,23 @@ export class WidgetNavbar extends LitElement {
161
236
  >
162
237
  ${this.inputData?.title}
163
238
  </h2>
164
- <md-tab class="xnav-list">
239
+ <div class="nav-list" role="tablist">
165
240
  ${repeat(
166
241
  this.inputData?.navItems || [],
167
242
  (item) => item.label,
168
243
  (item) => html`
169
244
  <md-secondary-tab
170
245
  ?active=${this.matchesRoute(this.resolveRoute(item))}
171
- style="font-size: ${fontSize}px;
172
- --md-secondary-tab-container-color: ${bgColor};
173
- color: ${fontColor};"
174
246
  @click=${() => this.handleNavItemClick(this.resolveRoute(item))}
175
247
  >
176
248
  ${item.iconName
177
- ? html`
178
- <md-icon
179
- slot="icon"
180
- style="font-size: ${iconFontSize}px;width: ${iconFontSize}px;color: ${fontColor}"
181
- >
182
- ${item.iconName}
183
- </md-icon>
184
- `
249
+ ? html`<md-icon slot="icon">${item.iconName}</md-icon>`
185
250
  : nothing}
186
251
  ${item.label}
187
252
  </md-secondary-tab>
188
253
  `
189
254
  )}
190
- </md-tab>
255
+ </div>
191
256
  </div>
192
257
  `
193
258
  }