/* ============================================================
   Componentes base — Promotoria Hyris
   Exporta em window.* no final.
   ============================================================ */
const { useState, useRef, useEffect } = React;

/* ---------- Ícones (stroke, minimalistas) ---------- */
function Icon({ name, size = 20, style }) {
  const s = { width: size, height: size, display: "block", flexShrink: 0, ...style };
  const p = { fill: "none", stroke: "currentColor", strokeWidth: 1.8, strokeLinecap: "round", strokeLinejoin: "round" };
  const paths = {
    feed: <><path {...p} d="M4 5h16M4 12h16M4 19h10" /></>,
    megaphone: <><path {...p} d="M3 11v2a1 1 0 0 0 1 1h2l4 4V6L6 10H4a1 1 0 0 0-1 1Z" /><path {...p} d="M14 8a4 4 0 0 1 0 8M10 18v2" /></>,
    calendar: <><rect {...p} x="3" y="4" width="18" height="17" rx="2.5" /><path {...p} d="M3 9h18M8 2v4M16 2v4" /></>,
    pin: <><path {...p} d="M9 4h6l-1 7 3 3H7l3-3-1-7ZM12 17v4" /></>,
    users: <><circle {...p} cx="9" cy="8" r="3.2" /><path {...p} d="M3 20a6 6 0 0 1 12 0M16 5.5a3 3 0 0 1 0 5.8M18 20a5 5 0 0 0-3-4.6" /></>,
    key: <><circle {...p} cx="8" cy="15" r="4" /><path {...p} d="M11 12l8-8M16 4l3 3M14 6l3 3" /></>,
    plus: <><path {...p} d="M12 5v14M5 12h14" /></>,
    edit: <><path {...p} d="M4 20h4L19 9l-4-4L4 16v4ZM14 6l4 4" /></>,
    trash: <><path {...p} d="M4 7h16M9 7V4h6v3M6 7l1 13h10l1-13" /></>,
    reply: <><path {...p} d="M9 7L4 12l5 5M4 12h11a5 5 0 0 1 5 5v1" /></>,
    search: <><circle {...p} cx="11" cy="11" r="7" /><path {...p} d="M20 20l-3.5-3.5" /></>,
    eye: <><path {...p} d="M2 12s4-7 10-7 10 7 10 7-4 7-10 7-10-7-10-7Z" /><circle {...p} cx="12" cy="12" r="3" /></>,
    eyeoff: <><path {...p} d="M3 3l18 18M10.5 10.6a3 3 0 0 0 4 4M9.9 4.6A10 10 0 0 1 22 12a17 17 0 0 1-3 3.6M6.6 6.6A17 17 0 0 0 2 12s4 7 10 7a10 10 0 0 0 3.4-.6" /></>,
    copy: <><rect {...p} x="9" y="9" width="11" height="11" rx="2" /><path {...p} d="M5 15V5a2 2 0 0 1 2-2h8" /></>,
    logout: <><path {...p} d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4M16 17l5-5-5-5M21 12H9" /></>,
    check: <><path {...p} d="M5 12l5 5L20 6" /></>,
    x: <><path {...p} d="M6 6l12 12M18 6L6 18" /></>,
    chevron: <><path {...p} d="M9 6l6 6-6 6" /></>,
    back: <><path {...p} d="M15 6l-6 6 6 6" /></>,
    dot: <><circle cx="12" cy="12" r="4" fill="currentColor" stroke="none" /></>,
    lock: <><rect {...p} x="5" y="11" width="14" height="9" rx="2" /><path {...p} d="M8 11V8a4 4 0 0 1 8 0v3" /></>,
    shield: <><path {...p} d="M12 3l7 3v5c0 4.5-3 8-7 10-4-2-7-5.5-7-10V6l7-3Z" /></>,
    star: <><path {...p} d="M12 3l2.6 5.6L20 9.3l-4 4 1 6-5-2.8L7 19.3l1-6-4-4 5.4-.7L12 3Z" /></>,
    refresh: <><path {...p} d="M4 12a8 8 0 0 1 13.5-5.8L20 8M20 4v4h-4M20 12a8 8 0 0 1-13.5 5.8L4 16M4 20v-4h4" /></>,
    dots: <><circle cx="5" cy="12" r="1.6" fill="currentColor" stroke="none" /><circle cx="12" cy="12" r="1.6" fill="currentColor" stroke="none" /><circle cx="19" cy="12" r="1.6" fill="currentColor" stroke="none" /></>,
    smile: <><circle {...p} cx="12" cy="12" r="9" /><path {...p} d="M8.5 14a4 4 0 0 0 7 0" /><circle cx="9" cy="9.5" r="1.1" fill="currentColor" stroke="none" /><circle cx="15" cy="9.5" r="1.1" fill="currentColor" stroke="none" /></>,
    folder: <><path {...p} d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V7Z" /></>,
    bell: <><path {...p} d="M6 9a6 6 0 0 1 12 0c0 5 2 6 2 6H4s2-1 2-6Z" /><path {...p} d="M10 21a2 2 0 0 0 4 0" /></>,
  };
  return <svg viewBox="0 0 24 24" style={s}>{paths[name] || null}</svg>;
}

