(function (root, factory) {
  const api = factory();
  if (typeof module === "object" && module.exports) {
    module.exports = api;
  }
  root.LabelNovaTextLayouts = api;
})(typeof globalThis !== "undefined" ? globalThis : this, function () {
  function toFiniteNumber(value, fallback) {
    const num = Number(value);
    return Number.isFinite(num) ? num : fallback;
  }

  function splitTextIntoGraphemes(text) {
    return Array.from(String(text || ""));
  }

  function normalizeTextLayoutMode(value) {
    switch (value) {
      case "vertical":
      case "arcUp":
      case "arcDown":
        return value;
      default:
        return "horizontal";
    }
  }

  function isCurvedTextLayout(value) {
    const mode = normalizeTextLayoutMode(value);
    return mode === "arcUp" || mode === "arcDown";
  }

  function verticalizeText(text) {
    return String(text || "")
      .split("\n")
      .map((line) => splitTextIntoGraphemes(line).join("\n"))
      .join("\n\n");
  }

  function buildArcGlyphLayout(options) {
    const widths = Array.isArray(options && options.widths)
      ? options.widths.map((width) => Math.max(0, toFiniteNumber(width, 0)))
      : [];
    const radius = Math.max(1, toFiniteNumber(options && options.radius, 1));
    const letterSpacing = Math.max(0, toFiniteNumber(options && options.letterSpacing, 0));
    const bend = normalizeTextLayoutMode(options && options.bend) === "arcDown" || (options && options.bend) === "down"
      ? "down"
      : "up";
    const direction = bend === "down" ? -1 : 1;
    const totalAdvance = widths.reduce((sum, width) => sum + width, 0) + letterSpacing * Math.max(0, widths.length - 1);

    let cursor = -totalAdvance / 2;
    const glyphs = widths.map((width, index) => {
      const centerAdvance = cursor + width / 2;
      const theta = centerAdvance / radius;
      const x = Math.sin(theta) * radius;
      const y = direction * (radius - Math.cos(theta) * radius);
      const angle = (Math.atan2(direction * Math.sin(theta), Math.cos(theta)) * 180) / Math.PI;
      cursor += width + (index < widths.length - 1 ? letterSpacing : 0);
      return {
        x,
        y,
        angle,
      };
    });

    return {
      bend,
      radius,
      totalAdvance,
      glyphs,
    };
  }

  return {
    splitTextIntoGraphemes,
    normalizeTextLayoutMode,
    isCurvedTextLayout,
    verticalizeText,
    buildArcGlyphLayout,
  };
});
