@khipu/design-system 0.1.0-alpha.48 → 0.1.0-alpha.50

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.
@@ -11,7 +11,7 @@
11
11
  *
12
12
  * AUTO-GENERATED FILE - DO NOT EDIT MANUALLY
13
13
  * Source: design-system/src/tokens/tokens.json
14
- * Generated: 2026-04-23T20:33:31.235Z
14
+ * Generated: 2026-04-27T13:24:37.477Z
15
15
  *
16
16
  * To regenerate:
17
17
  * cd design-system && npm run tokens:generate
@@ -642,12 +642,21 @@ body.dark {
642
642
  --kds-color-info-soft: #EFF6FF; /* Alias for info backgrounds */
643
643
  --kds-color-success-soft: #ECFDF5; /* Success mark and borders */
644
644
 
645
+ /* Border colors */
646
+ --kds-color-border-subtle: #F3F4F6; /* Very light border for cards/rows (origin --rule) */
647
+ --kds-color-border-default: #E5E7EB; /* Standard light border for hover/separators (origin --rule-2) */
648
+
649
+ /* Hover background */
650
+ --kds-color-hover-bg: #FAFAFA; /* Ultra-subtle hover background for rows */
651
+
645
652
  /* Layout colors */
646
653
  --kds-color-shell: #F5F5F5; /* Neutral page background */
647
654
 
648
655
  /* Card specific */
649
656
  --kds-radius-card: 14px; /* Payment card radius (between lg and xl) */
657
+ --kds-radius-row: 10px; /* Interactive row radius (copy-row, etc.) */
650
658
  --kds-shadow-card: 0 1px 2px rgba(16,24,40,.04), 0 1px 3px rgba(16,24,40,.06); /* Subtle card shadow */
659
+ --kds-shadow-elevated: var(--kds-shadow-8); /* Elevated surfaces like modals */
651
660
 
652
661
  /* Extended semantic soft backgrounds */
653
662
  --kds-color-warning-soft: var(--kds-alert-warning-bg); /* #FFFBEB */
@@ -4492,17 +4501,23 @@ dialog#surveyModal button.circle {
4492
4501
  .field.locked > input,
4493
4502
  .field.locked > textarea {
4494
4503
  background: var(--kds-color-shell);
4495
- color: var(--kds-color-text-primary);
4504
+ color: var(--kds-color-text-secondary);
4496
4505
  cursor: default;
4506
+ border-color: var(--kds-color-divider);
4507
+ }
4508
+
4509
+ .field.locked > label {
4510
+ color: var(--kds-color-text-hint);
4497
4511
  }
4498
4512
 
4499
4513
  .field.locked > i {
4500
4514
  position: absolute;
4501
- right: 12px;
4515
+ right: var(--kds-spacing-1-5);
4502
4516
  top: 50%;
4503
4517
  transform: translateY(-50%);
4504
4518
  color: var(--kds-color-text-disabled);
4505
4519
  pointer-events: none;
4520
+ font-size: 18px;
4506
4521
  }
4507
4522
 
4508
4523
  /* Verified variant (green check) */
@@ -4566,12 +4581,11 @@ dialog#surveyModal button.circle {
4566
4581
  display: flex;
4567
4582
  align-items: center;
4568
4583
  gap: var(--kds-spacing-1-5);
4569
- width: 100%;
4570
- padding: var(--kds-spacing-1-75);
4584
+ padding: var(--kds-spacing-1-5);
4571
4585
  background: var(--kds-color-surface);
4572
4586
  color: var(--kds-color-text-primary);
4573
- border: 1px solid var(--kds-color-divider);
4574
- border-radius: var(--kds-radius-lg);
4587
+ border: 1px solid var(--kds-color-border-subtle);
4588
+ border-radius: var(--kds-radius-card);
4575
4589
  text-align: left;
4576
4590
  cursor: pointer;
4577
4591
  transition: border-color 0.2s, background 0.2s;
@@ -4579,8 +4593,8 @@ dialog#surveyModal button.circle {
4579
4593
  }
4580
4594
 
4581
4595
  .kds-bank-row:hover {
4582
- border-color: var(--kds-color-primary-main);
4583
- background: var(--kds-color-primary-faint);
4596
+ border-color: var(--kds-color-border-default);
4597
+ background: var(--kds-color-hover-bg);
4584
4598
  }
4585
4599
 