/* ---------- Avatar (iniciais em bloco) ---------- */
function mcHeadUrl(nick) {
  const clean = String(nick || "").trim().replace(/[^A-Za-z0-9_]/g, "");
  if (!clean) return null;
  return `https://mc-heads.net/avatar/${encodeURIComponent(clean)}/256`;
}

function Avatar({ member, size = 38 }) {
  const initials = (member.display || "?").slice(0, 2).toUpperCase();
  // permite override manual (member.avatar) ou usa a cabeça do Minecraft pelo nick
  const src = member.avatar || mcHeadUrl(member.display);
  const [failed, setFailed] = useState(false);
  // sempre que o nick/source mudar, tenta carregar de novo
  useEffect(() => { setFailed(false); }, [src]);

  const box = {
    width: size, height: size, borderRadius: size * 0.28,
    border: `1px solid ${member.color}55`,
  };

  if (src && !failed) {
    return (
      <div className="pr-avatar pr-avatar-img" style={box}>
        <img src={src} alt={member.display} draggable={false}
          style={{ imageRendering: "pixelated" }}
          onError={() => setFailed(true)} />
      </div>
    );
  }
  return (
    <div className="pr-avatar" style={{
      ...box,
      background: `linear-gradient(150deg, ${member.color}33, ${member.color}14)`,
      color: member.color,
      fontSize: size * 0.36,
    }}>
      {initials}
    </div>
  );
}

/* ---------- Medalha do cargo (emoji ou imagem) ---------- */
function Medal({ role, size = 15 }) {
  const r = PR.ROLES[role];
  const m = r && r.medal;
  if (!m || !m.value) return null;
  if (m.type === "image") {
    return <img className="pr-medal-img" src={m.value} alt="" style={{ width: size, height: size }} />;
  }
  return <span className="pr-medal-emoji" style={{ fontSize: size }}>{m.value}</span>;
}

/* ---------- Badge de cargo ---------- */
function RoleBadge({ role, size = "md" }) {
  const r = PR.ROLES[role];
  if (!r) return null;
  return (
    <span className={"pr-rolebadge " + size} style={{ color: r.color, background: r.color + "1c", borderColor: r.color + "44" }}>
      {r.label}
    </span>
  );
}

/* ---------- Botão ---------- */
function Button({ children, variant = "primary", size = "md", icon, onClick, type, disabled, full, style }) {
  return (
    <button
      type={type || "button"}
      className={`pr-btn ${variant} ${size}${full ? " full" : ""}`}
      onClick={onClick}
      disabled={disabled}
      style={style}
    >
      {icon && <Icon name={icon} size={size === "sm" ? 15 : 17} />}
      {children}
    </button>
  );
}

/* ---------- Input / Textarea ---------- */
function Field({ label, hint, children }) {
  return (
    <label className="pr-field">
      {label && <span className="pr-field-label">{label}</span>}
      {children}
      {hint && <span className="pr-field-hint">{hint}</span>}
    </label>
  );
}
function Input(props) { return <input className="pr-input" {...props} />; }
const Textarea = React.forwardRef(function Textarea(props, ref) { return <textarea ref={ref} className="pr-input pr-textarea" {...props} />; });

