@zentauri-ui/zentauri-components 1.8.4 → 1.8.41

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 (115) hide show
  1. package/dist/animations/blur-in.js +2 -2
  2. package/dist/animations/blur-in.mjs +1 -1
  3. package/dist/animations/blur-out.js +2 -2
  4. package/dist/animations/blur-out.mjs +1 -1
  5. package/dist/animations/bounce.js +2 -2
  6. package/dist/animations/bounce.mjs +1 -1
  7. package/dist/animations/fade-down.js +2 -2
  8. package/dist/animations/fade-down.mjs +1 -1
  9. package/dist/animations/fade-in.js +2 -2
  10. package/dist/animations/fade-in.mjs +1 -1
  11. package/dist/animations/fade-left.js +2 -2
  12. package/dist/animations/fade-left.mjs +1 -1
  13. package/dist/animations/fade-out.js +2 -2
  14. package/dist/animations/fade-out.mjs +1 -1
  15. package/dist/animations/fade-right.js +2 -2
  16. package/dist/animations/fade-right.mjs +1 -1
  17. package/dist/animations/fade-up.js +2 -2
  18. package/dist/animations/fade-up.mjs +1 -1
  19. package/dist/animations/flip-in.js +2 -2
  20. package/dist/animations/flip-in.mjs +1 -1
  21. package/dist/animations/flip.js +2 -2
  22. package/dist/animations/flip.mjs +1 -1
  23. package/dist/animations/float.js +2 -2
  24. package/dist/animations/float.mjs +1 -1
  25. package/dist/animations/hover-lift.js +2 -2
  26. package/dist/animations/hover-lift.mjs +1 -1
  27. package/dist/animations/hover-scale.js +2 -2
  28. package/dist/animations/hover-scale.mjs +1 -1
  29. package/dist/animations/magnetic.js +2 -2
  30. package/dist/animations/magnetic.mjs +1 -1
  31. package/dist/animations/parallax.js +2 -2
  32. package/dist/animations/parallax.mjs +1 -1
  33. package/dist/animations/ping.js +2 -2
  34. package/dist/animations/ping.mjs +1 -1
  35. package/dist/animations/pop-in.js +2 -2
  36. package/dist/animations/pop-in.mjs +1 -1
  37. package/dist/animations/press.js +2 -2
  38. package/dist/animations/press.mjs +1 -1
  39. package/dist/animations/progress.js +2 -2
  40. package/dist/animations/progress.mjs +1 -1
  41. package/dist/animations/pulse.js +2 -2
  42. package/dist/animations/pulse.mjs +1 -1
  43. package/dist/animations/reorder.js +2 -2
  44. package/dist/animations/reorder.mjs +1 -1
  45. package/dist/animations/reveal-blur.js +2 -2
  46. package/dist/animations/reveal-blur.mjs +1 -1
  47. package/dist/animations/reveal-down.js +2 -2
  48. package/dist/animations/reveal-down.mjs +1 -1
  49. package/dist/animations/reveal-left.js +2 -2
  50. package/dist/animations/reveal-left.mjs +1 -1
  51. package/dist/animations/reveal-right.js +2 -2
  52. package/dist/animations/reveal-right.mjs +1 -1
  53. package/dist/animations/reveal-up.js +2 -2
  54. package/dist/animations/reveal-up.mjs +1 -1
  55. package/dist/animations/rotate-in.js +2 -2
  56. package/dist/animations/rotate-in.mjs +1 -1
  57. package/dist/animations/scale-in.js +2 -2
  58. package/dist/animations/scale-in.mjs +1 -1
  59. package/dist/animations/scale-out.js +2 -2
  60. package/dist/animations/scale-out.mjs +1 -1
  61. package/dist/animations/shake.js +2 -2
  62. package/dist/animations/shake.mjs +1 -1
  63. package/dist/animations/shared/create-motion-animation.d.ts.map +1 -1
  64. package/dist/animations/shared/index.d.ts +1 -1
  65. package/dist/animations/shared/index.d.ts.map +1 -1
  66. package/dist/animations/shared/types.d.ts +3 -1
  67. package/dist/animations/shared/types.d.ts.map +1 -1
  68. package/dist/animations/skeleton-shimmer.js +2 -2
  69. package/dist/animations/skeleton-shimmer.mjs +1 -1
  70. package/dist/animations/slide-down.js +2 -2
  71. package/dist/animations/slide-down.mjs +1 -1
  72. package/dist/animations/slide-left.js +2 -2
  73. package/dist/animations/slide-left.mjs +1 -1
  74. package/dist/animations/slide-right.js +2 -2
  75. package/dist/animations/slide-right.mjs +1 -1
  76. package/dist/animations/slide-up.js +2 -2
  77. package/dist/animations/slide-up.mjs +1 -1
  78. package/dist/animations/spin.js +2 -2
  79. package/dist/animations/spin.mjs +1 -1
  80. package/dist/animations/text-reveal.js +2 -2
  81. package/dist/animations/text-reveal.mjs +1 -1
  82. package/dist/animations/text-shimmer.js +2 -2
  83. package/dist/animations/text-shimmer.mjs +1 -1
  84. package/dist/animations/tilt.js +2 -2
  85. package/dist/animations/tilt.mjs +1 -1
  86. package/dist/animations/wiggle.js +2 -2
  87. package/dist/animations/wiggle.mjs +1 -1
  88. package/dist/{chunk-AACGI7FX.mjs → chunk-7OVJXYSS.mjs} +16 -5
  89. package/dist/chunk-7OVJXYSS.mjs.map +1 -0
  90. package/dist/{chunk-VARQ7W4G.mjs → chunk-C6NA452Q.mjs} +43 -2
  91. package/dist/chunk-C6NA452Q.mjs.map +1 -0
  92. package/dist/{chunk-JFS5PJSH.js → chunk-OKCC7E36.js} +43 -2
  93. package/dist/chunk-OKCC7E36.js.map +1 -0
  94. package/dist/{chunk-ODZM25II.js → chunk-R5LL56ZO.js} +16 -5
  95. package/dist/chunk-R5LL56ZO.js.map +1 -0
  96. package/dist/ui/buttons/button-base.d.ts +1 -1
  97. package/dist/ui/buttons/button-base.d.ts.map +1 -1
  98. package/dist/ui/buttons/types.d.ts +16 -2
  99. package/dist/ui/buttons/types.d.ts.map +1 -1
  100. package/dist/ui/buttons.js +2 -2
  101. package/dist/ui/buttons.mjs +1 -1
  102. package/dist/ui/dynamic-stepper.js +3 -3
  103. package/dist/ui/dynamic-stepper.mjs +1 -1
  104. package/package.json +1 -1
  105. package/src/animations/animations.test.tsx +113 -1
  106. package/src/animations/shared/create-motion-animation.tsx +33 -3
  107. package/src/animations/shared/index.ts +5 -1
  108. package/src/animations/shared/types.ts +9 -1
  109. package/src/ui/buttons/button-base.tsx +53 -0
  110. package/src/ui/buttons/button.test.tsx +40 -0
  111. package/src/ui/buttons/types.ts +25 -2
  112. package/dist/chunk-AACGI7FX.mjs.map +0 -1
  113. package/dist/chunk-JFS5PJSH.js.map +0 -1
  114. package/dist/chunk-ODZM25II.js.map +0 -1
  115. package/dist/chunk-VARQ7W4G.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ui/buttons/button-base.tsx","../src/ui/buttons/button.tsx"],"names":["className","appearance","size","children","rest","isValidElement","cloneElement","cn","buttonVariants","ref","jsx"],"mappings":";;;;;;;AASO,IAAM,UAAA,GAAa,CAAC,KAAA,KAAuB;AAChD,EAAA,IAAI,SAAA,IAAa,KAAA,IAAS,KAAA,CAAM,OAAA,EAAS;AACvC,IAAA,MAAM;AAAA,MACJ,SAAA,EAAAA,UAAAA;AAAA,MACA,UAAA,EAAAC,WAAAA;AAAA,MACA,IAAA,EAAAC,KAAAA;AAAA,MACA,QAAA,EAAAC,SAAAA;AAAA,MACA,OAAA,EAAS,QAAA;AAAA,MACT,QAAA;AAAA,MACA,OAAA;AAAA,MACA,GAAGC;AAAA,KACL,GAAI,KAAA;AAEJ,IAAA,IAAI,CAACC,oBAAA,CAAuCF,SAAQ,CAAA,EAAG;AACrD,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,MAAM,cAAA,GAAiBA,UAAS,IAAA,KAAS,QAAA;AACzC,IAAA,MAAM,YAAA,GAAeA,UAAS,KAAA,CAAM,OAAA;AAGpC,IAAA,MAAM,WAAA,GAA8C,CAAC,KAAA,KAAU;AAC7D,MAAA,IAAI,QAAA,EAAU;AACZ,QAAA,KAAA,CAAM,cAAA,EAAe;AACrB,QAAA,KAAA,CAAM,eAAA,EAAgB;AACtB,QAAA;AAAA,MACF;AAEA,MAAA,OAAA,GAAU,KAAK,CAAA;AACf,MAAA,IAAI,CAAC,MAAM,gBAAA,EAAkB;AAC3B,QAAA,YAAA,GAAe,KAAK,CAAA;AAAA,MACtB;AAAA,IACF,CAAA;AAEA,IAAA,OAAOG,mBAAaH,SAAAA,EAAU;AAAA,MAC5B,GAAGC,KAAAA;AAAA,MACH,GAAGD,SAAAA,CAAS,KAAA;AAAA,MACZ,GAAI,QAAA,GACA,cAAA,GACE,EAAE,QAAA,EAAU,IAAA,EAAK,GACjB,EAAE,eAAA,EAAiB,IAAA,EAAM,QAAA,EAAU,EAAA,EAAG,GACxC,IAAA;AAAA,MACJ,WAAA,EAAa,QAAA;AAAA,MACb,OAAA,EAAS,WAAA;AAAA,MACT,SAAA,EAAWI,mBAAA;AAAA,QACTC,gCAAe,EAAE,UAAA,EAAAP,WAAAA,EAAY,IAAA,EAAAC,OAAM,CAAA;AAAA,QACnCC,UAAS,KAAA,CAAM,SAAA;AAAA,QACfH;AAAA;AACF,KACD,CAAA;AAAA,EACH;AAEA,EAAA,IAAI,KAAA,CAAM,OAAO,MAAA,EAAQ;AACvB,IAAA,MAAM;AAAA,MACJ,SAAA,EAAAA,UAAAA;AAAA,MACA,UAAA,EAAAC,WAAAA;AAAA,MACA,IAAA,EAAAC,KAAAA;AAAA,MACA,QAAA,EAAAC,SAAAA;AAAA,MACA,GAAA,EAAAM,IAAAA;AAAA,MACA,IAAA;AAAA,MACA,MAAA;AAAA,MACA,GAAGL;AAAA,KACL,GAAI,KAAA;AAEJ,IAAA,uBACEM,cAAA;AAAA,MAAC,GAAA;AAAA,MAAA;AAAA,QACC,GAAA,EAAKD,IAAAA;AAAA,QACL,IAAA;AAAA,QACA,MAAA;AAAA,QACA,GAAA,EAAK,MAAA,KAAW,QAAA,GAAW,qBAAA,GAAwB,MAAA;AAAA,QACnD,WAAA,EAAU,QAAA;AAAA,QACV,SAAA,EAAWF,mBAAA,CAAGC,+BAAA,CAAe,EAAE,UAAA,EAAAP,aAAY,IAAA,EAAAC,KAAAA,EAAM,CAAA,EAAGF,UAAS,CAAA;AAAA,QAC5D,GAAGI,KAAAA;AAAA,QAEH,QAAA,EAAAD;AAAA;AAAA,KACH;AAAA,EAEJ;AAEA,EAAA,MAAM;AAAA,IACJ,SAAA;AAAA,IACA,UAAA;AAAA,IACA,IAAA;AAAA,IACA,IAAA,GAAO,QAAA;AAAA,IACP,QAAA;AAAA,IACA,GAAA;AAAA,IACA,GAAG;AAAA,GACL,GAAI,KAAA;AAEJ,EAAA,uBACEO,cAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,GAAA;AAAA,MACA,IAAA;AAAA,MACA,WAAA,EAAU,QAAA;AAAA,MACV,SAAA,EAAWH,oBAAGC,+BAAA,CAAe,EAAE,YAAY,IAAA,EAAM,GAAG,SAAS,CAAA;AAAA,MAC5D,GAAG,IAAA;AAAA,MAEH;AAAA;AAAA,GACH;AAEJ,CAAA;AAEA,UAAA,CAAW,WAAA,GAAc,QAAA;AC3GlB,IAAM,MAAA,GAAS,CAAC,KAAA,KAAuB;AAC5C,EAAA,uBAAOE,cAAAA,CAAC,UAAA,EAAA,EAAY,GAAG,KAAA,EAAO,CAAA;AAChC;AAEA,MAAA,CAAO,WAAA,GAAc,QAAA","file":"chunk-OKCC7E36.js","sourcesContent":["\"use client\";\n\nimport { cloneElement, isValidElement, type MouseEventHandler } from \"react\";\n\nimport { cn } from \"../../lib/utils\";\n\nimport type { ButtonProps } from \"./types\";\nimport { buttonVariants } from \"./variants\";\n\nexport const ButtonBase = (props: ButtonProps) => {\n if (\"asChild\" in props && props.asChild) {\n const {\n className,\n appearance,\n size,\n children,\n asChild: _asChild,\n disabled,\n onClick,\n ...rest\n } = props;\n\n if (!isValidElement<{ className?: string }>(children)) {\n return null;\n }\n\n const isNativeButton = children.type === \"button\";\n const childOnClick = children.props.onClick as\n | MouseEventHandler<HTMLElement>\n | undefined;\n const handleClick: MouseEventHandler<HTMLElement> = (event) => {\n if (disabled) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n\n onClick?.(event);\n if (!event.defaultPrevented) {\n childOnClick?.(event);\n }\n };\n\n return cloneElement(children, {\n ...rest,\n ...children.props,\n ...(disabled\n ? isNativeButton\n ? { disabled: true }\n : { \"aria-disabled\": true, tabIndex: -1 }\n : null),\n \"data-slot\": \"button\",\n onClick: handleClick,\n className: cn(\n buttonVariants({ appearance, size }),\n children.props.className,\n className,\n ),\n });\n }\n\n if (props.as === \"link\") {\n const {\n className,\n appearance,\n size,\n children,\n ref,\n href,\n target,\n ...rest\n } = props;\n\n return (\n <a\n ref={ref}\n href={href}\n target={target}\n rel={target === \"_blank\" ? \"noopener noreferrer\" : undefined}\n data-slot=\"button\"\n className={cn(buttonVariants({ appearance, size }), className)}\n {...rest}\n >\n {children}\n </a>\n );\n }\n\n const {\n className,\n appearance,\n size,\n type = \"button\",\n children,\n ref,\n ...rest\n } = props;\n\n return (\n <button\n ref={ref}\n type={type}\n data-slot=\"button\"\n className={cn(buttonVariants({ appearance, size }), className)}\n {...rest}\n >\n {children}\n </button>\n );\n};\n\nButtonBase.displayName = \"Button\";\n","// button.tsx — default static entry (no framer-motion)\nimport { ButtonBase } from \"./button-base\";\nimport type { ButtonProps } from \"./types\";\n\nexport const Button = (props: ButtonProps) => {\n return <ButtonBase {...props} />;\n};\n\nButton.displayName = \"Button\";\n"]}