4586
4600
  .kds-bank-row-logo {
@@ -4602,12 +4616,12 @@ dialog#surveyModal button.circle {
4602
4616
  .kds-bank-row-name {
4603
4617
  flex: 1;
4604
4618
  font-weight: 500;
4605
- font-size: var(--kds-font-size-base);
4619
+ font-size: var(--kds-font-size-sm);
4606
4620
  color: var(--kds-color-text-primary);
4607
4621
  }
4608
4622
 
4609
4623
  .kds-bank-row > i {
4610
- color: var(--kds-color-text-secondary);
4624
+ color: var(--kds-color-border-default);
4611
4625
  flex-shrink: 0;
4612
4626
  }
4613
4627
 
@@ -4845,8 +4859,8 @@ dialog#surveyModal button.circle {
4845
4859
  justify-content: flex-start;
4846
4860
  gap: var(--kds-spacing-1-25);
4847
4861
  padding: var(--kds-spacing-1-5) var(--kds-spacing-1-75);
4848
- border: var(--kds-border-width-sm) solid var(--kds-color-divider);
4849
- border-radius: var(--kds-radius-md);
4862
+ border: var(--kds-border-width-sm) solid var(--kds-color-border-subtle);
4863
+ border-radius: var(--kds-radius-row);
4850
4864
  background: var(--kds-color-surface, var(--kds-color-background-paper));
4851
4865
  cursor: pointer;
4852
4866
  text-align: left;
@@ -4858,8 +4872,8 @@ dialog#surveyModal button.circle {
4858
4872
  }
4859
4873
 
4860
4874
  .kds-copy-row:hover {
4861
- background: var(--kds-color-background-muted);
4862
- border-color: var(--kds-border-light);
4875
+ background: var(--kds-color-hover-bg);
4876
+ border-color: var(--kds-color-border-default);
4863
4877
  }
4864
4878
 
