@wrrdev/fenix-ui 1.1.9 → 1.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +20 -2
  2. package/dist/assets/{font-CF0TXsAP.js → font-DPeWTz-n.js} +58 -13
  3. package/dist/assets/font-DPeWTz-n.js.map +1 -0
  4. package/dist/components/breadcrumb/breadcrumb.d.ts +4 -0
  5. package/dist/components/breadcrumb/breadcrumb.d.ts.map +1 -1
  6. package/dist/components/breadcrumb/breadcrumb.js +12 -2
  7. package/dist/components/breadcrumb/breadcrumb.js.map +1 -1
  8. package/dist/components/table/table.d.ts +38 -0
  9. package/dist/components/table/table.d.ts.map +1 -1
  10. package/dist/components/table/table.js +34 -1
  11. package/dist/components/table/table.js.map +1 -1
  12. package/dist/components/toast/toast.d.ts +8 -0
  13. package/dist/components/toast/toast.d.ts.map +1 -1
  14. package/dist/components/toast/toast.js +13 -0
  15. package/dist/components/toast/toast.js.map +1 -1
  16. package/dist/components/tooltip/directive.d.ts +8 -0
  17. package/dist/components/tooltip/directive.d.ts.map +1 -1
  18. package/dist/components/tooltip/directive.js +59 -18
  19. package/dist/components/tooltip/directive.js.map +1 -1
  20. package/dist/core/jsx.d.ts +22 -1
  21. package/dist/core/jsx.d.ts.map +1 -1
  22. package/dist/core/jsx.js.map +1 -1
  23. package/dist/docs/app.d.ts.map +1 -1
  24. package/dist/docs/componentes/table-cell-rules.d.ts +3 -0
  25. package/dist/docs/componentes/table-cell-rules.d.ts.map +1 -0
  26. package/dist/docs/componentes/table.doc.d.ts.map +1 -1
  27. package/dist/docs/types.d.ts +9 -0
  28. package/dist/docs/types.d.ts.map +1 -1
  29. package/dist/fenix-ui.umd.min.js +142 -142
  30. package/dist/fenix-ui3.esm.js +8 -13
  31. package/dist/fenix-ui3.esm.js.map +1 -1
  32. package/dist/fenix-ui4.esm.js +190 -93
  33. package/dist/fenix-ui4.esm.js.map +1 -1
  34. package/dist/icons/font.d.ts +23 -0
  35. package/dist/icons/font.d.ts.map +1 -1
  36. package/dist/icons/font.js +54 -8
  37. package/dist/icons/font.js.map +1 -1
  38. package/dist/icons/index.d.ts +7 -2
  39. package/dist/icons/index.d.ts.map +1 -1
  40. package/dist/icons/index.js +6 -11
  41. package/dist/icons/index.js.map +1 -1
  42. package/package.json +1 -1
  43. package/dist/assets/font-CF0TXsAP.js.map +0 -1
@@ -5,8 +5,8 @@ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot
5
5
  var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
6
6
  var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
7
7
  var _FxToast_instances, syncProgress_fn, render_fn;
