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.
@@ -20345,7 +20345,7 @@ ${rangeText}`;
20345
20345
  const contentMaxHeight = isMaximized ? "100vh" : "95vh";
20346
20346
  const contentBorderRadius = isMaximized ? "0" : "10px";
20347
20347
  container.innerHTML = `
20348
- <div class="myio-temp-modal-overlay" style="
20348
+ <div class="myio-temp-modal-overlay myio-modal-scope" style="
20349
20349
  position: fixed; top: 0; left: 0; width: 100%; height: 100%;
20350
20350
  background: rgba(0, 0, 0, 0.5); z-index: 9998;
20351
20351
  display: flex; justify-content: center; align-items: center;
@@ -20600,6 +20600,22 @@ ${rangeText}`;
20600
20600
  background: rgba(255, 255, 255, 0.1) !important;
20601
20601
  color: white !important;
20602
20602
  }
20603
+
20604
+ /* DateRangePicker styles */
20605
+ ${CSS_TOKENS}
20606
+ ${DATERANGEPICKER_STYLES}
20607
+
20608
+ /* Fix DateRangePicker buttons alignment */
20609
+ .myio-modal-scope .daterangepicker .drp-buttons {
20610
+ display: flex;
20611
+ justify-content: flex-end;
20612
+ align-items: center;
20613
+ gap: 8px;
20614
+ }
20615
+ .myio-modal-scope .daterangepicker .drp-buttons .btn {
20616
+ display: inline-block;
20617
+ margin-left: 0;
20618
+ }
20603
20619
  </style>
20604
20620
  `;
20605
20621
  }
@@ -23395,11 +23411,16 @@ ${rangeText}`;
23395
23411
  let isMaximized = false;
23396
23412
  const domainCfg = DOMAIN_CONFIG3[config.domain] || { name: config.domain, icon: "\u{1F4CA}" };
23397
23413
  const title = config.title || `${domainCfg.name} - Hist\xF3rico de Consumo`;
23398
- function getThemeColors2() {
23414
+ function getThemeColors3() {
23399
23415
  return THEME_COLORS[currentTheme];
23400
23416
  }
23417
+ 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>`;
23418
+ 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>`;
23419
+ 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>`;
23420
+ 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>`;
23421
+ const showSettingsButton = config.showSettingsButton ?? true;
23401
23422
  function renderModal4() {
23402
- const colors = getThemeColors2();
23423
+ const colors = getThemeColors3();
23403
23424
  const exportFormats = config.exportFormats || ["csv"];
23404
23425
  headerInstance = createModalHeader({
23405
23426
  id: modalId,
@@ -23432,7 +23453,55 @@ ${rangeText}`;
23432
23453
  instance.close();
23433
23454
  }
23434
23455
  });
23456
+ const btnBaseStyle = `
23457
+ display: flex;
23458
+ align-items: center;
23459
+ justify-content: center;
23460
+ gap: 6px;
23461
+ padding: 6px 12px;
23462
+ border: none;
23463
+ border-radius: 6px;
23464
+ font-size: 12px;
23465
+ font-weight: 500;
23466
+ cursor: pointer;
23467
+ transition: all 0.2s;
23468
+ white-space: nowrap;
23469
+ `.replace(/\s+/g, " ").trim();
23470
+ const tabBgColor = currentTheme === "dark" ? "#4b5563" : "#e5e7eb";
23471
+ const activeColor = "#3e1a7d";
23472
+ const inactiveTextColor = colors.text;
23435
23473
  return `
23474
+ <style>
23475
+ .myio-modal-tab-btn {
23476
+ ${btnBaseStyle}
23477
+ }
23478
+ .myio-modal-tab-btn:hover {
23479
+ opacity: 0.85;
23480
+ }
23481
+ .myio-modal-tab-btn.active {
23482
+ background: ${activeColor} !important;
23483
+ color: white !important;
23484
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
23485
+ }
23486
+ .myio-modal-tab-btn svg {
23487
+ pointer-events: none;
23488
+ }
23489
+ .myio-modal-settings-btn {
23490
+ background: transparent;
23491
+ border: 1px solid ${colors.border};
23492
+ font-size: 16px;
23493
+ cursor: pointer;
23494
+ padding: 6px 10px;
23495
+ border-radius: 6px;
23496
+ transition: all 0.2s;
23497
+ color: ${colors.text};
23498
+ }
23499
+ .myio-modal-settings-btn:hover {
23500
+ background: ${activeColor};
23501
+ border-color: ${activeColor};
23502
+ color: white;
23503
+ }
23504
+ </style>
23436
23505
  <div class="myio-consumption-modal-overlay" style="
23437
23506
  position: fixed;
23438
23507
  top: 0;
@@ -23463,59 +23532,44 @@ ${rangeText}`;
23463
23532
  <!-- Controls Bar -->
23464
23533
  <div class="myio-consumption-modal-controls" style="
23465
23534
  display: flex;
23466
- gap: 16px;
23535
+ gap: 12px;
23467
23536
  padding: 12px 16px;
23468
23537
  background: ${currentTheme === "dark" ? "#374151" : "#f7f7f7"};
23469
23538
  border-bottom: 1px solid ${colors.border};
23470
23539
  align-items: center;
23471
23540
  flex-wrap: wrap;
23472
23541
  ">
23542
+ <!-- Settings Button -->
23543
+ ${showSettingsButton ? `
23544
+ <button id="${modalId}-settings-btn" class="myio-modal-settings-btn" title="Configura\xE7\xF5es">\u2699\uFE0F</button>
23545
+ ` : ""}
23546
+
23473
23547
  <!-- Viz Mode Tabs -->
23474
- <div style="display: flex; gap: 2px; background: ${currentTheme === "dark" ? "#4b5563" : "#e5e7eb"}; border-radius: 8px; padding: 2px;">
23475
- <button id="${modalId}-viz-total" style="
23476
- padding: 6px 12px;
23477
- border: none;
23478
- border-radius: 6px;
23479
- font-size: 13px;
23480
- cursor: pointer;
23481
- transition: all 0.2s;
23482
- background: ${currentVizMode === "total" ? "#3e1a7d" : "transparent"};
23483
- color: ${currentVizMode === "total" ? "white" : colors.text};
23484
- ">Consolidado</button>
23485
- <button id="${modalId}-viz-separate" style="
23486
- padding: 6px 12px;
23487
- border: none;
23488
- border-radius: 6px;
23489
- font-size: 13px;
23490
- cursor: pointer;
23491
- transition: all 0.2s;
23492
- background: ${currentVizMode === "separate" ? "#3e1a7d" : "transparent"};
23493
- color: ${currentVizMode === "separate" ? "white" : colors.text};
23494
- ">Por Shopping</button>
23548
+ <div style="display: flex; gap: 2px; background: ${tabBgColor}; border-radius: 8px; padding: 3px;">
23549
+ <button id="${modalId}-viz-total" class="myio-modal-tab-btn ${currentVizMode === "total" ? "active" : ""}"
23550
+ data-viz="total" title="Consolidado"
23551
+ style="background: ${currentVizMode === "total" ? activeColor : "transparent"}; color: ${currentVizMode === "total" ? "white" : inactiveTextColor};">
23552
+ ${consolidadoIcon}
23553
+ </button>
23554
+ <button id="${modalId}-viz-separate" class="myio-modal-tab-btn ${currentVizMode === "separate" ? "active" : ""}"
23555
+ data-viz="separate" title="Por Shopping"
23556
+ style="background: ${currentVizMode === "separate" ? activeColor : "transparent"}; color: ${currentVizMode === "separate" ? "white" : inactiveTextColor};">
23557
+ ${porShoppingIcon}
23558
+ </button>
23495
23559
  </div>
23496
23560
 
23497
23561
  <!-- Chart Type Tabs -->
