premium-react-loaders 1.2.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 (135) hide show
  1. package/dist/components/overlay/LoaderOverlay.d.ts.map +1 -1
  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/progress/ProgressSteps.d.ts.map +1 -1
  6. package/dist/components/pulse/PulseBars.d.ts.map +1 -1
  7. package/dist/components/pulse/PulseDots.d.ts.map +1 -1
  8. package/dist/components/pulse/PulseWave.d.ts.map +1 -1
  9. package/dist/components/pulse/TypingIndicator.d.ts.map +1 -1
  10. package/dist/components/skeleton/Skeleton.d.ts.map +1 -1
  11. package/dist/components/skeleton/SkeletonAvatar.d.ts.map +1 -1
  12. package/dist/components/skeleton/SkeletonCard.d.ts.map +1 -1
  13. package/dist/components/skeleton/SkeletonForm.d.ts.map +1 -1
  14. package/dist/components/skeleton/SkeletonImage.d.ts.map +1 -1
  15. package/dist/components/skeleton/SkeletonList.d.ts.map +1 -1
  16. package/dist/components/skeleton/SkeletonPage.d.ts.map +1 -1
  17. package/dist/components/skeleton/SkeletonTable.d.ts.map +1 -1
  18. package/dist/components/skeleton/SkeletonText.d.ts.map +1 -1
  19. package/dist/components/spinner/SpinnerBars.d.ts.map +1 -1
  20. package/dist/components/spinner/SpinnerCircle.d.ts.map +1 -1
  21. package/dist/components/spinner/SpinnerDots.d.ts.map +1 -1
  22. package/dist/components/spinner/SpinnerGrid.d.ts.map +1 -1
  23. package/dist/components/spinner/SpinnerPulse.d.ts.map +1 -1
  24. package/dist/components/spinner/SpinnerRing.d.ts.map +1 -1
  25. package/dist/components/spinner/SpinnerWave.d.ts.map +1 -1
  26. package/dist/index10.cjs +14 -2
  27. package/dist/index10.cjs.map +1 -1
  28. package/dist/index10.js +14 -2
  29. package/dist/index10.js.map +1 -1
  30. package/dist/index11.cjs +16 -2
  31. package/dist/index11.cjs.map +1 -1
  32. package/dist/index11.js +16 -2
  33. package/dist/index11.js.map +1 -1
  34. package/dist/index12.cjs +16 -2
  35. package/dist/index12.cjs.map +1 -1
  36. package/dist/index12.js +16 -2
  37. package/dist/index12.js.map +1 -1
  38. package/dist/index13.cjs +12 -2
  39. package/dist/index13.cjs.map +1 -1
  40. package/dist/index13.js +12 -2
  41. package/dist/index13.js.map +1 -1
  42. package/dist/index14.cjs +15 -2
  43. package/dist/index14.cjs.map +1 -1
  44. package/dist/index14.js +16 -3
  45. package/dist/index14.js.map +1 -1
  46. package/dist/index15.cjs +15 -2
  47. package/dist/index15.cjs.map +1 -1
  48. package/dist/index15.js +16 -3
  49. package/dist/index15.js.map +1 -1
  50. package/dist/index16.cjs +15 -2
  51. package/dist/index16.cjs.map +1 -1
  52. package/dist/index16.js +16 -3
  53. package/dist/index16.js.map +1 -1
  54. package/dist/index17.cjs +13 -2
  55. package/dist/index17.cjs.map +1 -1
  56. package/dist/index17.js +14 -3
  57. package/dist/index17.js.map +1 -1
  58. package/dist/index18.cjs +17 -4
  59. package/dist/index18.cjs.map +1 -1
  60. package/dist/index18.js +18 -5
  61. package/dist/index18.js.map +1 -1
  62. package/dist/index19.cjs +15 -2
  63. package/dist/index19.cjs.map +1 -1
  64. package/dist/index19.js +16 -3
  65. package/dist/index19.js.map +1 -1
  66. package/dist/index20.cjs +15 -2
  67. package/dist/index20.cjs.map +1 -1
  68. package/dist/index20.js +16 -3
  69. package/dist/index20.js.map +1 -1
  70. package/dist/index21.cjs +14 -3
  71. package/dist/index21.cjs.map +1 -1
  72. package/dist/index21.js +15 -4
  73. package/dist/index21.js.map +1 -1
  74. package/dist/index22.cjs +13 -2
  75. package/dist/index22.cjs.map +1 -1
  76. package/dist/index22.js +14 -3
  77. package/dist/index22.js.map +1 -1
  78. package/dist/index23.cjs +14 -3
  79. package/dist/index23.cjs.map +1 -1
  80. package/dist/index23.js +15 -4
  81. package/dist/index23.js.map +1 -1
  82. package/dist/index24.cjs +16 -2
  83. package/dist/index24.cjs.map +1 -1
  84. package/dist/index24.js +16 -2
  85. package/dist/index24.js.map +1 -1
  86. package/dist/index25.cjs +13 -2
  87. package/dist/index25.cjs.map +1 -1
  88. package/dist/index25.js +14 -3
  89. package/dist/index25.js.map +1 -1
  90. package/dist/index26.cjs +15 -4
  91. package/dist/index26.cjs.map +1 -1
  92. package/dist/index26.js +16 -5
  93. package/dist/index26.js.map +1 -1
  94. package/dist/index27.cjs +15 -4
  95. package/dist/index27.cjs.map +1 -1
  96. package/dist/index27.js +16 -5
  97. package/dist/index27.js.map +1 -1
  98. package/dist/index28.cjs +13 -2
  99. package/dist/index28.cjs.map +1 -1
  100. package/dist/index28.js +14 -3
  101. package/dist/index28.js.map +1 -1
  102. package/dist/index29.cjs +14 -2
  103. package/dist/index29.cjs.map +1 -1
  104. package/dist/index29.js +14 -2
  105. package/dist/index29.js.map +1 -1
  106. package/dist/index31.cjs +84 -0
  107. package/dist/index31.cjs.map +1 -1
  108. package/dist/index31.js +85 -1
  109. package/dist/index31.js.map +1 -1
  110. package/dist/index5.cjs +14 -2
  111. package/dist/index5.cjs.map +1 -1
  112. package/dist/index5.js +14 -2
  113. package/dist/index5.js.map +1 -1
  114. package/dist/index6.cjs +14 -2
  115. package/dist/index6.cjs.map +1 -1
  116. package/dist/index6.js +14 -2
  117. package/dist/index6.js.map +1 -1
  118. package/dist/index7.cjs +16 -2
  119. package/dist/index7.cjs.map +1 -1
  120. package/dist/index7.js +16 -2
  121. package/dist/index7.js.map +1 -1
  122. package/dist/index8.cjs +14 -2
  123. package/dist/index8.cjs.map +1 -1
  124. package/dist/index8.js +14 -2
  125. package/dist/index8.js.map +1 -1
  126. package/dist/index9.cjs +16 -2
  127. package/dist/index9.cjs.map +1 -1
  128. package/dist/index9.js +16 -2
  129. package/dist/index9.js.map +1 -1
  130. package/dist/premium-react-loaders.css +136 -4
  131. package/dist/types/common.d.ts +6 -0
  132. package/dist/types/common.d.ts.map +1 -1
  133. package/dist/utils/hooks.d.ts +9 -0
  134. package/dist/utils/hooks.d.ts.map +1 -1
  135. package/package.json +1 -1
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;"}
package/dist/index31.cjs CHANGED
@@ -37,6 +37,90 @@ function getEffectiveDuration(speed, respectMotionPreference, prefersReducedMoti
37
37
  };
