@wrrdev/fenix-ui 1.1.4 → 1.1.5

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 (69) hide show
  1. package/README.md +2 -2
  2. package/dist/assets/base-css-Be_r8aTo.js +74 -0
  3. package/dist/assets/base-css-Be_r8aTo.js.map +1 -0
  4. package/dist/components/autocomplete/autocomplete.d.ts.map +1 -1
  5. package/dist/components/autocomplete/autocomplete.js +21 -7
  6. package/dist/components/autocomplete/autocomplete.js.map +1 -1
  7. package/dist/components/button/button.d.ts +4 -2
  8. package/dist/components/button/button.d.ts.map +1 -1
  9. package/dist/components/button/button.js +29 -9
  10. package/dist/components/button/button.js.map +1 -1
  11. package/dist/components/chip/chip.d.ts.map +1 -1
  12. package/dist/components/chip/chip.js +4 -2
  13. package/dist/components/chip/chip.js.map +1 -1
  14. package/dist/components/datepicker/datepicker.d.ts.map +1 -1
  15. package/dist/components/datepicker/datepicker.js +5 -1
  16. package/dist/components/datepicker/datepicker.js.map +1 -1
  17. package/dist/components/empty-state/empty-state.d.ts.map +1 -1
  18. package/dist/components/empty-state/empty-state.js +4 -1
  19. package/dist/components/empty-state/empty-state.js.map +1 -1
  20. package/dist/components/fileupload/fileupload.d.ts.map +1 -1
  21. package/dist/components/fileupload/fileupload.js +10 -3
  22. package/dist/components/fileupload/fileupload.js.map +1 -1
  23. package/dist/components/floatlabel/floatlabel.d.ts +8 -0
  24. package/dist/components/floatlabel/floatlabel.d.ts.map +1 -1
  25. package/dist/components/floatlabel/floatlabel.js +66 -3
  26. package/dist/components/floatlabel/floatlabel.js.map +1 -1
  27. package/dist/components/input/input.d.ts +4 -1
  28. package/dist/components/input/input.d.ts.map +1 -1
  29. package/dist/components/input/input.js +68 -2
  30. package/dist/components/input/input.js.map +1 -1
  31. package/dist/components/multiselect/multiselect.d.ts.map +1 -1
  32. package/dist/components/multiselect/multiselect.js +4 -1
  33. package/dist/components/multiselect/multiselect.js.map +1 -1
  34. package/dist/components/select/select.d.ts.map +1 -1
  35. package/dist/components/select/select.js +5 -1
  36. package/dist/components/select/select.js.map +1 -1
  37. package/dist/components/textarea/textarea.d.ts.map +1 -1
  38. package/dist/components/textarea/textarea.js +5 -2
  39. package/dist/components/textarea/textarea.js.map +1 -1
  40. package/dist/core/jsx.d.ts +25 -0
  41. package/dist/core/jsx.d.ts.map +1 -1
  42. package/dist/core/jsx.js.map +1 -1
  43. package/dist/core/vue.d.ts +3 -1
  44. package/dist/core/vue.d.ts.map +1 -1
  45. package/dist/core/vue.js.map +1 -1
  46. package/dist/docs/app.d.ts.map +1 -1
  47. package/dist/docs/componentes/alert.doc.d.ts.map +1 -1
  48. package/dist/docs/componentes/autocomplete.doc.d.ts.map +1 -1
  49. package/dist/docs/componentes/button.doc.d.ts.map +1 -1
  50. package/dist/docs/componentes/confirmpopup.doc.d.ts.map +1 -1
  51. package/dist/docs/componentes/datepicker.doc.d.ts.map +1 -1
  52. package/dist/docs/componentes/fileupload.doc.d.ts.map +1 -1
  53. package/dist/docs/componentes/floatlabel.doc.d.ts.map +1 -1
  54. package/dist/docs/componentes/input.doc.d.ts.map +1 -1
  55. package/dist/docs/componentes/multiselect.doc.d.ts.map +1 -1
  56. package/dist/docs/componentes/select.doc.d.ts.map +1 -1
  57. package/dist/docs/componentes/textarea.doc.d.ts.map +1 -1
  58. package/dist/fenix-ui.esm.js.map +1 -1
  59. package/dist/fenix-ui.umd.min.js +342 -218
  60. package/dist/fenix-ui2.esm.js +2 -2
  61. package/dist/fenix-ui3.esm.js +302 -147
  62. package/dist/fenix-ui3.esm.js.map +1 -1
  63. package/dist/icons/base-css.d.ts +16 -0
  64. package/dist/icons/base-css.d.ts.map +1 -1
  65. package/dist/icons/base-css.js +10 -0
  66. package/dist/icons/base-css.js.map +1 -1
  67. package/package.json +1 -1
  68. package/dist/assets/base-css-BifSeW2H.js +0 -31
  69. package/dist/assets/base-css-BifSeW2H.js.map +0 -1
