{
  "version": 3,
  "sources": ["../../../../../packages/cfpb-design-system/src/elements/cfpb-utilities/i18n-service.js", "../../../../../packages/cfpb-design-system/src/elements/cfpb-utilities/media-query-service.js"],
  "sourcesContent": ["/**\n * A service for embedding and using translations via markup.\n *\n * Expect markup like:\n * <i18n-service>\n *   <template>\n *     {\n *       \"en\": { \"hello\": \"Hello\", \"good afternoon\": \"Good afternoon\" },\n *       \"es\": { \"hello\": \"Hola\", \"good afternoon\": \"Buenas tardes\" }\n *     }\n *   </template>\n * </i18n-service>\n */\nexport class I18nService extends HTMLElement {\n  #translations;\n  #language;\n\n  constructor() {\n    super();\n    this.#translations = {};\n    this.#language = '';\n  }\n\n  connectedCallback() {\n    const errors = [];\n    const template = this.querySelector('template');\n    if (!template) {\n      errors.push([\n        'missing-template',\n        'No <template> found inside <i18n-service>',\n      ]);\n      return;\n    }\n\n    try {\n      const json = template.innerHTML.trim();\n      const data = JSON.parse(json);\n\n      if (typeof data !== 'object' || Array.isArray(data)) {\n        errors.push([\n          'invalid-format',\n          'Translations JSON must be an object keyed by the language codes',\n        ]);\n      }\n\n      this.#translations = data;\n\n      // Set default lanugage to the first available one, if not already set.\n      const available = this.availableLanguages;\n      if (available.length > 0 && !this.#language) {\n        this.language = available[0];\n      }\n    } catch (err) {\n      errors.push([\n        'parse-error',\n        'Failed to parse i18n template JSON',\n        { err },\n      ]);\n    }\n\n    // Aggregate any errors together and dispatch them when the app has\n    // refreshed, which gives other components a chance to listen for them.\n    requestAnimationFrame(() => {\n      errors.forEach((error) => {\n        this.#dispatchError(...error);\n      });\n    });\n  }\n\n  /**\n   * Set the current language\n   * @param {string} lang - Language code (e.g. \"en\", \"es\", \"ar\", \"ru\", etc.)\n   */\n  set language(lang) {\n    if (!this.#translations[lang]) {\n      this.#dispatchError('invalid-language', `Unsupported language: ${lang}`, {\n        lang,\n      });\n      return;\n    }\n\n    if (this.#language !== lang) {\n      this.#language = lang;\n      this.dispatchEvent(\n        new CustomEvent('i18n-change', {\n          detail: { language: lang },\n          bubbles: true,\n          composed: true,\n        }),\n      );\n    }\n  }\n\n  /**\n   * @returns {string} The currently set language.\n   */\n  get language() {\n    return this.#language;\n  }\n\n  get availableLanguages() {\n    return Object.keys(this.#translations);\n  }\n\n  /**\n   * Translate a language key.\n   * @param {string} key - An arbitrary key from the <template>.\n   * @returns {string} The translation.\n   */\n  translate(key) {\n    return this.#translations[this.#language]?.[key] || key;\n  }\n\n  #dispatchError(type, message, extra = {}) {\n    this.dispatchEvent(\n      new CustomEvent('i18n-error', {\n        detail: { type, message, ...extra },\n        bubbles: true,\n        composed: true,\n      }),\n    );\n  }\n\n  static init() {\n    window.customElements.get('i18n-service') ||\n      window.customElements.define('i18n-service', I18nService);\n  }\n}\n", "/**\n * A service for observing named breakpoints via matchMedia.\n * Emits a `change` event (CustomEvent) whenever any breakpoint match status changes.\n * Consumers can also call `matches` or `is(breakpointName)` to get current state.\n */\nexport class MediaQueryService extends EventTarget {\n  #breakpoints;\n  #mqls = new Map(); // Map<key, MediaQueryList>\n  #handlers = new Map(); // Map<key, listener>\n  #matches = new Map(); // Map<key, boolean>\n  #pendingUpdate = false;\n\n  /**\n   *\n   * @param {Record<string, {min: number, max?: number}} [breakpoints]\n   *   A map of breakpoint name -> { min: px, optional max: px }.\n   *   If not provided, default breakpoints are used.\n   */\n  constructor(breakpoints) {\n    super();\n\n    this.#breakpoints = breakpoints ?? {\n      xs: { min: 0, max: 600 },\n      sm: { min: 601, max: 900 },\n      med: { min: 901, max: 1020 },\n      lg: { min: 1021, max: 1200 },\n      xl: { min: 1201 },\n    };\n\n    // Setup each media query.\n    for (const [key, range] of Object.entries(this.#breakpoints)) {\n      const mqString = this.#rangeToMediaQuery(range);\n      const mql = window.matchMedia(mqString);\n\n      this.#mqls.set(key, mql);\n      this.#matches.set(key, mql.matches);\n\n      const listener = (evt) => {\n        this.#matches.set(key, evt.matches);\n\n        if (!this.#pendingUpdate) {\n          this.#pendingUpdate = true;\n\n          requestAnimationFrame(() => {\n            this.#pendingUpdate = false;\n            this.#dispatchChange(); // Dispatch only once per frame.\n          });\n        }\n\n        /*\n        const prev = this.#matches.get(key);\n        if (prev !== evt.matches) {\n          this.#matches.set(key, evt.matches);\n          this.#dispatchChange();\n        }\n        */\n      };\n\n      mql.addEventListener('change', listener);\n\n      this.#handlers.set(key, listener);\n    }\n\n    // Emit initial state.\n    this.#dispatchChange();\n  }\n\n  #rangeToMediaQuery(range) {\n    const parts = [];\n    if (range.min != null) {\n      parts.push(`(min-width: ${range.min}px)`);\n    }\n    if (range.max != null) {\n      parts.push(`(max-width: ${range.max}px)`);\n    }\n    return parts.join(' and ');\n  }\n\n  #dispatchChange() {\n    const detail = {\n      matches: Object.fromEntries(this.#matches),\n    };\n\n    this.dispatchEvent(new CustomEvent('change', { detail }));\n  }\n\n  get matches() {\n    return Object.fromEntries(this.#matches);\n  }\n\n  destroy() {\n    for (const [key, mql] of this.#mqls.entries()) {\n      const listener = this.#handlers.get(key);\n      if (!listener) continue;\n      mql.removeEventListener('change', listener);\n    }\n\n    this.#mqls.clear();\n    this.#handlers.clear();\n    this.#matches.clear();\n  }\n}\n"],
  "mappings": "wtBAAA,IAAAA,EAAAC,EAAAC,EAAAC,EAaaC,EAAN,MAAMA,UAAoB,WAAY,CAI3C,aAAc,CACZ,MAAM,EALHC,EAAA,KAAAH,GACLG,EAAA,KAAAL,GACAK,EAAA,KAAAJ,GAIEK,EAAA,KAAKN,EAAgB,CAAC,GACtBM,EAAA,KAAKL,EAAY,GACnB,CAEA,mBAAoB,CAClB,IAAMM,EAAS,CAAC,EACVC,EAAW,KAAK,cAAc,UAAU,EAC9C,GAAI,CAACA,EAAU,CACbD,EAAO,KAAK,CACV,mBACA,2CACF,CAAC,EACD,MACF,CAEA,GAAI,CACF,IAAME,EAAOD,EAAS,UAAU,KAAK,EAC/BE,EAAO,KAAK,MAAMD,CAAI,GAExB,OAAOC,GAAS,UAAY,MAAM,QAAQA,CAAI,IAChDH,EAAO,KAAK,CACV,iBACA,iEACF,CAAC,EAGHD,EAAA,KAAKN,EAAgBU,GAGrB,IAAMC,EAAY,KAAK,mBACnBA,EAAU,OAAS,GAAK,CAACC,EAAA,KAAKX,KAChC,KAAK,SAAWU,EAAU,CAAC,EAE/B,OAASE,EAAK,CACZN,EAAO,KAAK,CACV,cACA,qCACA,CAAE,IAAAM,CAAI,CACR,CAAC,CACH,CAIA,sBAAsB,IAAM,CAC1BN,EAAO,QAASO,GAAU,CACxBC,EAAA,KAAKb,EAAAC,GAAL,UAAoB,GAAGW,EACzB,CAAC,CACH,CAAC,CACH,CAMA,IAAI,SAASE,EAAM,CACjB,GAAI,CAACJ,EAAA,KAAKZ,GAAcgB,CAAI,EAAG,CAC7BD,EAAA,KAAKb,EAAAC,GAAL,UAAoB,mBAAoB,yBAAyBa,CAAI,GAAI,CACvE,KAAAA,CACF,GACA,MACF,CAEIJ,EAAA,KAAKX,KAAce,IACrBV,EAAA,KAAKL,EAAYe,GACjB,KAAK,cACH,IAAI,YAAY,cAAe,CAC7B,OAAQ,CAAE,SAAUA,CAAK,EACzB,QAAS,GACT,SAAU,EACZ,CAAC,CACH,EAEJ,CAKA,IAAI,UAAW,CACb,OAAOJ,EAAA,KAAKX,EACd,CAEA,IAAI,oBAAqB,CACvB,OAAO,OAAO,KAAKW,EAAA,KAAKZ,EAAa,CACvC,CAOA,UAAUiB,EAAK,CA7GjB,IAAAC,EA8GI,QAAOA,EAAAN,EAAA,KAAKZ,GAAcY,EAAA,KAAKX,EAAS,IAAjC,YAAAiB,EAAqCD,KAAQA,CACtD,CAYA,OAAO,MAAO,CACZ,OAAO,eAAe,IAAI,cAAc,GACtC,OAAO,eAAe,OAAO,eAAgBb,CAAW,CAC5D,CACF,EAjHEJ,EAAA,YACAC,EAAA,YAFKC,EAAA,YAoGLC,EAAc,SAACgB,EAAMC,EAASC,EAAQ,CAAC,EAAG,CACxC,KAAK,cACH,IAAI,YAAY,aAAc,CAC5B,OAAQC,EAAA,CAAE,KAAAH,EAAM,QAAAC,GAAYC,GAC5B,QAAS,GACT,SAAU,EACZ,CAAC,CACH,CACF,EA5GK,IAAME,EAANnB,ECbP,IAAAoB,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAKaC,EAAN,cAAgC,WAAY,CAajD,YAAYC,EAAa,CACvB,MAAM,EAdHC,EAAA,KAAAL,GACLK,EAAA,KAAAV,GACAU,EAAA,KAAAT,EAAQ,IAAI,KACZS,EAAA,KAAAR,EAAY,IAAI,KAChBQ,EAAA,KAAAP,EAAW,IAAI,KACfO,EAAA,KAAAN,EAAiB,IAWfO,EAAA,KAAKX,EAAeS,GAAA,KAAAA,EAAe,CACjC,GAAI,CAAE,IAAK,EAAG,IAAK,GAAI,EACvB,GAAI,CAAE,IAAK,IAAK,IAAK,GAAI,EACzB,IAAK,CAAE,IAAK,IAAK,IAAK,IAAK,EAC3B,GAAI,CAAE,IAAK,KAAM,IAAK,IAAK,EAC3B,GAAI,CAAE,IAAK,IAAK,CAClB,GAGA,OAAW,CAACG,EAAKC,CAAK,IAAK,OAAO,QAAQC,EAAA,KAAKd,EAAY,EAAG,CAC5D,IAAMe,EAAWC,EAAA,KAAKX,EAAAC,GAAL,UAAwBO,GACnCI,EAAM,OAAO,WAAWF,CAAQ,EAEtCD,EAAA,KAAKb,GAAM,IAAIW,EAAKK,CAAG,EACvBH,EAAA,KAAKX,GAAS,IAAIS,EAAKK,EAAI,OAAO,EAElC,IAAMC,EAAYC,GAAQ,CACxBL,EAAA,KAAKX,GAAS,IAAIS,EAAKO,EAAI,OAAO,EAE7BL,EAAA,KAAKV,KACRO,EAAA,KAAKP,EAAiB,IAEtB,sBAAsB,IAAM,CAC1BO,EAAA,KAAKP,EAAiB,IACtBY,EAAA,KAAKX,EAAAE,GAAL,UACF,CAAC,EAUL,EAEAU,EAAI,iBAAiB,SAAUC,CAAQ,EAEvCJ,EAAA,KAAKZ,GAAU,IAAIU,EAAKM,CAAQ,CAClC,CAGAF,EAAA,KAAKX,EAAAE,GAAL,UACF,CAqBA,IAAI,SAAU,CACZ,OAAO,OAAO,YAAYO,EAAA,KAAKX,EAAQ,CACzC,CAEA,SAAU,CACR,OAAW,CAACS,EAAKK,CAAG,IAAKH,EAAA,KAAKb,GAAM,QAAQ,EAAG,CAC7C,IAAMiB,EAAWJ,EAAA,KAAKZ,GAAU,IAAIU,CAAG,EAClCM,GACLD,EAAI,oBAAoB,SAAUC,CAAQ,CAC5C,CAEAJ,EAAA,KAAKb,GAAM,MAAM,EACjBa,EAAA,KAAKZ,GAAU,MAAM,EACrBY,EAAA,KAAKX,GAAS,MAAM,CACtB,CACF,EA/FEH,EAAA,YACAC,EAAA,YACAC,EAAA,YACAC,EAAA,YACAC,EAAA,YALKC,EAAA,YA8DLC,EAAkB,SAACO,EAAO,CACxB,IAAMO,EAAQ,CAAC,EACf,OAAIP,EAAM,KAAO,MACfO,EAAM,KAAK,eAAeP,EAAM,GAAG,KAAK,EAEtCA,EAAM,KAAO,MACfO,EAAM,KAAK,eAAeP,EAAM,GAAG,KAAK,EAEnCO,EAAM,KAAK,OAAO,CAC3B,EAEAb,EAAe,UAAG,CAChB,IAAMc,EAAS,CACb,QAAS,OAAO,YAAYP,EAAA,KAAKX,EAAQ,CAC3C,EAEA,KAAK,cAAc,IAAI,YAAY,SAAU,CAAE,OAAAkB,CAAO,CAAC,CAAC,CAC1D",
  "names": ["_translations", "_language", "_I18nService_instances", "dispatchError_fn", "_I18nService", "__privateAdd", "__privateSet", "errors", "template", "json", "data", "available", "__privateGet", "err", "error", "__privateMethod", "lang", "key", "_a", "type", "message", "extra", "__spreadValues", "I18nService", "_breakpoints", "_mqls", "_handlers", "_matches", "_pendingUpdate", "_MediaQueryService_instances", "rangeToMediaQuery_fn", "dispatchChange_fn", "MediaQueryService", "breakpoints", "__privateAdd", "__privateSet", "key", "range", "__privateGet", "mqString", "__privateMethod", "mql", "listener", "evt", "parts", "detail"]
}
