@khipu/design-system 0.1.0-alpha.55 → 0.2.0-alpha.10

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.
@@ -923,16 +923,34 @@ const ui = _context.ui;
923
923
  }
924
924
 
925
925
  /**
926
- * Initialize flash messages with auto-dismiss
926
+ * Dismiss and remove a snackbar with fade-out
927
+ */
928
+ function dismissSnackbar(snackbar) {
929
+ snackbar.classList.remove('active');
930
+ setTimeout(function() { snackbar.remove(); }, 300);
931
+ }
932
+
933
+ /**
934
+ * Initialize flash messages with auto-dismiss and close button
927
935
  */
928
936
  function initFlashMessages() {
929
- const snackbars = document.querySelectorAll('.snackbar[data-auto-dismiss="true"]');
937
+ var snackbars = document.querySelectorAll('.snackbar[data-auto-dismiss="true"]');
930
938
 
931
939
  snackbars.forEach(function(snackbar) {
940
+ // Give text span flex-grow so close button stays right
941
+ var span = snackbar.querySelector('span');
942
+ if (span) span.classList.add('max');
943
+
944
+ // Inject close button
945
+ var closeBtn = document.createElement('button');
946
+ closeBtn.className = 'kds-snackbar-close';
947
+ closeBtn.setAttribute('aria-label', 'Cerrar');
948
+ closeBtn.innerHTML = '<i class="material-symbols-outlined">close</i>';
949
+ closeBtn.onclick = function() { dismissSnackbar(snackbar); };
950
+ snackbar.appendChild(closeBtn);
951
+
932
952
  // Auto-dismiss after 5 seconds
933
- setTimeout(function() {
934
- snackbar.classList.remove('active');
935
- }, 5000);
953
+ setTimeout(function() { dismissSnackbar(snackbar); }, 5000);
936
954
  });
937
955
  }
938
956
 
@@ -973,10 +991,15 @@ const ui = _context.ui;
973
991
 
974
992
  if (!logoSource) return;
975
993
 
994
+ // Insert inside the amount div (first child of .kds-invoice-header)
995
+ var header = card.querySelector('.kds-invoice-header');
996
+ var amountDiv = header ? header.firstElementChild : null;
997
+ if (!amountDiv) return;
998
+
976
999
  var inner = document.createElement('div');
977
1000
  inner.className = 'kds-brand-inner';
978
1001
  inner.appendChild(logoSource.cloneNode(true));
979
- card.insertBefore(inner, card.firstChild);
1002
+ amountDiv.insertBefore(inner, amountDiv.firstChild);
980
1003
  });
981
1004
  }
982
1005
 
@@ -1136,13 +1159,14 @@ const ui = _context.ui;
1136
1159
  * Initialize segmented tabs
1137
1160
  * Delegated click on .kds-segmented-tabs button toggles .active and aria-selected
1138
1161
  * Sets --_active-idx and --_tab-count CSS custom properties for sliding pill animation
1162
+ * Auto-manages tab panels via data-kds-tab-panel attributes on sibling elements
1139
1163
  * Dispatches kds:tab:change with { index, button }
1140
1164
  * @param {Element} root - Root element to scope listeners (default: document)
1141
1165
  */
1142
1166
  function initSegmentedTabs(root) {
1143
1167
  root = root || document;
1144
1168
 
1145
- /* Set initial CSS vars on all segmented-tab containers */
1169
+ /* Set initial CSS vars and panel visibility on all segmented-tab containers */
1146
1170
  root.querySelectorAll('.kds-segmented-tabs').forEach(function(tabs) {
1147
1171
  var buttons = tabs.querySelectorAll('button');
1148
1172
  tabs.style.setProperty('--_tab-count', buttons.length);
@@ -1151,6 +1175,15 @@ const ui = _context.ui;
1151
1175
  if (b.classList.contains('active') || b.getAttribute('aria-selected') === 'true') activeIdx = i;
1152
1176
  });
1153
1177
  tabs.style.setProperty('--_active-idx', activeIdx);
1178
+
1179
+ /* Auto-bind panels: find sibling elements with data-kds-tab-panel */
1180
+ var parent = tabs.parentElement;
1181
+ if (parent) {
1182
+ var panels = parent.querySelectorAll('[data-kds-tab-panel]');
1183
+ panels.forEach(function(panel, i) {
1184
+ panel.hidden = i !== activeIdx;
1185
+ });
1186
+ }
1154
1187
  });
1155
1188
 
