myio-js-library 0.1.516 → 0.1.518
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/index.cjs +312 -35
- package/dist/index.d.cts +54 -0
- package/dist/index.js +312 -35
- package/dist/myio-js-library.umd.js +312 -35
- package/dist/myio-js-library.umd.min.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1208,7 +1208,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
1208
1208
|
// package.json
|
|
1209
1209
|
var package_default = {
|
|
1210
1210
|
name: "myio-js-library",
|
|
1211
|
-
version: "0.1.
|
|
1211
|
+
version: "0.1.518",
|
|
1212
1212
|
description: "A clean, standalone JS SDK for MYIO projects",
|
|
1213
1213
|
license: "MIT",
|
|
1214
1214
|
repository: "github:gh-myio/myio-js-library",
|
|
@@ -20627,6 +20627,35 @@ var PANEL_CSS2 = `
|
|
|
20627
20627
|
background: #ffffff;
|
|
20628
20628
|
color: #2F5848;
|
|
20629
20629
|
}
|
|
20630
|
+
|
|
20631
|
+
/* \u2500\u2500 Accordion (opt-in via options.collapsible) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
20632
|
+
The header (.myio-hp, from HeaderPanelComponent) becomes clickable and an
|
|
20633
|
+
arrow is shown before its title. Collapsed hides the body (.myio-cgp__grid)
|
|
20634
|
+
and lets the panel shrink to header height. Arrow uses CSS escapes
|
|
20635
|
+
(ASCII only) to stay safe across strict CSS parsers (e.g. ThingsBoard). */
|
|
20636
|
+
.myio-cgp--collapsible > .myio-hp {
|
|
20637
|
+
cursor: pointer;
|
|
20638
|
+
user-select: none;
|
|
20639
|
+
}
|
|
20640
|
+
.myio-cgp--collapsible > .myio-hp .myio-hp__title::before {
|
|
20641
|
+
content: "\\25BE";
|
|
20642
|
+
display: inline-block;
|
|
20643
|
+
margin-right: 6px;
|
|
20644
|
+
font-size: 0.7em;
|
|
20645
|
+
opacity: 0.65;
|
|
20646
|
+
}
|
|
20647
|
+
.myio-cgp--collapsed > .myio-hp .myio-hp__title::before {
|
|
20648
|
+
content: "\\25B8";
|
|
20649
|
+
}
|
|
20650
|
+
.myio-cgp--collapsed > .myio-cgp__grid,
|
|
20651
|
+
.myio-cgp--collapsed > .myio-cgp__tabs-wrapper,
|
|
20652
|
+
.myio-cgp--collapsed > .myio-cgp__content {
|
|
20653
|
+
display: none !important;
|
|
20654
|
+
}
|
|
20655
|
+
.myio-cgp--collapsed {
|
|
20656
|
+
height: auto !important;
|
|
20657
|
+
flex: 0 0 auto !important;
|
|
20658
|
+
}
|
|
20630
20659
|
`;
|
|
20631
20660
|
function injectStyles5() {
|
|
20632
20661
|
if (document.getElementById(CSS_ID3)) return;
|
|
@@ -20643,9 +20672,13 @@ var CardGridPanel = class {
|
|
|
20643
20672
|
headerComponent = null;
|
|
20644
20673
|
searchText = "";
|
|
20645
20674
|
tabsContainer = null;
|
|
20675
|
+
collapsible = false;
|
|
20676
|
+
collapsed = false;
|
|
20677
|
+
headerClickBound = false;
|
|
20646
20678
|
constructor(options) {
|
|
20647
20679
|
injectStyles5();
|
|
20648
20680
|
this.options = options;
|
|
20681
|
+
this.collapsible = !!options.collapsible;
|
|
20649
20682
|
this.root = document.createElement("div");
|
|
20650
20683
|
this.root.className = "myio-cgp";
|
|
20651
20684
|
if (options.panelBackground) {
|
|
@@ -20795,6 +20828,46 @@ var CardGridPanel = class {
|
|
|
20795
20828
|
this.root.appendChild(grid);
|
|
20796
20829
|
this.renderTabs();
|
|
20797
20830
|
this.renderGrid();
|
|
20831
|
+
this.applyCollapsibleState();
|
|
20832
|
+
}
|
|
20833
|
+
// ── Accordion / collapse (opt-in via options.collapsible) ──
|
|
20834
|
+
/** Enable/disable collapsible behavior at runtime. */
|
|
20835
|
+
setCollapsible(value) {
|
|
20836
|
+
this.collapsible = value;
|
|
20837
|
+
if (!value) this.collapsed = false;
|
|
20838
|
+
this.applyCollapsibleState();
|
|
20839
|
+
}
|
|
20840
|
+
/** Collapse or expand the panel body programmatically. */
|
|
20841
|
+
setCollapsed(value) {
|
|
20842
|
+
if (!this.collapsible) return;
|
|
20843
|
+
this.collapsed = value;
|
|
20844
|
+
this.root.classList.toggle("myio-cgp--collapsed", this.collapsed);
|
|
20845
|
+
}
|
|
20846
|
+
/** Toggle collapsed state. */
|
|
20847
|
+
toggleCollapsed() {
|
|
20848
|
+
this.setCollapsed(!this.collapsed);
|
|
20849
|
+
}
|
|
20850
|
+
/** Returns whether the panel is currently collapsed. */
|
|
20851
|
+
isCollapsed() {
|
|
20852
|
+
return this.collapsed;
|
|
20853
|
+
}
|
|
20854
|
+
/** Reflects collapsible/collapsed state on the DOM and wires the header click once. */
|
|
20855
|
+
applyCollapsibleState() {
|
|
20856
|
+
this.root.classList.toggle("myio-cgp--collapsible", this.collapsible);
|
|
20857
|
+
if (!this.collapsible) this.collapsed = false;
|
|
20858
|
+
this.root.classList.toggle("myio-cgp--collapsed", this.collapsible && this.collapsed);
|
|
20859
|
+
if (this.collapsible && !this.headerClickBound) {
|
|
20860
|
+
const header = this.headerComponent?.getElement();
|
|
20861
|
+
if (header) {
|
|
20862
|
+
this.headerClickBound = true;
|
|
20863
|
+
header.addEventListener("click", (e) => {
|
|
20864
|
+
if (!this.collapsible) return;
|
|
20865
|
+
const target = e.target;
|
|
20866
|
+
if (target.closest && target.closest('button, a, input, select, svg, [role="button"]')) return;
|
|
20867
|
+
this.toggleCollapsed();
|
|
20868
|
+
});
|
|
20869
|
+
}
|
|
20870
|
+
}
|
|
20798
20871
|
}
|
|
20799
20872
|
renderGrid() {
|
|
20800
20873
|
const grid = this.root.querySelector(".myio-cgp__grid");
|
|
@@ -23767,8 +23840,14 @@ var CDN_RESOURCES = [
|
|
|
23767
23840
|
},
|
|
23768
23841
|
{
|
|
23769
23842
|
id: "daterangepicker-3.1.0",
|
|
23770
|
-
|
|
23771
|
-
|
|
23843
|
+
// IMPORTANT: use the ORIGINAL packaged file, NOT daterangepicker.min.js.
|
|
23844
|
+
// The npm package ships no .min.js — jsDelivr auto-minifies on the fly and
|
|
23845
|
+
// that output is NOT byte-stable across edges/minifier versions, so any
|
|
23846
|
+
// pinned SRI hash for the .min.js URL breaks randomly in production
|
|
23847
|
+
// (observed 2026-06-09: same URL served two different digests).
|
|
23848
|
+
// The packaged daterangepicker.js bytes are immutable for a pinned version.
|
|
23849
|
+
src: "https://cdn.jsdelivr.net/npm/daterangepicker@3.1.0/daterangepicker.js",
|
|
23850
|
+
integrity: "sha384-mnAM7GRdEYmwFIfdpoD/nOPQFbdJrbTrXa7om4CrSzKCQfysFJ0jbwgw+55cdvi7",
|
|
23772
23851
|
crossorigin: "anonymous"
|
|
23773
23852
|
}
|
|
23774
23853
|
];
|
|
@@ -79971,6 +80050,21 @@ function getWidgetStyles(theme, primaryColor, headerStyles) {
|
|
|
79971
80050
|
flex-wrap: wrap;
|
|
79972
80051
|
}
|
|
79973
80052
|
|
|
80053
|
+
/* Accordion (opt-in via config.collapsible): header clicavel; recolhido
|
|
80054
|
+
esconde o corpo + footer, deixando so a barra do header. */
|
|
80055
|
+
.myio-chart-widget--collapsible .myio-chart-widget-header {
|
|
80056
|
+
cursor: pointer;
|
|
80057
|
+
user-select: none;
|
|
80058
|
+
}
|
|
80059
|
+
.myio-chart-widget--collapsed .myio-chart-widget-body,
|
|
80060
|
+
.myio-chart-widget--collapsed .myio-chart-widget-footer {
|
|
80061
|
+
display: none !important;
|
|
80062
|
+
}
|
|
80063
|
+
.myio-chart-widget--collapsed {
|
|
80064
|
+
height: auto !important;
|
|
80065
|
+
flex: 0 0 auto !important;
|
|
80066
|
+
}
|
|
80067
|
+
|
|
79974
80068
|
.myio-chart-widget-stat {
|
|
79975
80069
|
display: flex;
|
|
79976
80070
|
flex-direction: column;
|
|
@@ -80326,6 +80420,9 @@ function createConsumptionChartWidget(config) {
|
|
|
80326
80420
|
let currentVizMode = config.defaultVizMode ?? "total";
|
|
80327
80421
|
let currentPeriod = config.defaultPeriod ?? 7;
|
|
80328
80422
|
let currentIdealRange = config.idealRange ?? null;
|
|
80423
|
+
let isCollapsible = !!config.collapsible;
|
|
80424
|
+
let isCollapsed = false;
|
|
80425
|
+
let collapseWired = false;
|
|
80329
80426
|
let isLoading = false;
|
|
80330
80427
|
let tempPeriod = currentPeriod;
|
|
80331
80428
|
let tempChartType = currentChartType;
|
|
@@ -81086,6 +81183,26 @@ function createConsumptionChartWidget(config) {
|
|
|
81086
81183
|
}
|
|
81087
81184
|
});
|
|
81088
81185
|
}
|
|
81186
|
+
function applyCollapseState() {
|
|
81187
|
+
const widget = document.getElementById(widgetId);
|
|
81188
|
+
if (!widget) return;
|
|
81189
|
+
widget.classList.toggle("myio-chart-widget--collapsible", isCollapsible);
|
|
81190
|
+
if (!isCollapsible) isCollapsed = false;
|
|
81191
|
+
widget.classList.toggle("myio-chart-widget--collapsed", isCollapsible && isCollapsed);
|
|
81192
|
+
if (isCollapsible && !collapseWired) {
|
|
81193
|
+
const header = widget.querySelector(".myio-chart-widget-header");
|
|
81194
|
+
if (header) {
|
|
81195
|
+
collapseWired = true;
|
|
81196
|
+
header.addEventListener("click", (e) => {
|
|
81197
|
+
if (!isCollapsible) return;
|
|
81198
|
+
const target = e.target;
|
|
81199
|
+
if (target.closest && target.closest('button, a, input, select, svg, [role="button"], [class*="-tab"]')) return;
|
|
81200
|
+
isCollapsed = !isCollapsed;
|
|
81201
|
+
applyCollapseState();
|
|
81202
|
+
});
|
|
81203
|
+
}
|
|
81204
|
+
}
|
|
81205
|
+
}
|
|
81089
81206
|
const instance = {
|
|
81090
81207
|
async render() {
|
|
81091
81208
|
containerElement = document.getElementById(config.containerId);
|
|
@@ -81096,6 +81213,7 @@ function createConsumptionChartWidget(config) {
|
|
|
81096
81213
|
injectStyles16();
|
|
81097
81214
|
containerElement.innerHTML = renderHTML();
|
|
81098
81215
|
setupListeners();
|
|
81216
|
+
applyCollapseState();
|
|
81099
81217
|
setLoading(true);
|
|
81100
81218
|
chartInstance = createConsumption7DaysChart({
|
|
81101
81219
|
...config,
|
|
@@ -81186,6 +81304,21 @@ function createConsumptionChartWidget(config) {
|
|
|
81186
81304
|
exportCSV(filename) {
|
|
81187
81305
|
chartInstance?.exportCSV(filename);
|
|
81188
81306
|
},
|
|
81307
|
+
setCollapsible(value) {
|
|
81308
|
+
isCollapsible = value;
|
|
81309
|
+
if (!value) isCollapsed = false;
|
|
81310
|
+
applyCollapseState();
|
|
81311
|
+
},
|
|
81312
|
+
setCollapsed(value) {
|
|
81313
|
+
if (!isCollapsible) return;
|
|
81314
|
+
isCollapsed = value;
|
|
81315
|
+
applyCollapseState();
|
|
81316
|
+
},
|
|
81317
|
+
toggleCollapsed() {
|
|
81318
|
+
if (!isCollapsible) return;
|
|
81319
|
+
isCollapsed = !isCollapsed;
|
|
81320
|
+
applyCollapseState();
|
|
81321
|
+
},
|
|
81189
81322
|
destroy() {
|
|
81190
81323
|
chartInstance?.destroy();
|
|
81191
81324
|
chartInstance = null;
|
|
@@ -136314,40 +136447,94 @@ function injectSidebarMenuStyles() {
|
|
|
136314
136447
|
background: #6b7280;
|
|
136315
136448
|
}
|
|
136316
136449
|
|
|
136317
|
-
/* =====
|
|
136318
|
-
|
|
136319
|
-
|
|
136320
|
-
|
|
136321
|
-
|
|
136322
|
-
|
|
136323
|
-
height: 100vh;
|
|
136324
|
-
transform: translateX(-100%);
|
|
136325
|
-
box-shadow: none;
|
|
136326
|
-
z-index: 1000;
|
|
136327
|
-
}
|
|
136450
|
+
/* ===== Mobile mode (JS-driven via .--mobile, NOT @media) =====
|
|
136451
|
+
The host measures its real element width and calls setMobileMode();
|
|
136452
|
+
in ThingsBoard the widget element width != viewport, so @media is
|
|
136453
|
+
unreliable. In mobile mode the sidebar becomes an off-canvas drawer
|
|
136454
|
+
opened by a persistent top bar (hamburger); the drawer keeps its
|
|
136455
|
+
footer/logout. */
|
|
136328
136456
|
|
|
136329
|
-
|
|
136330
|
-
|
|
136331
|
-
|
|
136332
|
-
|
|
136457
|
+
/* Persistent top bar with the hamburger \u2014 hidden until mobile */
|
|
136458
|
+
.${SIDEBAR_MENU_CSS_PREFIX}__mobile-topbar {
|
|
136459
|
+
display: none;
|
|
136460
|
+
}
|
|
136461
|
+
.${SIDEBAR_MENU_CSS_PREFIX}__mobile-topbar.is-mobile {
|
|
136462
|
+
display: flex;
|
|
136463
|
+
align-items: center;
|
|
136464
|
+
gap: 12px;
|
|
136465
|
+
width: 100%;
|
|
136466
|
+
height: 56px;
|
|
136467
|
+
padding: 0 12px;
|
|
136468
|
+
box-sizing: border-box;
|
|
136469
|
+
background: linear-gradient(135deg, var(--sidebar-primary) 0%, var(--sidebar-primary-light) 100%);
|
|
136470
|
+
color: #ffffff;
|
|
136471
|
+
z-index: 900;
|
|
136472
|
+
}
|
|
136473
|
+
.${SIDEBAR_MENU_CSS_PREFIX}__mobile-hamburger {
|
|
136474
|
+
display: inline-flex;
|
|
136475
|
+
align-items: center;
|
|
136476
|
+
justify-content: center;
|
|
136477
|
+
width: 40px;
|
|
136478
|
+
height: 40px;
|
|
136479
|
+
padding: 0;
|
|
136480
|
+
border: none;
|
|
136481
|
+
border-radius: 8px;
|
|
136482
|
+
background: rgba(255, 255, 255, 0.14);
|
|
136483
|
+
color: #ffffff;
|
|
136484
|
+
cursor: pointer;
|
|
136485
|
+
transition: background 0.2s ease;
|
|
136486
|
+
}
|
|
136487
|
+
.${SIDEBAR_MENU_CSS_PREFIX}__mobile-hamburger:hover {
|
|
136488
|
+
background: rgba(255, 255, 255, 0.26);
|
|
136489
|
+
}
|
|
136490
|
+
.${SIDEBAR_MENU_CSS_PREFIX}__mobile-hamburger svg {
|
|
136491
|
+
width: 22px;
|
|
136492
|
+
height: 22px;
|
|
136493
|
+
}
|
|
136494
|
+
.${SIDEBAR_MENU_CSS_PREFIX}__mobile-topbar-title {
|
|
136495
|
+
font-size: 15px;
|
|
136496
|
+
font-weight: 700;
|
|
136497
|
+
letter-spacing: 0.2px;
|
|
136498
|
+
}
|
|
136333
136499
|
|
|
136334
|
-
|
|
136335
|
-
|
|
136336
|
-
|
|
136337
|
-
|
|
136338
|
-
|
|
136339
|
-
|
|
136340
|
-
|
|
136341
|
-
|
|
136342
|
-
|
|
136343
|
-
|
|
136344
|
-
|
|
136345
|
-
|
|
136500
|
+
/* Sidebar becomes an off-canvas drawer */
|
|
136501
|
+
.${SIDEBAR_MENU_CSS_PREFIX}--mobile {
|
|
136502
|
+
position: fixed;
|
|
136503
|
+
left: 0;
|
|
136504
|
+
top: 0;
|
|
136505
|
+
height: 100vh;
|
|
136506
|
+
width: var(--sidebar-expanded-width);
|
|
136507
|
+
max-width: 86vw;
|
|
136508
|
+
transform: translateX(-100%);
|
|
136509
|
+
box-shadow: none;
|
|
136510
|
+
z-index: 1000;
|
|
136511
|
+
transition: transform var(--sidebar-transition);
|
|
136512
|
+
}
|
|
136513
|
+
.${SIDEBAR_MENU_CSS_PREFIX}--mobile.mobile-open {
|
|
136514
|
+
transform: translateX(0);
|
|
136515
|
+
box-shadow: 4px 0 20px rgba(0, 0, 0, 0.15);
|
|
136516
|
+
}
|
|
136346
136517
|
|
|
136347
|
-
|
|
136348
|
-
|
|
136349
|
-
|
|
136350
|
-
|
|
136518
|
+
/* Backdrop \u2014 only present/active in mobile mode */
|
|
136519
|
+
.${SIDEBAR_MENU_CSS_PREFIX}__backdrop {
|
|
136520
|
+
display: none;
|
|
136521
|
+
position: fixed;
|
|
136522
|
+
top: 0;
|
|
136523
|
+
left: 0;
|
|
136524
|
+
right: 0;
|
|
136525
|
+
bottom: 0;
|
|
136526
|
+
background: rgba(0, 0, 0, 0.5);
|
|
136527
|
+
opacity: 0;
|
|
136528
|
+
visibility: hidden;
|
|
136529
|
+
transition: opacity 0.3s ease, visibility 0.3s ease;
|
|
136530
|
+
z-index: 999;
|
|
136531
|
+
}
|
|
136532
|
+
.${SIDEBAR_MENU_CSS_PREFIX}__backdrop.is-mobile {
|
|
136533
|
+
display: block;
|
|
136534
|
+
}
|
|
136535
|
+
.${SIDEBAR_MENU_CSS_PREFIX}__backdrop.is-open {
|
|
136536
|
+
opacity: 1;
|
|
136537
|
+
visibility: visible;
|
|
136351
136538
|
}
|
|
136352
136539
|
`;
|
|
136353
136540
|
document.head.appendChild(style);
|
|
@@ -136424,8 +136611,15 @@ var SidebarMenuView = class {
|
|
|
136424
136611
|
activeItemId = null;
|
|
136425
136612
|
collapsedSections = /* @__PURE__ */ new Set();
|
|
136426
136613
|
tooltip = null;
|
|
136614
|
+
container;
|
|
136615
|
+
// Mobile mode (JS-driven; NOT @media — the host measures its real width)
|
|
136616
|
+
mobile = false;
|
|
136617
|
+
drawerOpen = false;
|
|
136618
|
+
mobileTopbar = null;
|
|
136619
|
+
backdrop = null;
|
|
136427
136620
|
constructor(container, config) {
|
|
136428
136621
|
injectSidebarMenuStyles();
|
|
136622
|
+
this.container = container;
|
|
136429
136623
|
this.config = { ...DEFAULT_SIDEBAR_CONFIG, ...config };
|
|
136430
136624
|
this.state = this.config.initialState || "expanded";
|
|
136431
136625
|
this.themeMode = this.config.themeMode || "light";
|
|
@@ -136666,7 +136860,11 @@ var SidebarMenuView = class {
|
|
|
136666
136860
|
const target = e.target;
|
|
136667
136861
|
const action = target.closest("[data-action]")?.getAttribute("data-action");
|
|
136668
136862
|
if (action === "toggle") {
|
|
136669
|
-
this.
|
|
136863
|
+
if (this.mobile) {
|
|
136864
|
+
this.closeDrawer();
|
|
136865
|
+
} else {
|
|
136866
|
+
this.toggle();
|
|
136867
|
+
}
|
|
136670
136868
|
} else if (action === "theme-toggle") {
|
|
136671
136869
|
this.handleThemeToggle();
|
|
136672
136870
|
} else if (action === "logout") {
|
|
@@ -136686,6 +136884,7 @@ var SidebarMenuView = class {
|
|
|
136686
136884
|
const sectionId = itemEl.getAttribute("data-section-id");
|
|
136687
136885
|
if (itemId && sectionId) {
|
|
136688
136886
|
this.handleItemClick(itemId, sectionId);
|
|
136887
|
+
if (this.mobile) this.closeDrawer();
|
|
136689
136888
|
}
|
|
136690
136889
|
}
|
|
136691
136890
|
}
|
|
@@ -136834,6 +137033,71 @@ var SidebarMenuView = class {
|
|
|
136834
137033
|
getState() {
|
|
136835
137034
|
return this.state;
|
|
136836
137035
|
}
|
|
137036
|
+
/**
|
|
137037
|
+
* Toggle mobile mode. Driven by the host (it measures its real width),
|
|
137038
|
+
* NOT by @media — the widget element width != viewport in ThingsBoard.
|
|
137039
|
+
* In mobile mode the sidebar becomes an off-canvas drawer and a persistent
|
|
137040
|
+
* top bar (hamburger) is shown to open it; the drawer keeps its footer/logout.
|
|
137041
|
+
*/
|
|
137042
|
+
setMobileMode(on) {
|
|
137043
|
+
if (this.mobile === on) return;
|
|
137044
|
+
this.mobile = on;
|
|
137045
|
+
if (on) {
|
|
137046
|
+
this.ensureMobileChrome();
|
|
137047
|
+
this.root.classList.add(`${SIDEBAR_MENU_CSS_PREFIX}--mobile`);
|
|
137048
|
+
this.root.classList.remove("collapsed");
|
|
137049
|
+
if (this.mobileTopbar) this.mobileTopbar.classList.add("is-mobile");
|
|
137050
|
+
if (this.backdrop) this.backdrop.classList.add("is-mobile");
|
|
137051
|
+
this.closeDrawer();
|
|
137052
|
+
} else {
|
|
137053
|
+
this.closeDrawer();
|
|
137054
|
+
this.root.classList.remove(`${SIDEBAR_MENU_CSS_PREFIX}--mobile`);
|
|
137055
|
+
if (this.mobileTopbar) this.mobileTopbar.classList.remove("is-mobile");
|
|
137056
|
+
if (this.backdrop) this.backdrop.classList.remove("is-mobile");
|
|
137057
|
+
if (this.state === "collapsed") this.root.classList.add("collapsed");
|
|
137058
|
+
}
|
|
137059
|
+
}
|
|
137060
|
+
/** Lazily create the persistent mobile top bar (hamburger) + backdrop. */
|
|
137061
|
+
ensureMobileChrome() {
|
|
137062
|
+
if (!this.mobileTopbar) {
|
|
137063
|
+
const header = this.config.header || {};
|
|
137064
|
+
const title = header.title || "Menu";
|
|
137065
|
+
const bar = document.createElement("div");
|
|
137066
|
+
bar.className = `${SIDEBAR_MENU_CSS_PREFIX}__mobile-topbar`;
|
|
137067
|
+
bar.innerHTML = `
|
|
137068
|
+
<button
|
|
137069
|
+
class="${SIDEBAR_MENU_CSS_PREFIX}__mobile-hamburger"
|
|
137070
|
+
data-action="mobile-open"
|
|
137071
|
+
aria-label="Abrir menu"
|
|
137072
|
+
>${SIDEBAR_ICONS.menu}</button>
|
|
137073
|
+
<span class="${SIDEBAR_MENU_CSS_PREFIX}__mobile-topbar-title">${title}</span>
|
|
137074
|
+
`;
|
|
137075
|
+
bar.querySelector('[data-action="mobile-open"]')?.addEventListener("click", () => this.openDrawer());
|
|
137076
|
+
this.container.insertBefore(bar, this.root);
|
|
137077
|
+
this.mobileTopbar = bar;
|
|
137078
|
+
}
|
|
137079
|
+
if (!this.backdrop) {
|
|
137080
|
+
const bd = document.createElement("div");
|
|
137081
|
+
bd.className = `${SIDEBAR_MENU_CSS_PREFIX}__backdrop`;
|
|
137082
|
+
bd.addEventListener("click", () => this.closeDrawer());
|
|
137083
|
+
this.container.insertBefore(bd, this.root.nextSibling);
|
|
137084
|
+
this.backdrop = bd;
|
|
137085
|
+
}
|
|
137086
|
+
}
|
|
137087
|
+
openDrawer() {
|
|
137088
|
+
if (!this.mobile) return;
|
|
137089
|
+
this.drawerOpen = true;
|
|
137090
|
+
this.root.classList.add("mobile-open");
|
|
137091
|
+
this.backdrop?.classList.add("is-open");
|
|
137092
|
+
}
|
|
137093
|
+
closeDrawer() {
|
|
137094
|
+
this.drawerOpen = false;
|
|
137095
|
+
this.root.classList.remove("mobile-open");
|
|
137096
|
+
this.backdrop?.classList.remove("is-open");
|
|
137097
|
+
}
|
|
137098
|
+
isMobile() {
|
|
137099
|
+
return this.mobile;
|
|
137100
|
+
}
|
|
136837
137101
|
setThemeMode(mode) {
|
|
136838
137102
|
this.themeMode = mode;
|
|
136839
137103
|
this.root.classList.remove("light", "dark");
|
|
@@ -136959,6 +137223,19 @@ var SidebarMenuController = class {
|
|
|
136959
137223
|
toggle() {
|
|
136960
137224
|
this.view.toggle();
|
|
136961
137225
|
}
|
|
137226
|
+
/** Enable/disable mobile mode (hamburger top bar + off-canvas drawer). */
|
|
137227
|
+
setMobileMode(on) {
|
|
137228
|
+
this.view.setMobileMode(on);
|
|
137229
|
+
}
|
|
137230
|
+
openDrawer() {
|
|
137231
|
+
this.view.openDrawer();
|
|
137232
|
+
}
|
|
137233
|
+
closeDrawer() {
|
|
137234
|
+
this.view.closeDrawer();
|
|
137235
|
+
}
|
|
137236
|
+
isMobile() {
|
|
137237
|
+
return this.view.isMobile();
|
|
137238
|
+
}
|
|
136962
137239
|
getState() {
|
|
136963
137240
|
return this.view.getState();
|
|
136964
137241
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -3177,6 +3177,13 @@ interface CardGridPanelOptions {
|
|
|
3177
3177
|
tabs?: TabItem[];
|
|
3178
3178
|
/** Callback when tab selection changes (receives the newly selected tab) */
|
|
3179
3179
|
onTabChange?: (tab: TabItem) => void;
|
|
3180
|
+
/**
|
|
3181
|
+
* When true, the panel becomes an accordion item: clicking the header
|
|
3182
|
+
* (anywhere except its buttons) collapses/expands the body. A small arrow
|
|
3183
|
+
* indicator is shown before the title. Default: false (fully backward-compatible).
|
|
3184
|
+
* Can be toggled at runtime via setCollapsible().
|
|
3185
|
+
*/
|
|
3186
|
+
collapsible?: boolean;
|
|
3180
3187
|
}
|
|
3181
3188
|
declare class CardGridPanel {
|
|
3182
3189
|
private root;
|
|
@@ -3184,6 +3191,9 @@ declare class CardGridPanel {
|
|
|
3184
3191
|
private headerComponent;
|
|
3185
3192
|
private searchText;
|
|
3186
3193
|
private tabsContainer;
|
|
3194
|
+
private collapsible;
|
|
3195
|
+
private collapsed;
|
|
3196
|
+
private headerClickBound;
|
|
3187
3197
|
constructor(options: CardGridPanelOptions);
|
|
3188
3198
|
getElement(): HTMLElement;
|
|
3189
3199
|
/** Replace items and re-render grid */
|
|
@@ -3210,6 +3220,16 @@ declare class CardGridPanel {
|
|
|
3210
3220
|
setCardCustomStyle(style: CardGridCustomStyle | undefined): void;
|
|
3211
3221
|
destroy(): void;
|
|
3212
3222
|
private render;
|
|
3223
|
+
/** Enable/disable collapsible behavior at runtime. */
|
|
3224
|
+
setCollapsible(value: boolean): void;
|
|
3225
|
+
/** Collapse or expand the panel body programmatically. */
|
|
3226
|
+
setCollapsed(value: boolean): void;
|
|
3227
|
+
/** Toggle collapsed state. */
|
|
3228
|
+
toggleCollapsed(): void;
|
|
3229
|
+
/** Returns whether the panel is currently collapsed. */
|
|
3230
|
+
isCollapsed(): boolean;
|
|
3231
|
+
/** Reflects collapsible/collapsed state on the DOM and wires the header click once. */
|
|
3232
|
+
private applyCollapsibleState;
|
|
3213
3233
|
private renderGrid;
|
|
3214
3234
|
private renderTabs;
|
|
3215
3235
|
}
|
|
@@ -9518,6 +9538,12 @@ interface ConsumptionWidgetConfig extends Omit<Consumption7DaysConfig, 'containe
|
|
|
9518
9538
|
onMaximizeClick?: () => void;
|
|
9519
9539
|
/** Custom CSS class for the widget container */
|
|
9520
9540
|
className?: string;
|
|
9541
|
+
/**
|
|
9542
|
+
* When true, the widget becomes an accordion item: clicking the header
|
|
9543
|
+
* (except its buttons/tabs) collapses/expands the chart body, leaving only
|
|
9544
|
+
* the header bar. Default: false. Toggle at runtime via setCollapsible().
|
|
9545
|
+
*/
|
|
9546
|
+
collapsible?: boolean;
|
|
9521
9547
|
/**
|
|
9522
9548
|
* Custom header styles for compact layouts
|
|
9523
9549
|
* @example { padding: '8px 12px', fontSize: '12px', titleFontSize: '12px', tabPadding: '4px 10px', tabFontSize: '11px' }
|
|
@@ -9566,6 +9592,12 @@ interface ConsumptionWidgetInstance {
|
|
|
9566
9592
|
};
|
|
9567
9593
|
/** Exports data to CSV */
|
|
9568
9594
|
exportCSV: (filename?: string) => void;
|
|
9595
|
+
/** Enable/disable collapsible (accordion) behavior at runtime. */
|
|
9596
|
+
setCollapsible: (value: boolean) => void;
|
|
9597
|
+
/** Collapse/expand the chart body, keeping only the header bar. */
|
|
9598
|
+
setCollapsed: (value: boolean) => void;
|
|
9599
|
+
/** Toggle collapsed state. */
|
|
9600
|
+
toggleCollapsed: () => void;
|
|
9569
9601
|
/** Destroys the widget */
|
|
9570
9602
|
destroy: () => void;
|
|
9571
9603
|
}
|
|
@@ -18445,6 +18477,11 @@ declare class SidebarMenuController implements SidebarMenuInstance {
|
|
|
18445
18477
|
expand(): void;
|
|
18446
18478
|
collapse(): void;
|
|
18447
18479
|
toggle(): void;
|
|
18480
|
+
/** Enable/disable mobile mode (hamburger top bar + off-canvas drawer). */
|
|
18481
|
+
setMobileMode(on: boolean): void;
|
|
18482
|
+
openDrawer(): void;
|
|
18483
|
+
closeDrawer(): void;
|
|
18484
|
+
isMobile(): boolean;
|
|
18448
18485
|
getState(): SidebarState;
|
|
18449
18486
|
setThemeMode(mode: SidebarThemeMode): void;
|
|
18450
18487
|
updateSections(sections: SidebarMenuSection[]): void;
|
|
@@ -18473,6 +18510,11 @@ declare class SidebarMenuView {
|
|
|
18473
18510
|
private activeItemId;
|
|
18474
18511
|
private collapsedSections;
|
|
18475
18512
|
private tooltip;
|
|
18513
|
+
private container;
|
|
18514
|
+
private mobile;
|
|
18515
|
+
private drawerOpen;
|
|
18516
|
+
private mobileTopbar;
|
|
18517
|
+
private backdrop;
|
|
18476
18518
|
constructor(container: HTMLElement, config: SidebarMenuConfig);
|
|
18477
18519
|
private createSidebar;
|
|
18478
18520
|
private renderHeader;
|
|
@@ -18493,6 +18535,18 @@ declare class SidebarMenuView {
|
|
|
18493
18535
|
collapse(): void;
|
|
18494
18536
|
toggle(): void;
|
|
18495
18537
|
getState(): SidebarState;
|
|
18538
|
+
/**
|
|
18539
|
+
* Toggle mobile mode. Driven by the host (it measures its real width),
|
|
18540
|
+
* NOT by @media — the widget element width != viewport in ThingsBoard.
|
|
18541
|
+
* In mobile mode the sidebar becomes an off-canvas drawer and a persistent
|
|
18542
|
+
* top bar (hamburger) is shown to open it; the drawer keeps its footer/logout.
|
|
18543
|
+
*/
|
|
18544
|
+
setMobileMode(on: boolean): void;
|
|
18545
|
+
/** Lazily create the persistent mobile top bar (hamburger) + backdrop. */
|
|
18546
|
+
private ensureMobileChrome;
|
|
18547
|
+
openDrawer(): void;
|
|
18548
|
+
closeDrawer(): void;
|
|
18549
|
+
isMobile(): boolean;
|
|
18496
18550
|
setThemeMode(mode: SidebarThemeMode): void;
|
|
18497
18551
|
updateSections(sections: SidebarMenuSection[]): void;
|
|
18498
18552
|
updateItemBadge(itemId: string, badge: number | string | null): void;
|