@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.
- package/dist/widget-navbar.js +121 -71
- package/dist/widget-navbar.js.map +1 -1
- package/package.json +2 -2
- package/src/definition-schema.json +1 -1
- package/src/widget-navbar.ts +93 -28
package/dist/widget-navbar.js
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
|
-
import { LitElement as
|
|
2
|
-
import { property as
|
|
3
|
-
import { repeat as
|
|
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,
|
|
9
|
-
for (var
|
|
10
|
-
(
|
|
11
|
-
return
|
|
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
|
|
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.
|
|
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(),
|
|
25
|
-
this.themeBgColor =
|
|
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
|
|
45
|
-
|
|
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
|
|
48
|
-
for (let
|
|
49
|
-
r
|
|
50
|
-
e = (e.startsWith("/") ? "/" : "") +
|
|
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 || "/")),
|
|
57
|
-
return t.startsWith("/") ? e.startsWith(
|
|
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 =
|
|
61
|
-
return
|
|
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="
|
|
65
|
-
font-weight: ${
|
|
66
|
-
|
|
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
|
-
<
|
|
82
|
-
${
|
|
85
|
+
<div class="nav-list" role="tablist">
|
|
86
|
+
${m(
|
|
83
87
|
this.inputData?.navItems || [],
|
|
84
|
-
(
|
|
85
|
-
(
|
|
88
|
+
(n) => n.label,
|
|
89
|
+
(n) => c`
|
|
86
90
|
<md-secondary-tab
|
|
87
|
-
?active=${this.matchesRoute(this.resolveRoute(
|
|
88
|
-
|
|
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
|
-
${
|
|
94
|
-
|
|
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
|
-
</
|
|
99
|
+
</div>
|
|
106
100
|
</div>
|
|
107
101
|
`;
|
|
108
102
|
}
|
|
109
103
|
};
|
|
110
|
-
|
|
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
|
-
|
|
132
|
-
|
|
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
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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
|
-
|
|
145
|
-
|
|
193
|
+
/* the UA stylesheet forces bold, which would ignore the
|
|
194
|
+
configured font weight */
|
|
195
|
+
font-weight: inherit;
|
|
146
196
|
}
|
|
147
197
|
`;
|
|
148
|
-
let
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
],
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
],
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
],
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
],
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
],
|
|
164
|
-
window.customElements.define("widget-navbar-1.0.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
32
|
+
"lit": "^3.3.3",
|
|
33
33
|
"tslib": "^2.8.1"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
package/src/widget-navbar.ts
CHANGED
|
@@ -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
|
-
|
|
41
|
-
this.
|
|
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
|
-
|
|
81
|
-
|
|
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
|
-
.
|
|
85
|
-
|
|
86
|
-
|
|
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
|
-
|
|
94
|
-
|
|
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
|
|
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="
|
|
147
|
-
font-weight: ${
|
|
148
|
-
|
|
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
|
-
<
|
|
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
|
-
</
|
|
255
|
+
</div>
|
|
191
256
|
</div>
|
|
192
257
|
`
|
|
193
258
|
}
|