4865
4879
  .kds-copy-row > i {
@@ -5159,6 +5173,67 @@ dialog#surveyModal button.circle {
5159
5173
  amount summary, recap, success button
5160
5174
  ======================================== */
5161
5175
 
5176
+ /* -- Sticky Invoice Card (.kds-invoice-sticky) -- */
5177
+ /* Collapses detail rows on scroll via .collapsed class (JS toggle) */
5178
+
5179
+ .kds-invoice-sticky {
5180
+ position: sticky;
5181
+ top: 0;
5182
+ z-index: 10;
5183
+ transition: box-shadow 0.25s ease, border-radius 0.25s ease;
5184
+ }
5185
+
5186
+ .kds-invoice-sticky.collapsed {
5187
+ box-shadow: var(--kds-shadow-2);
5188
+ border-radius: 0 0 var(--kds-radius-card) var(--kds-radius-card);
5189
+ }
5190
+
5191
+ .kds-invoice-sticky .kds-invoice-collapsible {
5192
+ overflow: hidden;
5193
+ max-height: 300px;
5194
+ opacity: 1;
5195
+ transition: max-height 0.3s ease, opacity 0.2s ease;
5196
+ }
5197
+
5198
+ .kds-invoice-sticky.collapsed .kds-invoice-collapsible {
5199
+ max-height: 0;
5200
+ opacity: 0;
5201
+ }
5202
+
5203
+ .kds-invoice-sticky .kds-invoice-amount {
5204
+ transition: font-size 0.25s ease;
5205
+ }
5206
+
5207
+ .kds-invoice-sticky.collapsed .kds-invoice-amount {
5208
+ font-size: var(--kds-font-size-xl);
5209
+ }
5210
+
5211
+ .kds-invoice-sticky .kds-invoice-merchant {
5212
+ transition: width 0.25s ease, height 0.25s ease;
5213
+ }
5214
+
5215
+ .kds-invoice-sticky.collapsed .kds-invoice-merchant {
5216
+ width: var(--kds-status-icon-size-sm);
5217
+ height: var(--kds-status-icon-size-sm);
5218
+ }
5219
+
5220
+ .kds-invoice-sticky .kds-invoice-merchant i {
5221
+ transition: font-size 0.25s ease;
5222
+ }
5223
+
5224
+ .kds-invoice-sticky.collapsed .kds-invoice-merchant i {
5225
+ font-size: var(--kds-font-size-xl);
5226
+ }
5227
+
5228
+ .kds-invoice-sticky .kds-invoice-code {
5229
+ transition: margin-top 0.25s ease, font-size 0.25s ease;
5230
+ }
5231
+
5232
+ .kds-invoice-sticky.collapsed .kds-invoice-code {
5233
+ margin-top: 0;
5234
+ font-size: var(--kds-font-size-caption);
5235
+ }
5236
+
5162
5237
  /* -- Invoice Header (amount + merchant tile) -- */
5163
5238
  .kds-invoice-header {
5164
5239
  display: flex;
@@ -5725,3 +5800,125 @@ button.kds-btn-success::after {
5725
5800
 
5726
5801
  .kds-demo-center { text-align: center; }
5727
5802
  .kds-demo-spacer { height: var(--kds-spacing-3); }
5803
+
5804
+ /* ========================================
5805
+ BANK MODAL (.kds-bank-modal)
5806
+ Full-screen overlay with scrollable bank list + search
5807
+ ======================================== */
5808
+
5809
+ .kds-bank-modal-scrim {
5810
+ position: fixed;
5811
+ inset: 0;
5812
+ background: var(--kds-modal-backdrop);
5813
+ display: none;
5814
+ align-items: center;
5815
+ justify-content: center;
5816
+ z-index: var(--kds-z-index-modal, 50);
5817
+ animation: kds-fade 0.2s ease both;
5818
+ padding: var(--kds-spacing-2);
5819
+ }
5820
+
5821
+ .kds-bank-modal-scrim.open {
5822
+ display: flex;
5823
+ }
5824
+
5825
+ .kds-bank-modal {
5826
+ width: 100%;
5827
+ max-width: var(--kds-stage-narrow-max-width, 448px);
5828
+ height: 85vh;
5829
+ background: var(--kds-color-background-paper);
5830
+ border-radius: var(--kds-radius-card);
5831
+ box-shadow: var(--kds-shadow-elevated);
5832
+ display: flex;
5833
+ flex-direction: column;
5834
+ overflow: hidden;
5835
+ animation: kds-rise 0.28s cubic-bezier(0.2, 0.8, 0.2, 1) both;
5836
+ }
5837
+
5838
+ .kds-bank-modal-header {
5839
+ display: flex;
5840
+ align-items: center;
5841
+ justify-content: space-between;
5842
+ padding: var(--kds-spacing-2) var(--kds-spacing-2) var(--kds-spacing-1);
5843
+ }
5844
+
5845
+ .kds-bank-modal-header h3 {
5846
+ font-size: var(--kds-font-size-lg);
5847
+ font-weight: var(--kds-font-weight-semibold);
5848
+ margin: 0;
5849
+ color: var(--kds-color-text-primary);
5850
+ }
5851
+
5852
+ .kds-bank-modal-close {
5853
+ background: none;
5854
+ border: 0;
5855
+ padding: var(--kds-spacing-0-5);
5856
+ cursor: pointer;
5857
+ color: var(--kds-color-text-secondary);
5858
+ border-radius: var(--kds-radius-full);
5859
+ display: grid;
5860
+ place-items: center;
5861
+ }
5862
+
5863
+ .kds-bank-modal-close::after {
5864
+ display: none;
5865
+ }
5866
+
5867
+ .kds-bank-modal-search {
5868
+ padding: 0 var(--kds-spacing-2) var(--kds-spacing-1-5);
5869
+ }
5870
+
5871
+ .kds-bank-modal-search input {
5872
+ width: 100%;
5873
+ padding: var(--kds-spacing-1-25) var(--kds-spacing-1-5);
5874
+ border: 1px solid var(--kds-color-divider);
5875
+ border-radius: var(--kds-radius-md);
5876
+ font-size: var(--kds-font-size-sm);
5877
+ font-family: inherit;
5878
+ outline: none;
5879
+ color: var(--kds-color-text-primary);
5880
+ background: var(--kds-color-surface);
5881
+ }
5882
+
5883
+ .kds-bank-modal-search input::placeholder {
5884
+ color: var(--kds-color-text-hint);
5885
+ }
5886
+
5887
+ .kds-bank-modal-search input:focus {
5888
+ border-color: var(--kds-color-primary-main);
5889
+ box-shadow: 0 0 0 2px var(--kds-color-primary-faint);
5890
+ }
5891
+
5892
+ .kds-bank-modal-body {
5893
+ flex: 1;
5894
+ overflow-y: auto;
5895
+ padding: 0 var(--kds-spacing-1) var(--kds-spacing-1);
5896
+ }
5897
+
5898
+ .kds-bank-modal-body .kds-bank-list {
5899
+ margin-top: 0;
5900
+ gap: var(--kds-spacing-0-5);
5901
+ }
5902
+
5903
+ .kds-bank-modal-body .kds-bank-row {
5904
+ border: 0;
5905
+ border-radius: var(--kds-radius-md);
5906
+ padding: var(--kds-spacing-1) var(--kds-spacing-1-25);
5907
+ }
5908
+
5909
+ .kds-bank-modal-body .kds-bank-row:hover {
5910
+ background: var(--kds-color-primary-faint);
5911
+ border-color: transparent;
5912
+ }
5913
+
5914
+ .kds-bank-modal-empty {
5915
+ text-align: center;
5916
+ padding: var(--kds-spacing-4) var(--kds-spacing-2);
5917
+ color: var(--kds-color-text-hint);
5918
+ font-size: var(--kds-font-size-sm);
5919
+ display: none;
5920
+ }
5921
+
5922
+ .kds-bank-modal-empty.visible {
5923
+ display: block;
5924
+ }
@@ -1644,6 +1644,8 @@ function H(e){return e<0?-1:e===0?0:1}function nt(e,t,r){return(1-r)*e+r*t}funct
1644
1644
  * - Clipboard copy rows
1645
1645
  * - Countdown timers
1646
1646
  * - Segmented tabs
1647
+ * - Bank modal (search and selection)
1648
+ * - Sticky invoice card (collapse on scroll)
1647
1649
  */
1648
1650
 
1649
1651
  (function() {
@@ -1681,6 +1683,8 @@ function H(e){return e<0?-1:e===0?0:1}function nt(e,t,r){return(1-r)*e+r*t}funct
1681
1683
  initCopyRow();
1682
1684
  initCountdown();
1683
1685
  initSegmentedTabs();
1686
+ initStickyInvoice();
1687
+ initBankModal();
1684
1688
 
1685
1689
  console.log('Material Design initialization complete!');
1686
1690
  }
@@ -1895,6 +1899,143 @@ function H(e){return e<0?-1:e===0?0:1}function nt(e,t,r){return(1-r)*e+r*t}funct
1895
1899
  });
1896
1900
  }
1897
1901
 
1902
+ /**
1903
+ * Initialize bank modal
1904
+ * Handles opening, closing, search, and selection of banks
1905
+ * Delegated events for [data-open-bank-modal], [data-close-bank-modal], and bank selection
1906
+ * @param {Element} root - Root element to scope listeners (default: document)
1907
+ */
1908
+ function initBankModal(root) {
1909
+ root = root || document;
1910
+
1911
+ var modal = root.querySelector('#bankModal');
1912
+ var searchInput = root.querySelector('#bankSearch');
1913
+ var bankList = root.querySelector('#bankModalList');
1914
+ var noResults = root.querySelector('#bankNoResults');
1915
+
1916
+ if (!modal) return;
1917
+
1918
+ /**
1919
+ * Filter banks by search query
1920
+ * @param {string} query - Search term
1921
+ */
1922
+ function filterBanks(query) {
1923
+ if (!bankList) return;
1924
+
1925
+ var q = query.toLowerCase().trim();
1926
+ var rows = bankList.querySelectorAll('.kds-bank-row');
1927
+ var visible = 0;
1928
+
1929
+ rows.forEach(function(row) {
1930
+ var nameEl = row.querySelector('.kds-bank-row-name');
1931
+ if (!nameEl) return;
1932
+
1933
+ var name = nameEl.textContent.toLowerCase();
1934
+ var match = !q || name.indexOf(q) !== -1;
1935
+ row.style.display = match ? '' : 'none';
1936
+ if (match) visible++;
1937
+ });
1938
+
1939
+ if (noResults) {
1940
+ noResults.classList.toggle('visible', visible === 0);
1941
+ }
1942
+ }
1943
+
1944
+ // Open modal
1945
+ root.addEventListener('click', function(e) {
1946
+ var opener = e.target.closest('[data-open-bank-modal]');
1947
+ if (opener) {
1948
+ modal.classList.add('open');
1949
+ if (searchInput) {
1950
+ searchInput.value = '';
1951
+ searchInput.focus();
1952
+ }
1953
+ filterBanks('');
1954
+ }
1955
+ });
1956
+
1957
+ // Close modal
1958
+ root.addEventListener('click', function(e) {
1959
+ var closer = e.target.closest('[data-close-bank-modal]');
1960
+ if (closer) {
1961
+ modal.classList.remove('open');
1962
+ }
1963
+ });
1964
+
1965
+ // Select bank (closes modal and dispatches event)
1966
+ if (bankList) {
1967
+ bankList.addEventListener('click', function(e) {
1968
+ var bankRow = e.target.closest('.kds-bank-row');
1969
+ if (bankRow) {
1970
+ var bankId = bankRow.dataset.bankId || bankRow.dataset.bank || '';
1971
+ var bankName = bankRow.querySelector('.kds-bank-row-name');
1972
+
1973
+ // Dispatch custom event with bank data
1974
+ modal.dispatchEvent(new CustomEvent('kds:bank:selected', {
1975
+ bubbles: true,
1976
+ detail: {
1977
+ id: bankId,
1978
+ name: bankName ? bankName.textContent : '',
1979
+ element: bankRow
1980
+ }
1981
+ }));
1982
+
1983
+ // Close modal
1984
+ modal.classList.remove('open');
1985
+ }
1986
+ });
1987
+ }
1988
+
1989
+ // Search input
1990
+ if (searchInput) {
1991
+ searchInput.addEventListener('input', function(e) {
1992
+ filterBanks(e.target.value);
1993
+ });
1994
+ }
1995
+
1996
+ // Export filterBanks for manual use if needed
1997
+ if (!window.Khipu) window.Khipu = {};
1998
+ window.Khipu.filterBanks = filterBanks;
1999
+ }
2000
+
2001
+ /**
2002
+ * Initialize sticky invoice card collapse on scroll
2003
+ * Toggles .collapsed class on .kds-invoice-sticky when user scrolls past threshold
2004
+ * Works with multiple screens - targets sticky element in currently active screen
2005
+ * Uses hysteresis (different thresholds for collapse/expand) to prevent oscillation
2006
+ * @param {Element} root - Root element to scope queries (default: document)
2007
+ */
2008
+ function initStickyInvoice(root) {
2009
+ root = root || document;
2010
+
2011
+ var collapseAt = 60; // px scrolled to collapse
2012
+ var expandAt = 20; // px scrolled to expand (lower = hysteresis)
2013
+ var collapsedStates = {}; // Track collapsed state per screen
2014
+
2015
+ function onScroll() {
2016
+ // Find sticky element in currently active screen
2017
+ var activeScreen = root.querySelector('.kds-screen.active');
2018
+ if (!activeScreen) return;
2019
+
2020
+ var sticky = activeScreen.querySelector('.kds-invoice-sticky');
2021
+ if (!sticky) return;
2022
+
2023
+ var screenId = activeScreen.id || 'default';
2024
+ var isCollapsed = collapsedStates[screenId] || false;
2025
+ var scrollY = window.scrollY || window.pageYOffset;
2026
+
2027
+ if (!isCollapsed && scrollY > collapseAt) {
2028
+ sticky.classList.add('collapsed');
2029
+ collapsedStates[screenId] = true;
2030
+ } else if (isCollapsed && scrollY < expandAt) {
2031
+ sticky.classList.remove('collapsed');
2032
+ collapsedStates[screenId] = false;
2033
+ }
2034
+ }
2035
+
2036
+ window.addEventListener('scroll', onScroll, { passive: true });
2037
+ }
2038
+
1898
2039
  /**
1899
2040
  * Utility: Show a snackbar programmatically
1900
2041
  * @param {string} message - The message to display
@@ -1949,6 +2090,8 @@ function H(e){return e<0?-1:e===0?0:1}function nt(e,t,r){return(1-r)*e+r*t}funct
1949
2090
  window.Khipu.initCopyRow = initCopyRow;
1950
2091
  window.Khipu.initCountdown = initCountdown;
1951
2092
  window.Khipu.initSegmentedTabs = initSegmentedTabs;
2093
+ window.Khipu.initBankModal = initBankModal;
2094
+ window.Khipu.initStickyInvoice = initStickyInvoice;
1952
2095
 
1953
2096
  // Also export showSnackbar to global scope for backward compatibility
1954
2097
  window.showSnackbar = showSnackbar;