{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "face-frown",
  "type": "registry:component",
  "title": "face-frown",
  "description": "Animated face-frown icon for Vue",
  "author": "Aniket Pawar <pawaraniket508@gmail.com>",
  "registryDependencies": [],
  "dependencies": [
    "motion-v"
  ],
  "files": [
    {
      "path": "src/icons/face-frown.vue",
      "type": "registry:component",
      "target": "~/src/components/heroicons-animated/face-frown.vue",
      "content": "<template>\n  <div\n    :class=\"props.class\"\n    @mouseenter=\"handleMouseEnter\"\n    @mouseleave=\"handleMouseLeave\"\n    v-bind=\"$attrs\"\n  >\n    <svg\n      ref=\"faceRef\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n      :width=\"props.size\"\n      :height=\"props.size\"\n      viewBox=\"0 0 24 24\"\n      fill=\"none\"\n      :stroke=\"props.color\"\n      :stroke-width=\"props.strokeWidth\"\n      stroke-linecap=\"round\"\n      stroke-linejoin=\"round\"\n      style=\"transform-origin: 50% 50%\"\n    >\n      <circle cx=\"12\" cy=\"12\" r=\"9\" />\n      <path\n        ref=\"mouthRef\"\n        d=\"M15.1823 16.3179C14.3075 15.4432 13.1623 15.0038 12.0158 14.9999C10.859 14.996 9.70095 15.4353 8.81834 16.3179\"\n      />\n      <path\n        ref=\"leftEyeRef\"\n        d=\"M9.75 9.75C9.75 10.1642 9.58211 10.5 9.375 10.5C9.16789 10.5 9 10.1642 9 9.75C9 9.33579 9.16789 9 9.375 9C9.58211 9 9.75 9.33579 9.75 9.75Z\"\n      />\n      <path\n        ref=\"rightEyeRef\"\n        d=\"M15 9.75C15 10.1642 14.8321 10.5 14.625 10.5C14.4179 10.5 14.25 10.1642 14.25 9.75C14.25 9.33579 14.4179 9 14.625 9C14.8321 9 15 9.33579 15 9.75Z\"\n      />\n    </svg>\n  </div>\n</template>\n\n<script lang=\"ts\">\n  export default {\n    name: \"FaceFrownIcon\",\n  };\n</script>\n\n<script setup lang=\"ts\">\n  import { useMotion } from \"../motion\";\n  import { ref } from \"vue\";\n\n  export interface Props {\n    size?: number;\n    class?: string;\n    color?: string;\n    strokeWidth?: number | string;\n  }\n\n  const props = withDefaults(defineProps<Props>(), {\n    size: 28,\n    color: \"currentColor\",\n    strokeWidth: 1.5,\n  });\n\n  const faceVariants = {\n    normal: {\n      scale: 1,\n      rotate: 0,\n      transition: {\n        duration: 0.3,\n        ease: \"easeOut\",\n      },\n    },\n    animate: {\n      scale: [1, 1.15, 1.05, 1.08],\n      rotate: [0, -2, 2, 0],\n      transition: {\n        duration: 0.8,\n        times: [0, 0.3, 0.6, 1],\n        ease: \"easeInOut\",\n      },\n    },\n  };\n\n  const mouthVariants = {\n    normal: {\n      d: \"M15.1823 16.3179C14.3075 15.4432 13.1623 15.0038 12.0158 14.9999C10.859 14.996 9.70095 15.4353 8.81834 16.3179\",\n      pathLength: 1,\n      transition: { duration: 0.3, ease: \"easeOut\" },\n    },\n    animate: {\n      d: [\n        \"M15.1823 16.3179C14.3075 15.4432 13.1623 15.0038 12.0158 14.9999C10.859 14.996 9.70095 15.4353 8.81834 16.3179\",\n        \"M15.5 17C14.5 16 13 15.5 12 15.5C11 15.5 9.5 16 8.5 17\",\n        \"M15.1823 16.3179C14.3075 15.4432 13.1623 15.0038 12.0158 14.9999C10.859 14.996 9.70095 15.4353 8.81834 16.3179\",\n      ],\n      pathLength: [0.3, 1, 1],\n      transition: {\n        d: { duration: 0.5, ease: \"easeOut\" },\n        pathLength: {\n          duration: 0.5,\n          times: [0, 0.5, 1],\n          ease: \"easeInOut\",\n        },\n        delay: 0.1,\n      },\n    },\n  };\n\n  const leftEyeVariants = {\n    normal: {\n      scale: 1,\n      y: 0,\n      transition: { duration: 0.3, ease: \"easeOut\" },\n    },\n    animate: {\n      scale: [1, 1.3, 0.9, 1.1],\n      y: [0, -0.5, 0.3, 0],\n      transition: {\n        duration: 0.6,\n        times: [0, 0.3, 0.6, 1],\n        ease: \"easeInOut\",\n      },\n    },\n  };\n\n  const rightEyeVariants = {\n    normal: {\n      scale: 1,\n      y: 0,\n      transition: { duration: 0.3, ease: \"easeOut\" },\n    },\n    animate: {\n      scale: [1, 0.9, 1.3, 1.1],\n      y: [0, -0.5, 0.3, 0],\n      transition: {\n        duration: 0.6,\n        times: [0, 0.3, 0.6, 1],\n        ease: \"easeInOut\",\n      },\n    },\n  };\n\n  const faceRef = ref<SVGSVGElement | null>(null);\n  const mouthRef = ref<SVGPathElement | null>(null);\n  const leftEyeRef = ref<SVGPathElement | null>(null);\n  const rightEyeRef = ref<SVGPathElement | null>(null);\n\n  const faceMotion = useMotion(faceRef, {\n    initial: faceVariants.normal,\n    enter: faceVariants.normal,\n  });\n  const mouthMotion = useMotion(mouthRef, {\n    initial: mouthVariants.normal,\n    enter: mouthVariants.normal,\n  });\n  const leftEyeMotion = useMotion(leftEyeRef, {\n    initial: leftEyeVariants.normal,\n    enter: leftEyeVariants.normal,\n  });\n  const rightEyeMotion = useMotion(rightEyeRef, {\n    initial: rightEyeVariants.normal,\n    enter: rightEyeVariants.normal,\n  });\n\n  let isControlled = false;\n\n  const startAnimation = () => {\n    faceMotion.apply(faceVariants.animate);\n    mouthMotion.apply(mouthVariants.animate);\n    leftEyeMotion.apply(leftEyeVariants.animate);\n    rightEyeMotion.apply(rightEyeVariants.animate);\n  };\n\n  const stopAnimation = () => {\n    faceMotion.apply(faceVariants.normal);\n    mouthMotion.apply(mouthVariants.normal);\n    leftEyeMotion.apply(leftEyeVariants.normal);\n    rightEyeMotion.apply(rightEyeVariants.normal);\n  };\n\n  const handleMouseEnter = () => {\n    if (!isControlled) {\n      startAnimation();\n    }\n  };\n\n  const handleMouseLeave = () => {\n    if (!isControlled) {\n      stopAnimation();\n    }\n  };\n\n  const setControlled = (value: boolean) => {\n    isControlled = value;\n  };\n\n  defineExpose({\n    startAnimation,\n    stopAnimation,\n    setControlled,\n  });\n</script>\n"
    },
    {
      "path": "src/motion.ts",
      "type": "registry:component",
      "target": "~/src/components/motion.ts",
      "content": "import { animate } from \"motion-v\";\nimport { isRef, watch, type Ref } from \"vue\";\n\ntype MotionElement = Element | SVGElement;\ntype MotionTarget =\n  | MotionElement\n  | Ref<MotionElement | null | undefined>\n  | null\n  | undefined;\n\ntype MotionTransition = Record<string, unknown>;\ntype MotionValues = Record<string, unknown>;\n\nexport interface MotionVariant extends MotionValues {\n  transition?: MotionTransition;\n}\n\nexport interface UseMotionOptions {\n  initial?: MotionVariant;\n  enter?: MotionVariant;\n}\n\ninterface MotionControls {\n  stop?: () => void;\n}\n\nexport interface MotionInstance {\n  apply: (variant: MotionVariant) => void;\n  stop: () => void;\n}\n\nconst isDomElement = (value: unknown): value is MotionElement => {\n  if (typeof window === \"undefined\") {\n    return false;\n  }\n  return value instanceof Element;\n};\n\nconst resolveElement = (target: MotionTarget): MotionElement | null => {\n  const element = isRef(target) ? target.value : target;\n  if (!element) {\n    return null;\n  }\n  return isDomElement(element) ? element : null;\n};\n\nconst takeTransformOrigin = (value: unknown): string | null => {\n  if (typeof value === \"string\") {\n    return value;\n  }\n  if (Array.isArray(value) && value.length > 0) {\n    // biome-ignore lint/style/useAtIndex: ES2020 lib target for package type-check does not include Array.prototype.at.\n    const lastValue = value[value.length - 1];\n    if (typeof lastValue === \"string\") {\n      return lastValue;\n    }\n  }\n  return null;\n};\n\nconst extractAnimatableValues = (\n  element: MotionElement,\n  values: MotionValues\n): MotionValues => {\n  const animatableValues: MotionValues = { ...values };\n  const transformOrigin = takeTransformOrigin(values.transformOrigin);\n\n  if (transformOrigin && \"style\" in element) {\n    element.style.transformOrigin = transformOrigin;\n    animatableValues.transformOrigin = undefined;\n  }\n\n  return animatableValues;\n};\n\nconst runAnimation = (\n  element: MotionElement,\n  controlsRef: { current: MotionControls | null },\n  variant: MotionVariant,\n  instant = false\n): void => {\n  if (typeof window === \"undefined\") {\n    return;\n  }\n\n  const { transition, ...values } = variant;\n  const animatableValues = extractAnimatableValues(element, values);\n\n  if (Object.keys(animatableValues).length === 0) {\n    return;\n  }\n\n  controlsRef.current?.stop?.();\n\n  const animationOptions = instant\n    ? ({ duration: 0 } as MotionTransition)\n    : (transition ?? {});\n\n  controlsRef.current = animate(\n    element,\n    animatableValues as Record<string, unknown>,\n    animationOptions\n  ) as MotionControls;\n};\n\nexport const useMotion = (\n  target: MotionTarget,\n  options: UseMotionOptions = {}\n): MotionInstance => {\n  const controlsRef: { current: MotionControls | null } = { current: null };\n\n  const initialize = (element: MotionElement): void => {\n    if (options.initial) {\n      runAnimation(element, controlsRef, options.initial, true);\n      return;\n    }\n    if (options.enter) {\n      runAnimation(element, controlsRef, options.enter, true);\n    }\n  };\n\n  const resolvedAtSetup = resolveElement(target);\n  if (resolvedAtSetup) {\n    initialize(resolvedAtSetup);\n  }\n\n  if (isRef(target)) {\n    watch(\n      () => target.value,\n      (element) => {\n        if (isDomElement(element)) {\n          initialize(element);\n        }\n      },\n      { immediate: true }\n    );\n  }\n\n  const apply = (variant: MotionVariant): void => {\n    if (typeof window === \"undefined\") {\n      return;\n    }\n    const element = resolveElement(target);\n    if (!element) {\n      return;\n    }\n    runAnimation(element, controlsRef, variant);\n  };\n\n  return {\n    apply,\n    stop: () => {\n      controlsRef.current?.stop?.();\n    },\n  };\n};\n"
    }
  ]
}