@khipu/design-system 0.2.0-alpha.83 → 0.2.0-alpha.85
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/beercss/khipu-beercss.css +155 -6
- package/dist/beercss/khipu-beercss.js +63 -0
- package/dist/beercss/khipu-beercss.min.css +1 -1
- package/dist/beercss/khipu-beercss.min.js +1 -1
- package/dist/beercss/khipu-beercss.scoped.css +155 -6
- package/dist/beercss/khipu-beercss.scoped.min.css +1 -1
- package/dist/beercss/metadata.json +5 -5
- package/dist/index.d.mts +89 -2
- package/dist/index.d.ts +89 -2
- package/dist/index.js +224 -142
- package/dist/index.mjs +191 -111
- package/package.json +1 -1
|
@@ -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-07-
|
|
14
|
+
* Generated: 2026-07-01T19:20:36.949Z
|
|
15
15
|
*
|
|
16
16
|
* To regenerate:
|
|
17
17
|
* cd design-system && npm run tokens:generate
|
|
@@ -363,6 +363,7 @@
|
|
|
363
363
|
RESPONSIVE TYPOGRAPHY (MOBILE BASE)
|
|
364
364
|
========================================================================== */
|
|
365
365
|
|
|
366
|
+
--kds-font-size-2xs: 0.5625rem;
|
|
366
367
|
|
|
367
368
|
/* Base font-size scale */
|
|
368
369
|
--kds-font-size-xs: 0.6875rem;
|
|
@@ -410,6 +411,7 @@
|
|
|
410
411
|
/* Tablet (600px+) - Typography */
|
|
411
412
|
@media (min-width: 600px) {
|
|
412
413
|
:root {
|
|
414
|
+
--kds-font-size-2xs: 0.625rem;
|
|
413
415
|
|
|
414
416
|
/* Base font-size scale */
|
|
415
417
|
--kds-font-size-xs: 0.75rem;
|
|
@@ -447,6 +449,7 @@
|
|
|
447
449
|
/* Desktop (840px+) - Typography */
|
|
448
450
|
@media (min-width: 840px) {
|
|
449
451
|
:root {
|
|
452
|
+
--kds-font-size-2xs: 0.625rem;
|
|
450
453
|
|
|
451
454
|
/* Base font-size scale */
|
|
452
455
|
--kds-font-size-xs: 0.75rem;
|
|
@@ -2891,7 +2894,7 @@ label.radio {
|
|
|
2891
2894
|
border-radius: 8px;
|
|
2892
2895
|
cursor: pointer;
|
|
2893
2896
|
transition: background-color 0.2s;
|
|
2894
|
-
font-size:
|
|
2897
|
+
font-size: var(--kds-font-size-sm);
|
|
2895
2898
|
line-height: 1.5;
|
|
2896
2899
|
color: var(--kds-color-text-primary);
|
|
2897
2900
|
}
|
|
@@ -4732,6 +4735,35 @@ dialog#surveyModal button.circle {
|
|
|
4732
4735
|
text-transform: uppercase;
|
|
4733
4736
|
}
|
|
4734
4737
|
|
|
4738
|
+
/* Value — dato/valor destacado (ej. nombre del comercio en el header del cobro). */
|
|
4739
|
+
.kds-text-value {
|
|
4740
|
+
font-family: var(--kds-font-family-primary, 'Public Sans', sans-serif);
|
|
4741
|
+
font-size: var(--kds-font-size-sm);
|
|
4742
|
+
font-weight: var(--kds-font-weight-semibold);
|
|
4743
|
+
line-height: var(--kds-line-height-relaxed);
|
|
4744
|
+
color: var(--kds-color-gray-800);
|
|
4745
|
+
}
|
|
4746
|
+
|
|
4747
|
+
/* Code — texto tipo código/referencia (mono, uppercase, gris), como el "CÓDIGO" del header. */
|
|
4748
|
+
.kds-text-code {
|
|
4749
|
+
font-family: var(--kds-font-family-mono);
|
|
4750
|
+
font-size: var(--kds-font-size-xs);
|
|
4751
|
+
font-weight: var(--kds-font-weight-regular);
|
|
4752
|
+
letter-spacing: var(--kds-letter-spacing-wider);
|
|
4753
|
+
font-variant-numeric: tabular-nums;
|
|
4754
|
+
color: var(--kds-color-gray-400);
|
|
4755
|
+
text-transform: uppercase;
|
|
4756
|
+
}
|
|
4757
|
+
|
|
4758
|
+
/* Caption — texto muy chico y liviano para pie de página (ej. número de versión). */
|
|
4759
|
+
.kds-text-caption {
|
|
4760
|
+
font-family: var(--kds-font-family-primary, 'Public Sans', sans-serif);
|
|
4761
|
+
font-size: var(--kds-font-size-2xs);
|
|
4762
|
+
font-weight: var(--kds-font-weight-regular);
|
|
4763
|
+
line-height: var(--kds-line-height-normal);
|
|
4764
|
+
color: var(--kds-color-gray-400);
|
|
4765
|
+
}
|
|
4766
|
+
|
|
4735
4767
|
.kds-text-link {
|
|
4736
4768
|
font-family: var(--kds-font-family-primary, 'Public Sans', sans-serif);
|
|
4737
4769
|
font-size: inherit;
|
|
@@ -5508,6 +5540,125 @@ dialog#surveyModal button.circle {
|
|
|
5508
5540
|
box-shadow: 0 -4px 16px rgba(16,24,40,.08);
|
|
5509
5541
|
}
|
|
5510
5542
|
|
|
5543
|
+
/* ========================================
|
|
5544
|
+
08b - FAB (.kds-fab)
|
|
5545
|
+
Circular, icon-only floating action button with an animated hide state.
|
|
5546
|
+
Presentational: drive `.kds-fab--hidden` from useHideOnScroll for scroll-away.
|
|
5547
|
+
======================================== */
|
|
5548
|
+
|
|
5549
|
+
.kds-fab {
|
|
5550
|
+
display: inline-flex;
|
|
5551
|
+
align-items: center;
|
|
5552
|
+
justify-content: center;
|
|
5553
|
+
width: var(--kds-spacing-5);
|
|
5554
|
+
height: var(--kds-spacing-5);
|
|
5555
|
+
padding: 0;
|
|
5556
|
+
border: none;
|
|
5557
|
+
border-radius: var(--kds-radius-full);
|
|
5558
|
+
background: var(--kds-color-background-paper);
|
|
5559
|
+
color: var(--kds-color-text-primary);
|
|
5560
|
+
box-shadow: var(--kds-shadow-elevated);
|
|
5561
|
+
cursor: pointer;
|
|
5562
|
+
z-index: 100;
|
|
5563
|
+
/* Neutralize native button rendering so the pressed state doesn't flash a square. */
|
|
5564
|
+
-webkit-appearance: none;
|
|
5565
|
+
appearance: none;
|
|
5566
|
+
-webkit-tap-highlight-color: transparent;
|
|
5567
|
+
transition: opacity var(--kds-transition-short) ease, transform var(--kds-transition-short) ease,
|
|
5568
|
+
background-color var(--kds-transition-shorter) ease;
|
|
5569
|
+
}
|
|
5570
|
+
|
|
5571
|
+
/* Keep the circle in EVERY interaction state. Uses `button.kds-fab` (element + class) to
|
|
5572
|
+
out-specify BeerCSS's base `button`/`button:active` rules — same trick as `.kds-btn`. */
|
|
5573
|
+
button.kds-fab,
|
|
5574
|
+
button.kds-fab:hover,
|
|
5575
|
+
button.kds-fab:active,
|
|
5576
|
+
button.kds-fab:focus,
|
|
5577
|
+
button.kds-fab:focus-visible {
|
|
5578
|
+
border-radius: var(--kds-radius-full);
|
|
5579
|
+
background: var(--kds-color-background-paper);
|
|
5580
|
+
}
|
|
5581
|
+
|
|
5582
|
+
button.kds-fab:hover:not(:disabled) {
|
|
5583
|
+
background: var(--kds-color-background-muted);
|
|
5584
|
+
}
|
|
5585
|
+
|
|
5586
|
+
/* Subtle press feedback that preserves the round shape. */
|
|
5587
|
+
button.kds-fab:active:not(:disabled) {
|
|
5588
|
+
transform: translateY(var(--kds-spacing-0-25));
|
|
5589
|
+
}
|
|
5590
|
+
|
|
5591
|
+
button.kds-fab:focus-visible {
|
|
5592
|
+
outline: var(--kds-spacing-0-25) solid var(--kds-color-primary-main);
|
|
5593
|
+
outline-offset: var(--kds-spacing-0-25);
|
|
5594
|
+
}
|
|
5595
|
+
|
|
5596
|
+
.kds-fab > i.material-symbols-outlined {
|
|
5597
|
+
font-size: var(--kds-spacing-button-icon-size);
|
|
5598
|
+
line-height: 1;
|
|
5599
|
+
}
|
|
5600
|
+
|
|
5601
|
+
/* Pinned corners — fixed to the viewport (stays visible on scroll-up, iframe-friendly).
|
|
5602
|
+
Horizontally the top-right FAB hugs the right edge of the centered content column set via
|
|
5603
|
+
`--kds-fab-column-width` (default 100% → viewport edge). The consumer sets that var to its
|
|
5604
|
+
widget width so on desktop the FAB overlaps the header's top-right corner instead of drifting
|
|
5605
|
+
to the far viewport edge. `max(...)` keeps at least a token inset on narrow (mobile) viewports. */
|
|
5606
|
+
.kds-fab--top-right,
|
|
5607
|
+
.kds-fab--top-left,
|
|
5608
|
+
.kds-fab--bottom-right,
|
|
5609
|
+
.kds-fab--bottom-left {
|
|
5610
|
+
position: fixed;
|
|
5611
|
+
}
|
|
5612
|
+
|
|
5613
|
+
.kds-fab--top-right {
|
|
5614
|
+
top: var(--kds-spacing-2);
|
|
5615
|
+
right: max(var(--kds-spacing-2), calc((100% - var(--kds-fab-column-width, 100%)) / 2 + var(--kds-spacing-2)));
|
|
5616
|
+
}
|
|
5617
|
+
|
|
5618
|
+
.kds-fab--top-left {
|
|
5619
|
+
top: var(--kds-spacing-2);
|
|
5620
|
+
left: max(var(--kds-spacing-2), calc((100% - var(--kds-fab-column-width, 100%)) / 2 + var(--kds-spacing-2)));
|
|
5621
|
+
}
|
|
5622
|
+
|
|
5623
|
+
.kds-fab--bottom-right {
|
|
5624
|
+
bottom: var(--kds-spacing-2);
|
|
5625
|
+
right: max(var(--kds-spacing-2), calc((100% - var(--kds-fab-column-width, 100%)) / 2 + var(--kds-spacing-2)));
|
|
5626
|
+
}
|
|
5627
|
+
|
|
5628
|
+
.kds-fab--bottom-left {
|
|
5629
|
+
bottom: var(--kds-spacing-2);
|
|
5630
|
+
left: max(var(--kds-spacing-2), calc((100% - var(--kds-fab-column-width, 100%)) / 2 + var(--kds-spacing-2)));
|
|
5631
|
+
}
|
|
5632
|
+
|
|
5633
|
+
/* Desktop: nudge the top-right FAB up so it sits partially over the header's top edge. */
|
|
5634
|
+
@media (min-width: 768px) {
|
|
5635
|
+
.kds-fab--top-right {
|
|
5636
|
+
top: var(--kds-spacing-1);
|
|
5637
|
+
}
|
|
5638
|
+
}
|
|
5639
|
+
|
|
5640
|
+
/* Hidden (scroll-away) state — fade + slide toward the nearest edge */
|
|
5641
|
+
.kds-fab--hidden {
|
|
5642
|
+
opacity: 0;
|
|
5643
|
+
transform: translateY(calc(-1 * var(--kds-spacing-1))) scale(0.9);
|
|
5644
|
+
pointer-events: none;
|
|
5645
|
+
}
|
|
5646
|
+
|
|
5647
|
+
.kds-fab--bottom-right.kds-fab--hidden,
|
|
5648
|
+
.kds-fab--bottom-left.kds-fab--hidden {
|
|
5649
|
+
transform: translateY(var(--kds-spacing-1)) scale(0.9);
|
|
5650
|
+
}
|
|
5651
|
+
|
|
5652
|
+
@media (prefers-reduced-motion: reduce) {
|
|
5653
|
+
.kds-fab {
|
|
5654
|
+
transition: opacity var(--kds-transition-short) ease;
|
|
5655
|
+
}
|
|
5656
|
+
|
|
5657
|
+
.kds-fab--hidden {
|
|
5658
|
+
transform: none;
|
|
5659
|
+
}
|
|
5660
|
+
}
|
|
5661
|
+
|
|
5511
5662
|
/* ========================================
|
|
5512
5663
|
09 - SUCCESS MARK (.kds-success-mark)
|
|
5513
5664
|
Large success icon for completion screens
|
|
@@ -5631,10 +5782,8 @@ dialog#surveyModal button.circle {
|
|
|
5631
5782
|
display: block;
|
|
5632
5783
|
object-fit: contain;
|
|
5633
5784
|
overflow: visible;
|
|
5634
|
-
/*
|
|
5635
|
-
|
|
5636
|
-
position: relative;
|
|
5637
|
-
top: 1px;
|
|
5785
|
+
/* La tinta del wordmark ocupa casi todo su viewBox (45x15), así que el centro de caja
|
|
5786
|
+
coincide con el óptico: se alinea por `align-items: center` del footer, sin nudge. */
|
|
5638
5787
|
}
|
|
5639
5788
|
|
|
5640
5789
|
/* Divisor entre el logo de Khipu y el del PSP ("Khipu | klap") */
|
|
@@ -892,6 +892,7 @@ const ui = _context.ui;
|
|
|
892
892
|
initCountdown();
|
|
893
893
|
initSegmentedTabs();
|
|
894
894
|
initStickyInvoice();
|
|
895
|
+
initHideOnScroll();
|
|
895
896
|
initBankModal();
|
|
896
897
|
|
|
897
898
|
console.log('Material Design initialization complete!');
|
|
@@ -1429,6 +1430,67 @@ const ui = _context.ui;
|
|
|
1429
1430
|
onScroll();
|
|
1430
1431
|
}
|
|
1431
1432
|
|
|
1433
|
+
/**
|
|
1434
|
+
* Initialize hide-on-scroll for floating elements (vanilla equivalent of the React
|
|
1435
|
+
* `useHideOnScroll` hook). Any element with `[data-hide-on-scroll]` gets its hide class
|
|
1436
|
+
* (default `kds-fab--hidden`, override with `data-hide-class`) toggled: hidden when
|
|
1437
|
+
* scrolling down past the threshold, shown when scrolling up, always shown within
|
|
1438
|
+
* `data-hide-top-offset` px of the top. Tune with `data-hide-threshold` (default 8).
|
|
1439
|
+
*
|
|
1440
|
+
* Works standalone (`window.scrollY`) and embedded in an iframe, where the parent posts
|
|
1441
|
+
* `postMessage({ type: 'VIEWPORT_OFFSET', offsetTop })`.
|
|
1442
|
+
* @param {Element} root - Root element to scope the query (default: document)
|
|
1443
|
+
*/
|
|
1444
|
+
function initHideOnScroll(root) {
|
|
1445
|
+
root = root || document;
|
|
1446
|
+
var els = root.querySelectorAll('[data-hide-on-scroll]');
|
|
1447
|
+
if (!els.length) return;
|
|
1448
|
+
|
|
1449
|
+
var viewportOffset = 0;
|
|
1450
|
+
var ticking = false;
|
|
1451
|
+
var lastYs = new Map();
|
|
1452
|
+
|
|
1453
|
+
function currentY() {
|
|
1454
|
+
return Math.max(window.scrollY || window.pageYOffset || 0, viewportOffset);
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
function apply() {
|
|
1458
|
+
ticking = false;
|
|
1459
|
+
var y = currentY();
|
|
1460
|
+
els.forEach(function(el) {
|
|
1461
|
+
var threshold = parseInt(el.getAttribute('data-hide-threshold'), 10) || 8;
|
|
1462
|
+
var topOffset = parseInt(el.getAttribute('data-hide-top-offset'), 10) || 0;
|
|
1463
|
+
var hideClass = el.getAttribute('data-hide-class') || 'kds-fab--hidden';
|
|
1464
|
+
var lastY = lastYs.has(el) ? lastYs.get(el) : y;
|
|
1465
|
+
if (y <= topOffset) {
|
|
1466
|
+
el.classList.remove(hideClass);
|
|
1467
|
+
lastYs.set(el, y);
|
|
1468
|
+
return;
|
|
1469
|
+
}
|
|
1470
|
+
var delta = y - lastY;
|
|
1471
|
+
if (Math.abs(delta) < threshold) return;
|
|
1472
|
+
el.classList.toggle(hideClass, delta > 0);
|
|
1473
|
+
lastYs.set(el, y);
|
|
1474
|
+
});
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
function onScroll() {
|
|
1478
|
+
if (ticking) return;
|
|
1479
|
+
ticking = true;
|
|
1480
|
+
requestAnimationFrame(apply);
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
window.addEventListener('scroll', onScroll, { passive: true });
|
|
1484
|
+
window.addEventListener('resize', onScroll);
|
|
1485
|
+
window.addEventListener('message', function(event) {
|
|
1486
|
+
if (event.data && event.data.type === 'VIEWPORT_OFFSET') {
|
|
1487
|
+
viewportOffset = Math.max(0, event.data.offsetTop || 0);
|
|
1488
|
+
onScroll();
|
|
1489
|
+
}
|
|
1490
|
+
});
|
|
1491
|
+
apply();
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1432
1494
|
/**
|
|
1433
1495
|
* Initialize copyable table rows
|
|
1434
1496
|
* Delegated click on .kds-copyable-table-row[data-copy] copies value and shows feedback
|
|
@@ -1599,6 +1661,7 @@ const ui = _context.ui;
|
|
|
1599
1661
|
window.Khipu.initInfoTip = initInfoTip;
|
|
1600
1662
|
window.Khipu.initBankModal = initBankModal;
|
|
1601
1663
|
window.Khipu.initStickyInvoice = initStickyInvoice;
|
|
1664
|
+
window.Khipu.initHideOnScroll = initHideOnScroll;
|
|
1602
1665
|
|
|
1603
1666
|
// Also export showSnackbar to global scope for backward compatibility
|
|
1604
1667
|
window.showSnackbar = showSnackbar;
|