@record-evolution/widget-navbutton 1.0.9 → 1.0.11

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,16 +1,22 @@
1
- import { css as c, LitElement as h, html as u } from "lit";
2
- import { property as p, state as m, customElement as d } from "lit/decorators.js";
1
+ import { css as d, LitElement as h, html as m } from "lit";
2
+ import { property as c, state as u, customElement as p } from "lit/decorators.js";
3
3
  import "@material/web/icon/icon.js";
4
4
  import "@material/web/button/filled-button.js";
5
- import "@material/web/ripple/ripple.js";
6
- var f = Object.defineProperty, b = Object.getOwnPropertyDescriptor, s = (t, e, o, r) => {
7
- for (var i = r > 1 ? void 0 : r ? b(e, o) : e, n = t.length - 1, a; n >= 0; n--)
8
- (a = t[n]) && (i = (r ? a(e, o, i) : a(i)) || i);
9
- return r && i && f(e, o, i), i;
5
+ var f = Object.defineProperty, b = Object.getOwnPropertyDescriptor, n = (t, e, o, r) => {
6
+ for (var l = r > 1 ? void 0 : r ? b(e, o) : e, s = t.length - 1, a; s >= 0; s--)
7
+ (a = t[s]) && (l = (r ? a(e, o, l) : a(l)) || l);
8
+ return r && l && f(e, o, l), l;
10
9
  };
11
- let l = class extends h {
10
+ const g = (t) => {
11
+ if (!t) return !0;
12
+ const e = t.trim().toLowerCase();
13
+ if (e === "transparent") return !0;
14
+ const o = e.match(/^(?:rgba|hsla)\([^)]*[,/]\s*([\d.]+%?)\s*\)$/);
15
+ return o ? parseFloat(o[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 i = class extends h {
12
18
  constructor() {
13
- super(...arguments), this.version = "1.0.9";
19
+ super(...arguments), this.version = "1.0.11";
14
20
  }
15
21
  update(t) {
16
22
  t.has("theme") && this.registerTheme(this.theme), super.update(t);
@@ -19,8 +25,8 @@ let l = class extends h {
19
25
  this.registerTheme(this.theme);
20
26
  }
21
27
  registerTheme(t) {
22
- const e = getComputedStyle(this).getPropertyValue("--re-text-color").trim(), o = getComputedStyle(this).getPropertyValue("--re-tile-background-color").trim();
23
- this.themeBgColor = o || 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(), o = getComputedStyle(this).getPropertyValue("--re-tile-background-color").trim(), r = t?.theme_object?.backgroundColor;
29
+ this.themeBgColor = o || (g(r) ? void 0 : r), this.themeTitleColor = e || t?.theme_object?.title?.textStyle?.color;
24
30
  }
25
31
  handleNavItemClick() {
26
32
  let t;
@@ -42,35 +48,42 @@ let l = class extends h {
42
48
  o.label && (e = e.split(`{{${o.label}}}`).join(encodeURIComponent(String(o.value ?? ""))));
43
49
  if (e.includes("*")) {
44
50
  const o = (this.route || "").split("/").filter(Boolean), r = e.split("/").filter(Boolean);
45
- for (let i = 0; i < r.length; i++)
46
- r[i] === "*" && (r[i] = o[i] ?? "");
51
+ for (let l = 0; l < r.length; l++)
52
+ r[l] === "*" && (r[l] = o[l] ?? "");
47
53
  e = (e.startsWith("/") ? "/" : "") + r.filter(Boolean).join("/");
48
54
  }
49
55
  return e;
50
56
  }
51
57
  render() {
52
- const t = this.inputData?.style?.fontSize ?? 16, e = (this.inputData?.style?.fontSize ?? 16) * 1.5, o = this.inputData?.style?.color || this.themeTitleColor || "black", r = this.inputData?.style?.backgroundColor || this.themeBgColor || "white";
53
- return u`
58
+ const t = this.inputData?.style?.fontSize ?? 16, e = t * 1.5, o = this.inputData?.style?.color || this.themeTitleColor || "black", r = this.inputData?.style?.backgroundColor || this.themeBgColor || "white", l = Math.max(40, Math.round(t * 2.5));
59
+ return m`
54
60
  <md-filled-button
55
- style="font-size: ${t}px;
56
- --md-filled-button-label-text-color: ${o};
61
+ style="--btn-fg: ${o};
62
+ font-size: ${t}px;
63
+ --md-filled-button-label-text-size: ${t}px;
64
+ --md-filled-button-container-height: ${l}px;
65
+ --md-filled-button-icon-size: ${e}px;
66
+ --md-filled-button-label-text-color: ${o};
57
67
  --md-filled-button-hover-label-text-color: ${o};
58
68
  --md-filled-button-pressed-label-text-color: ${o};
59
69
  --md-filled-button-focus-label-text-color: ${o};
70
+ --md-filled-button-icon-color: ${o};
71
+ --md-filled-button-hover-icon-color: ${o};
72
+ --md-filled-button-pressed-icon-color: ${o};
73
+ --md-filled-button-focus-icon-color: ${o};
60
74
  --md-filled-button-container-color: ${r};
61
75
  "
62
76
  @click=${() => this.handleNavItemClick()}
63
77
  >
64
78
  ${this.inputData?.title}
65
- <md-ripple></md-ripple>
66
- <md-icon slot="icon" style="font-size: ${e}px; color: ${o}"
79
+ <md-icon slot="icon" style="--md-icon-size: ${e}px;"
67
80
  >${this.inputData?.iconName}</md-icon
68
81
  >
69
82
  </md-filled-button>
70
83
  `;
71
84
  }
72
85
  };
73
- l.styles = c`
86
+ i.styles = d`
74
87
  :host {
75
88
  display: flex;
76
89
  align-items: center;
@@ -90,30 +103,33 @@ l.styles = c`
90
103
  flex: 1;
91
104
  --md-filled-button-container-shape: 4px;
92
105
  --md-filled-button-container-shadow-color: none;
93
- --md-sys-color-primary: #006a6a;
94
- --md-ripple-hover-color: var(--md-sys-color-primary);
95
- --md-ripple-pressed-color: var(--md-sys-color-primary);
106
+ /* State layers follow the configured label color; a hard-coded
107
+ accent stays teal no matter how the button is styled. */
108
+ --md-ripple-hover-color: var(--btn-fg);
109
+ --md-ripple-pressed-color: var(--btn-fg);
110
+ --md-filled-button-hover-state-layer-color: var(--btn-fg);
111
+ --md-filled-button-pressed-state-layer-color: var(--btn-fg);
96
112
  }
97
113
  `;
98
- s([
99
- p({ type: Object })
100
- ], l.prototype, "inputData", 2);
101
- s([
102
- p({ type: Object })
103
- ], l.prototype, "theme", 2);
104
- s([
105
- p({ type: String })
106
- ], l.prototype, "route", 2);
107
- s([
108
- m()
109
- ], l.prototype, "themeBgColor", 2);
110
- s([
111
- m()
112
- ], l.prototype, "themeTitleColor", 2);
113
- l = s([
114
- d("widget-navbutton-1.0.9")
115
- ], l);
114
+ n([
115
+ c({ type: Object })
116
+ ], i.prototype, "inputData", 2);
117
+ n([
118
+ c({ type: Object })
119
+ ], i.prototype, "theme", 2);
120
+ n([
121
+ c({ type: String })
122
+ ], i.prototype, "route", 2);
123
+ n([
124
+ u()
125
+ ], i.prototype, "themeBgColor", 2);
126
+ n([
127
+ u()
128
+ ], i.prototype, "themeTitleColor", 2);
129
+ i = n([
130
+ p("widget-navbutton-1.0.11")
131
+ ], i);
116
132
  export {
117
- l as WidgetNavbutton
133
+ i as WidgetNavbutton
118
134
  };
119
135
  //# sourceMappingURL=widget-navbutton.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"widget-navbutton.js","sources":["../src/widget-navbutton.ts"],"sourcesContent":["import { html, css, LitElement, PropertyValues } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { InputData } from './definition-schema'\n\nimport '@material/web/icon/icon.js'\nimport '@material/web/button/filled-button.js'\nimport '@material/web/ripple/ripple.js'\n\ntype Theme = {\n theme_name: string\n theme_object: any\n}\n\n@customElement('widget-navbutton-versionplaceholder')\nexport class WidgetNavbutton 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() {\n let goto: string\n if (this.inputData?.route === '') {\n goto = '/' + this.route?.split('/').filter(Boolean).slice(0, -1).join('/') + '/' || '/'\n goto = goto === '//' ? '/' : goto\n } else {\n goto =\n this.resolveRoute({\n route: this.inputData?.route,\n variables: this.inputData?.variables\n }) || '/'\n }\n const event = new CustomEvent('nav-submit', {\n detail: { path: goto },\n bubbles: true,\n composed: true\n })\n this.dispatchEvent(event)\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 static styles = css`\n :host {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n font-family: sans-serif;\n box-sizing: border-box;\n margin: auto;\n padding: 2cqh 2cqw;\n }\n\n md-icon {\n font-family: 'Material Symbols Outlined';\n }\n md-filled-button {\n flex: 1;\n --md-filled-button-container-shape: 4px;\n --md-filled-button-container-shadow-color: none;\n --md-sys-color-primary: #006a6a;\n --md-ripple-hover-color: var(--md-sys-color-primary);\n --md-ripple-pressed-color: var(--md-sys-color-primary);\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 const gap = fontSize * 0.4\n return html`\n <md-filled-button\n style=\"font-size: ${fontSize}px; \n --md-filled-button-label-text-color: ${fontColor}; \n --md-filled-button-hover-label-text-color: ${fontColor};\n --md-filled-button-pressed-label-text-color: ${fontColor};\n --md-filled-button-focus-label-text-color: ${fontColor};\n --md-filled-button-container-color: ${bgColor};\n \"\n @click=${() => this.handleNavItemClick()}\n >\n ${this.inputData?.title}\n <md-ripple></md-ripple>\n <md-icon slot=\"icon\" style=\"font-size: ${iconFontSize}px; color: ${fontColor}\"\n >${this.inputData?.iconName}</md-icon\n >\n </md-filled-button>\n `\n }\n}\n"],"names":["WidgetNavbutton","LitElement","changedProperties","_changedProperties","theme","cssTextColor","cssBgColor","goto","event","item","route","variable","currentSegments","routeSegments","fontSize","iconFontSize","fontColor","bgColor","html","css","__decorateClass","property","state","customElement"],"mappings":"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"}
1
+ {"version":3,"file":"widget-navbutton.js","sources":["../src/widget-navbutton.ts"],"sourcesContent":["import { html, css, LitElement, PropertyValues } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { NavigationButtonConfiguration } from './definition-schema'\n\nimport '@material/web/icon/icon.js'\nimport '@material/web/button/filled-button.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 button 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-navbutton-versionplaceholder')\nexport class WidgetNavbutton extends LitElement {\n @property({ type: Object }) inputData?: NavigationButtonConfiguration\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() {\n let goto: string\n if (this.inputData?.route === '') {\n goto = '/' + this.route?.split('/').filter(Boolean).slice(0, -1).join('/') + '/' || '/'\n goto = goto === '//' ? '/' : goto\n } else {\n goto =\n this.resolveRoute({\n route: this.inputData?.route,\n variables: this.inputData?.variables\n }) || '/'\n }\n const event = new CustomEvent('nav-submit', {\n detail: { path: goto },\n bubbles: true,\n composed: true\n })\n this.dispatchEvent(event)\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 static styles = css`\n :host {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n font-family: sans-serif;\n box-sizing: border-box;\n margin: auto;\n padding: 2cqh 2cqw;\n }\n\n md-icon {\n font-family: 'Material Symbols Outlined';\n }\n md-filled-button {\n flex: 1;\n --md-filled-button-container-shape: 4px;\n --md-filled-button-container-shadow-color: none;\n /* State layers follow the configured label color; a hard-coded\n accent stays teal no matter how the button is styled. */\n --md-ripple-hover-color: var(--btn-fg);\n --md-ripple-pressed-color: var(--btn-fg);\n --md-filled-button-hover-state-layer-color: var(--btn-fg);\n --md-filled-button-pressed-state-layer-color: var(--btn-fg);\n }\n `\n\n render() {\n const fontSize = this.inputData?.style?.fontSize ?? 16\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 // The container height is a fixed 40px token, so it has to grow with the\n // label or larger font sizes overflow the button.\n const buttonHeight = Math.max(40, Math.round(fontSize * 2.5))\n return html`\n <md-filled-button\n style=\"--btn-fg: ${fontColor};\n font-size: ${fontSize}px;\n --md-filled-button-label-text-size: ${fontSize}px;\n --md-filled-button-container-height: ${buttonHeight}px;\n --md-filled-button-icon-size: ${iconFontSize}px;\n --md-filled-button-label-text-color: ${fontColor};\n --md-filled-button-hover-label-text-color: ${fontColor};\n --md-filled-button-pressed-label-text-color: ${fontColor};\n --md-filled-button-focus-label-text-color: ${fontColor};\n --md-filled-button-icon-color: ${fontColor};\n --md-filled-button-hover-icon-color: ${fontColor};\n --md-filled-button-pressed-icon-color: ${fontColor};\n --md-filled-button-focus-icon-color: ${fontColor};\n --md-filled-button-container-color: ${bgColor};\n \"\n @click=${() => this.handleNavItemClick()}\n >\n ${this.inputData?.title}\n <md-icon slot=\"icon\" style=\"--md-icon-size: ${iconFontSize}px;\"\n >${this.inputData?.iconName}</md-icon\n >\n </md-filled-button>\n `\n }\n}\n"],"names":["isTransparent","color","value","functional","WidgetNavbutton","LitElement","changedProperties","_changedProperties","theme","cssTextColor","cssBgColor","themeBgColor","goto","event","item","route","variable","currentSegments","routeSegments","i","fontSize","iconFontSize","fontColor","bgColor","buttonHeight","html","css","__decorateClass","property","state","customElement"],"mappings":"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"}
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Webcomponent widget-navbutton following open-wc recommendations",
4
4
  "license": "MIT",
5
5
  "author": "widget-navbutton",
6
- "version": "1.0.9",
6
+ "version": "1.0.11",
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": {
@@ -3,7 +3,6 @@
3
3
  "iconName": "arrow_back",
4
4
  "route": "",
5
5
  "style": {
6
- "fontSize": 16,
7
- "fontWeight": 400
6
+ "fontSize": 16
8
7
  }
9
8
  }
@@ -41,7 +41,7 @@ export type FontSize = number;
41
41
  /**
42
42
  * A navigation button widget for in-dashboard navigation between pages or sections. Use this widget to create clickable buttons that navigate users to different dashboard views, external pages, or perform back navigation. Supports Material Design icons and customizable styling. Ideal for creating navigation flows, back buttons, call-to-action links, or any clickable element that should route users to another location.
43
43
  */
44
- export interface InputData {
44
+ export interface NavigationButtonConfiguration {
45
45
  title?: Label;
46
46
  iconName?: IconName;
47
47
  route?: Navigation;
@@ -1,6 +1,19 @@
1
1
  {
2
- "title": "Input Data",
2
+ "title": "Navigation Button Configuration",
3
3
  "description": "A navigation button widget for in-dashboard navigation between pages or sections. Use this widget to create clickable buttons that navigate users to different dashboard views, external pages, or perform back navigation. Supports Material Design icons and customizable styling. Ideal for creating navigation flows, back buttons, call-to-action links, or any clickable element that should route users to another location.",
4
+ "aiSelection": {
5
+ "dataShape": "A single destination: a label, an icon and a route, plus optional route variables. No data input.",
6
+ "useWhen": [
7
+ "One clickable element should take the user somewhere — a detail page, an external site, or back.",
8
+ "A call to action belongs next to specific content rather than in a navigation menu."
9
+ ],
10
+ "notFor": [
11
+ "Several destinations that belong together as a menu — use widget-navbar or widget-sidenav.",
12
+ "A button that writes or submits data — use widget-form.",
13
+ "A button that commands a device — use widget-switch, or widget-scada for an industrial symbol.",
14
+ "Per-row links inside a list of records — use widget-table with a column of type 'button'."
15
+ ]
16
+ },
4
17
  "type": "object",
5
18
  "properties": {
6
19
  "title": {
@@ -1,19 +1,37 @@
1
1
  import { html, css, LitElement, PropertyValues } from 'lit'
2
2
  import { customElement, property, state } from 'lit/decorators.js'
3
- import { InputData } from './definition-schema'
3
+ import { NavigationButtonConfiguration } from './definition-schema'
4
4
 
5
5
  import '@material/web/icon/icon.js'
6
6
  import '@material/web/button/filled-button.js'
7
- import '@material/web/ripple/ripple.js'
8
7
 
9
8
  type Theme = {
10
9
  theme_name: string
11
10
  theme_object: any
12
11
  }
13
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 button 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
+
14
32
  @customElement('widget-navbutton-versionplaceholder')
15
33
  export class WidgetNavbutton extends LitElement {
16
- @property({ type: Object }) inputData?: InputData
34
+ @property({ type: Object }) inputData?: NavigationButtonConfiguration
17
35
  @property({ type: Object }) theme?: Theme
18
36
  @property({ type: String }) route?: string
19
37
 
@@ -37,8 +55,9 @@ export class WidgetNavbutton extends LitElement {
37
55
  registerTheme(theme?: Theme) {
38
56
  const cssTextColor = getComputedStyle(this).getPropertyValue('--re-text-color').trim()
39
57
  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
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
42
61
  }
43
62
 
44
63
  handleNavItemClick() {
@@ -105,32 +124,44 @@ export class WidgetNavbutton extends LitElement {
105
124
  flex: 1;
106
125
  --md-filled-button-container-shape: 4px;
107
126
  --md-filled-button-container-shadow-color: none;
108
- --md-sys-color-primary: #006a6a;
109
- --md-ripple-hover-color: var(--md-sys-color-primary);
110
- --md-ripple-pressed-color: var(--md-sys-color-primary);
127
+ /* State layers follow the configured label color; a hard-coded
128
+ accent stays teal no matter how the button is styled. */
129
+ --md-ripple-hover-color: var(--btn-fg);
130
+ --md-ripple-pressed-color: var(--btn-fg);
131
+ --md-filled-button-hover-state-layer-color: var(--btn-fg);
132
+ --md-filled-button-pressed-state-layer-color: var(--btn-fg);
111
133
  }
112
134
  `
113
135
 
114
136
  render() {
115
137
  const fontSize = this.inputData?.style?.fontSize ?? 16
116
- const iconFontSize = (this.inputData?.style?.fontSize ?? 16) * 1.5
138
+ const iconFontSize = fontSize * 1.5
117
139
  const fontColor = this.inputData?.style?.color || this.themeTitleColor || 'black'
118
140
  const bgColor = this.inputData?.style?.backgroundColor || this.themeBgColor || 'white'
119
- const gap = fontSize * 0.4
141
+ // The container height is a fixed 40px token, so it has to grow with the
142
+ // label or larger font sizes overflow the button.
143
+ const buttonHeight = Math.max(40, Math.round(fontSize * 2.5))
120
144
  return html`
121
145
  <md-filled-button
122
- style="font-size: ${fontSize}px;
123
- --md-filled-button-label-text-color: ${fontColor};
146
+ style="--btn-fg: ${fontColor};
147
+ font-size: ${fontSize}px;
148
+ --md-filled-button-label-text-size: ${fontSize}px;
149
+ --md-filled-button-container-height: ${buttonHeight}px;
150
+ --md-filled-button-icon-size: ${iconFontSize}px;
151
+ --md-filled-button-label-text-color: ${fontColor};
124
152
  --md-filled-button-hover-label-text-color: ${fontColor};
125
153
  --md-filled-button-pressed-label-text-color: ${fontColor};
126
154
  --md-filled-button-focus-label-text-color: ${fontColor};
155
+ --md-filled-button-icon-color: ${fontColor};
156
+ --md-filled-button-hover-icon-color: ${fontColor};
157
+ --md-filled-button-pressed-icon-color: ${fontColor};
158
+ --md-filled-button-focus-icon-color: ${fontColor};
127
159
  --md-filled-button-container-color: ${bgColor};
128
160
  "
129
161
  @click=${() => this.handleNavItemClick()}
130
162
  >
131
163
  ${this.inputData?.title}
132
- <md-ripple></md-ripple>
133
- <md-icon slot="icon" style="font-size: ${iconFontSize}px; color: ${fontColor}"
164
+ <md-icon slot="icon" style="--md-icon-size: ${iconFontSize}px;"
134
165
  >${this.inputData?.iconName}</md-icon
135
166
  >
136
167
  </md-filled-button>