premium-react-loaders 1.1.0 → 1.3.0

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.
Files changed (154) hide show
  1. package/README.md +55 -6
  2. package/dist/components/overlay/LoaderOverlay.d.ts.map +1 -1
  3. package/dist/components/progress/ProgressBar.d.ts.map +1 -1
  4. package/dist/components/progress/ProgressCircle.d.ts.map +1 -1
  5. package/dist/components/progress/ProgressRing.d.ts.map +1 -1
  6. package/dist/components/progress/ProgressSteps.d.ts.map +1 -1
  7. package/dist/components/pulse/PulseBars.d.ts +2 -2
  8. package/dist/components/pulse/PulseBars.d.ts.map +1 -1
  9. package/dist/components/pulse/PulseDots.d.ts +2 -2
  10. package/dist/components/pulse/PulseDots.d.ts.map +1 -1
  11. package/dist/components/pulse/PulseWave.d.ts +2 -2
  12. package/dist/components/pulse/PulseWave.d.ts.map +1 -1
  13. package/dist/components/pulse/TypingIndicator.d.ts.map +1 -1
  14. package/dist/components/skeleton/Skeleton.d.ts.map +1 -1
  15. package/dist/components/skeleton/SkeletonAvatar.d.ts.map +1 -1
  16. package/dist/components/skeleton/SkeletonCard.d.ts.map +1 -1
  17. package/dist/components/skeleton/SkeletonForm.d.ts.map +1 -1
  18. package/dist/components/skeleton/SkeletonImage.d.ts.map +1 -1
  19. package/dist/components/skeleton/SkeletonList.d.ts.map +1 -1
  20. package/dist/components/skeleton/SkeletonPage.d.ts.map +1 -1
  21. package/dist/components/skeleton/SkeletonTable.d.ts.map +1 -1
  22. package/dist/components/skeleton/SkeletonText.d.ts.map +1 -1
  23. package/dist/components/spinner/SpinnerBars.d.ts +2 -2
  24. package/dist/components/spinner/SpinnerBars.d.ts.map +1 -1
  25. package/dist/components/spinner/SpinnerCircle.d.ts +2 -1
  26. package/dist/components/spinner/SpinnerCircle.d.ts.map +1 -1
  27. package/dist/components/spinner/SpinnerDots.d.ts +2 -2
  28. package/dist/components/spinner/SpinnerDots.d.ts.map +1 -1
  29. package/dist/components/spinner/SpinnerGrid.d.ts +2 -2
  30. package/dist/components/spinner/SpinnerGrid.d.ts.map +1 -1
  31. package/dist/components/spinner/SpinnerPulse.d.ts +3 -3
  32. package/dist/components/spinner/SpinnerPulse.d.ts.map +1 -1
  33. package/dist/components/spinner/SpinnerRing.d.ts +3 -3
  34. package/dist/components/spinner/SpinnerRing.d.ts.map +1 -1
  35. package/dist/components/spinner/SpinnerWave.d.ts +3 -3
  36. package/dist/components/spinner/SpinnerWave.d.ts.map +1 -1
  37. package/dist/index10.cjs +14 -2
  38. package/dist/index10.cjs.map +1 -1
  39. package/dist/index10.js +14 -2
  40. package/dist/index10.js.map +1 -1
  41. package/dist/index11.cjs +16 -2
  42. package/dist/index11.cjs.map +1 -1
  43. package/dist/index11.js +16 -2
  44. package/dist/index11.js.map +1 -1
  45. package/dist/index12.cjs +16 -2
  46. package/dist/index12.cjs.map +1 -1
  47. package/dist/index12.js +16 -2
  48. package/dist/index12.js.map +1 -1
  49. package/dist/index13.cjs +12 -2
  50. package/dist/index13.cjs.map +1 -1
  51. package/dist/index13.js +12 -2
  52. package/dist/index13.js.map +1 -1
  53. package/dist/index14.cjs +24 -5
  54. package/dist/index14.cjs.map +1 -1
  55. package/dist/index14.js +24 -5
  56. package/dist/index14.js.map +1 -1
  57. package/dist/index15.cjs +23 -4
  58. package/dist/index15.cjs.map +1 -1
  59. package/dist/index15.js +24 -5
  60. package/dist/index15.js.map +1 -1
  61. package/dist/index16.cjs +23 -4
  62. package/dist/index16.cjs.map +1 -1
  63. package/dist/index16.js +24 -5
  64. package/dist/index16.js.map +1 -1
  65. package/dist/index17.cjs +21 -6
  66. package/dist/index17.cjs.map +1 -1
  67. package/dist/index17.js +22 -7
  68. package/dist/index17.js.map +1 -1
  69. package/dist/index18.cjs +25 -7
  70. package/dist/index18.cjs.map +1 -1
  71. package/dist/index18.js +26 -8
  72. package/dist/index18.js.map +1 -1
  73. package/dist/index19.cjs +24 -6
  74. package/dist/index19.cjs.map +1 -1
  75. package/dist/index19.js +25 -7
  76. package/dist/index19.js.map +1 -1
  77. package/dist/index20.cjs +24 -6
  78. package/dist/index20.cjs.map +1 -1
  79. package/dist/index20.js +25 -7
  80. package/dist/index20.js.map +1 -1
  81. package/dist/index21.cjs +21 -5
  82. package/dist/index21.cjs.map +1 -1
  83. package/dist/index21.js +22 -6
  84. package/dist/index21.js.map +1 -1
  85. package/dist/index22.cjs +24 -6
  86. package/dist/index22.cjs.map +1 -1
  87. package/dist/index22.js +25 -7
  88. package/dist/index22.js.map +1 -1
  89. package/dist/index23.cjs +25 -7
  90. package/dist/index23.cjs.map +1 -1
  91. package/dist/index23.js +26 -8
  92. package/dist/index23.js.map +1 -1
  93. package/dist/index24.cjs +16 -2
  94. package/dist/index24.cjs.map +1 -1
  95. package/dist/index24.js +16 -2
  96. package/dist/index24.js.map +1 -1
  97. package/dist/index25.cjs +21 -6
  98. package/dist/index25.cjs.map +1 -1
  99. package/dist/index25.js +22 -7
  100. package/dist/index25.js.map +1 -1
  101. package/dist/index26.cjs +22 -7
  102. package/dist/index26.cjs.map +1 -1
  103. package/dist/index26.js +23 -8
  104. package/dist/index26.js.map +1 -1
  105. package/dist/index27.cjs +23 -7
  106. package/dist/index27.cjs.map +1 -1
  107. package/dist/index27.js +24 -8
  108. package/dist/index27.js.map +1 -1
  109. package/dist/index28.cjs +20 -5
  110. package/dist/index28.cjs.map +1 -1
  111. package/dist/index28.js +21 -6
  112. package/dist/index28.js.map +1 -1
  113. package/dist/index29.cjs +14 -2
  114. package/dist/index29.cjs.map +1 -1
  115. package/dist/index29.js +14 -2
  116. package/dist/index29.js.map +1 -1
  117. package/dist/index31.cjs +126 -0
  118. package/dist/index31.cjs.map +1 -0
  119. package/dist/index31.js +126 -0
  120. package/dist/index31.js.map +1 -0
  121. package/dist/index4.cjs +10 -0
  122. package/dist/index4.cjs.map +1 -1
  123. package/dist/index4.js +10 -0
  124. package/dist/index4.js.map +1 -1
  125. package/dist/index5.cjs +14 -2
  126. package/dist/index5.cjs.map +1 -1
  127. package/dist/index5.js +14 -2
  128. package/dist/index5.js.map +1 -1
  129. package/dist/index6.cjs +14 -2
  130. package/dist/index6.cjs.map +1 -1
  131. package/dist/index6.js +14 -2
  132. package/dist/index6.js.map +1 -1
  133. package/dist/index7.cjs +16 -2
  134. package/dist/index7.cjs.map +1 -1
  135. package/dist/index7.js +16 -2
  136. package/dist/index7.js.map +1 -1
  137. package/dist/index8.cjs +14 -2
  138. package/dist/index8.cjs.map +1 -1
  139. package/dist/index8.js +14 -2
  140. package/dist/index8.js.map +1 -1
  141. package/dist/index9.cjs +16 -2
  142. package/dist/index9.cjs.map +1 -1
  143. package/dist/index9.js +16 -2
  144. package/dist/index9.js.map +1 -1
  145. package/dist/premium-react-loaders.css +405 -6
  146. package/dist/types/common.d.ts +20 -2
  147. package/dist/types/common.d.ts.map +1 -1
  148. package/dist/utils/colors.d.ts +2 -1
  149. package/dist/utils/colors.d.ts.map +1 -1
  150. package/dist/utils/hooks.d.ts +19 -0
  151. package/dist/utils/hooks.d.ts.map +1 -0
  152. package/dist/utils/index.d.ts +1 -0
  153. package/dist/utils/index.d.ts.map +1 -1
  154. package/package.json +1 -1
package/dist/index28.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { forwardRef } from "react";
3
- import { normalizeSize, getAnimationDuration } from "./index4.js";
3
+ import { useReducedMotion, useLoaderVisibility, getEffectiveDuration } from "./index31.js";
4
+ import { normalizeSize } from "./index4.js";
4
5
  import { cn } from "./index3.js";
