{"version":3,"file":"icon.cjs","sources":["../../../packages/components/src/icon.ts"],"sourcesContent":["import { LitElement, html, nothing } from 'lit'\nimport { property, state } from 'lit/decorators.js'\nimport { styleMap } from 'lit/directives/style-map.js'\nimport { safeCustomElement } from './base/define'\n\ntype IconOutputType = 'iconify' | 'unocss' | 'css' | 'img' | 'svg' | 'empty'\n\n@safeCustomElement('qxs-icon')\nexport class QxsIcon extends LitElement {\n  @property({ attribute: false }) icon = ''\n  @property({ type: String }) flip: 'horizontal' | 'vertical' | 'both' | '' = ''\n  @property({ type: Number }) rotate = 0\n  @property({ type: String }) color = ''\n  @property({ attribute: false }) size: string | number | undefined\n  @property({ type: String, attribute: 'local-icon-prefix' }) localIconPrefix = 'icon-'\n  @property({ type: String }) fallback = ''\n  @property({ type: String }) loading = ''\n\n  @state() private _imageLoading = false\n  @state() private _imageError = false\n\n  createRenderRoot() {\n    return this\n  }\n\n  connectedCallback() {\n    super.connectedCallback()\n    this._resetImageState()\n  }\n\n  protected willUpdate(changed: Map<string, unknown>) {\n    if (changed.has('icon') || (changed.has('color') && this._outputType() === 'iconify')) {\n      this._resetImageState()\n    }\n  }\n\n  private _outputType(): IconOutputType {\n    if (typeof this.icon !== 'string') {\n      return 'empty'\n    }\n\n    const icon = this.icon.trim()\n    if (!icon) {\n      return 'empty'\n    }\n\n    const hasPathFeatures = (value: string) => /^\\.{1,2}\\//.test(value) || value.startsWith('/') || value.includes('/')\n    if (/^https?:\\/\\//.test(icon) || hasPathFeatures(icon)) {\n      return 'img'\n    }\n\n    if (/^i-[^:]+:[^:]+/.test(icon)) {\n      return 'unocss'\n    }\n\n    if (icon.startsWith('i-') && !icon.includes(':')) {\n      return 'css'\n    }\n\n    if (icon.includes(':') && !icon.startsWith('i-')) {\n      return 'iconify'\n    }\n\n    if (/^[\\w-]+$/.test(icon) && !icon.startsWith('i-')) {\n      return 'svg'\n    }\n\n    return 'css'\n  }\n\n  private _iconName() {\n    return typeof this.icon === 'string' ? this.icon.trim() : ''\n  }\n\n  private _resetImageState() {\n    const type = this._outputType()\n    if (type === 'img' || type === 'iconify') {\n      this._imageLoading = true\n      this._imageError = false\n      return\n    }\n\n    this._imageLoading = false\n    this._imageError = false\n  }\n\n  private _formatSize(size: string | number | undefined) {\n    if (size == null || size === '') {\n      return ''\n    }\n\n    if (typeof size === 'number') {\n      return `${size}px`\n    }\n\n    if (/^\\d+(?:\\.\\d+)?$/.test(size)) {\n      return `${size}px`\n    }\n\n    return size\n  }\n\n  private _transformStyle() {\n    const transforms: string[] = []\n\n    switch (this.flip) {\n      case 'horizontal':\n        transforms.push('rotateY(180deg)')\n        break\n      case 'vertical':\n        transforms.push('rotateX(180deg)')\n        break\n      case 'both':\n        transforms.push('rotateX(180deg)', 'rotateY(180deg)')\n        break\n    }\n\n    if (this.rotate) {\n      transforms.push(`rotate(${this.rotate % 360}deg)`)\n    }\n\n    return transforms.join(' ')\n  }\n\n  private _containerStyle() {\n    const formattedSize = this._formatSize(this.size) || '1em'\n    const transform = this._transformStyle()\n\n    return {\n      position: 'relative',\n      display: 'inline-flex',\n      alignItems: 'center',\n      justifyContent: 'center',\n      width: formattedSize,\n      height: formattedSize,\n      fontSize: formattedSize,\n      lineHeight: '1',\n      color: this.color || 'currentColor',\n      verticalAlign: '-2px',\n      transform: transform || undefined,\n      transformOrigin: 'center',\n      fill: 'currentColor',\n    }\n  }\n\n  private _glyphStyle() {\n    return {\n      display: 'inline-flex',\n      alignItems: 'center',\n      justifyContent: 'center',\n      width: '100%',\n      height: '100%',\n      lineHeight: '1',\n      color: 'inherit',\n      fontSize: 'inherit',\n      flexShrink: '0',\n    }\n  }\n\n  private _imageStyle(visible = true) {\n    return {\n      display: visible ? 'block' : 'none',\n      width: '100%',\n      height: '100%',\n      objectFit: 'contain',\n      flexShrink: '0',\n    }\n  }\n\n  private _imageSource() {\n    if (this._outputType() === 'iconify') {\n      const url = new URL(`https://api.iconify.design/${this._iconName()}.svg`)\n      if (this.color) {\n        url.searchParams.set('color', this.color)\n      }\n      return url.toString()\n    }\n    return this._iconName()\n  }\n\n  private _renderClassGlyph(iconClass: string) {\n    const classes = iconClass.split(/\\s+/).filter(Boolean).join(' ')\n    if (!classes) {\n      return nothing\n    }\n\n    return html`<i class=${classes} style=${styleMap(this._glyphStyle())} aria-hidden=\"true\"></i>`\n  }\n\n  private _renderSvgSprite() {\n    const iconName = this._iconName()\n    if (!iconName) {\n      return nothing\n    }\n\n    return html`\n      <svg\n        aria-hidden=\"true\"\n        viewBox=\"0 0 1024 1024\"\n        style=${styleMap({\n          display: 'block',\n          width: '100%',\n          height: '100%',\n          fill: 'currentColor',\n          flexShrink: '0',\n        })}\n      >\n        <use href=${`#${this.localIconPrefix}${iconName}`}></use>\n      </svg>\n    `\n  }\n\n  private _renderImage() {\n    const source = this._imageSource()\n    if (!source) {\n      return nothing\n    }\n\n    const showFallback = this._imageError && !!this.fallback\n    const showLoading = !this._imageError && this._imageLoading && !!this.loading\n    const showImage = !this._imageError && !showLoading\n\n    return html`\n      ${showLoading ? this._renderClassGlyph(this.loading) : nothing}\n      ${showFallback ? this._renderClassGlyph(this.fallback) : nothing}\n      <img\n        src=${source}\n        alt=\"\"\n        style=${styleMap(this._imageStyle(showImage))}\n        @load=${() => {\n          this._imageLoading = false\n          this._imageError = false\n        }}\n        @error=${() => {\n          this._imageLoading = false\n          this._imageError = true\n        }}\n      />\n    `\n  }\n\n  render() {\n    const type = this._outputType()\n    if (type === 'empty') {\n      return nothing\n    }\n\n    let content: ReturnType<typeof html> | typeof nothing = nothing\n\n    switch (type) {\n      case 'iconify':\n      case 'img':\n        content = this._renderImage()\n        break\n      case 'unocss':\n      case 'css':\n        content = this._renderClassGlyph(this._iconName())\n        break\n      case 'svg':\n        content = this._renderSvgSprite()\n        break\n      default:\n        content = nothing\n    }\n\n    return html`<span class=\"qxs-icon-wc\" style=${styleMap(this._containerStyle())}>${content}</span>`\n  }\n}\n\nexport function register() {\n  // auto-registered via @safeCustomElement\n}\n"],"names":["QxsIcon","LitElement","changed","icon","hasPathFeatures","value","type","size","transforms","formattedSize","transform","visible","url","iconClass","classes","html","styleMap","nothing","iconName","source","showFallback","showLoading","showImage","content","__decorateClass","property","state","safeCustomElement"],"mappings":"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"}