23498
- <div style="display: flex; gap: 2px; background: ${currentTheme === "dark" ? "#4b5563" : "#e5e7eb"}; border-radius: 8px; padding: 2px;">
23499
- <button id="${modalId}-type-line" style="
23500
- padding: 6px 12px;
23501
- border: none;
23502
- border-radius: 6px;
23503
- font-size: 13px;
23504
- cursor: pointer;
23505
- transition: all 0.2s;
23506
- background: ${currentChartType === "line" ? "#3e1a7d" : "transparent"};
23507
- color: ${currentChartType === "line" ? "white" : colors.text};
23508
- ">Linhas</button>
23509
- <button id="${modalId}-type-bar" style="
23510
- padding: 6px 12px;
23511
- border: none;
23512
- border-radius: 6px;
23513
- font-size: 13px;
23514
- cursor: pointer;
23515
- transition: all 0.2s;
23516
- background: ${currentChartType === "bar" ? "#3e1a7d" : "transparent"};
23517
- color: ${currentChartType === "bar" ? "white" : colors.text};
23518
- ">Barras</button>
23562
+ <div style="display: flex; gap: 2px; background: ${tabBgColor}; border-radius: 8px; padding: 3px;">
23563
+ <button id="${modalId}-type-line" class="myio-modal-tab-btn ${currentChartType === "line" ? "active" : ""}"
23564
+ data-type="line" title="Gr\xE1fico de Linhas"
23565
+ style="background: ${currentChartType === "line" ? activeColor : "transparent"}; color: ${currentChartType === "line" ? "white" : inactiveTextColor};">
23566
+ ${lineChartIcon}
23567
+ </button>
23568
+ <button id="${modalId}-type-bar" class="myio-modal-tab-btn ${currentChartType === "bar" ? "active" : ""}"
23569
+ data-type="bar" title="Gr\xE1fico de Barras"
23570
+ style="background: ${currentChartType === "bar" ? activeColor : "transparent"}; color: ${currentChartType === "bar" ? "white" : inactiveTextColor};">
23571
+ ${barChartIcon}
23572
+ </button>
23519
23573
  </div>
23520
23574
  </div>
23521
23575
 
@@ -23536,6 +23590,11 @@ ${rangeText}`;
23536
23590
  function setupListeners() {
23537
23591
  if (!modalElement) return;
23538
23592
  headerInstance?.attachListeners();
23593
+ if (showSettingsButton) {
23594
+ document.getElementById(`${modalId}-settings-btn`)?.addEventListener("click", () => {
23595
+ config.onSettingsClick?.();
23596
+ });
23597
+ }
23539
23598
  document.getElementById(`${modalId}-viz-total`)?.addEventListener("click", () => {
23540
23599
  currentVizMode = "total";
23541
23600
  chartInstance?.setVizMode("total");
@@ -23570,25 +23629,30 @@ ${rangeText}`;
23570
23629
  modalElement.__handleKeydown = handleKeydown;
23571
23630
  }
23572
23631
  function updateControlStyles() {
23573
- const colors = getThemeColors2();
23632
+ const colors = getThemeColors3();
23633
+ const activeColor = "#3e1a7d";
23574
23634
  const vizTotalBtn = document.getElementById(`${modalId}-viz-total`);
23575
23635
  const vizSeparateBtn = document.getElementById(`${modalId}-viz-separate`);
23576
23636
  if (vizTotalBtn) {
23577
- vizTotalBtn.style.background = currentVizMode === "total" ? "#3e1a7d" : "transparent";
23637
+ vizTotalBtn.classList.toggle("active", currentVizMode === "total");
23638
+ vizTotalBtn.style.background = currentVizMode === "total" ? activeColor : "transparent";
23578
23639
  vizTotalBtn.style.color = currentVizMode === "total" ? "white" : colors.text;
23579
23640
  }
23580
23641
  if (vizSeparateBtn) {
23581
- vizSeparateBtn.style.background = currentVizMode === "separate" ? "#3e1a7d" : "transparent";
23642
+ vizSeparateBtn.classList.toggle("active", currentVizMode === "separate");
23643
+ vizSeparateBtn.style.background = currentVizMode === "separate" ? activeColor : "transparent";
23582
23644
  vizSeparateBtn.style.color = currentVizMode === "separate" ? "white" : colors.text;
23583
23645
  }
23584
23646
  const typeLineBtn = document.getElementById(`${modalId}-type-line`);
23585
23647
  const typeBarBtn = document.getElementById(`${modalId}-type-bar`);
23586
23648
  if (typeLineBtn) {
23587
- typeLineBtn.style.background = currentChartType === "line" ? "#3e1a7d" : "transparent";
23649
+ typeLineBtn.classList.toggle("active", currentChartType === "line");
23650
+ typeLineBtn.style.background = currentChartType === "line" ? activeColor : "transparent";
23588
23651
  typeLineBtn.style.color = currentChartType === "line" ? "white" : colors.text;
23589
23652
  }
23590
23653
  if (typeBarBtn) {
23591
- typeBarBtn.style.background = currentChartType === "bar" ? "#3e1a7d" : "transparent";
23654
+ typeBarBtn.classList.toggle("active", currentChartType === "bar");
23655
+ typeBarBtn.style.background = currentChartType === "bar" ? activeColor : "transparent";
23592
23656
  typeBarBtn.style.color = currentChartType === "bar" ? "white" : colors.text;
23593
23657
  }
23594
23658
  }
@@ -23714,18 +23778,11 @@ ${rangeText}`;
23714
23778
 
23715
23779
  .myio-chart-widget-title {
23716
23780
  margin: 0;
23717
- font-size: 16px;
23781
+ font-size: 14px;
23718
23782
  font-weight: 600;
23719
23783
  color: ${colors.text};
23720
23784
  }
23721
23785
 
23722
- .myio-chart-widget-controls {
23723
- display: flex;
23724
- align-items: center;
23725
- gap: 12px;
23726
- flex-wrap: wrap;
23727
- }
23728
-
23729
23786
  .myio-chart-widget-tabs {
23730
23787
  display: flex;
23731
23788
  gap: 2px;
@@ -23745,6 +23802,20 @@ ${rangeText}`;
23745
23802
  border-radius: 6px;
23746
23803
  transition: all 0.2s;
23747
23804
  white-space: nowrap;
23805
+ display: flex;
23806
+ align-items: center;
23807
+ justify-content: center;
23808
+ gap: 4px;
23809
+ }
23810
+
23811
+ .myio-chart-widget-tab.icon-only {
23812
+ padding: 6px 10px;
23813
+ }
23814
+
23815
+ .myio-chart-widget-tab svg {
23816
+ width: 16px;
23817
+ height: 16px;
23818
+ pointer-events: none;
23748
23819
  }
23749
23820
 
23750
23821
  .myio-chart-widget-tab:hover {
@@ -23878,7 +23949,7 @@ ${rangeText}`;
23878
23949
  background: ${colors.chartBackground};
23879
23950
  border-radius: 10px;
23880
23951
  width: 90%;
23881
- max-width: 600px;
23952
+ max-width: 860px;
23882
23953
  max-height: 90vh;
23883
23954
  display: flex;
23884
23955
  flex-direction: column;
@@ -23895,7 +23966,7 @@ ${rangeText}`;
23895
23966
  overflow-y: auto;
23896
23967
  display: flex;
23897
23968
  flex-direction: column;
23898
- gap: 20px;
23969
+ gap: 12px;
23899
23970
  }
23900
23971
 
23901
23972
  .myio-settings-section {
@@ -23938,10 +24009,10 @@ ${rangeText}`;
23938
24009
 
23939
24010
  .myio-settings-input,
23940
24011
  .myio-settings-select {
23941
- padding: 10px 14px;
24012
+ padding: 8px 12px;
23942
24013
  border: 1px solid ${colors.border};
23943
24014
  border-radius: 8px;
23944
- font-size: 14px;
24015
+ font-size: 12px;
23945
24016
  background: ${colors.chartBackground};
23946
24017
  color: ${colors.text};
23947
24018
  width: 100%;
@@ -23973,6 +24044,10 @@ ${rangeText}`;
23973
24044
  border-radius: 6px;
23974
24045
  transition: all 0.2s;
23975
24046
  white-space: nowrap;
24047
+ display: flex;
24048
+ align-items: center;
24049
+ justify-content: center;
24050
+ gap: 6px;
23976
24051
  }