8
- import { a as FENIX_ICON_BASE_CSS, f as fenixIconHtml, e as esc, l as loadFenixIconsFont, i as isFenixIconName } from "./assets/font-CF0TXsAP.js";
9
- import { s, g } from "./assets/font-CF0TXsAP.js";
8
+ import { a as FENIX_ICON_BASE_CSS, f as fenixIconHtml, g as esc, l as loadFenixIconsFont, i as isFenixIconName } from "./assets/font-DPeWTz-n.js";
9
+ import { h, j } from "./assets/font-DPeWTz-n.js";
10
10
  const lightTokens = {
11
11
  color: {
12
12
  primary: "#c2410c",
@@ -353,8 +353,8 @@ const _FxButton = class _FxButton extends FxElement {
353
353
  }
354
354
  /** Tamanho. Padrão: `'md'`. */
355
355
  get size() {
356
- const s2 = this.getAttr("size", "md");
357
- return s2 === "sm" || s2 === "lg" ? s2 : "md";
356
+ const s = this.getAttr("size", "md");
357
+ return s === "sm" || s === "lg" ? s : "md";
358
358
  }
359
359
  set size(value) {
360
360
  this.setAttribute("size", value);
@@ -582,8 +582,8 @@ const _FxSpinner = class _FxSpinner extends FxElement {
582
582
  }
583
583
  /** Tamanho do spinner. Padrão: `'md'`. */
584
584
  get size() {
585
- const s2 = this.getAttr("size", "md");
586
- return s2 === "sm" || s2 === "lg" ? s2 : "md";
585
+ const s = this.getAttr("size", "md");
586
+ return s === "sm" || s === "lg" ? s : "md";
587
587
  }
588
588
  set size(value) {
589
589
  this.setAttribute("size", value);
@@ -627,8 +627,8 @@ const _FxSelect = class _FxSelect extends FxElement {
627
627
  }
628
628
  /** Tamanho do campo. Padrão: `'md'`. */
629
629
  get size() {
630
- const s2 = this.getAttr("size", "md");
631
- return s2 === "sm" || s2 === "lg" ? s2 : "md";
630
+ const s = this.getAttr("size", "md");
631
+ return s === "sm" || s === "lg" ? s : "md";
632
632
  }
633
633
  set size(value) {
634
634
  this.setAttribute("size", value);
@@ -971,8 +971,8 @@ const _FxInput = class _FxInput extends FxElement {
971
971
  }
972
972
  /** Tamanho do campo. Padrão: `'md'`. */
973
973
  get size() {
974
- const s2 = this.getAttr("size", "md");
975
- return s2 === "sm" || s2 === "lg" ? s2 : "md";
974
+ const s = this.getAttr("size", "md");
975
+ return s === "sm" || s === "lg" ? s : "md";
976
976
  }
977
977
  set size(value) {
978
978
  this.setAttribute("size", value);
@@ -1195,8 +1195,8 @@ const _FxSwitch = class _FxSwitch extends FxElement {
1195
1195
  }
1196
1196
  /** Tamanho da trilha. Padrão: `'md'`. */
1197
1197
  get size() {
1198
- const s2 = this.getAttr("size", "md");
1199
- return s2 === "sm" || s2 === "lg" ? s2 : "md";
1198
+ const s = this.getAttr("size", "md");
1199
+ return s === "sm" || s === "lg" ? s : "md";
1200
1200
  }
1201
1201
  set size(value) {
1202
1202
  this.setAttribute("size", value);
@@ -1838,13 +1838,13 @@ const _FxCalendar = class _FxCalendar extends FxElement {
1838
1838
  this.values.map((iso) => parseBound(iso)?.lo ?? 0).filter(Boolean)
1839
1839
  );
1840
1840
  if (this.mode === "range") {
1841
- let s2 = this.pickStart;
1841
+ let s = this.pickStart;
1842
1842
  let e = this.pickEnd;
1843
1843
  const attrS = parseBound(this.getAttr("start", ""));
1844
1844
  const attrE = parseBound(this.getAttr("end", ""));
1845
- if (s2 === null && attrS) s2 = attrS.lo;
1845
+ if (s === null && attrS) s = attrS.lo;
1846
1846
  if (e === null && attrE) e = attrE.lo;
1847
- return { start: s2, end: e, single: null, multi };
1847
+ return { start: s, end: e, single: null, multi };
1848
1848
  }
1849
1849
  if (this.mode === "multiple") {
1850
1850
  return { start: null, end: null, single: null, multi };
@@ -2220,15 +2220,15 @@ const _FxDatepicker = class _FxDatepicker extends FxElement {
2220
2220
  /** Texto exibido no input conforme o modo. */
2221
2221
  displayText() {
2222
2222
  if (this.mode === "range") {
2223
- const s2 = this.getAttr("start");
2223
+ const s = this.getAttr("start");
2224
2224
  const e = this.getAttr("end");
2225
2225
  this.hasAttr("show-time") ? " " : " → ";
2226
- if (!s2 && !e) return "";
2226
+ if (!s && !e) return "";
2227
2227
  if (this.hasAttr("show-time")) {
2228
2228
  const f = (iso) => iso ? `${this.formatDate(iso)} ${this.timeText()}` : iso ? `${this.formatDate(iso)} …` : "";
2229
- return s2 && e ? `${f(s2)} → ${f(e)}` : f(s2);
2229
+ return s && e ? `${f(s)} → ${f(e)}` : f(s);
2230
2230
  }
2231
- return s2 && e ? `${this.formatDate(s2)} → ${this.formatDate(e)}` : s2 ? `${this.formatDate(s2)} → …` : "";
2231
+ return s && e ? `${this.formatDate(s)} → ${this.formatDate(e)}` : s ? `${this.formatDate(s)} → …` : "";
2232
2232
  }
2233
2233
  if (this.mode === "multiple") {
2234
2234
  return this.values.map((v) => this.formatDate(v)).join(", ");
@@ -2246,8 +2246,8 @@ const _FxDatepicker = class _FxDatepicker extends FxElement {
2246
2246
  const src = this.value || this.getAttr("start") || "";
2247
2247
  const t = src.split("T")[1];
2248
2248
  if (!t) return;
2249
- const [h, m, s2] = t.split(":").map((n) => parseInt(n, 10));
2250
- this.time = { h: h || 0, m: m || 0, s: s2 || 0 };
2249
+ const [h2, m, s] = t.split(":").map((n) => parseInt(n, 10));
2250
+ this.time = { h: h2 || 0, m: m || 0, s: s || 0 };
2251
2251
  }
2252
2252
  /** Anexa o horário interno ao ISO puro vindo do calendário. */
2253
2253
  withTime(iso) {
@@ -2353,14 +2353,14 @@ const _FxDatepicker = class _FxDatepicker extends FxElement {
2353
2353
  }
2354
2354
  if (showTime) {
2355
2355
  const applyTime = () => {
2356
- const h = this.root.querySelector(".t-h");
2356
+ const h2 = this.root.querySelector(".t-h");
2357
2357
  const m = this.root.querySelector(".t-m");
2358
- const s2 = this.root.querySelector(".t-s");
2358
+ const s = this.root.querySelector(".t-s");
2359
2359
  const clamp = (v, max) => Math.min(max, Math.max(0, parseInt(v ?? "0", 10) || 0));
2360
2360
  this.time = {
2361
- h: clamp(h?.value, 23),
2361
+ h: clamp(h2?.value, 23),
2362
2362
  m: clamp(m?.value, 59),
2363
- s: clamp(s2?.value, 59)
2363
+ s: clamp(s?.value, 59)
2364
2364
  };
2365
2365
  const reattach = (iso) => iso.split("T")[0] ? `${iso.split("T")[0]}T${this.timeText()}` : iso;
2366
2366
  if (this.value) this.setAttribute("value", reattach(this.value));
@@ -2626,8 +2626,8 @@ const _FxCheckbox = class _FxCheckbox extends FxElement {
2626
2626
  }
2627
2627
  /** Tamanho do controle. Padrão: `'md'`. */
2628
2628
  get size() {
2629
- const s2 = this.getAttr("size", "md");
2630
- return s2 === "sm" || s2 === "lg" ? s2 : "md";
2629
+ const s = this.getAttr("size", "md");
2630
+ return s === "sm" || s === "lg" ? s : "md";
2631
2631
  }
2632
2632
  set size(value) {
2633
2633
  this.setAttribute("size", value);
@@ -2755,8 +2755,8 @@ const _FxRadio = class _FxRadio extends FxElement {
2755
2755
  }
2756
2756
  /** Tamanho do controle. Padrão: `'md'`. */
2757
2757
  get size() {
2758
- const s2 = this.getAttr("size", "md");
2759
- return s2 === "sm" || s2 === "lg" ? s2 : "md";
2758
+ const s = this.getAttr("size", "md");
2759
+ return s === "sm" || s === "lg" ? s : "md";
2760
2760
  }
2761
2761
  set size(value) {
2762
2762
  this.setAttribute("size", value);
@@ -3294,6 +3294,7 @@ const _FxTable = class _FxTable extends FxElement {
3294
3294
  this.sortDir = 1;
3295
3295
  this.filters = {};
3296
3296
  this.globalSearch = "";
3297
+ this._shellKey = "";
3297
3298
  }
3298
3299
  static get observedAttributes() {
3299
3300
  return [
@@ -3361,6 +3362,12 @@ const _FxTable = class _FxTable extends FxElement {
3361
3362
  * `innerHTML` sempre chega intacto ao componente. O light DOM do
3362
3363
  * `<fx-table>` não é exibido (a tabela não usa `<slot>`), então o
3363
3364
  * conteúdo-fonte nunca aparece na tela.
3365
+ *
3366
+ * ⚠️ O conteúdo é TEXTO CRU para o motor de expressões: o `{{ }}` NÃO é
3367
+ * interpretado pelo framework hospedeiro. Cada um precisa neutralizar a
3368
+ * própria sintaxe antes (ver o cabeçalho do arquivo): `v-pre` no Vue,
3369
+ * `{'{{ }}'}` no JSX, `ngNonBindable` no Angular, string/entidades no
3370
+ * Svelte. Sem isso o template não chega ao `renderCell`.
3364
3371
  * 2. `template="#id"` (ou `template="id"`) — aponta para um `<template>`
3365
3372
  * declarado **fora** da tabela, útil em React/Angular, onde é mais
3366
3373
  * simples manter o markup num único lugar.
@@ -3482,7 +3489,7 @@ const _FxTable = class _FxTable extends FxElement {
3482
3489
  if (!input) return [];
3483
3490
  const attr = input.getAttribute("data-search-fields");
3484
3491
  if (attr === null) return [];
3485
- return attr.split(",").map((s2) => s2.trim()).filter(Boolean);
3492
+ return attr.split(",").map((s) => s.trim()).filter(Boolean);
3486
3493
  }
3487
3494
  cellHtml(col, row) {
3488
3495
  const template = col.template?.innerHTML ?? col.directTemplate;
@@ -3524,6 +3531,23 @@ const _FxTable = class _FxTable extends FxElement {
3524
3531
  </div>`;
3525
3532
  const loading = this.hasAttr("loading");
3526
3533
  const loadingHtml = loading ? `<div class="loading-overlay" part="loading-overlay"><div class="tbl-spinner" part="spinner"></div><span class="loading-text">${esc(this.getAttr("loading-message", "Carregando…"))}</span></div>` : "";
3534
+ const shellKey = [
3535
+ toolbarHtml,
3536
+ headHtml,
3537
+ filterRow,
3538
+ pagerHtml,
3539
+ loadingHtml,
3540
+ cols.length
3541
+ ].join("|");
3542
+ if (shellKey === this._shellKey) {
3543
+ const tbody = this.root.querySelector("tbody");
3544
+ if (tbody) {
3545
+ tbody.innerHTML = bodyHtml;
3546
+ this._bindRowClicks(rows);
3547
+ return;
3548
+ }
3549
+ }
3550
+ this._shellKey = shellKey;
3527
3551
  this.setTemplate(`
3528
3552
  ${toolbarHtml}
3529
3553
  <div class="table-wrap">
@@ -3627,6 +3651,16 @@ const _FxTable = class _FxTable extends FxElement {
3627
3651
  this.page = 0;
3628
3652
  this.render();
3629
3653
  });
3654
+ this._bindRowClicks(rows);
3655
+ this._restoreToolbarSearch();
3656
+ }
3657
+ /**
3658
+ * Liga o clique das linhas ao evento `row-click`.
3659
+ *
3660
+ * Extraído do render para ser reaproveitado no caminho rápido (troca só do
3661
+ * <tbody>): os <tr> são novos, então precisam ser rebound.
3662
+ */
3663
+ _bindRowClicks(rows) {
3630
3664
  this.root.querySelectorAll("tbody tr[data-index]").forEach((tr) => {
3631
3665
  tr.addEventListener("click", () => {
3632
3666
  this.dispatchEvent(
@@ -3641,7 +3675,6 @@ const _FxTable = class _FxTable extends FxElement {
3641
3675
  );
3642
3676
  });
3643
3677
  });
3644
- this._restoreToolbarSearch();
3645
3678
  }
3646
3679
  _restoreToolbarSearch() {
3647
3680
  const input = this.root.querySelector(
@@ -4196,8 +4229,8 @@ const _FxTextarea = class _FxTextarea extends FxElement {
4196
4229
  return ["size", "placeholder", "disabled", "readonly", "rows", "maxlength", "error", "invalid", "success", "valid"];
4197
4230
  }
4198
4231
  get size() {
4199
- const s2 = this.getAttr("size", "md");
4200
- return s2 === "sm" || s2 === "lg" ? s2 : "md";
4232
+ const s = this.getAttr("size", "md");
4233
+ return s === "sm" || s === "lg" ? s : "md";
4201
4234
  }
4202
4235
  set size(value) {
4203
4236
  this.setAttribute("size", value);
@@ -4790,8 +4823,8 @@ const _FxFileUpload = class _FxFileUpload extends FxElement {
4790
4823
  return ["mode", "size", "severity", "label", "icon", "accept", "multiple", "disabled", "show-progress", "progress", "value", "full"];
4791
4824
  }
4792
4825
  get size() {
4793
- const s2 = this.getAttr("size", "md");
4794
- return s2 === "sm" || s2 === "lg" ? s2 : "md";
4826
+ const s = this.getAttr("size", "md");
4827
+ return s === "sm" || s === "lg" ? s : "md";
4795
4828
  }
4796
4829
  set size(value) {
4797
4830
  this.setAttribute("size", value);
@@ -5715,26 +5748,36 @@ const _FxBreadcrumb = class _FxBreadcrumb extends FxElement {
5715
5748
  item.setAttribute("aria-current", isLast ? "page" : "false");
5716
5749
  nav.appendChild(item);
5717
5750
  if (isLast) return;
5718
- const s2 = document.createElement("span");
5719
- s2.className = "sep";
5720
- s2.setAttribute("part", "separator");
5721
- s2.setAttribute("aria-hidden", "true");
5722
- s2.textContent = sep;
5723
- nav.appendChild(s2);
5751
+ const s = document.createElement("span");
5752
+ s.className = "sep";
5753
+ s.setAttribute("part", "separator");
5754
+ s.setAttribute("aria-hidden", "true");
5755
+ s.textContent = sep;
5756
+ nav.appendChild(s);
5724
5757
  });
5725
5758
  }
5726
5759
  connectedCallback() {
5727
5760
  super.connectedCallback();
5728
5761
  const obs = new MutationObserver(() => {
5729
5762
  if (this.children.length > 0) {
5730
- obs.disconnect();
5763
+ this._stopObservingChildren();
5731
5764
  this._decorateItems();
5732
5765
  }
5733
5766
  });
5767
+ this._childObserver = obs;
5734
5768
  obs.observe(this, { childList: true });
5735
- if (this.children.length > 0) this._decorateItems();
5769
+ if (this.children.length > 0) {
5770
+ this._stopObservingChildren();
5771
+ this._decorateItems();
5772
+ }
5773
+ }
5774
+ /** Desconecta o observer de filhos (evita trabalho eterno após o connect). */
5775
+ _stopObservingChildren() {
5776
+ this._childObserver?.disconnect();
5777
+ this._childObserver = void 0;
5736
5778
  }
5737
5779
  disconnectedCallback() {
5780
+ this._stopObservingChildren();
5738
5781
  super.disconnectedCallback();
5739
5782
  this._items = [];
5740
5783
  }
@@ -6294,7 +6337,7 @@ const _FxMenu = class _FxMenu extends FxElement {
6294
6337
  }
6295
6338
  render() {
6296
6339
  const titleAttr = this.getAttr("titles");
6297
- const titles = titleAttr ? titleAttr.split(",").map((s2) => s2.trim()) : [];
6340
+ const titles = titleAttr ? titleAttr.split(",").map((s) => s.trim()) : [];
6298
6341
  const items = this.items;
6299
6342
  const itemsHtml = items.map((it, i) => {
6300
6343
  const label = titles[i] || it.textContent?.trim() || `Item ${i + 1}`;
@@ -6426,7 +6469,7 @@ const _FxToggleButtonGroup = class _FxToggleButtonGroup extends FxElement {
6426
6469
  }
6427
6470
  get value() {
6428
6471
  const raw = this.getAttr("value");
6429
- return raw ? raw.split(",").map((s2) => s2.trim()).filter(Boolean) : [];
6472
+ return raw ? raw.split(",").map((s) => s.trim()).filter(Boolean) : [];
6430
6473
  }
6431
6474
  set value(v) {
6432
6475
  this.setAttribute("value", v.join(","));
@@ -6857,7 +6900,7 @@ const _FxCarousel = class _FxCarousel extends FxElement {
6857
6900
  }
6858
6901
  render() {
6859
6902
  this._slides = Array.from(this.children).filter((el) => el.matches('[slot="slide"]'));
6860
- const contentsHtml = this._slides.map((s2, i) => `<div class="slide" part="slide" data-i="${i}" ${i === this.active ? "" : "hidden"}>${s2.innerHTML}</div>`).join("");
6903
+ const contentsHtml = this._slides.map((s, i) => `<div class="slide" part="slide" data-i="${i}" ${i === this.active ? "" : "hidden"}>${s.innerHTML}</div>`).join("");
6861
6904
  this.setTemplate(`
6862
6905
  <div class="viewport" part="viewport">
6863
6906
  ${contentsHtml}
@@ -6891,8 +6934,8 @@ const _FxCarousel = class _FxCarousel extends FxElement {
6891
6934
  }
6892
6935
  if (String(target) === this.getAttribute("active")) return;
6893
6936
  this.active = target;
6894
- this.root.querySelectorAll(".slide").forEach((s2) => {
6895
- s2.toggleAttribute("hidden", Number(s2.dataset.i) !== target);
6937
+ this.root.querySelectorAll(".slide").forEach((s) => {
6938
+ s.toggleAttribute("hidden", Number(s.dataset.i) !== target);
6896
6939
  });
6897
6940
  this.root.querySelectorAll(".dot").forEach((d) => {
6898
6941
  d.classList.toggle("on", Number(d.dataset.i) === target);
@@ -7147,6 +7190,7 @@ function defineFxTree() {
7147
7190
  return defineElement("fx-tree", FxTree);
7148
7191
  }
7149
7192
  defineFxTree();
7193
+ const REMOVED_EVENT = "fx-toast:removed";
7150
7194
  const KIND_COLOR = {
7151
7195
  success: "var(--fx-color-success, #10b981)",
7152
7196
  error: "var(--fx-color-danger, #f43f5e)",
@@ -7337,9 +7381,18 @@ class FxToast extends HTMLElement {
7337
7381
  }
7338
7382
  __privateMethod(this, _FxToast_instances, syncProgress_fn).call(this);
7339
7383
  }
7384
+ /**
7385
+ * Limpa recursos ao sair do DOM e avisa a API imperativa (`FenixToast`).
7386
+ *
7387
+ * O aviso é essencial: `dismiss()` (timer ou botão de fechar) tira o
7388
+ * elemento do DOM mas, sem isto, `ToastApi.map` continuaria segurando uma
7389
+ * referência forte para cada toast já dispensado — crescimento de memória
7390
+ * sem limite em uso prolongado.
7391
+ */
7340
7392
  disconnectedCallback() {
7341
7393
  if (this.timer) clearTimeout(this.timer);
7342
7394
  this.timer = null;
7395
+ this.dispatchEvent(new CustomEvent(REMOVED_EVENT, { bubbles: false, composed: false }));
7343
7396
  }
7344
7397
  attributeChangedCallback(name) {
7345
7398
  if (name === "duration" || name === "progress" || name === "progress-origin" || name === "kind") {
@@ -7461,6 +7514,9 @@ class ToastApi {
7461
7514
  if (o.progress) el.setAttribute("progress", o.progress);
7462
7515
  if (o.progressOrigin) el.setAttribute("progress-origin", o.progressOrigin);
7463
7516
  regionFor(o.position ?? "top-right").appendChild(el);
7517
+ el.addEventListener(REMOVED_EVENT, () => {
7518
+ if (this.map.get(id) === el) this.map.delete(id);
7519
+ });
7464
7520
  this.map.set(id, el);
7465
7521
  return id;
7466
7522
  }
@@ -7645,6 +7701,8 @@ const _FxTooltipManager = class _FxTooltipManager {
7645
7701
  this.observer = null;
7646
7702
  this.behaviors = /* @__PURE__ */ new Map();
7647
7703
  this.injectedStyles = null;
7704
+ this._pending = { added: [] };
7705
+ this._flushScheduled = false;
7648
7706
  this.injectStyles();
7649
7707
  this.observe();
7650
7708
  this.processExistingElements();
@@ -7655,6 +7713,20 @@ const _FxTooltipManager = class _FxTooltipManager {
7655
7713
  }
7656
7714
  return _FxTooltipManager.instance;
7657
7715
  }
7716
+ /** Quantos tooltips estão ativos agora (0 se a diretiva nunca foi iniciada). */
7717
+ static peekActiveCount() {
7718
+ return _FxTooltipManager.instance?.behaviors.size ?? 0;
7719
+ }
7720
+ /**
7721
+ * Quantos tooltips estão ativamente gerenciados.
7722
+ *
7723
+ * Deve acompanhar o número de elementos `[fx-tooltip]` no documento: um
7724
+ * valor crescente depois de trocar de tela significa comportamento retido
7725
+ * (vazamento). Usado nos testes de regressão e no diagnóstico em produção.
7726
+ */
7727
+ get activeCount() {
7728
+ return this.behaviors.size;
7729
+ }
7658
7730
  injectStyles() {
7659
7731
  if (document.getElementById("fx-tooltip-directive-styles")) return;
7660
7732
  this.injectedStyles = document.createElement("style");
@@ -7664,32 +7736,55 @@ const _FxTooltipManager = class _FxTooltipManager {
7664
7736
  }
7665
7737
  observe() {
7666
7738
  this.observer = new MutationObserver((mutations) => {
7667
- for (const mutation of mutations) {
7668
- if (mutation.type === "childList") {
7669
- mutation.addedNodes.forEach((node) => {
7670
- if (node instanceof HTMLElement) {
7671
- this.processElement(node);
7672
- node.querySelectorAll("[fx-tooltip]").forEach((el) => this.processElement(el));
7673
- }
7674
- });
7675
- }
7676
- if (mutation.type === "attributes" && mutation.target instanceof HTMLElement) {
7677
- const target = mutation.target;
7678
- if (target.hasAttribute("fx-tooltip")) {
7679
- this.processElement(target);
7680
- } else if (this.behaviors.has(target)) {
7681
- this.removeBehavior(target);
7682
- }
7683
- }
7684
- }
7739
+ this._pending.added.push(...mutations);
7740
+ if (this._flushScheduled) return;
7741
+ this._flushScheduled = true;
7742
+ const run = () => {
7743
+ this._flushScheduled = false;
7744
+ const batch = this._pending;
7745
+ this._pending = { added: [] };
7746
+ this._flush(batch.added);
7747
+ };
7748
+ if (typeof requestAnimationFrame === "function") requestAnimationFrame(run);
7749
+ else setTimeout(run, 0);
7685
7750
  });
7686
7751
  this.observer.observe(document.body, {
7687
7752
  childList: true,
7688
7753
  subtree: true,
7689
7754
  attributes: true,
7755
+ // `attributeFilter` é o que mantém o custo baixo: o browser só notifica
7756
+ // mudanças nestes 3 atributos, e não em qualquer atributo da página.
7690
7757
  attributeFilter: ["fx-tooltip", "fx-tooltip-position", "fx-tooltip-html"]
7691
7758
  });
7692
7759
  }
7760
+ /** Um passe de verificação sobre todos os registros acumulados. */
7761
+ _flush(records) {
7762
+ const toProcess = /* @__PURE__ */ new Set();
7763
+ const toRemove = /* @__PURE__ */ new Set();
7764
+ for (const mutation of records) {
7765
+ if (mutation.type === "childList") {
7766
+ mutation.addedNodes.forEach((node) => {
7767
+ if (node instanceof HTMLElement) {
7768
+ toProcess.add(node);
7769
+ node.querySelectorAll("[fx-tooltip]").forEach((el) => toProcess.add(el));
7770
+ }
7771
+ });
7772
+ mutation.removedNodes.forEach((node) => {
7773
+ if (node instanceof HTMLElement) {
7774
+ toRemove.add(node);
7775
+ node.querySelectorAll("[fx-tooltip]").forEach((el) => toRemove.add(el));
7776
+ }
7777
+ });
7778
+ }
7779
+ if (mutation.type === "attributes" && mutation.target instanceof HTMLElement) {
7780
+ const target = mutation.target;
7781
+ if (target.hasAttribute("fx-tooltip")) toProcess.add(target);
7782
+ else toRemove.add(target);
7783
+ }
7784
+ }
7785
+ toRemove.forEach((el) => this.removeBehavior(el));
7786
+ toProcess.forEach((el) => this.processElement(el));
7787
+ }
7693
7788
  processExistingElements() {
7694
7789
  document.querySelectorAll("[fx-tooltip]").forEach((el) => this.processElement(el));
7695
7790
  }
@@ -7712,6 +7807,8 @@ const _FxTooltipManager = class _FxTooltipManager {
7712
7807
  }
7713
7808
  }
7714
7809
  destroy() {
7810
+ this._pending.added = [];
7811
+ this._flushScheduled = false;
7715
7812
  if (this.observer) {
7716
7813
  this.observer.disconnect();
7717
7814
  this.observer = null;
@@ -8116,8 +8213,8 @@ const _FxSkeleton = class _FxSkeleton extends FxElement {
8116
8213
  return;
8117
8214
  }
8118
8215
  if (variant === "rect") {
8119
- const s2 = style || "width:100%;height:80px;";
8120
- this.setTemplate(`<div class="bone" part="bone" style="${s2}"></div>`);
8216
+ const s = style || "width:100%;height:80px;";
8217
+ this.setTemplate(`<div class="bone" part="bone" style="${s}"></div>`);
8121
8218
  return;
8122
8219
  }
8123
8220
  const lines = Number(this.getAttr("lines", "3")) || 3;
@@ -8632,7 +8729,7 @@ const _FxPagination = class _FxPagination extends FxElement {
8632
8729
  render() {
8633
8730
  const pages = this.pages;
8634
8731
  const current = Math.min(Math.max(1, this.page), pages);
8635
- const opts = (this.getAttr("rows-options", "5,10,20,50") || "").split(",").map((s2) => s2.trim()).filter(Boolean);
8732
+ const opts = (this.getAttr("rows-options", "5,10,20,50") || "").split(",").map((s) => s.trim()).filter(Boolean);
8636
8733
  const window_ = [];
8637
8734
  for (let p = Math.max(1, current - 2); p <= Math.min(pages, current + 2); p++) window_.push(p);
8638
8735
  const from = total0(current, this.rows);
@@ -8742,8 +8839,8 @@ const _FxAutocomplete = class _FxAutocomplete extends FxElement {
8742
8839
  return ["size", "placeholder", "source", "disabled", "min-chars", "error", "invalid", "success", "valid"];
8743
8840
  }
8744
8841
  get size() {
8745
- const s2 = this.getAttr("size", "md");
8746
- return s2 === "sm" || s2 === "lg" ? s2 : "md";
8842
+ const s = this.getAttr("size", "md");
8843
+ return s === "sm" || s === "lg" ? s : "md";
8747
8844
  }
8748
8845
  set size(v) {
8749
8846
  this.setAttribute("size", v);
@@ -8795,7 +8892,7 @@ const _FxAutocomplete = class _FxAutocomplete extends FxElement {
8795
8892
  const openList = () => {
8796
8893
  if (!list) return;
8797
8894
  const q = field.value.toLowerCase();
8798
- const matches = this.source.filter((s2) => s2.toLowerCase().includes(q)).slice(0, 8);
8895
+ const matches = this.source.filter((s) => s.toLowerCase().includes(q)).slice(0, 8);
8799
8896
  list.innerHTML = matches.length ? matches.map((m) => `<button type="button" class="opt" role="option" data-v="${esc(m)}">${esc(m)}</button>`).join("") : '<div class="empty">Nenhum resultado</div>';
8800
8897
  list.querySelectorAll(".opt").forEach((btn) => {
8801
8898
  btn.addEventListener("click", () => {
@@ -8995,8 +9092,8 @@ const _FxKnob = class _FxKnob extends FxElement {
8995
9092
  this.setAttribute("step", String(v));
8996
9093
  }
8997
9094
  get size() {
8998
- const s2 = this.getAttr("size", "md");
8999
- return s2 === "sm" || s2 === "lg" ? s2 : "md";
9095
+ const s = this.getAttr("size", "md");
9096
+ return s === "sm" || s === "lg" ? s : "md";
9000
9097
  }
9001
9098
  set size(v) {
9002
9099
  this.setAttribute("size", v);
@@ -9072,9 +9169,9 @@ const _FxKnob = class _FxKnob extends FxElement {
9072
9169
  this.attachListeners();
9073
9170
  }
9074
9171
  getSizeNum() {
9075
- const s2 = this.size;
9076
- if (s2 === "sm") return 60;
9077
- if (s2 === "lg") return 140;
9172
+ const s = this.size;
9173
+ if (s === "sm") return 60;
9174
+ if (s === "lg") return 140;
9078
9175
  return 100;
9079
9176
  }
9080
9177
  /** Valida um valor de cor CSS, retornando-o seguro ou vazio. */
@@ -9338,8 +9435,8 @@ const _FxOrderList = class _FxOrderList extends FxElement {
9338
9435
  this.toggleAttr("striped", v);
9339
9436
  }
9340
9437
  get selectionMode() {
9341
- const s2 = this.getAttr("selection-mode", "");
9342
- return s2 === "single" || s2 === "multiple" ? s2 : "";
9438
+ const s = this.getAttr("selection-mode", "");
9439
+ return s === "single" || s === "multiple" ? s : "";
9343
9440
  }
9344
9441
  set selectionMode(v) {
9345
9442
  this.setAttribute("selection-mode", v);
@@ -9421,7 +9518,7 @@ const _FxOrderList = class _FxOrderList extends FxElement {
9421
9518
  return JSON.stringify(item);
9422
9519
  }
9423
9520
  _isSelected(item) {
9424
- return this._selection.some((s2) => this._getItemKey(s2, -1) === this._getItemKey(item, -1));
9521
+ return this._selection.some((s) => this._getItemKey(s, -1) === this._getItemKey(item, -1));
9425
9522
  }
9426
9523
  _moveItem(fromIndex, toIndex) {
9427
9524
  const actualFrom = this._getActualIndex(fromIndex);
@@ -9457,7 +9554,7 @@ const _FxOrderList = class _FxOrderList extends FxElement {
9457
9554
  }
9458
9555
  _toggleSelection(item) {
9459
9556
  const key2 = this._getItemKey(item, -1);
9460
- const index = this._selection.findIndex((s2) => this._getItemKey(s2, -1) === key2);
9557
+ const index = this._selection.findIndex((s) => this._getItemKey(s, -1) === key2);
9461
9558
  if (index >= 0) {
9462
9559
  this._selection.splice(index, 1);
9463
9560
  } else if (this.selectionMode === "multiple") {
@@ -9731,7 +9828,7 @@ const _FxOrderList = class _FxOrderList extends FxElement {
9731
9828
  _handleMoveAction(action) {
9732
9829
  if (!this._selection.length) return;
9733
9830
  const displayData = this._getDisplayData();
9734
- const selectedIndices = this._selection.map((s2) => displayData.findIndex((d) => this._getItemKey(d, -1) === this._getItemKey(s2, -1))).filter((i) => i >= 0).sort((a, b) => a - b);
9831
+ const selectedIndices = this._selection.map((s) => displayData.findIndex((d) => this._getItemKey(d, -1) === this._getItemKey(s, -1))).filter((i) => i >= 0).sort((a, b) => a - b);
9735
9832
  if (selectedIndices.length === 0) return;
9736
9833
  switch (action) {
9737
9834
  case "top":
@@ -9807,7 +9904,7 @@ const _FxOrderList = class _FxOrderList extends FxElement {
9807
9904
  }
9808
9905
  _updateControlsState() {
9809
9906
  const displayData = this._getDisplayData();
9810
- const selectedIndices = this._selection.map((s2) => displayData.findIndex((d) => this._getItemKey(d, -1) === this._getItemKey(s2, -1))).filter((i) => i >= 0);
9907
+ const selectedIndices = this._selection.map((s) => displayData.findIndex((d) => this._getItemKey(d, -1) === this._getItemKey(s, -1))).filter((i) => i >= 0);
9811
9908
  const buttons = this.root.querySelectorAll(".control-btn");
9812
9909
  buttons.forEach((btn) => {
9813
9910
  const action = btn.dataset.action;
@@ -10013,8 +10110,8 @@ const _FxPickList = class _FxPickList extends FxElement {
10013
10110
  this.toggleAttr("striped", v);
10014
10111
  }
10015
10112
  get selectionMode() {
10016
- const s2 = this.getAttr("selection-mode", "");
10017
- return s2 === "single" || s2 === "multiple" ? s2 : "";
10113
+ const s = this.getAttr("selection-mode", "");
10114
+ return s === "single" || s === "multiple" ? s : "";
10018
10115
  }
10019
10116
  set selectionMode(v) {
10020
10117
  this.setAttribute("selection-mode", v);
@@ -10149,10 +10246,10 @@ const _FxPickList = class _FxPickList extends FxElement {
10149
10246
  return JSON.stringify(item);
10150
10247
  }
10151
10248
  _isSourceSelected(item, index) {
10152
- return this._sourceSelection.some((s2) => this._getItemKey(s2, -1, true) === this._getItemKey(item, index, true));
10249
+ return this._sourceSelection.some((s) => this._getItemKey(s, -1, true) === this._getItemKey(item, index, true));
10153
10250
  }
10154
10251
  _isTargetSelected(item, index) {
10155
- return this._targetSelection.some((s2) => this._getItemKey(s2, -1, false) === this._getItemKey(item, index, false));
10252
+ return this._targetSelection.some((s) => this._getItemKey(s, -1, false) === this._getItemKey(item, index, false));
10156
10253
  }
10157
10254
  _emitMoveToTarget() {
10158
10255
  this.dispatchEvent(new CustomEvent("move-to-target", {
@@ -10295,7 +10392,7 @@ const _FxPickList = class _FxPickList extends FxElement {
10295
10392
  _moveToTarget() {
10296
10393
  if (!this._sourceSelection.length) return;
10297
10394
  const items = [...this._sourceSelection];
10298
- this._source = this._source.filter((s2) => !items.some((i) => this._getItemKey(i, -1, true) === this._getItemKey(s2, -1, true)));
10395
+ this._source = this._source.filter((s) => !items.some((i) => this._getItemKey(i, -1, true) === this._getItemKey(s, -1, true)));
10299
10396
  this._target = [...this._target, ...items];
10300
10397
  this._sourceSelection = [];
10301
10398
  this._filteredSource = null;
@@ -10341,7 +10438,7 @@ const _FxPickList = class _FxPickList extends FxElement {
10341
10438
  _toggleSourceSelection(item, index) {
10342
10439
  const mode = this.selectionMode || "single";
10343
10440
  const key2 = this._getItemKey(item, index, true);
10344
- const idx = this._sourceSelection.findIndex((s2) => this._getItemKey(s2, -1, true) === key2);
10441
+ const idx = this._sourceSelection.findIndex((s) => this._getItemKey(s, -1, true) === key2);
10345
10442
  if (idx >= 0) {
10346
10443
  this._sourceSelection.splice(idx, 1);
10347
10444
  } else if (mode === "multiple") {
@@ -10356,7 +10453,7 @@ const _FxPickList = class _FxPickList extends FxElement {
10356
10453
  _toggleTargetSelection(item, index) {
10357
10454
  const mode = this.selectionMode || "single";
10358
10455
  const key2 = this._getItemKey(item, index, false);
10359
- const idx = this._targetSelection.findIndex((s2) => this._getItemKey(s2, -1, false) === key2);
10456
+ const idx = this._targetSelection.findIndex((s) => this._getItemKey(s, -1, false) === key2);
10360
10457
  if (idx >= 0) {
10361
10458
  this._targetSelection.splice(idx, 1);
10362
10459
  } else if (mode === "multiple") {
@@ -10819,7 +10916,7 @@ const _FxAccordion = class _FxAccordion extends FxElement {
10819
10916
  }
10820
10917
  /** Valores ativos como array. */
10821
10918
  get values() {
10822
- return this.getAttr("value", "").split(",").map((s2) => s2.trim()).filter(Boolean);
10919
+ return this.getAttr("value", "").split(",").map((s) => s.trim()).filter(Boolean);
10823
10920
  }
10824
10921
  set values(v) {
10825
10922
  this.setAttribute("value", v.join(","));
@@ -11001,9 +11098,9 @@ export {
11001
11098
  lightTokens,
11002
11099
  listPresets,
11003
11100
  resetTheme,
11004
- s as sanitizeData,
11101
+ h as sanitizeData,
11005
11102
  setTokens,
11006
- g as stripTags,
11103
+ j as stripTags,
11007
11104
  theme,
11008
11105
  themePresets,
11009
11106
  tokenCssVars