38
38
  return speedMap[speed] || speedMap.normal;
39
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
+ }
40
123
  exports.getEffectiveDuration = getEffectiveDuration;
124
+ exports.useLoaderVisibility = useLoaderVisibility;
41
125
  exports.useReducedMotion = useReducedMotion;
42
126
  //# sourceMappingURL=index31.cjs.map
@@ -1 +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;;;"}
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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"}
package/dist/index31.js CHANGED
@@ -1,4 +1,4 @@
1
- import { useState, useEffect } from "react";
1
+ import { useState, useRef, useEffect } from "react";
2
2
  function useReducedMotion() {
3
3
  const [prefersReducedMotion, setPrefersReducedMotion] = useState(false);
4
4
  useEffect(() => {
@@ -35,8 +35,92 @@ function getEffectiveDuration(speed, respectMotionPreference, prefersReducedMoti
35
35
  };
36
36
  return speedMap[speed] || speedMap.normal;
37
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
+ }
38
121
  export {
39
122
  getEffectiveDuration,
123
+ useLoaderVisibility,
40
124
  useReducedMotion
41
125
  };
42
126
  //# sourceMappingURL=index31.js.map
@@ -1 +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;"}
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/index5.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 Skeleton = react.forwardRef(
@@ -13,13 +14,22 @@ const Skeleton = react.forwardRef(
13
14
  animate = true,
14
15
  baseColor = "#e0e0e0",
15
16
  highlightColor = "#f5f5f5",
17
+ delay = 0,
18
+ minDuration = 0,
19
+ transition,
16
20
  className,
17
21
  style,
18
22
  testId = "skeleton",
19
23
  visible = true,
20
24
  ...rest
21
25
  }, ref) => {
22
- if (!visible) return null;
26
+ const { shouldRender, opacity, transitionStyle } = hooks.useLoaderVisibility(
27
+ visible,
28
+ delay,
29
+ minDuration,
30
+ transition
31
+ );
32
+ if (!shouldRender) return null;
23
33
  const getBorderRadius = () => {
24
34
  if (borderRadius !== void 0) return colors.normalizeSize(borderRadius);
25
35
  switch (variant) {
@@ -50,7 +60,9 @@ const Skeleton = react.forwardRef(
50
60
  borderRadius: getBorderRadius(),
51
61
  backgroundColor: baseColor,
52
62
  "--skeleton-highlight-color": highlightColor,
53
- ...style
63
+ ...style,
64
+ opacity,
65
+ transition: transitionStyle
54
66
  },
55
67
  role: "status",
56
68
  "aria-label": "Loading...",
@@ -1 +1 @@
1
- {"version":3,"file":"index5.cjs","sources":["../src/components/skeleton/Skeleton.tsx"],"sourcesContent":["import React, { forwardRef } from 'react';\nimport { SkeletonProps } from '../../types';\nimport { cn, normalizeSize } from '../../utils';\n\n/**\n * Skeleton - Base skeleton loader component\n *\n * A versatile skeleton loader that can be used standalone or as a building block for more complex loaders.\n *\n * @example\n * ```tsx\n * <Skeleton width={200} height={20} />\n * <Skeleton variant=\"circular\" width={40} height={40} />\n * ```\n */\nexport const Skeleton = forwardRef<HTMLDivElement, SkeletonProps>(\n (\n {\n width = '100%',\n height = '1rem',\n borderRadius,\n variant = 'text',\n animate = true,\n baseColor = '#e0e0e0',\n highlightColor = '#f5f5f5',\n className,\n style,\n testId = 'skeleton',\n visible = true,\n ...rest\n },\n ref\n ) => {\n if (!visible) return null;\n\n const getBorderRadius = () => {\n if (borderRadius !== undefined) return normalizeSize(borderRadius);\n\n switch (variant) {\n case 'circular':\n return '50%';\n case 'rounded':\n return '0.5rem';\n case 'text':\n return '0.25rem';\n case 'rectangular':\n default:\n return '0';\n }\n };\n\n return (\n <div\n ref={ref}\n data-testid={testId}\n className={cn(\n 'skeleton',\n animate && 'skeleton-animate',\n className\n )}\n style={{\n width: normalizeSize(width),\n height: normalizeSize(height),\n borderRadius: getBorderRadius(),\n backgroundColor: baseColor,\n '--skeleton-highlight-color': highlightColor,\n ...style,\n } as React.CSSProperties}\n role=\"status\"\n aria-label=\"Loading...\"\n aria-busy=\"true\"\n {...rest}\n />\n );\n }\n);\n\nSkeleton.displayName = 'Skeleton';\n"],"names":["forwardRef","normalizeSize","jsx","cn"],"mappings":";;;;;;AAeO,MAAM,WAAWA,MAAAA;AAAAA,EACtB,CACE;AAAA,IACE,QAAQ;AAAA,IACR,SAAS;AAAA,IACT;AAAA,IACA,UAAU;AAAA,IACV,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,UAAU;AAAA,IACV,GAAG;AAAA,EAAA,GAEL,QACG;AACH,QAAI,CAAC,QAAS,QAAO;AAErB,UAAM,kBAAkB,MAAM;AAC5B,UAAI,iBAAiB,OAAW,QAAOC,OAAAA,cAAc,YAAY;AAEjE,cAAQ,SAAA;AAAA,QACN,KAAK;AACH,iBAAO;AAAA,QACT,KAAK;AACH,iBAAO;AAAA,QACT,KAAK;AACH,iBAAO;AAAA,QACT,KAAK;AAAA,QACL;AACE,iBAAO;AAAA,MAAA;AAAA,IAEb;AAEA,WACEC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAa;AAAA,QACb,WAAWC,WAAAA;AAAAA,UACT;AAAA,UACA,WAAW;AAAA,UACX;AAAA,QAAA;AAAA,QAEF,OAAO;AAAA,UACL,OAAOF,OAAAA,cAAc,KAAK;AAAA,UAC1B,QAAQA,OAAAA,cAAc,MAAM;AAAA,UAC5B,cAAc,gBAAA;AAAA,UACd,iBAAiB;AAAA,UACjB,8BAA8B;AAAA,UAC9B,GAAG;AAAA,QAAA;AAAA,QAEL,MAAK;AAAA,QACL,cAAW;AAAA,QACX,aAAU;AAAA,QACT,GAAG;AAAA,MAAA;AAAA,IAAA;AAAA,EAGV;AACF;AAEA,SAAS,cAAc;;"}
1
+ {"version":3,"file":"index5.cjs","sources":["../src/components/skeleton/Skeleton.tsx"],"sourcesContent":["import React, { forwardRef } from 'react';\nimport { SkeletonProps } from '../../types';\nimport { cn, normalizeSize, useLoaderVisibility } from '../../utils';\n\n/**\n * Skeleton - Base skeleton loader component\n *\n * A versatile skeleton loader that can be used standalone or as a building block for more complex loaders.\n *\n * @example\n * ```tsx\n * <Skeleton width={200} height={20} />\n * <Skeleton variant=\"circular\" width={40} height={40} />\n * ```\n */\nexport const Skeleton = forwardRef<HTMLDivElement, SkeletonProps>(\n (\n {\n width = '100%',\n height = '1rem',\n borderRadius,\n variant = 'text',\n animate = true,\n baseColor = '#e0e0e0',\n highlightColor = '#f5f5f5',\n delay = 0,\n minDuration = 0,\n transition,\n className,\n style,\n testId = 'skeleton',\n visible = true,\n ...rest\n },\n ref\n ) => {\n const { shouldRender, opacity, transitionStyle } = useLoaderVisibility(\n visible,\n delay,\n minDuration,\n transition\n );\n\n if (!shouldRender) return null;\n\n const getBorderRadius = () => {\n if (borderRadius !== undefined) return normalizeSize(borderRadius);\n\n switch (variant) {\n case 'circular':\n return '50%';\n case 'rounded':\n return '0.5rem';\n case 'text':\n return '0.25rem';\n case 'rectangular':\n default:\n return '0';\n }\n };\n\n return (\n <div\n ref={ref}\n data-testid={testId}\n className={cn(\n 'skeleton',\n animate && 'skeleton-animate',\n className\n )}\n style={{\n width: normalizeSize(width),\n height: normalizeSize(height),\n borderRadius: getBorderRadius(),\n backgroundColor: baseColor,\n '--skeleton-highlight-color': highlightColor,\n ...style,\n opacity,\n transition: transitionStyle,\n } as React.CSSProperties}\n role=\"status\"\n aria-label=\"Loading...\"\n aria-busy=\"true\"\n {...rest}\n />\n );\n }\n);\n\nSkeleton.displayName = 'Skeleton';\n"],"names":["forwardRef","useLoaderVisibility","normalizeSize","jsx","cn"],"mappings":";;;;;;;AAeO,MAAM,WAAWA,MAAAA;AAAAA,EACtB,CACE;AAAA,IACE,QAAQ;AAAA,IACR,SAAS;AAAA,IACT;AAAA,IACA,UAAU;AAAA,IACV,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,QAAQ;AAAA,IACR,cAAc;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,UAAU;AAAA,IACV,GAAG;AAAA,EAAA,GAEL,QACG;AACH,UAAM,EAAE,cAAc,SAAS,gBAAA,IAAoBC,MAAAA;AAAAA,MACjD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAGF,QAAI,CAAC,aAAc,QAAO;AAE1B,UAAM,kBAAkB,MAAM;AAC5B,UAAI,iBAAiB,OAAW,QAAOC,OAAAA,cAAc,YAAY;AAEjE,cAAQ,SAAA;AAAA,QACN,KAAK;AACH,iBAAO;AAAA,QACT,KAAK;AACH,iBAAO;AAAA,QACT,KAAK;AACH,iBAAO;AAAA,QACT,KAAK;AAAA,QACL;AACE,iBAAO;AAAA,MAAA;AAAA,IAEb;AAEA,WACEC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAa;AAAA,QACb,WAAWC,WAAAA;AAAAA,UACT;AAAA,UACA,WAAW;AAAA,UACX;AAAA,QAAA;AAAA,QAEF,OAAO;AAAA,UACL,OAAOF,OAAAA,cAAc,KAAK;AAAA,UAC1B,QAAQA,OAAAA,cAAc,MAAM;AAAA,UAC5B,cAAc,gBAAA;AAAA,UACd,iBAAiB;AAAA,UACjB,8BAA8B;AAAA,UAC9B,GAAG;AAAA,UACH;AAAA,UACA,YAAY;AAAA,QAAA;AAAA,QAEd,MAAK;AAAA,QACL,cAAW;AAAA,QACX,aAAU;AAAA,QACT,GAAG;AAAA,MAAA;AAAA,IAAA;AAAA,EAGV;AACF;AAEA,SAAS,cAAc;;"}
package/dist/index5.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { forwardRef } from "react";
3
+ import { useLoaderVisibility } from "./index31.js";
3
4
  import { normalizeSize } from "./index4.js";
4
5
  import { cn } from "./index3.js";
5
6
  const Skeleton = forwardRef(
@@ -11,13 +12,22 @@ const Skeleton = forwardRef(
11
12
  animate = true,
12
13
  baseColor = "#e0e0e0",
13
14
  highlightColor = "#f5f5f5",
15
+ delay = 0,
16
+ minDuration = 0,
17
+ transition,
14
18
  className,
15
19
  style,
16
20
  testId = "skeleton",
17
21
  visible = true,
18
22
  ...rest
19
23
  }, ref) => {
20
- if (!visible) return null;
24
+ const { shouldRender, opacity, transitionStyle } = useLoaderVisibility(
25
+ visible,
26
+ delay,
27
+ minDuration,
28
+ transition
29
+ );
30
+ if (!shouldRender) return null;
21
31
  const getBorderRadius = () => {
22
32
  if (borderRadius !== void 0) return normalizeSize(borderRadius);
23
33
  switch (variant) {
@@ -48,7 +58,9 @@ const Skeleton = forwardRef(
48
58
  borderRadius: getBorderRadius(),
49
59
  backgroundColor: baseColor,
50
60
  "--skeleton-highlight-color": highlightColor,
51
- ...style
61
+ ...style,
62
+ opacity,
63
+ transition: transitionStyle
52
64
  },
53
65
  role: "status",
54
66
  "aria-label": "Loading...",
@@ -1 +1 @@
1
- {"version":3,"file":"index5.js","sources":["../src/components/skeleton/Skeleton.tsx"],"sourcesContent":["import React, { forwardRef } from 'react';\nimport { SkeletonProps } from '../../types';\nimport { cn, normalizeSize } from '../../utils';\n\n/**\n * Skeleton - Base skeleton loader component\n *\n * A versatile skeleton loader that can be used standalone or as a building block for more complex loaders.\n *\n * @example\n * ```tsx\n * <Skeleton width={200} height={20} />\n * <Skeleton variant=\"circular\" width={40} height={40} />\n * ```\n */\nexport const Skeleton = forwardRef<HTMLDivElement, SkeletonProps>(\n (\n {\n width = '100%',\n height = '1rem',\n borderRadius,\n variant = 'text',\n animate = true,\n baseColor = '#e0e0e0',\n highlightColor = '#f5f5f5',\n className,\n style,\n testId = 'skeleton',\n visible = true,\n ...rest\n },\n ref\n ) => {\n if (!visible) return null;\n\n const getBorderRadius = () => {\n if (borderRadius !== undefined) return normalizeSize(borderRadius);\n\n switch (variant) {\n case 'circular':\n return '50%';\n case 'rounded':\n return '0.5rem';\n case 'text':\n return '0.25rem';\n case 'rectangular':\n default:\n return '0';\n }\n };\n\n return (\n <div\n ref={ref}\n data-testid={testId}\n className={cn(\n 'skeleton',\n animate && 'skeleton-animate',\n className\n )}\n style={{\n width: normalizeSize(width),\n height: normalizeSize(height),\n borderRadius: getBorderRadius(),\n backgroundColor: baseColor,\n '--skeleton-highlight-color': highlightColor,\n ...style,\n } as React.CSSProperties}\n role=\"status\"\n aria-label=\"Loading...\"\n aria-busy=\"true\"\n {...rest}\n />\n );\n }\n);\n\nSkeleton.displayName = 'Skeleton';\n"],"names":[],"mappings":";;;;AAeO,MAAM,WAAW;AAAA,EACtB,CACE;AAAA,IACE,QAAQ;AAAA,IACR,SAAS;AAAA,IACT;AAAA,IACA,UAAU;AAAA,IACV,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,UAAU;AAAA,IACV,GAAG;AAAA,EAAA,GAEL,QACG;AACH,QAAI,CAAC,QAAS,QAAO;AAErB,UAAM,kBAAkB,MAAM;AAC5B,UAAI,iBAAiB,OAAW,QAAO,cAAc,YAAY;AAEjE,cAAQ,SAAA;AAAA,QACN,KAAK;AACH,iBAAO;AAAA,QACT,KAAK;AACH,iBAAO;AAAA,QACT,KAAK;AACH,iBAAO;AAAA,QACT,KAAK;AAAA,QACL;AACE,iBAAO;AAAA,MAAA;AAAA,IAEb;AAEA,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAa;AAAA,QACb,WAAW;AAAA,UACT;AAAA,UACA,WAAW;AAAA,UACX;AAAA,QAAA;AAAA,QAEF,OAAO;AAAA,UACL,OAAO,cAAc,KAAK;AAAA,UAC1B,QAAQ,cAAc,MAAM;AAAA,UAC5B,cAAc,gBAAA;AAAA,UACd,iBAAiB;AAAA,UACjB,8BAA8B;AAAA,UAC9B,GAAG;AAAA,QAAA;AAAA,QAEL,MAAK;AAAA,QACL,cAAW;AAAA,QACX,aAAU;AAAA,QACT,GAAG;AAAA,MAAA;AAAA,IAAA;AAAA,EAGV;AACF;AAEA,SAAS,cAAc;"}
1
+ {"version":3,"file":"index5.js","sources":["../src/components/skeleton/Skeleton.tsx"],"sourcesContent":["import React, { forwardRef } from 'react';\nimport { SkeletonProps } from '../../types';\nimport { cn, normalizeSize, useLoaderVisibility } from '../../utils';\n\n/**\n * Skeleton - Base skeleton loader component\n *\n * A versatile skeleton loader that can be used standalone or as a building block for more complex loaders.\n *\n * @example\n * ```tsx\n * <Skeleton width={200} height={20} />\n * <Skeleton variant=\"circular\" width={40} height={40} />\n * ```\n */\nexport const Skeleton = forwardRef<HTMLDivElement, SkeletonProps>(\n (\n {\n width = '100%',\n height = '1rem',\n borderRadius,\n variant = 'text',\n animate = true,\n baseColor = '#e0e0e0',\n highlightColor = '#f5f5f5',\n delay = 0,\n minDuration = 0,\n transition,\n className,\n style,\n testId = 'skeleton',\n visible = true,\n ...rest\n },\n ref\n ) => {\n const { shouldRender, opacity, transitionStyle } = useLoaderVisibility(\n visible,\n delay,\n minDuration,\n transition\n );\n\n if (!shouldRender) return null;\n\n const getBorderRadius = () => {\n if (borderRadius !== undefined) return normalizeSize(borderRadius);\n\n switch (variant) {\n case 'circular':\n return '50%';\n case 'rounded':\n return '0.5rem';\n case 'text':\n return '0.25rem';\n case 'rectangular':\n default:\n return '0';\n }\n };\n\n return (\n <div\n ref={ref}\n data-testid={testId}\n className={cn(\n 'skeleton',\n animate && 'skeleton-animate',\n className\n )}\n style={{\n width: normalizeSize(width),\n height: normalizeSize(height),\n borderRadius: getBorderRadius(),\n backgroundColor: baseColor,\n '--skeleton-highlight-color': highlightColor,\n ...style,\n opacity,\n transition: transitionStyle,\n } as React.CSSProperties}\n role=\"status\"\n aria-label=\"Loading...\"\n aria-busy=\"true\"\n {...rest}\n />\n );\n }\n);\n\nSkeleton.displayName = 'Skeleton';\n"],"names":[],"mappings":";;;;;AAeO,MAAM,WAAW;AAAA,EACtB,CACE;AAAA,IACE,QAAQ;AAAA,IACR,SAAS;AAAA,IACT;AAAA,IACA,UAAU;AAAA,IACV,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,QAAQ;AAAA,IACR,cAAc;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,UAAU;AAAA,IACV,GAAG;AAAA,EAAA,GAEL,QACG;AACH,UAAM,EAAE,cAAc,SAAS,gBAAA,IAAoB;AAAA,MACjD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAGF,QAAI,CAAC,aAAc,QAAO;AAE1B,UAAM,kBAAkB,MAAM;AAC5B,UAAI,iBAAiB,OAAW,QAAO,cAAc,YAAY;AAEjE,cAAQ,SAAA;AAAA,QACN,KAAK;AACH,iBAAO;AAAA,QACT,KAAK;AACH,iBAAO;AAAA,QACT,KAAK;AACH,iBAAO;AAAA,QACT,KAAK;AAAA,QACL;AACE,iBAAO;AAAA,MAAA;AAAA,IAEb;AAEA,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAa;AAAA,QACb,WAAW;AAAA,UACT;AAAA,UACA,WAAW;AAAA,UACX;AAAA,QAAA;AAAA,QAEF,OAAO;AAAA,UACL,OAAO,cAAc,KAAK;AAAA,UAC1B,QAAQ,cAAc,MAAM;AAAA,UAC5B,cAAc,gBAAA;AAAA,UACd,iBAAiB;AAAA,UACjB,8BAA8B;AAAA,UAC9B,GAAG;AAAA,UACH;AAAA,UACA,YAAY;AAAA,QAAA;AAAA,QAEd,MAAK;AAAA,QACL,cAAW;AAAA,QACX,aAAU;AAAA,QACT,GAAG;AAAA,MAAA;AAAA,IAAA;AAAA,EAGV;AACF;AAEA,SAAS,cAAc;"}
package/dist/index6.cjs CHANGED
@@ -3,6 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const jsxRuntime = require("react/jsx-runtime");
4
4
  const react = require("react");
5
5
  const Skeleton = require("./index5.cjs");
6
+ const hooks = require("./index31.cjs");
6
7
  const colors = require("./index4.cjs");
7
8
  const classNames = require("./index3.cjs");
8
9
  const SkeletonText = react.forwardRef(
@@ -15,13 +16,22 @@ const SkeletonText = react.forwardRef(
15
16
  animate = true,
16
17
  baseColor,
17
18
  highlightColor,
19
+ delay = 0,
20
+ minDuration = 0,
21
+ transition,
18
22
  className,
19
23
  style,
20
24
  testId = "skeleton-text",
21
25
  visible = true,
22
26
  ...rest
23
27
  }, ref) => {
24
- if (!visible) return null;
28
+ const { shouldRender, opacity, transitionStyle } = hooks.useLoaderVisibility(
29
+ visible,
30
+ delay,
31
+ minDuration,
32
+ transition
33
+ );
34
+ if (!shouldRender) return null;
25
35
  return /* @__PURE__ */ jsxRuntime.jsx(
26
36
  "div",
27
37
  {
@@ -30,7 +40,9 @@ const SkeletonText = react.forwardRef(
30
40
  className: classNames.cn("flex flex-col", className),
31
41
  style: {
32
42
  gap: colors.normalizeSize(gap),
33
- ...style
43
+ ...style,
44
+ opacity,
45
+ transition: transitionStyle
34
46
  },
35
47
  role: "status",
36
48
  "aria-label": "Loading text...",
@@ -1 +1 @@
1
- {"version":3,"file":"index6.cjs","sources":["../src/components/skeleton/SkeletonText.tsx"],"sourcesContent":["import { forwardRef } from 'react';\nimport { SkeletonTextProps } from '../../types';\nimport { cn, normalizeSize } from '../../utils';\nimport { Skeleton } from './Skeleton';\n\n/**\n * SkeletonText - Multi-line text skeleton loader\n *\n * Renders multiple skeleton lines to mimic text content while loading.\n *\n * @example\n * ```tsx\n * <SkeletonText lines={3} />\n * <SkeletonText lines={5} gap={8} lastLineWidth=\"60%\" />\n * ```\n */\nexport const SkeletonText = forwardRef<HTMLDivElement, SkeletonTextProps>(\n (\n {\n lines = 3,\n width = '100%',\n height = '1rem',\n gap = '0.5rem',\n lastLineWidth = '80%',\n animate = true,\n baseColor,\n highlightColor,\n className,\n style,\n testId = 'skeleton-text',\n visible = true,\n ...rest\n },\n ref\n ) => {\n if (!visible) return null;\n\n return (\n <div\n ref={ref}\n data-testid={testId}\n className={cn('flex flex-col', className)}\n style={{\n gap: normalizeSize(gap),\n ...style,\n }}\n role=\"status\"\n aria-label=\"Loading text...\"\n aria-busy=\"true\"\n {...rest}\n >\n {Array.from({ length: lines }).map((_, index) => {\n // Last line uses custom width or default (80%)\n const lineWidth = index === lines - 1 ? lastLineWidth : width;\n\n return (\n <Skeleton\n key={index}\n width={lineWidth}\n height={height}\n animate={animate}\n baseColor={baseColor}\n highlightColor={highlightColor}\n variant=\"text\"\n />\n );\n })}\n </div>\n );\n }\n);\n\nSkeletonText.displayName = 'SkeletonText';\n"],"names":["forwardRef","jsx","cn","normalizeSize","Skeleton"],"mappings":";;;;;;;AAgBO,MAAM,eAAeA,MAAAA;AAAAA,EAC1B,CACE;AAAA,IACE,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,MAAM;AAAA,IACN,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,UAAU;AAAA,IACV,GAAG;AAAA,EAAA,GAEL,QACG;AACH,QAAI,CAAC,QAAS,QAAO;AAErB,WACEC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAa;AAAA,QACb,WAAWC,WAAAA,GAAG,iBAAiB,SAAS;AAAA,QACxC,OAAO;AAAA,UACL,KAAKC,OAAAA,cAAc,GAAG;AAAA,UACtB,GAAG;AAAA,QAAA;AAAA,QAEL,MAAK;AAAA,QACL,cAAW;AAAA,QACX,aAAU;AAAA,QACT,GAAG;AAAA,QAEH,UAAA,MAAM,KAAK,EAAE,QAAQ,MAAA,CAAO,EAAE,IAAI,CAAC,GAAG,UAAU;AAE/C,gBAAM,YAAY,UAAU,QAAQ,IAAI,gBAAgB;AAExD,iBACEF,2BAAAA;AAAAA,YAACG,SAAAA;AAAAA,YAAA;AAAA,cAEC,OAAO;AAAA,cACP;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA,SAAQ;AAAA,YAAA;AAAA,YANH;AAAA,UAAA;AAAA,QASX,CAAC;AAAA,MAAA;AAAA,IAAA;AAAA,EAGP;AACF;AAEA,aAAa,cAAc;;"}
1
+ {"version":3,"file":"index6.cjs","sources":["../src/components/skeleton/SkeletonText.tsx"],"sourcesContent":["import { forwardRef } from 'react';\nimport { SkeletonTextProps } from '../../types';\nimport { cn, normalizeSize, useLoaderVisibility } from '../../utils';\nimport { Skeleton } from './Skeleton';\n\n/**\n * SkeletonText - Multi-line text skeleton loader\n *\n * Renders multiple skeleton lines to mimic text content while loading.\n *\n * @example\n * ```tsx\n * <SkeletonText lines={3} />\n * <SkeletonText lines={5} gap={8} lastLineWidth=\"60%\" />\n * ```\n */\nexport const SkeletonText = forwardRef<HTMLDivElement, SkeletonTextProps>(\n (\n {\n lines = 3,\n width = '100%',\n height = '1rem',\n gap = '0.5rem',\n lastLineWidth = '80%',\n animate = true,\n baseColor,\n highlightColor,\n delay = 0,\n minDuration = 0,\n transition,\n className,\n style,\n testId = 'skeleton-text',\n visible = true,\n ...rest\n },\n ref\n ) => {\n const { shouldRender, opacity, transitionStyle } = useLoaderVisibility(\n visible,\n delay,\n minDuration,\n transition\n );\n\n if (!shouldRender) return null;\n\n return (\n <div\n ref={ref}\n data-testid={testId}\n className={cn('flex flex-col', className)}\n style={{\n gap: normalizeSize(gap),\n ...style,\n opacity,\n transition: transitionStyle,\n }}\n role=\"status\"\n aria-label=\"Loading text...\"\n aria-busy=\"true\"\n {...rest}\n >\n {Array.from({ length: lines }).map((_, index) => {\n // Last line uses custom width or default (80%)\n const lineWidth = index === lines - 1 ? lastLineWidth : width;\n\n return (\n <Skeleton\n key={index}\n width={lineWidth}\n height={height}\n animate={animate}\n baseColor={baseColor}\n highlightColor={highlightColor}\n variant=\"text\"\n />\n );\n })}\n </div>\n );\n }\n);\n\nSkeletonText.displayName = 'SkeletonText';\n"],"names":["forwardRef","useLoaderVisibility","jsx","cn","normalizeSize","Skeleton"],"mappings":";;;;;;;;AAgBO,MAAM,eAAeA,MAAAA;AAAAA,EAC1B,CACE;AAAA,IACE,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,MAAM;AAAA,IACN,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,cAAc;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,UAAU;AAAA,IACV,GAAG;AAAA,EAAA,GAEL,QACG;AACH,UAAM,EAAE,cAAc,SAAS,gBAAA,IAAoBC,MAAAA;AAAAA,MACjD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAGF,QAAI,CAAC,aAAc,QAAO;AAE1B,WACEC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAa;AAAA,QACb,WAAWC,WAAAA,GAAG,iBAAiB,SAAS;AAAA,QACxC,OAAO;AAAA,UACL,KAAKC,OAAAA,cAAc,GAAG;AAAA,UACtB,GAAG;AAAA,UACH;AAAA,UACA,YAAY;AAAA,QAAA;AAAA,QAEd,MAAK;AAAA,QACL,cAAW;AAAA,QACX,aAAU;AAAA,QACT,GAAG;AAAA,QAEH,UAAA,MAAM,KAAK,EAAE,QAAQ,MAAA,CAAO,EAAE,IAAI,CAAC,GAAG,UAAU;AAE/C,gBAAM,YAAY,UAAU,QAAQ,IAAI,gBAAgB;AAExD,iBACEF,2BAAAA;AAAAA,YAACG,SAAAA;AAAAA,YAAA;AAAA,cAEC,OAAO;AAAA,cACP;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA,SAAQ;AAAA,YAAA;AAAA,YANH;AAAA,UAAA;AAAA,QASX,CAAC;AAAA,MAAA;AAAA,IAAA;AAAA,EAGP;AACF;AAEA,aAAa,cAAc;;"}
package/dist/index6.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { forwardRef } from "react";
3
3
  import { Skeleton } from "./index5.js";
4
+ import { useLoaderVisibility } from "./index31.js";
4
5
  import { normalizeSize } from "./index4.js";
5
6
  import { cn } from "./index3.js";
6
7
  const SkeletonText = forwardRef(
@@ -13,13 +14,22 @@ const SkeletonText = forwardRef(
13
14
  animate = true,
14
15
  baseColor,
15
16
  highlightColor,
17
+ delay = 0,
18
+ minDuration = 0,
19
+ transition,
16
20
  className,
17
21
  style,
18
22
  testId = "skeleton-text",
19
23
  visible = true,
20
24
  ...rest
21
25
  }, ref) => {
22
- if (!visible) return null;
26
+ const { shouldRender, opacity, transitionStyle } = useLoaderVisibility(
27
+ visible,
28
+ delay,
29
+ minDuration,
30
+ transition
31
+ );
32
+ if (!shouldRender) return null;
23
33
  return /* @__PURE__ */ jsx(
24
34
  "div",
25
35
  {
@@ -28,7 +38,9 @@ const SkeletonText = forwardRef(
28
38
  className: cn("flex flex-col", className),
29
39
  style: {
30
40
  gap: normalizeSize(gap),
31
- ...style
41
+ ...style,
42
+ opacity,
43
+ transition: transitionStyle
32
44
  },
33
45
  role: "status",
34
46
  "aria-label": "Loading text...",
@@ -1 +1 @@
1
- {"version":3,"file":"index6.js","sources":["../src/components/skeleton/SkeletonText.tsx"],"sourcesContent":["import { forwardRef } from 'react';\nimport { SkeletonTextProps } from '../../types';\nimport { cn, normalizeSize } from '../../utils';\nimport { Skeleton } from './Skeleton';\n\n/**\n * SkeletonText - Multi-line text skeleton loader\n *\n * Renders multiple skeleton lines to mimic text content while loading.\n *\n * @example\n * ```tsx\n * <SkeletonText lines={3} />\n * <SkeletonText lines={5} gap={8} lastLineWidth=\"60%\" />\n * ```\n */\nexport const SkeletonText = forwardRef<HTMLDivElement, SkeletonTextProps>(\n (\n {\n lines = 3,\n width = '100%',\n height = '1rem',\n gap = '0.5rem',\n lastLineWidth = '80%',\n animate = true,\n baseColor,\n highlightColor,\n className,\n style,\n testId = 'skeleton-text',\n visible = true,\n ...rest\n },\n ref\n ) => {\n if (!visible) return null;\n\n return (\n <div\n ref={ref}\n data-testid={testId}\n className={cn('flex flex-col', className)}\n style={{\n gap: normalizeSize(gap),\n ...style,\n }}\n role=\"status\"\n aria-label=\"Loading text...\"\n aria-busy=\"true\"\n {...rest}\n >\n {Array.from({ length: lines }).map((_, index) => {\n // Last line uses custom width or default (80%)\n const lineWidth = index === lines - 1 ? lastLineWidth : width;\n\n return (\n <Skeleton\n key={index}\n width={lineWidth}\n height={height}\n animate={animate}\n baseColor={baseColor}\n highlightColor={highlightColor}\n variant=\"text\"\n />\n );\n })}\n </div>\n );\n }\n);\n\nSkeletonText.displayName = 'SkeletonText';\n"],"names":[],"mappings":";;;;;AAgBO,MAAM,eAAe;AAAA,EAC1B,CACE;AAAA,IACE,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,MAAM;AAAA,IACN,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,UAAU;AAAA,IACV,GAAG;AAAA,EAAA,GAEL,QACG;AACH,QAAI,CAAC,QAAS,QAAO;AAErB,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAa;AAAA,QACb,WAAW,GAAG,iBAAiB,SAAS;AAAA,QACxC,OAAO;AAAA,UACL,KAAK,cAAc,GAAG;AAAA,UACtB,GAAG;AAAA,QAAA;AAAA,QAEL,MAAK;AAAA,QACL,cAAW;AAAA,QACX,aAAU;AAAA,QACT,GAAG;AAAA,QAEH,UAAA,MAAM,KAAK,EAAE,QAAQ,MAAA,CAAO,EAAE,IAAI,CAAC,GAAG,UAAU;AAE/C,gBAAM,YAAY,UAAU,QAAQ,IAAI,gBAAgB;AAExD,iBACE;AAAA,YAAC;AAAA,YAAA;AAAA,cAEC,OAAO;AAAA,cACP;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA,SAAQ;AAAA,YAAA;AAAA,YANH;AAAA,UAAA;AAAA,QASX,CAAC;AAAA,MAAA;AAAA,IAAA;AAAA,EAGP;AACF;AAEA,aAAa,cAAc;"}
1
+ {"version":3,"file":"index6.js","sources":["../src/components/skeleton/SkeletonText.tsx"],"sourcesContent":["import { forwardRef } from 'react';\nimport { SkeletonTextProps } from '../../types';\nimport { cn, normalizeSize, useLoaderVisibility } from '../../utils';\nimport { Skeleton } from './Skeleton';\n\n/**\n * SkeletonText - Multi-line text skeleton loader\n *\n * Renders multiple skeleton lines to mimic text content while loading.\n *\n * @example\n * ```tsx\n * <SkeletonText lines={3} />\n * <SkeletonText lines={5} gap={8} lastLineWidth=\"60%\" />\n * ```\n */\nexport const SkeletonText = forwardRef<HTMLDivElement, SkeletonTextProps>(\n (\n {\n lines = 3,\n width = '100%',\n height = '1rem',\n gap = '0.5rem',\n lastLineWidth = '80%',\n animate = true,\n baseColor,\n highlightColor,\n delay = 0,\n minDuration = 0,\n transition,\n className,\n style,\n testId = 'skeleton-text',\n visible = true,\n ...rest\n },\n ref\n ) => {\n const { shouldRender, opacity, transitionStyle } = useLoaderVisibility(\n visible,\n delay,\n minDuration,\n transition\n );\n\n if (!shouldRender) return null;\n\n return (\n <div\n ref={ref}\n data-testid={testId}\n className={cn('flex flex-col', className)}\n style={{\n gap: normalizeSize(gap),\n ...style,\n opacity,\n transition: transitionStyle,\n }}\n role=\"status\"\n aria-label=\"Loading text...\"\n aria-busy=\"true\"\n {...rest}\n >\n {Array.from({ length: lines }).map((_, index) => {\n // Last line uses custom width or default (80%)\n const lineWidth = index === lines - 1 ? lastLineWidth : width;\n\n return (\n <Skeleton\n key={index}\n width={lineWidth}\n height={height}\n animate={animate}\n baseColor={baseColor}\n highlightColor={highlightColor}\n variant=\"text\"\n />\n );\n })}\n </div>\n );\n }\n);\n\nSkeletonText.displayName = 'SkeletonText';\n"],"names":[],"mappings":";;;;;;AAgBO,MAAM,eAAe;AAAA,EAC1B,CACE;AAAA,IACE,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,MAAM;AAAA,IACN,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,cAAc;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,UAAU;AAAA,IACV,GAAG;AAAA,EAAA,GAEL,QACG;AACH,UAAM,EAAE,cAAc,SAAS,gBAAA,IAAoB;AAAA,MACjD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAGF,QAAI,CAAC,aAAc,QAAO;AAE1B,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAa;AAAA,QACb,WAAW,GAAG,iBAAiB,SAAS;AAAA,QACxC,OAAO;AAAA,UACL,KAAK,cAAc,GAAG;AAAA,UACtB,GAAG;AAAA,UACH;AAAA,UACA,YAAY;AAAA,QAAA;AAAA,QAEd,MAAK;AAAA,QACL,cAAW;AAAA,QACX,aAAU;AAAA,QACT,GAAG;AAAA,QAEH,UAAA,MAAM,KAAK,EAAE,QAAQ,MAAA,CAAO,EAAE,IAAI,CAAC,GAAG,UAAU;AAE/C,gBAAM,YAAY,UAAU,QAAQ,IAAI,gBAAgB;AAExD,iBACE;AAAA,YAAC;AAAA,YAAA;AAAA,cAEC,OAAO;AAAA,cACP;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA,SAAQ;AAAA,YAAA;AAAA,YANH;AAAA,UAAA;AAAA,QASX,CAAC;AAAA,MAAA;AAAA,IAAA;AAAA,EAGP;AACF;AAEA,aAAa,cAAc;"}