23977
24052
 
23978
24053
  .myio-settings-tab:hover {
@@ -24030,13 +24105,17 @@ ${rangeText}`;
24030
24105
  }
24031
24106
 
24032
24107
  .myio-settings-context-group {
24033
- margin-bottom: 8px;
24108
+ margin-bottom: 12px;
24034
24109
  }
24035
24110
 
24036
24111
  .myio-settings-context-group:last-child {
24037
24112
  margin-bottom: 0;
24038
24113
  }
24039
24114
 
24115
+ .myio-settings-section + .myio-settings-section {
24116
+ margin-top: 12px;
24117
+ }
24118
+
24040
24119
  /* Dropdown styles */
24041
24120
  .myio-settings-dropdown-container {
24042
24121
  position: relative;
@@ -24140,6 +24219,23 @@ ${rangeText}`;
24140
24219
  opacity: 1 !important;
24141
24220
  transform: scale(1.2);
24142
24221
  }
24222
+
24223
+ /* DateRangePicker styles (CSS tokens + premium styling) */
24224
+ ${CSS_TOKENS}
24225
+ ${DATERANGEPICKER_STYLES}
24226
+
24227
+ /* Fix DateRangePicker buttons alignment */
24228
+ .myio-modal-scope .daterangepicker .drp-buttons {
24229
+ display: flex;
24230
+ justify-content: flex-end;
24231
+ align-items: center;
24232
+ gap: 8px;
24233
+ }
24234
+
24235
+ .myio-modal-scope .daterangepicker .drp-buttons .btn {
24236
+ display: inline-block;
24237
+ margin-left: 0;
24238
+ }
24143
24239
  `;
24144
24240
  }
24145
24241
  function createConsumptionChartWidget(config) {
@@ -24149,6 +24245,7 @@ ${rangeText}`;
24149
24245
  let styleElement = null;
24150
24246
  let settingsModalElement = null;
24151
24247
  let settingsHeaderInstance = null;
24248
+ let dateRangePickerInstance = null;
24152
24249
  let currentTheme = config.theme ?? "light";
24153
24250
  let currentChartType = config.defaultChartType ?? "line";
24154
24251
  let currentVizMode = config.defaultVizMode ?? "total";
@@ -24159,6 +24256,8 @@ ${rangeText}`;
24159
24256
  let tempVizMode = currentVizMode;
24160
24257
  let tempTheme = currentTheme;
24161
24258
  let tempIdealRange = currentIdealRange;
24259
+ let tempStartDate = null;
24260
+ let tempEndDate = null;
24162
24261
  let currentSuggestion = null;
24163
24262
  const domainCfg = DOMAIN_CONFIG4[config.domain] || DOMAIN_CONFIG4.energy;
24164
24263
  const primaryColor = config.colors?.primary || domainCfg.color;
@@ -24174,6 +24273,10 @@ ${rangeText}`;
24174
24273
  return `${domainName} dos \xFAltimos ${currentPeriod} dias`;
24175
24274
  }
24176
24275
  function renderHTML() {
24276
+ const consolidadoIcon = `<svg viewBox="0 0 16 16" fill="currentColor"><rect x="3" y="3" width="10" height="10" rx="2"/></svg>`;
24277
+ 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>`;
24278
+ 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>`;
24279
+ 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>`;
24177
24280
  return `
24178
24281
  <div id="${widgetId}" class="myio-chart-widget ${currentTheme === "dark" ? "dark" : ""} ${config.className || ""}">
24179
24282
  <div class="myio-chart-widget-header">
@@ -24182,18 +24285,16 @@ ${rangeText}`;
24182
24285
  <button id="${widgetId}-settings-btn" class="myio-chart-widget-btn" title="Configura\xE7\xF5es">\u2699\uFE0F</button>
24183
24286
  ` : ""}
24184
24287
  <h4 id="${widgetId}-title" class="myio-chart-widget-title">${getTitle()}</h4>
24185
- </div>
24186
- <div class="myio-chart-widget-controls">
24187
24288
  ${showVizModeTabs ? `
24188
24289
  <div class="myio-chart-widget-tabs" id="${widgetId}-viz-tabs">
24189
- <button class="myio-chart-widget-tab ${currentVizMode === "total" ? "active" : ""}" data-viz="total">Consolidado</button>
24190
- <button class="myio-chart-widget-tab ${currentVizMode === "separate" ? "active" : ""}" data-viz="separate">Por Shopping</button>
24290
+ <button class="myio-chart-widget-tab icon-only ${currentVizMode === "total" ? "active" : ""}" data-viz="total" title="Consolidado">${consolidadoIcon}</button>
24291
+ <button class="myio-chart-widget-tab icon-only ${currentVizMode === "separate" ? "active" : ""}" data-viz="separate" title="Por Shopping">${porShoppingIcon}</button>
24191
24292
  </div>
24192
24293
  ` : ""}
24193
24294
  ${showChartTypeTabs ? `
24194
24295
  <div class="myio-chart-widget-tabs" id="${widgetId}-type-tabs">
24195
- <button class="myio-chart-widget-tab ${currentChartType === "line" ? "active" : ""}" data-type="line">Linhas</button>
24196
- <button class="myio-chart-widget-tab ${currentChartType === "bar" ? "active" : ""}" data-type="bar">Barras</button>
24296
+ <button class="myio-chart-widget-tab icon-only ${currentChartType === "line" ? "active" : ""}" data-type="line" title="Gr\xE1fico de Linhas">${lineChartIcon}</button>
24297
+ <button class="myio-chart-widget-tab icon-only ${currentChartType === "bar" ? "active" : ""}" data-type="bar" title="Gr\xE1fico de Barras">${barChartIcon}</button>
24197
24298
  </div>
24198
24299
  ` : ""}