@@ -5,7 +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, render_fn;
8
- import { a as FENIX_ICON_BASE_CSS, i as isFenixIconName } from "./assets/base-css-BifSeW2H.js";
8
+ import { a as FENIX_ICON_BASE_CSS, f as fenixIconHtml, e as esc, i as isFenixIconName } from "./assets/base-css-Be_r8aTo.js";
9
+ import { s, b } from "./assets/base-css-Be_r8aTo.js";
9
10
  const lightTokens = {
10
11
  color: {
11
12
  primary: "#c2410c",
@@ -306,37 +307,6 @@ function defineElement(tag, ctor) {
306
307
  }
307
308
  return customElements.get(tag) ?? ctor;
308
309
  }
309
- const HTML_ENTITIES = {
310
- "&": "&",
311
- "<": "&lt;",
312
- ">": "&gt;",
313
- '"': "&quot;",
314
- "'": "&#39;",
315
- "/": "&#x2F;",
316
- "`": "&#x60;",
317
- "=": "&#x3D;"
318
- };
319
- const SANITIZE_REGEX = /[&<>"'`=/]/g;
320
- function esc(value) {
321
- if (value == null) return "";
322
- return String(value).replace(SANITIZE_REGEX, (char) => HTML_ENTITIES[char] || char);
323
- }
324
- function stripTags(html) {
325
- return html.replace(/<[^>]*>/g, "");
326
- }
327
- function sanitizeData(data) {
328
- if (data == null) return data;
329
- if (typeof data === "string") return esc(data);
330
- if (Array.isArray(data)) return data.map(sanitizeData);
331
- if (typeof data === "object") {
332
- const result = {};
333
- for (const [key2, value] of Object.entries(data)) {
334
- result[key2] = sanitizeData(value);
335
- }
336
- return result;
337
- }
338
- return data;
339
- }
340
310
  const FX_JSX_TYPES = true;
341
311
  const _FxButton = class _FxButton extends FxElement {
342
312
  constructor() {
@@ -359,12 +329,12 @@ const _FxButton = class _FxButton extends FxElement {
359
329
  };
360
330
  }
361
331
  static get observedAttributes() {
362
- return ["variant", "size", "disabled", "loading", "type", "full"];
332
+ return ["variant", "size", "disabled", "loading", "type", "full", "icon", "icon-pos"];
363
333
  }
364
334
  /** Tamanho. Padrão: `'md'`. */
365
335
  get size() {
366
- const s = this.getAttr("size", "md");
367
- return s === "sm" || s === "lg" ? s : "md";
336
+ const s2 = this.getAttr("size", "md");
337
+ return s2 === "sm" || s2 === "lg" ? s2 : "md";
368
338
  }
369
339
  set size(value) {
370
340
  this.setAttribute("size", value);
@@ -385,21 +355,28 @@ const _FxButton = class _FxButton extends FxElement {
385
355
  const loading = this.hasAttr("loading");
386
356
  const disabled = this.hasAttr("disabled") || loading;
387
357
  const btnType = this.getAttr("type", "button");
358
+ const icon = this.getAttr("icon");
359
+ const iconRight = this.getAttr("icon-pos", "left") === "right";
360
+ const slottedIcon = this.querySelector('[slot="icon"]');
361
+ const iconContent = slottedIcon ? '<slot name="icon"></slot>' : icon ? fenixIconHtml(icon) : "";
388
362
  this.setTemplate(`
389
363
  <button class="btn" part="button" type="${btnType}">
390
- <span class="btn__icon" part="icon"><slot name="icon"></slot></span>
364
+ ${!iconRight ? `<span class="btn__icon" part="icon">${iconContent}</span>` : ""}
391
365
  <span class="btn__label" part="label"><slot></slot></span>
366
+ ${iconRight ? `<span class="btn__icon" part="icon">${iconContent}</span>` : ""}
392
367
  ${loading ? '<span class="btn__spinner" aria-hidden="true"></span>' : ""}
393
368
  </button>
394
369
  `);
395
370
  const btn = this.root.querySelector(".btn");
396
371
  if (!btn) return;
397
- const iconSlot = btn.querySelector(".btn__icon slot");
398
- const iconWrap = this.root.querySelector(".btn__icon");
399
- const hasIcon = Boolean(iconSlot?.assignedNodes({ flatten: true }).some(
400
- (n) => n.nodeType === Node.ELEMENT_NODE || (n.textContent ?? "").trim() !== ""
401
- ));
402
- iconWrap?.toggleAttribute("hidden", !hasIcon);
372
+ const hasIcon = iconContent.trim() !== "";
373
+ for (const wrap of this.root.querySelectorAll(".btn__icon")) {
374
+ wrap.toggleAttribute("hidden", !hasIcon);
375
+ }
376
+ const hasLabel = [...this.childNodes ?? []].some(
377
+ (n) => n.nodeType === Node.ELEMENT_NODE ? n.getAttribute?.("slot") !== "icon" : (n.textContent ?? "").trim() !== ""
378
+ );
379
+ btn.classList.toggle("btn--icon-only", !hasLabel && hasIcon);
403
380
  if (disabled) {
404
381
  btn.setAttribute("disabled", "");
405
382
  btn.setAttribute("aria-disabled", "true");
@@ -420,10 +397,18 @@ const _FxButton = class _FxButton extends FxElement {
420
397
  }
421
398
  };
422
399
  _FxButton.styles = css`
400
+ ${FENIX_ICON_BASE_CSS}
423
401
  :host {
424
402
  display: inline-block;
425
403
  vertical-align: middle;
426
404
  }
405
+ /* Full width: o host inline-block é shrink-to-fit, então precisa virar
406
+ block para o 100% do .btn interno ter contra o que esticar. */
407
+ :host([full]) {
408
+ display: block;
409
+ width: 100%;
410
+ max-width: 100%;
411
+ }
427
412
  .btn {
428
413
  display: inline-flex;
429
414
  align-items: center;
@@ -475,9 +460,13 @@ _FxButton.styles = css`
475
460
  :host([variant='outline']) .btn:hover { background: var(--fx-surface-surface-hover); filter: none; }
476
461
 
477
462
  /* Ícone e spinner */
478
- .btn__icon { display: inline-flex; }
463
+ .btn__icon { display: inline-flex; align-items: center; font-size: var(--fx-button-icon-size, calc(var(--fx-font-size) + 6px)); line-height: 1; }
479
464
  .btn__icon[hidden] { display: none; }
480
465
  .btn__label { display: inline-flex; align-items: center; justify-content: center; }
466
+ /* Icon-only: a label some (o gap do flex some junto) e o botão vira
467
+ quadrado com padding simétrico — ícone perfeitamente centralizado. */
468
+ .btn--icon-only { padding-left: var(--fx-space-md); padding-right: var(--fx-space-md); }
469
+ .btn--icon-only .btn__label { display: none; }
481
470
  .btn[hidden] { display: none; }
482
471
  .btn__spinner {
483
472
  width: 1em;
@@ -571,8 +560,8 @@ const _FxSpinner = class _FxSpinner extends FxElement {
571
560
  }
572
561
  /** Tamanho do spinner. Padrão: `'md'`. */
573
562
  get size() {
574
- const s = this.getAttr("size", "md");
575
- return s === "sm" || s === "lg" ? s : "md";
563
+ const s2 = this.getAttr("size", "md");
564
+ return s2 === "sm" || s2 === "lg" ? s2 : "md";
576
565
  }
577
566
  set size(value) {
578
567
  this.setAttribute("size", value);
@@ -612,12 +601,12 @@ const _FxSelect = class _FxSelect extends FxElement {
612
601
  // `value` fica FORA da observação: refleti-lo no change não pode
613
602
  // re-renderizar o template e fechar o dropdown.
614
603
  static get observedAttributes() {
615
- return ["size", "disabled", "placeholder", "searchable", "clearable", "error", "success"];
604
+ return ["size", "disabled", "placeholder", "searchable", "clearable", "error", "invalid", "success", "valid"];
616
605
  }
617
606
  /** Tamanho do campo. Padrão: `'md'`. */
618
607
  get size() {
619
- const s = this.getAttr("size", "md");
620
- return s === "sm" || s === "lg" ? s : "md";
608
+ const s2 = this.getAttr("size", "md");
609
+ return s2 === "sm" || s2 === "lg" ? s2 : "md";
621
610
  }
622
611
  set size(value) {
623
612
  this.setAttribute("size", value);
@@ -808,6 +797,10 @@ _FxSelect.styles = css`
808
797
  }
809
798
  :host([size='sm']) .trigger { min-width: 180px; min-height: var(--fx-size-sm); }
810
799
  :host([size='lg']) .trigger { min-height: var(--fx-size-lg); font-size: calc(var(--fx-font-size) + 4px); }
800
+ /* Full width: o host estica até o pai e o trigger acompanha. */
801
+ :host([full]) { display: block; width: 100%; }
802
+ :host([full]) .trigger { width: 100%; min-width: 0; }
803
+ :host([full]) .panel { width: 100%; }
811
804
  /* Validação */
812
805
  :host([error]) .trigger,
813
806
  :host([invalid]) .trigger {
@@ -921,6 +914,8 @@ defineFxSelect();
921
914
  const _FxInput = class _FxInput extends FxElement {
922
915
  // `value` fica FORA da observação: refleti-lo a cada tecla não pode
923
916
  // re-renderizar o template, senão o campo perde o foco ao digitar.
917
+ // `error`/`success` (+ aliases `invalid`/`valid`) PRECISAM ser observados:
918
+ // é assim que o toggle no playground / setAttribute no submit re-renderiza.
924
919
  static get observedAttributes() {
925
920
  return [
926
921
  "type",
@@ -930,13 +925,19 @@ const _FxInput = class _FxInput extends FxElement {
930
925
  "readonly",
931
926
  "min",
932
927
  "max",
933
- "step"
928
+ "step",
929
+ "icon",
930
+ "icon-pos",
931
+ "error",
932
+ "invalid",
933
+ "success",
934
+ "valid"
934
935
  ];
935
936
  }
936
937
  /** Tamanho do campo. Padrão: `'md'`. */
937
938
  get size() {
938
- const s = this.getAttr("size", "md");
939
- return s === "sm" || s === "lg" ? s : "md";
939
+ const s2 = this.getAttr("size", "md");
940
+ return s2 === "sm" || s2 === "lg" ? s2 : "md";
940
941
  }
941
942
  set size(value) {
942
943
  this.setAttribute("size", value);
@@ -961,12 +962,21 @@ const _FxInput = class _FxInput extends FxElement {
961
962
  const min = this.getAttr("min");
962
963
  const max = this.getAttr("max");
963
964
  const step = this.getAttr("step");
965
+ const icon = this.getAttr("icon");
966
+ const iconPos = this.getAttr("icon-pos", "left") === "right" ? "right" : "left";
967
+ const slottedIcon = this.querySelector('[slot="icon"]');
968
+ const iconContent = slottedIcon ? '<slot name="icon" part="icon"></slot>' : icon ? fenixIconHtml(icon) : "";
969
+ const useIconBox = Boolean(iconContent);
964
970
  this.setTemplate(`
965
- ${this.hasAttr("clearable") ? '<div class="wrap">' : ""}
971
+ ${this.hasAttr("clearable") ? '<div class="wrap" part="wrap">' : ""}
972
+ ${useIconBox ? `<div class="field-icon icon-${iconPos}">` : ""}
973
+ ${useIconBox && iconPos === "left" ? iconContent : ""}
966
974
  <input class="field" part="input" type="${esc(type)}"
967
975
  ${placeholder ? `placeholder="${esc(placeholder)}"` : ""}
968
976
  ${min ? `min="${esc(min)}"` : ""} ${max ? `max="${esc(max)}"` : ""} ${step ? `step="${esc(step)}"` : ""}
969
977
  />
978
+ ${useIconBox && iconPos === "right" ? iconContent : ""}
979
+ ${useIconBox ? "</div>" : ""}
970
980
  ${this.hasAttr("clearable") ? '<button type="button" class="clear" part="clear" aria-label="Limpar" tabindex="-1">×</button></div>' : ""}
971
981
  `);
972
982
  const field = this.root.querySelector(".field");
@@ -1056,10 +1066,56 @@ _FxInput.styles = css`
1056
1066
  }
1057
1067
  :host([size='sm']) .field { padding: var(--fx-space-sm) var(--fx-space-md); font-size: var(--fx-font-size); width: 220px; min-height: var(--fx-size-sm); }
1058
1068
  :host([size='lg']) .field { padding: var(--fx-space-lg) var(--fx-space-xl); font-size: calc(var(--fx-font-size) + 4px); width: 300px; min-height: var(--fx-size-lg); }
1069
+ /* Full width: o host estica até o pai e o campo interno acompanha
1070
+ (usar com um container de largura controlada, ex. w-full no Vue). */
1071
+ :host([full]) { display: block; width: 100%; }
1072
+ :host([full]) .field { width: 100%; }
1059
1073
  /* Clearable */
1060
1074
  :host([clearable]) { position: relative; display: inline-flex; }
1075
+ :host([clearable][full]) { display: block; }
1061
1076
  .wrap { position: relative; display: inline-flex; align-items: center; }
1077
+ :host([full]) .wrap { display: flex; width: 100%; }
1062
1078
  :host([clearable]) .field { padding-right: var(--fx-space-xl); }
1079
+ :host([clearable][full]) .field { flex: 1 1 auto; }
1080
+ /* Ícones (attr icon + slot icon) — DENTRO do campo, sobre o padding
1081
+ (padrão Material/PrimeVue). Tamanho ajustável via --fx-input-icon-size. */
1082
+ .field-icon {
1083
+ position: relative;
1084
+ display: inline-flex;
1085
+ box-sizing: border-box;
1086
+ }
1087
+ .field-icon .field { flex: 1 1 auto; min-width: 0; }
1088
+ :host([full]) .field-icon { display: flex; width: 100%; }
1089
+ .field-icon .fx-icon,
1090
+ .field-icon ::slotted([slot='icon']) {
1091
+ position: absolute;
1092
+ top: 50%;
1093
+ transform: translateY(-50%);
1094
+ display: inline-flex;
1095
+ align-items: center;
1096
+ justify-content: center;
1097
+ font-size: var(--fx-input-icon-size, calc(var(--fx-font-size) + 6px));
1098
+ line-height: 1;
1099
+ color: var(--fx-text-muted);
1100
+ pointer-events: none;
1101
+ z-index: 1;
1102
+ }
1103
+ .field-icon.icon-left .fx-icon,
1104
+ .field-icon.icon-left ::slotted([slot='icon']) { left: var(--fx-space-md); }
1105
+ .field-icon.icon-right .fx-icon,
1106
+ .field-icon.icon-right ::slotted([slot='icon']) { right: var(--fx-space-md); }
1107
+ /* padding = posição do ícone + largura + folga extra para o texto
1108
+ não colar no glifo. */
1109
+ .field-icon.icon-left .field {
1110
+ padding-left: calc(var(--fx-input-icon-size, calc(var(--fx-font-size) + 6px)) + var(--fx-space-md) + var(--fx-space-sm));
1111
+ }
1112
+ .field-icon.icon-right .field {
1113
+ padding-right: calc(var(--fx-input-icon-size, calc(var(--fx-font-size) + 6px)) + var(--fx-space-md) + var(--fx-space-sm));
1114
+ }
1115
+ /* icon-pos right + clearable: desloca o × para não sobrepor o ícone. */
1116
+ .field-icon.icon-right + .clear {
1117
+ right: calc(var(--fx-input-icon-size, calc(var(--fx-font-size) + 6px)) + var(--fx-space-lg));
1118
+ }
1063
1119
  .clear {
1064
1120
  position: absolute;
1065
1121
  right: var(--fx-space-xs);
@@ -1074,6 +1130,8 @@ _FxInput.styles = css`
1074
1130
  }
1075
1131
  .clear:hover { color: var(--fx-color-danger); }
1076
1132
  .clear[hidden] { display: none; }
1133
+ /* Base dos glifos Fenix Icons (o @font-face vem de @wrrdev/fenix-ui/icons). */
1134
+ ${FENIX_ICON_BASE_CSS}
1077
1135
  `;
1078
1136
  let FxInput = _FxInput;
1079
1137
  function defineFxInput() {
@@ -1086,8 +1144,8 @@ const _FxSwitch = class _FxSwitch extends FxElement {
1086
1144
  }
1087
1145
  /** Tamanho da trilha. Padrão: `'md'`. */
1088
1146
  get size() {
1089
- const s = this.getAttr("size", "md");
1090
- return s === "sm" || s === "lg" ? s : "md";
1147
+ const s2 = this.getAttr("size", "md");
1148
+ return s2 === "sm" || s2 === "lg" ? s2 : "md";
1091
1149
  }
1092
1150
  set size(value) {
1093
1151
  this.setAttribute("size", value);
@@ -1194,7 +1252,7 @@ const _FxMultiselect = class _FxMultiselect extends FxElement {
1194
1252
  this.selected = /* @__PURE__ */ new Set();
1195
1253
  }
1196
1254
  static get observedAttributes() {
1197
- return ["disabled", "placeholder"];
1255
+ return ["disabled", "placeholder", "error", "invalid", "success", "valid"];
1198
1256
  }
1199
1257
  /** Valores selecionados (CSV no atributo / array na propriedade). */
1200
1258
  get values() {
@@ -1416,6 +1474,9 @@ _FxMultiselect.styles = css`
1416
1474
  }
1417
1475
  :host([size='sm']) .trigger { min-height: var(--fx-size-sm); width: 200px; }
1418
1476
  :host([size='lg']) .trigger { min-height: var(--fx-size-lg); width: 280px; font-size: calc(var(--fx-font-size) + 4px); }
1477
+ /* Full width: o host estica até o pai e o trigger acompanha. */
1478
+ :host([full]) { display: block; width: 100%; }
1479
+ :host([full]) .trigger { width: 100%; }
1419
1480
  /* Validação */
1420
1481
  :host([error]) .trigger,
1421
1482
  :host([invalid]) .trigger {
@@ -1715,13 +1776,13 @@ const _FxCalendar = class _FxCalendar extends FxElement {
1715
1776
  this.values.map((iso) => parseBound(iso)?.lo ?? 0).filter(Boolean)
1716
1777
  );
1717
1778
  if (this.mode === "range") {
1718
- let s = this.pickStart;
1779
+ let s2 = this.pickStart;
1719
1780
  let e = this.pickEnd;
1720
1781
  const attrS = parseBound(this.getAttr("start", ""));
1721
1782
  const attrE = parseBound(this.getAttr("end", ""));
1722
- if (s === null && attrS) s = attrS.lo;
1783
+ if (s2 === null && attrS) s2 = attrS.lo;
1723
1784
  if (e === null && attrE) e = attrE.lo;
1724
- return { start: s, end: e, single: null, multi };
1785
+ return { start: s2, end: e, single: null, multi };
1725
1786
  }
1726
1787
  if (this.mode === "multiple") {
1727
1788
  return { start: null, end: null, single: null, multi };
@@ -1844,9 +1905,9 @@ const _FxCalendar = class _FxCalendar extends FxElement {
1844
1905
  <div class="grid ${this.view}">${cells}</div>
1845
1906
  `);
1846
1907
  this.root.querySelectorAll("[data-nav]").forEach(
1847
- (b) => b.addEventListener(
1908
+ (b2) => b2.addEventListener(
1848
1909
  "click",
1849
- () => this.navigate(Number(b.dataset.nav))
1910
+ () => this.navigate(Number(b2.dataset.nav))
1850
1911
  )
1851
1912
  );
1852
1913
  const gotoBtn = this.root.querySelector("[data-goto]");
@@ -1855,21 +1916,21 @@ const _FxCalendar = class _FxCalendar extends FxElement {
1855
1916
  this.render();
1856
1917
  });
1857
1918
  this.root.querySelectorAll("[data-day]").forEach(
1858
- (b) => b.addEventListener(
1919
+ (b2) => b2.addEventListener(
1859
1920
  "click",
1860
- () => this.pickDay(Number(b.dataset.day))
1921
+ () => this.pickDay(Number(b2.dataset.day))
1861
1922
  )
1862
1923
  );
1863
1924
  this.root.querySelectorAll("[data-month]").forEach(
1864
- (b) => b.addEventListener("click", () => {
1865
- this.cursor.m = Number(b.dataset.month);
1925
+ (b2) => b2.addEventListener("click", () => {
1926
+ this.cursor.m = Number(b2.dataset.month);
1866
1927
  this.view = "days";
1867
1928
  this.render();
1868
1929
  })
1869
1930
  );
1870
1931
  this.root.querySelectorAll("[data-year]").forEach(
1871
- (b) => b.addEventListener("click", () => {
1872
- this.cursor.y = Number(b.dataset.year);
1932
+ (b2) => b2.addEventListener("click", () => {
1933
+ this.cursor.y = Number(b2.dataset.year);
1873
1934
  this.view = "months";
1874
1935
  this.render();
1875
1936
  })
@@ -2042,7 +2103,7 @@ const _FxDatepicker = class _FxDatepicker extends FxElement {
2042
2103
  this.time = { h: 0, m: 0, s: 0 };
2043
2104
  }
2044
2105
  static get observedAttributes() {
2045
- return ["value", "start", "end", "values", "mode", "min", "max", "placeholder", "disabled", "format", "show-time", "free-text"];
2106
+ return ["value", "start", "end", "values", "mode", "min", "max", "placeholder", "disabled", "format", "show-time", "free-text", "error", "invalid", "success", "valid"];
2046
2107
  }
2047
2108
  get mode() {
2048
2109
  const m = this.getAttr("mode", "single");
@@ -2097,15 +2158,15 @@ const _FxDatepicker = class _FxDatepicker extends FxElement {
2097
2158
  /** Texto exibido no input conforme o modo. */
2098
2159
  displayText() {
2099
2160
  if (this.mode === "range") {
2100
- const s = this.getAttr("start");
2161
+ const s2 = this.getAttr("start");
2101
2162
  const e = this.getAttr("end");
2102
2163
  this.hasAttr("show-time") ? " " : " → ";
2103
- if (!s && !e) return "";
2164
+ if (!s2 && !e) return "";
2104
2165
  if (this.hasAttr("show-time")) {
2105
2166
  const f = (iso) => iso ? `${this.formatDate(iso)} ${this.timeText()}` : iso ? `${this.formatDate(iso)} …` : "";
2106
- return s && e ? `${f(s)} → ${f(e)}` : f(s);
2167
+ return s2 && e ? `${f(s2)} → ${f(e)}` : f(s2);
2107
2168
  }
2108
- return s && e ? `${this.formatDate(s)} → ${this.formatDate(e)}` : s ? `${this.formatDate(s)} → …` : "";
2169
+ return s2 && e ? `${this.formatDate(s2)} → ${this.formatDate(e)}` : s2 ? `${this.formatDate(s2)} → …` : "";
2109
2170
  }
2110
2171
  if (this.mode === "multiple") {
2111
2172
  return this.values.map((v) => this.formatDate(v)).join(", ");
@@ -2123,8 +2184,8 @@ const _FxDatepicker = class _FxDatepicker extends FxElement {
2123
2184
  const src = this.value || this.getAttr("start") || "";
2124
2185
  const t = src.split("T")[1];
2125
2186
  if (!t) return;
2126
- const [h, m, s] = t.split(":").map((n) => parseInt(n, 10));
2127
- this.time = { h: h || 0, m: m || 0, s: s || 0 };
2187
+ const [h, m, s2] = t.split(":").map((n) => parseInt(n, 10));
2188
+ this.time = { h: h || 0, m: m || 0, s: s2 || 0 };
2128
2189
  }
2129
2190
  /** Anexa o horário interno ao ISO puro vindo do calendário. */
2130
2191
  withTime(iso) {
@@ -2232,12 +2293,12 @@ const _FxDatepicker = class _FxDatepicker extends FxElement {
2232
2293
  const applyTime = () => {
2233
2294
  const h = this.root.querySelector(".t-h");
2234
2295
  const m = this.root.querySelector(".t-m");
2235
- const s = this.root.querySelector(".t-s");
2296
+ const s2 = this.root.querySelector(".t-s");
2236
2297
  const clamp = (v, max) => Math.min(max, Math.max(0, parseInt(v ?? "0", 10) || 0));
2237
2298
  this.time = {
2238
2299
  h: clamp(h?.value, 23),
2239
2300
  m: clamp(m?.value, 59),
2240
- s: clamp(s?.value, 59)
2301
+ s: clamp(s2?.value, 59)
2241
2302
  };
2242
2303
  const reattach = (iso) => iso.split("T")[0] ? `${iso.split("T")[0]}T${this.timeText()}` : iso;
2243
2304
  if (this.value) this.setAttribute("value", reattach(this.value));
@@ -2280,7 +2341,7 @@ const _FxDatepicker = class _FxDatepicker extends FxElement {
2280
2341
  if (Number.isNaN(d.getTime())) return null;
2281
2342
  const [y, m, day] = iso.split("-").map((n) => parseInt(n, 10));
2282
2343
  if (d.getFullYear() !== y || d.getMonth() + 1 !== m || d.getDate() !== day) return null;
2283
- const cmp = (a, b) => a.split("T")[0].localeCompare(b.split("T")[0]);
2344
+ const cmp = (a, b2) => a.split("T")[0].localeCompare(b2.split("T")[0]);
2284
2345
  const min = this.getAttr("min");
2285
2346
  const max = this.getAttr("max");
2286
2347
  if (min && cmp(iso, min) < 0) return null;
@@ -2307,9 +2368,9 @@ const _FxDatepicker = class _FxDatepicker extends FxElement {
2307
2368
  this.setAttribute("start", this.withTime(parsed));
2308
2369
  this.removeAttribute("end");
2309
2370
  } else {
2310
- const [a, b] = [this.getAttr("start").split("T")[0], parsed].sort();
2371
+ const [a, b2] = [this.getAttr("start").split("T")[0], parsed].sort();
2311
2372
  this.setAttribute("start", this.withTime(a));
2312
- this.setAttribute("end", this.withTime(b));
2373
+ this.setAttribute("end", this.withTime(b2));
2313
2374
  }
2314
2375
  this.emitChange({ start: this.getAttr("start"), end: this.getAttr("end") });
2315
2376
  } else {
@@ -2356,6 +2417,10 @@ _FxDatepicker.styles = css`
2356
2417
  :host([mode='range'][size='lg']) .field { min-width: 360px; }
2357
2418
  :host([mode='multiple'][size='lg']) .field { min-width: 320px; }
2358
2419
  :host([show-time]) .field { min-width: 250px; }
2420
+ /* Full width: o host estica até o pai (os min-width dos modos são
2421
+ descartados para permitir layouts estreitos sob controle do pai). */
2422
+ :host([full]) { display: block; width: 100%; }
2423
+ :host([full]) .field { min-width: 0; }
2359
2424
  /* Validação */
2360
2425
  :host([error]) .field,
2361
2426
  :host([invalid]) .field {
@@ -2494,8 +2559,8 @@ const _FxCheckbox = class _FxCheckbox extends FxElement {
2494
2559
  }
2495
2560
  /** Tamanho do controle. Padrão: `'md'`. */
2496
2561
  get size() {
2497
- const s = this.getAttr("size", "md");
2498
- return s === "sm" || s === "lg" ? s : "md";
2562
+ const s2 = this.getAttr("size", "md");
2563
+ return s2 === "sm" || s2 === "lg" ? s2 : "md";
2499
2564
  }
2500
2565
  set size(value) {
2501
2566
  this.setAttribute("size", value);
@@ -2623,8 +2688,8 @@ const _FxRadio = class _FxRadio extends FxElement {
2623
2688
  }
2624
2689
  /** Tamanho do controle. Padrão: `'md'`. */
2625
2690
  get size() {
2626
- const s = this.getAttr("size", "md");
2627
- return s === "sm" || s === "lg" ? s : "md";
2691
+ const s2 = this.getAttr("size", "md");
2692
+ return s2 === "sm" || s2 === "lg" ? s2 : "md";
2628
2693
  }
2629
2694
  set size(value) {
2630
2695
  this.setAttribute("size", value);
@@ -3267,8 +3332,8 @@ const _FxTable = class _FxTable extends FxElement {
3267
3332
  }
3268
3333
  const total = this.lazy ? this.total : out.length;
3269
3334
  if (this.sortField) {
3270
- out.sort((a, b) => {
3271
- const av = a[this.sortField], bv = b[this.sortField];
3335
+ out.sort((a, b2) => {
3336
+ const av = a[this.sortField], bv = b2[this.sortField];
3272
3337
  if (typeof av === "number" && typeof bv === "number")
3273
3338
  return (av - bv) * this.sortDir;
3274
3339
  return String(av ?? "").localeCompare(String(bv ?? ""), "pt-BR") * this.sortDir;
@@ -3287,7 +3352,7 @@ const _FxTable = class _FxTable extends FxElement {
3287
3352
  if (!input) return [];
3288
3353
  const attr = input.getAttribute("data-search-fields");
3289
3354
  if (attr === null) return [];
3290
- return attr.split(",").map((s) => s.trim()).filter(Boolean);
3355
+ return attr.split(",").map((s2) => s2.trim()).filter(Boolean);
3291
3356
  }
3292
3357
  cellHtml(col, row) {
3293
3358
  const template = col.template?.innerHTML ?? col.directTemplate;
@@ -3671,7 +3736,7 @@ const _FxFloatlabel = class _FxFloatlabel extends FxElement {
3671
3736
  this.listenersReady = false;
3672
3737
  }
3673
3738
  static get observedAttributes() {
3674
- return ["variant", "error", "invalid", "success", "valid"];
3739
+ return ["variant", "error", "invalid", "success", "valid", "full", "icon", "icon-pos"];
3675
3740
  }
3676
3741
  render() {
3677
3742
  const control = this.findControl();
@@ -3695,6 +3760,9 @@ const _FxFloatlabel = class _FxFloatlabel extends FxElement {
3695
3760
  this.syncControlReference(control);
3696
3761
  this.syncState();
3697
3762
  this.applyError();
3763
+ this.applyFull();
3764
+ this.applyIcon();
3765
+ this.syncIconIndent();
3698
3766
  }
3699
3767
  disconnectedCallback() {
3700
3768
  super.disconnectedCallback();
@@ -3720,6 +3788,7 @@ const _FxFloatlabel = class _FxFloatlabel extends FxElement {
3720
3788
  this.syncControlReference(control);
3721
3789
  this.syncState();
3722
3790
  this.applyError();
3791
+ this.applyFull();
3723
3792
  });
3724
3793
  }
3725
3794
  if (this.listenersReady) return;
@@ -3739,10 +3808,13 @@ const _FxFloatlabel = class _FxFloatlabel extends FxElement {
3739
3808
  this.observer = null;
3740
3809
  this.targetControl = control;
3741
3810
  if (control) {
3742
- this.observer = new MutationObserver(() => this.syncState());
3811
+ this.observer = new MutationObserver(() => {
3812
+ this.syncState();
3813
+ this.syncIconIndent();
3814
+ });
3743
3815
  this.observer.observe(control, {
3744
3816
  attributes: true,
3745
- attributeFilter: ["value", "values", "start", "end", "open"]
3817
+ attributeFilter: ["value", "values", "start", "end", "open", "icon", "icon-pos"]
3746
3818
  });
3747
3819
  }
3748
3820
  }
@@ -3774,6 +3846,41 @@ const _FxFloatlabel = class _FxFloatlabel extends FxElement {
3774
3846
  this.removeAttribute("focus");
3775
3847
  }
3776
3848
  }
3849
+ /**
3850
+ * variant="in" + ícone à esquerda dentro do campo (fx-input icon):
3851
+ * enquanto a label é placeholder ela precisa começar depois do glifo.
3852
+ * Detecta via atributos icon/icon-pos (ou slot icon) do controle.
3853
+ */
3854
+ syncIconIndent() {
3855
+ const label = this.root.querySelector(".flabel");
3856
+ if (!label) return;
3857
+ const c = this.targetControl;
3858
+ const hasLeftIcon = Boolean(
3859
+ c && (c.hasAttribute("icon") || c.querySelector(':scope > [slot="icon"]')) && c.getAttribute("icon-pos") !== "right"
3860
+ );
3861
+ label.classList.toggle("icon-indent", hasLeftIcon);
3862
+ }
3863
+ applyFull() {
3864
+ if (this.targetControl && typeof this.targetControl.setAttribute === "function") {
3865
+ if (this.hasAttr("full")) {
3866
+ this.targetControl.setAttribute("full", "");
3867
+ } else {
3868
+ this.targetControl.removeAttribute("full");
3869
+ }
3870
+ }
3871
+ }
3872
+ applyIcon() {
3873
+ if (this.targetControl && typeof this.targetControl.setAttribute === "function") {
3874
+ if (this.hasAttr("icon")) {
3875
+ const icon = this.getAttr("icon");
3876
+ const iconPos = this.getAttr("icon-pos");
3877
+ if (icon !== "") this.targetControl.setAttribute("icon", icon);
3878
+ else this.targetControl.setAttribute("icon", "");
3879
+ if (iconPos && iconPos !== "left") this.targetControl.setAttribute("icon-pos", iconPos);
3880
+ else this.targetControl.removeAttribute("icon-pos");
3881
+ }
3882
+ }
3883
+ }
3777
3884
  applyError() {
3778
3885
  const hasError = this.hasAttr("error") || this.hasAttr("invalid");
3779
3886
  const errMsg = this.root.querySelector(
@@ -3816,6 +3923,12 @@ _FxFloatlabel.styles = css`
3816
3923
  font-size: var(--fx-font-size);
3817
3924
  vertical-align: middle;
3818
3925
  }
3926
+ /* Full width: o host estica até o pai; o controle interno com
3927
+ atributo full (ou largura herdada) acompanha. */
3928
+ :host([full]) {
3929
+ display: block;
3930
+ width: 100%;
3931
+ }
3819
3932
  .wrapper {
3820
3933
  position: relative;
3821
3934
  display: inline-block;
@@ -3881,6 +3994,21 @@ _FxFloatlabel.styles = css`
3881
3994
  color: var(--fx-color-primary, #4f46e5);
3882
3995
  }
3883
3996
 
3997
+ /* ---- variant="in" com ícone dentro do campo (fx-input icon):
3998
+ enquanto a label funciona como placeholder (sem foco/valor), ela
3999
+ começa DEPOIS do glifo (mesma métrica de padding do fx-input).
4000
+ Ao subir (active), volta ao offset padrão da borda. ---- */
4001
+ :host([variant="in"]) .flabel.icon-indent {
4002
+ left: calc(
4003
+ var(--fx-space-md, 12px) +
4004
+ var(--fx-input-icon-size, calc(var(--fx-font-size, 14px) + 6px)) +
4005
+ var(--fx-space-sm, 8px)
4006
+ );
4007
+ }
4008
+ :host([variant="in"][active]) .flabel.icon-indent {
4009
+ left: var(--fx-space-md, 12px);
4010
+ }
4011
+
3884
4012
  /* ---- variant="over": label estática ACIMA do campo (fora, em fluxo) ---- */
3885
4013
  :host([variant="over"]) {
3886
4014
  display: block;
@@ -3928,11 +4056,11 @@ function defineFxFloatlabel() {
3928
4056
  defineFxFloatlabel();
3929
4057
  const _FxTextarea = class _FxTextarea extends FxElement {
3930
4058
  static get observedAttributes() {
3931
- return ["size", "placeholder", "disabled", "readonly", "rows", "maxlength"];
4059
+ return ["size", "placeholder", "disabled", "readonly", "rows", "maxlength", "error", "invalid", "success", "valid"];
3932
4060
  }
3933
4061
  get size() {
3934
- const s = this.getAttr("size", "md");
3935
- return s === "sm" || s === "lg" ? s : "md";
4062
+ const s2 = this.getAttr("size", "md");
4063
+ return s2 === "sm" || s2 === "lg" ? s2 : "md";
3936
4064
  }
3937
4065
  set size(value) {
3938
4066
  this.setAttribute("size", value);
@@ -4020,8 +4148,11 @@ _FxTextarea.styles = css`
4020
4148
  border-color: var(--fx-color-success, #16a34a);
4021
4149
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--fx-color-success, #16a34a) 18%, transparent);
4022
4150
  }
4023
- :host([size='sm']) .field { width: 220px; min-height: var(--fx-size-sm); padding: var(--fx-space-sm) var(--fx-space-md); }
4151
+ :host([size='sm']) .field { min-height: var(--fx-size-sm); padding: var(--fx-space-sm) var(--fx-space-md); width: 220px; }
4024
4152
  :host([size='lg']) .field { width: 300px; min-height: calc(var(--fx-size-lg) + 80px); }
4153
+ /* Full width: o host estica até o pai e o campo interno acompanha. */
4154
+ :host([full]) { display: block; width: 100%; }
4155
+ :host([full]) .field { width: 100%; }
4025
4156
  `;
4026
4157
  let FxTextarea = _FxTextarea;
4027
4158
  function defineFxTextarea() {
@@ -4508,11 +4639,11 @@ const _FxFileUpload = class _FxFileUpload extends FxElement {
4508
4639
  this._done = false;
4509
4640
  }
4510
4641
  static get observedAttributes() {
4511
- return ["mode", "size", "severity", "label", "icon", "accept", "multiple", "disabled", "show-progress", "progress", "value"];
4642
+ return ["mode", "size", "severity", "label", "icon", "accept", "multiple", "disabled", "show-progress", "progress", "value", "full"];
4512
4643
  }
4513
4644
  get size() {
4514
- const s = this.getAttr("size", "md");
4515
- return s === "sm" || s === "lg" ? s : "md";
4645
+ const s2 = this.getAttr("size", "md");
4646
+ return s2 === "sm" || s2 === "lg" ? s2 : "md";
4516
4647
  }
4517
4648
  set size(value) {
4518
4649
  this.setAttribute("size", value);
@@ -4552,11 +4683,11 @@ const _FxFileUpload = class _FxFileUpload extends FxElement {
4552
4683
  const fileInput = `<input type="file" class="picker" ${accept ? `accept="${esc(accept)}"` : ""} ${multiple ? "multiple" : ""} ${disabled ? "disabled" : ""} />`;
4553
4684
  this.setTemplate(`
4554
4685
  ${advanced ? `<div class="drop" part="dropzone" role="button" tabindex="0" aria-label="${esc(label)}">
4555
- ${icon ? `<span class="icon" aria-hidden="true">${esc(icon)}</span>` : ""}
4686
+ ${icon ? `<span class="icon" part="icon" aria-hidden="true">${fenixIconHtml(icon)}</span>` : ""}
4556
4687
  <span>${esc(label)}</span>
4557
4688
  <span class="hint">ou arraste e solte aqui</span>
4558
4689
  </div>` : `<button type="button" class="btn" part="button">
4559
- ${icon ? `<span class="icon" aria-hidden="true">${esc(icon)}</span>` : ""}
4690
+ ${icon ? `<span class="icon" part="icon" aria-hidden="true">${fenixIconHtml(icon)}</span>` : ""}
4560
4691
  <span>${esc(label)}</span>
4561
4692
  </button>`}
4562
4693
  ${fileInput}
@@ -4771,6 +4902,12 @@ _FxFileUpload.styles = css`
4771
4902
  min-width: 34px;
4772
4903
  text-align: right;
4773
4904
  }
4905
+ /* Full width: o host estica até o pai e o botão/dropzone acompanha. */
4906
+ :host([full]) { display: block; width: 100%; }
4907
+ :host([full]) .btn { width: 100%; }
4908
+ :host([full]) .drop { width: 100%; }
4909
+ /* Base dos glifos Fenix Icons (o @font-face vem de @wrrdev/fenix-ui/icons). */
4910
+ ${FENIX_ICON_BASE_CSS}
4774
4911
  `;
4775
4912
  let FxFileUpload = _FxFileUpload;
4776
4913
  function defineFxFileUpload() {
@@ -5058,7 +5195,7 @@ const _FxChip = class _FxChip extends FxElement {
5058
5195
  this.setTemplate(`
5059
5196
  <span class="chip ${clickable ? "clickable" : ""}" part="chip" role="${clickable ? "button" : "status"}"
5060
5197
  ${clickable ? `tabindex="0" aria-pressed="${this.selected}"` : ""} ${disabled ? 'aria-disabled="true"' : ""}>
5061
- ${icon ? `<span class="icon" aria-hidden="true">${esc(icon)}</span>` : ""}
5198
+ ${icon ? `<span class="icon" aria-hidden="true">${fenixIconHtml(icon)}</span>` : ""}
5062
5199
  <slot></slot>
5063
5200
  <button type="button" class="remove" part="remove" aria-label="Remover" ${removable ? "" : "hidden"}>×</button>
5064
5201
  </span>
@@ -5135,6 +5272,8 @@ _FxChip.styles = css`
5135
5272
  .chip.clickable:active { transform: scale(0.97); }
5136
5273
 
5137
5274
  .icon { line-height: 1; }
5275
+ /* Base dos glifos Fenix Icons (o @font-face vem de @wrrdev/fenix-ui/icons). */
5276
+ ${FENIX_ICON_BASE_CSS}
5138
5277
  .remove {
5139
5278
  display: inline-flex;
5140
5279
  align-items: center;
@@ -5349,12 +5488,12 @@ const _FxBreadcrumb = class _FxBreadcrumb extends FxElement {
5349
5488
  item.setAttribute("aria-current", isLast ? "page" : "false");
5350
5489
  nav.appendChild(item);
5351
5490
  if (isLast) return;
5352
- const s = document.createElement("span");
5353
- s.className = "sep";
5354
- s.setAttribute("part", "separator");
5355
- s.setAttribute("aria-hidden", "true");
5356
- s.textContent = sep;
5357
- nav.appendChild(s);
5491
+ const s2 = document.createElement("span");
5492
+ s2.className = "sep";
5493
+ s2.setAttribute("part", "separator");
5494
+ s2.setAttribute("aria-hidden", "true");
5495
+ s2.textContent = sep;
5496
+ nav.appendChild(s2);
5358
5497
  });
5359
5498
  }
5360
5499
  connectedCallback() {
@@ -5928,7 +6067,7 @@ const _FxMenu = class _FxMenu extends FxElement {
5928
6067
  }
5929
6068
  render() {
5930
6069
  const titleAttr = this.getAttr("titles");
5931
- const titles = titleAttr ? titleAttr.split(",").map((s) => s.trim()) : [];
6070
+ const titles = titleAttr ? titleAttr.split(",").map((s2) => s2.trim()) : [];
5932
6071
  const items = this.items;
5933
6072
  const itemsHtml = items.map((it, i) => {
5934
6073
  const label = titles[i] || it.textContent?.trim() || `Item ${i + 1}`;
@@ -6060,7 +6199,7 @@ const _FxToggleButtonGroup = class _FxToggleButtonGroup extends FxElement {
6060
6199
  }
6061
6200
  get value() {
6062
6201
  const raw = this.getAttr("value");
6063
- return raw ? raw.split(",").map((s) => s.trim()).filter(Boolean) : [];
6202
+ return raw ? raw.split(",").map((s2) => s2.trim()).filter(Boolean) : [];
6064
6203
  }
6065
6204
  set value(v) {
6066
6205
  this.setAttribute("value", v.join(","));
@@ -6159,7 +6298,7 @@ const _FxEmptyState = class _FxEmptyState extends FxElement {
6159
6298
  const description = this.getAttr("description");
6160
6299
  this.setTemplate(`
6161
6300
  <div class="wrap" part="wrap">
6162
- <span class="icon" part="icon" aria-hidden="true">${esc(icon)}</span>
6301
+ <span class="icon" part="icon" aria-hidden="true">${fenixIconHtml(icon)}</span>
6163
6302
  <h4 part="heading" ${heading ? "" : "hidden"}>${esc(heading)}</h4>
6164
6303
  <p part="description" ${description ? "" : "hidden"}>${esc(description)}</p>
6165
6304
  <slot name="icon"></slot>
@@ -6206,6 +6345,8 @@ _FxEmptyState.styles = css`
6206
6345
  p[hidden] { display: none; }
6207
6346
  .action { margin-top: var(--fx-space-sm); }
6208
6347
  .action:empty { display: none; }
6348
+ /* Base dos glifos Fenix Icons (o @font-face vem de @wrrdev/fenix-ui/icons). */
6349
+ ${FENIX_ICON_BASE_CSS}
6209
6350
  `;
6210
6351
  let FxEmptyState = _FxEmptyState;
6211
6352
  function defineFxEmptyState() {
@@ -6487,7 +6628,7 @@ const _FxCarousel = class _FxCarousel extends FxElement {
6487
6628
  }
6488
6629
  render() {
6489
6630
  this._slides = Array.from(this.children).filter((el) => el.matches('[slot="slide"]'));
6490
- const contentsHtml = this._slides.map((s, i) => `<div class="slide" part="slide" data-i="${i}" ${i === this.active ? "" : "hidden"}>${s.innerHTML}</div>`).join("");
6631
+ const contentsHtml = this._slides.map((s2, i) => `<div class="slide" part="slide" data-i="${i}" ${i === this.active ? "" : "hidden"}>${s2.innerHTML}</div>`).join("");
6491
6632
  this.setTemplate(`
6492
6633
  <div class="viewport" part="viewport">
6493
6634
  ${contentsHtml}
@@ -6521,8 +6662,8 @@ const _FxCarousel = class _FxCarousel extends FxElement {
6521
6662
  }
6522
6663
  if (String(target) === this.getAttribute("active")) return;
6523
6664
  this.active = target;
6524
- this.root.querySelectorAll(".slide").forEach((s) => {
6525
- s.toggleAttribute("hidden", Number(s.dataset.i) !== target);
6665
+ this.root.querySelectorAll(".slide").forEach((s2) => {
6666
+ s2.toggleAttribute("hidden", Number(s2.dataset.i) !== target);
6526
6667
  });
6527
6668
  this.root.querySelectorAll(".dot").forEach((d) => {
6528
6669
  d.classList.toggle("on", Number(d.dataset.i) === target);
@@ -7623,8 +7764,8 @@ const _FxSkeleton = class _FxSkeleton extends FxElement {
7623
7764
  return;
7624
7765
  }
7625
7766
  if (variant === "rect") {
7626
- const s = style || "width:100%;height:80px;";
7627
- this.setTemplate(`<div class="bone" part="bone" style="${s}"></div>`);
7767
+ const s2 = style || "width:100%;height:80px;";
7768
+ this.setTemplate(`<div class="bone" part="bone" style="${s2}"></div>`);
7628
7769
  return;
7629
7770
  }
7630
7771
  const lines = Number(this.getAttr("lines", "3")) || 3;
@@ -8131,7 +8272,7 @@ const _FxPagination = class _FxPagination extends FxElement {
8131
8272
  render() {
8132
8273
  const pages = this.pages;
8133
8274
  const current = Math.min(Math.max(1, this.page), pages);
8134
- const opts = (this.getAttr("rows-options", "5,10,20,50") || "").split(",").map((s) => s.trim()).filter(Boolean);
8275
+ const opts = (this.getAttr("rows-options", "5,10,20,50") || "").split(",").map((s2) => s2.trim()).filter(Boolean);
8135
8276
  const window_ = [];
8136
8277
  for (let p = Math.max(1, current - 2); p <= Math.min(pages, current + 2); p++) window_.push(p);
8137
8278
  const from = total0(current, this.rows);
@@ -8228,11 +8369,11 @@ function defineFxPagination() {
8228
8369
  defineFxPagination();
8229
8370
  const _FxAutocomplete = class _FxAutocomplete extends FxElement {
8230
8371
  static get observedAttributes() {
8231
- return ["size", "placeholder", "source", "disabled", "min-chars"];
8372
+ return ["size", "placeholder", "source", "disabled", "min-chars", "error", "invalid", "success", "valid"];
8232
8373
  }
8233
8374
  get size() {
8234
- const s = this.getAttr("size", "md");
8235
- return s === "sm" || s === "lg" ? s : "md";
8375
+ const s2 = this.getAttr("size", "md");
8376
+ return s2 === "sm" || s2 === "lg" ? s2 : "md";
8236
8377
  }
8237
8378
  set size(v) {
8238
8379
  this.setAttribute("size", v);
@@ -8284,7 +8425,7 @@ const _FxAutocomplete = class _FxAutocomplete extends FxElement {
8284
8425
  const openList = () => {
8285
8426
  if (!list) return;
8286
8427
  const q = field.value.toLowerCase();
8287
- const matches = this.source.filter((s) => s.toLowerCase().includes(q)).slice(0, 8);
8428
+ const matches = this.source.filter((s2) => s2.toLowerCase().includes(q)).slice(0, 8);
8288
8429
  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>';
8289
8430
  list.querySelectorAll(".opt").forEach((btn) => {
8290
8431
  btn.addEventListener("click", () => {
@@ -8330,7 +8471,7 @@ _FxAutocomplete.styles = css`
8330
8471
  font-family: var(--fx-font-family);
8331
8472
  font-size: var(--fx-font-size);
8332
8473
  }
8333
- input {
8474
+ .field {
8334
8475
  font-family: inherit;
8335
8476
  font-size: inherit;
8336
8477
  font-weight: var(--fx-font-weight);
@@ -8346,15 +8487,29 @@ _FxAutocomplete.styles = css`
8346
8487
  border-color var(--fx-motion-duration-normal) var(--fx-motion-easing),
8347
8488
  box-shadow var(--fx-motion-duration-normal) var(--fx-motion-easing);
8348
8489
  }
8349
- input::placeholder { color: var(--fx-text-muted); opacity: 1; }
8350
- input:hover { border-color: var(--fx-border-hover); }
8351
- input:focus-visible {
8490
+ .field::placeholder { color: var(--fx-text-muted); opacity: 1; }
8491
+ .field:hover { border-color: var(--fx-border-hover); }
8492
+ .field:focus-visible {
8352
8493
  outline: none;
8353
8494
  border-color: var(--fx-color-primary);
8354
8495
  box-shadow: var(--fx-effect-focus-ring, none);
8355
8496
  }
8356
- :host([size='sm']) input { width: 220px; min-height: var(--fx-size-sm); padding: var(--fx-space-sm) var(--fx-space-md); }
8357
- :host([size='lg']) input { width: 300px; min-height: var(--fx-size-lg); }
8497
+ :host([size='sm']) .field { width: 220px; min-height: var(--fx-size-sm); padding: var(--fx-space-sm) var(--fx-space-md); }
8498
+ :host([size='lg']) .field { width: 300px; min-height: var(--fx-size-lg); }
8499
+ /* Full width: o host estica até o pai e o campo interno acompanha. */
8500
+ :host([full]) { display: block; width: 100%; }
8501
+ :host([full]) .field { width: 100%; }
8502
+ /* Validação: sobrescrevem a borda/foco via token do preset. */
8503
+ :host([error]) .field,
8504
+ :host([invalid]) .field {
8505
+ border-color: var(--fx-color-danger, #dc2626);
8506
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--fx-color-danger, #dc2626) 18%, transparent);
8507
+ }
8508
+ :host([success]) .field,
8509
+ :host([valid]) .field {
8510
+ border-color: var(--fx-color-success, #16a34a);
8511
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--fx-color-success, #16a34a) 18%, transparent);
8512
+ }
8358
8513
  .list {
8359
8514
  position: absolute;
8360
8515
  top: calc(100% + 4px);
@@ -8461,8 +8616,8 @@ const _FxKnob = class _FxKnob extends FxElement {
8461
8616
  this.setAttribute("step", String(v));
8462
8617
  }
8463
8618
  get size() {
8464
- const s = this.getAttr("size", "md");
8465
- return s === "sm" || s === "lg" ? s : "md";
8619
+ const s2 = this.getAttr("size", "md");
8620
+ return s2 === "sm" || s2 === "lg" ? s2 : "md";
8466
8621
  }
8467
8622
  set size(v) {
8468
8623
  this.setAttribute("size", v);
@@ -8538,9 +8693,9 @@ const _FxKnob = class _FxKnob extends FxElement {
8538
8693
  this.attachListeners();
8539
8694
  }
8540
8695
  getSizeNum() {
8541
- const s = this.size;
8542
- if (s === "sm") return 60;
8543
- if (s === "lg") return 140;
8696
+ const s2 = this.size;
8697
+ if (s2 === "sm") return 60;
8698
+ if (s2 === "lg") return 140;
8544
8699
  return 100;
8545
8700
  }
8546
8701
  /** Valida um valor de cor CSS, retornando-o seguro ou vazio. */
@@ -8802,8 +8957,8 @@ const _FxOrderList = class _FxOrderList extends FxElement {
8802
8957
  this.toggleAttr("striped", v);
8803
8958
  }
8804
8959
  get selectionMode() {
8805
- const s = this.getAttr("selection-mode", "");
8806
- return s === "single" || s === "multiple" ? s : "";
8960
+ const s2 = this.getAttr("selection-mode", "");
8961
+ return s2 === "single" || s2 === "multiple" ? s2 : "";
8807
8962
  }
8808
8963
  set selectionMode(v) {
8809
8964
  this.setAttribute("selection-mode", v);
@@ -8885,7 +9040,7 @@ const _FxOrderList = class _FxOrderList extends FxElement {
8885
9040
  return JSON.stringify(item);
8886
9041
  }
8887
9042
  _isSelected(item) {
8888
- return this._selection.some((s) => this._getItemKey(s, -1) === this._getItemKey(item, -1));
9043
+ return this._selection.some((s2) => this._getItemKey(s2, -1) === this._getItemKey(item, -1));
8889
9044
  }
8890
9045
  _moveItem(fromIndex, toIndex) {
8891
9046
  const actualFrom = this._getActualIndex(fromIndex);
@@ -8921,7 +9076,7 @@ const _FxOrderList = class _FxOrderList extends FxElement {
8921
9076
  }
8922
9077
  _toggleSelection(item) {
8923
9078
  const key2 = this._getItemKey(item, -1);
8924
- const index = this._selection.findIndex((s) => this._getItemKey(s, -1) === key2);
9079
+ const index = this._selection.findIndex((s2) => this._getItemKey(s2, -1) === key2);
8925
9080
  if (index >= 0) {
8926
9081
  this._selection.splice(index, 1);
8927
9082
  } else if (this.selectionMode === "multiple") {
@@ -9195,7 +9350,7 @@ const _FxOrderList = class _FxOrderList extends FxElement {
9195
9350
  _handleMoveAction(action) {
9196
9351
  if (!this._selection.length) return;
9197
9352
  const displayData = this._getDisplayData();
9198
- 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);
9353
+ const selectedIndices = this._selection.map((s2) => displayData.findIndex((d) => this._getItemKey(d, -1) === this._getItemKey(s2, -1))).filter((i) => i >= 0).sort((a, b2) => a - b2);
9199
9354
  if (selectedIndices.length === 0) return;
9200
9355
  switch (action) {
9201
9356
  case "top":
@@ -9220,7 +9375,7 @@ const _FxOrderList = class _FxOrderList extends FxElement {
9220
9375
  items.push(this._data[actualIdx]);
9221
9376
  actualIndices.push(actualIdx);
9222
9377
  }
9223
- actualIndices.sort((a, b) => b - a).forEach((i) => this._data.splice(i, 1));
9378
+ actualIndices.sort((a, b2) => b2 - a).forEach((i) => this._data.splice(i, 1));
9224
9379
  const insertIdx = this._getActualIndex(0);
9225
9380
  this._data.splice(insertIdx, 0, ...items);
9226
9381
  this._applyFilter();
@@ -9236,7 +9391,7 @@ const _FxOrderList = class _FxOrderList extends FxElement {
9236
9391
  items.push(this._data[actualIdx]);
9237
9392
  actualIndices.push(actualIdx);
9238
9393
  }
9239
- actualIndices.sort((a, b) => b - a).forEach((i) => this._data.splice(i, 1));
9394
+ actualIndices.sort((a, b2) => b2 - a).forEach((i) => this._data.splice(i, 1));
9240
9395
  const displayData = this._getDisplayData();
9241
9396
  const insertIdx = this._getActualIndex(displayData.length - 1);
9242
9397
  this._data.splice(insertIdx + 1, 0, ...items);
@@ -9248,7 +9403,7 @@ const _FxOrderList = class _FxOrderList extends FxElement {
9248
9403
  _moveSelectedByOne(indices, delta) {
9249
9404
  const displayData = this._getDisplayData();
9250
9405
  if (displayData.length === 0) return;
9251
- const actualIndices = indices.map((idx) => this._getActualIndex(idx)).filter((idx) => idx >= 0).sort((a, b) => a - b);
9406
+ const actualIndices = indices.map((idx) => this._getActualIndex(idx)).filter((idx) => idx >= 0).sort((a, b2) => a - b2);
9252
9407
  if (actualIndices.length === 0) return;
9253
9408
  if (delta < 0 && actualIndices[0] <= 0) return;
9254
9409
  if (delta > 0 && actualIndices[actualIndices.length - 1] >= this._data.length - 1) return;
@@ -9271,7 +9426,7 @@ const _FxOrderList = class _FxOrderList extends FxElement {
9271
9426
  }
9272
9427
  _updateControlsState() {
9273
9428
  const displayData = this._getDisplayData();
9274
- const selectedIndices = this._selection.map((s) => displayData.findIndex((d) => this._getItemKey(d, -1) === this._getItemKey(s, -1))).filter((i) => i >= 0);
9429
+ const selectedIndices = this._selection.map((s2) => displayData.findIndex((d) => this._getItemKey(d, -1) === this._getItemKey(s2, -1))).filter((i) => i >= 0);
9275
9430
  const buttons = this.root.querySelectorAll(".control-btn");
9276
9431
  buttons.forEach((btn) => {
9277
9432
  const action = btn.dataset.action;
@@ -9477,8 +9632,8 @@ const _FxPickList = class _FxPickList extends FxElement {
9477
9632
  this.toggleAttr("striped", v);
9478
9633
  }
9479
9634
  get selectionMode() {
9480
- const s = this.getAttr("selection-mode", "");
9481
- return s === "single" || s === "multiple" ? s : "";
9635
+ const s2 = this.getAttr("selection-mode", "");
9636
+ return s2 === "single" || s2 === "multiple" ? s2 : "";
9482
9637
  }
9483
9638
  set selectionMode(v) {
9484
9639
  this.setAttribute("selection-mode", v);
@@ -9613,10 +9768,10 @@ const _FxPickList = class _FxPickList extends FxElement {
9613
9768
  return JSON.stringify(item);
9614
9769
  }
9615
9770
  _isSourceSelected(item, index) {
9616
- return this._sourceSelection.some((s) => this._getItemKey(s, -1, true) === this._getItemKey(item, index, true));
9771
+ return this._sourceSelection.some((s2) => this._getItemKey(s2, -1, true) === this._getItemKey(item, index, true));
9617
9772
  }
9618
9773
  _isTargetSelected(item, index) {
9619
- return this._targetSelection.some((s) => this._getItemKey(s, -1, false) === this._getItemKey(item, index, false));
9774
+ return this._targetSelection.some((s2) => this._getItemKey(s2, -1, false) === this._getItemKey(item, index, false));
9620
9775
  }
9621
9776
  _emitMoveToTarget() {
9622
9777
  this.dispatchEvent(new CustomEvent("move-to-target", {
@@ -9759,7 +9914,7 @@ const _FxPickList = class _FxPickList extends FxElement {
9759
9914
  _moveToTarget() {
9760
9915
  if (!this._sourceSelection.length) return;
9761
9916
  const items = [...this._sourceSelection];
9762
- this._source = this._source.filter((s) => !items.some((i) => this._getItemKey(i, -1, true) === this._getItemKey(s, -1, true)));
9917
+ this._source = this._source.filter((s2) => !items.some((i) => this._getItemKey(i, -1, true) === this._getItemKey(s2, -1, true)));
9763
9918
  this._target = [...this._target, ...items];
9764
9919
  this._sourceSelection = [];
9765
9920
  this._filteredSource = null;
@@ -9805,7 +9960,7 @@ const _FxPickList = class _FxPickList extends FxElement {
9805
9960
  _toggleSourceSelection(item, index) {
9806
9961
  const mode = this.selectionMode || "single";
9807
9962
  const key2 = this._getItemKey(item, index, true);
9808
- const idx = this._sourceSelection.findIndex((s) => this._getItemKey(s, -1, true) === key2);
9963
+ const idx = this._sourceSelection.findIndex((s2) => this._getItemKey(s2, -1, true) === key2);
9809
9964
  if (idx >= 0) {
9810
9965
  this._sourceSelection.splice(idx, 1);
9811
9966
  } else if (mode === "multiple") {
@@ -9820,7 +9975,7 @@ const _FxPickList = class _FxPickList extends FxElement {
9820
9975
  _toggleTargetSelection(item, index) {
9821
9976
  const mode = this.selectionMode || "single";
9822
9977
  const key2 = this._getItemKey(item, index, false);
9823
- const idx = this._targetSelection.findIndex((s) => this._getItemKey(s, -1, false) === key2);
9978
+ const idx = this._targetSelection.findIndex((s2) => this._getItemKey(s2, -1, false) === key2);
9824
9979
  if (idx >= 0) {
9825
9980
  this._targetSelection.splice(idx, 1);
9826
9981
  } else if (mode === "multiple") {
@@ -10283,7 +10438,7 @@ const _FxAccordion = class _FxAccordion extends FxElement {
10283
10438
  }
10284
10439
  /** Valores ativos como array. */
10285
10440
  get values() {
10286
- return this.getAttr("value", "").split(",").map((s) => s.trim()).filter(Boolean);
10441
+ return this.getAttr("value", "").split(",").map((s2) => s2.trim()).filter(Boolean);
10287
10442
  }
10288
10443
  set values(v) {
10289
10444
  this.setAttribute("value", v.join(","));
@@ -10464,9 +10619,9 @@ export {
10464
10619
  lightTokens,
10465
10620
  listPresets,
10466
10621
  resetTheme,
10467
- sanitizeData,
10622
+ s as sanitizeData,
10468
10623
  setTokens,
10469
- stripTags,
10624
+ b as stripTags,
10470
10625
  theme,
10471
10626
  themePresets,
10472
10627
  tokenCssVars