/* ---------- Textarea com @menção + emoji (estilo Discord) ---------- */
// calcula a posição (viewport) do cursor dentro de um textarea
function caretCoords(el) {
  const cs = getComputedStyle(el);
  const div = document.createElement("div");
  const props = ["fontFamily","fontSize","fontWeight","fontStyle","letterSpacing","textTransform","lineHeight","paddingTop","paddingRight","paddingBottom","paddingLeft","borderTopWidth","borderRightWidth","borderBottomWidth","borderLeftWidth"];
  props.forEach((p) => { div.style[p] = cs[p]; });
  div.style.position = "absolute";
  div.style.visibility = "hidden";
  div.style.whiteSpace = "pre-wrap";
  div.style.wordWrap = "break-word";
  div.style.boxSizing = "border-box";
  div.style.width = el.offsetWidth + "px";
  div.style.top = "0";
  div.style.left = "-9999px";
  const pos = el.selectionStart;
  div.textContent = el.value.slice(0, pos);
  const span = document.createElement("span");
  span.textContent = el.value.slice(pos) || ".";
  div.appendChild(span);
  document.body.appendChild(div);
  const top = span.offsetTop;
  const left = span.offsetLeft;
  document.body.removeChild(div);
  let lh = parseFloat(cs.lineHeight);
  if (isNaN(lh)) lh = parseFloat(cs.fontSize) * 1.4;
  const r = el.getBoundingClientRect();
  return {
    caretTop: r.top + top - el.scrollTop,
    caretBottom: r.top + top - el.scrollTop + lh,
    caretLeft: r.left + left - el.scrollLeft,
  };
}