24199
24300
  ${showMaximizeButton ? `
@@ -24230,19 +24331,22 @@ ${rangeText}`;
24230
24331
  function renderSettingsModal() {
24231
24332
  const unit = config.unit ?? "";
24232
24333
  const isTemperature = config.domain === "temperature";
24334
+ 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>`;
24335
+ 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>`;
24336
+ 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>`;
24337
+ 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>`;
24233
24338
  settingsHeaderInstance = createModalHeader({
24234
24339
  id: `${widgetId}-settings`,
24235
24340
  title: "Configura\xE7\xF5es",
24236
24341
  icon: "\u2699\uFE0F",
24237
24342
  theme: tempTheme,
24238
- backgroundColor: primaryColor,
24239
24343
  showThemeToggle: false,
24240
24344
  showMaximize: false,
24241
24345
  showClose: true,
24242
24346
  onClose: () => closeSettingsModal()
24243
24347
  });
24244
24348
  return `
24245
- <div id="${widgetId}-settings-overlay" class="myio-settings-overlay hidden">
24349
+ <div id="${widgetId}-settings-overlay" class="myio-settings-overlay myio-modal-scope hidden">
24246
24350
  <div class="myio-settings-card">
24247
24351
  ${settingsHeaderInstance.render()}
24248
24352
  <div class="myio-settings-body">
@@ -24253,13 +24357,8 @@ ${rangeText}`;
24253
24357
  <div class="myio-settings-section-label">\u{1F4C5} Per\xEDodo</div>
24254
24358
  <div class="myio-settings-row">
24255
24359
  <div class="myio-settings-field" style="flex: 1;">
24256
- <select id="${widgetId}-settings-period" class="myio-settings-select">
24257
- <option value="7" ${tempPeriod === 7 ? "selected" : ""}>\xDAltimos 7 dias</option>
24258
- <option value="14" ${tempPeriod === 14 ? "selected" : ""}>\xDAltimos 14 dias</option>
24259
- <option value="30" ${tempPeriod === 30 ? "selected" : ""}>\xDAltimos 30 dias</option>
24260
- <option value="60" ${tempPeriod === 60 ? "selected" : ""}>\xDAltimos 60 dias</option>
24261
- <option value="90" ${tempPeriod === 90 ? "selected" : ""}>\xDAltimos 90 dias</option>
24262
- </select>
24360
+ <input type="text" id="${widgetId}-settings-daterange" class="myio-settings-input"
24361
+ readonly placeholder="Selecione o per\xEDodo..." style="cursor: pointer;">
24263
24362
  </div>
24264
24363
  </div>
24265
24364
  </div>
@@ -24388,8 +24487,8 @@ ${rangeText}`;
24388
24487
  <div class="myio-settings-field" style="flex: 1; min-width: 180px;">
24389
24488
  <label class="myio-settings-field-label">Tipo de Gr\xE1fico</label>
24390
24489
  <div class="myio-settings-tabs" id="${widgetId}-settings-chart-type">
24391
- <button class="myio-settings-tab ${tempChartType === "line" ? "active" : ""}" data-type="line">\u{1F4C8} Linhas</button>
24392
- <button class="myio-settings-tab ${tempChartType === "bar" ? "active" : ""}" data-type="bar">\u{1F4CA} Barras</button>
24490
+ <button class="myio-settings-tab ${tempChartType === "line" ? "active" : ""}" data-type="line">${lineChartIcon} Linhas</button>
24491
+ <button class="myio-settings-tab ${tempChartType === "bar" ? "active" : ""}" data-type="bar">${barChartIcon} Barras</button>
24393
24492
  </div>
24394
24493
  </div>
24395
24494
 
@@ -24397,8 +24496,8 @@ ${rangeText}`;
24397
24496
  <div class="myio-settings-field" style="flex: 1; min-width: 200px;">
24398
24497
  <label class="myio-settings-field-label">Agrupamento</label>
24399
24498
  <div class="myio-settings-tabs" id="${widgetId}-settings-viz-mode">
24400
- <button class="myio-settings-tab ${tempVizMode === "total" ? "active" : ""}" data-viz="total">\u{1F517} Consolidado</button>
24401
- <button class="myio-settings-tab ${tempVizMode === "separate" ? "active" : ""}" data-viz="separate">\u{1F3EC} Por Shopping</button>
24499
+ <button class="myio-settings-tab ${tempVizMode === "total" ? "active" : ""}" data-viz="total">${consolidadoIcon} Consolidado</button>
24500
+ <button class="myio-settings-tab ${tempVizMode === "separate" ? "active" : ""}" data-viz="separate">${porShoppingIcon} Por Shopping</button>
24402
24501
  </div>
24403
24502
  </div>
24404
24503
 
@@ -24539,18 +24638,21 @@ ${rangeText}`;
24539
24638
  peakDateEl.textContent = peakDate;
24540
24639
  }
24541
24640
  }
24542
- function openSettingsModal() {
24641
+ async function openSettingsModal() {
24543
24642
  tempPeriod = currentPeriod;
24544
24643
  tempChartType = currentChartType;
24545
24644
  tempVizMode = currentVizMode;
24546
24645
  tempTheme = currentTheme;
24547
24646
  tempIdealRange = currentIdealRange ? { ...currentIdealRange } : null;
24647
+ dateRangePickerInstance = null;
24548
24648
  if (!settingsModalElement) {
24549
24649
  settingsModalElement = document.createElement("div");
24550
24650
  settingsModalElement.innerHTML = renderSettingsModal();
24551
24651
  document.body.appendChild(settingsModalElement.firstElementChild);
24552
24652
  settingsModalElement = document.getElementById(`${widgetId}-settings-overlay`);
24553
- setupSettingsModalListeners();
24653
+ await setupSettingsModalListeners();
24654
+ } else {
24655
+ await setupSettingsModalListeners();
24554
24656
  }
24555
24657
  updateSettingsModalValues();
24556
24658
  updateIdealRangeSuggestionTooltip();
@@ -24558,6 +24660,10 @@ ${rangeText}`;
24558
24660
  }
24559
24661
  function closeSettingsModal() {
24560
24662
  settingsModalElement?.classList.add("hidden");
24663
+ if (dateRangePickerInstance) {
24664
+ dateRangePickerInstance.destroy();
24665
+ dateRangePickerInstance = null;
24666
+ }
24561
24667
  }
24562
24668
  function updateSettingsModalValues() {
24563
24669
  const periodSelect = document.getElementById(`${widgetId}-settings-period`);
@@ -24667,8 +24773,46 @@ ${rangeText}`;
24667
24773
  label: "Faixa Sugerida"
24668
24774
  };
24669
24775
  }
24670
- function setupSettingsModalListeners() {
24776
+ async function setupSettingsModalListeners() {
24671
24777
  settingsHeaderInstance?.attachListeners();
24778
+ const dateRangeInput = document.getElementById(`${widgetId}-settings-daterange`);
24779
+ if (dateRangeInput && !dateRangePickerInstance) {
24780
+ try {
24781
+ const endDate = /* @__PURE__ */ new Date();
24782
+ const startDate = /* @__PURE__ */ new Date();
24783
+ startDate.setDate(endDate.getDate() - tempPeriod);
24784
+ const presetStart = tempStartDate || startDate.toISOString();
24785
+ const presetEnd = tempEndDate || endDate.toISOString();
24786
+ dateRangePickerInstance = await createDateRangePicker2(dateRangeInput, {
24787
+ presetStart,
24788
+ presetEnd,
24789
+ includeTime: true,
24790
+ timePrecision: "hour",
24791
+ maxRangeDays: 90,
24792
+ locale: "pt-BR",
24793
+ parentEl: document.getElementById(`${widgetId}-settings-overlay`),
24794
+ onApply: (result) => {
24795
+ tempStartDate = result.startISO;
24796
+ tempEndDate = result.endISO;
24797
+ const start = new Date(result.startISO);
24798
+ const end = new Date(result.endISO);
24799
+ const diffTime = Math.abs(end.getTime() - start.getTime());
24800
+ const diffHours = diffTime / (1e3 * 60 * 60);
24801
+ const diffDays = Math.ceil(diffTime / (1e3 * 60 * 60 * 24));
24802
+ tempPeriod = diffDays || 7;
24803
+ const granularitySelect = document.getElementById(`${widgetId}-settings-granularity`);
24804
+ if (granularitySelect && diffHours <= 48) {
24805
+ granularitySelect.value = "1h";
24806
+ const dayPeriodField = document.getElementById(`${widgetId}-settings-dayperiod-field`);
24807
+ if (dayPeriodField) dayPeriodField.style.display = "block";
24808
+ }
24809
+ console.log("[ConsumptionChartWidget] Date range applied:", { start: result.startISO, end: result.endISO, hours: diffHours, days: tempPeriod });
24810
+ }
24811
+ });
24812
+ } catch (error) {
24813
+ console.warn("[ConsumptionChartWidget] DateRangePicker initialization failed:", error);
24814
+ }
24815
+ }
24672
24816
  document.getElementById(`${widgetId}-settings-overlay`)?.addEventListener("click", (e) => {
24673
24817
  if (e.target.classList.contains("myio-settings-overlay")) {
24674
24818
  closeSettingsModal();
@@ -24756,13 +24900,56 @@ ${rangeText}`;
24756
24900
  updateSettingsModalTabs();
24757
24901
  }
24758
24902
  });