5
6
  const TypingIndicator = forwardRef(
6
7
  ({
@@ -11,6 +12,11 @@ const TypingIndicator = forwardRef(
11
12
  gap = 4,
12
13
  variant = "bounce",
13
14
  speed = "normal",
15
+ reverse = false,
16
+ respectMotionPreference = true,
17
+ delay = 0,
18
+ minDuration = 0,
19
+ transition,
14
20
  className,
15
21
  style,
16
22
  testId = "typing-indicator",
@@ -18,8 +24,15 @@ const TypingIndicator = forwardRef(
18
24
  ariaLabel = "Typing...",
19
25
  ...rest
20
26
  }, ref) => {
21
- if (!visible) return null;
22
- const animationDuration = getAnimationDuration(speed);
27
+ const prefersReducedMotion = useReducedMotion();
28
+ const effectiveDuration = getEffectiveDuration(speed, respectMotionPreference, prefersReducedMotion);
29
+ const { shouldRender, opacity, transitionStyle } = useLoaderVisibility(
30
+ visible,
31
+ delay,
32
+ minDuration,
33
+ transition
34
+ );
35
+ if (!shouldRender) return null;
23
36
  const gapValue = normalizeSize(gap);
24
37
  return /* @__PURE__ */ jsx(
25
38
  "div",
@@ -30,7 +43,9 @@ const TypingIndicator = forwardRef(
30
43
  style: {
31
44
  gap: gapValue,
32
45
  height: size ? normalizeSize(size) : "auto",
33
- ...style
46
+ ...style,
47
+ opacity,
48
+ transition: transitionStyle
34
49
  },
35
50
  role: "status",
36
51
  "aria-label": ariaLabel,
@@ -44,8 +59,8 @@ const TypingIndicator = forwardRef(
44
59
  width: normalizeSize(dotSize),
45
60
  height: normalizeSize(dotSize),
46
61
  backgroundColor: color,
47
- animation: `typing-${variant} ${animationDuration} ease-in-out infinite`,
48
- animationDelay: `${index * 0.2}s`
62
+ animation: `typing-${variant} ${effectiveDuration} ease-in-out infinite`,
63
+ animationDelay: reverse ? `${(dotCount - index - 1) * 0.2}s` : `${index * 0.2}s`
49
64
  }
50
65
  },
51
66
  index
@@ -1 +1 @@
1
- {"version":3,"file":"index28.js","sources":["../src/components/pulse/TypingIndicator.tsx"],"sourcesContent":["import { forwardRef } from 'react';\nimport { TypingIndicatorProps } from '../../types';\nimport { cn, normalizeSize, getAnimationDuration } from '../../utils';\n\n/**\n * TypingIndicator - Chat typing indicator\n *\n * A loader for messaging/chat applications showing typing activity.\n *\n * @example\n * ```tsx\n * <TypingIndicator />\n * <TypingIndicator variant=\"fade\" />\n * <TypingIndicator dotCount={5} color=\"#3b82f6\" />\n * <TypingIndicator dotSize={10} gap={6} />\n * ```\n */\nexport const TypingIndicator = forwardRef<HTMLDivElement, TypingIndicatorProps>(\n (\n {\n size,\n color = '#3b82f6',\n dotCount = 3,\n dotSize = 8,\n gap = 4,\n variant = 'bounce',\n speed = 'normal',\n className,\n style,\n testId = 'typing-indicator',\n visible = true,\n ariaLabel = 'Typing...',\n ...rest\n },\n ref\n ) => {\n if (!visible) return null;\n\n const animationDuration = getAnimationDuration(speed);\n const gapValue = normalizeSize(gap);\n\n return (\n <div\n ref={ref}\n data-testid={testId}\n className={cn('inline-flex items-center', className)}\n style={{\n gap: gapValue,\n height: size ? normalizeSize(size) : 'auto',\n ...style,\n }}\n role=\"status\"\n aria-label={ariaLabel}\n aria-busy=\"true\"\n {...rest}\n >\n {Array.from({ length: dotCount }).map((_, index) => (\n <div\n key={index}\n className=\"rounded-full\"\n style={{\n width: normalizeSize(dotSize),\n height: normalizeSize(dotSize),\n backgroundColor: color,\n animation: `typing-${variant} ${animationDuration} ease-in-out infinite`,\n animationDelay: `${index * 0.2}s`,\n }}\n />\n ))}\n </div>\n );\n }\n);\n\nTypingIndicator.displayName = 'TypingIndicator';\n"],"names":[],"mappings":";;;;AAiBO,MAAM,kBAAkB;AAAA,EAC7B,CACE;AAAA,IACE;AAAA,IACA,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,UAAU;AAAA,IACV,MAAM;AAAA,IACN,UAAU;AAAA,IACV,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,GAAG;AAAA,EAAA,GAEL,QACG;AACH,QAAI,CAAC,QAAS,QAAO;AAErB,UAAM,oBAAoB,qBAAqB,KAAK;AACpD,UAAM,WAAW,cAAc,GAAG;AAElC,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAa;AAAA,QACb,WAAW,GAAG,4BAA4B,SAAS;AAAA,QACnD,OAAO;AAAA,UACL,KAAK;AAAA,UACL,QAAQ,OAAO,cAAc,IAAI,IAAI;AAAA,UACrC,GAAG;AAAA,QAAA;AAAA,QAEL,MAAK;AAAA,QACL,cAAY;AAAA,QACZ,aAAU;AAAA,QACT,GAAG;AAAA,QAEH,UAAA,MAAM,KAAK,EAAE,QAAQ,UAAU,EAAE,IAAI,CAAC,GAAG,UACxC;AAAA,UAAC;AAAA,UAAA;AAAA,YAEC,WAAU;AAAA,YACV,OAAO;AAAA,cACL,OAAO,cAAc,OAAO;AAAA,cAC5B,QAAQ,cAAc,OAAO;AAAA,cAC7B,iBAAiB;AAAA,cACjB,WAAW,UAAU,OAAO,IAAI,iBAAiB;AAAA,cACjD,gBAAgB,GAAG,QAAQ,GAAG;AAAA,YAAA;AAAA,UAChC;AAAA,UARK;AAAA,QAAA,CAUR;AAAA,MAAA;AAAA,IAAA;AAAA,EAGP;AACF;AAEA,gBAAgB,cAAc;"}
1
+ {"version":3,"file":"index28.js","sources":["../src/components/pulse/TypingIndicator.tsx"],"sourcesContent":["import { forwardRef } from 'react';\nimport { TypingIndicatorProps } from '../../types';\nimport { cn, normalizeSize, useReducedMotion, getEffectiveDuration, useLoaderVisibility } from '../../utils';\n\n/**\n * TypingIndicator - Chat typing indicator\n *\n * A loader for messaging/chat applications showing typing activity.\n *\n * @example\n * ```tsx\n * <TypingIndicator />\n * <TypingIndicator variant=\"fade\" />\n * <TypingIndicator dotCount={5} color=\"#3b82f6\" />\n * <TypingIndicator dotSize={10} gap={6} />\n * ```\n */\nexport const TypingIndicator = forwardRef<HTMLDivElement, TypingIndicatorProps>(\n (\n {\n size,\n color = '#3b82f6',\n dotCount = 3,\n dotSize = 8,\n gap = 4,\n variant = 'bounce',\n speed = 'normal',\n reverse = false,\n respectMotionPreference = true,\n delay = 0,\n minDuration = 0,\n transition,\n className,\n style,\n testId = 'typing-indicator',\n visible = true,\n ariaLabel = 'Typing...',\n ...rest\n },\n ref\n ) => {\n const prefersReducedMotion = useReducedMotion();\n const effectiveDuration = getEffectiveDuration(speed, respectMotionPreference, prefersReducedMotion);\n const { shouldRender, opacity, transitionStyle } = useLoaderVisibility(\n visible,\n delay,\n minDuration,\n transition\n );\n\n if (!shouldRender) return null;\n const gapValue = normalizeSize(gap);\n\n return (\n <div\n ref={ref}\n data-testid={testId}\n className={cn('inline-flex items-center', className)}\n style={{\n gap: gapValue,\n height: size ? normalizeSize(size) : 'auto',\n ...style,\n opacity,\n transition: transitionStyle,\n }}\n role=\"status\"\n aria-label={ariaLabel}\n aria-busy=\"true\"\n {...rest}\n >\n {Array.from({ length: dotCount }).map((_, index) => (\n <div\n key={index}\n className=\"rounded-full\"\n style={{\n width: normalizeSize(dotSize),\n height: normalizeSize(dotSize),\n backgroundColor: color,\n animation: `typing-${variant} ${effectiveDuration} ease-in-out infinite`,\n animationDelay: reverse ? `${(dotCount - index - 1) * 0.2}s` : `${index * 0.2}s`,\n }}\n />\n ))}\n </div>\n );\n }\n);\n\nTypingIndicator.displayName = 'TypingIndicator';\n"],"names":[],"mappings":";;;;;AAiBO,MAAM,kBAAkB;AAAA,EAC7B,CACE;AAAA,IACE;AAAA,IACA,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,UAAU;AAAA,IACV,MAAM;AAAA,IACN,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,0BAA0B;AAAA,IAC1B,QAAQ;AAAA,IACR,cAAc;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,GAAG;AAAA,EAAA,GAEL,QACG;AACH,UAAM,uBAAuB,iBAAA;AAC7B,UAAM,oBAAoB,qBAAqB,OAAO,yBAAyB,oBAAoB;AACnG,UAAM,EAAE,cAAc,SAAS,gBAAA,IAAoB;AAAA,MACjD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAGF,QAAI,CAAC,aAAc,QAAO;AAC1B,UAAM,WAAW,cAAc,GAAG;AAElC,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAa;AAAA,QACb,WAAW,GAAG,4BAA4B,SAAS;AAAA,QACnD,OAAO;AAAA,UACL,KAAK;AAAA,UACL,QAAQ,OAAO,cAAc,IAAI,IAAI;AAAA,UACrC,GAAG;AAAA,UACH;AAAA,UACA,YAAY;AAAA,QAAA;AAAA,QAEd,MAAK;AAAA,QACL,cAAY;AAAA,QACZ,aAAU;AAAA,QACT,GAAG;AAAA,QAEH,UAAA,MAAM,KAAK,EAAE,QAAQ,UAAU,EAAE,IAAI,CAAC,GAAG,UACxC;AAAA,UAAC;AAAA,UAAA;AAAA,YAEC,WAAU;AAAA,YACV,OAAO;AAAA,cACL,OAAO,cAAc,OAAO;AAAA,cAC5B,QAAQ,cAAc,OAAO;AAAA,cAC7B,iBAAiB;AAAA,cACjB,WAAW,UAAU,OAAO,IAAI,iBAAiB;AAAA,cACjD,gBAAgB,UAAU,IAAI,WAAW,QAAQ,KAAK,GAAG,MAAM,GAAG,QAAQ,GAAG;AAAA,YAAA;AAAA,UAC/E;AAAA,UARK;AAAA,QAAA,CAUR;AAAA,MAAA;AAAA,IAAA;AAAA,EAGP;AACF;AAEA,gBAAgB,cAAc;"}
package/dist/index29.cjs CHANGED
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const jsxRuntime = require("react/jsx-runtime");
4
4
  const react = require("react");
5
+ const hooks = require("./index31.cjs");
5
6
  const classNames = require("./index3.cjs");
6
7
  const LoaderOverlay = react.forwardRef(
7
8
  ({
@@ -12,6 +13,9 @@ const LoaderOverlay = react.forwardRef(
12
13
  backdropOpacity = 0.5,
13
14
  backdropColor = "#000000",
14
15
  blur = false,
16
+ delay = 0,
17
+ minDuration = 0,
18
+ transition,
15
19
  className,
16
20
  style,
17
21
  testId = "loader-overlay",
@@ -19,6 +23,12 @@ const LoaderOverlay = react.forwardRef(
19
23
  zIndex = 9999,
20
24
  ...rest
21
25
  }, ref) => {
26
+ const { shouldRender, opacity, transitionStyle } = hooks.useLoaderVisibility(
27
+ loading,
28
+ delay,
29
+ minDuration,
30
+ transition
31
+ );
22
32
  const backdropStyles = {
23
33
  backgroundColor: backdropColor,
24
34
  opacity: backdropOpacity,
@@ -35,7 +45,7 @@ const LoaderOverlay = react.forwardRef(
35
45
  ...rest,
36
46
  children: [
37
47
  children,
38
- loading && /* @__PURE__ */ jsxRuntime.jsxs(
48
+ shouldRender && /* @__PURE__ */ jsxRuntime.jsxs(
39
49
  "div",
40
50
  {
41
51
  className: classNames.cn(
@@ -43,7 +53,9 @@ const LoaderOverlay = react.forwardRef(
43
53
  position === "fixed" ? "fixed" : "absolute"
44
54
  ),
45
55
  style: {
46
- zIndex
56
+ zIndex,
57
+ opacity,
58
+ transition: transitionStyle
47
59
  },
48
60
  role: "status",
49
61
  "aria-label": ariaLabel,
@@ -1 +1 @@
1
- {"version":3,"file":"index29.cjs","sources":["../src/components/overlay/LoaderOverlay.tsx"],"sourcesContent":["import { forwardRef } from 'react';\nimport { LoaderOverlayProps } from '../../types';\nimport { cn } from '../../utils';\n\n/**\n * LoaderOverlay - Overlay wrapper for displaying loaders over content\n *\n * A flexible overlay component that displays a loader over content during loading states.\n * Supports both full-screen and container-relative positioning.\n *\n * @example\n * ```tsx\n * // Full screen overlay\n * <LoaderOverlay loading={isLoading} loader={<SpinnerCircle />}>\n * <YourContent />\n * </LoaderOverlay>\n *\n * // Container overlay with custom backdrop\n * <LoaderOverlay\n * loading={isLoading}\n * loader={<SpinnerRing />}\n * position=\"absolute\"\n * backdropOpacity={0.7}\n * blur\n * >\n * <YourContent />\n * </LoaderOverlay>\n * ```\n */\nexport const LoaderOverlay = forwardRef<HTMLDivElement, LoaderOverlayProps>(\n (\n {\n loading = false,\n loader,\n children,\n position = 'fixed',\n backdropOpacity = 0.5,\n backdropColor = '#000000',\n blur = false,\n className,\n style,\n testId = 'loader-overlay',\n ariaLabel = 'Loading content...',\n zIndex = 9999,\n ...rest\n },\n ref\n ) => {\n const backdropStyles = {\n backgroundColor: backdropColor,\n opacity: backdropOpacity,\n backdropFilter: blur ? 'blur(4px)' : undefined,\n WebkitBackdropFilter: blur ? 'blur(4px)' : undefined,\n };\n\n return (\n <div\n ref={ref}\n data-testid={testId}\n className={cn('relative', className)}\n style={style}\n {...rest}\n >\n {children}\n\n {loading && (\n <div\n className={cn(\n 'inset-0 flex items-center justify-center',\n position === 'fixed' ? 'fixed' : 'absolute'\n )}\n style={{\n zIndex,\n }}\n role=\"status\"\n aria-label={ariaLabel}\n aria-busy=\"true\"\n >\n {/* Backdrop */}\n <div\n className=\"absolute inset-0\"\n style={backdropStyles}\n aria-hidden=\"true\"\n />\n\n {/* Loader */}\n <div className=\"relative z-10\">{loader}</div>\n </div>\n )}\n </div>\n );\n }\n);\n\nLoaderOverlay.displayName = 'LoaderOverlay';\n"],"names":["forwardRef","jsxs","cn","jsx"],"mappings":";;;;;AA6BO,MAAM,gBAAgBA,MAAAA;AAAAA,EAC3B,CACE;AAAA,IACE,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,OAAO;AAAA,IACP;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,GAAG;AAAA,EAAA,GAEL,QACG;AACH,UAAM,iBAAiB;AAAA,MACrB,iBAAiB;AAAA,MACjB,SAAS;AAAA,MACT,gBAAgB,OAAO,cAAc;AAAA,MACrC,sBAAsB,OAAO,cAAc;AAAA,IAAA;AAG7C,WACEC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAa;AAAA,QACb,WAAWC,WAAAA,GAAG,YAAY,SAAS;AAAA,QACnC;AAAA,QACC,GAAG;AAAA,QAEH,UAAA;AAAA,UAAA;AAAA,UAEA,WACCD,2BAAAA;AAAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAWC,WAAAA;AAAAA,gBACT;AAAA,gBACA,aAAa,UAAU,UAAU;AAAA,cAAA;AAAA,cAEnC,OAAO;AAAA,gBACL;AAAA,cAAA;AAAA,cAEF,MAAK;AAAA,cACL,cAAY;AAAA,cACZ,aAAU;AAAA,cAGV,UAAA;AAAA,gBAAAC,2BAAAA;AAAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,WAAU;AAAA,oBACV,OAAO;AAAA,oBACP,eAAY;AAAA,kBAAA;AAAA,gBAAA;AAAA,gBAIdA,2BAAAA,IAAC,OAAA,EAAI,WAAU,iBAAiB,UAAA,OAAA,CAAO;AAAA,cAAA;AAAA,YAAA;AAAA,UAAA;AAAA,QACzC;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEA,cAAc,cAAc;;"}
1
+ {"version":3,"file":"index29.cjs","sources":["../src/components/overlay/LoaderOverlay.tsx"],"sourcesContent":["import { forwardRef } from 'react';\nimport { LoaderOverlayProps } from '../../types';\nimport { cn, useLoaderVisibility } from '../../utils';\n\n/**\n * LoaderOverlay - Overlay wrapper for displaying loaders over content\n *\n * A flexible overlay component that displays a loader over content during loading states.\n * Supports both full-screen and container-relative positioning.\n *\n * @example\n * ```tsx\n * // Full screen overlay\n * <LoaderOverlay loading={isLoading} loader={<SpinnerCircle />}>\n * <YourContent />\n * </LoaderOverlay>\n *\n * // Container overlay with custom backdrop\n * <LoaderOverlay\n * loading={isLoading}\n * loader={<SpinnerRing />}\n * position=\"absolute\"\n * backdropOpacity={0.7}\n * blur\n * >\n * <YourContent />\n * </LoaderOverlay>\n * ```\n */\nexport const LoaderOverlay = forwardRef<HTMLDivElement, LoaderOverlayProps>(\n (\n {\n loading = false,\n loader,\n children,\n position = 'fixed',\n backdropOpacity = 0.5,\n backdropColor = '#000000',\n blur = false,\n delay = 0,\n minDuration = 0,\n transition,\n className,\n style,\n testId = 'loader-overlay',\n ariaLabel = 'Loading content...',\n zIndex = 9999,\n ...rest\n },\n ref\n ) => {\n const { shouldRender, opacity, transitionStyle } = useLoaderVisibility(\n loading,\n delay,\n minDuration,\n transition\n );\n\n const backdropStyles = {\n backgroundColor: backdropColor,\n opacity: backdropOpacity,\n backdropFilter: blur ? 'blur(4px)' : undefined,\n WebkitBackdropFilter: blur ? 'blur(4px)' : undefined,\n };\n\n return (\n <div\n ref={ref}\n data-testid={testId}\n className={cn('relative', className)}\n style={style}\n {...rest}\n >\n {children}\n\n {shouldRender && (\n <div\n className={cn(\n 'inset-0 flex items-center justify-center',\n position === 'fixed' ? 'fixed' : 'absolute'\n )}\n style={{\n zIndex,\n opacity,\n transition: transitionStyle,\n }}\n role=\"status\"\n aria-label={ariaLabel}\n aria-busy=\"true\"\n >\n {/* Backdrop */}\n <div\n className=\"absolute inset-0\"\n style={backdropStyles}\n aria-hidden=\"true\"\n />\n\n {/* Loader */}\n <div className=\"relative z-10\">{loader}</div>\n </div>\n )}\n </div>\n );\n }\n);\n\nLoaderOverlay.displayName = 'LoaderOverlay';\n"],"names":["forwardRef","useLoaderVisibility","jsxs","cn","jsx"],"mappings":";;;;;;AA6BO,MAAM,gBAAgBA,MAAAA;AAAAA,EAC3B,CACE;AAAA,IACE,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,cAAc;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,GAAG;AAAA,EAAA,GAEL,QACG;AACH,UAAM,EAAE,cAAc,SAAS,gBAAA,IAAoBC,MAAAA;AAAAA,MACjD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAGF,UAAM,iBAAiB;AAAA,MACrB,iBAAiB;AAAA,MACjB,SAAS;AAAA,MACT,gBAAgB,OAAO,cAAc;AAAA,MACrC,sBAAsB,OAAO,cAAc;AAAA,IAAA;AAG7C,WACEC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAa;AAAA,QACb,WAAWC,WAAAA,GAAG,YAAY,SAAS;AAAA,QACnC;AAAA,QACC,GAAG;AAAA,QAEH,UAAA;AAAA,UAAA;AAAA,UAEA,gBACCD,2BAAAA;AAAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAWC,WAAAA;AAAAA,gBACT;AAAA,gBACA,aAAa,UAAU,UAAU;AAAA,cAAA;AAAA,cAEnC,OAAO;AAAA,gBACL;AAAA,gBACA;AAAA,gBACA,YAAY;AAAA,cAAA;AAAA,cAEd,MAAK;AAAA,cACL,cAAY;AAAA,cACZ,aAAU;AAAA,cAGV,UAAA;AAAA,gBAAAC,2BAAAA;AAAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,WAAU;AAAA,oBACV,OAAO;AAAA,oBACP,eAAY;AAAA,kBAAA;AAAA,gBAAA;AAAA,gBAIdA,2BAAAA,IAAC,OAAA,EAAI,WAAU,iBAAiB,UAAA,OAAA,CAAO;AAAA,cAAA;AAAA,YAAA;AAAA,UAAA;AAAA,QACzC;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEA,cAAc,cAAc;;"}
package/dist/index29.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { jsxs, jsx } from "react/jsx-runtime";
2
2
  import { forwardRef } from "react";
3
+ import { useLoaderVisibility } from "./index31.js";
3
4
  import { cn } from "./index3.js";
4
5
  const LoaderOverlay = forwardRef(
5
6
  ({
@@ -10,6 +11,9 @@ const LoaderOverlay = forwardRef(
10
11
  backdropOpacity = 0.5,
11
12
  backdropColor = "#000000",
12
13
  blur = false,
14
+ delay = 0,
15
+ minDuration = 0,
16
+ transition,
13
17
  className,
14
18
  style,
15
19
  testId = "loader-overlay",
@@ -17,6 +21,12 @@ const LoaderOverlay = forwardRef(
17
21
  zIndex = 9999,
18
22
  ...rest
19
23
  }, ref) => {
24
+ const { shouldRender, opacity, transitionStyle } = useLoaderVisibility(
25
+ loading,
26
+ delay,
27
+ minDuration,
28
+ transition
29
+ );
20
30
  const backdropStyles = {
21
31
  backgroundColor: backdropColor,
22
32
  opacity: backdropOpacity,
@@ -33,7 +43,7 @@ const LoaderOverlay = forwardRef(
33
43
  ...rest,
34
44
  children: [
35
45
  children,
36
- loading && /* @__PURE__ */ jsxs(
46
+ shouldRender && /* @__PURE__ */ jsxs(
37
47
  "div",
38
48
  {
39
49
  className: cn(
@@ -41,7 +51,9 @@ const LoaderOverlay = forwardRef(
41
51
  position === "fixed" ? "fixed" : "absolute"
42
52
  ),
43
53
  style: {
44
- zIndex
54
+ zIndex,
55
+ opacity,
56
+ transition: transitionStyle
45
57
  },
46
58
  role: "status",
47
59
  "aria-label": ariaLabel,
@@ -1 +1 @@
1
- {"version":3,"file":"index29.js","sources":["../src/components/overlay/LoaderOverlay.tsx"],"sourcesContent":["import { forwardRef } from 'react';\nimport { LoaderOverlayProps } from '../../types';\nimport { cn } from '../../utils';\n\n/**\n * LoaderOverlay - Overlay wrapper for displaying loaders over content\n *\n * A flexible overlay component that displays a loader over content during loading states.\n * Supports both full-screen and container-relative positioning.\n *\n * @example\n * ```tsx\n * // Full screen overlay\n * <LoaderOverlay loading={isLoading} loader={<SpinnerCircle />}>\n * <YourContent />\n * </LoaderOverlay>\n *\n * // Container overlay with custom backdrop\n * <LoaderOverlay\n * loading={isLoading}\n * loader={<SpinnerRing />}\n * position=\"absolute\"\n * backdropOpacity={0.7}\n * blur\n * >\n * <YourContent />\n * </LoaderOverlay>\n * ```\n */\nexport const LoaderOverlay = forwardRef<HTMLDivElement, LoaderOverlayProps>(\n (\n {\n loading = false,\n loader,\n children,\n position = 'fixed',\n backdropOpacity = 0.5,\n backdropColor = '#000000',\n blur = false,\n className,\n style,\n testId = 'loader-overlay',\n ariaLabel = 'Loading content...',\n zIndex = 9999,\n ...rest\n },\n ref\n ) => {\n const backdropStyles = {\n backgroundColor: backdropColor,\n opacity: backdropOpacity,\n backdropFilter: blur ? 'blur(4px)' : undefined,\n WebkitBackdropFilter: blur ? 'blur(4px)' : undefined,\n };\n\n return (\n <div\n ref={ref}\n data-testid={testId}\n className={cn('relative', className)}\n style={style}\n {...rest}\n >\n {children}\n\n {loading && (\n <div\n className={cn(\n 'inset-0 flex items-center justify-center',\n position === 'fixed' ? 'fixed' : 'absolute'\n )}\n style={{\n zIndex,\n }}\n role=\"status\"\n aria-label={ariaLabel}\n aria-busy=\"true\"\n >\n {/* Backdrop */}\n <div\n className=\"absolute inset-0\"\n style={backdropStyles}\n aria-hidden=\"true\"\n />\n\n {/* Loader */}\n <div className=\"relative z-10\">{loader}</div>\n </div>\n )}\n </div>\n );\n }\n);\n\nLoaderOverlay.displayName = 'LoaderOverlay';\n"],"names":[],"mappings":";;;AA6BO,MAAM,gBAAgB;AAAA,EAC3B,CACE;AAAA,IACE,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,OAAO;AAAA,IACP;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,GAAG;AAAA,EAAA,GAEL,QACG;AACH,UAAM,iBAAiB;AAAA,MACrB,iBAAiB;AAAA,MACjB,SAAS;AAAA,MACT,gBAAgB,OAAO,cAAc;AAAA,MACrC,sBAAsB,OAAO,cAAc;AAAA,IAAA;AAG7C,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAa;AAAA,QACb,WAAW,GAAG,YAAY,SAAS;AAAA,QACnC;AAAA,QACC,GAAG;AAAA,QAEH,UAAA;AAAA,UAAA;AAAA,UAEA,WACC;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAW;AAAA,gBACT;AAAA,gBACA,aAAa,UAAU,UAAU;AAAA,cAAA;AAAA,cAEnC,OAAO;AAAA,gBACL;AAAA,cAAA;AAAA,cAEF,MAAK;AAAA,cACL,cAAY;AAAA,cACZ,aAAU;AAAA,cAGV,UAAA;AAAA,gBAAA;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,WAAU;AAAA,oBACV,OAAO;AAAA,oBACP,eAAY;AAAA,kBAAA;AAAA,gBAAA;AAAA,gBAId,oBAAC,OAAA,EAAI,WAAU,iBAAiB,UAAA,OAAA,CAAO;AAAA,cAAA;AAAA,YAAA;AAAA,UAAA;AAAA,QACzC;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEA,cAAc,cAAc;"}
1
+ {"version":3,"file":"index29.js","sources":["../src/components/overlay/LoaderOverlay.tsx"],"sourcesContent":["import { forwardRef } from 'react';\nimport { LoaderOverlayProps } from '../../types';\nimport { cn, useLoaderVisibility } from '../../utils';\n\n/**\n * LoaderOverlay - Overlay wrapper for displaying loaders over content\n *\n * A flexible overlay component that displays a loader over content during loading states.\n * Supports both full-screen and container-relative positioning.\n *\n * @example\n * ```tsx\n * // Full screen overlay\n * <LoaderOverlay loading={isLoading} loader={<SpinnerCircle />}>\n * <YourContent />\n * </LoaderOverlay>\n *\n * // Container overlay with custom backdrop\n * <LoaderOverlay\n * loading={isLoading}\n * loader={<SpinnerRing />}\n * position=\"absolute\"\n * backdropOpacity={0.7}\n * blur\n * >\n * <YourContent />\n * </LoaderOverlay>\n * ```\n */\nexport const LoaderOverlay = forwardRef<HTMLDivElement, LoaderOverlayProps>(\n (\n {\n loading = false,\n loader,\n children,\n position = 'fixed',\n backdropOpacity = 0.5,\n backdropColor = '#000000',\n blur = false,\n delay = 0,\n minDuration = 0,\n transition,\n className,\n style,\n testId = 'loader-overlay',\n ariaLabel = 'Loading content...',\n zIndex = 9999,\n ...rest\n },\n ref\n ) => {\n const { shouldRender, opacity, transitionStyle } = useLoaderVisibility(\n loading,\n delay,\n minDuration,\n transition\n );\n\n const backdropStyles = {\n backgroundColor: backdropColor,\n opacity: backdropOpacity,\n backdropFilter: blur ? 'blur(4px)' : undefined,\n WebkitBackdropFilter: blur ? 'blur(4px)' : undefined,\n };\n\n return (\n <div\n ref={ref}\n data-testid={testId}\n className={cn('relative', className)}\n style={style}\n {...rest}\n >\n {children}\n\n {shouldRender && (\n <div\n className={cn(\n 'inset-0 flex items-center justify-center',\n position === 'fixed' ? 'fixed' : 'absolute'\n )}\n style={{\n zIndex,\n opacity,\n transition: transitionStyle,\n }}\n role=\"status\"\n aria-label={ariaLabel}\n aria-busy=\"true\"\n >\n {/* Backdrop */}\n <div\n className=\"absolute inset-0\"\n style={backdropStyles}\n aria-hidden=\"true\"\n />\n\n {/* Loader */}\n <div className=\"relative z-10\">{loader}</div>\n </div>\n )}\n </div>\n );\n }\n);\n\nLoaderOverlay.displayName = 'LoaderOverlay';\n"],"names":[],"mappings":";;;;AA6BO,MAAM,gBAAgB;AAAA,EAC3B,CACE;AAAA,IACE,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,cAAc;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,GAAG;AAAA,EAAA,GAEL,QACG;AACH,UAAM,EAAE,cAAc,SAAS,gBAAA,IAAoB;AAAA,MACjD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAGF,UAAM,iBAAiB;AAAA,MACrB,iBAAiB;AAAA,MACjB,SAAS;AAAA,MACT,gBAAgB,OAAO,cAAc;AAAA,MACrC,sBAAsB,OAAO,cAAc;AAAA,IAAA;AAG7C,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAa;AAAA,QACb,WAAW,GAAG,YAAY,SAAS;AAAA,QACnC;AAAA,QACC,GAAG;AAAA,QAEH,UAAA;AAAA,UAAA;AAAA,UAEA,gBACC;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAW;AAAA,gBACT;AAAA,gBACA,aAAa,UAAU,UAAU;AAAA,cAAA;AAAA,cAEnC,OAAO;AAAA,gBACL;AAAA,gBACA;AAAA,gBACA,YAAY;AAAA,cAAA;AAAA,cAEd,MAAK;AAAA,cACL,cAAY;AAAA,cACZ,aAAU;AAAA,cAGV,UAAA;AAAA,gBAAA;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,WAAU;AAAA,oBACV,OAAO;AAAA,oBACP,eAAY;AAAA,kBAAA;AAAA,gBAAA;AAAA,gBAId,oBAAC,OAAA,EAAI,WAAU,iBAAiB,UAAA,OAAA,CAAO;AAAA,cAAA;AAAA,YAAA;AAAA,UAAA;AAAA,QACzC;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEA,cAAc,cAAc;"}
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const react = require("react");
4
+ function useReducedMotion() {
5
+ const [prefersReducedMotion, setPrefersReducedMotion] = react.useState(false);
6
+ react.useEffect(() => {
7
+ if (typeof window === "undefined" || !window.matchMedia) {
8
+ return;
9
+ }
10
+ const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
11
+ setPrefersReducedMotion(mediaQuery.matches);
12
+ const handleChange = (event) => {
13
+ setPrefersReducedMotion(event.matches);
14
+ };
15
+ if (mediaQuery.addEventListener) {
16
+ mediaQuery.addEventListener("change", handleChange);
17
+ return () => mediaQuery.removeEventListener("change", handleChange);
18
+ } else {
19
+ mediaQuery.addListener(handleChange);
20
+ return () => mediaQuery.removeListener(handleChange);
21
+ }
22
+ }, []);
23
+ return prefersReducedMotion;
24
+ }
25
+ function getEffectiveDuration(speed, respectMotionPreference, prefersReducedMotion) {
26
+ if (respectMotionPreference && prefersReducedMotion) {
27
+ return "0.01ms";
28
+ }
29
+ if (typeof speed === "number") {
30
+ const validSpeed = !isNaN(speed) && speed > 0 ? Math.max(50, Math.min(1e4, speed)) : 1e3;
31
+ return `${validSpeed}ms`;
32
+ }
33
+ const speedMap = {
34
+ slow: "2s",
35
+ normal: "1s",
36
+ fast: "0.5s"
37
+ };
38
+ return speedMap[speed] || speedMap.normal;
39
+ }
40
+ function useLoaderVisibility(visible = true, delay = 0, minDuration = 0, transition) {
41
+ const transitionDuration = transition === true ? 150 : typeof transition === "number" ? transition : 0;
42
+ const hasTransition = transitionDuration > 0;
43
+ const [shouldRender, setShouldRender] = react.useState(visible && delay === 0);
44
+ const [isTransitioning, setIsTransitioning] = react.useState(visible && delay === 0 && hasTransition);
45
+ const showTimeRef = react.useRef(visible && delay === 0 ? Date.now() : null);
46
+ const delayTimerRef = react.useRef(null);
47
+ const minDurationTimerRef = react.useRef(null);
48
+ const transitionTimerRef = react.useRef(null);
49
+ react.useEffect(() => {
50
+ if (delayTimerRef.current) {
51
+ clearTimeout(delayTimerRef.current);
52
+ delayTimerRef.current = null;
53
+ }
54
+ if (minDurationTimerRef.current) {
55
+ clearTimeout(minDurationTimerRef.current);
56
+ minDurationTimerRef.current = null;
57
+ }
58
+ if (transitionTimerRef.current) {
59
+ clearTimeout(transitionTimerRef.current);
60
+ transitionTimerRef.current = null;
61
+ }
62
+ if (visible) {
63
+ if (delay > 0) {
64
+ delayTimerRef.current = setTimeout(() => {
65
+ setShouldRender(true);
66
+ showTimeRef.current = Date.now();
67
+ if (hasTransition) {
68
+ setIsTransitioning(true);
69
+ }
70
+ }, delay);
71
+ } else {
72
+ setShouldRender(true);
73
+ showTimeRef.current = Date.now();
74
+ if (hasTransition) {
75
+ setIsTransitioning(true);
76
+ }
77
+ }
78
+ } else {
79
+ const hideLoader = () => {
80
+ if (hasTransition) {
81
+ setIsTransitioning(false);
82
+ transitionTimerRef.current = setTimeout(() => {
83
+ setShouldRender(false);
84
+ showTimeRef.current = null;
85
+ }, transitionDuration);
86
+ } else {
87
+ setShouldRender(false);
88
+ showTimeRef.current = null;
89
+ }
90
+ };
91
+ if (showTimeRef.current !== null && minDuration > 0) {
92
+ const elapsedTime = Date.now() - showTimeRef.current;
93
+ const remainingTime = minDuration - elapsedTime;
94
+ if (remainingTime > 0) {
95
+ minDurationTimerRef.current = setTimeout(hideLoader, remainingTime);
96
+ } else {
97
+ hideLoader();
98
+ }
99
+ } else {
100
+ hideLoader();
101
+ }
102
+ }
103
+ return () => {
104
+ if (delayTimerRef.current) {
105
+ clearTimeout(delayTimerRef.current);
106
+ }
107
+ if (minDurationTimerRef.current) {
108
+ clearTimeout(minDurationTimerRef.current);
109
+ }
110
+ if (transitionTimerRef.current) {
111
+ clearTimeout(transitionTimerRef.current);
112
+ }
113
+ };
114
+ }, [visible, delay, minDuration, hasTransition, transitionDuration]);
115
+ const opacity = hasTransition ? isTransitioning ? 1 : 0 : 1;
116
+ const transitionStyle = hasTransition ? `opacity ${transitionDuration}ms ease-in-out` : "none";
117
+ return {
118
+ shouldRender,
119
+ opacity,
120
+ transitionStyle
121
+ };
122
+ }
123
+ exports.getEffectiveDuration = getEffectiveDuration;
124
+ exports.useLoaderVisibility = useLoaderVisibility;
125
+ exports.useReducedMotion = useReducedMotion;
126
+ //# sourceMappingURL=index31.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index31.cjs","sources":["../src/utils/hooks.ts"],"sourcesContent":["import { useEffect, useState, useRef } from 'react';\n\n/**\n * Hook to detect user's reduced motion preference\n * Returns true if user prefers reduced motion\n */\nexport function useReducedMotion(): boolean {\n const [prefersReducedMotion, setPrefersReducedMotion] = useState(false);\n\n useEffect(() => {\n // Check if matchMedia is available (SSR safety)\n if (typeof window === 'undefined' || !window.matchMedia) {\n return;\n }\n\n const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)');\n\n // Set initial value\n setPrefersReducedMotion(mediaQuery.matches);\n\n // Listen for changes\n const handleChange = (event: MediaQueryListEvent) => {\n setPrefersReducedMotion(event.matches);\n };\n\n // Use addEventListener if available (modern browsers)\n if (mediaQuery.addEventListener) {\n mediaQuery.addEventListener('change', handleChange);\n return () => mediaQuery.removeEventListener('change', handleChange);\n } else {\n // Fallback for older browsers\n mediaQuery.addListener(handleChange);\n return () => mediaQuery.removeListener(handleChange);\n }\n }, []);\n\n return prefersReducedMotion;\n}\n\n/**\n * Get effective animation duration based on speed and reduced motion preference\n */\nexport function getEffectiveDuration(\n speed: 'slow' | 'normal' | 'fast' | number,\n respectMotionPreference: boolean,\n prefersReducedMotion: boolean\n): string {\n // If user prefers reduced motion and we should respect it, use a very short duration\n if (respectMotionPreference && prefersReducedMotion) {\n return '0.01ms';\n }\n\n if (typeof speed === 'number') {\n const validSpeed = !isNaN(speed) && speed > 0 ? Math.max(50, Math.min(10000, speed)) : 1000;\n return `${validSpeed}ms`;\n }\n\n const speedMap = {\n slow: '2s',\n normal: '1s',\n fast: '0.5s',\n };\n\n return speedMap[speed] || speedMap.normal;\n}\n\n/**\n * Hook to manage loader visibility with delay, minimum duration, and transitions\n * Prevents flashing on fast loads and jarring quick disappears\n */\nexport function useLoaderVisibility(\n visible: boolean = true,\n delay: number = 0,\n minDuration: number = 0,\n transition?: boolean | number\n): {\n shouldRender: boolean;\n opacity: number;\n transitionStyle: string;\n} {\n // Calculate transition duration\n const transitionDuration =\n transition === true ? 150 : typeof transition === 'number' ? transition : 0;\n const hasTransition = transitionDuration > 0;\n\n // Initialize shouldRender based on visible state and delay\n // If visible and no delay, render immediately; otherwise start hidden\n const [shouldRender, setShouldRender] = useState(visible && delay === 0);\n const [isTransitioning, setIsTransitioning] = useState(visible && delay === 0 && hasTransition);\n const showTimeRef = useRef<number | null>(visible && delay === 0 ? Date.now() : null);\n const delayTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const minDurationTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const transitionTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n // Clear any existing timers\n if (delayTimerRef.current) {\n clearTimeout(delayTimerRef.current);\n delayTimerRef.current = null;\n }\n if (minDurationTimerRef.current) {\n clearTimeout(minDurationTimerRef.current);\n minDurationTimerRef.current = null;\n }\n if (transitionTimerRef.current) {\n clearTimeout(transitionTimerRef.current);\n transitionTimerRef.current = null;\n }\n\n if (visible) {\n // Show loader after delay\n if (delay > 0) {\n delayTimerRef.current = setTimeout(() => {\n setShouldRender(true);\n showTimeRef.current = Date.now();\n // Trigger transition\n if (hasTransition) {\n setIsTransitioning(true);\n }\n }, delay);\n } else {\n setShouldRender(true);\n showTimeRef.current = Date.now();\n // Trigger transition\n if (hasTransition) {\n setIsTransitioning(true);\n }\n }\n } else {\n // Hide loader, but respect minimum duration if it was shown\n const hideLoader = () => {\n if (hasTransition) {\n setIsTransitioning(false);\n // Wait for transition to complete before unmounting\n transitionTimerRef.current = setTimeout(() => {\n setShouldRender(false);\n showTimeRef.current = null;\n }, transitionDuration);\n } else {\n setShouldRender(false);\n showTimeRef.current = null;\n }\n };\n\n if (showTimeRef.current !== null && minDuration > 0) {\n const elapsedTime = Date.now() - showTimeRef.current;\n const remainingTime = minDuration - elapsedTime;\n\n if (remainingTime > 0) {\n minDurationTimerRef.current = setTimeout(hideLoader, remainingTime);\n } else {\n hideLoader();\n }\n } else {\n hideLoader();\n }\n }\n\n // Cleanup timers on unmount or when dependencies change\n return () => {\n if (delayTimerRef.current) {\n clearTimeout(delayTimerRef.current);\n }\n if (minDurationTimerRef.current) {\n clearTimeout(minDurationTimerRef.current);\n }\n if (transitionTimerRef.current) {\n clearTimeout(transitionTimerRef.current);\n }\n };\n }, [visible, delay, minDuration, hasTransition, transitionDuration]);\n\n // Calculate opacity based on transition state\n const opacity = hasTransition ? (isTransitioning ? 1 : 0) : 1;\n\n // Build transition style\n const transitionStyle = hasTransition\n ? `opacity ${transitionDuration}ms ease-in-out`\n : 'none';\n\n return {\n shouldRender,\n opacity,\n transitionStyle,\n };\n}\n"],"names":["useState","useEffect","useRef"],"mappings":"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"}
@@ -0,0 +1,126 @@
1
+ import { useState, useRef, useEffect } from "react";
2
+ function useReducedMotion() {
3
+ const [prefersReducedMotion, setPrefersReducedMotion] = useState(false);
4
+ useEffect(() => {
5
+ if (typeof window === "undefined" || !window.matchMedia) {
6
+ return;
7
+ }
8
+ const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
9
+ setPrefersReducedMotion(mediaQuery.matches);
10
+ const handleChange = (event) => {
11
+ setPrefersReducedMotion(event.matches);
12
+ };
13
+ if (mediaQuery.addEventListener) {
14
+ mediaQuery.addEventListener("change", handleChange);
15
+ return () => mediaQuery.removeEventListener("change", handleChange);
16
+ } else {
17
+ mediaQuery.addListener(handleChange);
18
+ return () => mediaQuery.removeListener(handleChange);
19
+ }
20
+ }, []);
21
+ return prefersReducedMotion;
22
+ }
23
+ function getEffectiveDuration(speed, respectMotionPreference, prefersReducedMotion) {
24
+ if (respectMotionPreference && prefersReducedMotion) {
25
+ return "0.01ms";
26
+ }
27
+ if (typeof speed === "number") {
28
+ const validSpeed = !isNaN(speed) && speed > 0 ? Math.max(50, Math.min(1e4, speed)) : 1e3;
29
+ return `${validSpeed}ms`;
30
+ }
31
+ const speedMap = {
32
+ slow: "2s",
33
+ normal: "1s",
34
+ fast: "0.5s"
35
+ };
36
+ return speedMap[speed] || speedMap.normal;
37
+ }
38
+ function useLoaderVisibility(visible = true, delay = 0, minDuration = 0, transition) {
39
+ const transitionDuration = transition === true ? 150 : typeof transition === "number" ? transition : 0;
40
+ const hasTransition = transitionDuration > 0;
41
+ const [shouldRender, setShouldRender] = useState(visible && delay === 0);
42
+ const [isTransitioning, setIsTransitioning] = useState(visible && delay === 0 && hasTransition);
43
+ const showTimeRef = useRef(visible && delay === 0 ? Date.now() : null);
44
+ const delayTimerRef = useRef(null);
45
+ const minDurationTimerRef = useRef(null);
46
+ const transitionTimerRef = useRef(null);
47
+ useEffect(() => {
48
+ if (delayTimerRef.current) {
49
+ clearTimeout(delayTimerRef.current);
50
+ delayTimerRef.current = null;
51
+ }
52
+ if (minDurationTimerRef.current) {
53
+ clearTimeout(minDurationTimerRef.current);
54
+ minDurationTimerRef.current = null;
55
+ }
56
+ if (transitionTimerRef.current) {
57
+ clearTimeout(transitionTimerRef.current);
58
+ transitionTimerRef.current = null;
59
+ }
60
+ if (visible) {
61
+ if (delay > 0) {
62
+ delayTimerRef.current = setTimeout(() => {
63
+ setShouldRender(true);
64
+ showTimeRef.current = Date.now();
65
+ if (hasTransition) {
66
+ setIsTransitioning(true);
67
+ }
68
+ }, delay);
69
+ } else {
70
+ setShouldRender(true);
71
+ showTimeRef.current = Date.now();
72
+ if (hasTransition) {
73
+ setIsTransitioning(true);
74
+ }
75
+ }
76
+ } else {
77
+ const hideLoader = () => {
78
+ if (hasTransition) {
79
+ setIsTransitioning(false);
80
+ transitionTimerRef.current = setTimeout(() => {
81
+ setShouldRender(false);
82
+ showTimeRef.current = null;
83
+ }, transitionDuration);
84
+ } else {
85
+ setShouldRender(false);
86
+ showTimeRef.current = null;
87
+ }
88
+ };
89
+ if (showTimeRef.current !== null && minDuration > 0) {
90
+ const elapsedTime = Date.now() - showTimeRef.current;
91
+ const remainingTime = minDuration - elapsedTime;
92
+ if (remainingTime > 0) {
93
+ minDurationTimerRef.current = setTimeout(hideLoader, remainingTime);
94
+ } else {
95
+ hideLoader();
96
+ }
97
+ } else {
98
+ hideLoader();
99
+ }
100
+ }
101
+ return () => {
102
+ if (delayTimerRef.current) {
103
+ clearTimeout(delayTimerRef.current);
104
+ }
105
+ if (minDurationTimerRef.current) {
106
+ clearTimeout(minDurationTimerRef.current);
107
+ }
108
+ if (transitionTimerRef.current) {
109
+ clearTimeout(transitionTimerRef.current);
110
+ }
111
+ };
112
+ }, [visible, delay, minDuration, hasTransition, transitionDuration]);
113
+ const opacity = hasTransition ? isTransitioning ? 1 : 0 : 1;
114
+ const transitionStyle = hasTransition ? `opacity ${transitionDuration}ms ease-in-out` : "none";
115
+ return {
116
+ shouldRender,
117
+ opacity,
118
+ transitionStyle
119
+ };
120
+ }
121
+ export {
122
+ getEffectiveDuration,
123
+ useLoaderVisibility,
124
+ useReducedMotion
125
+ };
126
+ //# sourceMappingURL=index31.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index31.js","sources":["../src/utils/hooks.ts"],"sourcesContent":["import { useEffect, useState, useRef } from 'react';\n\n/**\n * Hook to detect user's reduced motion preference\n * Returns true if user prefers reduced motion\n */\nexport function useReducedMotion(): boolean {\n const [prefersReducedMotion, setPrefersReducedMotion] = useState(false);\n\n useEffect(() => {\n // Check if matchMedia is available (SSR safety)\n if (typeof window === 'undefined' || !window.matchMedia) {\n return;\n }\n\n const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)');\n\n // Set initial value\n setPrefersReducedMotion(mediaQuery.matches);\n\n // Listen for changes\n const handleChange = (event: MediaQueryListEvent) => {\n setPrefersReducedMotion(event.matches);\n };\n\n // Use addEventListener if available (modern browsers)\n if (mediaQuery.addEventListener) {\n mediaQuery.addEventListener('change', handleChange);\n return () => mediaQuery.removeEventListener('change', handleChange);\n } else {\n // Fallback for older browsers\n mediaQuery.addListener(handleChange);\n return () => mediaQuery.removeListener(handleChange);\n }\n }, []);\n\n return prefersReducedMotion;\n}\n\n/**\n * Get effective animation duration based on speed and reduced motion preference\n */\nexport function getEffectiveDuration(\n speed: 'slow' | 'normal' | 'fast' | number,\n respectMotionPreference: boolean,\n prefersReducedMotion: boolean\n): string {\n // If user prefers reduced motion and we should respect it, use a very short duration\n if (respectMotionPreference && prefersReducedMotion) {\n return '0.01ms';\n }\n\n if (typeof speed === 'number') {\n const validSpeed = !isNaN(speed) && speed > 0 ? Math.max(50, Math.min(10000, speed)) : 1000;\n return `${validSpeed}ms`;\n }\n\n const speedMap = {\n slow: '2s',\n normal: '1s',\n fast: '0.5s',\n };\n\n return speedMap[speed] || speedMap.normal;\n}\n\n/**\n * Hook to manage loader visibility with delay, minimum duration, and transitions\n * Prevents flashing on fast loads and jarring quick disappears\n */\nexport function useLoaderVisibility(\n visible: boolean = true,\n delay: number = 0,\n minDuration: number = 0,\n transition?: boolean | number\n): {\n shouldRender: boolean;\n opacity: number;\n transitionStyle: string;\n} {\n // Calculate transition duration\n const transitionDuration =\n transition === true ? 150 : typeof transition === 'number' ? transition : 0;\n const hasTransition = transitionDuration > 0;\n\n // Initialize shouldRender based on visible state and delay\n // If visible and no delay, render immediately; otherwise start hidden\n const [shouldRender, setShouldRender] = useState(visible && delay === 0);\n const [isTransitioning, setIsTransitioning] = useState(visible && delay === 0 && hasTransition);\n const showTimeRef = useRef<number | null>(visible && delay === 0 ? Date.now() : null);\n const delayTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const minDurationTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const transitionTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n // Clear any existing timers\n if (delayTimerRef.current) {\n clearTimeout(delayTimerRef.current);\n delayTimerRef.current = null;\n }\n if (minDurationTimerRef.current) {\n clearTimeout(minDurationTimerRef.current);\n minDurationTimerRef.current = null;\n }\n if (transitionTimerRef.current) {\n clearTimeout(transitionTimerRef.current);\n transitionTimerRef.current = null;\n }\n\n if (visible) {\n // Show loader after delay\n if (delay > 0) {\n delayTimerRef.current = setTimeout(() => {\n setShouldRender(true);\n showTimeRef.current = Date.now();\n // Trigger transition\n if (hasTransition) {\n setIsTransitioning(true);\n }\n }, delay);\n } else {\n setShouldRender(true);\n showTimeRef.current = Date.now();\n // Trigger transition\n if (hasTransition) {\n setIsTransitioning(true);\n }\n }\n } else {\n // Hide loader, but respect minimum duration if it was shown\n const hideLoader = () => {\n if (hasTransition) {\n setIsTransitioning(false);\n // Wait for transition to complete before unmounting\n transitionTimerRef.current = setTimeout(() => {\n setShouldRender(false);\n showTimeRef.current = null;\n }, transitionDuration);\n } else {\n setShouldRender(false);\n showTimeRef.current = null;\n }\n };\n\n if (showTimeRef.current !== null && minDuration > 0) {\n const elapsedTime = Date.now() - showTimeRef.current;\n const remainingTime = minDuration - elapsedTime;\n\n if (remainingTime > 0) {\n minDurationTimerRef.current = setTimeout(hideLoader, remainingTime);\n } else {\n hideLoader();\n }\n } else {\n hideLoader();\n }\n }\n\n // Cleanup timers on unmount or when dependencies change\n return () => {\n if (delayTimerRef.current) {\n clearTimeout(delayTimerRef.current);\n }\n if (minDurationTimerRef.current) {\n clearTimeout(minDurationTimerRef.current);\n }\n if (transitionTimerRef.current) {\n clearTimeout(transitionTimerRef.current);\n }\n };\n }, [visible, delay, minDuration, hasTransition, transitionDuration]);\n\n // Calculate opacity based on transition state\n const opacity = hasTransition ? (isTransitioning ? 1 : 0) : 1;\n\n // Build transition style\n const transitionStyle = hasTransition\n ? `opacity ${transitionDuration}ms ease-in-out`\n : 'none';\n\n return {\n shouldRender,\n opacity,\n transitionStyle,\n };\n}\n"],"names":[],"mappings":"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"}
package/dist/index4.cjs CHANGED
@@ -27,6 +27,16 @@ function getAnimationDuration(speed = "normal") {
27
27
  return speedMap[speed] || speedMap.normal;
28
28
  }
29
29
  function normalizeSize(size) {
30
+ const sizePresetMap = {
31
+ xs: 16,
32
+ sm: 24,
33
+ md: 40,
34
+ lg: 56,
35
+ xl: 72
36
+ };
37
+ if (typeof size === "string" && size in sizePresetMap) {
38
+ return `${sizePresetMap[size]}px`;
39
+ }
30
40
  if (typeof size === "number") {
31
41
  return `${size}px`;
32
42
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index4.cjs","sources":["../src/utils/colors.ts"],"sourcesContent":["/**\n * Check if a color is a valid hex color\n */\nexport function isHexColor(color: string): boolean {\n return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(color);\n}\n\n/**\n * Check if a color is a valid RGB/RGBA color\n */\nexport function isRgbColor(color: string): boolean {\n return /^rgba?\\([\\d\\s,./]+\\)$/.test(color);\n}\n\n/**\n * Convert hex color to RGB\n */\nexport function hexToRgb(hex: string): { r: number; g: number; b: number } | null {\n const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\n return result\n ? {\n r: parseInt(result[1], 16),\n g: parseInt(result[2], 16),\n b: parseInt(result[3], 16),\n }\n : null;\n}\n\n/**\n * Get animation duration in CSS format\n */\nexport function getAnimationDuration(speed: 'slow' | 'normal' | 'fast' | number = 'normal'): string {\n if (typeof speed === 'number') {\n // Validate number is valid and positive, clamp to reasonable range (50ms - 10000ms)\n const validSpeed = !isNaN(speed) && speed > 0 ? Math.max(50, Math.min(10000, speed)) : 1000;\n return `${validSpeed}ms`;\n }\n\n const speedMap = {\n slow: '2s',\n normal: '1s',\n fast: '0.5s',\n };\n\n return speedMap[speed] || speedMap.normal;\n}\n\n/**\n * Normalize size value to CSS string\n */\nexport function normalizeSize(size?: number | string): string {\n if (typeof size === 'number') {\n return `${size}px`;\n }\n return size || 'auto';\n}\n\n/**\n * Safely parse size to number with fallback\n */\nexport function parseSizeToNumber(size: number | string | undefined, fallback: number): number {\n if (typeof size === 'number') {\n return !isNaN(size) && size > 0 ? size : fallback;\n }\n\n if (typeof size === 'string') {\n const parsed = parseInt(size, 10);\n return !isNaN(parsed) && parsed > 0 ? parsed : fallback;\n }\n\n return fallback;\n}\n\n/**\n * Calculate relative luminance of a color (0-1 scale)\n * Used for determining if text should be light or dark for contrast\n */\nexport function getColorLuminance(color: string): number {\n // Try to parse hex color\n if (isHexColor(color)) {\n const rgb = hexToRgb(color);\n if (rgb) {\n // Convert RGB to relative luminance using WCAG formula\n const { r, g, b } = rgb;\n const [rs, gs, bs] = [r, g, b].map((c) => {\n const val = c / 255;\n return val <= 0.03928 ? val / 12.92 : Math.pow((val + 0.055) / 1.055, 2.4);\n });\n return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;\n }\n }\n\n // Try to parse RGB/RGBA color\n if (isRgbColor(color)) {\n const match = color.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\n if (match) {\n const [, r, g, b] = match.map(Number);\n const [rs, gs, bs] = [r, g, b].map((c) => {\n const val = c / 255;\n return val <= 0.03928 ? val / 12.92 : Math.pow((val + 0.055) / 1.055, 2.4);\n });\n return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;\n }\n }\n\n // Default to 0.5 (medium luminance) if unable to parse\n return 0.5;\n}\n\n/**\n * Get contrast color (black or white) based on background luminance\n */\nexport function getContrastColor(backgroundColor: string): string {\n const luminance = getColorLuminance(backgroundColor);\n // WCAG standard: use white text on dark backgrounds (luminance < 0.5)\n return luminance < 0.5 ? '#ffffff' : '#000000';\n}\n"],"names":[],"mappings":";;AAGO,SAAS,WAAW,OAAwB;AACjD,SAAO,qCAAqC,KAAK,KAAK;AACxD;AAKO,SAAS,WAAW,OAAwB;AACjD,SAAO,wBAAwB,KAAK,KAAK;AAC3C;AAKO,SAAS,SAAS,KAAyD;AAChF,QAAM,SAAS,4CAA4C,KAAK,GAAG;AACnE,SAAO,SACH;AAAA,IACE,GAAG,SAAS,OAAO,CAAC,GAAG,EAAE;AAAA,IACzB,GAAG,SAAS,OAAO,CAAC,GAAG,EAAE;AAAA,IACzB,GAAG,SAAS,OAAO,CAAC,GAAG,EAAE;AAAA,EAAA,IAE3B;AACN;AAKO,SAAS,qBAAqB,QAA6C,UAAkB;AAClG,MAAI,OAAO,UAAU,UAAU;AAE7B,UAAM,aAAa,CAAC,MAAM,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,IAAI,KAAK,IAAI,KAAO,KAAK,CAAC,IAAI;AACvF,WAAO,GAAG,UAAU;AAAA,EACtB;AAEA,QAAM,WAAW;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,MAAM;AAAA,EAAA;AAGR,SAAO,SAAS,KAAK,KAAK,SAAS;AACrC;AAKO,SAAS,cAAc,MAAgC;AAC5D,MAAI,OAAO,SAAS,UAAU;AAC5B,WAAO,GAAG,IAAI;AAAA,EAChB;AACA,SAAO,QAAQ;AACjB;AAKO,SAAS,kBAAkB,MAAmC,UAA0B;AAC7F,MAAI,OAAO,SAAS,UAAU;AAC5B,WAAO,CAAC,MAAM,IAAI,KAAK,OAAO,IAAI,OAAO;AAAA,EAC3C;AAEA,MAAI,OAAO,SAAS,UAAU;AAC5B,UAAM,SAAS,SAAS,MAAM,EAAE;AAChC,WAAO,CAAC,MAAM,MAAM,KAAK,SAAS,IAAI,SAAS;AAAA,EACjD;AAEA,SAAO;AACT;AAMO,SAAS,kBAAkB,OAAuB;AAEvD,MAAI,WAAW,KAAK,GAAG;AACrB,UAAM,MAAM,SAAS,KAAK;AAC1B,QAAI,KAAK;AAEP,YAAM,EAAE,GAAG,GAAG,EAAA,IAAM;AACpB,YAAM,CAAC,IAAI,IAAI,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM;AACxC,cAAM,MAAM,IAAI;AAChB,eAAO,OAAO,UAAU,MAAM,QAAQ,KAAK,KAAK,MAAM,SAAS,OAAO,GAAG;AAAA,MAC3E,CAAC;AACD,aAAO,SAAS,KAAK,SAAS,KAAK,SAAS;AAAA,IAC9C;AAAA,EACF;AAGA,MAAI,WAAW,KAAK,GAAG;AACrB,UAAM,QAAQ,MAAM,MAAM,gCAAgC;AAC1D,QAAI,OAAO;AACT,YAAM,CAAA,EAAG,GAAG,GAAG,CAAC,IAAI,MAAM,IAAI,MAAM;AACpC,YAAM,CAAC,IAAI,IAAI,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM;AACxC,cAAM,MAAM,IAAI;AAChB,eAAO,OAAO,UAAU,MAAM,QAAQ,KAAK,KAAK,MAAM,SAAS,OAAO,GAAG;AAAA,MAC3E,CAAC;AACD,aAAO,SAAS,KAAK,SAAS,KAAK,SAAS;AAAA,IAC9C;AAAA,EACF;AAGA,SAAO;AACT;AAKO,SAAS,iBAAiB,iBAAiC;AAChE,QAAM,YAAY,kBAAkB,eAAe;AAEnD,SAAO,YAAY,MAAM,YAAY;AACvC;;;;;;;;;"}
1
+ {"version":3,"file":"index4.cjs","sources":["../src/utils/colors.ts"],"sourcesContent":["/**\n * Check if a color is a valid hex color\n */\nexport function isHexColor(color: string): boolean {\n return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(color);\n}\n\n/**\n * Check if a color is a valid RGB/RGBA color\n */\nexport function isRgbColor(color: string): boolean {\n return /^rgba?\\([\\d\\s,./]+\\)$/.test(color);\n}\n\n/**\n * Convert hex color to RGB\n */\nexport function hexToRgb(hex: string): { r: number; g: number; b: number } | null {\n const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\n return result\n ? {\n r: parseInt(result[1], 16),\n g: parseInt(result[2], 16),\n b: parseInt(result[3], 16),\n }\n : null;\n}\n\n/**\n * Get animation duration in CSS format\n */\nexport function getAnimationDuration(speed: 'slow' | 'normal' | 'fast' | number = 'normal'): string {\n if (typeof speed === 'number') {\n // Validate number is valid and positive, clamp to reasonable range (50ms - 10000ms)\n const validSpeed = !isNaN(speed) && speed > 0 ? Math.max(50, Math.min(10000, speed)) : 1000;\n return `${validSpeed}ms`;\n }\n\n const speedMap = {\n slow: '2s',\n normal: '1s',\n fast: '0.5s',\n };\n\n return speedMap[speed] || speedMap.normal;\n}\n\n/**\n * Normalize size value to CSS string\n * Supports size presets ('xs', 'sm', 'md', 'lg', 'xl'), numeric values, or CSS strings\n */\nexport function normalizeSize(size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | number | string): string {\n // Handle size presets\n const sizePresetMap = {\n xs: 16,\n sm: 24,\n md: 40,\n lg: 56,\n xl: 72,\n };\n\n if (typeof size === 'string' && size in sizePresetMap) {\n return `${sizePresetMap[size as keyof typeof sizePresetMap]}px`;\n }\n\n if (typeof size === 'number') {\n return `${size}px`;\n }\n return size || 'auto';\n}\n\n/**\n * Safely parse size to number with fallback\n */\nexport function parseSizeToNumber(size: number | string | undefined, fallback: number): number {\n if (typeof size === 'number') {\n return !isNaN(size) && size > 0 ? size : fallback;\n }\n\n if (typeof size === 'string') {\n const parsed = parseInt(size, 10);\n return !isNaN(parsed) && parsed > 0 ? parsed : fallback;\n }\n\n return fallback;\n}\n\n/**\n * Calculate relative luminance of a color (0-1 scale)\n * Used for determining if text should be light or dark for contrast\n */\nexport function getColorLuminance(color: string): number {\n // Try to parse hex color\n if (isHexColor(color)) {\n const rgb = hexToRgb(color);\n if (rgb) {\n // Convert RGB to relative luminance using WCAG formula\n const { r, g, b } = rgb;\n const [rs, gs, bs] = [r, g, b].map((c) => {\n const val = c / 255;\n return val <= 0.03928 ? val / 12.92 : Math.pow((val + 0.055) / 1.055, 2.4);\n });\n return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;\n }\n }\n\n // Try to parse RGB/RGBA color\n if (isRgbColor(color)) {\n const match = color.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\n if (match) {\n const [, r, g, b] = match.map(Number);\n const [rs, gs, bs] = [r, g, b].map((c) => {\n const val = c / 255;\n return val <= 0.03928 ? val / 12.92 : Math.pow((val + 0.055) / 1.055, 2.4);\n });\n return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;\n }\n }\n\n // Default to 0.5 (medium luminance) if unable to parse\n return 0.5;\n}\n\n/**\n * Get contrast color (black or white) based on background luminance\n */\nexport function getContrastColor(backgroundColor: string): string {\n const luminance = getColorLuminance(backgroundColor);\n // WCAG standard: use white text on dark backgrounds (luminance < 0.5)\n return luminance < 0.5 ? '#ffffff' : '#000000';\n}\n"],"names":[],"mappings":";;AAGO,SAAS,WAAW,OAAwB;AACjD,SAAO,qCAAqC,KAAK,KAAK;AACxD;AAKO,SAAS,WAAW,OAAwB;AACjD,SAAO,wBAAwB,KAAK,KAAK;AAC3C;AAKO,SAAS,SAAS,KAAyD;AAChF,QAAM,SAAS,4CAA4C,KAAK,GAAG;AACnE,SAAO,SACH;AAAA,IACE,GAAG,SAAS,OAAO,CAAC,GAAG,EAAE;AAAA,IACzB,GAAG,SAAS,OAAO,CAAC,GAAG,EAAE;AAAA,IACzB,GAAG,SAAS,OAAO,CAAC,GAAG,EAAE;AAAA,EAAA,IAE3B;AACN;AAKO,SAAS,qBAAqB,QAA6C,UAAkB;AAClG,MAAI,OAAO,UAAU,UAAU;AAE7B,UAAM,aAAa,CAAC,MAAM,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,IAAI,KAAK,IAAI,KAAO,KAAK,CAAC,IAAI;AACvF,WAAO,GAAG,UAAU;AAAA,EACtB;AAEA,QAAM,WAAW;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,MAAM;AAAA,EAAA;AAGR,SAAO,SAAS,KAAK,KAAK,SAAS;AACrC;AAMO,SAAS,cAAc,MAAmE;AAE/F,QAAM,gBAAgB;AAAA,IACpB,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,EAAA;AAGN,MAAI,OAAO,SAAS,YAAY,QAAQ,eAAe;AACrD,WAAO,GAAG,cAAc,IAAkC,CAAC;AAAA,EAC7D;AAEA,MAAI,OAAO,SAAS,UAAU;AAC5B,WAAO,GAAG,IAAI;AAAA,EAChB;AACA,SAAO,QAAQ;AACjB;AAKO,SAAS,kBAAkB,MAAmC,UAA0B;AAC7F,MAAI,OAAO,SAAS,UAAU;AAC5B,WAAO,CAAC,MAAM,IAAI,KAAK,OAAO,IAAI,OAAO;AAAA,EAC3C;AAEA,MAAI,OAAO,SAAS,UAAU;AAC5B,UAAM,SAAS,SAAS,MAAM,EAAE;AAChC,WAAO,CAAC,MAAM,MAAM,KAAK,SAAS,IAAI,SAAS;AAAA,EACjD;AAEA,SAAO;AACT;AAMO,SAAS,kBAAkB,OAAuB;AAEvD,MAAI,WAAW,KAAK,GAAG;AACrB,UAAM,MAAM,SAAS,KAAK;AAC1B,QAAI,KAAK;AAEP,YAAM,EAAE,GAAG,GAAG,EAAA,IAAM;AACpB,YAAM,CAAC,IAAI,IAAI,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM;AACxC,cAAM,MAAM,IAAI;AAChB,eAAO,OAAO,UAAU,MAAM,QAAQ,KAAK,KAAK,MAAM,SAAS,OAAO,GAAG;AAAA,MAC3E,CAAC;AACD,aAAO,SAAS,KAAK,SAAS,KAAK,SAAS;AAAA,IAC9C;AAAA,EACF;AAGA,MAAI,WAAW,KAAK,GAAG;AACrB,UAAM,QAAQ,MAAM,MAAM,gCAAgC;AAC1D,QAAI,OAAO;AACT,YAAM,CAAA,EAAG,GAAG,GAAG,CAAC,IAAI,MAAM,IAAI,MAAM;AACpC,YAAM,CAAC,IAAI,IAAI,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM;AACxC,cAAM,MAAM,IAAI;AAChB,eAAO,OAAO,UAAU,MAAM,QAAQ,KAAK,KAAK,MAAM,SAAS,OAAO,GAAG;AAAA,MAC3E,CAAC;AACD,aAAO,SAAS,KAAK,SAAS,KAAK,SAAS;AAAA,IAC9C;AAAA,EACF;AAGA,SAAO;AACT;AAKO,SAAS,iBAAiB,iBAAiC;AAChE,QAAM,YAAY,kBAAkB,eAAe;AAEnD,SAAO,YAAY,MAAM,YAAY;AACvC;;;;;;;;;"}
package/dist/index4.js CHANGED
@@ -25,6 +25,16 @@ function getAnimationDuration(speed = "normal") {
25
25
  return speedMap[speed] || speedMap.normal;
26
26
  }
27
27
  function normalizeSize(size) {
28
+ const sizePresetMap = {
29
+ xs: 16,
30
+ sm: 24,
31
+ md: 40,
32
+ lg: 56,
33
+ xl: 72
34
+ };
35
+ if (typeof size === "string" && size in sizePresetMap) {
36
+ return `${sizePresetMap[size]}px`;
37
+ }
28
38
  if (typeof size === "number") {
29
39
  return `${size}px`;
30
40
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index4.js","sources":["../src/utils/colors.ts"],"sourcesContent":["/**\n * Check if a color is a valid hex color\n */\nexport function isHexColor(color: string): boolean {\n return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(color);\n}\n\n/**\n * Check if a color is a valid RGB/RGBA color\n */\nexport function isRgbColor(color: string): boolean {\n return /^rgba?\\([\\d\\s,./]+\\)$/.test(color);\n}\n\n/**\n * Convert hex color to RGB\n */\nexport function hexToRgb(hex: string): { r: number; g: number; b: number } | null {\n const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\n return result\n ? {\n r: parseInt(result[1], 16),\n g: parseInt(result[2], 16),\n b: parseInt(result[3], 16),\n }\n : null;\n}\n\n/**\n * Get animation duration in CSS format\n */\nexport function getAnimationDuration(speed: 'slow' | 'normal' | 'fast' | number = 'normal'): string {\n if (typeof speed === 'number') {\n // Validate number is valid and positive, clamp to reasonable range (50ms - 10000ms)\n const validSpeed = !isNaN(speed) && speed > 0 ? Math.max(50, Math.min(10000, speed)) : 1000;\n return `${validSpeed}ms`;\n }\n\n const speedMap = {\n slow: '2s',\n normal: '1s',\n fast: '0.5s',\n };\n\n return speedMap[speed] || speedMap.normal;\n}\n\n/**\n * Normalize size value to CSS string\n */\nexport function normalizeSize(size?: number | string): string {\n if (typeof size === 'number') {\n return `${size}px`;\n }\n return size || 'auto';\n}\n\n/**\n * Safely parse size to number with fallback\n */\nexport function parseSizeToNumber(size: number | string | undefined, fallback: number): number {\n if (typeof size === 'number') {\n return !isNaN(size) && size > 0 ? size : fallback;\n }\n\n if (typeof size === 'string') {\n const parsed = parseInt(size, 10);\n return !isNaN(parsed) && parsed > 0 ? parsed : fallback;\n }\n\n return fallback;\n}\n\n/**\n * Calculate relative luminance of a color (0-1 scale)\n * Used for determining if text should be light or dark for contrast\n */\nexport function getColorLuminance(color: string): number {\n // Try to parse hex color\n if (isHexColor(color)) {\n const rgb = hexToRgb(color);\n if (rgb) {\n // Convert RGB to relative luminance using WCAG formula\n const { r, g, b } = rgb;\n const [rs, gs, bs] = [r, g, b].map((c) => {\n const val = c / 255;\n return val <= 0.03928 ? val / 12.92 : Math.pow((val + 0.055) / 1.055, 2.4);\n });\n return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;\n }\n }\n\n // Try to parse RGB/RGBA color\n if (isRgbColor(color)) {\n const match = color.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\n if (match) {\n const [, r, g, b] = match.map(Number);\n const [rs, gs, bs] = [r, g, b].map((c) => {\n const val = c / 255;\n return val <= 0.03928 ? val / 12.92 : Math.pow((val + 0.055) / 1.055, 2.4);\n });\n return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;\n }\n }\n\n // Default to 0.5 (medium luminance) if unable to parse\n return 0.5;\n}\n\n/**\n * Get contrast color (black or white) based on background luminance\n */\nexport function getContrastColor(backgroundColor: string): string {\n const luminance = getColorLuminance(backgroundColor);\n // WCAG standard: use white text on dark backgrounds (luminance < 0.5)\n return luminance < 0.5 ? '#ffffff' : '#000000';\n}\n"],"names":[],"mappings":"AAGO,SAAS,WAAW,OAAwB;AACjD,SAAO,qCAAqC,KAAK,KAAK;AACxD;AAKO,SAAS,WAAW,OAAwB;AACjD,SAAO,wBAAwB,KAAK,KAAK;AAC3C;AAKO,SAAS,SAAS,KAAyD;AAChF,QAAM,SAAS,4CAA4C,KAAK,GAAG;AACnE,SAAO,SACH;AAAA,IACE,GAAG,SAAS,OAAO,CAAC,GAAG,EAAE;AAAA,IACzB,GAAG,SAAS,OAAO,CAAC,GAAG,EAAE;AAAA,IACzB,GAAG,SAAS,OAAO,CAAC,GAAG,EAAE;AAAA,EAAA,IAE3B;AACN;AAKO,SAAS,qBAAqB,QAA6C,UAAkB;AAClG,MAAI,OAAO,UAAU,UAAU;AAE7B,UAAM,aAAa,CAAC,MAAM,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,IAAI,KAAK,IAAI,KAAO,KAAK,CAAC,IAAI;AACvF,WAAO,GAAG,UAAU;AAAA,EACtB;AAEA,QAAM,WAAW;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,MAAM;AAAA,EAAA;AAGR,SAAO,SAAS,KAAK,KAAK,SAAS;AACrC;AAKO,SAAS,cAAc,MAAgC;AAC5D,MAAI,OAAO,SAAS,UAAU;AAC5B,WAAO,GAAG,IAAI;AAAA,EAChB;AACA,SAAO,QAAQ;AACjB;AAKO,SAAS,kBAAkB,MAAmC,UAA0B;AAC7F,MAAI,OAAO,SAAS,UAAU;AAC5B,WAAO,CAAC,MAAM,IAAI,KAAK,OAAO,IAAI,OAAO;AAAA,EAC3C;AAEA,MAAI,OAAO,SAAS,UAAU;AAC5B,UAAM,SAAS,SAAS,MAAM,EAAE;AAChC,WAAO,CAAC,MAAM,MAAM,KAAK,SAAS,IAAI,SAAS;AAAA,EACjD;AAEA,SAAO;AACT;AAMO,SAAS,kBAAkB,OAAuB;AAEvD,MAAI,WAAW,KAAK,GAAG;AACrB,UAAM,MAAM,SAAS,KAAK;AAC1B,QAAI,KAAK;AAEP,YAAM,EAAE,GAAG,GAAG,EAAA,IAAM;AACpB,YAAM,CAAC,IAAI,IAAI,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM;AACxC,cAAM,MAAM,IAAI;AAChB,eAAO,OAAO,UAAU,MAAM,QAAQ,KAAK,KAAK,MAAM,SAAS,OAAO,GAAG;AAAA,MAC3E,CAAC;AACD,aAAO,SAAS,KAAK,SAAS,KAAK,SAAS;AAAA,IAC9C;AAAA,EACF;AAGA,MAAI,WAAW,KAAK,GAAG;AACrB,UAAM,QAAQ,MAAM,MAAM,gCAAgC;AAC1D,QAAI,OAAO;AACT,YAAM,CAAA,EAAG,GAAG,GAAG,CAAC,IAAI,MAAM,IAAI,MAAM;AACpC,YAAM,CAAC,IAAI,IAAI,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM;AACxC,cAAM,MAAM,IAAI;AAChB,eAAO,OAAO,UAAU,MAAM,QAAQ,KAAK,KAAK,MAAM,SAAS,OAAO,GAAG;AAAA,MAC3E,CAAC;AACD,aAAO,SAAS,KAAK,SAAS,KAAK,SAAS;AAAA,IAC9C;AAAA,EACF;AAGA,SAAO;AACT;AAKO,SAAS,iBAAiB,iBAAiC;AAChE,QAAM,YAAY,kBAAkB,eAAe;AAEnD,SAAO,YAAY,MAAM,YAAY;AACvC;"}
1
+ {"version":3,"file":"index4.js","sources":["../src/utils/colors.ts"],"sourcesContent":["/**\n * Check if a color is a valid hex color\n */\nexport function isHexColor(color: string): boolean {\n return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(color);\n}\n\n/**\n * Check if a color is a valid RGB/RGBA color\n */\nexport function isRgbColor(color: string): boolean {\n return /^rgba?\\([\\d\\s,./]+\\)$/.test(color);\n}\n\n/**\n * Convert hex color to RGB\n */\nexport function hexToRgb(hex: string): { r: number; g: number; b: number } | null {\n const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\n return result\n ? {\n r: parseInt(result[1], 16),\n g: parseInt(result[2], 16),\n b: parseInt(result[3], 16),\n }\n : null;\n}\n\n/**\n * Get animation duration in CSS format\n */\nexport function getAnimationDuration(speed: 'slow' | 'normal' | 'fast' | number = 'normal'): string {\n if (typeof speed === 'number') {\n // Validate number is valid and positive, clamp to reasonable range (50ms - 10000ms)\n const validSpeed = !isNaN(speed) && speed > 0 ? Math.max(50, Math.min(10000, speed)) : 1000;\n return `${validSpeed}ms`;\n }\n\n const speedMap = {\n slow: '2s',\n normal: '1s',\n fast: '0.5s',\n };\n\n return speedMap[speed] || speedMap.normal;\n}\n\n/**\n * Normalize size value to CSS string\n * Supports size presets ('xs', 'sm', 'md', 'lg', 'xl'), numeric values, or CSS strings\n */\nexport function normalizeSize(size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | number | string): string {\n // Handle size presets\n const sizePresetMap = {\n xs: 16,\n sm: 24,\n md: 40,\n lg: 56,\n xl: 72,\n };\n\n if (typeof size === 'string' && size in sizePresetMap) {\n return `${sizePresetMap[size as keyof typeof sizePresetMap]}px`;\n }\n\n if (typeof size === 'number') {\n return `${size}px`;\n }\n return size || 'auto';\n}\n\n/**\n * Safely parse size to number with fallback\n */\nexport function parseSizeToNumber(size: number | string | undefined, fallback: number): number {\n if (typeof size === 'number') {\n return !isNaN(size) && size > 0 ? size : fallback;\n }\n\n if (typeof size === 'string') {\n const parsed = parseInt(size, 10);\n return !isNaN(parsed) && parsed > 0 ? parsed : fallback;\n }\n\n return fallback;\n}\n\n/**\n * Calculate relative luminance of a color (0-1 scale)\n * Used for determining if text should be light or dark for contrast\n */\nexport function getColorLuminance(color: string): number {\n // Try to parse hex color\n if (isHexColor(color)) {\n const rgb = hexToRgb(color);\n if (rgb) {\n // Convert RGB to relative luminance using WCAG formula\n const { r, g, b } = rgb;\n const [rs, gs, bs] = [r, g, b].map((c) => {\n const val = c / 255;\n return val <= 0.03928 ? val / 12.92 : Math.pow((val + 0.055) / 1.055, 2.4);\n });\n return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;\n }\n }\n\n // Try to parse RGB/RGBA color\n if (isRgbColor(color)) {\n const match = color.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\n if (match) {\n const [, r, g, b] = match.map(Number);\n const [rs, gs, bs] = [r, g, b].map((c) => {\n const val = c / 255;\n return val <= 0.03928 ? val / 12.92 : Math.pow((val + 0.055) / 1.055, 2.4);\n });\n return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;\n }\n }\n\n // Default to 0.5 (medium luminance) if unable to parse\n return 0.5;\n}\n\n/**\n * Get contrast color (black or white) based on background luminance\n */\nexport function getContrastColor(backgroundColor: string): string {\n const luminance = getColorLuminance(backgroundColor);\n // WCAG standard: use white text on dark backgrounds (luminance < 0.5)\n return luminance < 0.5 ? '#ffffff' : '#000000';\n}\n"],"names":[],"mappings":"AAGO,SAAS,WAAW,OAAwB;AACjD,SAAO,qCAAqC,KAAK,KAAK;AACxD;AAKO,SAAS,WAAW,OAAwB;AACjD,SAAO,wBAAwB,KAAK,KAAK;AAC3C;AAKO,SAAS,SAAS,KAAyD;AAChF,QAAM,SAAS,4CAA4C,KAAK,GAAG;AACnE,SAAO,SACH;AAAA,IACE,GAAG,SAAS,OAAO,CAAC,GAAG,EAAE;AAAA,IACzB,GAAG,SAAS,OAAO,CAAC,GAAG,EAAE;AAAA,IACzB,GAAG,SAAS,OAAO,CAAC,GAAG,EAAE;AAAA,EAAA,IAE3B;AACN;AAKO,SAAS,qBAAqB,QAA6C,UAAkB;AAClG,MAAI,OAAO,UAAU,UAAU;AAE7B,UAAM,aAAa,CAAC,MAAM,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,IAAI,KAAK,IAAI,KAAO,KAAK,CAAC,IAAI;AACvF,WAAO,GAAG,UAAU;AAAA,EACtB;AAEA,QAAM,WAAW;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,MAAM;AAAA,EAAA;AAGR,SAAO,SAAS,KAAK,KAAK,SAAS;AACrC;AAMO,SAAS,cAAc,MAAmE;AAE/F,QAAM,gBAAgB;AAAA,IACpB,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,EAAA;AAGN,MAAI,OAAO,SAAS,YAAY,QAAQ,eAAe;AACrD,WAAO,GAAG,cAAc,IAAkC,CAAC;AAAA,EAC7D;AAEA,MAAI,OAAO,SAAS,UAAU;AAC5B,WAAO,GAAG,IAAI;AAAA,EAChB;AACA,SAAO,QAAQ;AACjB;AAKO,SAAS,kBAAkB,MAAmC,UAA0B;AAC7F,MAAI,OAAO,SAAS,UAAU;AAC5B,WAAO,CAAC,MAAM,IAAI,KAAK,OAAO,IAAI,OAAO;AAAA,EAC3C;AAEA,MAAI,OAAO,SAAS,UAAU;AAC5B,UAAM,SAAS,SAAS,MAAM,EAAE;AAChC,WAAO,CAAC,MAAM,MAAM,KAAK,SAAS,IAAI,SAAS;AAAA,EACjD;AAEA,SAAO;AACT;AAMO,SAAS,kBAAkB,OAAuB;AAEvD,MAAI,WAAW,KAAK,GAAG;AACrB,UAAM,MAAM,SAAS,KAAK;AAC1B,QAAI,KAAK;AAEP,YAAM,EAAE,GAAG,GAAG,EAAA,IAAM;AACpB,YAAM,CAAC,IAAI,IAAI,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM;AACxC,cAAM,MAAM,IAAI;AAChB,eAAO,OAAO,UAAU,MAAM,QAAQ,KAAK,KAAK,MAAM,SAAS,OAAO,GAAG;AAAA,MAC3E,CAAC;AACD,aAAO,SAAS,KAAK,SAAS,KAAK,SAAS;AAAA,IAC9C;AAAA,EACF;AAGA,MAAI,WAAW,KAAK,GAAG;AACrB,UAAM,QAAQ,MAAM,MAAM,gCAAgC;AAC1D,QAAI,OAAO;AACT,YAAM,CAAA,EAAG,GAAG,GAAG,CAAC,IAAI,MAAM,IAAI,MAAM;AACpC,YAAM,CAAC,IAAI,IAAI,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM;AACxC,cAAM,MAAM,IAAI;AAChB,eAAO,OAAO,UAAU,MAAM,QAAQ,KAAK,KAAK,MAAM,SAAS,OAAO,GAAG;AAAA,MAC3E,CAAC;AACD,aAAO,SAAS,KAAK,SAAS,KAAK,SAAS;AAAA,IAC9C;AAAA,EACF;AAGA,SAAO;AACT;AAKO,SAAS,iBAAiB,iBAAiC;AAChE,QAAM,YAAY,kBAAkB,eAAe;AAEnD,SAAO,YAAY,MAAM,YAAY;AACvC;"}