{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "z-mail-content",
  "title": "Z Mail Content",
  "dependencies": [],
  "devDependencies": [],
  "registryDependencies": [
    "https://ui.orchid.ai/r/orchid-theme.json",
    "https://ui.orchid.ai/r/z-scroll-area.json"
  ],
  "files": [
    {
      "path": "registry/ui/orchid/spectrum/organisms/z-mail-view/z-mail-content.tsx",
      "content": "\"use client\";\nimport { useEffect, useRef } from 'react';\nimport { ZScrollArea } from \"../../atoms/z-scroll-area/z-scroll-area\";\ninterface Props {\n    html: string;\n}\nconst LINKABLE_TEXT_REGEX = /https?:\\/\\/[^\\s<>\"']+|(([^<>()[\\]\\\\.,;:\\s@\"]+(\\.[^<>()[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))/g;\nfunction linkifyText(root: ShadowRoot) {\n    const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {\n        acceptNode(node) {\n            if (!node.nodeValue || !hasLinkableText(node.nodeValue))\n                return NodeFilter.FILTER_REJECT;\n            const parent = (node as Text).parentElement;\n            if (!parent)\n                return NodeFilter.FILTER_REJECT;\n            if (parent.closest('a,script,style,textarea,code'))\n                return NodeFilter.FILTER_REJECT;\n            return NodeFilter.FILTER_ACCEPT;\n        },\n    });\n    const textNodes: Text[] = [];\n    while (walker.nextNode()) {\n        textNodes.push(walker.currentNode as Text);\n    }\n    for (const node of textNodes) {\n        const text = node.nodeValue ?? '';\n        LINKABLE_TEXT_REGEX.lastIndex = 0;\n        let match: RegExpExecArray | null;\n        let lastIndex = 0;\n        let didReplace = false;\n        const fragment = document.createDocumentFragment();\n        while ((match = LINKABLE_TEXT_REGEX.exec(text)) !== null) {\n            const rawMatch = match[0];\n            const start = match.index;\n            const [linkText, trailingText] = splitTrailingPunctuation(rawMatch);\n            if (!linkText) {\n                continue;\n            }\n            const href = isUrl(linkText) ? linkText : `mailto:${linkText}`;\n            if (start > lastIndex) {\n                fragment.append(document.createTextNode(text.slice(lastIndex, start)));\n            }\n            const anchor = document.createElement('a');\n            anchor.setAttribute('href', href);\n            anchor.textContent = linkText;\n            fragment.append(anchor);\n            if (trailingText) {\n                fragment.append(document.createTextNode(trailingText));\n            }\n            lastIndex = start + rawMatch.length;\n            didReplace = true;\n        }\n        if (!didReplace)\n            continue;\n        if (lastIndex < text.length) {\n            fragment.append(document.createTextNode(text.slice(lastIndex)));\n        }\n        node.parentNode?.replaceChild(fragment, node);\n    }\n}\nfunction hasLinkableText(text: string) {\n    return text.includes('@') || text.includes('http://') || text.includes('https://');\n}\nfunction splitTrailingPunctuation(value: string): [\n    string,\n    string\n] {\n    let end = value.length;\n    while (end > 0 && /[),.;!?]$/.test(value.slice(0, end))) {\n        end -= 1;\n    }\n    return [value.slice(0, end), value.slice(end)];\n}\nfunction isUrl(value: string) {\n    return value.startsWith('http://') || value.startsWith('https://');\n}\nfunction forceLightEmailHtml(html: string): string {\n    return html\n        .replace(/prefers-color-scheme:\\s*dark/gi, 'max-width: 0px')\n        .replace(/prefers-color-scheme:\\s*light/gi, 'min-width: 0px');\n}\nfunction forceLightEmailStyles(root: ShadowRoot) {\n    root.querySelectorAll('style').forEach((styleEl) => {\n        const css = styleEl.textContent ?? '';\n        if (!css.includes('prefers-color-scheme'))\n            return;\n        styleEl.textContent = css\n            .replace(/prefers-color-scheme\\s*:\\s*dark/gi, 'max-width: 0px')\n            .replace(/prefers-color-scheme\\s*:\\s*light/gi, 'min-width: 0px');\n    });\n}\nfunction handleLinkClick(e: Event) {\n    const target = (e.target as HTMLElement).closest('a');\n    if (!target)\n        return;\n    e.preventDefault();\n    const href = target.getAttribute('href');\n    if (href && (href.startsWith('http://') || href.startsWith('https://'))) {\n        window.open(href, '_blank', 'noopener,noreferrer');\n    }\n    else if (href && href.startsWith('mailto:')) {\n        window.location.href = href;\n    }\n}\nexport function ZMailContent({ html }: Props) {\n    const hostRef = useRef<HTMLDivElement>(null);\n    const shadowRootRef = useRef<ShadowRoot | null>(null);\n    useEffect(() => {\n        if (!hostRef.current || shadowRootRef.current)\n            return;\n        shadowRootRef.current = hostRef.current.attachShadow({ mode: 'open' });\n    }, []);\n    useEffect(() => {\n        const root = shadowRootRef.current;\n        if (!root || !html)\n            return;\n        const baseStyles = `\n      <style>\n        :host {\n          color-scheme: light;\n          display: block;\n        }\n\n        #email-root {\n          background-color: #fff;\n          color: #1a1a1a;\n          font-family: Helvetica Neue,Helvetica,Arial,sans-serif;\n          font-size: 16px;\n        }\n\n        html, body {\n          margin: 0;\n          width: 100%;\n          max-width: 100%;\n          overflow-x: hidden;\n        }\n\n        table {\n          max-width: 100%;\n        }\n\n        img { max-width: 100%; }\n\n        pre,\n        xmp,\n        plaintext,\n        code,\n        samp,\n        kbd {\n          white-space: pre-wrap !important;\n          overflow-wrap: anywhere !important;\n          word-break: break-word !important;\n          max-width: 100% !important;\n        }\n\n        div,\n        p,\n        span,\n        td,\n        li,\n        blockquote {\n          max-width: 100%;\n          overflow-wrap: anywhere;\n          word-break: break-word;\n        }\n\n        blockquote {\n          border-left: 3px solid #d4d4d4;\n          padding-left: 0.75rem;\n          margin-left: 0;\n        }\n\n        .quoted-toggle {\n          margin-top: 1em;\n        }\n        .quoted-toggle summary {\n          cursor: pointer;\n          font-size: 13px;\n          color: #737373;\n        }\n      </style>\n    `;\n        root.innerHTML = baseStyles + `<div id=\"email-root\">${forceLightEmailHtml(html)}</div>`;\n        forceLightEmailStyles(root);\n        const nestedDetails = root.querySelectorAll('details details');\n        nestedDetails.forEach((details) => {\n            const parentDetails = details.parentElement?.closest('details');\n            if (!parentDetails)\n                return;\n            Array.from(details.childNodes).forEach((node) => {\n                if (node.nodeName === 'SUMMARY')\n                    return;\n                parentDetails.appendChild(node);\n            });\n            details.remove();\n        });\n        linkifyText(root);\n        root.addEventListener('click', handleLinkClick);\n        return () => {\n            root.removeEventListener('click', handleLinkClick);\n        };\n    }, [html]);\n    return (<ZScrollArea className=\"w-full flex-1\">\n      <div ref={hostRef} className=\"m-0 w-full rounded-md p-0\" style={{ fontFamily: 'Helvetica Neue,Helvetica,Arial,sans-serif', fontSize: 16 }}/>\n    </ZScrollArea>);\n}\n",
      "type": "registry:ui",
      "target": "@ui/orchid/spectrum/organisms/z-mail-view/z-mail-content.tsx"
    }
  ],
  "type": "registry:ui"
}