@wrrdev/fenix-ui 1.1.10 → 1.1.12

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 (39) 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 +18 -1
  9. package/dist/components/table/table.d.ts.map +1 -1
  10. package/dist/components/table/table.js +120 -23
  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 +19 -0
  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.doc.d.ts.map +1 -1
  25. package/dist/fenix-ui.umd.min.js +237 -170
  26. package/dist/fenix-ui3.esm.js +8 -13
  27. package/dist/fenix-ui3.esm.js.map +1 -1
  28. package/dist/fenix-ui4.esm.js +275 -114
  29. package/dist/fenix-ui4.esm.js.map +1 -1
  30. package/dist/icons/font.d.ts +23 -0
  31. package/dist/icons/font.d.ts.map +1 -1
  32. package/dist/icons/font.js +54 -8
  33. package/dist/icons/font.js.map +1 -1
  34. package/dist/icons/index.d.ts +7 -2
  35. package/dist/icons/index.d.ts.map +1 -1
  36. package/dist/icons/index.js +6 -11
  37. package/dist/icons/index.js.map +1 -1
  38. package/package.json +1 -1
  39. 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 [
@@ -3310,7 +3311,10 @@ const _FxTable = class _FxTable extends FxElement {
3310
3311
  "loading",
3311
3312
  "loading-message",
3312
3313
  "sort-field",
3313
- "sort-order"
3314
+ "sort-order",
3315
+ "rounded",
3316
+ "radius",
3317
+ "no-borders-x"
3314
3318
  ];
3315
3319
  }
