myio-js-library 0.1.164 → 0.1.166

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.js CHANGED
@@ -20527,7 +20527,7 @@ function renderModal(container, state, modalId, error) {
20527
20527
  const contentMaxHeight = isMaximized ? "100vh" : "95vh";
20528
20528
  const contentBorderRadius = isMaximized ? "0" : "10px";
20529
20529
  container.innerHTML = `
20530
- <div class="myio-temp-modal-overlay" style="
20530
+ <div class="myio-temp-modal-overlay myio-modal-scope" style="
20531
20531
  position: fixed; top: 0; left: 0; width: 100%; height: 100%;
20532
20532
  background: rgba(0, 0, 0, 0.5); z-index: 9998;
20533
20533
  display: flex; justify-content: center; align-items: center;
@@ -20782,6 +20782,22 @@ function renderModal(container, state, modalId, error) {
20782
20782
  background: rgba(255, 255, 255, 0.1) !important;
20783
20783
  color: white !important;
20784
20784
  }
20785
+
20786
+ /* DateRangePicker styles */
20787
+ ${CSS_TOKENS}
20788
+ ${DATERANGEPICKER_STYLES}
20789
+
20790
+ /* Fix DateRangePicker buttons alignment */
20791
+ .myio-modal-scope .daterangepicker .drp-buttons {
20792
+ display: flex;
20793
+ justify-content: flex-end;
20794
+ align-items: center;
20795
+ gap: 8px;
20796
+ }
20797
+ .myio-modal-scope .daterangepicker .drp-buttons .btn {
20798
+ display: inline-block;
20799
+ margin-left: 0;
20800
+ }
20785
20801
  </style>
20786
20802
  `;
20787
20803
  }
