{"version":3,"file":"theme-utils.cjs","sources":["../../../src/lib/theme-utils.ts"],"sourcesContent":["/**\r\n * 테마 유틸리티 함수\r\n * Theme utility functions for tweakcn custom theme support\r\n */\r\n\r\n/**\r\n * CSS 스타일시트에서 theme-* 클래스를 자동으로 감지합니다.\r\n * Detects theme-* classes from CSS stylesheets\r\n * \r\n * @returns 감지된 테마 이름 배열 (예: ['default', 'slate', 'rose', ...])\r\n */\r\nexport function detectThemeClasses(): string[] {\r\n  const themeClasses: Set<string> = new Set()\r\n  \r\n  try {\r\n    // 모든 스타일시트 순회\r\n    const styleSheets = Array.from(document.styleSheets)\r\n    \r\n    for (const styleSheet of styleSheets) {\r\n      try {\r\n        // CORS 제한으로 인해 접근 불가능한 스타일시트는 건너뛰기\r\n        const rules = styleSheet.cssRules || styleSheet.rules\r\n        \r\n        if (!rules) continue\r\n        \r\n        for (const rule of Array.from(rules)) {\r\n          if (rule instanceof CSSStyleRule) {\r\n            const selector = rule.selectorText\r\n            \r\n            // .theme-{name} 형식의 클래스 선택자 찾기\r\n            const themeMatch = selector.match(/\\.theme-([a-zA-Z0-9_-]+)/)\r\n            if (themeMatch && themeMatch[1]) {\r\n              themeClasses.add(themeMatch[1])\r\n            }\r\n          }\r\n        }\r\n      } catch {\r\n        // CORS 오류 등으로 인한 접근 불가 스타일시트는 무시\r\n        continue\r\n      }\r\n    }\r\n    \r\n    // document에서 직접 클래스 찾기 (동적으로 추가된 스타일)\r\n    const allClasses = Array.from(document.querySelectorAll('[class*=\"theme-\"]'))\r\n    for (const element of allClasses) {\r\n      const classList = Array.from(element.classList)\r\n      for (const className of classList) {\r\n        const themeMatch = className.match(/^theme-([a-zA-Z0-9_-]+)$/)\r\n        if (themeMatch && themeMatch[1]) {\r\n          themeClasses.add(themeMatch[1])\r\n        }\r\n      }\r\n    }\r\n  } catch (error) {\r\n    console.warn('[theme-utils] Failed to detect theme classes:', error)\r\n  }\r\n  \r\n  return Array.from(themeClasses)\r\n}\r\n\r\n/**\r\n * 현재 문서의 모든 테마 클래스를 반환합니다.\r\n * Returns all theme classes currently in the document\r\n * \r\n * @returns 테마 이름 배열\r\n */\r\nexport function getAllThemeClasses(): string[] {\r\n  return detectThemeClasses()\r\n}\r\n\r\n/**\r\n * 테마 이름이 유효한지 검사합니다.\r\n * Validates if a theme name is valid\r\n * \r\n * @param theme - 검사할 테마 이름\r\n * @returns 유효하면 true\r\n */\r\nexport function isValidTheme(theme: string): boolean {\r\n  if (!theme || typeof theme !== 'string') {\r\n    return false\r\n  }\r\n  \r\n  // theme-{name} 형식인지 확인\r\n  const themeClasses = detectThemeClasses()\r\n  return themeClasses.includes(theme)\r\n}\r\n\r\n/**\r\n * 디폴트 테마가 항상 포함되도록 보장합니다.\r\n * Ensures that the default theme is always included\r\n * \r\n * @param themes - 테마 이름 배열\r\n * @returns 디폴트 테마가 포함된 테마 배열 (default가 맨 앞에 위치)\r\n */\r\nexport function ensureDefaultTheme(themes: string[]): string[] {\r\n  const uniqueThemes = Array.from(new Set(themes))\r\n  \r\n  // default가 없으면 경고하고 추가\r\n  if (!uniqueThemes.includes('default')) {\r\n    console.warn('[theme-utils] Default theme not found. Adding default theme to list.')\r\n    return ['default', ...uniqueThemes]\r\n  }\r\n  \r\n  // default를 맨 앞에 배치\r\n  const otherThemes = uniqueThemes.filter(t => t !== 'default')\r\n  return ['default', ...otherThemes]\r\n}\r\n\r\n/**\r\n * 디폴트 테마 이름을 반환합니다.\r\n * Returns the default theme name\r\n * \r\n * @returns 항상 'default'\r\n */\r\nexport function getDefaultTheme(): string {\r\n  return 'default'\r\n}\r\n\r\n/**\r\n * 테마가 존재하는지 검증하고, 없으면 디폴트 테마를 반환합니다.\r\n * Validates if a theme exists, returns default if not found\r\n * \r\n * @param theme - 검증할 테마 이름\r\n * @returns 유효한 테마 이름 (없으면 'default')\r\n */\r\nexport function validateThemeExists(theme: string): string {\r\n  if (!theme || typeof theme !== 'string') {\r\n    return getDefaultTheme()\r\n  }\r\n  \r\n  const themeClasses = detectThemeClasses()\r\n  \r\n  if (themeClasses.includes(theme)) {\r\n    return theme\r\n  }\r\n  \r\n  console.warn(`[theme-utils] Theme '${theme}' not found. Using default theme.`)\r\n  return getDefaultTheme()\r\n}\r\n\r\n/**\r\n * 로컬 스토리지에서 저장된 테마를 가져옵니다.\r\n * Gets stored theme from localStorage\r\n * \r\n * @param storageKey - 스토리지 키 (기본값: 'tweakcn-theme')\r\n * @returns 저장된 테마 이름 또는 null\r\n */\r\nexport function getStoredTheme(storageKey: string = 'tweakcn-theme'): string | null {\r\n  try {\r\n    return localStorage.getItem(storageKey)\r\n  } catch (error) {\r\n    console.warn('[theme-utils] Failed to get stored theme:', error)\r\n    return null\r\n  }\r\n}\r\n\r\n/**\r\n * 테마를 로컬 스토리지에 저장합니다.\r\n * Saves theme to localStorage\r\n * \r\n * @param theme - 저장할 테마 이름\r\n * @param storageKey - 스토리지 키 (기본값: 'tweakcn-theme')\r\n */\r\nexport function setStoredTheme(theme: string, storageKey: string = 'tweakcn-theme'): void {\r\n  try {\r\n    localStorage.setItem(storageKey, theme)\r\n  } catch (error) {\r\n    console.warn('[theme-utils] Failed to save theme:', error)\r\n  }\r\n}\r\n\r\n/**\r\n * 문서의 루트 요소에 테마 클래스를 적용합니다.\r\n * Applies theme class to document root element\r\n * \r\n * @param theme - 적용할 테마 이름\r\n * @returns 성공 여부\r\n */\r\nexport function applyTheme(theme: string): boolean {\r\n  if (!theme || typeof theme !== 'string') {\r\n    return false\r\n  }\r\n  \r\n  try {\r\n    const root = document.documentElement\r\n    \r\n    // 모든 theme-* 클래스 제거\r\n    const themeClasses = detectThemeClasses()\r\n    for (const themeClass of themeClasses) {\r\n      root.classList.remove(`theme-${themeClass}`)\r\n    }\r\n    \r\n    // 새 테마 클래스 추가\r\n    root.classList.add(`theme-${theme}`)\r\n    \r\n    return true\r\n  } catch (error) {\r\n    console.error('[theme-utils] Failed to apply theme:', error)\r\n    return false\r\n  }\r\n}\r\n"],"names":["detectThemeClasses","themeClasses","styleSheets","styleSheet","rules","rule","themeMatch","allClasses","element","classList","className","error","ensureDefaultTheme","themes","uniqueThemes","t","getDefaultTheme","validateThemeExists","theme","getStoredTheme","storageKey","setStoredTheme","applyTheme","root","themeClass"],"mappings":"gFAWO,SAASA,GAA+B,CAC7C,MAAMC,MAAgC,IAEtC,GAAI,CAEF,MAAMC,EAAc,MAAM,KAAK,SAAS,WAAW,EAEnD,UAAWC,KAAcD,EACvB,GAAI,CAEF,MAAME,EAAQD,EAAW,UAAYA,EAAW,MAEhD,GAAI,CAACC,EAAO,SAEZ,UAAWC,KAAQ,MAAM,KAAKD,CAAK,EACjC,GAAIC,aAAgB,aAAc,CAIhC,MAAMC,EAHWD,EAAK,aAGM,MAAM,0BAA0B,EACxDC,GAAcA,EAAW,CAAC,GAC5BL,EAAa,IAAIK,EAAW,CAAC,CAAC,CAElC,CAEJ,MAAQ,CAEN,QACF,CAIF,MAAMC,EAAa,MAAM,KAAK,SAAS,iBAAiB,mBAAmB,CAAC,EAC5E,UAAWC,KAAWD,EAAY,CAChC,MAAME,EAAY,MAAM,KAAKD,EAAQ,SAAS,EAC9C,UAAWE,KAAaD,EAAW,CACjC,MAAMH,EAAaI,EAAU,MAAM,0BAA0B,EACzDJ,GAAcA,EAAW,CAAC,GAC5BL,EAAa,IAAIK,EAAW,CAAC,CAAC,CAElC,CACF,CACF,OAASK,EAAO,CACd,QAAQ,KAAK,gDAAiDA,CAAK,CACrE,CAEA,OAAO,MAAM,KAAKV,CAAY,CAChC,CAoCO,SAASW,EAAmBC,EAA4B,CAC7D,MAAMC,EAAe,MAAM,KAAK,IAAI,IAAID,CAAM,CAAC,EAG/C,OAAKC,EAAa,SAAS,SAAS,EAO7B,CAAC,UAAW,GADCA,EAAa,OAAOC,GAAKA,IAAM,SAAS,CAC3B,GAN/B,QAAQ,KAAK,sEAAsE,EAC5E,CAAC,UAAW,GAAGD,CAAY,EAMtC,CAQO,SAASE,GAA0B,CACxC,MAAO,SACT,CASO,SAASC,EAAoBC,EAAuB,CACzD,MAAI,CAACA,GAAS,OAAOA,GAAU,SACtBF,EAAA,EAGYhB,EAAA,EAEJ,SAASkB,CAAK,EACtBA,GAGT,QAAQ,KAAK,wBAAwBA,CAAK,mCAAmC,EACtEF,EAAA,EACT,CASO,SAASG,EAAeC,EAAqB,gBAAgC,CAClF,GAAI,CACF,OAAO,aAAa,QAAQA,CAAU,CACxC,OAAST,EAAO,CACd,eAAQ,KAAK,4CAA6CA,CAAK,EACxD,IACT,CACF,CASO,SAASU,EAAeH,EAAeE,EAAqB,gBAAuB,CACxF,GAAI,CACF,aAAa,QAAQA,EAAYF,CAAK,CACxC,OAASP,EAAO,CACd,QAAQ,KAAK,sCAAuCA,CAAK,CAC3D,CACF,CASO,SAASW,EAAWJ,EAAwB,CACjD,GAAI,CAACA,GAAS,OAAOA,GAAU,SAC7B,MAAO,GAGT,GAAI,CACF,MAAMK,EAAO,SAAS,gBAGhBtB,EAAeD,EAAA,EACrB,UAAWwB,KAAcvB,EACvBsB,EAAK,UAAU,OAAO,SAASC,CAAU,EAAE,EAI7C,OAAAD,EAAK,UAAU,IAAI,SAASL,CAAK,EAAE,EAE5B,EACT,OAASP,EAAO,CACd,eAAQ,MAAM,uCAAwCA,CAAK,EACpD,EACT,CACF"}