@@ -21,6 +21,9 @@ function mergeTargetOverrides(target, overrides) {
21
21
  ...blur === void 0 ? null : { filter: formatBlurValue(blur) }
22
22
  };
23
23
  }
24
+ function isTargetObject(target) {
25
+ return target !== null && typeof target === "object" && !Array.isArray(target);
26
+ }
24
27
  function createMotionAnimation(displayName, slot, preset) {
25
28
  function MotionAnimation(props) {
26
29
  const {
@@ -32,6 +35,7 @@ function createMotionAnimation(displayName, slot, preset) {
32
35
  transition,
33
36
  layout,
34
37
  whileHover,
38
+ whileInView,
35
39
  whileTap,
36
40
  from,
37
41
  to,
@@ -39,20 +43,27 @@ function createMotionAnimation(displayName, slot, preset) {
39
43
  ...rest
40
44
  } = props;
41
45
  const shouldReduceMotion = framerMotion.useReducedMotion();
42
- const resolvedAnimate = animate ?? mergeTargetOverrides(preset.animate, to);
43
- const resolvedInitial = initial ?? (shouldReduceMotion ? resolvedAnimate : mergeTargetOverrides(preset.initial, from));
46
+ const resolvedAnimateTarget = mergeTargetOverrides(preset.animate, to);
47
+ const resolvedAnimate = animate ?? resolvedAnimateTarget;
48
+ const shouldAnimateInView = whileInView !== void 0;
49
+ const usesPresetWhileInView = whileInView === true;
50
+ const resolvedWhileInView = whileInView === void 0 ? void 0 : usesPresetWhileInView ? resolvedAnimateTarget : isTargetObject(whileInView) ? { ...resolvedAnimateTarget, ...whileInView } : whileInView;
51
+ const reducedMotionTarget = shouldAnimateInView ? resolvedWhileInView : resolvedAnimate;
52
+ const resolvedInitial = initial ?? (shouldReduceMotion ? reducedMotionTarget : mergeTargetOverrides(preset.initial, from));
44
53
  const resolvedExit = exit ?? mergeTargetOverrides(preset.exit, exitTo);
45
54
  const resolvedTransition = transition ? { ...preset.transition, ...transition } : preset.transition;
55
+ const shouldDisableAnimate = usesPresetWhileInView || shouldReduceMotion && shouldAnimateInView;
46
56
  return /* @__PURE__ */ jsxRuntime.jsx(
47
57
  framerMotion.motion.div,
48
58
  {
49
59
  "data-slot": slot,
50
60
  className: chunkZS5756ZC_js.cn(className),
51
61
  initial: resolvedInitial,
52
- animate: resolvedAnimate,
62
+ animate: shouldDisableAnimate ? void 0 : resolvedAnimate,
53
63
  exit: resolvedExit,
54
64
  layout: layout ?? preset.layout,
55
65
  whileHover: whileHover ?? preset.whileHover,
66
+ whileInView: shouldReduceMotion ? void 0 : shouldAnimateInView ? resolvedWhileInView : void 0,
56
67
  whileTap: whileTap ?? preset.whileTap,
57
68
  transition: resolvedTransition,
58
69
  ...rest,
@@ -65,5 +76,5 @@ function createMotionAnimation(displayName, slot, preset) {
65
76
  }
66
77
 
67
78
  exports.createMotionAnimation = createMotionAnimation;
68
- //# sourceMappingURL=chunk-ODZM25II.js.map
69
- //# sourceMappingURL=chunk-ODZM25II.js.map
79
+ //# sourceMappingURL=chunk-R5LL56ZO.js.map
80
+ //# sourceMappingURL=chunk-R5LL56ZO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/animations/shared/create-motion-animation.tsx"],"names":["useReducedMotion","jsx","motion","cn"],"mappings":"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","file":"chunk-R5LL56ZO.js","sourcesContent":["\"use client\";\n\nimport { motion, useReducedMotion } from \"framer-motion\";\n\nimport { cn } from \"../../lib/utils\";\n\nimport type {\n MotionAnimationPreset,\n MotionAnimationProps,\n MotionAnimationTargetOverrides,\n} from \"./types\";\n\nfunction formatBlurValue(value: number | string) {\n if (typeof value === \"number\") {\n return `blur(${value}px)`;\n }\n return value.includes(\"(\") ? value : `blur(${value})`;\n}\n\nfunction mergeTargetOverrides(\n target: MotionAnimationPreset[\"initial\"] | undefined,\n overrides: MotionAnimationTargetOverrides | undefined,\n) {\n if (!overrides) {\n return target;\n }\n\n const { blur, ...rest } = overrides;\n return {\n ...(target ?? {}),\n ...rest,\n ...(blur === undefined ? null : { filter: formatBlurValue(blur) }),\n };\n}\n\nfunction isTargetObject(\n target: NonNullable<MotionAnimationProps[\"whileInView\"]>,\n): target is MotionAnimationPreset[\"animate\"] {\n return target !== null && typeof target === \"object\" && !Array.isArray(target);\n}\n\nexport function createMotionAnimation(\n displayName: string,\n slot: string,\n preset: MotionAnimationPreset,\n) {\n function MotionAnimation(props: MotionAnimationProps) {\n const {\n children,\n className,\n initial,\n animate,\n exit,\n transition,\n layout,\n whileHover,\n whileInView,\n whileTap,\n from,\n to,\n exitTo,\n ...rest\n } = props;\n const shouldReduceMotion = useReducedMotion();\n const resolvedAnimateTarget = mergeTargetOverrides(preset.animate, to);\n const resolvedAnimate = animate ?? resolvedAnimateTarget;\n const shouldAnimateInView = whileInView !== undefined;\n const usesPresetWhileInView = whileInView === true;\n const resolvedWhileInView =\n whileInView === undefined\n ? undefined\n : usesPresetWhileInView\n ? resolvedAnimateTarget\n : isTargetObject(whileInView)\n ? { ...resolvedAnimateTarget, ...whileInView }\n : whileInView;\n const reducedMotionTarget = shouldAnimateInView\n ? resolvedWhileInView\n : resolvedAnimate;\n const resolvedInitial =\n initial ??\n (shouldReduceMotion\n ? reducedMotionTarget\n : mergeTargetOverrides(preset.initial, from));\n const resolvedExit = exit ?? mergeTargetOverrides(preset.exit, exitTo);\n const resolvedTransition = transition\n ? { ...preset.transition, ...transition }\n : preset.transition;\n const shouldDisableAnimate =\n usesPresetWhileInView || (shouldReduceMotion && shouldAnimateInView);\n\n return (\n <motion.div\n data-slot={slot}\n className={cn(className)}\n initial={resolvedInitial}\n animate={shouldDisableAnimate ? undefined : resolvedAnimate}\n exit={resolvedExit}\n layout={layout ?? preset.layout}\n whileHover={whileHover ?? preset.whileHover}\n whileInView={\n shouldReduceMotion\n ? undefined\n : shouldAnimateInView\n ? resolvedWhileInView\n : undefined\n }\n whileTap={whileTap ?? preset.whileTap}\n transition={resolvedTransition}\n {...rest}\n >\n {children}\n </motion.div>\n );\n }\n\n MotionAnimation.displayName = displayName;\n return MotionAnimation;\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import type { ButtonProps } from "./types";
2
2
  export declare const ButtonBase: {
3
- (props: ButtonProps): import("react/jsx-runtime").JSX.Element;
3
+ (props: ButtonProps): import("react/jsx-runtime").JSX.Element | null;
4
4
  displayName: string;
5
5
  };
6
6
  //# sourceMappingURL=button-base.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"button-base.d.ts","sourceRoot":"","sources":["../../../src/ui/buttons/button-base.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAG3C,eAAO,MAAM,UAAU;YAAW,WAAW;;CAiD5C,CAAC"}
1
+ {"version":3,"file":"button-base.d.ts","sourceRoot":"","sources":["../../../src/ui/buttons/button-base.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAG3C,eAAO,MAAM,UAAU;YAAW,WAAW;;CAoG5C,CAAC"}
@@ -1,10 +1,24 @@
1
1
  import type { VariantProps } from "class-variance-authority";
2
- import type { ComponentPropsWithRef } from "react";
2
+ import type { ComponentPropsWithRef, MouseEventHandler, ReactElement } from "react";
3
3
  import type { buttonVariants } from "./variants";
4
4
  export type ButtonSharedStatic = VariantProps<typeof buttonVariants>;
5
- export type ButtonProps = (ButtonSharedStatic & ComponentPropsWithRef<"button"> & {
5
+ export type ButtonProps = (ButtonSharedStatic & Omit<ComponentPropsWithRef<"button">, "children" | "onClick" | "ref" | "type"> & {
6
+ asChild: true;
7
+ as?: never;
8
+ children: ReactElement<{
9
+ "aria-disabled"?: boolean | "false" | "true";
10
+ className?: string;
11
+ "data-slot"?: string;
12
+ disabled?: boolean;
13
+ onClick?: MouseEventHandler<HTMLElement>;
14
+ tabIndex?: number;
15
+ }>;
16
+ onClick?: MouseEventHandler<HTMLElement>;
17
+ }) | (ButtonSharedStatic & ComponentPropsWithRef<"button"> & {
6
18
  as?: "button";
19
+ asChild?: false;
7
20
  }) | (ButtonSharedStatic & ComponentPropsWithRef<"a"> & {
8
21
  as: "link";
22
+ asChild?: false;
9
23
  });
10
24
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/ui/buttons/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,OAAO,CAAC;AAEnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,MAAM,kBAAkB,GAAG,YAAY,CAAC,OAAO,cAAc,CAAC,CAAC;AAErE,MAAM,MAAM,WAAW,GACnB,CAAC,kBAAkB,GACjB,qBAAqB,CAAC,QAAQ,CAAC,GAAG;IAChC,EAAE,CAAC,EAAE,QAAQ,CAAC;CACf,CAAC,GACJ,CAAC,kBAAkB,GAAG,qBAAqB,CAAC,GAAG,CAAC,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/ui/buttons/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EACV,qBAAqB,EACrB,iBAAiB,EACjB,YAAY,EACb,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,MAAM,kBAAkB,GAAG,YAAY,CAAC,OAAO,cAAc,CAAC,CAAC;AAErE,MAAM,MAAM,WAAW,GACnB,CAAC,kBAAkB,GACjB,IAAI,CACF,qBAAqB,CAAC,QAAQ,CAAC,EAC/B,UAAU,GAAG,SAAS,GAAG,KAAK,GAAG,MAAM,CACxC,GAAG;IACF,OAAO,EAAE,IAAI,CAAC;IACd,EAAE,CAAC,EAAE,KAAK,CAAC;IACX,QAAQ,EAAE,YAAY,CAAC;QACrB,eAAe,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;QAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,OAAO,CAAC,EAAE,iBAAiB,CAAC,WAAW,CAAC,CAAC;QACzC,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC,CAAC;IACH,OAAO,CAAC,EAAE,iBAAiB,CAAC,WAAW,CAAC,CAAC;CAC1C,CAAC,GACJ,CAAC,kBAAkB,GACjB,qBAAqB,CAAC,QAAQ,CAAC,GAAG;IAChC,EAAE,CAAC,EAAE,QAAQ,CAAC;IACd,OAAO,CAAC,EAAE,KAAK,CAAC;CACjB,CAAC,GACJ,CAAC,kBAAkB,GACjB,qBAAqB,CAAC,GAAG,CAAC,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC,CAAC"}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
- var chunkJFS5PJSH_js = require('../chunk-JFS5PJSH.js');
4
+ var chunkOKCC7E36_js = require('../chunk-OKCC7E36.js');
5
5
  var chunk466QDL44_js = require('../chunk-466QDL44.js');
6
6
  require('../chunk-MUP7DVQR.js');
7
7
  require('../chunk-ZS5756ZC.js');
@@ -10,7 +10,7 @@ require('../chunk-ZS5756ZC.js');
10
10
 
11
11
  Object.defineProperty(exports, "Button", {
12
12
  enumerable: true,
13
- get: function () { return chunkJFS5PJSH_js.Button; }
13
+ get: function () { return chunkOKCC7E36_js.Button; }
14
14
  });
15
15
  Object.defineProperty(exports, "buttonVariants", {
16
16
  enumerable: true,
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- export { Button } from '../chunk-VARQ7W4G.mjs';
2
+ export { Button } from '../chunk-C6NA452Q.mjs';
3
3
  export { buttonVariants } from '../chunk-CIEZFHCO.mjs';
4
4
  import '../chunk-4ZP444GA.mjs';
5
5
  import '../chunk-4D54YOL6.mjs';
@@ -3,7 +3,7 @@
3
3
 
4
4
  var chunkVMCOX3Z2_js = require('../chunk-VMCOX3Z2.js');
5
5
  require('../chunk-HPN7H5ZM.js');
6
- var chunkJFS5PJSH_js = require('../chunk-JFS5PJSH.js');
6
+ var chunkOKCC7E36_js = require('../chunk-OKCC7E36.js');
7
7
  require('../chunk-466QDL44.js');
8
8
  require('../chunk-MUP7DVQR.js');
9
9
  var chunkZS5756ZC_js = require('../chunk-ZS5756ZC.js');
@@ -215,7 +215,7 @@ var DynamicStepper = ({
215
215
  ...rest,
216
216
  children: [
217
217
  /* @__PURE__ */ jsxRuntime.jsx(
218
- chunkJFS5PJSH_js.Button,
218
+ chunkOKCC7E36_js.Button,
219
219
  {
220
220
  id: previousId,
221
221
  "data-slot": "dynamic-stepper-previous",
@@ -294,7 +294,7 @@ var DynamicStepper = ({
294
294
  }
295
295
  ),
296
296
  /* @__PURE__ */ jsxRuntime.jsx(
297
- chunkJFS5PJSH_js.Button,
297
+ chunkOKCC7E36_js.Button,
298
298
  {
299
299
  id: nextId,
300
300
  "data-slot": "dynamic-stepper-next",
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { useDynamicStepper } from '../chunk-4MPNRGUA.mjs';
3
3
  import '../chunk-NWOE2TZN.mjs';
4
- import { Button } from '../chunk-VARQ7W4G.mjs';
4
+ import { Button } from '../chunk-C6NA452Q.mjs';
5
5
  import '../chunk-CIEZFHCO.mjs';
6
6
  import '../chunk-4ZP444GA.mjs';
7
7
  import { cn } from '../chunk-4D54YOL6.mjs';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zentauri-ui/zentauri-components",
3
- "version": "1.8.4",
3
+ "version": "1.8.41",
4
4
  "description": "React + Tailwind UI kit with charts, ESM/CJS builds, per-entry exports, and a zentauri-components / zentauri-ui CLI to vendor UI or hook source into your app",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -1,5 +1,59 @@
1
1
  import { render, screen } from "@testing-library/react";
2
- import { describe, expect, it } from "vitest";
2
+ import { beforeEach, describe, expect, it, vi } from "vitest";
3
+
4
+ const motionMockState = vi.hoisted(() => ({
5
+ shouldReduceMotion: false,
6
+ }));
7
+
8
+ vi.mock("framer-motion", async () => {
9
+ const React = await import("react");
10
+
11
+ function serializeMotionValue(value: unknown) {
12
+ return value === undefined ? "undefined" : JSON.stringify(value);
13
+ }
14
+
15
+ return {
16
+ motion: {
17
+ div: React.forwardRef<HTMLDivElement, Record<string, unknown>>(
18
+ (
19
+ {
20
+ animate,
21
+ children,
22
+ exit,
23
+ initial,
24
+ layout,
25
+ transition,
26
+ viewport,
27
+ whileHover,
28
+ whileInView,
29
+ whileTap,
30
+ ...props
31
+ },
32
+ ref,
33
+ ) =>
34
+ React.createElement(
35
+ "div",
36
+ {
37
+ ...props,
38
+ ref,
39
+ "data-motion-animate": serializeMotionValue(animate),
40
+ "data-motion-exit": serializeMotionValue(exit),
41
+ "data-motion-initial": serializeMotionValue(initial),
42
+ "data-motion-layout": serializeMotionValue(layout),
43
+ "data-motion-transition": serializeMotionValue(transition),
44
+ "data-motion-viewport": serializeMotionValue(viewport),
45
+ "data-motion-while-hover": serializeMotionValue(whileHover),
46
+ "data-motion-while-in-view":
47
+ serializeMotionValue(whileInView),
48
+ "data-motion-while-tap": serializeMotionValue(whileTap),
49
+ },
50
+ children as React.ReactNode,
51
+ ),
52
+ ),
53
+ },
54
+ useReducedMotion: () => motionMockState.shouldReduceMotion,
55
+ };
56
+ });
3
57
 
4
58
  import { BlurIn } from "./blur-in";
5
59
  import { BlurOut } from "./blur-out";
@@ -88,6 +142,10 @@ const animations = [
88
142
  ] as const;
89
143
 
90
144
  describe("animation primitives", () => {
145
+ beforeEach(() => {
146
+ motionMockState.shouldReduceMotion = false;
147
+ });
148
+
91
149
  for (const [displayName, Component, slot] of animations) {
92
150
  it(`${displayName} stamps the animation slot and forwards content`, () => {
93
151
  render(<Component className="custom-motion">Preview</Component>);
@@ -126,4 +184,58 @@ describe("animation primitives", () => {
126
184
  expect(root).not.toHaveAttribute("to");
127
185
  expect(root).not.toHaveAttribute("exitTo");
128
186
  });
187
+
188
+ it("can defer the preset animate target until the element enters the viewport", () => {
189
+ render(
190
+ <FadeUp viewport={{ once: true, amount: 0.35 }} whileInView>
191
+ Viewport gated
192
+ </FadeUp>,
193
+ );
194
+
195
+ const root = screen.getByText("Viewport gated");
196
+
197
+ expect(root).toHaveAttribute("data-motion-animate", "undefined");
198
+ expect(root).toHaveAttribute(
199
+ "data-motion-while-in-view",
200
+ JSON.stringify({ opacity: 1, y: 0 }),
201
+ );
202
+ expect(root).toHaveAttribute(
203
+ "data-motion-viewport",
204
+ JSON.stringify({ once: true, amount: 0.35 }),
205
+ );
206
+ });
207
+
208
+ it("keeps the preset animate target when whileInView receives a custom target", () => {
209
+ render(
210
+ <FadeUp whileInView={{ scale: 1.05 }}>Custom viewport target</FadeUp>,
211
+ );
212
+
213
+ const root = screen.getByText("Custom viewport target");
214
+
215
+ expect(root).toHaveAttribute(
216
+ "data-motion-animate",
217
+ JSON.stringify({ opacity: 1, y: 0 }),
218
+ );
219
+ expect(root).toHaveAttribute(
220
+ "data-motion-while-in-view",
221
+ JSON.stringify({ opacity: 1, y: 0, scale: 1.05 }),
222
+ );
223
+ });
224
+
225
+ it("renders the effective whileInView target immediately when motion is reduced", () => {
226
+ motionMockState.shouldReduceMotion = true;
227
+
228
+ render(
229
+ <FadeUp whileInView={{ scale: 1.05 }}>Reduced viewport target</FadeUp>,
230
+ );
231
+
232
+ const root = screen.getByText("Reduced viewport target");
233
+
234
+ expect(root).toHaveAttribute(
235
+ "data-motion-initial",
236
+ JSON.stringify({ opacity: 1, y: 0, scale: 1.05 }),
237
+ );
238
+ expect(root).toHaveAttribute("data-motion-animate", "undefined");
239
+ expect(root).toHaveAttribute("data-motion-while-in-view", "undefined");
240
+ });
129
241
  });
@@ -33,6 +33,12 @@ function mergeTargetOverrides(
33
33
  };
34
34
  }
35
35
 
36
+ function isTargetObject(
37
+ target: NonNullable<MotionAnimationProps["whileInView"]>,
38
+ ): target is MotionAnimationPreset["animate"] {
39
+ return target !== null && typeof target === "object" && !Array.isArray(target);
40
+ }
41
+
36
42
  export function createMotionAnimation(
37
43
  displayName: string,
38
44
  slot: string,
@@ -48,6 +54,7 @@ export function createMotionAnimation(
48
54
  transition,
49
55
  layout,
50
56
  whileHover,
57
+ whileInView,
51
58
  whileTap,
52
59
  from,
53
60
  to,
@@ -55,26 +62,49 @@ export function createMotionAnimation(
55
62
  ...rest
56
63
  } = props;
57
64
  const shouldReduceMotion = useReducedMotion();
58
- const resolvedAnimate = animate ?? mergeTargetOverrides(preset.animate, to);
65
+ const resolvedAnimateTarget = mergeTargetOverrides(preset.animate, to);
66
+ const resolvedAnimate = animate ?? resolvedAnimateTarget;
67
+ const shouldAnimateInView = whileInView !== undefined;
68
+ const usesPresetWhileInView = whileInView === true;
69
+ const resolvedWhileInView =
70
+ whileInView === undefined
71
+ ? undefined
72
+ : usesPresetWhileInView
73
+ ? resolvedAnimateTarget
74
+ : isTargetObject(whileInView)
75
+ ? { ...resolvedAnimateTarget, ...whileInView }
76
+ : whileInView;
77
+ const reducedMotionTarget = shouldAnimateInView
78
+ ? resolvedWhileInView
79
+ : resolvedAnimate;
59
80
  const resolvedInitial =
60
81
  initial ??
61
82
  (shouldReduceMotion
62
- ? resolvedAnimate
83
+ ? reducedMotionTarget
63
84
  : mergeTargetOverrides(preset.initial, from));
64
85
  const resolvedExit = exit ?? mergeTargetOverrides(preset.exit, exitTo);
65
86
  const resolvedTransition = transition
66
87
  ? { ...preset.transition, ...transition }
67
88
  : preset.transition;
89
+ const shouldDisableAnimate =
90
+ usesPresetWhileInView || (shouldReduceMotion && shouldAnimateInView);
68
91
 
69
92
  return (
70
93
  <motion.div
71
94
  data-slot={slot}
72
95
  className={cn(className)}
73
96
  initial={resolvedInitial}
74
- animate={resolvedAnimate}
97
+ animate={shouldDisableAnimate ? undefined : resolvedAnimate}
75
98
  exit={resolvedExit}
76
99
  layout={layout ?? preset.layout}
77
100
  whileHover={whileHover ?? preset.whileHover}
101
+ whileInView={
102
+ shouldReduceMotion
103
+ ? undefined
104
+ : shouldAnimateInView
105
+ ? resolvedWhileInView
106
+ : undefined
107
+ }
78
108
  whileTap={whileTap ?? preset.whileTap}
79
109
  transition={resolvedTransition}
80
110
  {...rest}
@@ -1,2 +1,6 @@
1
1
  export { createMotionAnimation } from "./create-motion-animation";
2
- export type { MotionAnimationPreset, MotionAnimationProps } from "./types";
2
+ export type {
3
+ MotionAnimationPreset,
4
+ MotionAnimationProps,
5
+ MotionAnimationWhileInView,
6
+ } from "./types";
@@ -27,8 +27,16 @@ export type MotionAnimationTargetOverrides = {
27
27
  blur?: number | string;
28
28
  };
29
29
 
30
- export type MotionAnimationProps = HTMLMotionProps<"div"> & {
30
+ export type MotionAnimationWhileInView =
31
+ | true
32
+ | HTMLMotionProps<"div">["whileInView"];
33
+
34
+ export type MotionAnimationProps = Omit<
35
+ HTMLMotionProps<"div">,
36
+ "whileInView"
37
+ > & {
31
38
  from?: MotionAnimationTargetOverrides;
32
39
  to?: MotionAnimationTargetOverrides;
33
40
  exitTo?: MotionAnimationTargetOverrides;
41
+ whileInView?: MotionAnimationWhileInView;
34
42
  };
@@ -1,11 +1,64 @@
1
1
  "use client";
2
2
 
3
+ import { cloneElement, isValidElement, type MouseEventHandler } from "react";
4
+
3
5
  import { cn } from "../../lib/utils";
4
6
 
5
7
  import type { ButtonProps } from "./types";
6
8
  import { buttonVariants } from "./variants";
7
9
 
8
10
  export const ButtonBase = (props: ButtonProps) => {
11
+ if ("asChild" in props && props.asChild) {
12
+ const {
13
+ className,
14
+ appearance,
15
+ size,
16
+ children,
17
+ asChild: _asChild,
18
+ disabled,
19
+ onClick,
20
+ ...rest
21
+ } = props;
22
+
23
+ if (!isValidElement<{ className?: string }>(children)) {
24
+ return null;
25
+ }
26
+
27
+ const isNativeButton = children.type === "button";
28
+ const childOnClick = children.props.onClick as
29
+ | MouseEventHandler<HTMLElement>
30
+ | undefined;
31
+ const handleClick: MouseEventHandler<HTMLElement> = (event) => {
32
+ if (disabled) {
33
+ event.preventDefault();
34
+ event.stopPropagation();
35
+ return;
36
+ }
37
+
38
+ onClick?.(event);
39
+ if (!event.defaultPrevented) {
40
+ childOnClick?.(event);
41
+ }
42
+ };
43
+
44
+ return cloneElement(children, {
45
+ ...rest,
46
+ ...children.props,
47
+ ...(disabled
48
+ ? isNativeButton
49
+ ? { disabled: true }
50
+ : { "aria-disabled": true, tabIndex: -1 }
51
+ : null),
52
+ "data-slot": "button",
53
+ onClick: handleClick,
54
+ className: cn(
55
+ buttonVariants({ appearance, size }),
56
+ children.props.className,
57
+ className,
58
+ ),
59
+ });
60
+ }
61
+
9
62
  if (props.as === "link") {
10
63
  const {
11
64
  className,
@@ -449,6 +449,46 @@ describe("Button (component library)", () => {
449
449
  "Link mode must keep the same data-slot contract",
450
450
  ).toBe("A");
451
451
  });
452
+
453
+ it("should style a child anchor without replacing its navigation props", () => {
454
+ render(
455
+ <Button asChild appearance="gradient-teal" size="lg">
456
+ <a href="/preview/installation">Get started</a>
457
+ </Button>,
458
+ );
459
+ const link = screen.getByRole("link", { name: "Get started" });
460
+
461
+ expect(link).toBe(getButtonSlot());
462
+ expect(link).toHaveAttribute("href", "/preview/installation");
463
+ expect(link.className).toMatch(/gradient-teal/);
464
+ });
465
+
466
+ it("should make disabled child anchors inert", async () => {
467
+ const user = userEvent.setup();
468
+ const onClick = vi.fn();
469
+ render(
470
+ <Button asChild disabled onClick={onClick}>
471
+ <a href="/preview/installation">Get started</a>
472
+ </Button>,
473
+ );
474
+ const link = screen.getByRole("link", { name: "Get started" });
475
+
476
+ expect(link).not.toHaveAttribute("disabled");
477
+ expect(link).toHaveAttribute("aria-disabled", "true");
478
+ expect(link).toHaveAttribute("tabindex", "-1");
479
+
480
+ await user.click(link);
481
+ expect(onClick).not.toHaveBeenCalled();
482
+ });
483
+
484
+ it("should forward disabled to native button children", () => {
485
+ render(
486
+ <Button asChild disabled>
487
+ <button type="button">Submit</button>
488
+ </Button>,
489
+ );
490
+ expect(screen.getByRole("button", { name: "Submit" })).toBeDisabled();
491
+ });
452
492
  });
453
493
 
454
494
  describe("props: animation presets (smoke)", () => {
@@ -1,13 +1,36 @@
1
1
  import type { VariantProps } from "class-variance-authority";
2
- import type { ComponentPropsWithRef } from "react";
2
+ import type {
3
+ ComponentPropsWithRef,
4
+ MouseEventHandler,
5
+ ReactElement,
6
+ } from "react";
3
7
 
4
8
  import type { buttonVariants } from "./variants";
5
9
 
6
10
  export type ButtonSharedStatic = VariantProps<typeof buttonVariants>;
7
11
 
8
12
  export type ButtonProps =
13
+ | (ButtonSharedStatic &
14
+ Omit<
15
+ ComponentPropsWithRef<"button">,
16
+ "children" | "onClick" | "ref" | "type"
17
+ > & {
18
+ asChild: true;
19
+ as?: never;
20
+ children: ReactElement<{
21
+ "aria-disabled"?: boolean | "false" | "true";
22
+ className?: string;
23
+ "data-slot"?: string;
24
+ disabled?: boolean;
25
+ onClick?: MouseEventHandler<HTMLElement>;
26
+ tabIndex?: number;
27
+ }>;
28
+ onClick?: MouseEventHandler<HTMLElement>;
29
+ })
9
30
  | (ButtonSharedStatic &
10
31
  ComponentPropsWithRef<"button"> & {
11
32
  as?: "button";
33
+ asChild?: false;
12
34
  })
13
- | (ButtonSharedStatic & ComponentPropsWithRef<"a"> & { as: "link" });
35
+ | (ButtonSharedStatic &
36
+ ComponentPropsWithRef<"a"> & { as: "link"; asChild?: false });
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/animations/shared/create-motion-animation.tsx"],"names":[],"mappings":";;;;AAYA,SAAS,gBAAgB,KAAA,EAAwB;AAC/C,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,OAAO,QAAQ,KAAK,CAAA,GAAA,CAAA;AAAA,EACtB;AACA,EAAA,OAAO,MAAM,QAAA,CAAS,GAAG,CAAA,GAAI,KAAA,GAAQ,QAAQ,KAAK,CAAA,CAAA,CAAA;AACpD;AAEA,SAAS,oBAAA,CACP,QACA,SAAA,EACA;AACA,EAAA,IAAI,CAAC,SAAA,EAAW;AACd,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,MAAM,EAAE,IAAA,EAAM,GAAG,IAAA,EAAK,GAAI,SAAA;AAC1B,EAAA,OAAO;AAAA,IACL,GAAI,UAAU,EAAC;AAAA,IACf,GAAG,IAAA;AAAA,IACH,GAAI,SAAS,MAAA,GAAY,IAAA,GAAO,EAAE,MAAA,EAAQ,eAAA,CAAgB,IAAI,CAAA;AAAE,GAClE;AACF;AAEO,SAAS,qBAAA,CACd,WAAA,EACA,IAAA,EACA,MAAA,EACA;AACA,EAAA,SAAS,gBAAgB,KAAA,EAA6B;AACpD,IAAA,MAAM;AAAA,MACJ,QAAA;AAAA,MACA,SAAA;AAAA,MACA,OAAA;AAAA,MACA,OAAA;AAAA,MACA,IAAA;AAAA,MACA,UAAA;AAAA,MACA,MAAA;AAAA,MACA,UAAA;AAAA,MACA,QAAA;AAAA,MACA,IAAA;AAAA,MACA,EAAA;AAAA,MACA,MAAA;AAAA,MACA,GAAG;AAAA,KACL,GAAI,KAAA;AACJ,IAAA,MAAM,qBAAqB,gBAAA,EAAiB;AAC5C,IAAA,MAAM,eAAA,GAAkB,OAAA,IAAW,oBAAA,CAAqB,MAAA,CAAO,SAAS,EAAE,CAAA;AAC1E,IAAA,MAAM,kBACJ,OAAA,KACC,kBAAA,GACG,kBACA,oBAAA,CAAqB,MAAA,CAAO,SAAS,IAAI,CAAA,CAAA;AAC/C,IAAA,MAAM,YAAA,GAAe,IAAA,IAAQ,oBAAA,CAAqB,MAAA,CAAO,MAAM,MAAM,CAAA;AACrE,IAAA,MAAM,kBAAA,GAAqB,aACvB,EAAE,GAAG,OAAO,UAAA,EAAY,GAAG,UAAA,EAAW,GACtC,MAAA,CAAO,UAAA;AAEX,IAAA,uBACE,GAAA;AAAA,MAAC,MAAA,CAAO,GAAA;AAAA,MAAP;AAAA,QACC,WAAA,EAAW,IAAA;AAAA,QACX,SAAA,EAAW,GAAG,SAAS,CAAA;AAAA,QACvB,OAAA,EAAS,eAAA;AAAA,QACT,OAAA,EAAS,eAAA;AAAA,QACT,IAAA,EAAM,YAAA;AAAA,QACN,MAAA,EAAQ,UAAU,MAAA,CAAO,MAAA;AAAA,QACzB,UAAA,EAAY,cAAc,MAAA,CAAO,UAAA;AAAA,QACjC,QAAA,EAAU,YAAY,MAAA,CAAO,QAAA;AAAA,QAC7B,UAAA,EAAY,kBAAA;AAAA,QACX,GAAG,IAAA;AAAA,QAEH;AAAA;AAAA,KACH;AAAA,EAEJ;AAEA,EAAA,eAAA,CAAgB,WAAA,GAAc,WAAA;AAC9B,EAAA,OAAO,eAAA;AACT","file":"chunk-AACGI7FX.mjs","sourcesContent":["\"use client\";\n\nimport { motion, useReducedMotion } from \"framer-motion\";\n\nimport { cn } from \"../../lib/utils\";\n\nimport type {\n MotionAnimationPreset,\n MotionAnimationProps,\n MotionAnimationTargetOverrides,\n} from \"./types\";\n\nfunction formatBlurValue(value: number | string) {\n if (typeof value === \"number\") {\n return `blur(${value}px)`;\n }\n return value.includes(\"(\") ? value : `blur(${value})`;\n}\n\nfunction mergeTargetOverrides(\n target: MotionAnimationPreset[\"initial\"] | undefined,\n overrides: MotionAnimationTargetOverrides | undefined,\n) {\n if (!overrides) {\n return target;\n }\n\n const { blur, ...rest } = overrides;\n return {\n ...(target ?? {}),\n ...rest,\n ...(blur === undefined ? null : { filter: formatBlurValue(blur) }),\n };\n}\n\nexport function createMotionAnimation(\n displayName: string,\n slot: string,\n preset: MotionAnimationPreset,\n) {\n function MotionAnimation(props: MotionAnimationProps) {\n const {\n children,\n className,\n initial,\n animate,\n exit,\n transition,\n layout,\n whileHover,\n whileTap,\n from,\n to,\n exitTo,\n ...rest\n } = props;\n const shouldReduceMotion = useReducedMotion();\n const resolvedAnimate = animate ?? mergeTargetOverrides(preset.animate, to);\n const resolvedInitial =\n initial ??\n (shouldReduceMotion\n ? resolvedAnimate\n : mergeTargetOverrides(preset.initial, from));\n const resolvedExit = exit ?? mergeTargetOverrides(preset.exit, exitTo);\n const resolvedTransition = transition\n ? { ...preset.transition, ...transition }\n : preset.transition;\n\n return (\n <motion.div\n data-slot={slot}\n className={cn(className)}\n initial={resolvedInitial}\n animate={resolvedAnimate}\n exit={resolvedExit}\n layout={layout ?? preset.layout}\n whileHover={whileHover ?? preset.whileHover}\n whileTap={whileTap ?? preset.whileTap}\n transition={resolvedTransition}\n {...rest}\n >\n {children}\n </motion.div>\n );\n }\n\n MotionAnimation.displayName = displayName;\n return MotionAnimation;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/ui/buttons/button-base.tsx","../src/ui/buttons/button.tsx"],"names":["className","appearance","size","children","ref","rest","jsx","cn","buttonVariants"],"mappings":";;;;;;AAOO,IAAM,UAAA,GAAa,CAAC,KAAA,KAAuB;AAChD,EAAA,IAAI,KAAA,CAAM,OAAO,MAAA,EAAQ;AACvB,IAAA,MAAM;AAAA,MACJ,SAAA,EAAAA,UAAAA;AAAA,MACA,UAAA,EAAAC,WAAAA;AAAA,MACA,IAAA,EAAAC,KAAAA;AAAA,MACA,QAAA,EAAAC,SAAAA;AAAA,MACA,GAAA,EAAAC,IAAAA;AAAA,MACA,IAAA;AAAA,MACA,MAAA;AAAA,MACA,GAAGC;AAAA,KACL,GAAI,KAAA;AAEJ,IAAA,uBACEC,cAAA;AAAA,MAAC,GAAA;AAAA,MAAA;AAAA,QACC,GAAA,EAAKF,IAAAA;AAAA,QACL,IAAA;AAAA,QACA,MAAA;AAAA,QACA,GAAA,EAAK,MAAA,KAAW,QAAA,GAAW,qBAAA,GAAwB,MAAA;AAAA,QACnD,WAAA,EAAU,QAAA;AAAA,QACV,SAAA,EAAWG,mBAAA,CAAGC,+BAAA,CAAe,EAAE,UAAA,EAAAP,aAAY,IAAA,EAAAC,KAAAA,EAAM,CAAA,EAAGF,UAAS,CAAA;AAAA,QAC5D,GAAGK,KAAAA;AAAA,QAEH,QAAA,EAAAF;AAAA;AAAA,KACH;AAAA,EAEJ;AAEA,EAAA,MAAM;AAAA,IACJ,SAAA;AAAA,IACA,UAAA;AAAA,IACA,IAAA;AAAA,IACA,IAAA,GAAO,QAAA;AAAA,IACP,QAAA;AAAA,IACA,GAAA;AAAA,IACA,GAAG;AAAA,GACL,GAAI,KAAA;AAEJ,EAAA,uBACEG,cAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,GAAA;AAAA,MACA,IAAA;AAAA,MACA,WAAA,EAAU,QAAA;AAAA,MACV,SAAA,EAAWC,oBAAGC,+BAAA,CAAe,EAAE,YAAY,IAAA,EAAM,GAAG,SAAS,CAAA;AAAA,MAC5D,GAAG,IAAA;AAAA,MAEH;AAAA;AAAA,GACH;AAEJ,CAAA;AAEA,UAAA,CAAW,WAAA,GAAc,QAAA;ACtDlB,IAAM,MAAA,GAAS,CAAC,KAAA,KAAuB;AAC5C,EAAA,uBAAOF,cAAAA,CAAC,UAAA,EAAA,EAAY,GAAG,KAAA,EAAO,CAAA;AAChC;AAEA,MAAA,CAAO,WAAA,GAAc,QAAA","file":"chunk-JFS5PJSH.js","sourcesContent":["\"use client\";\n\nimport { cn } from \"../../lib/utils\";\n\nimport type { ButtonProps } from \"./types\";\nimport { buttonVariants } from \"./variants\";\n\nexport const ButtonBase = (props: ButtonProps) => {\n if (props.as === \"link\") {\n const {\n className,\n appearance,\n size,\n children,\n ref,\n href,\n target,\n ...rest\n } = props;\n\n return (\n <a\n ref={ref}\n href={href}\n target={target}\n rel={target === \"_blank\" ? \"noopener noreferrer\" : undefined}\n data-slot=\"button\"\n className={cn(buttonVariants({ appearance, size }), className)}\n {...rest}\n >\n {children}\n </a>\n );\n }\n\n const {\n className,\n appearance,\n size,\n type = \"button\",\n children,\n ref,\n ...rest\n } = props;\n\n return (\n <button\n ref={ref}\n type={type}\n data-slot=\"button\"\n className={cn(buttonVariants({ appearance, size }), className)}\n {...rest}\n >\n {children}\n </button>\n );\n};\n\nButtonBase.displayName = \"Button\";\n","// button.tsx — default static entry (no framer-motion)\nimport { ButtonBase } from \"./button-base\";\nimport type { ButtonProps } from \"./types\";\n\nexport const Button = (props: ButtonProps) => {\n return <ButtonBase {...props} />;\n};\n\nButton.displayName = \"Button\";\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/animations/shared/create-motion-animation.tsx"],"names":["useReducedMotion","jsx","motion","cn"],"mappings":";;;;;;AAYA,SAAS,gBAAgB,KAAA,EAAwB;AAC/C,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,OAAO,QAAQ,KAAK,CAAA,GAAA,CAAA;AAAA,EACtB;AACA,EAAA,OAAO,MAAM,QAAA,CAAS,GAAG,CAAA,GAAI,KAAA,GAAQ,QAAQ,KAAK,CAAA,CAAA,CAAA;AACpD;AAEA,SAAS,oBAAA,CACP,QACA,SAAA,EACA;AACA,EAAA,IAAI,CAAC,SAAA,EAAW;AACd,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,MAAM,EAAE,IAAA,EAAM,GAAG,IAAA,EAAK,GAAI,SAAA;AAC1B,EAAA,OAAO;AAAA,IACL,GAAI,UAAU,EAAC;AAAA,IACf,GAAG,IAAA;AAAA,IACH,GAAI,SAAS,MAAA,GAAY,IAAA,GAAO,EAAE,MAAA,EAAQ,eAAA,CAAgB,IAAI,CAAA;AAAE,GAClE;AACF;AAEO,SAAS,qBAAA,CACd,WAAA,EACA,IAAA,EACA,MAAA,EACA;AACA,EAAA,SAAS,gBAAgB,KAAA,EAA6B;AACpD,IAAA,MAAM;AAAA,MACJ,QAAA;AAAA,MACA,SAAA;AAAA,MACA,OAAA;AAAA,MACA,OAAA;AAAA,MACA,IAAA;AAAA,MACA,UAAA;AAAA,MACA,MAAA;AAAA,MACA,UAAA;AAAA,MACA,QAAA;AAAA,MACA,IAAA;AAAA,MACA,EAAA;AAAA,MACA,MAAA;AAAA,MACA,GAAG;AAAA,KACL,GAAI,KAAA;AACJ,IAAA,MAAM,qBAAqBA,6BAAA,EAAiB;AAC5C,IAAA,MAAM,eAAA,GAAkB,OAAA,IAAW,oBAAA,CAAqB,MAAA,CAAO,SAAS,EAAE,CAAA;AAC1E,IAAA,MAAM,kBACJ,OAAA,KACC,kBAAA,GACG,kBACA,oBAAA,CAAqB,MAAA,CAAO,SAAS,IAAI,CAAA,CAAA;AAC/C,IAAA,MAAM,YAAA,GAAe,IAAA,IAAQ,oBAAA,CAAqB,MAAA,CAAO,MAAM,MAAM,CAAA;AACrE,IAAA,MAAM,kBAAA,GAAqB,aACvB,EAAE,GAAG,OAAO,UAAA,EAAY,GAAG,UAAA,EAAW,GACtC,MAAA,CAAO,UAAA;AAEX,IAAA,uBACEC,cAAA;AAAA,MAACC,mBAAA,CAAO,GAAA;AAAA,MAAP;AAAA,QACC,WAAA,EAAW,IAAA;AAAA,QACX,SAAA,EAAWC,oBAAG,SAAS,CAAA;AAAA,QACvB,OAAA,EAAS,eAAA;AAAA,QACT,OAAA,EAAS,eAAA;AAAA,QACT,IAAA,EAAM,YAAA;AAAA,QACN,MAAA,EAAQ,UAAU,MAAA,CAAO,MAAA;AAAA,QACzB,UAAA,EAAY,cAAc,MAAA,CAAO,UAAA;AAAA,QACjC,QAAA,EAAU,YAAY,MAAA,CAAO,QAAA;AAAA,QAC7B,UAAA,EAAY,kBAAA;AAAA,QACX,GAAG,IAAA;AAAA,QAEH;AAAA;AAAA,KACH;AAAA,EAEJ;AAEA,EAAA,eAAA,CAAgB,WAAA,GAAc,WAAA;AAC9B,EAAA,OAAO,eAAA;AACT","file":"chunk-ODZM25II.js","sourcesContent":["\"use client\";\n\nimport { motion, useReducedMotion } from \"framer-motion\";\n\nimport { cn } from \"../../lib/utils\";\n\nimport type {\n MotionAnimationPreset,\n MotionAnimationProps,\n MotionAnimationTargetOverrides,\n} from \"./types\";\n\nfunction formatBlurValue(value: number | string) {\n if (typeof value === \"number\") {\n return `blur(${value}px)`;\n }\n return value.includes(\"(\") ? value : `blur(${value})`;\n}\n\nfunction mergeTargetOverrides(\n target: MotionAnimationPreset[\"initial\"] | undefined,\n overrides: MotionAnimationTargetOverrides | undefined,\n) {\n if (!overrides) {\n return target;\n }\n\n const { blur, ...rest } = overrides;\n return {\n ...(target ?? {}),\n ...rest,\n ...(blur === undefined ? null : { filter: formatBlurValue(blur) }),\n };\n}\n\nexport function createMotionAnimation(\n displayName: string,\n slot: string,\n preset: MotionAnimationPreset,\n) {\n function MotionAnimation(props: MotionAnimationProps) {\n const {\n children,\n className,\n initial,\n animate,\n exit,\n transition,\n layout,\n whileHover,\n whileTap,\n from,\n to,\n exitTo,\n ...rest\n } = props;\n const shouldReduceMotion = useReducedMotion();\n const resolvedAnimate = animate ?? mergeTargetOverrides(preset.animate, to);\n const resolvedInitial =\n initial ??\n (shouldReduceMotion\n ? resolvedAnimate\n : mergeTargetOverrides(preset.initial, from));\n const resolvedExit = exit ?? mergeTargetOverrides(preset.exit, exitTo);\n const resolvedTransition = transition\n ? { ...preset.transition, ...transition }\n : preset.transition;\n\n return (\n <motion.div\n data-slot={slot}\n className={cn(className)}\n initial={resolvedInitial}\n animate={resolvedAnimate}\n exit={resolvedExit}\n layout={layout ?? preset.layout}\n whileHover={whileHover ?? preset.whileHover}\n whileTap={whileTap ?? preset.whileTap}\n transition={resolvedTransition}\n {...rest}\n >\n {children}\n </motion.div>\n );\n }\n\n MotionAnimation.displayName = displayName;\n return MotionAnimation;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/ui/buttons/button-base.tsx","../src/ui/buttons/button.tsx"],"names":["className","appearance","size","children","ref","rest","jsx"],"mappings":";;;;AAOO,IAAM,UAAA,GAAa,CAAC,KAAA,KAAuB;AAChD,EAAA,IAAI,KAAA,CAAM,OAAO,MAAA,EAAQ;AACvB,IAAA,MAAM;AAAA,MACJ,SAAA,EAAAA,UAAAA;AAAA,MACA,UAAA,EAAAC,WAAAA;AAAA,MACA,IAAA,EAAAC,KAAAA;AAAA,MACA,QAAA,EAAAC,SAAAA;AAAA,MACA,GAAA,EAAAC,IAAAA;AAAA,MACA,IAAA;AAAA,MACA,MAAA;AAAA,MACA,GAAGC;AAAA,KACL,GAAI,KAAA;AAEJ,IAAA,uBACE,GAAA;AAAA,MAAC,GAAA;AAAA,MAAA;AAAA,QACC,GAAA,EAAKD,IAAAA;AAAA,QACL,IAAA;AAAA,QACA,MAAA;AAAA,QACA,GAAA,EAAK,MAAA,KAAW,QAAA,GAAW,qBAAA,GAAwB,MAAA;AAAA,QACnD,WAAA,EAAU,QAAA;AAAA,QACV,SAAA,EAAW,EAAA,CAAG,cAAA,CAAe,EAAE,UAAA,EAAAH,aAAY,IAAA,EAAAC,KAAAA,EAAM,CAAA,EAAGF,UAAS,CAAA;AAAA,QAC5D,GAAGK,KAAAA;AAAA,QAEH,QAAA,EAAAF;AAAA;AAAA,KACH;AAAA,EAEJ;AAEA,EAAA,MAAM;AAAA,IACJ,SAAA;AAAA,IACA,UAAA;AAAA,IACA,IAAA;AAAA,IACA,IAAA,GAAO,QAAA;AAAA,IACP,QAAA;AAAA,IACA,GAAA;AAAA,IACA,GAAG;AAAA,GACL,GAAI,KAAA;AAEJ,EAAA,uBACE,GAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,GAAA;AAAA,MACA,IAAA;AAAA,MACA,WAAA,EAAU,QAAA;AAAA,MACV,SAAA,EAAW,GAAG,cAAA,CAAe,EAAE,YAAY,IAAA,EAAM,GAAG,SAAS,CAAA;AAAA,MAC5D,GAAG,IAAA;AAAA,MAEH;AAAA;AAAA,GACH;AAEJ,CAAA;AAEA,UAAA,CAAW,WAAA,GAAc,QAAA;ACtDlB,IAAM,MAAA,GAAS,CAAC,KAAA,KAAuB;AAC5C,EAAA,uBAAOG,GAAAA,CAAC,UAAA,EAAA,EAAY,GAAG,KAAA,EAAO,CAAA;AAChC;AAEA,MAAA,CAAO,WAAA,GAAc,QAAA","file":"chunk-VARQ7W4G.mjs","sourcesContent":["\"use client\";\n\nimport { cn } from \"../../lib/utils\";\n\nimport type { ButtonProps } from \"./types\";\nimport { buttonVariants } from \"./variants\";\n\nexport const ButtonBase = (props: ButtonProps) => {\n if (props.as === \"link\") {\n const {\n className,\n appearance,\n size,\n children,\n ref,\n href,\n target,\n ...rest\n } = props;\n\n return (\n <a\n ref={ref}\n href={href}\n target={target}\n rel={target === \"_blank\" ? \"noopener noreferrer\" : undefined}\n data-slot=\"button\"\n className={cn(buttonVariants({ appearance, size }), className)}\n {...rest}\n >\n {children}\n </a>\n );\n }\n\n const {\n className,\n appearance,\n size,\n type = \"button\",\n children,\n ref,\n ...rest\n } = props;\n\n return (\n <button\n ref={ref}\n type={type}\n data-slot=\"button\"\n className={cn(buttonVariants({ appearance, size }), className)}\n {...rest}\n >\n {children}\n </button>\n );\n};\n\nButtonBase.displayName = \"Button\";\n","// button.tsx — default static entry (no framer-motion)\nimport { ButtonBase } from \"./button-base\";\nimport type { ButtonProps } from \"./types\";\n\nexport const Button = (props: ButtonProps) => {\n return <ButtonBase {...props} />;\n};\n\nButton.displayName = \"Button\";\n"]}