@khipu/design-system 0.3.4 → 0.3.5-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,3 +1,6 @@
1
+ // src/theme/KdsThemeProvider.tsx
2
+ import { useEffect } from "react";
3
+
1
4
  // src/components/core/utils.ts
2
5
  import { clsx } from "clsx";
3
6
  function hexToRgb(hex) {
@@ -71,7 +74,70 @@ function formatTime(iso) {
71
74
 
72
75
  // src/theme/KdsThemeProvider.tsx
73
76
  import { jsx } from "react/jsx-runtime";
77
+ var CARD_MIN_DELTA_PX = 8;
78
+ var CARD_TRANSITION_MS = 280;
79
+ var BODY_CARD_SELECTOR = ".kds-screen > .kds-card-elevated";
80
+ var CARD_MARK_ATTRIBUTE = "data-kds-height-transition";
81
+ function useCardHeightTransition() {
82
+ useEffect(() => {
83
+ if (typeof window === "undefined" || typeof ResizeObserver === "undefined") {
84
+ return;
85
+ }
86
+ if (typeof Element.prototype.animate !== "function") {
87
+ return;
88
+ }
89
+ if (window.matchMedia?.("(prefers-reduced-motion: reduce)").matches) {
90
+ return;
91
+ }
92
+ const observers = [];
93
+ const observe = (card) => {
94
+ if (card.getAttribute(CARD_MARK_ATTRIBUTE) === "on") {
95
+ return;
96
+ }
97
+ card.setAttribute(CARD_MARK_ATTRIBUTE, "on");
98
+ let previous = card.offsetHeight;
99
+ let animating = false;
100
+ const observer = new ResizeObserver(() => {
101
+ if (animating) {
102
+ return;
103
+ }
104
+ const next = card.offsetHeight;
105
+ if (Math.abs(next - previous) < CARD_MIN_DELTA_PX) {
106
+ previous = next;
107
+ return;
108
+ }
109
+ animating = true;
110
+ const animation = card.animate(
111
+ [{ height: `${previous}px` }, { height: `${next}px` }],
112
+ { duration: CARD_TRANSITION_MS, easing: "ease-out" }
113
+ );
114
+ previous = next;
115
+ animation.finished.then(() => {
116
+ animating = false;
117
+ previous = card.offsetHeight;
118
+ }).catch(() => {
119
+ animating = false;
120
+ });
121
+ });
122
+ observer.observe(card);
123
+ observers.push(observer);
124
+ };
125
+ document.querySelectorAll(BODY_CARD_SELECTOR).forEach(observe);
126
+ const tree = new MutationObserver(() => {
127
+ document.querySelectorAll(BODY_CARD_SELECTOR).forEach(observe);
128
+ });
129
+ tree.observe(document.body, { childList: true, subtree: true });
130
+ return () => {
131
+ tree.disconnect();
132
+ observers.forEach((observer) => observer.disconnect());
133
+ document.querySelectorAll(BODY_CARD_SELECTOR).forEach((card) => {
134
+ card.removeAttribute(CARD_MARK_ATTRIBUTE);
135
+ });
136
+ };
137
+ }, []);
138
+ }
74
139
  function KdsThemeProvider({ primaryColor, mode = "light", children }) {
140
+ useCardHeightTransition();
75
141
  const style = primaryColor ? {
76
142
  "--primary": primaryColor,
77
143
  "--on-primary": getContrastColor(primaryColor),
@@ -1454,7 +1520,7 @@ var KdsTypography = forwardRef11(
1454
1520
  KdsTypography.displayName = "KdsTypography";
1455
1521
 
1456
1522
  // src/components/core/KdsTabs/KdsTabs.tsx
1457
- import React12, { forwardRef as forwardRef12, Children, useMemo } from "react";
1523
+ import React13, { forwardRef as forwardRef12, Children, useMemo } from "react";
1458
1524
 
1459
1525
  // src/components/core/hooks/useTabsKeyboard.ts
1460
1526
  import { useCallback as useCallback2 } from "react";
@@ -1502,8 +1568,8 @@ var KdsTabs = forwardRef12(
1502
1568
  onKeyDown,
1503
1569
  ...props,
1504
1570
  children: Children.map(children, (child, i) => {
1505
- if (!React12.isValidElement(child)) return child;
1506
- return React12.cloneElement(child, {
1571
+ if (!React13.isValidElement(child)) return child;
1572
+ return React13.cloneElement(child, {
1507
1573
  _active: i === activeIndex,
1508
1574
  _onClick: () => onChange(i)
1509
1575
  });
@@ -1664,12 +1730,12 @@ KdsChip.displayName = "KdsChip";
1664
1730
  import { forwardRef as forwardRef16 } from "react";
1665
1731
 
1666
1732
  // src/components/core/hooks/useAutoHide.ts
1667
- import { useState as useState3, useEffect, useRef } from "react";
1733
+ import { useState as useState3, useEffect as useEffect2, useRef } from "react";
1668
1734
  function useAutoHide(durationMs, onHide) {
1669
1735
  const [visible, setVisible] = useState3(true);
1670
1736
  const onHideRef = useRef(onHide);
1671
1737
  onHideRef.current = onHide;
1672
- useEffect(() => {
1738
+ useEffect2(() => {
1673
1739
  if (durationMs <= 0) return;
1674
1740
  const timer = setTimeout(() => {
1675
1741
  setVisible(false);
@@ -2113,10 +2179,10 @@ var KdsExpandPanel = forwardRef24(
2113
2179
  KdsExpandPanel.displayName = "KdsExpandPanel";
2114
2180
 
2115
2181
  // src/components/core/KdsCountdown/KdsCountdown.tsx
2116
- import { forwardRef as forwardRef25, useEffect as useEffect3, useRef as useRef3 } from "react";
2182
+ import { forwardRef as forwardRef25, useEffect as useEffect4, useRef as useRef3 } from "react";
2117
2183
 
2118
2184
  // src/components/core/hooks/useCountdown.ts
2119
- import { useState as useState6, useEffect as useEffect2 } from "react";
2185
+ import { useState as useState6, useEffect as useEffect3 } from "react";
2120
2186
  function calcRemaining(deadline) {
2121
2187
  const diff = Math.max(0, new Date(deadline).getTime() - Date.now());
2122
2188
  const totalSeconds = Math.floor(diff / 1e3);
@@ -2130,7 +2196,7 @@ function calcRemaining(deadline) {
2130
2196
  }
2131
2197
  function useCountdown(deadline) {
2132
2198
  const [state, setState] = useState6(() => calcRemaining(deadline));
2133
- useEffect2(() => {
2199
+ useEffect3(() => {
2134
2200
  const tick = () => setState(calcRemaining(deadline));
2135
2201
  const id = setInterval(tick, 1e3);
2136
2202
  return () => clearInterval(id);
@@ -2145,7 +2211,7 @@ var KdsCountdown = forwardRef25(
2145
2211
  const { hours, minutes, seconds, expired, urgent } = useCountdown(deadline);
2146
2212
  const onExpireRef = useRef3(onExpire);
2147
2213
  onExpireRef.current = onExpire;
2148
- useEffect3(() => {
2214
+ useEffect4(() => {
2149
2215
  if (expired) {
2150
2216
  onExpireRef.current?.();
2151
2217
  }
@@ -2524,7 +2590,7 @@ KdsMerchantTile.displayName = "KdsMerchantTile";
2524
2590
  import { forwardRef as forwardRef42, useState as useState9 } from "react";
2525
2591
 
2526
2592
  // src/components/domain/KdsInvoiceMerchant/useLogoBackdrop.ts
2527
- import { useEffect as useEffect4, useState as useState8 } from "react";
2593
+ import { useEffect as useEffect5, useState as useState8 } from "react";
2528
2594
 
2529
2595
  // src/components/domain/KdsInvoiceMerchant/logoLuminance.ts
2530
2596
  var LIGHT_LOGO_LUMINANCE_THRESHOLD = 0.72;
@@ -2574,7 +2640,7 @@ function pickLogoBackdrop(luminance) {
2574
2640
  // src/components/domain/KdsInvoiceMerchant/useLogoBackdrop.ts
2575
2641
  function useLogoBackdrop(logoUrl) {
2576
2642
  const [backdrop, setBackdrop] = useState8("light");
2577
- useEffect4(() => {
2643
+ useEffect5(() => {
2578
2644
  let cancelled = false;
2579
2645
  setBackdrop("light");
2580
2646
  if (!logoUrl) {
@@ -2816,12 +2882,12 @@ var guideToFirstInvalidFieldOnBlur = (form) => {
2816
2882
  };
2817
2883
 
2818
2884
  // src/components/core/hooks/useStickyInvoiceCollapse.ts
2819
- import { useEffect as useEffect5, useRef as useRef4 } from "react";
2885
+ import { useEffect as useEffect6, useRef as useRef4 } from "react";
2820
2886
  function useStickyInvoiceCollapse(options = {}) {
2821
2887
  const { onCollapseStart, collapseEnd = 20, mobileBreakpoint = 768 } = options;
2822
2888
  const onCollapseStartRef = useRef4(onCollapseStart);
2823
2889
  onCollapseStartRef.current = onCollapseStart;
2824
- useEffect5(() => {
2890
+ useEffect6(() => {
2825
2891
  let viewportOffset = 0;
2826
2892
  let ticking = false;
2827
2893
  let wasCollapsing = false;
@@ -2943,11 +3009,11 @@ function useExpandToggle(options = {}) {
2943
3009
  }
2944
3010
 
2945
3011
  // src/components/core/hooks/useHideOnScroll.ts
2946
- import { useEffect as useEffect6, useState as useState11 } from "react";
3012
+ import { useEffect as useEffect7, useState as useState11 } from "react";
2947
3013
  function useHideOnScroll(options = {}) {
2948
3014
  const { threshold = 8, topOffset = 0 } = options;
2949
3015
  const [hidden, setHidden] = useState11(false);
2950
- useEffect6(() => {
3016
+ useEffect7(() => {
2951
3017
  let viewportOffset = 0;
2952
3018
  let lastY = 0;
2953
3019
  let ticking = false;
@@ -2990,12 +3056,12 @@ function useHideOnScroll(options = {}) {
2990
3056
  }
2991
3057
 
2992
3058
  // src/components/core/hooks/useMediaQuery.ts
2993
- import { useEffect as useEffect7, useState as useState12 } from "react";
3059
+ import { useEffect as useEffect8, useState as useState12 } from "react";
2994
3060
  function useMediaQuery(query) {
2995
3061
  const [matches, setMatches] = useState12(
2996
3062
  () => typeof window !== "undefined" ? window.matchMedia(query).matches : false
2997
3063
  );
2998
- useEffect7(() => {
3064
+ useEffect8(() => {
2999
3065
  if (typeof window === "undefined") return;
3000
3066
  const mql = window.matchMedia(query);
3001
3067
  setMatches(mql.matches);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khipu/design-system",
3
- "version": "0.3.4",
3
+ "version": "0.3.5-alpha.2",
4
4
  "description": "Khipu Design System - UI components and design tokens for the Khipu payment platform",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",