@record-evolution/widget-sidenav 1.0.15 → 1.0.17

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,15 +1,22 @@
1
- import { css as u, LitElement as d, html as p } from "lit";
2
- import { property as h, state as c, customElement as m } from "lit/decorators.js";
3
- import { repeat as g } from "lit/directives/repeat.js";
1
+ import { css as u, LitElement as d, html as c } from "lit";
2
+ import { property as h, state as p, customElement as g } from "lit/decorators.js";
3
+ import { repeat as m } from "lit/directives/repeat.js";
4
4
  import "@material/web/icon/icon.js";
5
- var f = Object.defineProperty, v = Object.getOwnPropertyDescriptor, n = (t, e, i, o) => {
6
- for (var r = o > 1 ? void 0 : o ? v(e, i) : e, l = t.length - 1, a; l >= 0; l--)
7
- (a = t[l]) && (r = (o ? a(e, i, r) : a(r)) || r);
8
- return o && r && f(e, i, r), r;
5
+ var b = Object.defineProperty, f = Object.getOwnPropertyDescriptor, l = (t, e, r, i) => {
6
+ for (var o = i > 1 ? void 0 : i ? f(e, r) : e, a = t.length - 1, s; a >= 0; a--)
7
+ (s = t[a]) && (o = (i ? s(e, r, o) : s(o)) || o);
8
+ return i && o && b(e, r, o), o;
9
9
  };
10
- let s = class extends d {
10
+ const v = (t) => {
11
+ if (!t) return !0;
12
+ const e = t.trim().toLowerCase();
13
+ if (e === "transparent") return !0;
14
+ const r = e.match(/^(?:rgba|hsla)\([^)]*[,/]\s*([\d.]+%?)\s*\)$/);
15
+ return r ? parseFloat(r[1]) === 0 : /^#[0-9a-f]{8}$/.test(e) ? e.slice(7) === "00" : /^#[0-9a-f]{4}$/.test(e) ? e[4] === "0" : !1;
16
+ };
17
+ let n = class extends d {
11
18
  constructor() {
12
- super(...arguments), this.version = "1.0.15";
19
+ super(...arguments), this.version = "1.0.17";
13
20
  }
14
21
  update(t) {
15
22
  t.has("theme") && this.registerTheme(this.theme), super.update(t);
@@ -18,8 +25,8 @@ let s = class extends d {
18
25
  this.registerTheme(this.theme);
19
26
  }
20
27
  registerTheme(t) {
21
- const e = getComputedStyle(this).getPropertyValue("--re-text-color").trim(), i = getComputedStyle(this).getPropertyValue("--re-tile-background-color").trim();
22
- 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(), r = getComputedStyle(this).getPropertyValue("--re-tile-background-color").trim(), i = t?.theme_object?.backgroundColor;
29
+ this.themeBgColor = r || (v(i) ? void 0 : i), this.themeTitleColor = e || t?.theme_object?.title?.textStyle?.color;
23
30
  }
24
31
  handleNavItemClick(t) {
25
32
  const e = new CustomEvent("nav-submit", {
@@ -35,29 +42,29 @@ let s = class extends d {
35
42
  resolveRoute(t) {
36
43
  let e = String(t?.route ?? "");
37
44
  if (t?.variables)
38
- for (const i of t.variables)
39
- i.label && (e = e.split(`{{${i.label}}}`).join(encodeURIComponent(String(i.value ?? ""))));
45
+ for (const r of t.variables)
46
+ r.label && (e = e.split(`{{${r.label}}}`).join(encodeURIComponent(String(r.value ?? ""))));
40
47
  if (e.includes("*")) {
41
- const i = (this.route || "").split("/").filter(Boolean), o = e.split("/").filter(Boolean);
42
- for (let r = 0; r < o.length; r++)
43
- o[r] === "*" && (o[r] = i[r] ?? "");
44
- e = (e.startsWith("/") ? "/" : "") + o.filter(Boolean).join("/");
48
+ const r = (this.route || "").split("/").filter(Boolean), i = e.split("/").filter(Boolean);
49
+ for (let o = 0; o < i.length; o++)
50
+ i[o] === "*" && (i[o] = r[o] ?? "");
51
+ e = (e.startsWith("/") ? "/" : "") + i.filter(Boolean).join("/");
45
52
  }
46
53
  return e;
47
54
  }
48
55
  matchesRoute(t) {
49
56
  if (t === void 0) return !1;
50
57
  t = String(t);
51
- const e = this.trimRoute(decodeURIComponent(this.route || "/")), i = this.trimRoute(t);
52
- return t.startsWith("/") ? e.startsWith(i) : e.endsWith(i) || e === i;
58
+ const e = this.trimRoute(decodeURIComponent(this.route || "/")), r = this.trimRoute(t);
59
+ return t.startsWith("/") ? e.startsWith(r) : e.endsWith(r) || e === r;
53
60
  }
54
61
  render() {
55
- const t = this.inputData?.style?.fontSize ?? 16, e = (this.inputData?.style?.fontSize ?? 16) * 1.5, i = t * 0.4;
56
- return p`
62
+ const t = this.inputData?.style?.fontSize ?? 16, e = this.inputData?.style?.fontWeight ?? 400, r = t * 1.5, i = this.inputData?.style?.color || this.themeTitleColor || "black", o = this.inputData?.style?.backgroundColor || this.themeBgColor || "white", a = t * 0.4;
63
+ return c`
57
64
  <div
58
65
  class="wrapper"
59
- style="background-color: ${this.inputData?.style?.backgroundColor || this.themeBgColor}; color: ${this.inputData?.style?.color || this.themeTitleColor};
60
- font-weight: ${this.inputData?.style?.fontWeight};
66
+ style="background-color: ${o}; color: ${i};
67
+ font-weight: ${e};
61
68
  font-size: ${t}px;"
62
69
  >
63
70
  <h2
@@ -74,22 +81,21 @@ let s = class extends d {
74
81
  ${this.inputData?.title}
75
82
  </h2>
76
83
  <div class="nav-list">
77
- ${g(
84
+ ${m(
78
85
  this.inputData?.navItems || [],
79
- (o) => o.label,
80
- (o) => p`
86
+ (s) => s.label,
87
+ (s) => c`
81
88
  <div
82
- class="nav-item ${this.matchesRoute(this.resolveRoute(o)) ? "selected" : ""}"
83
- style="gap: ${i}px;"
84
- @click=${() => this.handleNavItemClick(this.resolveRoute(o))}
89
+ class="nav-item ${this.matchesRoute(this.resolveRoute(s)) ? "selected" : ""}"
90
+ style="gap: ${a}px;"
91
+ @click=${() => this.handleNavItemClick(this.resolveRoute(s))}
85
92
  >
86
- ${o.iconName ? p`
87
- <md-icon
88
- style="font-size: ${e}px;width: ${e}px;"
89
- >${o.iconName}
93
+ ${s.iconName ? c`
94
+ <md-icon style="--md-icon-size: ${r}px;"
95
+ >${s.iconName}
90
96
  </md-icon>
91
97
  ` : ""}
92
- ${o.label}
98
+ ${s.label}
93
99
  </div>
94
100
  `
95
101
  )}
@@ -98,7 +104,7 @@ let s = class extends d {
98
104
  `;
99
105
  }
100
106
  };
101
- s.styles = u`
107
+ n.styles = u`
102
108
  :host {
103
109
  display: block;
104
110
  font-family: sans-serif;
@@ -126,6 +132,29 @@ s.styles = u`
126
132
  margin-top: 12px;
127
133
  overflow-y: auto;
128
134
  flex-grow: 1;
135
+ /* Derive scrollbar colors from the (inherited) text color so they
136
+ follow custom styles and themes — e.g. light thumb on dark nav. */
137
+ scrollbar-width: thin;
138
+ scrollbar-color: color-mix(in srgb, currentColor 35%, transparent) transparent;
139
+ }
140
+
141
+ /* WebKit/Blink fallback for browsers without scrollbar-color support. */
142
+ .nav-list::-webkit-scrollbar {
143
+ width: 8px;
144
+ height: 8px;
145
+ }
146
+
147
+ .nav-list::-webkit-scrollbar-track {
148
+ background: transparent;
149
+ }
150
+
151
+ .nav-list::-webkit-scrollbar-thumb {
152
+ background-color: color-mix(in srgb, currentColor 35%, transparent);
153
+ border-radius: 4px;
154
+ }
155
+
156
+ .nav-list::-webkit-scrollbar-thumb:hover {
157
+ background-color: color-mix(in srgb, currentColor 55%, transparent);
129
158
  }
130
159
 
131
160
  .nav-item {
@@ -141,35 +170,40 @@ s.styles = u`
141
170
  font-family: 'Material Symbols Outlined';
142
171
  }
143
172
 
173
+ /* Derive the highlight from the (inherited) text color, like the
174
+ scrollbar above — a fixed black wash is invisible on a dark nav. */
144
175
  .selected {
145
- background-color: rgba(0, 0, 0, 0.1);
176
+ background-color: color-mix(in srgb, currentColor 15%, transparent);
146
177
  }
147
178
 
148
179
  h2 {
149
180
  margin: 0;
150
181
  padding: 0px;
151
182
  font-size: 1.2em;
183
+ /* the UA stylesheet forces bold, which would ignore the
184
+ configured font weight */
185
+ font-weight: inherit;
152
186
  }
153
187
  `;
154
- n([
188
+ l([
155
189
  h({ type: Object })
156
- ], s.prototype, "inputData", 2);
157
- n([
190
+ ], n.prototype, "inputData", 2);
191
+ l([
158
192
  h({ type: Object })
159
- ], s.prototype, "theme", 2);
160
- n([
193
+ ], n.prototype, "theme", 2);
194
+ l([
161
195
  h({ type: String })
162
- ], s.prototype, "route", 2);
163
- n([
164
- c()
165
- ], s.prototype, "themeBgColor", 2);
166
- n([
167
- c()
168
- ], s.prototype, "themeTitleColor", 2);
169
- s = n([
170
- m("widget-sidenav-1.0.15")
171
- ], s);
196
+ ], n.prototype, "route", 2);
197
+ l([
198
+ p()
199
+ ], n.prototype, "themeBgColor", 2);
200
+ l([
201
+ p()
202
+ ], n.prototype, "themeTitleColor", 2);
203
+ n = l([
204
+ g("widget-sidenav-1.0.17")
205
+ ], n);
172
206
  export {
173
- s as WidgetSidenav
207
+ n as WidgetSidenav
174
208
  };
175
209
  //# sourceMappingURL=widget-sidenav.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"widget-sidenav.js","sources":["../src/widget-sidenav.ts"],"sourcesContent":["import { html, css, LitElement, PropertyValues } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { repeat } from 'lit/directives/repeat.js'\nimport { InputData } from './definition-schema'\n\nimport '@material/web/icon/icon.js'\n\ntype Theme = {\n theme_name: string\n theme_object: any\n}\n@customElement('widget-sidenav-versionplaceholder')\nexport class WidgetSidenav 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: String(route) },\n bubbles: true,\n composed: true\n })\n this.dispatchEvent(event)\n }\n\n trimRoute(route?: string) {\n route = String(route)\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 itemRoute = String(itemRoute)\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 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 flex-direction: column;\n height: 100%;\n width: 100%;\n padding: 12px;\n box-sizing: border-box;\n }\n\n .nav-list {\n display: flex;\n flex-direction: column;\n gap: 2px;\n margin-top: 12px;\n overflow-y: auto;\n flex-grow: 1;\n }\n\n .nav-item {\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px;\n border-radius: 4px;\n }\n\n md-icon {\n font-family: 'Material Symbols Outlined';\n }\n\n .selected {\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 }\n `\n\n render() {\n const fontSize = this.inputData?.style?.fontSize ?? 16\n const iconFontSize = (this.inputData?.style?.fontSize ?? 16) * 1.5\n const gap = fontSize * 0.4\n return html`\n <div\n class=\"wrapper\"\n style=\"background-color: ${this.inputData?.style?.backgroundColor ||\n this.themeBgColor}; color: ${this.inputData?.style?.color || this.themeTitleColor};\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 <div class=\"nav-list\">\n ${repeat(\n this.inputData?.navItems || [],\n (item) => item.label,\n (item) => html`\n <div\n class=\"nav-item ${this.matchesRoute(this.resolveRoute(item))\n ? 'selected'\n : ''}\"\n style=\"gap: ${gap}px;\"\n @click=${() => this.handleNavItemClick(this.resolveRoute(item))}\n >\n ${item.iconName\n ? html`\n <md-icon\n style=\"font-size: ${iconFontSize}px;width: ${iconFontSize}px;\"\n >${item.iconName}\n </md-icon>\n `\n : ''}\n ${item.label}\n </div>\n `\n )}\n </div>\n </div>\n `\n }\n}\n"],"names":["WidgetSidenav","LitElement","changedProperties","_changedProperties","theme","cssTextColor","cssBgColor","route","event","item","variable","currentSegments","routeSegments","i","itemRoute","subRoute","fontSize","iconFontSize","gap","html","repeat","css","__decorateClass","property","state","customElement"],"mappings":"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"}
1
+ {"version":3,"file":"widget-sidenav.js","sources":["../src/widget-sidenav.ts"],"sourcesContent":["import { html, css, LitElement, PropertyValues } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { repeat } from 'lit/directives/repeat.js'\nimport { InputData } from './definition-schema'\n\nimport '@material/web/icon/icon.js'\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 nav 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}\n\n@customElement('widget-sidenav-versionplaceholder')\nexport class WidgetSidenav 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: String(route) },\n bubbles: true,\n composed: true\n })\n this.dispatchEvent(event)\n }\n\n trimRoute(route?: string) {\n route = String(route)\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 itemRoute = String(itemRoute)\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 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 flex-direction: column;\n height: 100%;\n width: 100%;\n padding: 12px;\n box-sizing: border-box;\n }\n\n .nav-list {\n display: flex;\n flex-direction: column;\n gap: 2px;\n margin-top: 12px;\n overflow-y: auto;\n flex-grow: 1;\n /* Derive scrollbar colors from the (inherited) text color so they\n follow custom styles and themes — e.g. light thumb on dark nav. */\n scrollbar-width: thin;\n scrollbar-color: color-mix(in srgb, currentColor 35%, transparent) transparent;\n }\n\n /* WebKit/Blink fallback for browsers without scrollbar-color support. */\n .nav-list::-webkit-scrollbar {\n width: 8px;\n height: 8px;\n }\n\n .nav-list::-webkit-scrollbar-track {\n background: transparent;\n }\n\n .nav-list::-webkit-scrollbar-thumb {\n background-color: color-mix(in srgb, currentColor 35%, transparent);\n border-radius: 4px;\n }\n\n .nav-list::-webkit-scrollbar-thumb:hover {\n background-color: color-mix(in srgb, currentColor 55%, transparent);\n }\n\n .nav-item {\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px;\n border-radius: 4px;\n }\n\n md-icon {\n font-family: 'Material Symbols Outlined';\n }\n\n /* Derive the highlight from the (inherited) text color, like the\n scrollbar above — a fixed black wash is invisible on a dark nav. */\n .selected {\n background-color: color-mix(in srgb, currentColor 15%, transparent);\n }\n\n h2 {\n margin: 0;\n padding: 0px;\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 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 const gap = fontSize * 0.4\n return html`\n <div\n class=\"wrapper\"\n style=\"background-color: ${bgColor}; color: ${fontColor};\n font-weight: ${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 <div class=\"nav-list\">\n ${repeat(\n this.inputData?.navItems || [],\n (item) => item.label,\n (item) => html`\n <div\n class=\"nav-item ${this.matchesRoute(this.resolveRoute(item))\n ? 'selected'\n : ''}\"\n style=\"gap: ${gap}px;\"\n @click=${() => this.handleNavItemClick(this.resolveRoute(item))}\n >\n ${item.iconName\n ? html`\n <md-icon style=\"--md-icon-size: ${iconFontSize}px;\"\n >${item.iconName}\n </md-icon>\n `\n : ''}\n ${item.label}\n </div>\n `\n )}\n </div>\n </div>\n `\n }\n}\n"],"names":["isTransparent","color","value","functional","WidgetSidenav","LitElement","changedProperties","_changedProperties","theme","cssTextColor","cssBgColor","themeBgColor","route","event","item","variable","currentSegments","routeSegments","i","itemRoute","subRoute","fontSize","fontWeight","iconFontSize","fontColor","bgColor","gap","html","repeat","css","__decorateClass","property","state","customElement"],"mappings":"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"}
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Webcomponent widget-sidenav following open-wc recommendations",
4
4
  "license": "MIT",
5
5
  "author": "widget-sidenav",
6
- "version": "1.0.15",
6
+ "version": "1.0.17",
7
7
  "engines": {
8
8
  "node": ">=24.9.0",
9
9
  "npm": ">=10.0.2"
@@ -28,7 +28,7 @@
28
28
  "release": "npm run build && npm run types && npm version patch --tag-version-prefix='' && git push && git push --tag && npm run build"
29
29
  },
30
30
  "dependencies": {
31
- "lit": "^3.3.2",
31
+ "lit": "^3.3.3",
32
32
  "tslib": "^2.8.1"
33
33
  },
34
34
  "peerDependencies": {
@@ -9,6 +9,26 @@ type Theme = {
9
9
  theme_name: string
10
10
  theme_object: any
11
11
  }
12
+
13
+ /**
14
+ * ECharts themes describe a *chart canvas*, and most of them set
15
+ * `backgroundColor` to a fully transparent colour (the light theme uses
16
+ * `rgba(0, 0, 0, 0)`). That is a valid, truthy colour string, so using it
17
+ * verbatim as the nav background paints nothing at all. Treat any
18
+ * fully transparent theme colour as "no colour" so the fallback kicks in.
19
+ */
20
+ const isTransparent = (color?: string) => {
21
+ if (!color) return true
22
+ const value = color.trim().toLowerCase()
23
+ if (value === 'transparent') return true
24
+ const functional = value.match(/^(?:rgba|hsla)\([^)]*[,/]\s*([\d.]+%?)\s*\)$/)
25
+ if (functional) return parseFloat(functional[1]) === 0
26
+ // #rrggbbaa / #rgba
27
+ if (/^#[0-9a-f]{8}$/.test(value)) return value.slice(7) === '00'
28
+ if (/^#[0-9a-f]{4}$/.test(value)) return value[4] === '0'
29
+ return false
30
+ }
31
+
12
32
  @customElement('widget-sidenav-versionplaceholder')
13
33
  export class WidgetSidenav extends LitElement {
14
34
  @property({ type: Object }) inputData?: InputData
@@ -35,8 +55,9 @@ export class WidgetSidenav extends LitElement {
35
55
  registerTheme(theme?: Theme) {
36
56
  const cssTextColor = getComputedStyle(this).getPropertyValue('--re-text-color').trim()
37
57
  const cssBgColor = getComputedStyle(this).getPropertyValue('--re-tile-background-color').trim()
38
- this.themeBgColor = cssBgColor || this.theme?.theme_object?.backgroundColor
39
- this.themeTitleColor = cssTextColor || this.theme?.theme_object?.title?.textStyle?.color
58
+ const themeBgColor = theme?.theme_object?.backgroundColor
59
+ this.themeBgColor = cssBgColor || (isTransparent(themeBgColor) ? undefined : themeBgColor)
60
+ this.themeTitleColor = cssTextColor || theme?.theme_object?.title?.textStyle?.color
40
61
  }
41
62
 
42
63
  handleNavItemClick(route?: string) {
@@ -119,6 +140,29 @@ export class WidgetSidenav extends LitElement {
119
140
  margin-top: 12px;
120
141
  overflow-y: auto;
121
142
  flex-grow: 1;
143
+ /* Derive scrollbar colors from the (inherited) text color so they
144
+ follow custom styles and themes — e.g. light thumb on dark nav. */
145
+ scrollbar-width: thin;
146
+ scrollbar-color: color-mix(in srgb, currentColor 35%, transparent) transparent;
147
+ }
148
+
149
+ /* WebKit/Blink fallback for browsers without scrollbar-color support. */
150
+ .nav-list::-webkit-scrollbar {
151
+ width: 8px;
152
+ height: 8px;
153
+ }
154
+
155
+ .nav-list::-webkit-scrollbar-track {
156
+ background: transparent;
157
+ }
158
+
159
+ .nav-list::-webkit-scrollbar-thumb {
160
+ background-color: color-mix(in srgb, currentColor 35%, transparent);
161
+ border-radius: 4px;
162
+ }
163
+
164
+ .nav-list::-webkit-scrollbar-thumb:hover {
165
+ background-color: color-mix(in srgb, currentColor 55%, transparent);
122
166
  }
123
167
 
124
168
  .nav-item {
@@ -134,27 +178,34 @@ export class WidgetSidenav extends LitElement {
134
178
  font-family: 'Material Symbols Outlined';
135
179
  }
136
180
 
181
+ /* Derive the highlight from the (inherited) text color, like the
182
+ scrollbar above — a fixed black wash is invisible on a dark nav. */
137
183
  .selected {
138
- background-color: rgba(0, 0, 0, 0.1);
184
+ background-color: color-mix(in srgb, currentColor 15%, transparent);
139
185
  }
140
186
 
141
187
  h2 {
142
188
  margin: 0;
143
189
  padding: 0px;
144
190
  font-size: 1.2em;
191
+ /* the UA stylesheet forces bold, which would ignore the
192
+ configured font weight */
193
+ font-weight: inherit;
145
194
  }
146
195
  `
147
196
 
148
197
  render() {
149
198
  const fontSize = this.inputData?.style?.fontSize ?? 16
150
- const iconFontSize = (this.inputData?.style?.fontSize ?? 16) * 1.5
199
+ const fontWeight = this.inputData?.style?.fontWeight ?? 400
200
+ const iconFontSize = fontSize * 1.5
201
+ const fontColor = this.inputData?.style?.color || this.themeTitleColor || 'black'
202
+ const bgColor = this.inputData?.style?.backgroundColor || this.themeBgColor || 'white'
151
203
  const gap = fontSize * 0.4
152
204
  return html`
153
205
  <div
154
206
  class="wrapper"
155
- style="background-color: ${this.inputData?.style?.backgroundColor ||
156
- this.themeBgColor}; color: ${this.inputData?.style?.color || this.themeTitleColor};
157
- font-weight: ${this.inputData?.style?.fontWeight};
207
+ style="background-color: ${bgColor}; color: ${fontColor};
208
+ font-weight: ${fontWeight};
158
209
  font-size: ${fontSize}px;"
159
210
  >
160
211
  <h2
@@ -185,8 +236,7 @@ export class WidgetSidenav extends LitElement {
185
236
  >
186
237
  ${item.iconName
187
238
  ? html`
188
- <md-icon
189
- style="font-size: ${iconFontSize}px;width: ${iconFontSize}px;"
239
+ <md-icon style="--md-icon-size: ${iconFontSize}px;"
190
240
  >${item.iconName}
191
241
  </md-icon>
192
242
  `