1156
1189
  root.addEventListener('click', function(e) {
@@ -1171,6 +1204,14 @@ const ui = _context.ui;
1171
1204
  var index = Array.prototype.indexOf.call(buttons, btn);
1172
1205
  tabs.style.setProperty('--_active-idx', index);
1173
1206
 
1207
+ /* Auto-toggle panels */
1208
+ var parent = tabs.parentElement;
1209
+ if (parent) {
1210
+ parent.querySelectorAll('[data-kds-tab-panel]').forEach(function(panel, i) {
1211
+ panel.hidden = i !== index;
1212
+ });
1213
+ }
1214
+
1174
1215
  tabs.dispatchEvent(new CustomEvent('kds:tab:change', {
1175
1216
  bubbles: true,
1176
1217
  detail: { index: index, button: btn }
@@ -1280,7 +1321,7 @@ const ui = _context.ui;
1280
1321
  /**
1281
1322
  * Initialize sticky invoice card progressive collapse on scroll
1282
1323
  * MOBILE ONLY - Desktop mantiene cajitas normales
1283
- * Uses scroll-linked animation (0-150px) for smooth collapse/expand
1324
+ * Uses scroll-linked animation (0-60px) for smooth collapse/expand
1284
1325
  * Updates CSS custom property --collapse-progress (0 to 1) for GPU-accelerated animations
1285
1326
  * Works with multiple screens - targets sticky element in currently active screen
1286
1327
  * Safari-compatible: uses native CSS custom properties, calc(), and requestAnimationFrame
@@ -1289,9 +1330,9 @@ const ui = _context.ui;
1289
1330
  function initStickyInvoice(root) {
1290
1331
  root = root || document;
1291
1332
 
1292
- // Progressive collapse range: 0px (expanded) to 150px (collapsed)
1333
+ // Progressive collapse range: 0px (expanded) to 30px (collapsed)
1293
1334
  var COLLAPSE_START = 0;
1294
- var COLLAPSE_END = 150;
1335
+ var COLLAPSE_END = 30;
1295
1336
 
1296
1337
  var lastScrollY = 0;
1297
1338
  var ticking = false;
@@ -1339,13 +1380,23 @@ const ui = _context.ui;
1339
1380
  if (!currentScreen.style.getPropertyValue('--collapse-collapsible-h')) {
1340
1381
  var collapsible = currentSticky.querySelector('.kds-invoice-collapsible');
1341
1382
  if (collapsible) {
1342
- currentScreen.style.setProperty('--collapse-collapsible-h', collapsible.offsetHeight + 'px');
1383
+ currentScreen.style.setProperty('--collapse-collapsible-h', Math.min(collapsible.offsetHeight, 87) + 'px');
1343
1384
  }
1344
1385
  }
1345
1386
 
1346
1387
  // Single DOM write per frame — set on screen (parent) so it cascades to sticky + siblings
1347
1388
  currentScreen.style.setProperty('--collapse-progress', progress);
1348
1389
 
1390
+ // Close expand panels as soon as the sticky header starts collapsing
1391
+ if (progress > 0) {
1392
+ currentSticky.querySelectorAll('[data-expand-toggle][aria-expanded="true"]').forEach(function(toggle) {
1393
+ toggle.setAttribute('aria-expanded', 'false');
1394
+ var panelId = toggle.getAttribute('aria-controls');
1395
+ var panel = panelId ? document.getElementById(panelId) : null;
1396
+ if (panel) panel.classList.remove('open');
1397
+ });
1398
+ }
1399
+
1349
1400
  lastScrollY = scrollY;
1350
1401
  });
1351
1402
  }
@@ -1493,25 +1544,24 @@ const ui = _context.ui;
1493
1544
  type = type || 'info';
1494
1545
  duration = duration || 5000;
1495
1546
 
1496
- const snackbar = document.createElement('div');
1547
+ var snackbar = document.createElement('div');
1497
1548
  snackbar.className = 'snackbar active ' + type;
1549
+ snackbar.setAttribute('data-auto-dismiss', 'true');
1550
+ snackbar.style.setProperty('--kds-snackbar-duration', duration + 'ms');
1498
1551
 
1499
- const icon = document.createElement('i');
1552
+ var icon = document.createElement('i');
1500
1553
  icon.className = 'material-symbols-outlined';
1501
1554
  icon.textContent = type === 'success' ? 'check_circle' : (type === 'error' ? 'error' : 'info');
1502
1555
 
1503
- const span = document.createElement('span');
1556
+ var span = document.createElement('span');
1557
+ span.className = 'max';
1504
1558
  span.textContent = message;
1505
1559
 
1506
- const closeBtn = document.createElement('button');
1507
- closeBtn.className = 'transparent circle';
1560
+ var closeBtn = document.createElement('button');
1561
+ closeBtn.className = 'kds-snackbar-close';
1562
+ closeBtn.setAttribute('aria-label', 'Cerrar');
1508
1563
  closeBtn.innerHTML = '<i class="material-symbols-outlined">close</i>';
1509
- closeBtn.onclick = function() {
1510
- snackbar.classList.remove('active');
1511
- setTimeout(function() {
1512
- snackbar.remove();
1513
- }, 300);
1514
- };
1564
+ closeBtn.onclick = function() { dismissSnackbar(snackbar); };
1515
1565
 
1516
1566
  snackbar.appendChild(icon);
1517
1567
  snackbar.appendChild(span);
@@ -1519,12 +1569,7 @@ const ui = _context.ui;
1519
1569
 
1520
1570
  document.body.appendChild(snackbar);
1521
1571
 
1522
- setTimeout(function() {
1523
- snackbar.classList.remove('active');
1524
- setTimeout(function() {
1525
- snackbar.remove();
1526
- }, 300);
1527
- }, duration);
1572
+ setTimeout(function() { dismissSnackbar(snackbar); }, duration);
1528
1573
  }
1529
1574
 
1530
1575
  // Export utilities to window for backward compatibility