24759
- document.getElementById(`${widgetId}-settings-reset`)?.addEventListener("click", () => {
24903
+ document.getElementById(`${widgetId}-settings-reset`)?.addEventListener("click", async () => {
24760
24904
  tempPeriod = config.defaultPeriod ?? 7;
24761
24905
  tempChartType = config.defaultChartType ?? "line";
24762
24906
  tempVizMode = config.defaultVizMode ?? "total";
24763
24907
  tempTheme = config.theme ?? "light";
24764
24908
  tempIdealRange = config.idealRange ?? null;
24765
- const granularitySelect = document.getElementById(`${widgetId}-settings-granularity`);
24909
+ tempStartDate = null;
24910
+ tempEndDate = null;
24911
+ if (dateRangePickerInstance) {
24912
+ dateRangePickerInstance.destroy();
24913
+ dateRangePickerInstance = null;
24914
+ }
24915
+ const dateRangeInput2 = document.getElementById(`${widgetId}-settings-daterange`);
24916
+ if (dateRangeInput2) {
24917
+ const endDate = /* @__PURE__ */ new Date();
24918
+ const startDate = /* @__PURE__ */ new Date();
24919
+ startDate.setDate(endDate.getDate() - tempPeriod);
24920
+ try {
24921
+ dateRangePickerInstance = await createDateRangePicker2(dateRangeInput2, {
24922
+ presetStart: startDate.toISOString(),
24923
+ presetEnd: endDate.toISOString(),
24924
+ includeTime: true,
24925
+ timePrecision: "hour",
24926
+ maxRangeDays: 90,
24927
+ locale: "pt-BR",
24928
+ parentEl: document.getElementById(`${widgetId}-settings-overlay`),
24929
+ onApply: (result) => {
24930
+ tempStartDate = result.startISO;
24931
+ tempEndDate = result.endISO;
24932
+ const start = new Date(result.startISO);
24933
+ const end = new Date(result.endISO);
24934
+ const diffTime = Math.abs(end.getTime() - start.getTime());
24935
+ const diffHours = diffTime / (1e3 * 60 * 60);
24936
+ const diffDays = Math.ceil(diffTime / (1e3 * 60 * 60 * 24));
24937
+ tempPeriod = diffDays || 7;
24938
+ const granularitySelect2 = document.getElementById(`${widgetId}-settings-granularity`);
24939
+ if (granularitySelect2 && diffHours <= 48) {
24940
+ granularitySelect2.value = "1h";
24941
+ const dayPeriodField2 = document.getElementById(`${widgetId}-settings-dayperiod-field`);
24942
+ if (dayPeriodField2) dayPeriodField2.style.display = "block";
24943
+ }
24944
+ }
24945
+ });
24946
+ } catch (error) {
24947
+ console.warn("[ConsumptionChartWidget] DateRangePicker reset failed:", error);
24948
+ }
24949
+ }
24950
+ const granularitySelect = document.getElementById(
24951
+ `${widgetId}-settings-granularity`
24952
+ );
24766
24953
  if (granularitySelect) granularitySelect.value = "1d";
24767
24954
  const dayPeriodField = document.getElementById(`${widgetId}-settings-dayperiod-field`);
24768
24955
  if (dayPeriodField) dayPeriodField.style.display = "none";
@@ -24908,6 +25095,10 @@ ${rangeText}`;
24908
25095
  }
24909
25096
  settingsHeaderInstance?.destroy();
24910
25097
  settingsHeaderInstance = null;
25098
+ if (dateRangePickerInstance) {
25099
+ dateRangePickerInstance.destroy();
25100
+ dateRangePickerInstance = null;
25101
+ }
24911
25102
  if (settingsModalElement) {
24912
25103
  settingsModalElement.remove();
24913
25104
  settingsModalElement = null;
@@ -25360,12 +25551,589 @@ ${rangeText}`;
25360
25551
  var EXPORT_DOMAIN_LABELS = DOMAIN_LABELS;
25361
25552
  var EXPORT_DOMAIN_UNITS = DOMAIN_UNITS;
25362
25553
 
25554
+ // src/components/DistributionChart/colorManager.ts
25555
+ var DEFAULT_SHOPPING_COLORS = [
25556
+ "#3b82f6",
25557
+ // Blue
25558
+ "#8b5cf6",
25559
+ // Purple
25560
+ "#f59e0b",
25561
+ // Amber
25562
+ "#ef4444",
25563
+ // Red
25564
+ "#10b981",
25565
+ // Emerald
25566
+ "#06b6d4",
25567
+ // Cyan
25568
+ "#ec4899",
25569
+ // Pink
25570
+ "#14b8a6",
25571
+ // Teal
25572
+ "#f97316",
25573
+ // Orange
25574
+ "#a855f7"
25575
+ // Violet
25576
+ ];
25577
+ var DEFAULT_ENERGY_GROUP_COLORS = {
25578
+ "Elevadores": "#3b82f6",
25579
+ "Escadas Rolantes": "#8b5cf6",
25580
+ "Climatiza\xE7\xE3o": "#f59e0b",
25581
+ "Climatizacao": "#f59e0b",
25582
+ // Without accent
25583
+ "Outros Equipamentos": "#ef4444",
25584
+ "Lojas": "#10b981"
25585
+ };
25586
+ var DEFAULT_WATER_GROUP_COLORS = {
25587
+ "Lojas": "#10b981",
25588
+ "\xC1rea Comum": "#0288d1",
25589
+ "Area Comum": "#0288d1"
25590
+ // Without accent
25591
+ };
25592
+ var DEFAULT_GAS_GROUP_COLORS = {
25593
+ "Cozinha": "#f59e0b",
25594
+ "Aquecimento": "#ef4444",
25595
+ "Outros": "#94a3b8"
25596
+ };
25597
+ function getDefaultGroupColors(domain) {
25598
+ switch (domain.toLowerCase()) {
25599
+ case "energy":
25600
+ return DEFAULT_ENERGY_GROUP_COLORS;
25601
+ case "water":
25602
+ return DEFAULT_WATER_GROUP_COLORS;
25603
+ case "gas":
25604
+ return DEFAULT_GAS_GROUP_COLORS;
25605
+ default:
25606
+ return DEFAULT_ENERGY_GROUP_COLORS;
25607
+ }
25608
+ }
25609
+ function assignShoppingColors(shoppingIds) {
25610
+ const colors = {};
25611
+ shoppingIds.forEach((id, index) => {
25612
+ colors[id] = DEFAULT_SHOPPING_COLORS[index % DEFAULT_SHOPPING_COLORS.length];
25613
+ });
25614
+ return colors;
25615
+ }
25616
+ function getShoppingColor(shoppingId, shoppingColors, fallbackIndex = 0) {
25617
+ if (shoppingColors && shoppingColors[shoppingId]) {
25618
+ return shoppingColors[shoppingId];
25619
+ }
25620
+ if (shoppingColors) {
25621
+ const normalizedId = shoppingId.toLowerCase();
25622
+ for (const [key, color] of Object.entries(shoppingColors)) {
25623
+ if (key.toLowerCase() === normalizedId || key.toLowerCase().includes(normalizedId)) {
25624
+ return color;
25625
+ }
25626
+ }
25627
+ }
25628
+ return DEFAULT_SHOPPING_COLORS[Math.abs(fallbackIndex) % DEFAULT_SHOPPING_COLORS.length];
25629
+ }
25630
+ function getGroupColor(groupName, groupColors, domain = "energy", fallbackIndex = 0) {
25631
+ if (groupColors && groupColors[groupName]) {
25632
+ return groupColors[groupName];
25633
+ }
25634
+ const defaultColors = getDefaultGroupColors(domain);
25635
+ if (defaultColors[groupName]) {
25636
+ return defaultColors[groupName];
25637
+ }
25638
+ return DEFAULT_SHOPPING_COLORS[Math.abs(fallbackIndex) % DEFAULT_SHOPPING_COLORS.length];
25639
+ }
25640
+ function getThemeColors2(theme) {
25641
+ if (theme === "dark") {
25642
+ return {
25643
+ text: "#f3f4f6",
25644
+ secondaryText: "#9ca3af",
25645
+ background: "#111827",
25646
+ cardBackground: "#1f2937",
25647
+ border: "#374151",
25648
+ grid: "#374151"
25649
+ };
25650
+ }
25651
+ return {
25652
+ text: "#1f2937",
25653
+ secondaryText: "#6b7280",
25654
+ background: "#f5f5f5",
25655
+ cardBackground: "#ffffff",
25656
+ border: "#e5e7eb",
25657
+ grid: "#e5e7eb"
25658
+ };
25659
+ }
25660
+ function getHashColor(str) {
25661
+ let hash = 0;
25662
+ for (let i = 0; i < str.length; i++) {
25663
+ const char = str.charCodeAt(i);
25664
+ hash = (hash << 5) - hash + char;
25665
+ hash = hash & hash;
25666
+ }
25667
+ return DEFAULT_SHOPPING_COLORS[Math.abs(hash) % DEFAULT_SHOPPING_COLORS.length];
25668
+ }
25669
+
25670
+ // src/components/DistributionChart/createDistributionChartWidget.ts
25671
+ 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>`;
25672
+ 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>`;
25673
+ function createDistributionChartWidget(config) {
25674
+ const widgetId = `distribution-${config.domain}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
25675
+ let chartInstance = null;
25676
+ let currentMode = config.defaultMode || "groups";
25677
+ let currentTheme = config.theme || "light";
25678
+ let currentData = null;
25679
+ let containerElement = null;
25680
+ const title = config.title || getDomainTitle(config.domain);
25681
+ const chartHeight = config.chartHeight || 300;
25682
+ const showHeader = config.showHeader !== false;
25683
+ const showModeSelector = config.showModeSelector !== false;
25684
+ const showSettingsButton = config.showSettingsButton ?? false;
25685
+ const showMaximizeButton = config.showMaximizeButton ?? false;
25686
+ const decimalPlaces = config.decimalPlaces ?? 2;
25687
+ const modes = config.modes || getDefaultModes(config.domain);
25688
+ const groupColors = config.groupColors || getDefaultGroupColors(config.domain);
25689
+ function getDomainTitle(domain) {
25690
+ const titles = {
25691
+ energy: "Distribui\xE7\xE3o de Energia",
25692
+ water: "Distribui\xE7\xE3o de \xC1gua",
25693
+ gas: "Distribui\xE7\xE3o de G\xE1s",
25694
+ temperature: "Distribui\xE7\xE3o de Temperatura"
25695
+ };
25696
+ return titles[domain.toLowerCase()] || `Distribui\xE7\xE3o de ${domain}`;
25697
+ }
25698
+ function getDefaultModes(domain) {
25699
+ if (domain === "water") {
25700
+ return [
25701
+ { value: "groups", label: "Lojas vs \xC1rea Comum" },
25702
+ { value: "stores", label: "Lojas por Shopping" },
25703
+ { value: "common", label: "\xC1rea Comum por Shopping" }
25704
+ ];
25705
+ }
25706
+ return [
25707
+ { value: "groups", label: "Por Grupos de Equipamentos" },
25708
+ { value: "elevators", label: "Elevadores por Shopping" },
25709
+ { value: "escalators", label: "Escadas Rolantes por Shopping" },
25710
+ { value: "hvac", label: "Climatiza\xE7\xE3o por Shopping" },
25711
+ { value: "others", label: "Outros Equipamentos por Shopping" },
25712
+ { value: "stores", label: "Lojas por Shopping" }
25713
+ ];
25714
+ }
25715
+ function $id(id) {
25716
+ if (config.$container) {
25717
+ return config.$container[0].querySelector(`#${id}`);
25718
+ }
25719
+ return document.getElementById(id);
25720
+ }
25721
+ function formatValue(value) {
25722
+ if (config.unitLarge && config.thresholdForLargeUnit && value >= config.thresholdForLargeUnit) {
25723
+ return `${(value / config.thresholdForLargeUnit).toFixed(decimalPlaces)} ${config.unitLarge}`;
25724
+ }
25725
+ return `${value.toFixed(decimalPlaces)} ${config.unit}`;
25726
+ }
25727
+ function getColor(key, index, isGroupMode2) {
25728
+ if (isGroupMode2) {
25729
+ return getGroupColor(key, groupColors, config.domain, index);
25730
+ }
25731
+ const shoppingColors = config.getShoppingColors?.();
25732
+ return getShoppingColor(key, shoppingColors, index);
25733
+ }
25734
+ function getColors2() {
25735
+ return getThemeColors2(currentTheme);
25736
+ }
25737
+ function isGroupMode() {
25738
+ return currentMode === "groups";
25739
+ }
25740
+ function renderHTML() {
25741
+ const colors = getColors2();
25742
+ const modeOptions = modes.map(
25743
+ (m) => `<option value="${m.value}" ${m.value === currentMode ? "selected" : ""}>${m.label}</option>`
25744
+ ).join("");
25745
+ const headerButtons = [];
25746
+ if (showSettingsButton) {
25747
+ headerButtons.push(`
25748
+ <button id="${widgetId}-settings-btn" class="myio-dist-btn" title="Configura\xE7\xF5es">
25749
+ ${settingsIcon}
25750
+ </button>
25751
+ `);
25752
+ }
25753
+ if (showMaximizeButton) {
25754
+ headerButtons.push(`
25755
+ <button id="${widgetId}-maximize-btn" class="myio-dist-btn" title="Expandir">
25756
+ ${maximizeIcon}
25757
+ </button>
25758
+ `);
25759
+ }
25760
+ return `
25761
+ <style>
25762
+ #${widgetId} {
25763
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
25764
+ }
25765
+ #${widgetId} .myio-dist-header {
25766
+ display: flex;
25767
+ justify-content: space-between;
25768
+ align-items: center;
25769
+ margin-bottom: 16px;
25770
+ flex-wrap: wrap;
25771
+ gap: 12px;
25772
+ }
25773
+ #${widgetId} .myio-dist-title {
25774
+ margin: 0;
25775
+ font-size: 16px;
25776
+ font-weight: 600;
25777
+ color: ${colors.text};
25778
+ }
25779
+ #${widgetId} .myio-dist-controls {
25780
+ display: flex;
25781
+ align-items: center;
25782
+ gap: 8px;
25783
+ }
25784
+ #${widgetId} .myio-dist-label {
25785
+ font-size: 12px;
25786
+ color: ${colors.secondaryText};
25787
+ }
25788
+ #${widgetId} .myio-dist-select {
25789
+ padding: 6px 10px;
25790
+ border-radius: 6px;
25791
+ border: 1px solid ${colors.border};
25792
+ background: ${colors.cardBackground};
25793
+ color: ${colors.text};
25794
+ font-size: 12px;
25795
+ cursor: pointer;
25796
+ min-width: 180px;
25797
+ }
25798
+ #${widgetId} .myio-dist-select:focus {
25799
+ outline: none;
25800
+ border-color: #3e1a7d;
25801
+ }
25802
+ #${widgetId} .myio-dist-btn {
25803
+ display: flex;
25804
+ align-items: center;
25805
+ justify-content: center;
25806
+ padding: 6px 8px;
25807
+ border: 1px solid ${colors.border};
25808
+ border-radius: 6px;
25809
+ background: transparent;
25810
+ color: ${colors.text};
25811
+ cursor: pointer;
25812
+ transition: all 0.2s;
25813
+ }
25814
+ #${widgetId} .myio-dist-btn:hover {
25815
+ background: #3e1a7d;
25816
+ border-color: #3e1a7d;
25817
+ color: white;
25818
+ }
25819
+ #${widgetId} .myio-dist-chart-container {
25820
+ position: relative;
25821
+ height: ${chartHeight}px;
25822
+ }
25823
+ #${widgetId} .myio-dist-loading {
25824
+ position: absolute;
25825
+ top: 0;
25826
+ left: 0;
25827
+ right: 0;
25828
+ bottom: 0;
25829
+ display: flex;
25830
+ align-items: center;
25831
+ justify-content: center;
25832
+ background: ${colors.cardBackground}ee;
25833
+ z-index: 10;
25834
+ }
25835
+ #${widgetId} .myio-dist-spinner {
25836
+ width: 32px;
25837
+ height: 32px;
25838
+ border: 3px solid ${colors.border};
25839
+ border-top-color: #3e1a7d;
25840
+ border-radius: 50%;
25841
+ animation: myio-dist-spin 0.8s linear infinite;
25842
+ }
25843
+ @keyframes myio-dist-spin {
25844
+ to { transform: rotate(360deg); }
25845
+ }
25846
+ #${widgetId} .myio-dist-empty {
25847
+ display: flex;
25848
+ flex-direction: column;
25849
+ align-items: center;
25850
+ justify-content: center;
25851
+ height: 100%;
25852
+ color: ${colors.secondaryText};
25853
+ font-size: 14px;
25854
+ }
25855
+ #${widgetId} .myio-dist-empty-icon {
25856
+ font-size: 48px;
25857
+ margin-bottom: 12px;
25858
+ opacity: 0.5;
25859
+ }
25860
+ </style>
25861
+
25862
+ <div id="${widgetId}" class="myio-distribution-widget" style="
25863
+ background: ${colors.cardBackground};
25864
+ border-radius: 12px;
25865
+ padding: 16px;
25866
+ height: 100%;
25867
+ display: flex;
25868
+ flex-direction: column;
25869
+ ">
25870
+ ${showHeader ? `
25871
+ <div class="myio-dist-header">
25872
+ <h4 class="myio-dist-title">${title}</h4>
25873
+ <div class="myio-dist-controls">
25874
+ ${showModeSelector && modes.length > 1 ? `
25875
+ <label for="${widgetId}-mode" class="myio-dist-label">Visualizar:</label>
25876
+ <select id="${widgetId}-mode" class="myio-dist-select">
25877
+ ${modeOptions}
25878
+ </select>
25879
+ ` : ""}
25880
+ ${headerButtons.join("")}
25881
+ </div>
25882
+ </div>
25883
+ ` : ""}
25884
+
25885
+ <div class="myio-dist-chart-container">
25886
+ <canvas id="${widgetId}-canvas"></canvas>
25887
+ <div id="${widgetId}-loading" class="myio-dist-loading" style="display: none;">
25888
+ <div class="myio-dist-spinner"></div>
25889
+ </div>
25890
+ </div>
25891
+ </div>
25892
+ `;
25893
+ }
25894
+ function setLoading(loading) {
25895
+ const loadingEl = $id(`${widgetId}-loading`);
25896
+ if (loadingEl) {
25897
+ loadingEl.style.display = loading ? "flex" : "none";
25898
+ }
25899
+ }
25900
+ function buildChartData(distribution) {
25901
+ const labels = [];
25902
+ const data = [];
25903
+ const backgroundColors = [];
25904
+ const total = Object.values(distribution).reduce((sum, val) => sum + val, 0);
25905
+ const isGroup = isGroupMode();
25906
+ const entries = Object.entries(distribution).filter(([_, value]) => value > 0).sort((a, b) => b[1] - a[1]);
25907
+ entries.forEach(([key, value], index) => {
25908
+ const percentage = total > 0 ? (value / total * 100).toFixed(1) : "0";
25909
+ labels.push(`${key} (${formatValue(value)} - ${percentage}%)`);
25910
+ data.push(value);
25911
+ backgroundColors.push(getColor(key, index, isGroup));
25912
+ });
25913
+ return { labels, data, backgroundColors, total };
25914
+ }
25915
+ function renderEmptyState() {
25916
+ const container = $id(`${widgetId}-canvas`)?.parentElement;
25917
+ if (container) {
25918
+ const emptyEl = document.createElement("div");
25919
+ emptyEl.className = "myio-dist-empty";
25920
+ emptyEl.innerHTML = `
25921
+ <div class="myio-dist-empty-icon">\u{1F4CA}</div>
25922
+ <div>Sem dados dispon\xEDveis</div>
25923
+ `;
25924
+ const canvas = $id(`${widgetId}-canvas`);
25925
+ if (canvas) canvas.style.display = "none";
25926
+ const existingEmpty = container.querySelector(".myio-dist-empty");
25927
+ if (!existingEmpty) {
25928
+ container.appendChild(emptyEl);
25929
+ }
25930
+ }
25931
+ }
25932
+ function removeEmptyState() {
25933
+ const container = $id(`${widgetId}-canvas`)?.parentElement;
25934
+ if (container) {
25935
+ const emptyEl = container.querySelector(".myio-dist-empty");
25936
+ if (emptyEl) emptyEl.remove();
25937
+ const canvas = $id(`${widgetId}-canvas`);
25938
+ if (canvas) canvas.style.display = "block";
25939
+ }
25940
+ }
25941
+ async function updateChart() {
25942
+ const canvas = $id(`${widgetId}-canvas`);
25943
+ if (!canvas) {
25944
+ console.error(`[${config.domain.toUpperCase()}] Distribution canvas not found`);
25945
+ return;
25946
+ }
25947
+ setLoading(true);
25948
+ try {
25949
+ const distribution = await config.fetchDistribution(currentMode);
25950
+ if (!distribution || Object.keys(distribution).length === 0) {
25951
+ console.warn(`[${config.domain.toUpperCase()}] No distribution data for mode: ${currentMode}`);
25952
+ currentData = null;
25953
+ setLoading(false);
25954
+ renderEmptyState();
25955
+ return;
25956
+ }
25957
+ removeEmptyState();
25958
+ currentData = distribution;
25959
+ const { labels, data, backgroundColors, total } = buildChartData(distribution);
25960
+ const colors = getColors2();
25961
+ const Chart2 = window.Chart;
25962
+ if (!Chart2) {
25963
+ throw new Error("Chart.js not loaded");
25964
+ }
25965
+ if (chartInstance) {
25966
+ chartInstance.destroy();
25967
+ chartInstance = null;
25968
+ }
25969
+ const ctx = canvas.getContext("2d");
25970
+ if (!ctx) {
25971
+ throw new Error("Could not get canvas context");
25972
+ }
25973
+ chartInstance = new Chart2(ctx, {
25974
+ type: "bar",
25975
+ data: {
25976
+ labels,
25977
+ datasets: [
25978
+ {
25979
+ label: `Consumo (${config.unit})`,
25980
+ data,
25981
+ backgroundColor: backgroundColors
25982
+ }
25983
+ ]
25984
+ },
25985
+ options: {
25986
+ responsive: true,
25987
+ maintainAspectRatio: false,
25988
+ indexAxis: "y",
25989
+ // Horizontal bar chart
25990
+ animation: false,
25991
+ plugins: {
25992
+ legend: { display: false },
25993
+ tooltip: {
25994
+ callbacks: {
25995
+ label: (context) => {
25996
+ const value = context.parsed.x || 0;
25997
+ const percentage = total > 0 ? (value / total * 100).toFixed(1) : "0";
25998
+ return `${formatValue(value)} (${percentage}%)`;
25999
+ }
26000
+ }
26001
+ }
26002
+ },
26003
+ scales: {
26004
+ x: {
26005
+ beginAtZero: true,
26006
+ ticks: {
26007
+ callback: (value) => formatValue(Number(value)),
26008
+ color: colors.secondaryText,
26009
+ font: { size: 11 }
26010
+ },
26011
+ grid: { color: colors.grid }
26012
+ },
26013
+ y: {
26014
+ ticks: {
26015
+ font: { size: 11 },
26016
+ color: colors.text
26017
+ },
26018
+ grid: { display: false }
26019
+ }
26020
+ }
26021
+ }
26022
+ });
26023
+ config.onDataLoaded?.(distribution);
26024
+ console.log(`[${config.domain.toUpperCase()}] Distribution chart updated for mode: ${currentMode}`);
26025
+ } catch (error) {
26026
+ console.error(`[${config.domain.toUpperCase()}] Error updating distribution chart:`, error);
26027
+ config.onError?.(error);
26028
+ renderEmptyState();
26029
+ } finally {
26030
+ setLoading(false);
26031
+ }
26032
+ }
26033
+ function setupListeners() {
26034
+ const modeSelect = $id(`${widgetId}-mode`);
26035
+ if (modeSelect) {
26036
+ modeSelect.addEventListener("change", async (e) => {
26037
+ currentMode = e.target.value;
26038
+ config.onModeChange?.(currentMode);
26039
+ await updateChart();
26040
+ });
26041
+ }
26042
+ if (showSettingsButton) {
26043
+ const settingsBtn = $id(`${widgetId}-settings-btn`);
26044
+ if (settingsBtn) {
26045
+ settingsBtn.addEventListener("click", () => {
26046
+ config.onSettingsClick?.();
26047
+ });
26048
+ }
26049
+ }
26050
+ if (showMaximizeButton) {
26051
+ const maximizeBtn = $id(`${widgetId}-maximize-btn`);
26052
+ if (maximizeBtn) {
26053
+ maximizeBtn.addEventListener("click", () => {
26054
+ config.onMaximizeClick?.();
26055
+ });
26056
+ }
26057
+ }
26058
+ }
26059
+ function updateThemeStyles() {
26060
+ const colors = getColors2();
26061
+ const widget = $id(widgetId);
26062
+ if (widget) {
26063
+ widget.style.background = colors.cardBackground;
26064
+ const title2 = widget.querySelector(".myio-dist-title");
26065
+ if (title2) title2.style.color = colors.text;
26066
+ const labels = widget.querySelectorAll(".myio-dist-label");
26067
+ labels.forEach((l) => l.style.color = colors.secondaryText);
26068
+ const select = widget.querySelector(".myio-dist-select");
26069
+ if (select) {
26070
+ select.style.background = colors.cardBackground;
26071
+ select.style.color = colors.text;
26072
+ select.style.borderColor = colors.border;
26073
+ }
26074
+ const buttons = widget.querySelectorAll(".myio-dist-btn");
26075
+ buttons.forEach((b) => {
26076
+ b.style.color = colors.text;
26077
+ b.style.borderColor = colors.border;
26078
+ });
26079
+ }
26080
+ }
26081
+ const instance = {
26082
+ async render() {
26083
+ containerElement = $id(config.containerId);
26084
+ if (!containerElement) {
26085
+ throw new Error(`Container #${config.containerId} not found`);
26086
+ }
26087
+ containerElement.innerHTML = renderHTML();
26088
+ setupListeners();
26089
+ await updateChart();
26090
+ },
26091
+ async setMode(mode) {
26092
+ currentMode = mode;
26093
+ const modeSelect = $id(`${widgetId}-mode`);
26094
+ if (modeSelect) {
26095
+ modeSelect.value = mode;
26096
+ }
26097
+ config.onModeChange?.(mode);
26098
+ await updateChart();
26099
+ },
26100
+ async refresh() {
26101
+ await updateChart();
26102
+ },
26103
+ setTheme(theme) {
26104
+ currentTheme = theme;
26105
+ updateThemeStyles();
26106
+ if (currentData) {
26107
+ updateChart();
26108
+ }
26109
+ },
26110
+ destroy() {
26111
+ if (chartInstance) {
26112
+ chartInstance.destroy();
26113
+ chartInstance = null;
26114
+ }
26115
+ if (containerElement) {
26116
+ containerElement.innerHTML = "";
26117
+ }
26118
+ currentData = null;
26119
+ },
26120
+ getChartInstance: () => chartInstance,
26121
+ getCurrentMode: () => currentMode,
26122
+ getCurrentData: () => currentData
26123
+ };
26124
+ return instance;
26125
+ }
26126
+
25363
26127
  exports.CHART_COLORS = CHART_COLORS;
25364
26128
  exports.CONSUMPTION_CHART_COLORS = DEFAULT_COLORS;
25365
26129
  exports.CONSUMPTION_CHART_DEFAULTS = DEFAULT_CONFIG;
25366
26130
  exports.CONSUMPTION_THEME_COLORS = THEME_COLORS;
25367
26131
  exports.ConnectionStatusType = ConnectionStatusType;
25368
26132
  exports.DEFAULT_CLAMP_RANGE = DEFAULT_CLAMP_RANGE;
26133
+ exports.DEFAULT_ENERGY_GROUP_COLORS = DEFAULT_ENERGY_GROUP_COLORS;
26134
+ exports.DEFAULT_GAS_GROUP_COLORS = DEFAULT_GAS_GROUP_COLORS;
26135
+ exports.DEFAULT_SHOPPING_COLORS = DEFAULT_SHOPPING_COLORS;
26136
+ exports.DEFAULT_WATER_GROUP_COLORS = DEFAULT_WATER_GROUP_COLORS;
25369
26137
  exports.DeviceStatusType = DeviceStatusType;
25370
26138
  exports.EXPORT_DEFAULT_COLORS = EXPORT_DEFAULT_COLORS;
25371
26139
  exports.EXPORT_DOMAIN_ICONS = EXPORT_DOMAIN_ICONS;
@@ -25378,6 +26146,7 @@ ${rangeText}`;
25378
26146
  exports.addDetectionContext = addDetectionContext;
25379
26147
  exports.addNamespace = addNamespace;
25380
26148
  exports.aggregateByDay = aggregateByDay;
26149
+ exports.assignShoppingColors = assignShoppingColors;
25381
26150
  exports.averageByDay = averageByDay;
25382
26151
  exports.buildListItemsThingsboardByUniqueDatasource = buildListItemsThingsboardByUniqueDatasource;
25383
26152
  exports.buildMyioIngestionAuth = buildMyioIngestionAuth;
@@ -25399,6 +26168,7 @@ ${rangeText}`;
25399
26168
  exports.createConsumptionChartWidget = createConsumptionChartWidget;
25400
26169
  exports.createConsumptionModal = createConsumptionModal;
25401
26170
  exports.createDateRangePicker = createDateRangePicker2;
26171
+ exports.createDistributionChartWidget = createDistributionChartWidget;
25402
26172
  exports.createInputDateRangePickerInsideDIV = createInputDateRangePickerInsideDIV;
25403
26173
  exports.createModalHeader = createModalHeader;
25404
26174
  exports.decodePayload = decodePayload;
@@ -25437,11 +26207,16 @@ ${rangeText}`;
25437
26207
  exports.getAvailableContexts = getAvailableContexts;
25438
26208
  exports.getConnectionStatusIcon = getConnectionStatusIcon;
25439
26209
  exports.getDateRangeArray = getDateRangeArray;
26210
+ exports.getDefaultGroupColors = getDefaultGroupColors;
25440
26211
  exports.getDeviceStatusIcon = getDeviceStatusIcon;
25441
26212
  exports.getDeviceStatusInfo = getDeviceStatusInfo;
26213
+ exports.getDistributionThemeColors = getThemeColors2;
26214
+ exports.getGroupColor = getGroupColor;
26215
+ exports.getHashColor = getHashColor;
25442
26216
  exports.getModalHeaderStyles = getModalHeaderStyles;
25443
26217
  exports.getSaoPauloISOString = getSaoPauloISOString;
25444
26218
  exports.getSaoPauloISOStringFixed = getSaoPauloISOStringFixed;
26219
+ exports.getShoppingColor = getShoppingColor;
25445
26220
  exports.getValueByDatakey = getValueByDatakey;
25446
26221
  exports.getValueByDatakeyLegacy = getValueByDatakeyLegacy;
25447
26222
  exports.getWaterCategories = getWaterCategories;