{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "cake",
  "type": "registry:component",
  "title": "cake",
  "description": "Animated cake icon for Vue",
  "author": "Aniket Pawar <pawaraniket508@gmail.com>",
  "registryDependencies": [],
  "dependencies": [
    "motion-v"
  ],
  "files": [
    {
      "path": "src/icons/cake.vue",
      "type": "registry:component",
      "target": "~/src/components/heroicons-animated/cake.vue",
      "content": "<template>\n  <div\n    :class=\"props.class\"\n    @mouseenter=\"handleMouseEnter\"\n    @mouseleave=\"handleMouseLeave\"\n    v-bind=\"$attrs\"\n  >\n    <svg\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    >\n      <path\n        ref=\"cakeBodyRef\"\n        d=\"M12 8.25c-1.355 0-2.697.056-4.024.166C6.845 8.51 6 9.473 6 10.608v2.513m6-4.871c1.355 0 2.697.056 4.024.166C17.155 8.51 18 9.473 18 10.608v2.513m3 3.879-1.5.75a3.354 3.354 0 0 1-3 0 3.354 3.354 0 0 0-3 0 3.354 3.354 0 0 1-3 0 3.354 3.354 0 0 0-3 0 3.354 3.354 0 0 1-3 0L3 16.5m15-3.379a48.474 48.474 0 0 0-6-.371c-2.032 0-4.034.126-6 .371m12 0c.39.049.777.102 1.163.16 1.07.16 1.837 1.094 1.837 2.175v5.169c0 .621-.504 1.125-1.125 1.125H4.125A1.125 1.125 0 0 1 3 20.625v-5.17c0-1.08.768-2.014 1.837-2.174A47.78 47.78 0 0 1 6 13.12\"\n        style=\"transform-origin: center bottom\"\n      />\n      <g ref=\"candleGroupRef\" style=\"transform-origin: center bottom\">\n        <path d=\"M9 8.25v-1.5\" />\n        <path d=\"M12 8.25v-1.5\" />\n        <path d=\"M15 8.25v-1.5\" />\n      </g>\n      <path\n        ref=\"flameLeftRef\"\n        d=\"M9.265 3.11a.375.375 0 1 1-.53 0L9 2.845l.265.265Z\"\n        style=\"transform-origin: 37.5% 50%\"\n      />\n      <path\n        ref=\"flameMiddleRef\"\n        d=\"M12.265 3.11a.375.375 0 1 1-.53 0L12 2.845l.265.265Z\"\n        style=\"transform-origin: 50% 50%\"\n      />\n      <path\n        ref=\"flameRightRef\"\n        d=\"M15.265 3.11a.375.375 0 1 1-.53 0L15 2.845l.265.265Z\"\n        style=\"transform-origin: 62.5% 50%\"\n      />\n    </svg>\n  </div>\n</template>\n\n<script lang=\"ts\">\n  export default {\n    name: \"CakeIcon\",\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 cakeBodyVariants = {\n    normal: {\n      translateY: 0,\n      opacity: 1,\n    },\n    animate: {\n      translateY: [8, -1, 0],\n      opacity: [0, 1, 1],\n      transition: {\n        duration: 0.4,\n        ease: \"easeOut\",\n      },\n    },\n  };\n\n  const candleVariants = {\n    normal: {\n      scaleY: 1,\n      opacity: 1,\n    },\n    animate: {\n      scaleY: [0, 1.2, 1],\n      opacity: [0, 1, 1],\n      transition: {\n        duration: 0.3,\n        ease: \"easeOut\",\n        delay: 0.3,\n      },\n    },\n  };\n\n  const flameLeftVariants = {\n    normal: {\n      scale: 1,\n      opacity: 1,\n    },\n    animate: {\n      scale: [0, 1.3, 1],\n      opacity: [0, 1, 1],\n      transition: {\n        duration: 0.25,\n        ease: \"easeOut\",\n        delay: 0.5,\n      },\n    },\n  };\n\n  const flameMiddleVariants = {\n    normal: {\n      scale: 1,\n      opacity: 1,\n    },\n    animate: {\n      scale: [0, 1.3, 1],\n      opacity: [0, 1, 1],\n      transition: {\n        duration: 0.25,\n        ease: \"easeOut\",\n        delay: 0.65,\n      },\n    },\n  };\n\n  const flameRightVariants = {\n    normal: {\n      scale: 1,\n      opacity: 1,\n    },\n    animate: {\n      scale: [0, 1.3, 1],\n      opacity: [0, 1, 1],\n      transition: {\n        duration: 0.25,\n        ease: \"easeOut\",\n        delay: 0.8,\n      },\n    },\n  };\n\n  const cakeBodyRef = ref<SVGPathElement>();\n  const candleGroupRef = ref<SVGGElement>();\n  const flameLeftRef = ref<SVGPathElement>();\n  const flameMiddleRef = ref<SVGPathElement>();\n  const flameRightRef = ref<SVGPathElement>();\n\n  const cakeBodyMotion = useMotion(cakeBodyRef, {\n    initial: cakeBodyVariants.normal,\n    enter: cakeBodyVariants.normal,\n  });\n\n  const candleGroupMotion = useMotion(candleGroupRef, {\n    initial: candleVariants.normal,\n    enter: candleVariants.normal,\n  });\n\n  const flameLeftMotion = useMotion(flameLeftRef, {\n    initial: flameLeftVariants.normal,\n    enter: flameLeftVariants.normal,\n  });\n\n  const flameMiddleMotion = useMotion(flameMiddleRef, {\n    initial: flameMiddleVariants.normal,\n    enter: flameMiddleVariants.normal,\n  });\n\n  const flameRightMotion = useMotion(flameRightRef, {\n    initial: flameRightVariants.normal,\n    enter: flameRightVariants.normal,\n  });\n\n  let isControlled = false;\n\n  const startAnimation = () => {\n    cakeBodyMotion.apply(cakeBodyVariants.animate);\n    candleGroupMotion.apply(candleVariants.animate);\n    flameLeftMotion.apply(flameLeftVariants.animate);\n    flameMiddleMotion.apply(flameMiddleVariants.animate);\n    flameRightMotion.apply(flameRightVariants.animate);\n  };\n\n  const stopAnimation = () => {\n    cakeBodyMotion.apply(cakeBodyVariants.normal);\n    candleGroupMotion.apply(candleVariants.normal);\n    flameLeftMotion.apply(flameLeftVariants.normal);\n    flameMiddleMotion.apply(flameMiddleVariants.normal);\n    flameRightMotion.apply(flameRightVariants.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"
    }
  ]
}