3316
3320
  get data() {
@@ -3488,7 +3492,7 @@ const _FxTable = class _FxTable extends FxElement {
3488
3492
  if (!input) return [];
3489
3493
  const attr = input.getAttribute("data-search-fields");
3490
3494
  if (attr === null) return [];
3491
- return attr.split(",").map((s2) => s2.trim()).filter(Boolean);
3495
+ return attr.split(",").map((s) => s.trim()).filter(Boolean);
3492
3496
  }
3493
3497
  cellHtml(col, row) {
3494
3498
  const template = col.template?.innerHTML ?? col.directTemplate;
@@ -3530,18 +3534,37 @@ const _FxTable = class _FxTable extends FxElement {
3530
3534
  </div>`;
3531
3535
  const loading = this.hasAttr("loading");
3532
3536
  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>` : "";
3537
+ const shellKey = [
3538
+ toolbarHtml,
3539
+ headHtml,
3540
+ filterRow,
3541
+ pagerHtml,
3542
+ loadingHtml,
3543
+ cols.length
3544
+ ].join("|");
3545
+ if (shellKey === this._shellKey) {
3546
+ const tbody = this.root.querySelector("tbody");
3547
+ if (tbody) {
3548
+ tbody.innerHTML = bodyHtml;
3549
+ this._bindRowClicks(rows);
3550
+ return;
3551
+ }
3552
+ }
3553
+ this._shellKey = shellKey;
3533
3554
  this.setTemplate(`
3534
3555
  ${toolbarHtml}
3535
- <div class="table-wrap">
3536
- <div class="scroll">
3537
- <table part="table">
3538
- <thead><tr>${headHtml}</tr>${filterRow}</thead>
3539
- <tbody>${bodyHtml}</tbody>
3540
- </table>
3556
+ <div class="frame${toolbar ? " has-toolbar" : ""}" part="frame">
3557
+ <div class="table-wrap">
3558
+ <div class="scroll">
3559
+ <table part="table">
3560
+ <thead><tr>${headHtml}</tr>${filterRow}</thead>
3561
+ <tbody>${bodyHtml}</tbody>
3562
+ </table>
3563
+ </div>
3564
+ ${loadingHtml}
3541
3565
  </div>
3542
- ${loadingHtml}
3566
+ ${pagerHtml}
3543
3567
  </div>
3544
- ${pagerHtml}
3545
3568
  `);
3546
3569
  this.root.querySelectorAll("th.sortable").forEach((th) => {
3547
3570
  th.addEventListener("click", () => {
@@ -3633,6 +3656,16 @@ const _FxTable = class _FxTable extends FxElement {
3633
3656
  this.page = 0;
3634
3657
  this.render();
3635
3658
  });
3659
+ this._bindRowClicks(rows);
3660
+ this._restoreToolbarSearch();
3661
+ }
3662
+ /**
3663
+ * Liga o clique das linhas ao evento `row-click`.
3664
+ *
3665
+ * Extraído do render para ser reaproveitado no caminho rápido (troca só do
3666
+ * <tbody>): os <tr> são novos, então precisam ser rebound.
3667
+ */
3668
+ _bindRowClicks(rows) {
3636
3669
  this.root.querySelectorAll("tbody tr[data-index]").forEach((tr) => {
3637
3670
  tr.addEventListener("click", () => {
3638
3671
  this.dispatchEvent(
@@ -3647,7 +3680,6 @@ const _FxTable = class _FxTable extends FxElement {
3647
3680
  );
3648
3681
  });
3649
3682
  });
3650
- this._restoreToolbarSearch();
3651
3683
  }
3652
3684
  _restoreToolbarSearch() {
3653
3685
  const input = this.root.querySelector(
@@ -3664,14 +3696,61 @@ _FxTable.styles = css`
3664
3696
  font-size: var(--fx-font-size);
3665
3697
  color: var(--fx-text-default);
3666
3698
  background: var(--fx-surface-background);
3699
+ /* Raio da moldura (tabela + paginação). O atributo "rounded"
3700
+ sobrescreve este valor e o consumidor também pode sobrescrever
3701
+ por CSS: fx-table { --fx-table-radius: 20px; }. */
3702
+ --fx-table-radius: var(--fx-radius-md);
3703
+ }
3704
+ /* Arredondamento das bordas — "none" deixa tudo reto, como nos demais
3705
+ tokens de radius do design system. "rounded" é o nome atual; "radius"
3706
+ segue aceito como alias para ficar consistente com o <fx-card>. */
3707
+ :host([rounded="none"]),
3708
+ :host([radius="none"]) {
3709
+ --fx-table-radius: var(--fx-radius-none, 0);
3710
+ }
3711
+ :host([rounded="sm"]),
3712
+ :host([radius="sm"]) {
3713
+ --fx-table-radius: var(--fx-radius-sm);
3714
+ }
3715
+ :host([rounded="md"]),
3716
+ :host([radius="md"]) {
3717
+ --fx-table-radius: var(--fx-radius-md);
3718
+ }
3719
+ :host([rounded="lg"]),
3720
+ :host([radius="lg"]) {
3721
+ --fx-table-radius: var(--fx-radius-lg);
3722
+ }
3723
+ /* Moldura: uma única borda envolvendo a tabela E a paginação, para que
3724
+ o pager não fique "solto" fora do contorno da tabela. */
3725
+ .frame {
3726
+ border: 1px solid var(--fx-border-default);
3727
+ border-radius: var(--fx-table-radius);
3728
+ background: var(--fx-surface-background);
3729
+ }
3730
+ /* Com toolbar no topo, quem desenha a borda superior é a própria
3731
+ toolbar — a moldura desenha apenas o contorno restante. */
3732
+ .frame.has-toolbar {
3733
+ border-top: none;
3734
+ }
3735
+ /* "no-borders-x": mantém somente as bordas de topo e de base
3736
+ (tabela encaixada em um layout que já desenha as laterais). */
3737
+ :host([no-borders-x]) .frame,
3738
+ :host([no-borders-x]) .toolbar {
3739
+ border-left: none;
3740
+ border-right: none;
3667
3741
  }
3668
3742
  .table-wrap {
3669
3743
  position: relative;
3670
3744
  }
3671
3745
  .scroll {
3672
3746
  overflow-x: auto;
3673
- border: 1px solid var(--fx-border-default);
3674
- border-radius: var(--fx-radius-md);
3747
+ /* O topo acompanha o raio da moldura; a base fica reta porque o
3748
+ rodapé (.pager) é quem a desenha. */
3749
+ border-radius: var(--fx-table-radius) var(--fx-table-radius) 0 0;
3750
+ }
3751
+ /* Sem paginação não existe rodapé: a moldura fecha embaixo. */
3752
+ :host(:not([pagination])) .scroll {
3753
+ border-radius: var(--fx-table-radius);
3675
3754
  }
3676
3755
  table {
3677
3756
  width: 100%;
@@ -3758,7 +3837,13 @@ _FxTable.styles = css`
3758
3837
  align-items: center;
3759
3838
  gap: var(--fx-space-sm);
3760
3839
  flex-wrap: wrap;
3761
- padding: var(--fx-space-sm) 0;
3840
+ /* O rodapé é parte da moldura: borda só no topo (separando da
3841
+ tabela) e o mesmo padding horizontal das células. Antes ele
3842
+ ficava fora do contorno, sem borda e sem respiro lateral. */
3843
+ padding: var(--fx-space-sm) var(--fx-space-md);
3844
+ border-top: 1px solid var(--fx-border-default);
3845
+ border-radius: 0 0 var(--fx-table-radius) var(--fx-table-radius);
3846
+ background: var(--fx-surface-background);
3762
3847
  }
3763
3848
  :host([pagination-position="center"]) .pager {
3764
3849
  justify-content: center;
@@ -3807,15 +3892,27 @@ _FxTable.styles = css`
3807
3892
  color: #fff;
3808
3893
  font-weight: var(--fx-font-weight);
3809
3894
  }
3810
- fx-select {
3895
+ /* O seletor "Por página" só mostra números, então não pode herdar a
3896
+ largura padrão do <fx-select> (200px / 180px em size="sm"), que
3897
+ deixava o rodapé da paginação desproporcional. O limite tem que ser
3898
+ no HOST — apertar só ::part(trigger) não funciona, porque o
3899
+ trigger é width:100% e continua herdando o min-width do host.
3900
+ O painel (dropdown) continua largo (220px) em select.ts. */
3901
+ fx-select.rows-sel {
3811
3902
  vertical-align: middle;
3903
+ /* Não deixa o flex do .pager esticar nem esmagar o controle. */
3904
+ flex: none;
3905
+ width: auto;
3906
+ --fx-select-min-width: 56px;
3907
+ --fx-select-min-width-sm: 56px;
3812
3908
  }
3813
- fx-select::part(trigger) {
3814
- min-width: 64px !important;
3815
- min-height: var(--fx-size-sm) !important;
3816
- padding: 0 var(--fx-space-sm) !important;
3817
- border-radius: var(--fx-radius-sm) !important;
3818
- font-size: calc(var(--fx-font-size) - 2px) !important;
3909
+ fx-select.rows-sel::part(trigger) {
3910
+ min-width: 0;
3911
+ min-height: var(--fx-size-sm);
3912
+ /* Padding curto: sobra espaço para o número + caret. */
3913
+ padding: 0 var(--fx-space-xs);
3914
+ border-radius: var(--fx-radius-sm);
3915
+ font-size: calc(var(--fx-font-size) - 2px);
3819
3916
  }
3820
3917
  .toolbar {
3821
3918
  display: flex;
@@ -3825,7 +3922,7 @@ _FxTable.styles = css`
3825
3922
  padding: var(--fx-space-sm) var(--fx-space-md);
3826
3923
  border: 1px solid var(--fx-border-default);
3827
3924
  border-bottom: none;
3828
- border-radius: var(--fx-radius-md) var(--fx-radius-md) 0 0;
3925
+ border-radius: var(--fx-table-radius) var(--fx-table-radius) 0 0;
3829
3926
  background: var(--fx-surface-background);
3830
3927
  }
3831
3928
  .toolbar:empty {
@@ -3846,7 +3943,7 @@ _FxTable.styles = css`
3846
3943
  );
3847
3944
  backdrop-filter: blur(2px);
3848
3945
  z-index: 10;
3849
- border-radius: var(--fx-radius-md);
3946
+ border-radius: var(--fx-table-radius) var(--fx-table-radius) 0 0;
3850
3947
  }
3851
3948
  .tbl-spinner {
3852
3949
  width: 32px;
@@ -4202,8 +4299,8 @@ const _FxTextarea = class _FxTextarea extends FxElement {
4202
4299
  return ["size", "placeholder", "disabled", "readonly", "rows", "maxlength", "error", "invalid", "success", "valid"];
4203
4300
  }
4204
4301
  get size() {
4205
- const s2 = this.getAttr("size", "md");
4206
- return s2 === "sm" || s2 === "lg" ? s2 : "md";
4302
+ const s = this.getAttr("size", "md");
4303
+ return s === "sm" || s === "lg" ? s : "md";
4207
4304
  }
4208
4305
  set size(value) {
4209
4306
  this.setAttribute("size", value);
@@ -4796,8 +4893,8 @@ const _FxFileUpload = class _FxFileUpload extends FxElement {
4796
4893
  return ["mode", "size", "severity", "label", "icon", "accept", "multiple", "disabled", "show-progress", "progress", "value", "full"];
4797
4894
  }
4798
4895
  get size() {
4799
- const s2 = this.getAttr("size", "md");
4800
- return s2 === "sm" || s2 === "lg" ? s2 : "md";
4896
+ const s = this.getAttr("size", "md");
4897
+ return s === "sm" || s === "lg" ? s : "md";
4801
4898
  }
4802
4899
  set size(value) {
4803
4900
  this.setAttribute("size", value);
@@ -5721,26 +5818,36 @@ const _FxBreadcrumb = class _FxBreadcrumb extends FxElement {
5721
5818
  item.setAttribute("aria-current", isLast ? "page" : "false");
5722
5819
  nav.appendChild(item);
5723
5820
  if (isLast) return;
5724
- const s2 = document.createElement("span");
5725
- s2.className = "sep";
5726
- s2.setAttribute("part", "separator");
5727
- s2.setAttribute("aria-hidden", "true");
5728
- s2.textContent = sep;
5729
- nav.appendChild(s2);
5821
+ const s = document.createElement("span");
5822
+ s.className = "sep";
5823
+ s.setAttribute("part", "separator");
5824
+ s.setAttribute("aria-hidden", "true");
5825
+ s.textContent = sep;
5826
+ nav.appendChild(s);
5730
5827
  });
5731
5828
  }
5732
5829
  connectedCallback() {
5733
5830
  super.connectedCallback();
5734
5831
  const obs = new MutationObserver(() => {
5735
5832
  if (this.children.length > 0) {
5736
- obs.disconnect();
5833
+ this._stopObservingChildren();
5737
5834
  this._decorateItems();
5738
5835
  }
5739
5836
  });
5837
+ this._childObserver = obs;
5740
5838
  obs.observe(this, { childList: true });
5741
- if (this.children.length > 0) this._decorateItems();
5839
+ if (this.children.length > 0) {
5840
+ this._stopObservingChildren();
5841
+ this._decorateItems();
5842
+ }
5843
+ }
5844
+ /** Desconecta o observer de filhos (evita trabalho eterno após o connect). */
5845
+ _stopObservingChildren() {
5846
+ this._childObserver?.disconnect();
5847
+ this._childObserver = void 0;
5742
5848
  }
5743
5849
  disconnectedCallback() {
5850
+ this._stopObservingChildren();
5744
5851
  super.disconnectedCallback();
5745
5852
  this._items = [];
5746
5853
  }
@@ -6300,7 +6407,7 @@ const _FxMenu = class _FxMenu extends FxElement {
6300
6407
  }
6301
6408
  render() {
6302
6409
  const titleAttr = this.getAttr("titles");
6303
- const titles = titleAttr ? titleAttr.split(",").map((s2) => s2.trim()) : [];
6410
+ const titles = titleAttr ? titleAttr.split(",").map((s) => s.trim()) : [];
6304
6411
  const items = this.items;
6305
6412
  const itemsHtml = items.map((it, i) => {
6306
6413
  const label = titles[i] || it.textContent?.trim() || `Item ${i + 1}`;
@@ -6432,7 +6539,7 @@ const _FxToggleButtonGroup = class _FxToggleButtonGroup extends FxElement {
6432
6539
  }
6433
6540
  get value() {
6434
6541
  const raw = this.getAttr("value");
6435
- return raw ? raw.split(",").map((s2) => s2.trim()).filter(Boolean) : [];
6542
+ return raw ? raw.split(",").map((s) => s.trim()).filter(Boolean) : [];
6436
6543
  }
6437
6544
  set value(v) {
6438
6545
  this.setAttribute("value", v.join(","));
@@ -6863,7 +6970,7 @@ const _FxCarousel = class _FxCarousel extends FxElement {
6863
6970
  }
6864
6971
  render() {
6865
6972
  this._slides = Array.from(this.children).filter((el) => el.matches('[slot="slide"]'));
6866
- const contentsHtml = this._slides.map((s2, i) => `<div class="slide" part="slide" data-i="${i}" ${i === this.active ? "" : "hidden"}>${s2.innerHTML}</div>`).join("");
6973
+ const contentsHtml = this._slides.map((s, i) => `<div class="slide" part="slide" data-i="${i}" ${i === this.active ? "" : "hidden"}>${s.innerHTML}</div>`).join("");
6867
6974
  this.setTemplate(`
6868
6975
  <div class="viewport" part="viewport">
6869
6976
  ${contentsHtml}
@@ -6897,8 +7004,8 @@ const _FxCarousel = class _FxCarousel extends FxElement {
6897
7004
  }
6898
7005
  if (String(target) === this.getAttribute("active")) return;
6899
7006
  this.active = target;
6900
- this.root.querySelectorAll(".slide").forEach((s2) => {
6901
- s2.toggleAttribute("hidden", Number(s2.dataset.i) !== target);
7007
+ this.root.querySelectorAll(".slide").forEach((s) => {
7008
+ s.toggleAttribute("hidden", Number(s.dataset.i) !== target);
6902
7009
  });
6903
7010
  this.root.querySelectorAll(".dot").forEach((d) => {
6904
7011
  d.classList.toggle("on", Number(d.dataset.i) === target);
@@ -7153,6 +7260,7 @@ function defineFxTree() {
7153
7260
  return defineElement("fx-tree", FxTree);
7154
7261
  }
7155
7262
  defineFxTree();
7263
+ const REMOVED_EVENT = "fx-toast:removed";
7156
7264
  const KIND_COLOR = {
7157
7265
  success: "var(--fx-color-success, #10b981)",
7158
7266
  error: "var(--fx-color-danger, #f43f5e)",
@@ -7343,9 +7451,18 @@ class FxToast extends HTMLElement {
7343
7451
  }
7344
7452
  __privateMethod(this, _FxToast_instances, syncProgress_fn).call(this);
7345
7453
  }
7454
+ /**
7455
+ * Limpa recursos ao sair do DOM e avisa a API imperativa (`FenixToast`).
7456
+ *
7457
+ * O aviso é essencial: `dismiss()` (timer ou botão de fechar) tira o
7458
+ * elemento do DOM mas, sem isto, `ToastApi.map` continuaria segurando uma
7459
+ * referência forte para cada toast já dispensado — crescimento de memória
7460
+ * sem limite em uso prolongado.
7461
+ */
7346
7462
  disconnectedCallback() {
7347
7463
  if (this.timer) clearTimeout(this.timer);
7348
7464
  this.timer = null;
7465
+ this.dispatchEvent(new CustomEvent(REMOVED_EVENT, { bubbles: false, composed: false }));
7349
7466
  }
7350
7467
  attributeChangedCallback(name) {
7351
7468
  if (name === "duration" || name === "progress" || name === "progress-origin" || name === "kind") {
@@ -7467,6 +7584,9 @@ class ToastApi {
7467
7584
  if (o.progress) el.setAttribute("progress", o.progress);
7468
7585
  if (o.progressOrigin) el.setAttribute("progress-origin", o.progressOrigin);
7469
7586
  regionFor(o.position ?? "top-right").appendChild(el);
7587
+ el.addEventListener(REMOVED_EVENT, () => {
7588
+ if (this.map.get(id) === el) this.map.delete(id);
7589
+ });
7470
7590
  this.map.set(id, el);
7471
7591
  return id;
7472
7592
  }
@@ -7651,6 +7771,8 @@ const _FxTooltipManager = class _FxTooltipManager {
7651
7771
  this.observer = null;
7652
7772
  this.behaviors = /* @__PURE__ */ new Map();
7653
7773
  this.injectedStyles = null;
7774
+ this._pending = { added: [] };
7775
+ this._flushScheduled = false;
7654
7776
  this.injectStyles();
7655
7777
  this.observe();
7656
7778
  this.processExistingElements();
@@ -7661,6 +7783,20 @@ const _FxTooltipManager = class _FxTooltipManager {
7661
7783
  }
7662
7784
  return _FxTooltipManager.instance;
7663
7785
  }
7786
+ /** Quantos tooltips estão ativos agora (0 se a diretiva nunca foi iniciada). */
7787
+ static peekActiveCount() {
7788
+ return _FxTooltipManager.instance?.behaviors.size ?? 0;
7789
+ }
7790
+ /**
7791
+ * Quantos tooltips estão ativamente gerenciados.
7792
+ *
7793
+ * Deve acompanhar o número de elementos `[fx-tooltip]` no documento: um
7794
+ * valor crescente depois de trocar de tela significa comportamento retido
7795
+ * (vazamento). Usado nos testes de regressão e no diagnóstico em produção.
7796
+ */
7797
+ get activeCount() {
7798
+ return this.behaviors.size;
7799
+ }
7664
7800
  injectStyles() {
7665
7801
  if (document.getElementById("fx-tooltip-directive-styles")) return;
7666
7802
  this.injectedStyles = document.createElement("style");
@@ -7670,32 +7806,55 @@ const _FxTooltipManager = class _FxTooltipManager {
7670
7806
  }
7671
7807
  observe() {
7672
7808
  this.observer = new MutationObserver((mutations) => {
7673
- for (const mutation of mutations) {
7674
- if (mutation.type === "childList") {
7675
- mutation.addedNodes.forEach((node) => {
7676
- if (node instanceof HTMLElement) {
7677
- this.processElement(node);
7678
- node.querySelectorAll("[fx-tooltip]").forEach((el) => this.processElement(el));
7679
- }
7680
- });
7681
- }
7682
- if (mutation.type === "attributes" && mutation.target instanceof HTMLElement) {
7683
- const target = mutation.target;
7684
- if (target.hasAttribute("fx-tooltip")) {
7685
- this.processElement(target);
7686
- } else if (this.behaviors.has(target)) {
7687
- this.removeBehavior(target);
7688
- }
7689
- }
7690
- }
7809
+ this._pending.added.push(...mutations);
7810
+ if (this._flushScheduled) return;
7811
+ this._flushScheduled = true;
7812
+ const run = () => {
7813
+ this._flushScheduled = false;
7814
+ const batch = this._pending;
7815
+ this._pending = { added: [] };
7816
+ this._flush(batch.added);
7817
+ };
7818
+ if (typeof requestAnimationFrame === "function") requestAnimationFrame(run);
7819
+ else setTimeout(run, 0);
7691
7820
  });
7692
7821
  this.observer.observe(document.body, {
7693
7822
  childList: true,
7694
7823
  subtree: true,
7695
7824
  attributes: true,
7825
+ // `attributeFilter` é o que mantém o custo baixo: o browser só notifica
7826
+ // mudanças nestes 3 atributos, e não em qualquer atributo da página.
7696
7827
  attributeFilter: ["fx-tooltip", "fx-tooltip-position", "fx-tooltip-html"]
7697
7828
  });
7698
7829
  }
7830
+ /** Um passe de verificação sobre todos os registros acumulados. */
7831
+ _flush(records) {
7832
+ const toProcess = /* @__PURE__ */ new Set();
7833
+ const toRemove = /* @__PURE__ */ new Set();
7834
+ for (const mutation of records) {
7835
+ if (mutation.type === "childList") {
7836
+ mutation.addedNodes.forEach((node) => {
7837
+ if (node instanceof HTMLElement) {
7838
+ toProcess.add(node);
7839
+ node.querySelectorAll("[fx-tooltip]").forEach((el) => toProcess.add(el));
7840
+ }
7841
+ });
7842
+ mutation.removedNodes.forEach((node) => {
7843
+ if (node instanceof HTMLElement) {
7844
+ toRemove.add(node);
7845
+ node.querySelectorAll("[fx-tooltip]").forEach((el) => toRemove.add(el));
7846
+ }
7847
+ });
7848
+ }
7849
+ if (mutation.type === "attributes" && mutation.target instanceof HTMLElement) {
7850
+ const target = mutation.target;
7851
+ if (target.hasAttribute("fx-tooltip")) toProcess.add(target);
7852
+ else toRemove.add(target);
7853
+ }
7854
+ }
7855
+ toRemove.forEach((el) => this.removeBehavior(el));
7856
+ toProcess.forEach((el) => this.processElement(el));
7857
+ }
7699
7858
  processExistingElements() {
7700
7859
  document.querySelectorAll("[fx-tooltip]").forEach((el) => this.processElement(el));
7701
7860
  }
@@ -7718,6 +7877,8 @@ const _FxTooltipManager = class _FxTooltipManager {
7718
7877
  }
7719
7878
  }
7720
7879
  destroy() {
7880
+ this._pending.added = [];
7881
+ this._flushScheduled = false;
7721
7882
  if (this.observer) {
7722
7883
  this.observer.disconnect();
7723
7884
  this.observer = null;
@@ -8122,8 +8283,8 @@ const _FxSkeleton = class _FxSkeleton extends FxElement {
8122
8283
  return;
8123
8284
  }
8124
8285
  if (variant === "rect") {
8125
- const s2 = style || "width:100%;height:80px;";
8126
- this.setTemplate(`<div class="bone" part="bone" style="${s2}"></div>`);
8286
+ const s = style || "width:100%;height:80px;";
8287
+ this.setTemplate(`<div class="bone" part="bone" style="${s}"></div>`);
8127
8288
  return;
8128
8289
  }
8129
8290
  const lines = Number(this.getAttr("lines", "3")) || 3;
@@ -8638,7 +8799,7 @@ const _FxPagination = class _FxPagination extends FxElement {
8638
8799
  render() {
8639
8800
  const pages = this.pages;
8640
8801
  const current = Math.min(Math.max(1, this.page), pages);
8641
- const opts = (this.getAttr("rows-options", "5,10,20,50") || "").split(",").map((s2) => s2.trim()).filter(Boolean);
8802
+ const opts = (this.getAttr("rows-options", "5,10,20,50") || "").split(",").map((s) => s.trim()).filter(Boolean);
8642
8803
  const window_ = [];
8643
8804
  for (let p = Math.max(1, current - 2); p <= Math.min(pages, current + 2); p++) window_.push(p);
8644
8805
  const from = total0(current, this.rows);
@@ -8748,8 +8909,8 @@ const _FxAutocomplete = class _FxAutocomplete extends FxElement {
8748
8909
  return ["size", "placeholder", "source", "disabled", "min-chars", "error", "invalid", "success", "valid"];
8749
8910
  }
8750
8911
  get size() {
8751
- const s2 = this.getAttr("size", "md");
8752
- return s2 === "sm" || s2 === "lg" ? s2 : "md";
8912
+ const s = this.getAttr("size", "md");
8913
+ return s === "sm" || s === "lg" ? s : "md";
8753
8914
  }
8754
8915
  set size(v) {
8755
8916
  this.setAttribute("size", v);
@@ -8801,7 +8962,7 @@ const _FxAutocomplete = class _FxAutocomplete extends FxElement {
8801
8962
  const openList = () => {
8802
8963
  if (!list) return;
8803
8964
  const q = field.value.toLowerCase();
8804
- const matches = this.source.filter((s2) => s2.toLowerCase().includes(q)).slice(0, 8);
8965
+ const matches = this.source.filter((s) => s.toLowerCase().includes(q)).slice(0, 8);
8805
8966
  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>';
8806
8967
  list.querySelectorAll(".opt").forEach((btn) => {
8807
8968
  btn.addEventListener("click", () => {
@@ -9001,8 +9162,8 @@ const _FxKnob = class _FxKnob extends FxElement {
9001
9162
  this.setAttribute("step", String(v));
9002
9163
  }
9003
9164
  get size() {
9004
- const s2 = this.getAttr("size", "md");
9005
- return s2 === "sm" || s2 === "lg" ? s2 : "md";
9165
+ const s = this.getAttr("size", "md");
9166
+ return s === "sm" || s === "lg" ? s : "md";
9006
9167
  }
9007
9168
  set size(v) {
9008
9169
  this.setAttribute("size", v);
@@ -9078,9 +9239,9 @@ const _FxKnob = class _FxKnob extends FxElement {
9078
9239
  this.attachListeners();
9079
9240
  }
9080
9241
  getSizeNum() {
9081
- const s2 = this.size;
9082
- if (s2 === "sm") return 60;
9083
- if (s2 === "lg") return 140;
9242
+ const s = this.size;
9243
+ if (s === "sm") return 60;
9244
+ if (s === "lg") return 140;
9084
9245
  return 100;
9085
9246
  }
9086
9247
  /** Valida um valor de cor CSS, retornando-o seguro ou vazio. */
@@ -9344,8 +9505,8 @@ const _FxOrderList = class _FxOrderList extends FxElement {
9344
9505
  this.toggleAttr("striped", v);
9345
9506
  }
9346
9507
  get selectionMode() {
9347
- const s2 = this.getAttr("selection-mode", "");
9348
- return s2 === "single" || s2 === "multiple" ? s2 : "";
9508
+ const s = this.getAttr("selection-mode", "");
9509
+ return s === "single" || s === "multiple" ? s : "";
9349
9510
  }
9350
9511
  set selectionMode(v) {
9351
9512
  this.setAttribute("selection-mode", v);
@@ -9427,7 +9588,7 @@ const _FxOrderList = class _FxOrderList extends FxElement {
9427
9588
  return JSON.stringify(item);
9428
9589
  }
9429
9590
  _isSelected(item) {
9430
- return this._selection.some((s2) => this._getItemKey(s2, -1) === this._getItemKey(item, -1));
9591
+ return this._selection.some((s) => this._getItemKey(s, -1) === this._getItemKey(item, -1));
9431
9592
  }
9432
9593
  _moveItem(fromIndex, toIndex) {
9433
9594
  const actualFrom = this._getActualIndex(fromIndex);
@@ -9463,7 +9624,7 @@ const _FxOrderList = class _FxOrderList extends FxElement {
9463
9624
  }
9464
9625
  _toggleSelection(item) {
9465
9626
  const key2 = this._getItemKey(item, -1);
9466
- const index = this._selection.findIndex((s2) => this._getItemKey(s2, -1) === key2);
9627
+ const index = this._selection.findIndex((s) => this._getItemKey(s, -1) === key2);
9467
9628
  if (index >= 0) {
9468
9629
  this._selection.splice(index, 1);
9469
9630
  } else if (this.selectionMode === "multiple") {
@@ -9737,7 +9898,7 @@ const _FxOrderList = class _FxOrderList extends FxElement {
9737
9898
  _handleMoveAction(action) {
9738
9899
  if (!this._selection.length) return;
9739
9900
  const displayData = this._getDisplayData();
9740
- 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);
9901
+ 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);
9741
9902
  if (selectedIndices.length === 0) return;
9742
9903
  switch (action) {
9743
9904
  case "top":
@@ -9813,7 +9974,7 @@ const _FxOrderList = class _FxOrderList extends FxElement {
9813
9974
  }
9814
9975
  _updateControlsState() {
9815
9976
  const displayData = this._getDisplayData();
9816
- const selectedIndices = this._selection.map((s2) => displayData.findIndex((d) => this._getItemKey(d, -1) === this._getItemKey(s2, -1))).filter((i) => i >= 0);
9977
+ const selectedIndices = this._selection.map((s) => displayData.findIndex((d) => this._getItemKey(d, -1) === this._getItemKey(s, -1))).filter((i) => i >= 0);
9817
9978
  const buttons = this.root.querySelectorAll(".control-btn");
9818
9979
  buttons.forEach((btn) => {
9819
9980
  const action = btn.dataset.action;
@@ -10019,8 +10180,8 @@ const _FxPickList = class _FxPickList extends FxElement {
10019
10180
  this.toggleAttr("striped", v);
10020
10181
  }
10021
10182
  get selectionMode() {
10022
- const s2 = this.getAttr("selection-mode", "");
10023
- return s2 === "single" || s2 === "multiple" ? s2 : "";
10183
+ const s = this.getAttr("selection-mode", "");
10184
+ return s === "single" || s === "multiple" ? s : "";
10024
10185
  }
10025
10186
  set selectionMode(v) {
10026
10187
  this.setAttribute("selection-mode", v);
@@ -10155,10 +10316,10 @@ const _FxPickList = class _FxPickList extends FxElement {
10155
10316
  return JSON.stringify(item);
10156
10317
  }
10157
10318
  _isSourceSelected(item, index) {
10158
- return this._sourceSelection.some((s2) => this._getItemKey(s2, -1, true) === this._getItemKey(item, index, true));
10319
+ return this._sourceSelection.some((s) => this._getItemKey(s, -1, true) === this._getItemKey(item, index, true));
10159
10320
  }
10160
10321
  _isTargetSelected(item, index) {
10161
- return this._targetSelection.some((s2) => this._getItemKey(s2, -1, false) === this._getItemKey(item, index, false));
10322
+ return this._targetSelection.some((s) => this._getItemKey(s, -1, false) === this._getItemKey(item, index, false));
10162
10323
  }
10163
10324
  _emitMoveToTarget() {
10164
10325
  this.dispatchEvent(new CustomEvent("move-to-target", {
@@ -10301,7 +10462,7 @@ const _FxPickList = class _FxPickList extends FxElement {
10301
10462
  _moveToTarget() {
10302
10463
  if (!this._sourceSelection.length) return;
10303
10464
  const items = [...this._sourceSelection];
10304
- this._source = this._source.filter((s2) => !items.some((i) => this._getItemKey(i, -1, true) === this._getItemKey(s2, -1, true)));
10465
+ this._source = this._source.filter((s) => !items.some((i) => this._getItemKey(i, -1, true) === this._getItemKey(s, -1, true)));
10305
10466
  this._target = [...this._target, ...items];
10306
10467
  this._sourceSelection = [];
10307
10468
  this._filteredSource = null;
@@ -10347,7 +10508,7 @@ const _FxPickList = class _FxPickList extends FxElement {
10347
10508
  _toggleSourceSelection(item, index) {
10348
10509
  const mode = this.selectionMode || "single";
10349
10510
  const key2 = this._getItemKey(item, index, true);
10350
- const idx = this._sourceSelection.findIndex((s2) => this._getItemKey(s2, -1, true) === key2);
10511
+ const idx = this._sourceSelection.findIndex((s) => this._getItemKey(s, -1, true) === key2);
10351
10512
  if (idx >= 0) {
10352
10513
  this._sourceSelection.splice(idx, 1);
10353
10514
  } else if (mode === "multiple") {
@@ -10362,7 +10523,7 @@ const _FxPickList = class _FxPickList extends FxElement {
10362
10523
  _toggleTargetSelection(item, index) {
10363
10524
  const mode = this.selectionMode || "single";
10364
10525
  const key2 = this._getItemKey(item, index, false);
10365
- const idx = this._targetSelection.findIndex((s2) => this._getItemKey(s2, -1, false) === key2);
10526
+ const idx = this._targetSelection.findIndex((s) => this._getItemKey(s, -1, false) === key2);
10366
10527
  if (idx >= 0) {
10367
10528
  this._targetSelection.splice(idx, 1);
10368
10529
  } else if (mode === "multiple") {
@@ -10825,7 +10986,7 @@ const _FxAccordion = class _FxAccordion extends FxElement {
10825
10986
  }
10826
10987
  /** Valores ativos como array. */
10827
10988
  get values() {
10828
- return this.getAttr("value", "").split(",").map((s2) => s2.trim()).filter(Boolean);
10989
+ return this.getAttr("value", "").split(",").map((s) => s.trim()).filter(Boolean);
10829
10990
  }
10830
10991
  set values(v) {
10831
10992
  this.setAttribute("value", v.join(","));
@@ -11007,9 +11168,9 @@ export {
11007
11168
  lightTokens,
11008
11169
  listPresets,
11009
11170
  resetTheme,
11010
- s as sanitizeData,
11171
+ h as sanitizeData,
11011
11172
  setTokens,
11012
- g as stripTags,
11173
+ j as stripTags,
11013
11174
  theme,
11014
11175
  themePresets,
11015
11176
  tokenCssVars