premium-react-loaders 1.1.0 → 1.2.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 (99) hide show
  1. package/README.md +55 -6
  2. package/dist/components/progress/ProgressBar.d.ts.map +1 -1
  3. package/dist/components/progress/ProgressCircle.d.ts.map +1 -1
  4. package/dist/components/progress/ProgressRing.d.ts.map +1 -1
  5. package/dist/components/pulse/PulseBars.d.ts +2 -2
  6. package/dist/components/pulse/PulseBars.d.ts.map +1 -1
  7. package/dist/components/pulse/PulseDots.d.ts +2 -2
  8. package/dist/components/pulse/PulseDots.d.ts.map +1 -1
  9. package/dist/components/pulse/PulseWave.d.ts +2 -2
  10. package/dist/components/pulse/PulseWave.d.ts.map +1 -1
  11. package/dist/components/pulse/TypingIndicator.d.ts.map +1 -1
  12. package/dist/components/spinner/SpinnerBars.d.ts +2 -2
  13. package/dist/components/spinner/SpinnerBars.d.ts.map +1 -1
  14. package/dist/components/spinner/SpinnerCircle.d.ts +2 -1
  15. package/dist/components/spinner/SpinnerCircle.d.ts.map +1 -1
  16. package/dist/components/spinner/SpinnerDots.d.ts +2 -2
  17. package/dist/components/spinner/SpinnerDots.d.ts.map +1 -1
  18. package/dist/components/spinner/SpinnerGrid.d.ts +2 -2
  19. package/dist/components/spinner/SpinnerGrid.d.ts.map +1 -1
  20. package/dist/components/spinner/SpinnerPulse.d.ts +3 -3
  21. package/dist/components/spinner/SpinnerPulse.d.ts.map +1 -1
  22. package/dist/components/spinner/SpinnerRing.d.ts +3 -3
  23. package/dist/components/spinner/SpinnerRing.d.ts.map +1 -1
  24. package/dist/components/spinner/SpinnerWave.d.ts +3 -3
  25. package/dist/components/spinner/SpinnerWave.d.ts.map +1 -1
  26. package/dist/index14.cjs +9 -3
  27. package/dist/index14.cjs.map +1 -1
  28. package/dist/index14.js +9 -3
  29. package/dist/index14.js.map +1 -1
  30. package/dist/index15.cjs +8 -2
  31. package/dist/index15.cjs.map +1 -1
  32. package/dist/index15.js +9 -3
  33. package/dist/index15.js.map +1 -1
  34. package/dist/index16.cjs +8 -2
  35. package/dist/index16.cjs.map +1 -1
  36. package/dist/index16.js +9 -3
  37. package/dist/index16.js.map +1 -1
  38. package/dist/index17.cjs +8 -4
  39. package/dist/index17.cjs.map +1 -1
  40. package/dist/index17.js +9 -5
  41. package/dist/index17.js.map +1 -1
  42. package/dist/index18.cjs +9 -4
  43. package/dist/index18.cjs.map +1 -1
  44. package/dist/index18.js +10 -5
  45. package/dist/index18.js.map +1 -1
  46. package/dist/index19.cjs +9 -4
  47. package/dist/index19.cjs.map +1 -1
  48. package/dist/index19.js +10 -5
  49. package/dist/index19.js.map +1 -1
  50. package/dist/index20.cjs +9 -4
  51. package/dist/index20.cjs.map +1 -1
  52. package/dist/index20.js +10 -5
  53. package/dist/index20.js.map +1 -1
  54. package/dist/index21.cjs +7 -2
  55. package/dist/index21.cjs.map +1 -1
  56. package/dist/index21.js +8 -3
  57. package/dist/index21.js.map +1 -1
  58. package/dist/index22.cjs +11 -4
  59. package/dist/index22.cjs.map +1 -1
  60. package/dist/index22.js +12 -5
  61. package/dist/index22.js.map +1 -1
  62. package/dist/index23.cjs +11 -4
  63. package/dist/index23.cjs.map +1 -1
  64. package/dist/index23.js +12 -5
  65. package/dist/index23.js.map +1 -1
  66. package/dist/index25.cjs +8 -4
  67. package/dist/index25.cjs.map +1 -1
  68. package/dist/index25.js +9 -5
  69. package/dist/index25.js.map +1 -1
  70. package/dist/index26.cjs +8 -4
  71. package/dist/index26.cjs.map +1 -1
  72. package/dist/index26.js +9 -5
  73. package/dist/index26.js.map +1 -1
  74. package/dist/index27.cjs +9 -4
  75. package/dist/index27.cjs.map +1 -1
  76. package/dist/index27.js +10 -5
  77. package/dist/index27.js.map +1 -1
  78. package/dist/index28.cjs +7 -3
  79. package/dist/index28.cjs.map +1 -1
  80. package/dist/index28.js +8 -4
  81. package/dist/index28.js.map +1 -1
  82. package/dist/index31.cjs +42 -0
  83. package/dist/index31.cjs.map +1 -0
  84. package/dist/index31.js +42 -0
  85. package/dist/index31.js.map +1 -0
  86. package/dist/index4.cjs +10 -0
  87. package/dist/index4.cjs.map +1 -1
  88. package/dist/index4.js +10 -0
  89. package/dist/index4.js.map +1 -1
  90. package/dist/premium-react-loaders.css +270 -3
  91. package/dist/types/common.d.ts +14 -2
  92. package/dist/types/common.d.ts.map +1 -1
  93. package/dist/utils/colors.d.ts +2 -1
  94. package/dist/utils/colors.d.ts.map +1 -1
  95. package/dist/utils/hooks.d.ts +10 -0
  96. package/dist/utils/hooks.d.ts.map +1 -0
  97. package/dist/utils/index.d.ts +1 -0
  98. package/dist/utils/index.d.ts.map +1 -1
  99. package/package.json +1 -1
package/dist/index25.js CHANGED
@@ -1,14 +1,17 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { forwardRef } from "react";
3
- import { normalizeSize, getAnimationDuration } from "./index4.js";
3
+ import { useReducedMotion, getEffectiveDuration } from "./index31.js";
4
+ import { normalizeSize } from "./index4.js";
4
5
  import { cn } from "./index3.js";
