import { MOTION_TEXT_SPEEDS as d, MOTION_TEXT_ANIMATION_MODES as m, MOTION_TEXT_TIMING_PRESETS as l } from "./motion-text-constants.js";
import { n as c } from "../../_plugin-vue2_normalizer-DSLOjnn3.js";
const u = {
  compatConfig: { MODE: 3 },
  name: "DtRecipeMotionText",
  inheritAttrs: !1,
  props: {
    /**
     * The text content to animate.
     * @type {string}
     */
    text: {
      type: String,
      default: ""
    },
    /**
     * The animation mode to use for the text reveal.
     * @values gradient-in, fade-in, slide-in, gradient-sweep, shimmer, none
     */
    animationMode: {
      type: String,
      default: "gradient-in",
      validator: (e) => m.includes(e)
    },
    /**
     * Animation speed using t-shirt sizing.
     * @values sm, md, lg
     */
    speed: {
      type: String,
      default: "md",
      validator: (e) => d.includes(e)
    },
    /**
     * Whether to start animation automatically when component is mounted.
     * @values true, false
     */
    autoStart: {
      type: Boolean,
      default: !0
    },
    /**
     * Whether to loop the animation continuously.
     * @values true, false
     */
    loop: {
      type: Boolean,
      default: !1
    },
    /**
     * Whether to respect the user's prefers-reduced-motion system setting.
     * @values true, false
     */
    respectsReducedMotion: {
      type: Boolean,
      default: !0
    },
    /**
     * Alternative text for screen readers. If provided, this will be announced
     * instead of the animated text.
     * @type {string}
     */
    screenReaderText: {
      type: String,
      default: ""
    }
  },
  emits: [
    /**
     * Emitted when the animation starts.
     * @event start
     */
    "start",
    /**
     * Emitted when the animation completes.
     * @event complete
     */
    "complete",
    /**
     * Emitted during animation progress.
     * @event progress
     * @type {{ wordsComplete: number, totalWords: number, progress: number }}
     */
    "progress",
    /**
     * Emitted when the animation is paused.
     * @event pause
     */
    "pause",
    /**
     * Emitted when the animation resumes.
     * @event resume
     */
    "resume"
  ],
  data() {
    return {
      words: [],
      visibleWordCount: 0,
      visibleCharsPerWord: [],
      isAnimating: !1,
      isPaused: !1,
      isLooped: !1,
      animationTimeouts: [],
      prefersReducedMotion: !1,
      animationKey: 0
    };
  },
  computed: {
    /**
     * Get timing preset based on speed prop
     */
    timing() {
      return l[this.speed];
    },
    /**
     * Computed styles with timing CSS variables
     */
    componentStyles() {
      return {
        "--dt-recipe-motion-text-duration": `${this.timing.duration}ms`,
        "--dt-recipe-motion-text-char-duration": `${this.timing.duration}ms`,
        "--dt-recipe-motion-text-word-duration": `${this.timing.duration * 2}ms`
      };
    },
    /**
     * Check if current animation mode is static (gradient-sweep or shimmer)
     */
    isStaticAnimationMode() {
      return this.animationMode === "gradient-sweep" || this.animationMode === "shimmer";
    },
    /**
     * Computed classes for the motion text element
     */
    motionTextClasses() {
      return [
        "dt-recipe-motion-text",
        `dt-recipe-motion-text--${this.animationMode}`,
        {
          "dt-recipe-motion-text--animating": this.isAnimating,
          "dt-recipe-motion-text--paused": this.isPaused,
          "dt-recipe-motion-text--looped": this.isLooped
        },
        this.$attrs.class
      ];
    }
  },
  watch: {
    text() {
      this.reset(), this.initializeContent();
    },
    loop: {
      handler(e) {
        this.isLooped = e;
      },
      immediate: !0
    }
  },
  mounted() {
    this.checkReducedMotion(), this.initializeContent();
  },
  beforeUnmount() {
    this.clearTimeouts();
  },
  methods: {
    /**
     * Self-contained text processing from DOM nodes
     */
    processTextToChars(e) {
      const t = [], i = (s, n = 0) => {
        var r;
        if (s.nodeType === Node.TEXT_NODE) {
          const o = ((r = s.textContent) == null ? void 0 : r.match(/\S+\s*/g)) || [];
          return t.push(...o.map((a, h) => ({
            text: a,
            chars: a.split(""),
            index: n + h
          }))), n + o.length;
        } else if (s.nodeType === Node.ELEMENT_NODE) {
          let o = n;
          return Array.from(s.childNodes).forEach((a) => {
            o = i(a, o);
          }), o;
        }
        return n;
      };
      return i(e), t;
    },
    /**
     * Process direct text prop into word/character data
     */
    processDirectText(e) {
      return e ? (e.match(/\S+\s*/g) || []).map((i, s) => ({
        text: i,
        chars: i.split(""),
        index: s
      })) : [];
    },
    /**
     * Check for reduced motion preference
     */
    checkReducedMotion() {
      typeof window < "u" && window.matchMedia && (this.prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches);
    },
    /**
     * Clear all animation timeouts
     */
    clearTimeouts() {
      this.animationTimeouts.forEach((e) => clearTimeout(e)), this.animationTimeouts = [];
    },
    /**
     * Start the animation
     * @public
     */
    start() {
      if (!this.isAnimating) {
        if (this.isAnimating = !0, this.isPaused = !1, this.$emit("start"), this.respectsReducedMotion && this.prefersReducedMotion) {
          this.showAllContent();
          return;
        }
        if (this.animationMode === "none") {
          this.showAllContent();
          return;
        }
        this.isStaticAnimationMode || this.showNextWord();
      }
    },
    /**
     * Pause the animation
     * @public
     */
    pause() {
      !this.isAnimating || this.isPaused || (this.isPaused = !0, this.clearTimeouts(), this.$emit("pause"));
    },
    /**
     * Resume the animation
     * @public
     */
    resume() {
      this.isPaused && (this.isPaused = !1, this.$emit("resume"), this.showNextWord());
    },
    /**
     * Reset the animation to initial state
     * @public
     */
    reset() {
      this.clearTimeouts(), this.isAnimating = !1, this.isPaused = !1, this.visibleWordCount = 0, this.visibleCharsPerWord = Array(this.words.length).fill(0), this.animationKey++;
    },
    /**
     * Skip to the end of the animation
     * @public
     */
    skipToEnd() {
      this.showAllContent();
    },
    /**
     * Show all content immediately
     */
    showAllContent() {
      this.visibleWordCount = this.words.length, this.visibleCharsPerWord = this.words.map((e) => e.chars.length), setTimeout(() => {
        this.isAnimating = !1, this.$emit("complete");
      }, 0);
    },
    /**
     * Show next word in sequence
     */
    showNextWord() {
      if (this.isPaused || this.visibleWordCount >= this.words.length) {
        this.visibleWordCount >= this.words.length && this.completeAnimation();
        return;
      }
      const e = setTimeout(() => {
        this.visibleWordCount++, this.$emit("progress", {
          wordsComplete: this.visibleWordCount,
          totalWords: this.words.length,
          progress: this.visibleWordCount / this.words.length
        }), this.animateCharsForWord(this.visibleWordCount - 1);
      }, this.timing.wordDelay);
      this.animationTimeouts.push(e);
    },
    /**
     * Animate characters for a specific word
     */
    animateCharsForWord(e) {
      if (this.isPaused || e >= this.words.length) return;
      this.visibleCharsPerWord[e] = 0;
      const t = this.words[e].chars.length, i = () => {
        if (this.isPaused || this.visibleCharsPerWord[e] >= t) {
          this.visibleCharsPerWord[e] >= t && this.showNextWord();
          return;
        }
        this.visibleCharsPerWord[e]++;
        const s = setTimeout(i, this.timing.characterDelay);
        this.animationTimeouts.push(s);
      };
      i();
    },
    /**
     * Complete the animation
     */
    completeAnimation() {
      if (this.isAnimating = !1, this.clearTimeouts(), this.$emit("complete"), this.loop) {
        const e = setTimeout(() => {
          this.reset(), this.$nextTick(() => {
            this.start();
          });
        }, 500);
        this.animationTimeouts.push(e);
      }
    },
    /**
     * Initialize content based on text prop or slot content
     */
    initializeContent() {
      if (this.isStaticAnimationMode) {
        this.autoStart && this.$nextTick(() => this.start());
        return;
      }
      this.text ? this.words = this.processDirectText(this.text) : this.$refs.contentRef && (this.words = this.processTextToChars(this.$refs.contentRef)), this.visibleCharsPerWord = Array(this.words.length).fill(0), this.visibleWordCount = 0, this.autoStart && this.words.length > 0 && this.$nextTick(() => this.start());
    }
  }
};
var p = function() {
  var t = this, i = t._self._c;
  return i("span", { ref: "contentRef", class: t.motionTextClasses, style: t.componentStyles, attrs: { "data-text-content": t.isStaticAnimationMode ? t.text : void 0, "aria-live": t.isAnimating ? "polite" : "off", "aria-label": t.screenReaderText || void 0 } }, [t.screenReaderText ? i("span", { staticClass: "dt-recipe-motion-text__sr-only" }, [t._v(" " + t._s(t.screenReaderText) + " ")]) : t._e(), t.isStaticAnimationMode ? [t._v(" " + t._s(t.text) + " "), t.text ? t._e() : t._t("default")] : i("span", { key: t.animationKey, staticClass: "dt-recipe-motion-text__content", attrs: { "aria-hidden": t.isAnimating } }, [t._l(t.words, function(s, n) {
    return [i("Transition", { key: `${t.animationKey}-${n}`, attrs: { name: `dt-recipe-motion-text-word-${t.animationMode}` } }, [n < t.visibleWordCount ? i("span", { staticClass: "dt-recipe-motion-text__word", style: { "--word-index": n }, attrs: { "data-text-content": s.text } }, [t._l(s.chars, function(r, o) {
      return [i("Transition", { key: `${t.animationKey}-${n}-${o}`, attrs: { name: `dt-recipe-motion-text-char-${t.animationMode}` } }, [o < t.visibleCharsPerWord[n] ? i("span", { staticClass: "dt-recipe-motion-text__char", style: {
        "--char-index": o,
        "--char-delay": `${o * t.timing.characterDelay}ms`
      } }, [t._v(t._s(r))]) : t._e()])];
    })], 2) : t._e()])];
  })], 2), !t.words.length && !t.text && !t.isStaticAnimationMode ? i("span", { staticClass: "dt-recipe-motion-text__fallback" }, [t._t("default")], 2) : t._e()], 2);
}, f = [], T = /* @__PURE__ */ c(
  u,
  p,
  f
);
const C = T.exports;
export {
  C as default
};
//# sourceMappingURL=motion-text.js.map