function MentionTextarea({ value, onChange, members = [], rows = 4, placeholder, taRef, onKeyDown }) {
  const innerRef = useRef(null);
  const ta = taRef || innerRef;
  const [ac, setAc] = useState(null);       // {type, start, end, items, active, pos}
  const [showEmoji, setShowEmoji] = useState(false);
  const [emojiPos, setEmojiPos] = useState(null);
  const [emojiQ, setEmojiQ] = useState("");

  function popupPos() {
    const el = ta.current;
    const c = caretCoords(el);
    const W = 300;
    let left = Math.min(c.caretLeft, window.innerWidth - W - 12);
    left = Math.max(12, left);
    const spaceBelow = window.innerHeight - c.caretBottom;
    if (spaceBelow < 280 && c.caretTop > 280) {
      return { left, top: c.caretTop - 6, flip: true };
    }
    return { left, top: c.caretBottom + 6, flip: false };
  }

  function refreshAC() {
    const el = ta.current; if (!el) { setAc(null); return; }
    if (el.selectionStart !== el.selectionEnd) { setAc(null); return; }
    const upto = el.value.slice(0, el.selectionStart);
    const m = upto.match(/(^|[\s\n(])([@:])([\w.+-]*)$/);
    if (!m) { setAc(null); return; }
    const sym = m[2], query = m[3];
    const start = el.selectionStart - query.length - 1;
    let items;
    if (sym === "@") {
      const q = query.toLowerCase();
      const groups = PR.MENTION_GROUPS
        .filter((g) => g.key.includes(q) || g.aliases.some((a) => a.includes(q)) || g.label.toLowerCase().includes(q))
        .map((g) => ({ group: true, key: g.key, label: g.label, desc: g.desc, color: g.color }));
      const mems = members.filter((mm) => mm.username.toLowerCase().includes(q) || mm.display.toLowerCase().includes(q)).slice(0, 6);
      items = [...groups, ...mems];
      if (!items.length) { setAc(null); return; }
      setAc({ type: "mention", start, end: el.selectionStart, items, active: 0, pos: popupPos() });
    } else {
      if (query.length < 2) { setAc(null); return; }
      const q = query.toLowerCase();
      items = PR.EMOJIS.filter((em) => em.n.some((n) => n.includes(q))).slice(0, 8);
      if (!items.length) { setAc(null); return; }
      setAc({ type: "emoji", start, end: el.selectionStart, items, active: 0, pos: popupPos() });
    }
  }

  function accept(item) {
    const el = ta.current; const v = el.value;
    let insert;
    if (ac.type === "mention") insert = "@" + (item.group ? item.key : item.username) + " ";
    else insert = item.e + " ";
    const next = v.slice(0, ac.start) + insert + v.slice(ac.end);
    onChange(next);
    const caret = ac.start + insert.length;
    setAc(null);
    requestAnimationFrame(() => { el.focus(); el.setSelectionRange(caret, caret); });
  }

  function insertAtCaret(text) {
    const el = ta.current; const v = el.value;
    const pos = el ? el.selectionStart : v.length;
    const next = v.slice(0, pos) + text + v.slice(pos);
    onChange(next);
    const caret = pos + text.length;
    requestAnimationFrame(() => { el.focus(); el.setSelectionRange(caret, caret); });
  }

  function openEmoji() {
    const el = ta.current;
    const btn = el.parentNode.querySelector(".pr-emoji-btn");
    const r = btn.getBoundingClientRect();
    const W = 300, H = 264;
    let left = Math.min(r.right - W, window.innerWidth - W - 12);
    left = Math.max(12, left);
    let top, flip;
    if (r.top - 8 - H > 12) { top = r.top - 8; flip = true; }       // acima do botão
    else { top = r.bottom + 8; flip = false; }
    // garante que a caixa inteira caiba na viewport
    if (flip) top = Math.max(H + 12, Math.min(top, window.innerHeight - 12));
    else top = Math.max(12, Math.min(top, window.innerHeight - 12 - H));
    setEmojiPos({ left, top, flip });
    setShowEmoji(true);
  }

  function handleKey(e) {
    if (ac) {
      if (e.key === "ArrowDown") { e.preventDefault(); setAc((a) => ({ ...a, active: (a.active + 1) % a.items.length })); return; }
      if (e.key === "ArrowUp") { e.preventDefault(); setAc((a) => ({ ...a, active: (a.active - 1 + a.items.length) % a.items.length })); return; }
      if (e.key === "Enter" || e.key === "Tab") { e.preventDefault(); accept(ac.items[ac.active]); return; }
      if (e.key === "Escape") { e.preventDefault(); setAc(null); return; }
    }
    if (onKeyDown) onKeyDown(e);
  }

  const emojiList = emojiQ.trim()
    ? PR.EMOJIS.filter((em) => em.n.some((n) => n.includes(emojiQ.toLowerCase())))
    : PR.EMOJIS;

  return (
    <div className="pr-mta">
      <textarea
        ref={ta}
        className="pr-input pr-textarea"
        rows={rows}
        placeholder={placeholder}
        value={value}
        onChange={(e) => { onChange(e.target.value); requestAnimationFrame(refreshAC); }}
        onKeyUp={refreshAC}
        onClick={refreshAC}
        onScroll={() => ac && setAc(null)}
        onKeyDown={handleKey}
        onBlur={() => setTimeout(() => setAc(null), 150)}
      />
      <button type="button" className="pr-emoji-btn" title="Emoji" onMouseDown={(e) => e.preventDefault()} onClick={() => showEmoji ? setShowEmoji(false) : openEmoji()}>😀</button>

      {ac && (
        <div className={"pr-ac " + ac.type} style={{ left: ac.pos.left, top: ac.pos.top, transform: ac.pos.flip ? "translateY(-100%)" : "none" }}>
          <div className="pr-ac-head">{ac.type === "mention" ? "Membros" : "Emojis"}</div>
          {ac.items.map((it, i) => (
            <button key={i} type="button" className={"pr-ac-item" + (i === ac.active ? " active" : "")}
              onMouseDown={(e) => { e.preventDefault(); accept(it); }}
              onMouseEnter={() => setAc((a) => ({ ...a, active: i }))}>
              {ac.type === "mention"
                ? (it.group
                    ? <><span className="pr-ac-group-ic" style={it.color ? { background: "color-mix(in oklab, " + it.color + " 20%, transparent)", color: it.color } : {}}><Icon name="users" size={15} /></span><span className="pr-ac-name" style={it.color ? { color: it.color } : {}}>@{it.key}</span><span className="pr-ac-sub">{it.desc}</span></>
                    : <><Avatar member={it} size={24} /><span className="pr-ac-name">{it.display}</span><span className="pr-ac-sub">@{it.username}</span><RoleBadge role={it.role} size="sm" /></>)
                : <><span className="pr-ac-emoji">{it.e}</span><span className="pr-ac-name">:{it.n[0]}:</span></>}
            </button>
          ))}
        </div>
      )}

      {showEmoji && emojiPos && (
        <>
          <div className="pr-emoji-scrim" onClick={() => setShowEmoji(false)}></div>
          <div className="pr-emoji-pop" style={{ left: emojiPos.left, top: emojiPos.top, transform: emojiPos.flip ? "translateY(-100%)" : "none" }}>
            <div className="pr-emoji-search">
              <Icon name="search" size={15} />
              <input autoFocus placeholder="Buscar emoji..." value={emojiQ} onChange={(e) => setEmojiQ(e.target.value)} />
            </div>
            <div className="pr-emoji-grid">
              {emojiList.map((em, i) => (
                <button key={i} type="button" className="pr-emoji-cell" title={":" + em.n[0] + ":"}
                  onClick={() => { insertAtCaret(em.e + " "); setShowEmoji(false); setEmojiQ(""); }}>{em.e}</button>
              ))}
              {emojiList.length === 0 && <div className="pr-emoji-empty">Nenhum emoji</div>}
            </div>
          </div>
        </>
      )}
    </div>
  );
}
function Select({ children, ...props }) {
  return (
    <div className="pr-select-wrap">
      <select className="pr-input pr-select" {...props}>{children}</select>
      <Icon name="chevron" size={16} style={{ transform: "rotate(90deg)" }} />
    </div>
  );
}

/* ---------- Select2: dropdown com busca, cor e medalha ---------- */
function Select2({ value, onChange, options, placeholder = "Selecionar...", searchable, size }) {
  const [open, setOpen] = useState(false);
  const [q, setQ] = useState("");
  const [pos, setPos] = useState(null);
  const [active, setActive] = useState(0);
  const wrapRef = useRef(null);
  const auto = searchable !== undefined ? searchable : options.length > 6;

  const selected = options.find((o) => o.value === value);
  const filtered = q.trim() ? options.filter((o) => o.label.toLowerCase().includes(q.toLowerCase())) : options;

  function openMenu() {
    const r = wrapRef.current.getBoundingClientRect();
    const W = Math.max(r.width, 210);
    const maxH = 296;
    let left = r.left;
    if (left + W > window.innerWidth - 12) left = window.innerWidth - 12 - W;
    left = Math.max(12, left);
    let top, flip = false;
    if (window.innerHeight - r.bottom < maxH && r.top > maxH) { top = r.top - 6; flip = true; }
    else { top = r.bottom + 6; }
    setPos({ left, top, width: W, flip });
    setQ("");
    setActive(Math.max(0, options.findIndex((o) => o.value === value)));
    setOpen(true);
  }
  function choose(o) { onChange(o.value); setOpen(false); }
  function onKey(e) {
    if (e.key === "ArrowDown") { e.preventDefault(); setActive((a) => Math.min(filtered.length - 1, a + 1)); }
    else if (e.key === "ArrowUp") { e.preventDefault(); setActive((a) => Math.max(0, a - 1)); }
    else if (e.key === "Enter") { e.preventDefault(); if (filtered[active]) choose(filtered[active]); }
    else if (e.key === "Escape") { e.preventDefault(); setOpen(false); }
  }

  function renderGlyph(o, s) {
    if (o.role) return <Medal role={o.role} size={s} />;
    if (o.color) return <span className="pr-s2-dot" style={{ background: o.color }}></span>;
    return null;
  }

  return (
    <div className={"pr-s2" + (size === "sm" ? " sm" : "")} ref={wrapRef}>
      <button type="button" className={"pr-s2-btn" + (open ? " open" : "")} onClick={() => open ? setOpen(false) : openMenu()}>
        {selected
          ? <span className="pr-s2-val">{renderGlyph(selected, 15)}<span style={selected.color ? { color: selected.color, fontWeight: 600 } : null}>{selected.label}</span></span>
          : <span className="pr-s2-ph">{placeholder}</span>}
        <Icon name="chevron" size={15} style={{ transform: "rotate(90deg)", opacity: .55, flexShrink: 0 }} />
      </button>

      {open && pos && (
        <>
          <div className="pr-s2-scrim" onClick={() => setOpen(false)}></div>
          <div className="pr-s2-pop" style={{ left: pos.left, top: pos.top, width: pos.width, transform: pos.flip ? "translateY(-100%)" : "none" }} onKeyDown={onKey}>
            {auto && (
              <div className="pr-s2-search">
                <Icon name="search" size={14} />
                <input autoFocus placeholder="Buscar..." value={q} onChange={(e) => { setQ(e.target.value); setActive(0); }} />
              </div>
            )}
            <div className="pr-s2-list">
              {filtered.map((o, i) => (
                <button type="button" key={o.value}
                  className={"pr-s2-opt" + (o.value === value ? " sel" : "") + (i === active ? " active" : "")}
                  onMouseEnter={() => setActive(i)} onClick={() => choose(o)}>
                  {renderGlyph(o, 15)}
                  <span className="pr-s2-opt-label" style={o.color ? { color: o.color } : null}>{o.label}</span>
                  {o.value === value && <Icon name="check" size={15} style={{ marginLeft: "auto", opacity: .8 }} />}
                </button>
              ))}
              {filtered.length === 0 && <div className="pr-s2-empty">Nada encontrado</div>}
            </div>
          </div>
        </>
      )}
    </div>
  );
}

/* ---------- Seletor de cor: presets + cor livre ---------- */
const PR_PALETTE = [
  "#FFCB1E","#FFD84D","#FF9F1C","#FF7A59","#FF5C6C","#FF5C8A","#E84393","#C56CF0",
  "#9B5BFF","#7C5CFF","#5B6BFF","#4D9BFF","#18D6E8","#2BD4C0","#2FD27A","#7BE36B",
  "#B8C24D","#8C8C9E","#C0C0CF","#FFFFFF",
];
function SwatchPicker({ value, onChange, palette }) {
  const colors = palette || PR_PALETTE;
  const isPreset = colors.includes((value || "").toUpperCase()) || colors.includes(value);
  return (
    <div className="pr-swatches">
      {colors.map((c) => (
        <button key={c} type="button" className={"pr-swatch" + (value && value.toLowerCase() === c.toLowerCase() ? " on" : "")}
          style={{ background: c }} onClick={() => onChange(c)} title={c}>
          {value && value.toLowerCase() === c.toLowerCase() && <Icon name="check" size={13} />}
        </button>
      ))}
      <label className={"pr-swatch pr-swatch-custom" + (!isPreset ? " on" : "")} title="Escolher cor personalizada"
        style={!isPreset && value ? { background: value } : {}}>
        {!isPreset && value ? <Icon name="check" size={13} /> : <Icon name="plus" size={15} />}
        <input type="color" value={value || "#9B5BFF"} onChange={(e) => onChange(e.target.value)} />
      </label>
    </div>
  );
}

/* ---------- Modal ---------- */
function Modal({ title, onClose, children, width = 560, footer }) {
  useEffect(() => {
    const h = (e) => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", h);
    return () => window.removeEventListener("keydown", h);
  }, [onClose]);
  return (
    <div className="pr-modal-scrim" onMouseDown={onClose}>
      <div className="pr-modal" style={{ maxWidth: width }} onMouseDown={(e) => e.stopPropagation()}>
        <div className="pr-modal-head">
          <h3>{title}</h3>
          <button className="pr-iconbtn" onClick={onClose}><Icon name="x" size={18} /></button>
        </div>
        <div className="pr-modal-body">{children}</div>
        {footer && <div className="pr-modal-foot">{footer}</div>}
      </div>
    </div>
  );
}

/* ---------- Confirm ---------- */
function Confirm({ title, message, confirmLabel = "Confirmar", danger, onConfirm, onClose }) {
  return (
    <Modal title={title} onClose={onClose} width={440}
      footer={<>
        <Button variant="ghost" onClick={onClose}>Cancelar</Button>
        <Button variant={danger ? "danger" : "primary"} onClick={() => { onConfirm(); onClose(); }}>{confirmLabel}</Button>
      </>}>
      <p style={{ color: "var(--muted)", lineHeight: 1.6, margin: 0 }}>{message}</p>
    </Modal>
  );
}

/* ---------- Toast ---------- */
function useToasts() {
  const [toasts, setToasts] = useState([]);
  const push = (msg, kind = "ok") => {
    const id = Math.random().toString(36).slice(2);
    setToasts((t) => [...t, { id, msg, kind }]);
    setTimeout(() => setToasts((t) => t.filter((x) => x.id !== id)), 2600);
  };
  const node = (
    <div className="pr-toasts">
      {toasts.map((t) => (
        <div key={t.id} className={"pr-toast " + t.kind}>
          <Icon name={t.kind === "err" ? "x" : "check"} size={16} />
          {t.msg}
        </div>
      ))}
    </div>
  );
  return [push, node];
}

function Portal({ children }) {
  return ReactDOM.createPortal(children, document.body);
}

Object.assign(window, {
  Icon, Avatar, Medal, RoleBadge, Button, Field, Input, Textarea, MentionTextarea, Select, Select2, SwatchPicker, Modal, Confirm, useToasts, Portal,
});