@@ -23577,11 +23593,16 @@ function createConsumptionModal(config) {
23577
23593
  let isMaximized = false;
23578
23594
  const domainCfg = DOMAIN_CONFIG3[config.domain] || { name: config.domain, icon: "\u{1F4CA}" };
23579
23595
  const title = config.title || `${domainCfg.name} - Hist\xF3rico de Consumo`;
23580
- function getThemeColors2() {
23596
+ function getThemeColors3() {
23581
23597
  return THEME_COLORS[currentTheme];
23582
23598
  }
23599
+ const consolidadoIcon = `<svg viewBox="0 0 16 16" fill="currentColor" style="width:14px;height:14px;pointer-events:none"><rect x="3" y="3" width="10" height="10" rx="2"/></svg>`;
23600
+ const porShoppingIcon = `<svg viewBox="0 0 16 16" fill="currentColor" style="width:14px;height:14px;pointer-events:none"><rect x="1" y="1" width="6" height="6" rx="1"/><rect x="9" y="1" width="6" height="6" rx="1"/><rect x="1" y="9" width="6" height="6" rx="1"/><rect x="9" y="9" width="6" height="6" rx="1"/></svg>`;
23601
+ const lineChartIcon = `<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:14px;height:14px;pointer-events:none"><polyline points="2,12 5,7 9,9 14,3"/></svg>`;
23602
+ const barChartIcon = `<svg viewBox="0 0 16 16" fill="currentColor" style="width:14px;height:14px;pointer-events:none"><rect x="1" y="9" width="3" height="6" rx="0.5"/><rect x="6" y="5" width="3" height="10" rx="0.5"/><rect x="11" y="7" width="3" height="8" rx="0.5"/></svg>`;
23603
+ const showSettingsButton = config.showSettingsButton ?? true;
23583
23604
  function renderModal4() {
23584
- const colors = getThemeColors2();
23605
+ const colors = getThemeColors3();
23585
23606
  const exportFormats = config.exportFormats || ["csv"];
23586
23607
  headerInstance = createModalHeader({
23587
23608
  id: modalId,
@@ -23614,7 +23635,55 @@ function createConsumptionModal(config) {
23614
23635
  instance.close();
23615
23636
  }
23616
23637
  });
23638
+ const btnBaseStyle = `
23639
+ display: flex;
23640
+ align-items: center;
23641
+ justify-content: center;
23642
+ gap: 6px;
23643
+ padding: 6px 12px;
23644
+ border: none;
23645
+ border-radius: 6px;
23646
+ font-size: 12px;
23647
+ font-weight: 500;
23648
+ cursor: pointer;
23649
+ transition: all 0.2s;
23650
+ white-space: nowrap;
23651
+ `.replace(/\s+/g, " ").trim();
23652
+ const tabBgColor = currentTheme === "dark" ? "#4b5563" : "#e5e7eb";
23653
+ const activeColor = "#3e1a7d";
23654
+ const inactiveTextColor = colors.text;
23617
23655
  return `
23656
+ <style>
23657
+ .myio-modal-tab-btn {
23658
+ ${btnBaseStyle}
23659
+ }
23660
+ .myio-modal-tab-btn:hover {
23661
+ opacity: 0.85;
23662
+ }
23663
+ .myio-modal-tab-btn.active {
23664
+ background: ${activeColor} !important;
23665
+ color: white !important;
23666
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
23667
+ }
23668
+ .myio-modal-tab-btn svg {
23669
+ pointer-events: none;
23670
+ }
23671
+ .myio-modal-settings-btn {
23672
+ background: transparent;
23673
+ border: 1px solid ${colors.border};
23674
+ font-size: 16px;
23675
+ cursor: pointer;
23676
+ padding: 6px 10px;
23677
+ border-radius: 6px;
23678
+ transition: all 0.2s;
23679
+ color: ${colors.text};
23680
+ }
23681
+ .myio-modal-settings-btn:hover {
23682
+ background: ${activeColor};
23683
+ border-color: ${activeColor};
23684
+ color: white;
23685
+ }
23686
+ </style>
23618
23687
  <div class="myio-consumption-modal-overlay" style="
23619
23688
  position: fixed;
23620
23689
  top: 0;
@@ -23645,59 +23714,44 @@ function createConsumptionModal(config) {
23645
23714
  <!-- Controls Bar -->
23646
23715
  <div class="myio-consumption-modal-controls" style="
23647
23716
  display: flex;
23648
- gap: 16px;
23717
+ gap: 12px;
23649
23718
  padding: 12px 16px;
23650
23719
  background: ${currentTheme === "dark" ? "#374151" : "#f7f7f7"};
23651
23720
  border-bottom: 1px solid ${colors.border};
23652
23721
  align-items: center;
23653
23722
  flex-wrap: wrap;
23654
23723
  ">
23724
+ <!-- Settings Button -->
23725
+ ${showSettingsButton ? `
23726
+ <button id="${modalId}-settings-btn" class="myio-modal-settings-btn" title="Configura\xE7\xF5es">\u2699\uFE0F</button>
23727
+ ` : ""}
23728
+
23655
23729
  <!-- Viz Mode Tabs -->
23656
- <div style="display: flex; gap: 2px; background: ${currentTheme === "dark" ? "#4b5563" : "#e5e7eb"}; border-radius: 8px; padding: 2px;">
23657
- <button id="${modalId}-viz-total" style="
23658
- padding: 6px 12px;
23659
- border: none;
23660
- border-radius: 6px;
23661
- font-size: 13px;
23662
- cursor: pointer;
23663
- transition: all 0.2s;
23664
- background: ${currentVizMode === "total" ? "#3e1a7d" : "transparent"};
23665
- color: ${currentVizMode === "total" ? "white" : colors.text};
23666
- ">Consolidado</button>
23667
- <button id="${modalId}-viz-separate" style="
23668
- padding: 6px 12px;
23669
- border: none;
23670
- border-radius: 6px;
23671
- font-size: 13px;
23672
- cursor: pointer;
23673
- transition: all 0.2s;
23674
- background: ${currentVizMode === "separate" ? "#3e1a7d" : "transparent"};
23675
- color: ${currentVizMode === "separate" ? "white" : colors.text};
23676
- ">Por Shopping</button>
23730
+ <div style="display: flex; gap: 2px; background: ${tabBgColor}; border-radius: 8px; padding: 3px;">
23731
+ <button id="${modalId}-viz-total" class="myio-modal-tab-btn ${currentVizMode === "total" ? "active" : ""}"
23732
+ data-viz="total" title="Consolidado"
23733
+ style="background: ${currentVizMode === "total" ? activeColor : "transparent"}; color: ${currentVizMode === "total" ? "white" : inactiveTextColor};">
23734
+ ${consolidadoIcon}
23735
+ </button>
23736
+ <button id="${modalId}-viz-separate" class="myio-modal-tab-btn ${currentVizMode === "separate" ? "active" : ""}"
23737
+ data-viz="separate" title="Por Shopping"
23738
+ style="background: ${currentVizMode === "separate" ? activeColor : "transparent"}; color: ${currentVizMode === "separate" ? "white" : inactiveTextColor};">
23739
+ ${porShoppingIcon}
23740
+ </button>
23677
23741
  </div>
23678
23742
 
23679
23743
  <!-- Chart Type Tabs -->
23680
- <div style="display: flex; gap: 2px; background: ${currentTheme === "dark" ? "#4b5563" : "#e5e7eb"}; border-radius: 8px; padding: 2px;">
23681
- <button id="${modalId}-type-line" style="
23682
- padding: 6px 12px;
23683
- border: none;
23684
- border-radius: 6px;
23685
- font-size: 13px;
23686
- cursor: pointer;
23687
- transition: all 0.2s;
23688
- background: ${currentChartType === "line" ? "#3e1a7d" : "transparent"};
23689
- color: ${currentChartType === "line" ? "white" : colors.text};
23690
- ">Linhas</button>
23691
- <button id="${modalId}-type-bar" style="
23692
- padding: 6px 12px;
23693
- border: none;
23694
- border-radius: 6px;
23695
- font-size: 13px;
23696
- cursor: pointer;
23697
- transition: all 0.2s;
23698
- background: ${currentChartType === "bar" ? "#3e1a7d" : "transparent"};
23699
- color: ${currentChartType === "bar" ? "white" : colors.text};
23700
- ">Barras</button>
23744
+ <div style="display: flex; gap: 2px; background: ${tabBgColor}; border-radius: 8px; padding: 3px;">
23745
+ <button id="${modalId}-type-line" class="myio-modal-tab-btn ${currentChartType === "line" ? "active" : ""}"
23746
+ data-type="line" title="Gr\xE1fico de Linhas"
23747
+ style="background: ${currentChartType === "line" ? activeColor : "transparent"}; color: ${currentChartType === "line" ? "white" : inactiveTextColor};">
23748
+ ${lineChartIcon}
23749
+ </button>
23750
+ <button id="${modalId}-type-bar" class="myio-modal-tab-btn ${currentChartType === "bar" ? "active" : ""}"
23751
+ data-type="bar" title="Gr\xE1fico de Barras"
23752
+ style="background: ${currentChartType === "bar" ? activeColor : "transparent"}; color: ${currentChartType === "bar" ? "white" : inactiveTextColor};">
23753
+ ${barChartIcon}
23754
+ </button>
23701
23755
  </div>
23702
23756
  </div>
23703
23757
 
@@ -23718,6 +23772,11 @@ function createConsumptionModal(config) {
23718
23772
  function setupListeners() {
23719
23773
  if (!modalElement) return;
23720
23774
  headerInstance?.attachListeners();
23775
+ if (showSettingsButton) {
23776
+ document.getElementById(`${modalId}-settings-btn`)?.addEventListener("click", () => {
23777
+ config.onSettingsClick?.();
23778
+ });
23779
+ }
23721
23780
  document.getElementById(`${modalId}-viz-total`)?.addEventListener("click", () => {
23722
23781
  currentVizMode = "total";
23723
23782
  chartInstance?.setVizMode("total");
@@ -23752,25 +23811,30 @@ function createConsumptionModal(config) {
23752
23811
  modalElement.__handleKeydown = handleKeydown;
23753
23812
  }
23754
23813
  function updateControlStyles() {
23755
- const colors = getThemeColors2();
23814
+ const colors = getThemeColors3();
23815
+ const activeColor = "#3e1a7d";
23756
23816
  const vizTotalBtn = document.getElementById(`${modalId}-viz-total`);
23757
23817
  const vizSeparateBtn = document.getElementById(`${modalId}-viz-separate`);
23758
23818
  if (vizTotalBtn) {
23759
- vizTotalBtn.style.background = currentVizMode === "total" ? "#3e1a7d" : "transparent";
23819
+ vizTotalBtn.classList.toggle("active", currentVizMode === "total");
23820
+ vizTotalBtn.style.background = currentVizMode === "total" ? activeColor : "transparent";
23760
23821
  vizTotalBtn.style.color = currentVizMode === "total" ? "white" : colors.text;
23761
23822
  }
23762
23823
  if (vizSeparateBtn) {
23763
- vizSeparateBtn.style.background = currentVizMode === "separate" ? "#3e1a7d" : "transparent";
23824
+ vizSeparateBtn.classList.toggle("active", currentVizMode === "separate");
23825
+ vizSeparateBtn.style.background = currentVizMode === "separate" ? activeColor : "transparent";
23764
23826
  vizSeparateBtn.style.color = currentVizMode === "separate" ? "white" : colors.text;
23765
23827
  }
23766
23828
  const typeLineBtn = document.getElementById(`${modalId}-type-line`);
23767
23829
  const typeBarBtn = document.getElementById(`${modalId}-type-bar`);
23768
23830
  if (typeLineBtn) {
23769
- typeLineBtn.style.background = currentChartType === "line" ? "#3e1a7d" : "transparent";
23831
+ typeLineBtn.classList.toggle("active", currentChartType === "line");
23832
+ typeLineBtn.style.background = currentChartType === "line" ? activeColor : "transparent";
23770
23833
  typeLineBtn.style.color = currentChartType === "line" ? "white" : colors.text;
23771
23834
  }
23772
23835
  if (typeBarBtn) {
23773
- typeBarBtn.style.background = currentChartType === "bar" ? "#3e1a7d" : "transparent";
23836
+ typeBarBtn.classList.toggle("active", currentChartType === "bar");
23837
+ typeBarBtn.style.background = currentChartType === "bar" ? activeColor : "transparent";
23774
23838
  typeBarBtn.style.color = currentChartType === "bar" ? "white" : colors.text;
23775
23839
  }
23776
23840
  }
@@ -23896,18 +23960,11 @@ function getWidgetStyles(theme, primaryColor) {
23896
23960
 
23897
23961
  .myio-chart-widget-title {
23898
23962
  margin: 0;
23899
- font-size: 16px;
23963
+ font-size: 14px;
23900
23964
  font-weight: 600;
23901
23965
  color: ${colors.text};
23902
23966
  }
23903
23967
 
23904
- .myio-chart-widget-controls {
23905
- display: flex;
23906
- align-items: center;
23907
- gap: 12px;
23908
- flex-wrap: wrap;
23909
- }
23910
-
23911
23968
  .myio-chart-widget-tabs {
23912
23969
  display: flex;
23913
23970
  gap: 2px;
@@ -23927,6 +23984,20 @@ function getWidgetStyles(theme, primaryColor) {
23927
23984
  border-radius: 6px;
23928
23985
  transition: all 0.2s;
23929
23986
  white-space: nowrap;
23987
+ display: flex;
23988
+ align-items: center;
23989
+ justify-content: center;
23990
+ gap: 4px;
23991
+ }
23992
+
23993
+ .myio-chart-widget-tab.icon-only {
23994
+ padding: 6px 10px;
23995
+ }
23996
+
23997
+ .myio-chart-widget-tab svg {
23998
+ width: 16px;
23999
+ height: 16px;
24000
+ pointer-events: none;
23930
24001
  }
23931
24002
 
23932
24003
  .myio-chart-widget-tab:hover {
@@ -24060,7 +24131,7 @@ function getWidgetStyles(theme, primaryColor) {
24060
24131
  background: ${colors.chartBackground};
24061
24132
  border-radius: 10px;
24062
24133
  width: 90%;
24063
- max-width: 600px;
24134
+ max-width: 860px;
24064
24135
  max-height: 90vh;
24065
24136
  display: flex;
24066
24137
  flex-direction: column;
@@ -24077,7 +24148,7 @@ function getWidgetStyles(theme, primaryColor) {
24077
24148
  overflow-y: auto;
24078
24149
  display: flex;
24079
24150
  flex-direction: column;
24080
- gap: 20px;
24151
+ gap: 12px;
24081
24152
  }
24082
24153
 
24083
24154
  .myio-settings-section {
@@ -24120,10 +24191,10 @@ function getWidgetStyles(theme, primaryColor) {
24120
24191
 
24121
24192
  .myio-settings-input,
24122
24193
  .myio-settings-select {
24123
- padding: 10px 14px;
24194
+ padding: 8px 12px;
24124
24195
  border: 1px solid ${colors.border};
24125
24196
  border-radius: 8px;
24126
- font-size: 14px;
24197
+ font-size: 12px;
24127
24198
  background: ${colors.chartBackground};
24128
24199
  color: ${colors.text};
24129
24200
  width: 100%;
@@ -24155,6 +24226,10 @@ function getWidgetStyles(theme, primaryColor) {
24155
24226
  border-radius: 6px;
24156
24227
  transition: all 0.2s;
24157
24228
  white-space: nowrap;
24229
+ display: flex;
24230
+ align-items: center;
24231
+ justify-content: center;
24232
+ gap: 6px;
24158
24233
  }
24159
24234
 
24160
24235
  .myio-settings-tab:hover {
@@ -24212,13 +24287,17 @@ function getWidgetStyles(theme, primaryColor) {
24212
24287
  }
24213
24288
 
24214
24289
  .myio-settings-context-group {
24215
- margin-bottom: 8px;
24290
+ margin-bottom: 12px;
24216
24291
  }
24217
24292
 
24218
24293
  .myio-settings-context-group:last-child {
24219
24294
  margin-bottom: 0;
24220
24295
  }
24221
24296
 
24297
+ .myio-settings-section + .myio-settings-section {
24298
+ margin-top: 12px;
24299
+ }
24300
+
24222
24301
  /* Dropdown styles */
24223
24302
  .myio-settings-dropdown-container {
24224
24303
  position: relative;
@@ -24322,6 +24401,23 @@ function getWidgetStyles(theme, primaryColor) {
24322
24401
  opacity: 1 !important;
24323
24402
  transform: scale(1.2);
24324
24403
  }
24404
+
24405
+ /* DateRangePicker styles (CSS tokens + premium styling) */
24406
+ ${CSS_TOKENS}
24407
+ ${DATERANGEPICKER_STYLES}
24408
+
24409
+ /* Fix DateRangePicker buttons alignment */
24410
+ .myio-modal-scope .daterangepicker .drp-buttons {
24411
+ display: flex;
24412
+ justify-content: flex-end;
24413
+ align-items: center;
24414
+ gap: 8px;
24415
+ }
24416
+
24417
+ .myio-modal-scope .daterangepicker .drp-buttons .btn {
24418
+ display: inline-block;
24419
+ margin-left: 0;
24420
+ }
24325
24421
  `;
24326
24422
  }
24327
24423
  function createConsumptionChartWidget(config) {
@@ -24331,6 +24427,7 @@ function createConsumptionChartWidget(config) {
24331
24427
  let styleElement = null;
24332
24428
  let settingsModalElement = null;
24333
24429
  let settingsHeaderInstance = null;
24430
+ let dateRangePickerInstance = null;
24334
24431
  let currentTheme = config.theme ?? "light";
24335
24432
  let currentChartType = config.defaultChartType ?? "line";
24336
24433
  let currentVizMode = config.defaultVizMode ?? "total";
@@ -24342,6 +24439,8 @@ function createConsumptionChartWidget(config) {
24342
24439
  let tempVizMode = currentVizMode;
24343
24440
  let tempTheme = currentTheme;
24344
24441
  let tempIdealRange = currentIdealRange;
24442
+ let tempStartDate = null;
24443
+ let tempEndDate = null;
24345
24444
  let currentSuggestion = null;
24346
24445
  const domainCfg = DOMAIN_CONFIG4[config.domain] || DOMAIN_CONFIG4.energy;
24347
24446
  const primaryColor = config.colors?.primary || domainCfg.color;
@@ -24357,6 +24456,10 @@ function createConsumptionChartWidget(config) {
24357
24456
  return `${domainName} dos \xFAltimos ${currentPeriod} dias`;
24358
24457
  }
24359
24458
  function renderHTML() {
24459
+ const consolidadoIcon = `<svg viewBox="0 0 16 16" fill="currentColor"><rect x="3" y="3" width="10" height="10" rx="2"/></svg>`;
24460
+ const porShoppingIcon = `<svg viewBox="0 0 16 16" fill="currentColor"><rect x="1" y="1" width="6" height="6" rx="1"/><rect x="9" y="1" width="6" height="6" rx="1"/><rect x="1" y="9" width="6" height="6" rx="1"/><rect x="9" y="9" width="6" height="6" rx="1"/></svg>`;
24461
+ const lineChartIcon = `<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="2,12 5,7 9,9 14,3"/></svg>`;
24462
+ const barChartIcon = `<svg viewBox="0 0 16 16" fill="currentColor"><rect x="1" y="9" width="3" height="6" rx="0.5"/><rect x="6" y="5" width="3" height="10" rx="0.5"/><rect x="11" y="7" width="3" height="8" rx="0.5"/></svg>`;
24360
24463
  return `
24361
24464
  <div id="${widgetId}" class="myio-chart-widget ${currentTheme === "dark" ? "dark" : ""} ${config.className || ""}">
24362
24465
  <div class="myio-chart-widget-header">
@@ -24365,18 +24468,16 @@ function createConsumptionChartWidget(config) {
24365
24468
  <button id="${widgetId}-settings-btn" class="myio-chart-widget-btn" title="Configura\xE7\xF5es">\u2699\uFE0F</button>
24366
24469
  ` : ""}
24367
24470
  <h4 id="${widgetId}-title" class="myio-chart-widget-title">${getTitle()}</h4>
24368
- </div>
24369
- <div class="myio-chart-widget-controls">
24370
24471
  ${showVizModeTabs ? `
24371
24472
  <div class="myio-chart-widget-tabs" id="${widgetId}-viz-tabs">
24372
- <button class="myio-chart-widget-tab ${currentVizMode === "total" ? "active" : ""}" data-viz="total">Consolidado</button>
24373
- <button class="myio-chart-widget-tab ${currentVizMode === "separate" ? "active" : ""}" data-viz="separate">Por Shopping</button>
24473
+ <button class="myio-chart-widget-tab icon-only ${currentVizMode === "total" ? "active" : ""}" data-viz="total" title="Consolidado">${consolidadoIcon}</button>
24474
+ <button class="myio-chart-widget-tab icon-only ${currentVizMode === "separate" ? "active" : ""}" data-viz="separate" title="Por Shopping">${porShoppingIcon}</button>
24374
24475
  </div>
24375
24476
  ` : ""}
24376
24477
  ${showChartTypeTabs ? `
24377
24478
  <div class="myio-chart-widget-tabs" id="${widgetId}-type-tabs">
24378
- <button class="myio-chart-widget-tab ${currentChartType === "line" ? "active" : ""}" data-type="line">Linhas</button>
24379
- <button class="myio-chart-widget-tab ${currentChartType === "bar" ? "active" : ""}" data-type="bar">Barras</button>
24479
+ <button class="myio-chart-widget-tab icon-only ${currentChartType === "line" ? "active" : ""}" data-type="line" title="Gr\xE1fico de Linhas">${lineChartIcon}</button>
24480
+ <button class="myio-chart-widget-tab icon-only ${currentChartType === "bar" ? "active" : ""}" data-type="bar" title="Gr\xE1fico de Barras">${barChartIcon}</button>
24380
24481
  </div>
24381
24482
  ` : ""}
24382
24483
  ${showMaximizeButton ? `
@@ -24413,19 +24514,22 @@ function createConsumptionChartWidget(config) {
24413
24514
  function renderSettingsModal() {
24414
24515
  const unit = config.unit ?? "";
24415
24516
  const isTemperature = config.domain === "temperature";
24517
+ const consolidadoIcon = `<svg viewBox="0 0 16 16" fill="currentColor" style="width:14px;height:14px;pointer-events:none"><rect x="3" y="3" width="10" height="10" rx="2"/></svg>`;
24518
+ const porShoppingIcon = `<svg viewBox="0 0 16 16" fill="currentColor" style="width:14px;height:14px;pointer-events:none"><rect x="1" y="1" width="6" height="6" rx="1"/><rect x="9" y="1" width="6" height="6" rx="1"/><rect x="1" y="9" width="6" height="6" rx="1"/><rect x="9" y="9" width="6" height="6" rx="1"/></svg>`;
24519
+ const lineChartIcon = `<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:14px;height:14px;pointer-events:none"><polyline points="2,12 5,7 9,9 14,3"/></svg>`;
24520
+ const barChartIcon = `<svg viewBox="0 0 16 16" fill="currentColor" style="width:14px;height:14px;pointer-events:none"><rect x="1" y="9" width="3" height="6" rx="0.5"/><rect x="6" y="5" width="3" height="10" rx="0.5"/><rect x="11" y="7" width="3" height="8" rx="0.5"/></svg>`;
24416
24521
  settingsHeaderInstance = createModalHeader({
24417
24522
  id: `${widgetId}-settings`,
24418
24523
  title: "Configura\xE7\xF5es",
24419
24524
  icon: "\u2699\uFE0F",
24420
24525
  theme: tempTheme,
24421
- backgroundColor: primaryColor,
24422
24526
  showThemeToggle: false,
24423
24527
  showMaximize: false,
24424
24528
  showClose: true,
24425
24529
  onClose: () => closeSettingsModal()
24426
24530
  });
24427
24531
  return `
24428
- <div id="${widgetId}-settings-overlay" class="myio-settings-overlay hidden">
24532
+ <div id="${widgetId}-settings-overlay" class="myio-settings-overlay myio-modal-scope hidden">
24429
24533
  <div class="myio-settings-card">
24430
24534
  ${settingsHeaderInstance.render()}
24431
24535
  <div class="myio-settings-body">
@@ -24436,13 +24540,8 @@ function createConsumptionChartWidget(config) {
24436
24540
  <div class="myio-settings-section-label">\u{1F4C5} Per\xEDodo</div>
24437
24541
  <div class="myio-settings-row">
24438
24542
  <div class="myio-settings-field" style="flex: 1;">
24439
- <select id="${widgetId}-settings-period" class="myio-settings-select">
24440
- <option value="7" ${tempPeriod === 7 ? "selected" : ""}>\xDAltimos 7 dias</option>
24441
- <option value="14" ${tempPeriod === 14 ? "selected" : ""}>\xDAltimos 14 dias</option>
24442
- <option value="30" ${tempPeriod === 30 ? "selected" : ""}>\xDAltimos 30 dias</option>
24443
- <option value="60" ${tempPeriod === 60 ? "selected" : ""}>\xDAltimos 60 dias</option>
24444
- <option value="90" ${tempPeriod === 90 ? "selected" : ""}>\xDAltimos 90 dias</option>
24445
- </select>
24543
+ <input type="text" id="${widgetId}-settings-daterange" class="myio-settings-input"
24544
+ readonly placeholder="Selecione o per\xEDodo..." style="cursor: pointer;">
24446
24545
  </div>
24447
24546
  </div>
24448
24547
  </div>
@@ -24571,8 +24670,8 @@ function createConsumptionChartWidget(config) {
24571
24670
  <div class="myio-settings-field" style="flex: 1; min-width: 180px;">
24572
24671
  <label class="myio-settings-field-label">Tipo de Gr\xE1fico</label>
24573
24672
  <div class="myio-settings-tabs" id="${widgetId}-settings-chart-type">
24574
- <button class="myio-settings-tab ${tempChartType === "line" ? "active" : ""}" data-type="line">\u{1F4C8} Linhas</button>
24575
- <button class="myio-settings-tab ${tempChartType === "bar" ? "active" : ""}" data-type="bar">\u{1F4CA} Barras</button>
24673
+ <button class="myio-settings-tab ${tempChartType === "line" ? "active" : ""}" data-type="line">${lineChartIcon} Linhas</button>
24674
+ <button class="myio-settings-tab ${tempChartType === "bar" ? "active" : ""}" data-type="bar">${barChartIcon} Barras</button>
24576
24675
  </div>
24577
24676
  </div>
24578
24677
 
@@ -24580,8 +24679,8 @@ function createConsumptionChartWidget(config) {
24580
24679
  <div class="myio-settings-field" style="flex: 1; min-width: 200px;">
24581
24680
  <label class="myio-settings-field-label">Agrupamento</label>
24582
24681
  <div class="myio-settings-tabs" id="${widgetId}-settings-viz-mode">
24583
- <button class="myio-settings-tab ${tempVizMode === "total" ? "active" : ""}" data-viz="total">\u{1F517} Consolidado</button>
24584
- <button class="myio-settings-tab ${tempVizMode === "separate" ? "active" : ""}" data-viz="separate">\u{1F3EC} Por Shopping</button>
24682
+ <button class="myio-settings-tab ${tempVizMode === "total" ? "active" : ""}" data-viz="total">${consolidadoIcon} Consolidado</button>
24683
+ <button class="myio-settings-tab ${tempVizMode === "separate" ? "active" : ""}" data-viz="separate">${porShoppingIcon} Por Shopping</button>
24585
24684
  </div>
24586
24685
  </div>
24587
24686
 
@@ -24723,18 +24822,21 @@ function createConsumptionChartWidget(config) {
24723
24822
  peakDateEl.textContent = peakDate;
24724
24823
  }
24725
24824
  }
24726
- function openSettingsModal() {
24825
+ async function openSettingsModal() {
24727
24826
  tempPeriod = currentPeriod;
24728
24827
  tempChartType = currentChartType;
24729
24828
  tempVizMode = currentVizMode;
24730
24829
  tempTheme = currentTheme;
24731
24830
  tempIdealRange = currentIdealRange ? { ...currentIdealRange } : null;
24831
+ dateRangePickerInstance = null;
24732
24832
  if (!settingsModalElement) {
24733
24833
  settingsModalElement = document.createElement("div");
24734
24834
  settingsModalElement.innerHTML = renderSettingsModal();
24735
24835
  document.body.appendChild(settingsModalElement.firstElementChild);
24736
24836
  settingsModalElement = document.getElementById(`${widgetId}-settings-overlay`);
24737
- setupSettingsModalListeners();
24837
+ await setupSettingsModalListeners();
24838
+ } else {
24839
+ await setupSettingsModalListeners();
24738
24840
  }
24739
24841
  updateSettingsModalValues();
24740
24842
  updateIdealRangeSuggestionTooltip();
@@ -24742,6 +24844,10 @@ function createConsumptionChartWidget(config) {
24742
24844
  }
24743
24845
  function closeSettingsModal() {
24744
24846
  settingsModalElement?.classList.add("hidden");
24847
+ if (dateRangePickerInstance) {
24848
+ dateRangePickerInstance.destroy();
24849
+ dateRangePickerInstance = null;
24850
+ }
24745
24851
  }
24746
24852
  function updateSettingsModalValues() {
24747
24853
  const periodSelect = document.getElementById(`${widgetId}-settings-period`);
@@ -24851,8 +24957,46 @@ function createConsumptionChartWidget(config) {
24851
24957
  label: "Faixa Sugerida"
24852
24958
  };
24853
24959
  }
24854
- function setupSettingsModalListeners() {
24960
+ async function setupSettingsModalListeners() {
24855
24961
  settingsHeaderInstance?.attachListeners();
24962
+ const dateRangeInput = document.getElementById(`${widgetId}-settings-daterange`);
24963
+ if (dateRangeInput && !dateRangePickerInstance) {
24964
+ try {
24965
+ const endDate = /* @__PURE__ */ new Date();
24966
+ const startDate = /* @__PURE__ */ new Date();
24967
+ startDate.setDate(endDate.getDate() - tempPeriod);
24968
+ const presetStart = tempStartDate || startDate.toISOString();
24969
+ const presetEnd = tempEndDate || endDate.toISOString();
24970
+ dateRangePickerInstance = await createDateRangePicker2(dateRangeInput, {
24971
+ presetStart,
24972
+ presetEnd,
24973
+ includeTime: true,
24974
+ timePrecision: "hour",
24975
+ maxRangeDays: 90,
24976
+ locale: "pt-BR",
24977
+ parentEl: document.getElementById(`${widgetId}-settings-overlay`),
24978
+ onApply: (result) => {
24979
+ tempStartDate = result.startISO;
24980
+ tempEndDate = result.endISO;
24981
+ const start = new Date(result.startISO);
24982
+ const end = new Date(result.endISO);
24983
+ const diffTime = Math.abs(end.getTime() - start.getTime());
24984
+ const diffHours = diffTime / (1e3 * 60 * 60);
24985
+ const diffDays = Math.ceil(diffTime / (1e3 * 60 * 60 * 24));
24986
+ tempPeriod = diffDays || 7;
24987
+ const granularitySelect = document.getElementById(`${widgetId}-settings-granularity`);
24988
+ if (granularitySelect && diffHours <= 48) {
24989
+ granularitySelect.value = "1h";
24990
+ const dayPeriodField = document.getElementById(`${widgetId}-settings-dayperiod-field`);
24991
+ if (dayPeriodField) dayPeriodField.style.display = "block";
24992
+ }
24993
+ console.log("[ConsumptionChartWidget] Date range applied:", { start: result.startISO, end: result.endISO, hours: diffHours, days: tempPeriod });
24994
+ }
24995
+ });
24996
+ } catch (error) {
24997
+ console.warn("[ConsumptionChartWidget] DateRangePicker initialization failed:", error);
24998
+ }
24999
+ }
24856
25000
  document.getElementById(`${widgetId}-settings-overlay`)?.addEventListener("click", (e) => {
24857
25001
  if (e.target.classList.contains("myio-settings-overlay")) {
24858
25002
  closeSettingsModal();
@@ -24940,13 +25084,56 @@ function createConsumptionChartWidget(config) {
24940
25084
  updateSettingsModalTabs();
24941
25085
  }
24942
25086
  });
24943
- document.getElementById(`${widgetId}-settings-reset`)?.addEventListener("click", () => {
25087
+ document.getElementById(`${widgetId}-settings-reset`)?.addEventListener("click", async () => {
24944
25088
  tempPeriod = config.defaultPeriod ?? 7;
24945
25089
  tempChartType = config.defaultChartType ?? "line";
24946
25090
  tempVizMode = config.defaultVizMode ?? "total";
24947
25091
  tempTheme = config.theme ?? "light";
24948
25092
  tempIdealRange = config.idealRange ?? null;
24949
- const granularitySelect = document.getElementById(`${widgetId}-settings-granularity`);
25093
+ tempStartDate = null;
25094
+ tempEndDate = null;
25095
+ if (dateRangePickerInstance) {
25096
+ dateRangePickerInstance.destroy();
25097
+ dateRangePickerInstance = null;
25098
+ }
25099
+ const dateRangeInput2 = document.getElementById(`${widgetId}-settings-daterange`);
25100
+ if (dateRangeInput2) {
25101
+ const endDate = /* @__PURE__ */ new Date();
25102
+ const startDate = /* @__PURE__ */ new Date();
25103
+ startDate.setDate(endDate.getDate() - tempPeriod);
25104
+ try {
25105
+ dateRangePickerInstance = await createDateRangePicker2(dateRangeInput2, {
25106
+ presetStart: startDate.toISOString(),
25107
+ presetEnd: endDate.toISOString(),
25108
+ includeTime: true,
25109
+ timePrecision: "hour",
25110
+ maxRangeDays: 90,
25111
+ locale: "pt-BR",
25112
+ parentEl: document.getElementById(`${widgetId}-settings-overlay`),
25113
+ onApply: (result) => {
25114
+ tempStartDate = result.startISO;
25115
+ tempEndDate = result.endISO;
25116
+ const start = new Date(result.startISO);
25117
+ const end = new Date(result.endISO);
25118
+ const diffTime = Math.abs(end.getTime() - start.getTime());
25119
+ const diffHours = diffTime / (1e3 * 60 * 60);
25120
+ const diffDays = Math.ceil(diffTime / (1e3 * 60 * 60 * 24));
25121
+ tempPeriod = diffDays || 7;
25122
+ const granularitySelect2 = document.getElementById(`${widgetId}-settings-granularity`);
25123
+ if (granularitySelect2 && diffHours <= 48) {
25124
+ granularitySelect2.value = "1h";
25125
+ const dayPeriodField2 = document.getElementById(`${widgetId}-settings-dayperiod-field`);
25126
+ if (dayPeriodField2) dayPeriodField2.style.display = "block";
25127
+ }
25128
+ }
25129
+ });
25130
+ } catch (error) {
25131
+ console.warn("[ConsumptionChartWidget] DateRangePicker reset failed:", error);
25132
+ }
25133
+ }
25134
+ const granularitySelect = document.getElementById(
25135
+ `${widgetId}-settings-granularity`
25136
+ );
24950
25137
  if (granularitySelect) granularitySelect.value = "1d";
24951
25138
  const dayPeriodField = document.getElementById(`${widgetId}-settings-dayperiod-field`);
24952
25139
  if (dayPeriodField) dayPeriodField.style.display = "none";
@@ -25092,6 +25279,10 @@ function createConsumptionChartWidget(config) {
25092
25279
  }
25093
25280
  settingsHeaderInstance?.destroy();
25094
25281
  settingsHeaderInstance = null;
25282
+ if (dateRangePickerInstance) {
25283
+ dateRangePickerInstance.destroy();
25284
+ dateRangePickerInstance = null;
25285
+ }
25095
25286
  if (settingsModalElement) {
25096
25287
  settingsModalElement.remove();
25097
25288
  settingsModalElement = null;
@@ -25543,6 +25734,581 @@ var EXPORT_DEFAULT_COLORS = DEFAULT_COLORS4;
25543
25734
  var EXPORT_DOMAIN_ICONS = DOMAIN_ICONS;
25544
25735
  var EXPORT_DOMAIN_LABELS = DOMAIN_LABELS;
25545
25736
  var EXPORT_DOMAIN_UNITS = DOMAIN_UNITS;
25737
+
25738
+ // src/components/DistributionChart/colorManager.ts
25739
+ var DEFAULT_SHOPPING_COLORS = [
25740
+ "#3b82f6",
25741
+ // Blue
25742
+ "#8b5cf6",
25743
+ // Purple
25744
+ "#f59e0b",
25745
+ // Amber
25746
+ "#ef4444",
25747
+ // Red
25748
+ "#10b981",
25749
+ // Emerald
25750
+ "#06b6d4",
25751
+ // Cyan
25752
+ "#ec4899",
25753
+ // Pink
25754
+ "#14b8a6",
25755
+ // Teal
25756
+ "#f97316",
25757
+ // Orange
25758
+ "#a855f7"
25759
+ // Violet
25760
+ ];
25761
+ var DEFAULT_ENERGY_GROUP_COLORS = {
25762
+ "Elevadores": "#3b82f6",
25763
+ "Escadas Rolantes": "#8b5cf6",
25764
+ "Climatiza\xE7\xE3o": "#f59e0b",
25765
+ "Climatizacao": "#f59e0b",
25766
+ // Without accent
25767
+ "Outros Equipamentos": "#ef4444",
25768
+ "Lojas": "#10b981"
25769
+ };
25770
+ var DEFAULT_WATER_GROUP_COLORS = {
25771
+ "Lojas": "#10b981",
25772
+ "\xC1rea Comum": "#0288d1",
25773
+ "Area Comum": "#0288d1"
25774
+ // Without accent
25775
+ };
25776
+ var DEFAULT_GAS_GROUP_COLORS = {
25777
+ "Cozinha": "#f59e0b",
25778
+ "Aquecimento": "#ef4444",
25779
+ "Outros": "#94a3b8"
25780
+ };
25781
+ function getDefaultGroupColors(domain) {
25782
+ switch (domain.toLowerCase()) {
25783
+ case "energy":
25784
+ return DEFAULT_ENERGY_GROUP_COLORS;
25785
+ case "water":
25786
+ return DEFAULT_WATER_GROUP_COLORS;
25787
+ case "gas":
25788
+ return DEFAULT_GAS_GROUP_COLORS;
25789
+ default:
25790
+ return DEFAULT_ENERGY_GROUP_COLORS;
25791
+ }
25792
+ }
25793
+ function assignShoppingColors(shoppingIds) {
25794
+ const colors = {};
25795
+ shoppingIds.forEach((id, index) => {
25796
+ colors[id] = DEFAULT_SHOPPING_COLORS[index % DEFAULT_SHOPPING_COLORS.length];
25797
+ });
25798
+ return colors;
25799
+ }
25800
+ function getShoppingColor(shoppingId, shoppingColors, fallbackIndex = 0) {
25801
+ if (shoppingColors && shoppingColors[shoppingId]) {
25802
+ return shoppingColors[shoppingId];
25803
+ }
25804
+ if (shoppingColors) {
25805
+ const normalizedId = shoppingId.toLowerCase();
25806
+ for (const [key, color] of Object.entries(shoppingColors)) {
25807
+ if (key.toLowerCase() === normalizedId || key.toLowerCase().includes(normalizedId)) {
25808
+ return color;
25809
+ }
25810
+ }
25811
+ }
25812
+ return DEFAULT_SHOPPING_COLORS[Math.abs(fallbackIndex) % DEFAULT_SHOPPING_COLORS.length];
25813
+ }
25814
+ function getGroupColor(groupName, groupColors, domain = "energy", fallbackIndex = 0) {
25815
+ if (groupColors && groupColors[groupName]) {
25816
+ return groupColors[groupName];
25817
+ }
25818
+ const defaultColors = getDefaultGroupColors(domain);
25819
+ if (defaultColors[groupName]) {
25820
+ return defaultColors[groupName];
25821
+ }
25822
+ return DEFAULT_SHOPPING_COLORS[Math.abs(fallbackIndex) % DEFAULT_SHOPPING_COLORS.length];
25823
+ }
25824
+ function getThemeColors2(theme) {
25825
+ if (theme === "dark") {
25826
+ return {
25827
+ text: "#f3f4f6",
25828
+ secondaryText: "#9ca3af",
25829
+ background: "#111827",
25830
+ cardBackground: "#1f2937",
25831
+ border: "#374151",
25832
+ grid: "#374151"
25833
+ };
25834
+ }
25835
+ return {
25836
+ text: "#1f2937",
25837
+ secondaryText: "#6b7280",
25838
+ background: "#f5f5f5",
25839
+ cardBackground: "#ffffff",
25840
+ border: "#e5e7eb",
25841
+ grid: "#e5e7eb"
25842
+ };
25843
+ }
25844
+ function getHashColor(str) {
25845
+ let hash = 0;
25846
+ for (let i = 0; i < str.length; i++) {
25847
+ const char = str.charCodeAt(i);
25848
+ hash = (hash << 5) - hash + char;
25849
+ hash = hash & hash;
25850
+ }
25851
+ return DEFAULT_SHOPPING_COLORS[Math.abs(hash) % DEFAULT_SHOPPING_COLORS.length];
25852
+ }
25853
+
25854
+ // src/components/DistributionChart/createDistributionChartWidget.ts
25855
+ var settingsIcon = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:16px;height:16px;pointer-events:none"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>`;
25856
+ var maximizeIcon = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:16px;height:16px;pointer-events:none"><polyline points="15 3 21 3 21 9"/><polyline points="9 21 3 21 3 15"/><line x1="21" y1="3" x2="14" y2="10"/><line x1="3" y1="21" x2="10" y2="14"/></svg>`;
25857
+ function createDistributionChartWidget(config) {
25858
+ const widgetId = `distribution-${config.domain}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
25859
+ let chartInstance = null;
25860
+ let currentMode = config.defaultMode || "groups";
25861
+ let currentTheme = config.theme || "light";
25862
+ let currentData = null;
25863
+ let containerElement = null;
25864
+ let isLoading = false;
25865
+ const title = config.title || getDomainTitle(config.domain);
25866
+ const chartHeight = config.chartHeight || 300;
25867
+ const showHeader = config.showHeader !== false;
25868
+ const showModeSelector = config.showModeSelector !== false;
25869
+ const showSettingsButton = config.showSettingsButton ?? false;
25870
+ const showMaximizeButton = config.showMaximizeButton ?? false;
25871
+ const decimalPlaces = config.decimalPlaces ?? 2;
25872
+ const modes = config.modes || getDefaultModes(config.domain);
25873
+ const groupColors = config.groupColors || getDefaultGroupColors(config.domain);
25874
+ function getDomainTitle(domain) {
25875
+ const titles = {
25876
+ energy: "Distribui\xE7\xE3o de Energia",
25877
+ water: "Distribui\xE7\xE3o de \xC1gua",
25878
+ gas: "Distribui\xE7\xE3o de G\xE1s",
25879
+ temperature: "Distribui\xE7\xE3o de Temperatura"
25880
+ };
25881
+ return titles[domain.toLowerCase()] || `Distribui\xE7\xE3o de ${domain}`;
25882
+ }
25883
+ function getDefaultModes(domain) {
25884
+ if (domain === "water") {
25885
+ return [
25886
+ { value: "groups", label: "Lojas vs \xC1rea Comum" },
25887
+ { value: "stores", label: "Lojas por Shopping" },
25888
+ { value: "common", label: "\xC1rea Comum por Shopping" }
25889
+ ];
25890
+ }
25891
+ return [
25892
+ { value: "groups", label: "Por Grupos de Equipamentos" },
25893
+ { value: "elevators", label: "Elevadores por Shopping" },
25894
+ { value: "escalators", label: "Escadas Rolantes por Shopping" },
25895
+ { value: "hvac", label: "Climatiza\xE7\xE3o por Shopping" },
25896
+ { value: "others", label: "Outros Equipamentos por Shopping" },
25897
+ { value: "stores", label: "Lojas por Shopping" }
25898
+ ];
25899
+ }
25900
+ function $id(id) {
25901
+ if (config.$container) {
25902
+ return config.$container[0].querySelector(`#${id}`);
25903
+ }
25904
+ return document.getElementById(id);
25905
+ }
25906
+ function formatValue(value) {
25907
+ if (config.unitLarge && config.thresholdForLargeUnit && value >= config.thresholdForLargeUnit) {
25908
+ return `${(value / config.thresholdForLargeUnit).toFixed(decimalPlaces)} ${config.unitLarge}`;
25909
+ }
25910
+ return `${value.toFixed(decimalPlaces)} ${config.unit}`;
25911
+ }
25912
+ function getColor(key, index, isGroupMode2) {
25913
+ if (isGroupMode2) {
25914
+ return getGroupColor(key, groupColors, config.domain, index);
25915
+ }
25916
+ const shoppingColors = config.getShoppingColors?.();
25917
+ return getShoppingColor(key, shoppingColors, index);
25918
+ }
25919
+ function getColors2() {
25920
+ return getThemeColors2(currentTheme);
25921
+ }
25922
+ function isGroupMode() {
25923
+ return currentMode === "groups";
25924
+ }
25925
+ function renderHTML() {
25926
+ const colors = getColors2();
25927
+ const modeOptions = modes.map(
25928
+ (m) => `<option value="${m.value}" ${m.value === currentMode ? "selected" : ""}>${m.label}</option>`
25929
+ ).join("");
25930
+ const headerButtons = [];
25931
+ if (showSettingsButton) {
25932
+ headerButtons.push(`
25933
+ <button id="${widgetId}-settings-btn" class="myio-dist-btn" title="Configura\xE7\xF5es">
25934
+ ${settingsIcon}
25935
+ </button>
25936
+ `);
25937
+ }
25938
+ if (showMaximizeButton) {
25939
+ headerButtons.push(`
25940
+ <button id="${widgetId}-maximize-btn" class="myio-dist-btn" title="Expandir">
25941
+ ${maximizeIcon}
25942
+ </button>
25943
+ `);
25944
+ }
25945
+ return `
25946
+ <style>
25947
+ #${widgetId} {
25948
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
25949
+ }
25950
+ #${widgetId} .myio-dist-header {
25951
+ display: flex;
25952
+ justify-content: space-between;
25953
+ align-items: center;
25954
+ margin-bottom: 16px;
25955
+ flex-wrap: wrap;
25956
+ gap: 12px;
25957
+ }
25958
+ #${widgetId} .myio-dist-title {
25959
+ margin: 0;
25960
+ font-size: 16px;
25961
+ font-weight: 600;
25962
+ color: ${colors.text};
25963
+ }
25964
+ #${widgetId} .myio-dist-controls {
25965
+ display: flex;
25966
+ align-items: center;
25967
+ gap: 8px;
25968
+ }
25969
+ #${widgetId} .myio-dist-label {
25970
+ font-size: 12px;
25971
+ color: ${colors.secondaryText};
25972
+ }
25973
+ #${widgetId} .myio-dist-select {
25974
+ padding: 6px 10px;
25975
+ border-radius: 6px;
25976
+ border: 1px solid ${colors.border};
25977
+ background: ${colors.cardBackground};
25978
+ color: ${colors.text};
25979
+ font-size: 12px;
25980
+ cursor: pointer;
25981
+ min-width: 180px;
25982
+ }
25983
+ #${widgetId} .myio-dist-select:focus {
25984
+ outline: none;
25985
+ border-color: #3e1a7d;
25986
+ }
25987
+ #${widgetId} .myio-dist-btn {
25988
+ display: flex;
25989
+ align-items: center;
25990
+ justify-content: center;
25991
+ padding: 6px 8px;
25992
+ border: 1px solid ${colors.border};
25993
+ border-radius: 6px;
25994
+ background: transparent;
25995
+ color: ${colors.text};
25996
+ cursor: pointer;
25997
+ transition: all 0.2s;
25998
+ }
25999
+ #${widgetId} .myio-dist-btn:hover {
26000
+ background: #3e1a7d;
26001
+ border-color: #3e1a7d;
26002
+ color: white;
26003
+ }
26004
+ #${widgetId} .myio-dist-chart-container {
26005
+ position: relative;
26006
+ height: ${chartHeight}px;
26007
+ }
26008
+ #${widgetId} .myio-dist-loading {
26009
+ position: absolute;
26010
+ top: 0;
26011
+ left: 0;
26012
+ right: 0;
26013
+ bottom: 0;
26014
+ display: flex;
26015
+ align-items: center;
26016
+ justify-content: center;
26017
+ background: ${colors.cardBackground}ee;
26018
+ z-index: 10;
26019
+ }
26020
+ #${widgetId} .myio-dist-spinner {
26021
+ width: 32px;
26022
+ height: 32px;
26023
+ border: 3px solid ${colors.border};
26024
+ border-top-color: #3e1a7d;
26025
+ border-radius: 50%;
26026
+ animation: myio-dist-spin 0.8s linear infinite;
26027
+ }
26028
+ @keyframes myio-dist-spin {
26029
+ to { transform: rotate(360deg); }
26030
+ }
26031
+ #${widgetId} .myio-dist-empty {
26032
+ display: flex;
26033
+ flex-direction: column;
26034
+ align-items: center;
26035
+ justify-content: center;
26036
+ height: 100%;
26037
+ color: ${colors.secondaryText};
26038
+ font-size: 14px;
26039
+ }
26040
+ #${widgetId} .myio-dist-empty-icon {
26041
+ font-size: 48px;
26042
+ margin-bottom: 12px;
26043
+ opacity: 0.5;
26044
+ }
26045
+ </style>
26046
+
26047
+ <div id="${widgetId}" class="myio-distribution-widget" style="
26048
+ background: ${colors.cardBackground};
26049
+ border-radius: 12px;
26050
+ padding: 16px;
26051
+ height: 100%;
26052
+ display: flex;
26053
+ flex-direction: column;
26054
+ ">
26055
+ ${showHeader ? `
26056
+ <div class="myio-dist-header">
26057
+ <h4 class="myio-dist-title">${title}</h4>
26058
+ <div class="myio-dist-controls">
26059
+ ${showModeSelector && modes.length > 1 ? `
26060
+ <label for="${widgetId}-mode" class="myio-dist-label">Visualizar:</label>
26061
+ <select id="${widgetId}-mode" class="myio-dist-select">
26062
+ ${modeOptions}
26063
+ </select>
26064
+ ` : ""}
26065
+ ${headerButtons.join("")}
26066
+ </div>
26067
+ </div>
26068
+ ` : ""}
26069
+
26070
+ <div class="myio-dist-chart-container">
26071
+ <canvas id="${widgetId}-canvas"></canvas>
26072
+ <div id="${widgetId}-loading" class="myio-dist-loading" style="display: none;">
26073
+ <div class="myio-dist-spinner"></div>
26074
+ </div>
26075
+ </div>
26076
+ </div>
26077
+ `;
26078
+ }
26079
+ function setLoading(loading) {
26080
+ isLoading = loading;
26081
+ const loadingEl = $id(`${widgetId}-loading`);
26082
+ if (loadingEl) {
26083
+ loadingEl.style.display = loading ? "flex" : "none";
26084
+ }
26085
+ }
26086
+ function buildChartData(distribution) {
26087
+ const labels = [];
26088
+ const data = [];
26089
+ const backgroundColors = [];
26090
+ const total = Object.values(distribution).reduce((sum, val) => sum + val, 0);
26091
+ const isGroup = isGroupMode();
26092
+ const entries = Object.entries(distribution).filter(([_, value]) => value > 0).sort((a, b) => b[1] - a[1]);
26093
+ entries.forEach(([key, value], index) => {
26094
+ const percentage = total > 0 ? (value / total * 100).toFixed(1) : "0";
26095
+ labels.push(`${key} (${formatValue(value)} - ${percentage}%)`);
26096
+ data.push(value);
26097
+ backgroundColors.push(getColor(key, index, isGroup));
26098
+ });
26099
+ return { labels, data, backgroundColors, total };
26100
+ }
26101
+ function renderEmptyState() {
26102
+ const container = $id(`${widgetId}-canvas`)?.parentElement;
26103
+ if (container) {
26104
+ const emptyEl = document.createElement("div");
26105
+ emptyEl.className = "myio-dist-empty";
26106
+ emptyEl.innerHTML = `
26107
+ <div class="myio-dist-empty-icon">\u{1F4CA}</div>
26108
+ <div>Sem dados dispon\xEDveis</div>
26109
+ `;
26110
+ const canvas = $id(`${widgetId}-canvas`);
26111
+ if (canvas) canvas.style.display = "none";
26112
+ const existingEmpty = container.querySelector(".myio-dist-empty");
26113
+ if (!existingEmpty) {
26114
+ container.appendChild(emptyEl);
26115
+ }
26116
+ }
26117
+ }
26118
+ function removeEmptyState() {
26119
+ const container = $id(`${widgetId}-canvas`)?.parentElement;
26120
+ if (container) {
26121
+ const emptyEl = container.querySelector(".myio-dist-empty");
26122
+ if (emptyEl) emptyEl.remove();
26123
+ const canvas = $id(`${widgetId}-canvas`);
26124
+ if (canvas) canvas.style.display = "block";
26125
+ }
26126
+ }
26127
+ async function updateChart() {
26128
+ const canvas = $id(`${widgetId}-canvas`);
26129
+ if (!canvas) {
26130
+ console.error(`[${config.domain.toUpperCase()}] Distribution canvas not found`);
26131
+ return;
26132
+ }
26133
+ setLoading(true);
26134
+ try {
26135
+ const distribution = await config.fetchDistribution(currentMode);
26136
+ if (!distribution || Object.keys(distribution).length === 0) {
26137
+ console.warn(`[${config.domain.toUpperCase()}] No distribution data for mode: ${currentMode}`);
26138
+ currentData = null;
26139
+ setLoading(false);
26140
+ renderEmptyState();
26141
+ return;
26142
+ }
26143
+ removeEmptyState();
26144
+ currentData = distribution;
26145
+ const { labels, data, backgroundColors, total } = buildChartData(distribution);
26146
+ const colors = getColors2();
26147
+ const Chart2 = window.Chart;
26148
+ if (!Chart2) {
26149
+ throw new Error("Chart.js not loaded");
26150
+ }
26151
+ if (chartInstance) {
26152
+ chartInstance.destroy();
26153
+ chartInstance = null;
26154
+ }
26155
+ const ctx = canvas.getContext("2d");
26156
+ if (!ctx) {
26157
+ throw new Error("Could not get canvas context");
26158
+ }
26159
+ chartInstance = new Chart2(ctx, {
26160
+ type: "bar",
26161
+ data: {
26162
+ labels,
26163
+ datasets: [
26164
+ {
26165
+ label: `Consumo (${config.unit})`,
26166
+ data,
26167
+ backgroundColor: backgroundColors
26168
+ }
26169
+ ]
26170
+ },
26171
+ options: {
26172
+ responsive: true,
26173
+ maintainAspectRatio: false,
26174
+ indexAxis: "y",
26175
+ // Horizontal bar chart
26176
+ animation: false,
26177
+ plugins: {
26178
+ legend: { display: false },
26179
+ tooltip: {
26180
+ callbacks: {
26181
+ label: (context) => {
26182
+ const value = context.parsed.x || 0;
26183
+ const percentage = total > 0 ? (value / total * 100).toFixed(1) : "0";
26184
+ return `${formatValue(value)} (${percentage}%)`;
26185
+ }
26186
+ }
26187
+ }
26188
+ },
26189
+ scales: {
26190
+ x: {
26191
+ beginAtZero: true,
26192
+ ticks: {
26193
+ callback: (value) => formatValue(Number(value)),
26194
+ color: colors.secondaryText,
26195
+ font: { size: 11 }
26196
+ },
26197
+ grid: { color: colors.grid }
26198
+ },
26199
+ y: {
26200
+ ticks: {
26201
+ font: { size: 11 },
26202
+ color: colors.text
26203
+ },
26204
+ grid: { display: false }
26205
+ }
26206
+ }
26207
+ }
26208
+ });
26209
+ config.onDataLoaded?.(distribution);
26210
+ console.log(`[${config.domain.toUpperCase()}] Distribution chart updated for mode: ${currentMode}`);
26211
+ } catch (error) {
26212
+ console.error(`[${config.domain.toUpperCase()}] Error updating distribution chart:`, error);
26213
+ config.onError?.(error);
26214
+ renderEmptyState();
26215
+ } finally {
26216
+ setLoading(false);
26217
+ }
26218
+ }
26219
+ function setupListeners() {
26220
+ const modeSelect = $id(`${widgetId}-mode`);
26221
+ if (modeSelect) {
26222
+ modeSelect.addEventListener("change", async (e) => {
26223
+ currentMode = e.target.value;
26224
+ config.onModeChange?.(currentMode);
26225
+ await updateChart();
26226
+ });
26227
+ }
26228
+ if (showSettingsButton) {
26229
+ const settingsBtn = $id(`${widgetId}-settings-btn`);
26230
+ if (settingsBtn) {
26231
+ settingsBtn.addEventListener("click", () => {
26232
+ config.onSettingsClick?.();
26233
+ });
26234
+ }
26235
+ }
26236
+ if (showMaximizeButton) {
26237
+ const maximizeBtn = $id(`${widgetId}-maximize-btn`);
26238
+ if (maximizeBtn) {
26239
+ maximizeBtn.addEventListener("click", () => {
26240
+ config.onMaximizeClick?.();
26241
+ });
26242
+ }
26243
+ }
26244
+ }
26245
+ function updateThemeStyles() {
26246
+ const colors = getColors2();
26247
+ const widget = $id(widgetId);
26248
+ if (widget) {
26249
+ widget.style.background = colors.cardBackground;
26250
+ const title2 = widget.querySelector(".myio-dist-title");
26251
+ if (title2) title2.style.color = colors.text;
26252
+ const labels = widget.querySelectorAll(".myio-dist-label");
26253
+ labels.forEach((l) => l.style.color = colors.secondaryText);
26254
+ const select = widget.querySelector(".myio-dist-select");
26255
+ if (select) {
26256
+ select.style.background = colors.cardBackground;
26257
+ select.style.color = colors.text;
26258
+ select.style.borderColor = colors.border;
26259
+ }
26260
+ const buttons = widget.querySelectorAll(".myio-dist-btn");
26261
+ buttons.forEach((b) => {
26262
+ b.style.color = colors.text;
26263
+ b.style.borderColor = colors.border;
26264
+ });
26265
+ }
26266
+ }
26267
+ const instance = {
26268
+ async render() {
26269
+ containerElement = $id(config.containerId);
26270
+ if (!containerElement) {
26271
+ throw new Error(`Container #${config.containerId} not found`);
26272
+ }
26273
+ containerElement.innerHTML = renderHTML();
26274
+ setupListeners();
26275
+ await updateChart();
26276
+ },
26277
+ async setMode(mode) {
26278
+ currentMode = mode;
26279
+ const modeSelect = $id(`${widgetId}-mode`);
26280
+ if (modeSelect) {
26281
+ modeSelect.value = mode;
26282
+ }
26283
+ config.onModeChange?.(mode);
26284
+ await updateChart();
26285
+ },
26286
+ async refresh() {
26287
+ await updateChart();
26288
+ },
26289
+ setTheme(theme) {
26290
+ currentTheme = theme;
26291
+ updateThemeStyles();
26292
+ if (currentData) {
26293
+ updateChart();
26294
+ }
26295
+ },
26296
+ destroy() {
26297
+ if (chartInstance) {
26298
+ chartInstance.destroy();
26299
+ chartInstance = null;
26300
+ }
26301
+ if (containerElement) {
26302
+ containerElement.innerHTML = "";
26303
+ }
26304
+ currentData = null;
26305
+ },
26306
+ getChartInstance: () => chartInstance,
26307
+ getCurrentMode: () => currentMode,
26308
+ getCurrentData: () => currentData
26309
+ };
26310
+ return instance;
26311
+ }
25546
26312
  export {
25547
26313
  CHART_COLORS,
25548
26314
  DEFAULT_COLORS as CONSUMPTION_CHART_COLORS,
@@ -25550,6 +26316,10 @@ export {
25550
26316
  THEME_COLORS as CONSUMPTION_THEME_COLORS,
25551
26317
  ConnectionStatusType,
25552
26318
  DEFAULT_CLAMP_RANGE,
26319
+ DEFAULT_ENERGY_GROUP_COLORS,
26320
+ DEFAULT_GAS_GROUP_COLORS,
26321
+ DEFAULT_SHOPPING_COLORS,
26322
+ DEFAULT_WATER_GROUP_COLORS,
25553
26323
  DeviceStatusType,
25554
26324
  EXPORT_DEFAULT_COLORS,
25555
26325
  EXPORT_DOMAIN_ICONS,
@@ -25563,6 +26333,7 @@ export {
25563
26333
  addDetectionContext,
25564
26334
  addNamespace,
25565
26335
  aggregateByDay,
26336
+ assignShoppingColors,
25566
26337
  averageByDay,
25567
26338
  buildListItemsThingsboardByUniqueDatasource,
25568
26339
  buildMyioIngestionAuth,
@@ -25584,6 +26355,7 @@ export {
25584
26355
  createConsumptionChartWidget,
25585
26356
  createConsumptionModal,
25586
26357
  createDateRangePicker2 as createDateRangePicker,
26358
+ createDistributionChartWidget,
25587
26359
  createInputDateRangePickerInsideDIV,
25588
26360
  createModalHeader,
25589
26361
  decodePayload,
@@ -25622,11 +26394,16 @@ export {
25622
26394
  getAvailableContexts,
25623
26395
  getConnectionStatusIcon,
25624
26396
  getDateRangeArray,
26397
+ getDefaultGroupColors,
25625
26398
  getDeviceStatusIcon,
25626
26399
  getDeviceStatusInfo,
26400
+ getThemeColors2 as getDistributionThemeColors,
26401
+ getGroupColor,
26402
+ getHashColor,
25627
26403
  getModalHeaderStyles,
25628
26404
  getSaoPauloISOString,
25629
26405
  getSaoPauloISOStringFixed,
26406
+ getShoppingColor,
25630
26407
  getValueByDatakey,
25631
26408
  getValueByDatakeyLegacy,
25632
26409
  getWaterCategories,