5
6
  const PulseDots = forwardRef(
6
7
  ({
7
- size = 40,
8
+ size = "md",
8
9
  color = "#3b82f6",
9
10
  dotCount = 3,
10
11
  dotSize = 10,
11
12
  speed = "normal",
13
+ reverse = false,
14
+ respectMotionPreference = true,
12
15
  className,
13
16
  style,
14
17
  testId = "pulse-dots",
@@ -17,7 +20,8 @@ const PulseDots = forwardRef(
17
20
  ...rest
18
21
  }, ref) => {
19
22
  if (!visible) return null;
20
- const animationDuration = getAnimationDuration(speed);
23
+ const prefersReducedMotion = useReducedMotion();
24
+ const effectiveDuration = getEffectiveDuration(speed, respectMotionPreference, prefersReducedMotion);
21
25
  return /* @__PURE__ */ jsx(
22
26
  "div",
23
27
  {
@@ -40,8 +44,8 @@ const PulseDots = forwardRef(
40
44
  width: normalizeSize(dotSize),
41
45
  height: normalizeSize(dotSize),
42
46
  backgroundColor: color,
43
- animation: `pulse-bounce ${animationDuration} ease-in-out infinite`,
44
- animationDelay: `${index * 0.15}s`
47
+ animation: `pulse-bounce ${effectiveDuration} ease-in-out infinite`,
48
+ animationDelay: reverse ? `${(dotCount - index - 1) * 0.15}s` : `${index * 0.15}s`
45
49
  }
46
50
  },
47
51
  index
@@ -1 +1 @@
1
- {"version":3,"file":"index25.js","sources":["../src/components/pulse/PulseDots.tsx"],"sourcesContent":["import { forwardRef } from 'react';\nimport { PulseDotsProps } from '../../types';\nimport { cn, normalizeSize, getAnimationDuration } from '../../utils';\n\n/**\n * PulseDots - Bouncing dots loader\n *\n * A loader with bouncing dots that scale and fade in a sequence.\n *\n * @example\n * ```tsx\n * <PulseDots size={40} color=\"#3b82f6\" />\n * <PulseDots size={32} dotCount={5} speed=\"fast\" />\n * ```\n */\nexport const PulseDots = forwardRef<HTMLDivElement, PulseDotsProps>(\n (\n {\n size = 40,\n color = '#3b82f6',\n dotCount = 3,\n dotSize = 10,\n speed = 'normal',\n className,\n style,\n testId = 'pulse-dots',\n visible = true,\n ariaLabel = 'Loading...',\n ...rest\n },\n ref\n ) => {\n if (!visible) return null;\n\n const animationDuration = getAnimationDuration(speed);\n\n return (\n <div\n ref={ref}\n data-testid={testId}\n className={cn('inline-flex items-center justify-center gap-2', className)}\n style={{\n height: normalizeSize(size),\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: `pulse-bounce ${animationDuration} ease-in-out infinite`,\n animationDelay: `${index * 0.15}s`,\n }}\n />\n ))}\n </div>\n );\n }\n);\n\nPulseDots.displayName = 'PulseDots';\n"],"names":[],"mappings":";;;;AAeO,MAAM,YAAY;AAAA,EACvB,CACE;AAAA,IACE,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,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;AAEpD,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAa;AAAA,QACb,WAAW,GAAG,iDAAiD,SAAS;AAAA,QACxE,OAAO;AAAA,UACL,QAAQ,cAAc,IAAI;AAAA,UAC1B,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,gBAAgB,iBAAiB;AAAA,cAC5C,gBAAgB,GAAG,QAAQ,IAAI;AAAA,YAAA;AAAA,UACjC;AAAA,UARK;AAAA,QAAA,CAUR;AAAA,MAAA;AAAA,IAAA;AAAA,EAGP;AACF;AAEA,UAAU,cAAc;"}
1
+ {"version":3,"file":"index25.js","sources":["../src/components/pulse/PulseDots.tsx"],"sourcesContent":["import { forwardRef } from 'react';\nimport { PulseDotsProps } from '../../types';\nimport { cn, normalizeSize, useReducedMotion, getEffectiveDuration } from '../../utils';\n\n/**\n * PulseDots - Bouncing dots loader\n *\n * A loader with bouncing dots that scale and fade in a sequence.\n *\n * @example\n * ```tsx\n * <PulseDots size=\"lg\" color=\"#3b82f6\" />\n * <PulseDots size=\"sm\" dotCount={5} speed=\"fast\" reverse />\n * ```\n */\nexport const PulseDots = forwardRef<HTMLDivElement, PulseDotsProps>(\n (\n {\n size = 'md',\n color = '#3b82f6',\n dotCount = 3,\n dotSize = 10,\n speed = 'normal',\n reverse = false,\n respectMotionPreference = true,\n className,\n style,\n testId = 'pulse-dots',\n visible = true,\n ariaLabel = 'Loading...',\n ...rest\n },\n ref\n ) => {\n if (!visible) return null;\n\n const prefersReducedMotion = useReducedMotion();\n const effectiveDuration = getEffectiveDuration(speed, respectMotionPreference, prefersReducedMotion);\n\n return (\n <div\n ref={ref}\n data-testid={testId}\n className={cn('inline-flex items-center justify-center gap-2', className)}\n style={{\n height: normalizeSize(size),\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: `pulse-bounce ${effectiveDuration} ease-in-out infinite`,\n animationDelay: reverse ? `${(dotCount - index - 1) * 0.15}s` : `${index * 0.15}s`,\n }}\n />\n ))}\n </div>\n );\n }\n);\n\nPulseDots.displayName = 'PulseDots';\n"],"names":[],"mappings":";;;;;AAeO,MAAM,YAAY;AAAA,EACvB,CACE;AAAA,IACE,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,0BAA0B;AAAA,IAC1B;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,uBAAuB,iBAAA;AAC7B,UAAM,oBAAoB,qBAAqB,OAAO,yBAAyB,oBAAoB;AAEnG,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAa;AAAA,QACb,WAAW,GAAG,iDAAiD,SAAS;AAAA,QACxE,OAAO;AAAA,UACL,QAAQ,cAAc,IAAI;AAAA,UAC1B,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,gBAAgB,iBAAiB;AAAA,cAC5C,gBAAgB,UAAU,IAAI,WAAW,QAAQ,KAAK,IAAI,MAAM,GAAG,QAAQ,IAAI;AAAA,YAAA;AAAA,UACjF;AAAA,UARK;AAAA,QAAA,CAUR;AAAA,MAAA;AAAA,IAAA;AAAA,EAGP;AACF;AAEA,UAAU,cAAc;"}
package/dist/index26.cjs CHANGED
@@ -2,14 +2,17 @@
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 colors = require("./index4.cjs");
6
7
  const classNames = require("./index3.cjs");
7
8
  const PulseWave = react.forwardRef(
8
9
  ({
9
- size = 40,
10
+ size = "md",
10
11
  color = "#3b82f6",
11
12
  barCount = 5,
12
13
  speed = "normal",
14
+ reverse = false,
15
+ respectMotionPreference = true,
13
16
  className,
14
17
  style,
15
18
  testId = "pulse-wave",
@@ -18,9 +21,10 @@ const PulseWave = react.forwardRef(
18
21
  ...rest
19
22
  }, ref) => {
20
23
  if (!visible) return null;
24
+ const prefersReducedMotion = hooks.useReducedMotion();
25
+ const effectiveDuration = hooks.getEffectiveDuration(speed, respectMotionPreference, prefersReducedMotion);
21
26
  const sizeValue = colors.parseSizeToNumber(size, 40);
22
27
  const barWidth = Math.floor(sizeValue / (barCount * 2.5));
23
- const animationDuration = colors.getAnimationDuration(speed);
24
28
  return /* @__PURE__ */ jsxRuntime.jsx(
25
29
  "div",
26
30
  {
@@ -36,7 +40,7 @@ const PulseWave = react.forwardRef(
36
40
  "aria-busy": "true",
37
41
  ...rest,
38
42
  children: Array.from({ length: barCount }).map((_, index) => {
39
- const delay = index / barCount * 0.5;
43
+ const delay = reverse ? (barCount - index - 1) / barCount * 0.5 : index / barCount * 0.5;
40
44
  return /* @__PURE__ */ jsxRuntime.jsx(
41
45
  "div",
42
46
  {
@@ -45,7 +49,7 @@ const PulseWave = react.forwardRef(
45
49
  width: `${barWidth}px`,
46
50
  height: "100%",
47
51
  backgroundColor: color,
48
- animation: `pulse-wave ${animationDuration} ease-in-out infinite`,
52
+ animation: `pulse-wave ${effectiveDuration} ease-in-out infinite`,
49
53
  animationDelay: `${delay}s`,
50
54
  transformOrigin: "bottom"
51
55
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index26.cjs","sources":["../src/components/pulse/PulseWave.tsx"],"sourcesContent":["import { forwardRef } from 'react';\nimport { PulseWaveProps } from '../../types';\nimport { cn, normalizeSize, getAnimationDuration, parseSizeToNumber } from '../../utils';\n\n/**\n * PulseWave - Wave pattern loader\n *\n * A loader with bars that animate in a wave pattern.\n *\n * @example\n * ```tsx\n * <PulseWave size={40} color=\"#3b82f6\" />\n * <PulseWave size={32} barCount={7} speed=\"slow\" />\n * ```\n */\nexport const PulseWave = forwardRef<HTMLDivElement, PulseWaveProps>(\n (\n {\n size = 40,\n color = '#3b82f6',\n barCount = 5,\n speed = 'normal',\n className,\n style,\n testId = 'pulse-wave',\n visible = true,\n ariaLabel = 'Loading...',\n ...rest\n },\n ref\n ) => {\n if (!visible) return null;\n\n const sizeValue = parseSizeToNumber(size, 40);\n const barWidth = Math.floor(sizeValue / (barCount * 2.5));\n const animationDuration = getAnimationDuration(speed);\n\n return (\n <div\n ref={ref}\n data-testid={testId}\n className={cn('inline-flex items-end justify-center gap-1', className)}\n style={{\n height: normalizeSize(size),\n ...style,\n }}\n role=\"status\"\n aria-label={ariaLabel}\n aria-busy=\"true\"\n {...rest}\n >\n {Array.from({ length: barCount }).map((_, index) => {\n const delay = (index / barCount) * 0.5;\n\n return (\n <div\n key={index}\n className=\"rounded-sm\"\n style={{\n width: `${barWidth}px`,\n height: '100%',\n backgroundColor: color,\n animation: `pulse-wave ${animationDuration} ease-in-out infinite`,\n animationDelay: `${delay}s`,\n transformOrigin: 'bottom',\n }}\n />\n );\n })}\n </div>\n );\n }\n);\n\nPulseWave.displayName = 'PulseWave';\n"],"names":["forwardRef","parseSizeToNumber","getAnimationDuration","jsx","cn","normalizeSize"],"mappings":";;;;;;AAeO,MAAM,YAAYA,MAAAA;AAAAA,EACvB,CACE;AAAA,IACE,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,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,YAAYC,OAAAA,kBAAkB,MAAM,EAAE;AAC5C,UAAM,WAAW,KAAK,MAAM,aAAa,WAAW,IAAI;AACxD,UAAM,oBAAoBC,OAAAA,qBAAqB,KAAK;AAEpD,WACEC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAa;AAAA,QACb,WAAWC,WAAAA,GAAG,8CAA8C,SAAS;AAAA,QACrE,OAAO;AAAA,UACL,QAAQC,OAAAA,cAAc,IAAI;AAAA,UAC1B,GAAG;AAAA,QAAA;AAAA,QAEL,MAAK;AAAA,QACL,cAAY;AAAA,QACZ,aAAU;AAAA,QACT,GAAG;AAAA,QAEH,UAAA,MAAM,KAAK,EAAE,QAAQ,SAAA,CAAU,EAAE,IAAI,CAAC,GAAG,UAAU;AAClD,gBAAM,QAAS,QAAQ,WAAY;AAEnC,iBACEF,2BAAAA;AAAAA,YAAC;AAAA,YAAA;AAAA,cAEC,WAAU;AAAA,cACV,OAAO;AAAA,gBACL,OAAO,GAAG,QAAQ;AAAA,gBAClB,QAAQ;AAAA,gBACR,iBAAiB;AAAA,gBACjB,WAAW,cAAc,iBAAiB;AAAA,gBAC1C,gBAAgB,GAAG,KAAK;AAAA,gBACxB,iBAAiB;AAAA,cAAA;AAAA,YACnB;AAAA,YATK;AAAA,UAAA;AAAA,QAYX,CAAC;AAAA,MAAA;AAAA,IAAA;AAAA,EAGP;AACF;AAEA,UAAU,cAAc;;"}
1
+ {"version":3,"file":"index26.cjs","sources":["../src/components/pulse/PulseWave.tsx"],"sourcesContent":["import { forwardRef } from 'react';\nimport { PulseWaveProps } from '../../types';\nimport { cn, normalizeSize, parseSizeToNumber, useReducedMotion, getEffectiveDuration } from '../../utils';\n\n/**\n * PulseWave - Wave pattern loader\n *\n * A loader with bars that animate in a wave pattern.\n *\n * @example\n * ```tsx\n * <PulseWave size=\"lg\" color=\"#3b82f6\" />\n * <PulseWave size=\"sm\" barCount={7} speed=\"slow\" reverse />\n * ```\n */\nexport const PulseWave = forwardRef<HTMLDivElement, PulseWaveProps>(\n (\n {\n size = 'md',\n color = '#3b82f6',\n barCount = 5,\n speed = 'normal',\n reverse = false,\n respectMotionPreference = true,\n className,\n style,\n testId = 'pulse-wave',\n visible = true,\n ariaLabel = 'Loading...',\n ...rest\n },\n ref\n ) => {\n if (!visible) return null;\n\n const prefersReducedMotion = useReducedMotion();\n const effectiveDuration = getEffectiveDuration(speed, respectMotionPreference, prefersReducedMotion);\n\n const sizeValue = parseSizeToNumber(size, 40);\n const barWidth = Math.floor(sizeValue / (barCount * 2.5));\n\n return (\n <div\n ref={ref}\n data-testid={testId}\n className={cn('inline-flex items-end justify-center gap-1', className)}\n style={{\n height: normalizeSize(size),\n ...style,\n }}\n role=\"status\"\n aria-label={ariaLabel}\n aria-busy=\"true\"\n {...rest}\n >\n {Array.from({ length: barCount }).map((_, index) => {\n const delay = reverse ? ((barCount - index - 1) / barCount) * 0.5 : (index / barCount) * 0.5;\n\n return (\n <div\n key={index}\n className=\"rounded-sm\"\n style={{\n width: `${barWidth}px`,\n height: '100%',\n backgroundColor: color,\n animation: `pulse-wave ${effectiveDuration} ease-in-out infinite`,\n animationDelay: `${delay}s`,\n transformOrigin: 'bottom',\n }}\n />\n );\n })}\n </div>\n );\n }\n);\n\nPulseWave.displayName = 'PulseWave';\n"],"names":["forwardRef","useReducedMotion","getEffectiveDuration","parseSizeToNumber","jsx","cn","normalizeSize"],"mappings":";;;;;;;AAeO,MAAM,YAAYA,MAAAA;AAAAA,EACvB,CACE;AAAA,IACE,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,0BAA0B;AAAA,IAC1B;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,uBAAuBC,MAAAA,iBAAA;AAC7B,UAAM,oBAAoBC,MAAAA,qBAAqB,OAAO,yBAAyB,oBAAoB;AAEnG,UAAM,YAAYC,OAAAA,kBAAkB,MAAM,EAAE;AAC5C,UAAM,WAAW,KAAK,MAAM,aAAa,WAAW,IAAI;AAExD,WACEC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAa;AAAA,QACb,WAAWC,WAAAA,GAAG,8CAA8C,SAAS;AAAA,QACrE,OAAO;AAAA,UACL,QAAQC,OAAAA,cAAc,IAAI;AAAA,UAC1B,GAAG;AAAA,QAAA;AAAA,QAEL,MAAK;AAAA,QACL,cAAY;AAAA,QACZ,aAAU;AAAA,QACT,GAAG;AAAA,QAEH,UAAA,MAAM,KAAK,EAAE,QAAQ,SAAA,CAAU,EAAE,IAAI,CAAC,GAAG,UAAU;AAClD,gBAAM,QAAQ,WAAY,WAAW,QAAQ,KAAK,WAAY,MAAO,QAAQ,WAAY;AAEzF,iBACEF,2BAAAA;AAAAA,YAAC;AAAA,YAAA;AAAA,cAEC,WAAU;AAAA,cACV,OAAO;AAAA,gBACL,OAAO,GAAG,QAAQ;AAAA,gBAClB,QAAQ;AAAA,gBACR,iBAAiB;AAAA,gBACjB,WAAW,cAAc,iBAAiB;AAAA,gBAC1C,gBAAgB,GAAG,KAAK;AAAA,gBACxB,iBAAiB;AAAA,cAAA;AAAA,YACnB;AAAA,YATK;AAAA,UAAA;AAAA,QAYX,CAAC;AAAA,MAAA;AAAA,IAAA;AAAA,EAGP;AACF;AAEA,UAAU,cAAc;;"}
package/dist/index26.js CHANGED
@@ -1,13 +1,16 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { forwardRef } from "react";
3
- import { normalizeSize, getAnimationDuration, parseSizeToNumber } from "./index4.js";
3
+ import { useReducedMotion, getEffectiveDuration } from "./index31.js";
4
+ import { normalizeSize, parseSizeToNumber } from "./index4.js";
4
5
  import { cn } from "./index3.js";
5
6
  const PulseWave = forwardRef(
6
7
  ({
7
- size = 40,
8
+ size = "md",
8
9
  color = "#3b82f6",
9
10
  barCount = 5,
10
11
  speed = "normal",
12
+ reverse = false,
13
+ respectMotionPreference = true,
11
14
  className,
12
15
  style,
13
16
  testId = "pulse-wave",
@@ -16,9 +19,10 @@ const PulseWave = forwardRef(
16
19
  ...rest
17
20
  }, ref) => {
18
21
  if (!visible) return null;
22
+ const prefersReducedMotion = useReducedMotion();
23
+ const effectiveDuration = getEffectiveDuration(speed, respectMotionPreference, prefersReducedMotion);
19
24
  const sizeValue = parseSizeToNumber(size, 40);
20
25
  const barWidth = Math.floor(sizeValue / (barCount * 2.5));
21
- const animationDuration = getAnimationDuration(speed);
22
26
  return /* @__PURE__ */ jsx(
23
27
  "div",
24
28
  {
@@ -34,7 +38,7 @@ const PulseWave = forwardRef(
34
38
  "aria-busy": "true",
35
39
  ...rest,
36
40
  children: Array.from({ length: barCount }).map((_, index) => {
37
- const delay = index / barCount * 0.5;
41
+ const delay = reverse ? (barCount - index - 1) / barCount * 0.5 : index / barCount * 0.5;
38
42
  return /* @__PURE__ */ jsx(
39
43
  "div",
40
44
  {
@@ -43,7 +47,7 @@ const PulseWave = forwardRef(
43
47
  width: `${barWidth}px`,
44
48
  height: "100%",
45
49
  backgroundColor: color,
46
- animation: `pulse-wave ${animationDuration} ease-in-out infinite`,
50
+ animation: `pulse-wave ${effectiveDuration} ease-in-out infinite`,
47
51
  animationDelay: `${delay}s`,
48
52
  transformOrigin: "bottom"
49
53
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index26.js","sources":["../src/components/pulse/PulseWave.tsx"],"sourcesContent":["import { forwardRef } from 'react';\nimport { PulseWaveProps } from '../../types';\nimport { cn, normalizeSize, getAnimationDuration, parseSizeToNumber } from '../../utils';\n\n/**\n * PulseWave - Wave pattern loader\n *\n * A loader with bars that animate in a wave pattern.\n *\n * @example\n * ```tsx\n * <PulseWave size={40} color=\"#3b82f6\" />\n * <PulseWave size={32} barCount={7} speed=\"slow\" />\n * ```\n */\nexport const PulseWave = forwardRef<HTMLDivElement, PulseWaveProps>(\n (\n {\n size = 40,\n color = '#3b82f6',\n barCount = 5,\n speed = 'normal',\n className,\n style,\n testId = 'pulse-wave',\n visible = true,\n ariaLabel = 'Loading...',\n ...rest\n },\n ref\n ) => {\n if (!visible) return null;\n\n const sizeValue = parseSizeToNumber(size, 40);\n const barWidth = Math.floor(sizeValue / (barCount * 2.5));\n const animationDuration = getAnimationDuration(speed);\n\n return (\n <div\n ref={ref}\n data-testid={testId}\n className={cn('inline-flex items-end justify-center gap-1', className)}\n style={{\n height: normalizeSize(size),\n ...style,\n }}\n role=\"status\"\n aria-label={ariaLabel}\n aria-busy=\"true\"\n {...rest}\n >\n {Array.from({ length: barCount }).map((_, index) => {\n const delay = (index / barCount) * 0.5;\n\n return (\n <div\n key={index}\n className=\"rounded-sm\"\n style={{\n width: `${barWidth}px`,\n height: '100%',\n backgroundColor: color,\n animation: `pulse-wave ${animationDuration} ease-in-out infinite`,\n animationDelay: `${delay}s`,\n transformOrigin: 'bottom',\n }}\n />\n );\n })}\n </div>\n );\n }\n);\n\nPulseWave.displayName = 'PulseWave';\n"],"names":[],"mappings":";;;;AAeO,MAAM,YAAY;AAAA,EACvB,CACE;AAAA,IACE,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,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,YAAY,kBAAkB,MAAM,EAAE;AAC5C,UAAM,WAAW,KAAK,MAAM,aAAa,WAAW,IAAI;AACxD,UAAM,oBAAoB,qBAAqB,KAAK;AAEpD,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAa;AAAA,QACb,WAAW,GAAG,8CAA8C,SAAS;AAAA,QACrE,OAAO;AAAA,UACL,QAAQ,cAAc,IAAI;AAAA,UAC1B,GAAG;AAAA,QAAA;AAAA,QAEL,MAAK;AAAA,QACL,cAAY;AAAA,QACZ,aAAU;AAAA,QACT,GAAG;AAAA,QAEH,UAAA,MAAM,KAAK,EAAE,QAAQ,SAAA,CAAU,EAAE,IAAI,CAAC,GAAG,UAAU;AAClD,gBAAM,QAAS,QAAQ,WAAY;AAEnC,iBACE;AAAA,YAAC;AAAA,YAAA;AAAA,cAEC,WAAU;AAAA,cACV,OAAO;AAAA,gBACL,OAAO,GAAG,QAAQ;AAAA,gBAClB,QAAQ;AAAA,gBACR,iBAAiB;AAAA,gBACjB,WAAW,cAAc,iBAAiB;AAAA,gBAC1C,gBAAgB,GAAG,KAAK;AAAA,gBACxB,iBAAiB;AAAA,cAAA;AAAA,YACnB;AAAA,YATK;AAAA,UAAA;AAAA,QAYX,CAAC;AAAA,MAAA;AAAA,IAAA;AAAA,EAGP;AACF;AAEA,UAAU,cAAc;"}
1
+ {"version":3,"file":"index26.js","sources":["../src/components/pulse/PulseWave.tsx"],"sourcesContent":["import { forwardRef } from 'react';\nimport { PulseWaveProps } from '../../types';\nimport { cn, normalizeSize, parseSizeToNumber, useReducedMotion, getEffectiveDuration } from '../../utils';\n\n/**\n * PulseWave - Wave pattern loader\n *\n * A loader with bars that animate in a wave pattern.\n *\n * @example\n * ```tsx\n * <PulseWave size=\"lg\" color=\"#3b82f6\" />\n * <PulseWave size=\"sm\" barCount={7} speed=\"slow\" reverse />\n * ```\n */\nexport const PulseWave = forwardRef<HTMLDivElement, PulseWaveProps>(\n (\n {\n size = 'md',\n color = '#3b82f6',\n barCount = 5,\n speed = 'normal',\n reverse = false,\n respectMotionPreference = true,\n className,\n style,\n testId = 'pulse-wave',\n visible = true,\n ariaLabel = 'Loading...',\n ...rest\n },\n ref\n ) => {\n if (!visible) return null;\n\n const prefersReducedMotion = useReducedMotion();\n const effectiveDuration = getEffectiveDuration(speed, respectMotionPreference, prefersReducedMotion);\n\n const sizeValue = parseSizeToNumber(size, 40);\n const barWidth = Math.floor(sizeValue / (barCount * 2.5));\n\n return (\n <div\n ref={ref}\n data-testid={testId}\n className={cn('inline-flex items-end justify-center gap-1', className)}\n style={{\n height: normalizeSize(size),\n ...style,\n }}\n role=\"status\"\n aria-label={ariaLabel}\n aria-busy=\"true\"\n {...rest}\n >\n {Array.from({ length: barCount }).map((_, index) => {\n const delay = reverse ? ((barCount - index - 1) / barCount) * 0.5 : (index / barCount) * 0.5;\n\n return (\n <div\n key={index}\n className=\"rounded-sm\"\n style={{\n width: `${barWidth}px`,\n height: '100%',\n backgroundColor: color,\n animation: `pulse-wave ${effectiveDuration} ease-in-out infinite`,\n animationDelay: `${delay}s`,\n transformOrigin: 'bottom',\n }}\n />\n );\n })}\n </div>\n );\n }\n);\n\nPulseWave.displayName = 'PulseWave';\n"],"names":[],"mappings":";;;;;AAeO,MAAM,YAAY;AAAA,EACvB,CACE;AAAA,IACE,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,0BAA0B;AAAA,IAC1B;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,uBAAuB,iBAAA;AAC7B,UAAM,oBAAoB,qBAAqB,OAAO,yBAAyB,oBAAoB;AAEnG,UAAM,YAAY,kBAAkB,MAAM,EAAE;AAC5C,UAAM,WAAW,KAAK,MAAM,aAAa,WAAW,IAAI;AAExD,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAa;AAAA,QACb,WAAW,GAAG,8CAA8C,SAAS;AAAA,QACrE,OAAO;AAAA,UACL,QAAQ,cAAc,IAAI;AAAA,UAC1B,GAAG;AAAA,QAAA;AAAA,QAEL,MAAK;AAAA,QACL,cAAY;AAAA,QACZ,aAAU;AAAA,QACT,GAAG;AAAA,QAEH,UAAA,MAAM,KAAK,EAAE,QAAQ,SAAA,CAAU,EAAE,IAAI,CAAC,GAAG,UAAU;AAClD,gBAAM,QAAQ,WAAY,WAAW,QAAQ,KAAK,WAAY,MAAO,QAAQ,WAAY;AAEzF,iBACE;AAAA,YAAC;AAAA,YAAA;AAAA,cAEC,WAAU;AAAA,cACV,OAAO;AAAA,gBACL,OAAO,GAAG,QAAQ;AAAA,gBAClB,QAAQ;AAAA,gBACR,iBAAiB;AAAA,gBACjB,WAAW,cAAc,iBAAiB;AAAA,gBAC1C,gBAAgB,GAAG,KAAK;AAAA,gBACxB,iBAAiB;AAAA,cAAA;AAAA,YACnB;AAAA,YATK;AAAA,UAAA;AAAA,QAYX,CAAC;AAAA,MAAA;AAAA,IAAA;AAAA,EAGP;AACF;AAEA,UAAU,cAAc;"}
package/dist/index27.cjs CHANGED
@@ -2,14 +2,17 @@
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 colors = require("./index4.cjs");
6
7
  const classNames = require("./index3.cjs");
7
8
  const PulseBars = react.forwardRef(
8
9
  ({
9
- size = 40,
10
+ size = "md",
10
11
  color = "#3b82f6",
11
12
  barCount = 4,
12
13
  speed = "normal",
14
+ reverse = false,
15
+ respectMotionPreference = true,
13
16
  className,
14
17
  style,
15
18
  testId = "pulse-bars",
@@ -18,9 +21,10 @@ const PulseBars = react.forwardRef(
18
21
  ...rest
19
22
  }, ref) => {
20
23
  if (!visible) return null;
24
+ const prefersReducedMotion = hooks.useReducedMotion();
25
+ const effectiveDuration = hooks.getEffectiveDuration(speed, respectMotionPreference, prefersReducedMotion);
21
26
  const sizeValue = colors.parseSizeToNumber(size, 40);
22
27
  const barWidth = Math.floor(sizeValue / (barCount * 2));
23
- const animationDuration = colors.getAnimationDuration(speed);
24
28
  return /* @__PURE__ */ jsxRuntime.jsx(
25
29
  "div",
26
30
  {
@@ -37,7 +41,8 @@ const PulseBars = react.forwardRef(
37
41
  ...rest,
38
42
  children: Array.from({ length: barCount }).map((_, index) => {
39
43
  const delays = [0, 0.2, 0.4, 0.1, 0.3, 0.5];
40
- const delay = delays[index % delays.length];
44
+ const reversedDelays = [...delays].reverse();
45
+ const delay = reverse ? reversedDelays[index % reversedDelays.length] : delays[index % delays.length];
41
46
  return /* @__PURE__ */ jsxRuntime.jsx(
42
47
  "div",
43
48
  {
@@ -47,7 +52,7 @@ const PulseBars = react.forwardRef(
47
52
  minHeight: "30%",
48
53
  height: "100%",
49
54
  backgroundColor: color,
50
- animation: `pulse-wave ${animationDuration} ease-in-out infinite`,
55
+ animation: `pulse-wave ${effectiveDuration} ease-in-out infinite`,
51
56
  animationDelay: `${delay}s`,
52
57
  transformOrigin: "center"
53
58
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index27.cjs","sources":["../src/components/pulse/PulseBars.tsx"],"sourcesContent":["import { forwardRef } from 'react';\nimport { PulseBarsProps } from '../../types';\nimport { cn, normalizeSize, getAnimationDuration, parseSizeToNumber } from '../../utils';\n\n/**\n * PulseBars - Equalizer-style bars loader\n *\n * A loader with bars that pulse like an audio equalizer.\n *\n * @example\n * ```tsx\n * <PulseBars size={40} color=\"#3b82f6\" />\n * <PulseBars size={48} barCount={6} speed=\"fast\" />\n * ```\n */\nexport const PulseBars = forwardRef<HTMLDivElement, PulseBarsProps>(\n (\n {\n size = 40,\n color = '#3b82f6',\n barCount = 4,\n speed = 'normal',\n className,\n style,\n testId = 'pulse-bars',\n visible = true,\n ariaLabel = 'Loading...',\n ...rest\n },\n ref\n ) => {\n if (!visible) return null;\n\n const sizeValue = parseSizeToNumber(size, 40);\n const barWidth = Math.floor(sizeValue / (barCount * 2));\n const animationDuration = getAnimationDuration(speed);\n\n return (\n <div\n ref={ref}\n data-testid={testId}\n className={cn('inline-flex items-center justify-center gap-1', className)}\n style={{\n height: normalizeSize(size),\n ...style,\n }}\n role=\"status\"\n aria-label={ariaLabel}\n aria-busy=\"true\"\n {...rest}\n >\n {Array.from({ length: barCount }).map((_, index) => {\n // Random-looking delays for equalizer effect\n const delays = [0, 0.2, 0.4, 0.1, 0.3, 0.5];\n const delay = delays[index % delays.length];\n\n return (\n <div\n key={index}\n className=\"rounded-sm\"\n style={{\n width: `${barWidth}px`,\n minHeight: '30%',\n height: '100%',\n backgroundColor: color,\n animation: `pulse-wave ${animationDuration} ease-in-out infinite`,\n animationDelay: `${delay}s`,\n transformOrigin: 'center',\n }}\n />\n );\n })}\n </div>\n );\n }\n);\n\nPulseBars.displayName = 'PulseBars';\n"],"names":["forwardRef","parseSizeToNumber","getAnimationDuration","jsx","cn","normalizeSize"],"mappings":";;;;;;AAeO,MAAM,YAAYA,MAAAA;AAAAA,EACvB,CACE;AAAA,IACE,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,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,YAAYC,OAAAA,kBAAkB,MAAM,EAAE;AAC5C,UAAM,WAAW,KAAK,MAAM,aAAa,WAAW,EAAE;AACtD,UAAM,oBAAoBC,OAAAA,qBAAqB,KAAK;AAEpD,WACEC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAa;AAAA,QACb,WAAWC,WAAAA,GAAG,iDAAiD,SAAS;AAAA,QACxE,OAAO;AAAA,UACL,QAAQC,OAAAA,cAAc,IAAI;AAAA,UAC1B,GAAG;AAAA,QAAA;AAAA,QAEL,MAAK;AAAA,QACL,cAAY;AAAA,QACZ,aAAU;AAAA,QACT,GAAG;AAAA,QAEH,UAAA,MAAM,KAAK,EAAE,QAAQ,SAAA,CAAU,EAAE,IAAI,CAAC,GAAG,UAAU;AAElD,gBAAM,SAAS,CAAC,GAAG,KAAK,KAAK,KAAK,KAAK,GAAG;AAC1C,gBAAM,QAAQ,OAAO,QAAQ,OAAO,MAAM;AAE1C,iBACEF,2BAAAA;AAAAA,YAAC;AAAA,YAAA;AAAA,cAEC,WAAU;AAAA,cACV,OAAO;AAAA,gBACL,OAAO,GAAG,QAAQ;AAAA,gBAClB,WAAW;AAAA,gBACX,QAAQ;AAAA,gBACR,iBAAiB;AAAA,gBACjB,WAAW,cAAc,iBAAiB;AAAA,gBAC1C,gBAAgB,GAAG,KAAK;AAAA,gBACxB,iBAAiB;AAAA,cAAA;AAAA,YACnB;AAAA,YAVK;AAAA,UAAA;AAAA,QAaX,CAAC;AAAA,MAAA;AAAA,IAAA;AAAA,EAGP;AACF;AAEA,UAAU,cAAc;;"}
1
+ {"version":3,"file":"index27.cjs","sources":["../src/components/pulse/PulseBars.tsx"],"sourcesContent":["import { forwardRef } from 'react';\nimport { PulseBarsProps } from '../../types';\nimport { cn, normalizeSize, parseSizeToNumber, useReducedMotion, getEffectiveDuration } from '../../utils';\n\n/**\n * PulseBars - Equalizer-style bars loader\n *\n * A loader with bars that pulse like an audio equalizer.\n *\n * @example\n * ```tsx\n * <PulseBars size=\"lg\" color=\"#3b82f6\" />\n * <PulseBars size=\"md\" barCount={6} speed=\"fast\" reverse />\n * ```\n */\nexport const PulseBars = forwardRef<HTMLDivElement, PulseBarsProps>(\n (\n {\n size = 'md',\n color = '#3b82f6',\n barCount = 4,\n speed = 'normal',\n reverse = false,\n respectMotionPreference = true,\n className,\n style,\n testId = 'pulse-bars',\n visible = true,\n ariaLabel = 'Loading...',\n ...rest\n },\n ref\n ) => {\n if (!visible) return null;\n\n const prefersReducedMotion = useReducedMotion();\n const effectiveDuration = getEffectiveDuration(speed, respectMotionPreference, prefersReducedMotion);\n\n const sizeValue = parseSizeToNumber(size, 40);\n const barWidth = Math.floor(sizeValue / (barCount * 2));\n\n return (\n <div\n ref={ref}\n data-testid={testId}\n className={cn('inline-flex items-center justify-center gap-1', className)}\n style={{\n height: normalizeSize(size),\n ...style,\n }}\n role=\"status\"\n aria-label={ariaLabel}\n aria-busy=\"true\"\n {...rest}\n >\n {Array.from({ length: barCount }).map((_, index) => {\n // Random-looking delays for equalizer effect\n const delays = [0, 0.2, 0.4, 0.1, 0.3, 0.5];\n const reversedDelays = [...delays].reverse();\n const delay = reverse ? reversedDelays[index % reversedDelays.length] : delays[index % delays.length];\n\n return (\n <div\n key={index}\n className=\"rounded-sm\"\n style={{\n width: `${barWidth}px`,\n minHeight: '30%',\n height: '100%',\n backgroundColor: color,\n animation: `pulse-wave ${effectiveDuration} ease-in-out infinite`,\n animationDelay: `${delay}s`,\n transformOrigin: 'center',\n }}\n />\n );\n })}\n </div>\n );\n }\n);\n\nPulseBars.displayName = 'PulseBars';\n"],"names":["forwardRef","useReducedMotion","getEffectiveDuration","parseSizeToNumber","jsx","cn","normalizeSize"],"mappings":";;;;;;;AAeO,MAAM,YAAYA,MAAAA;AAAAA,EACvB,CACE;AAAA,IACE,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,0BAA0B;AAAA,IAC1B;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,uBAAuBC,MAAAA,iBAAA;AAC7B,UAAM,oBAAoBC,MAAAA,qBAAqB,OAAO,yBAAyB,oBAAoB;AAEnG,UAAM,YAAYC,OAAAA,kBAAkB,MAAM,EAAE;AAC5C,UAAM,WAAW,KAAK,MAAM,aAAa,WAAW,EAAE;AAEtD,WACEC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAa;AAAA,QACb,WAAWC,WAAAA,GAAG,iDAAiD,SAAS;AAAA,QACxE,OAAO;AAAA,UACL,QAAQC,OAAAA,cAAc,IAAI;AAAA,UAC1B,GAAG;AAAA,QAAA;AAAA,QAEL,MAAK;AAAA,QACL,cAAY;AAAA,QACZ,aAAU;AAAA,QACT,GAAG;AAAA,QAEH,UAAA,MAAM,KAAK,EAAE,QAAQ,SAAA,CAAU,EAAE,IAAI,CAAC,GAAG,UAAU;AAElD,gBAAM,SAAS,CAAC,GAAG,KAAK,KAAK,KAAK,KAAK,GAAG;AAC1C,gBAAM,iBAAiB,CAAC,GAAG,MAAM,EAAE,QAAA;AACnC,gBAAM,QAAQ,UAAU,eAAe,QAAQ,eAAe,MAAM,IAAI,OAAO,QAAQ,OAAO,MAAM;AAEpG,iBACEF,2BAAAA;AAAAA,YAAC;AAAA,YAAA;AAAA,cAEC,WAAU;AAAA,cACV,OAAO;AAAA,gBACL,OAAO,GAAG,QAAQ;AAAA,gBAClB,WAAW;AAAA,gBACX,QAAQ;AAAA,gBACR,iBAAiB;AAAA,gBACjB,WAAW,cAAc,iBAAiB;AAAA,gBAC1C,gBAAgB,GAAG,KAAK;AAAA,gBACxB,iBAAiB;AAAA,cAAA;AAAA,YACnB;AAAA,YAVK;AAAA,UAAA;AAAA,QAaX,CAAC;AAAA,MAAA;AAAA,IAAA;AAAA,EAGP;AACF;AAEA,UAAU,cAAc;;"}
package/dist/index27.js CHANGED
@@ -1,13 +1,16 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { forwardRef } from "react";
3
- import { normalizeSize, getAnimationDuration, parseSizeToNumber } from "./index4.js";
3
+ import { useReducedMotion, getEffectiveDuration } from "./index31.js";
4
+ import { normalizeSize, parseSizeToNumber } from "./index4.js";
4
5
  import { cn } from "./index3.js";
5
6
  const PulseBars = forwardRef(
6
7
  ({
7
- size = 40,
8
+ size = "md",
8
9
  color = "#3b82f6",
9
10
  barCount = 4,
10
11
  speed = "normal",
12
+ reverse = false,
13
+ respectMotionPreference = true,
11
14
  className,
12
15
  style,
13
16
  testId = "pulse-bars",
@@ -16,9 +19,10 @@ const PulseBars = forwardRef(
16
19
  ...rest
17
20
  }, ref) => {
18
21
  if (!visible) return null;
22
+ const prefersReducedMotion = useReducedMotion();
23
+ const effectiveDuration = getEffectiveDuration(speed, respectMotionPreference, prefersReducedMotion);
19
24
  const sizeValue = parseSizeToNumber(size, 40);
20
25
  const barWidth = Math.floor(sizeValue / (barCount * 2));
21
- const animationDuration = getAnimationDuration(speed);
22
26
  return /* @__PURE__ */ jsx(
23
27
  "div",
24
28
  {
@@ -35,7 +39,8 @@ const PulseBars = forwardRef(
35
39
  ...rest,
36
40
  children: Array.from({ length: barCount }).map((_, index) => {
37
41
  const delays = [0, 0.2, 0.4, 0.1, 0.3, 0.5];
38
- const delay = delays[index % delays.length];
42
+ const reversedDelays = [...delays].reverse();
43
+ const delay = reverse ? reversedDelays[index % reversedDelays.length] : delays[index % delays.length];
39
44
  return /* @__PURE__ */ jsx(
40
45
  "div",
41
46
  {
@@ -45,7 +50,7 @@ const PulseBars = forwardRef(
45
50
  minHeight: "30%",
46
51
  height: "100%",
47
52
  backgroundColor: color,
48
- animation: `pulse-wave ${animationDuration} ease-in-out infinite`,
53
+ animation: `pulse-wave ${effectiveDuration} ease-in-out infinite`,
49
54
  animationDelay: `${delay}s`,
50
55
  transformOrigin: "center"
51
56
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index27.js","sources":["../src/components/pulse/PulseBars.tsx"],"sourcesContent":["import { forwardRef } from 'react';\nimport { PulseBarsProps } from '../../types';\nimport { cn, normalizeSize, getAnimationDuration, parseSizeToNumber } from '../../utils';\n\n/**\n * PulseBars - Equalizer-style bars loader\n *\n * A loader with bars that pulse like an audio equalizer.\n *\n * @example\n * ```tsx\n * <PulseBars size={40} color=\"#3b82f6\" />\n * <PulseBars size={48} barCount={6} speed=\"fast\" />\n * ```\n */\nexport const PulseBars = forwardRef<HTMLDivElement, PulseBarsProps>(\n (\n {\n size = 40,\n color = '#3b82f6',\n barCount = 4,\n speed = 'normal',\n className,\n style,\n testId = 'pulse-bars',\n visible = true,\n ariaLabel = 'Loading...',\n ...rest\n },\n ref\n ) => {\n if (!visible) return null;\n\n const sizeValue = parseSizeToNumber(size, 40);\n const barWidth = Math.floor(sizeValue / (barCount * 2));\n const animationDuration = getAnimationDuration(speed);\n\n return (\n <div\n ref={ref}\n data-testid={testId}\n className={cn('inline-flex items-center justify-center gap-1', className)}\n style={{\n height: normalizeSize(size),\n ...style,\n }}\n role=\"status\"\n aria-label={ariaLabel}\n aria-busy=\"true\"\n {...rest}\n >\n {Array.from({ length: barCount }).map((_, index) => {\n // Random-looking delays for equalizer effect\n const delays = [0, 0.2, 0.4, 0.1, 0.3, 0.5];\n const delay = delays[index % delays.length];\n\n return (\n <div\n key={index}\n className=\"rounded-sm\"\n style={{\n width: `${barWidth}px`,\n minHeight: '30%',\n height: '100%',\n backgroundColor: color,\n animation: `pulse-wave ${animationDuration} ease-in-out infinite`,\n animationDelay: `${delay}s`,\n transformOrigin: 'center',\n }}\n />\n );\n })}\n </div>\n );\n }\n);\n\nPulseBars.displayName = 'PulseBars';\n"],"names":[],"mappings":";;;;AAeO,MAAM,YAAY;AAAA,EACvB,CACE;AAAA,IACE,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,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,YAAY,kBAAkB,MAAM,EAAE;AAC5C,UAAM,WAAW,KAAK,MAAM,aAAa,WAAW,EAAE;AACtD,UAAM,oBAAoB,qBAAqB,KAAK;AAEpD,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAa;AAAA,QACb,WAAW,GAAG,iDAAiD,SAAS;AAAA,QACxE,OAAO;AAAA,UACL,QAAQ,cAAc,IAAI;AAAA,UAC1B,GAAG;AAAA,QAAA;AAAA,QAEL,MAAK;AAAA,QACL,cAAY;AAAA,QACZ,aAAU;AAAA,QACT,GAAG;AAAA,QAEH,UAAA,MAAM,KAAK,EAAE,QAAQ,SAAA,CAAU,EAAE,IAAI,CAAC,GAAG,UAAU;AAElD,gBAAM,SAAS,CAAC,GAAG,KAAK,KAAK,KAAK,KAAK,GAAG;AAC1C,gBAAM,QAAQ,OAAO,QAAQ,OAAO,MAAM;AAE1C,iBACE;AAAA,YAAC;AAAA,YAAA;AAAA,cAEC,WAAU;AAAA,cACV,OAAO;AAAA,gBACL,OAAO,GAAG,QAAQ;AAAA,gBAClB,WAAW;AAAA,gBACX,QAAQ;AAAA,gBACR,iBAAiB;AAAA,gBACjB,WAAW,cAAc,iBAAiB;AAAA,gBAC1C,gBAAgB,GAAG,KAAK;AAAA,gBACxB,iBAAiB;AAAA,cAAA;AAAA,YACnB;AAAA,YAVK;AAAA,UAAA;AAAA,QAaX,CAAC;AAAA,MAAA;AAAA,IAAA;AAAA,EAGP;AACF;AAEA,UAAU,cAAc;"}
1
+ {"version":3,"file":"index27.js","sources":["../src/components/pulse/PulseBars.tsx"],"sourcesContent":["import { forwardRef } from 'react';\nimport { PulseBarsProps } from '../../types';\nimport { cn, normalizeSize, parseSizeToNumber, useReducedMotion, getEffectiveDuration } from '../../utils';\n\n/**\n * PulseBars - Equalizer-style bars loader\n *\n * A loader with bars that pulse like an audio equalizer.\n *\n * @example\n * ```tsx\n * <PulseBars size=\"lg\" color=\"#3b82f6\" />\n * <PulseBars size=\"md\" barCount={6} speed=\"fast\" reverse />\n * ```\n */\nexport const PulseBars = forwardRef<HTMLDivElement, PulseBarsProps>(\n (\n {\n size = 'md',\n color = '#3b82f6',\n barCount = 4,\n speed = 'normal',\n reverse = false,\n respectMotionPreference = true,\n className,\n style,\n testId = 'pulse-bars',\n visible = true,\n ariaLabel = 'Loading...',\n ...rest\n },\n ref\n ) => {\n if (!visible) return null;\n\n const prefersReducedMotion = useReducedMotion();\n const effectiveDuration = getEffectiveDuration(speed, respectMotionPreference, prefersReducedMotion);\n\n const sizeValue = parseSizeToNumber(size, 40);\n const barWidth = Math.floor(sizeValue / (barCount * 2));\n\n return (\n <div\n ref={ref}\n data-testid={testId}\n className={cn('inline-flex items-center justify-center gap-1', className)}\n style={{\n height: normalizeSize(size),\n ...style,\n }}\n role=\"status\"\n aria-label={ariaLabel}\n aria-busy=\"true\"\n {...rest}\n >\n {Array.from({ length: barCount }).map((_, index) => {\n // Random-looking delays for equalizer effect\n const delays = [0, 0.2, 0.4, 0.1, 0.3, 0.5];\n const reversedDelays = [...delays].reverse();\n const delay = reverse ? reversedDelays[index % reversedDelays.length] : delays[index % delays.length];\n\n return (\n <div\n key={index}\n className=\"rounded-sm\"\n style={{\n width: `${barWidth}px`,\n minHeight: '30%',\n height: '100%',\n backgroundColor: color,\n animation: `pulse-wave ${effectiveDuration} ease-in-out infinite`,\n animationDelay: `${delay}s`,\n transformOrigin: 'center',\n }}\n />\n );\n })}\n </div>\n );\n }\n);\n\nPulseBars.displayName = 'PulseBars';\n"],"names":[],"mappings":";;;;;AAeO,MAAM,YAAY;AAAA,EACvB,CACE;AAAA,IACE,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,0BAA0B;AAAA,IAC1B;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,uBAAuB,iBAAA;AAC7B,UAAM,oBAAoB,qBAAqB,OAAO,yBAAyB,oBAAoB;AAEnG,UAAM,YAAY,kBAAkB,MAAM,EAAE;AAC5C,UAAM,WAAW,KAAK,MAAM,aAAa,WAAW,EAAE;AAEtD,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAa;AAAA,QACb,WAAW,GAAG,iDAAiD,SAAS;AAAA,QACxE,OAAO;AAAA,UACL,QAAQ,cAAc,IAAI;AAAA,UAC1B,GAAG;AAAA,QAAA;AAAA,QAEL,MAAK;AAAA,QACL,cAAY;AAAA,QACZ,aAAU;AAAA,QACT,GAAG;AAAA,QAEH,UAAA,MAAM,KAAK,EAAE,QAAQ,SAAA,CAAU,EAAE,IAAI,CAAC,GAAG,UAAU;AAElD,gBAAM,SAAS,CAAC,GAAG,KAAK,KAAK,KAAK,KAAK,GAAG;AAC1C,gBAAM,iBAAiB,CAAC,GAAG,MAAM,EAAE,QAAA;AACnC,gBAAM,QAAQ,UAAU,eAAe,QAAQ,eAAe,MAAM,IAAI,OAAO,QAAQ,OAAO,MAAM;AAEpG,iBACE;AAAA,YAAC;AAAA,YAAA;AAAA,cAEC,WAAU;AAAA,cACV,OAAO;AAAA,gBACL,OAAO,GAAG,QAAQ;AAAA,gBAClB,WAAW;AAAA,gBACX,QAAQ;AAAA,gBACR,iBAAiB;AAAA,gBACjB,WAAW,cAAc,iBAAiB;AAAA,gBAC1C,gBAAgB,GAAG,KAAK;AAAA,gBACxB,iBAAiB;AAAA,cAAA;AAAA,YACnB;AAAA,YAVK;AAAA,UAAA;AAAA,QAaX,CAAC;AAAA,MAAA;AAAA,IAAA;AAAA,EAGP;AACF;AAEA,UAAU,cAAc;"}
package/dist/index28.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 colors = require("./index4.cjs");
6
7
  const classNames = require("./index3.cjs");
7
8
  const TypingIndicator = react.forwardRef(
@@ -13,6 +14,8 @@ const TypingIndicator = react.forwardRef(
13
14
  gap = 4,
14
15
  variant = "bounce",
15
16
  speed = "normal",
17
+ reverse = false,
18
+ respectMotionPreference = true,
16
19
  className,
17
20
  style,
18
21
  testId = "typing-indicator",
@@ -21,7 +24,8 @@ const TypingIndicator = react.forwardRef(
21
24
  ...rest
22
25
  }, ref) => {
23
26
  if (!visible) return null;
24
- const animationDuration = colors.getAnimationDuration(speed);
27
+ const prefersReducedMotion = hooks.useReducedMotion();
28
+ const effectiveDuration = hooks.getEffectiveDuration(speed, respectMotionPreference, prefersReducedMotion);
25
29
  const gapValue = colors.normalizeSize(gap);
26
30
  return /* @__PURE__ */ jsxRuntime.jsx(
27
31
  "div",
@@ -46,8 +50,8 @@ const TypingIndicator = react.forwardRef(
46
50
  width: colors.normalizeSize(dotSize),
47
51
  height: colors.normalizeSize(dotSize),
48
52
  backgroundColor: color,
49
- animation: `typing-${variant} ${animationDuration} ease-in-out infinite`,
50
- animationDelay: `${index * 0.2}s`
53
+ animation: `typing-${variant} ${effectiveDuration} ease-in-out infinite`,
54
+ animationDelay: reverse ? `${(dotCount - index - 1) * 0.2}s` : `${index * 0.2}s`
51
55
  }
52
56
  },
53
57
  index
@@ -1 +1 @@
1
- {"version":3,"file":"index28.cjs","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":["forwardRef","getAnimationDuration","normalizeSize","jsx","cn"],"mappings":";;;;;;AAiBO,MAAM,kBAAkBA,MAAAA;AAAAA,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,oBAAoBC,OAAAA,qBAAqB,KAAK;AACpD,UAAM,WAAWC,OAAAA,cAAc,GAAG;AAElC,WACEC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAa;AAAA,QACb,WAAWC,WAAAA,GAAG,4BAA4B,SAAS;AAAA,QACnD,OAAO;AAAA,UACL,KAAK;AAAA,UACL,QAAQ,OAAOF,qBAAc,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,UACxCC,2BAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YAEC,WAAU;AAAA,YACV,OAAO;AAAA,cACL,OAAOD,OAAAA,cAAc,OAAO;AAAA,cAC5B,QAAQA,OAAAA,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.cjs","sources":["../src/components/pulse/TypingIndicator.tsx"],"sourcesContent":["import { forwardRef } from 'react';\nimport { TypingIndicatorProps } from '../../types';\nimport { cn, normalizeSize, useReducedMotion, getEffectiveDuration } 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 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 prefersReducedMotion = useReducedMotion();\n const effectiveDuration = getEffectiveDuration(speed, respectMotionPreference, prefersReducedMotion);\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} ${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":["forwardRef","useReducedMotion","getEffectiveDuration","normalizeSize","jsx","cn"],"mappings":";;;;;;;AAiBO,MAAM,kBAAkBA,MAAAA;AAAAA,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;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,uBAAuBC,MAAAA,iBAAA;AAC7B,UAAM,oBAAoBC,MAAAA,qBAAqB,OAAO,yBAAyB,oBAAoB;AACnG,UAAM,WAAWC,OAAAA,cAAc,GAAG;AAElC,WACEC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAa;AAAA,QACb,WAAWC,WAAAA,GAAG,4BAA4B,SAAS;AAAA,QACnD,OAAO;AAAA,UACL,KAAK;AAAA,UACL,QAAQ,OAAOF,qBAAc,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,UACxCC,2BAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YAEC,WAAU;AAAA,YACV,OAAO;AAAA,cACL,OAAOD,OAAAA,cAAc,OAAO;AAAA,cAC5B,QAAQA,OAAAA,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/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, 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,8 @@ const TypingIndicator = forwardRef(
11
12
  gap = 4,
12
13
  variant = "bounce",
13
14
  speed = "normal",
15
+ reverse = false,
16
+ respectMotionPreference = true,
14
17
  className,
15
18
  style,
16
19
  testId = "typing-indicator",
@@ -19,7 +22,8 @@ const TypingIndicator = forwardRef(
19
22
  ...rest
20
23
  }, ref) => {
21
24
  if (!visible) return null;
22
- const animationDuration = getAnimationDuration(speed);
25
+ const prefersReducedMotion = useReducedMotion();
26
+ const effectiveDuration = getEffectiveDuration(speed, respectMotionPreference, prefersReducedMotion);
23
27
  const gapValue = normalizeSize(gap);
24
28
  return /* @__PURE__ */ jsx(
25
29
  "div",
@@ -44,8 +48,8 @@ const TypingIndicator = forwardRef(
44
48
  width: normalizeSize(dotSize),
45
49
  height: normalizeSize(dotSize),
46
50
  backgroundColor: color,
47
- animation: `typing-${variant} ${animationDuration} ease-in-out infinite`,
48
- animationDelay: `${index * 0.2}s`
51
+ animation: `typing-${variant} ${effectiveDuration} ease-in-out infinite`,
52
+ animationDelay: reverse ? `${(dotCount - index - 1) * 0.2}s` : `${index * 0.2}s`
49
53
  }
50
54
  },
51
55
  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 } 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 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 prefersReducedMotion = useReducedMotion();\n const effectiveDuration = getEffectiveDuration(speed, respectMotionPreference, prefersReducedMotion);\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} ${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;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,uBAAuB,iBAAA;AAC7B,UAAM,oBAAoB,qBAAqB,OAAO,yBAAyB,oBAAoB;AACnG,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,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;"}
@@ -0,0 +1,42 @@
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
+ exports.getEffectiveDuration = getEffectiveDuration;
41
+ exports.useReducedMotion = useReducedMotion;
42
+ //# sourceMappingURL=index31.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index31.cjs","sources":["../src/utils/hooks.ts"],"sourcesContent":["import { useEffect, useState } 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"],"names":["useState","useEffect"],"mappings":";;;AAMO,SAAS,mBAA4B;AAC1C,QAAM,CAAC,sBAAsB,uBAAuB,IAAIA,MAAAA,SAAS,KAAK;AAEtEC,QAAAA,UAAU,MAAM;AAEd,QAAI,OAAO,WAAW,eAAe,CAAC,OAAO,YAAY;AACvD;AAAA,IACF;AAEA,UAAM,aAAa,OAAO,WAAW,kCAAkC;AAGvE,4BAAwB,WAAW,OAAO;AAG1C,UAAM,eAAe,CAAC,UAA+B;AACnD,8BAAwB,MAAM,OAAO;AAAA,IACvC;AAGA,QAAI,WAAW,kBAAkB;AAC/B,iBAAW,iBAAiB,UAAU,YAAY;AAClD,aAAO,MAAM,WAAW,oBAAoB,UAAU,YAAY;AAAA,IACpE,OAAO;AAEL,iBAAW,YAAY,YAAY;AACnC,aAAO,MAAM,WAAW,eAAe,YAAY;AAAA,IACrD;AAAA,EACF,GAAG,CAAA,CAAE;AAEL,SAAO;AACT;AAKO,SAAS,qBACd,OACA,yBACA,sBACQ;AAER,MAAI,2BAA2B,sBAAsB;AACnD,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,UAAU,UAAU;AAC7B,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;;;"}
@@ -0,0 +1,42 @@
1
+ import { useState, 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
+ export {
39
+ getEffectiveDuration,
40
+ useReducedMotion
41
+ };
42
+ //# sourceMappingURL=index31.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index31.js","sources":["../src/utils/hooks.ts"],"sourcesContent":["import { useEffect, useState } 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"],"names":[],"mappings":";AAMO,SAAS,mBAA4B;AAC1C,QAAM,CAAC,sBAAsB,uBAAuB,IAAI,SAAS,KAAK;AAEtE,YAAU,MAAM;AAEd,QAAI,OAAO,WAAW,eAAe,CAAC,OAAO,YAAY;AACvD;AAAA,IACF;AAEA,UAAM,aAAa,OAAO,WAAW,kCAAkC;AAGvE,4BAAwB,WAAW,OAAO;AAG1C,UAAM,eAAe,CAAC,UAA+B;AACnD,8BAAwB,MAAM,OAAO;AAAA,IACvC;AAGA,QAAI,WAAW,kBAAkB;AAC/B,iBAAW,iBAAiB,UAAU,YAAY;AAClD,aAAO,MAAM,WAAW,oBAAoB,UAAU,YAAY;AAAA,IACpE,OAAO;AAEL,iBAAW,YAAY,YAAY;AACnC,aAAO,MAAM,WAAW,eAAe,YAAY;AAAA,IACrD;AAAA,EACF,GAAG,CAAA,CAAE;AAEL,SAAO;AACT;AAKO,SAAS,qBACd,OACA,yBACA,sBACQ;AAER,MAAI,2BAA2B,sBAAsB;AACnD,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,UAAU,UAAU;AAC7B,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;"}
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
  }