@wrrdev/fenix-ui 1.1.17 → 1.3.0

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 (59) hide show
  1. package/README.md +43 -4
  2. package/dist/components/datepicker/datepicker.js +4 -4
  3. package/dist/components/datepicker/datepicker.js.map +1 -1
  4. package/dist/components/editor/editor.js +3 -3
  5. package/dist/components/editor/editor.js.map +1 -1
  6. package/dist/components/floatlabel/floatlabel.d.ts +5 -0
  7. package/dist/components/floatlabel/floatlabel.d.ts.map +1 -1
  8. package/dist/components/floatlabel/floatlabel.js +52 -25
  9. package/dist/components/floatlabel/floatlabel.js.map +1 -1
  10. package/dist/components/input/input.d.ts +11 -0
  11. package/dist/components/input/input.d.ts.map +1 -1
  12. package/dist/components/input/input.js +11 -0
  13. package/dist/components/input/input.js.map +1 -1
  14. package/dist/components/multiselect/multiselect.js +1 -1
  15. package/dist/components/multiselect/multiselect.js.map +1 -1
  16. package/dist/components/orderlist/orderlist.js +1 -1
  17. package/dist/components/orderlist/orderlist.js.map +1 -1
  18. package/dist/components/picklist/picklist.js +1 -1
  19. package/dist/components/picklist/picklist.js.map +1 -1
  20. package/dist/components/select/select.js +1 -1
  21. package/dist/components/select/select.js.map +1 -1
  22. package/dist/components/table/table.d.ts.map +1 -1
  23. package/dist/components/table/table.js +14 -1
  24. package/dist/components/table/table.js.map +1 -1
  25. package/dist/components/textarea/textarea.d.ts +7 -0
  26. package/dist/components/textarea/textarea.d.ts.map +1 -1
  27. package/dist/components/textarea/textarea.js +22 -1
  28. package/dist/components/textarea/textarea.js.map +1 -1
  29. package/dist/core/jsx.d.ts +10 -0
  30. package/dist/core/jsx.d.ts.map +1 -1
  31. package/dist/core/jsx.js.map +1 -1
  32. package/dist/core/tokens.d.ts +2 -0
  33. package/dist/core/tokens.d.ts.map +1 -1
  34. package/dist/core/tokens.js +9 -0
  35. package/dist/core/tokens.js.map +1 -1
  36. package/dist/docs/app.d.ts.map +1 -1
  37. package/dist/docs/componentes/autocomplete.doc.d.ts.map +1 -1
  38. package/dist/docs/componentes/datepicker.doc.d.ts.map +1 -1
  39. package/dist/docs/componentes/editor.doc.d.ts.map +1 -1
  40. package/dist/docs/componentes/floatlabel.doc.d.ts.map +1 -1
  41. package/dist/docs/componentes/input.doc.d.ts.map +1 -1
  42. package/dist/docs/componentes/multiselect.doc.d.ts.map +1 -1
  43. package/dist/docs/componentes/orderlist.doc.d.ts.map +1 -1
  44. package/dist/docs/componentes/picklist.doc.d.ts.map +1 -1
  45. package/dist/docs/componentes/select.doc.d.ts.map +1 -1
  46. package/dist/docs/componentes/table.doc.d.ts.map +1 -1
  47. package/dist/docs/componentes/textarea.doc.d.ts.map +1 -1
  48. package/dist/docs/shared.d.ts +15 -0
  49. package/dist/docs/shared.d.ts.map +1 -1
  50. package/dist/docs/shell.d.ts +10 -1
  51. package/dist/docs/shell.d.ts.map +1 -1
  52. package/dist/docs/theme-reference.d.ts +53 -0
  53. package/dist/docs/theme-reference.d.ts.map +1 -0
  54. package/dist/docs/types.d.ts +2 -0
  55. package/dist/docs/types.d.ts.map +1 -1
  56. package/dist/fenix-ui.umd.min.js +200 -169
  57. package/dist/fenix-ui4.esm.js +119 -38
  58. package/dist/fenix-ui4.esm.js.map +1 -1
  59. package/package.json +1 -1
@@ -44,6 +44,8 @@ export declare class FxFloatlabel extends FxElement {
44
44
  private _labelClickBound;
45
45
  /** Observa o light DOM para readotar uma <label> recriada pelo framework. */
46
46
  private _labelObserver?;
47
+ /** Timer do `focusout`: confirma o estado no próximo tick (foco já movido). */
48
+ private _syncTimer;
47
49
  protected connectedCallback(): void;
48
50
  protected render(): void;
49
51
  protected disconnectedCallback(): void;
@@ -52,6 +54,9 @@ export declare class FxFloatlabel extends FxElement {
52
54
  /** Label = filho direto <label>. */
53
55
  private findLabel;
54
56
  private attachEvents;
57
+ /** Reavalia o estado no próximo tick (o foco já saiu do campo). */
58
+ private scheduleSync;
59
+ private cancelScheduledSync;
55
60
  /** Observa mudanças de atributos do controle (value, open, values...). */
56
61
  private syncControlReference;
57
62
  private syncState;
@@ -1 +1 @@
1
- {"version":3,"file":"floatlabel.d.ts","sourceRoot":"","sources":["../../../src/components/floatlabel/floatlabel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,YAAa,SAAQ,SAAS;IAC1C,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAEjD;IAED,IAAI,KAAK,IAAI,OAAO,CAEnB;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,OAAO,EAEvB;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAEzB;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAEzB;IAED,IAAI,KAAK,IAAI,OAAO,CAEnB;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,OAAO,EAEvB;IAED,IAAI,IAAI,IAAI,OAAO,CAElB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,EAEtB;IAED,IAAI,SAAS,IAAI,MAAM,CAEtB;IACD,IAAI,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAE7C;IAID,OAAgB,MAAM,SAqIpB;IACF,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,cAAc,CAAS;IAC/B,0EAA0E;IAC1E,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,gBAAgB,CAAS;IACjC,6EAA6E;IAC7E,OAAO,CAAC,cAAc,CAAC,CAAmB;cAEvB,iBAAiB,IAAI,IAAI;IAS5C,SAAS,CAAC,MAAM,IAAI,IAAI;cAmDL,oBAAoB,IAAI,IAAI;IAO/C,oEAAoE;IACpE,OAAO,CAAC,WAAW;IAQnB,oCAAoC;IACpC,OAAO,CAAC,SAAS;IAQjB,OAAO,CAAC,YAAY;IAwBpB,0EAA0E;IAC1E,OAAO,CAAC,oBAAoB;IAoB5B,OAAO,CAAC,SAAS;IAwCjB;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,SAAS;IAgBjB,OAAO,CAAC,SAAS;IAmBjB,OAAO,CAAC,UAAU;IA8BlB,OAAO,CAAC,QAAQ;IAQhB,OAAO,CAAC,eAAe;CAIvB;AAED,wBAAgB,kBAAkB,IAAI,OAAO,YAAY,CAExD"}
1
+ {"version":3,"file":"floatlabel.d.ts","sourceRoot":"","sources":["../../../src/components/floatlabel/floatlabel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,YAAa,SAAQ,SAAS;IAC1C,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAEjD;IAED,IAAI,KAAK,IAAI,OAAO,CAEnB;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,OAAO,EAEvB;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAEzB;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAEzB;IAED,IAAI,KAAK,IAAI,OAAO,CAEnB;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,OAAO,EAEvB;IAED,IAAI,IAAI,IAAI,OAAO,CAElB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,EAEtB;IAED,IAAI,SAAS,IAAI,MAAM,CAEtB;IACD,IAAI,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAE7C;IAKD,OAAgB,MAAM,SAmJpB;IACF,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,cAAc,CAAS;IAC/B,0EAA0E;IAC1E,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,gBAAgB,CAAS;IACjC,6EAA6E;IAC7E,OAAO,CAAC,cAAc,CAAC,CAAmB;IAC1C,+EAA+E;IAC/E,OAAO,CAAC,UAAU,CAA4C;cAE3C,iBAAiB,IAAI,IAAI;IAS5C,SAAS,CAAC,MAAM,IAAI,IAAI;cAmDL,oBAAoB,IAAI,IAAI;IAQ/C,oEAAoE;IACpE,OAAO,CAAC,WAAW;IAQnB,oCAAoC;IACpC,OAAO,CAAC,SAAS;IAQjB,OAAO,CAAC,YAAY;IA2BpB,mEAAmE;IACnE,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,mBAAmB;IAO3B,0EAA0E;IAC1E,OAAO,CAAC,oBAAoB;IAoB5B,OAAO,CAAC,SAAS;IA4CjB;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,SAAS;IAgBjB,OAAO,CAAC,SAAS;IAmBjB,OAAO,CAAC,UAAU;IA8BlB,OAAO,CAAC,QAAQ;IAQhB,OAAO,CAAC,eAAe;CAIvB;AAED,wBAAgB,kBAAkB,IAAI,OAAO,YAAY,CAExD"}
@@ -98,6 +98,7 @@ const _FxFloatlabel = class _FxFloatlabel extends FxElement {
98
98
  }
99
99
  disconnectedCallback() {
100
100
  super.disconnectedCallback();
101
+ this.cancelScheduledSync();
101
102
  this.observer?.disconnect();
102
103
  this._labelObserver?.disconnect();
103
104
  this._labelObserver = void 0;
@@ -127,14 +128,28 @@ const _FxFloatlabel = class _FxFloatlabel extends FxElement {
127
128
  }
128
129
  if (this.listenersReady) return;
129
130
  this.listenersReady = true;
130
- this.addEventListener("focusin", () => this.syncState());
131
- this.addEventListener(
132
- "focusout",
133
- () => setTimeout(() => this.syncState(), 60)
134
- );
131
+ this.addEventListener("focusin", () => {
132
+ this.cancelScheduledSync();
133
+ this.syncState();
134
+ });
135
+ this.addEventListener("focusout", () => this.scheduleSync());
135
136
  this.addEventListener("input", () => this.syncState());
136
137
  this.addEventListener("change", () => this.syncState());
137
138
  }
139
+ /** Reavalia o estado no próximo tick (o foco já saiu do campo). */
140
+ scheduleSync() {
141
+ this.cancelScheduledSync();
142
+ this._syncTimer = setTimeout(() => {
143
+ this._syncTimer = void 0;
144
+ this.syncState();
145
+ }, 0);
146
+ }
147
+ cancelScheduledSync() {
148
+ if (this._syncTimer !== void 0) {
149
+ clearTimeout(this._syncTimer);
150
+ this._syncTimer = void 0;
151
+ }
152
+ }
138
153
  /** Observa mudanças de atributos do controle (value, open, values...). */
139
154
  syncControlReference(control = this.targetControl) {
140
155
  if (control !== this.targetControl) {
@@ -167,18 +182,16 @@ const _FxFloatlabel = class _FxFloatlabel extends FxElement {
167
182
  const c = this.targetControl;
168
183
  const attrValue = c.getAttribute ? (c.getAttribute("value") ?? "").trim() : "";
169
184
  const attrValues = c.getAttribute ? (c.getAttribute("values") ?? "").trim() : "";
185
+ const isOpen = Boolean(c.hasAttribute?.("open"));
170
186
  const hasValue = Boolean(
171
- typeof c.value === "string" && c.value.trim() !== "" || Array.isArray(c.values) && c.values.length > 0 || attrValue !== "" || attrValues !== "" || c.hasAttribute && (c.hasAttribute("open") || c.hasAttribute("start"))
187
+ typeof c.value === "string" && c.value.trim() !== "" || Array.isArray(c.values) && c.values.length > 0 || attrValue !== "" || attrValues !== "" || c.hasAttribute && c.hasAttribute("start")
172
188
  );
173
189
  const focused = this.isFocusedInside();
174
- if (hasValue || focused) {
175
- this.setAttribute("active", "");
176
- if (focused) this.setAttribute("focus", "");
177
- else this.removeAttribute("focus");
178
- } else {
179
- this.removeAttribute("active");
180
- this.removeAttribute("focus");
181
- }
190
+ const highlighted = focused || isOpen;
191
+ if (hasValue || highlighted) this.setAttribute("active", "");
192
+ else this.removeAttribute("active");
193
+ if (highlighted) this.setAttribute("focus", "");
194
+ else this.removeAttribute("focus");
182
195
  }
183
196
  /**
184
197
  * variant="in" + ícone à esquerda dentro do campo (fx-input icon):
@@ -256,6 +269,10 @@ _FxFloatlabel.styles = css`
256
269
  font-family: var(--fx-font-family);
257
270
  font-size: var(--fx-font-size);
258
271
  vertical-align: middle;
272
+ /* Cor da label em UM único lugar. active (valor OU foco OU
273
+ dropdown) só posiciona; focus (foco OU dropdown) só destaca —
274
+ assim a label acompanha a borda, que só fica primária em foco. */
275
+ --_flabel-color: var(--fx-text-muted, #94a3b8);
259
276
  }
260
277
  /* Full width: o host estica até o pai; o controle interno com
261
278
  atributo full (ou largura herdada) acompanha. */
@@ -287,7 +304,7 @@ _FxFloatlabel.styles = css`
287
304
  transform: translateY(-50%);
288
305
  font-size: calc(var(--fx-font-size, 14px) - 3px);
289
306
  font-weight: 600;
290
- color: var(--fx-text-muted, #94a3b8);
307
+ color: var(--_flabel-color);
291
308
  background-color: var(--fx-surface-background, #fff);
292
309
  padding: 0 4px;
293
310
  line-height: 1;
@@ -305,8 +322,11 @@ _FxFloatlabel.styles = css`
305
322
  color var(--fx-motion-duration-normal, 180ms)
306
323
  var(--fx-motion-easing, ease-in-out);
307
324
  }
308
- :host([active]) .flabel {
309
- color: var(--fx-color-primary, #4f46e5);
325
+ /* Destacada = foco (ou dropdown aberto). NÃO usar [active]: ele
326
+ também é verdadeiro com valor e sem foco — era o que deixava a
327
+ label primária com a borda neutra. */
328
+ :host([focus]) {
329
+ --_flabel-color: var(--fx-color-primary, #4f46e5);
310
330
  }
311
331
 
312
332
  /* ---- variant="in": label como placeholder dentro, sobe ao focar/valor ---- */
@@ -325,7 +345,8 @@ _FxFloatlabel.styles = css`
325
345
  font-weight: 600;
326
346
  background-color: var(--fx-surface-background, #fff);
327
347
  padding: 0 5px;
328
- color: var(--fx-color-primary, #4f46e5);
348
+ /* Sem color aqui: a especificidade desta regra
349
+ (variant + active) venceria :host([error])/:host([focus]). */
329
350
  }
330
351
 
331
352
  /* ---- variant="in" com ícone dentro do campo (fx-input icon):
@@ -356,16 +377,22 @@ _FxFloatlabel.styles = css`
356
377
  font-size: calc(var(--fx-font-size, 14px) - 3px);
357
378
  font-weight: 600;
358
379
  white-space: normal;
380
+ /* Fora do campo, a label pode receber clique: o listener do
381
+ render() foca o controle (nas variantes on/in o
382
+ pointer-events: none é intencional, para não bloquear a borda). */
383
+ pointer-events: auto;
359
384
  }
360
385
 
361
- /* ---- estados de erro / sucesso ---- */
362
- :host([error]) .flabel,
363
- :host([invalid]) .flabel {
364
- color: var(--fx-color-danger, #dc2626);
386
+ /* ---- estados de erro / sucesso ----
387
+ Declarados DEPOIS de :host([focus]) e com a mesma especificidade:
388
+ a validação vence o foco pela ordem, sem depender de acidente. */
389
+ :host([error]),
390
+ :host([invalid]) {
391
+ --_flabel-color: var(--fx-color-danger, #dc2626);
365
392
  }
366
- :host([success]) .flabel,
367
- :host([valid]) .flabel {
368
- color: var(--fx-color-success, #10b981);
393
+ :host([success]),
394
+ :host([valid]) {
395
+ --_flabel-color: var(--fx-color-success, #10b981);
369
396
  }
370
397
 
371
398
  /* ---- mensagem de erro sob o campo (fonte menor) ---- */
@@ -1 +1 @@
1
- {"version":3,"file":"floatlabel.js","sources":["../../../src/components/floatlabel/floatlabel.ts"],"sourcesContent":["import { FxElement } from \"../../core/base\";\nimport { css } from \"../../core/css\";\nimport { defineElement } from \"../../core/define\";\n\n/**\n * Rótulo flutuante .\n *\n * Envolve um campo de formulário (fx-input, fx-select, fx-multiselect,\n * fx-datepicker, ...) + um <label>. A label se comporta como placeholder\n * quando o campo está vazio e \"sobe\" quando o campo é focado, contém valor\n * ou abre dropdown.\n *\n * - variant=\"on\" (padrão): label sobre a borda superior\n * - variant=\"in\" : label como placeholder interno, sobe ao focar/valor\n * - variant=\"over\" : label estática acima do campo\n *\n * - error / invalid: label + borda em vermelho, mensagem menor abaixo.\n * - success / valid: label + borda em verde.\n *\n * A <label> do light DOM é MOVIDA para dentro do Shadow DOM (como `.flabel`)\n * na primeira renderização — a partir daí NÃO existe cópia no light DOM.\n * Ocultá-la com `hidden` (solução anterior) era frágil: o consumidor, o\n * framework ou uma folha de estilo podiam remover o atributo e a label\n * original reaparecia embaixo do campo, quebrando o floatlabel. Mover o\n * elemento é estrutural: não há nada removível lá fora.\n */\nexport class FxFloatlabel extends FxElement {\n\tstatic override get observedAttributes(): string[] {\n\t\treturn [\"variant\", \"error\", \"invalid\", \"success\", \"valid\", \"full\", \"icon\", \"icon-pos\", \"error-text\"];\n\t}\n\n\tget error(): boolean {\n\t\treturn this.hasAttr(\"error\");\n\t}\n\tset error(value: boolean) {\n\t\tthis.toggleAttr(\"error\", Boolean(value));\n\t}\n\n\tget invalid(): boolean {\n\t\treturn this.hasAttr(\"invalid\");\n\t}\n\tset invalid(value: boolean) {\n\t\tthis.toggleAttr(\"invalid\", Boolean(value));\n\t}\n\n\tget success(): boolean {\n\t\treturn this.hasAttr(\"success\");\n\t}\n\tset success(value: boolean) {\n\t\tthis.toggleAttr(\"success\", Boolean(value));\n\t}\n\n\tget valid(): boolean {\n\t\treturn this.hasAttr(\"valid\");\n\t}\n\tset valid(value: boolean) {\n\t\tthis.toggleAttr(\"valid\", Boolean(value));\n\t}\n\n\tget full(): boolean {\n\t\treturn this.hasAttr(\"full\");\n\t}\n\tset full(value: boolean) {\n\t\tthis.toggleAttr(\"full\", Boolean(value));\n\t}\n\n\tget errorText(): string {\n\t\treturn this.getAttr(\"error-text\");\n\t}\n\tset errorText(value: string | null | undefined) {\n\t\tthis.setAttribute(\"error-text\", value == null ? \"\" : String(value));\n\t}\n\t// 'active' NÃO entra em observedAttributes: togglá-lo apenas atualiza CSS\n\t// via :host([active]), sem re-render destrutivo (mantém o foco do campo).\n\n\tstatic override styles = css`\n\t\t:host {\n\t\t\tdisplay: inline-block;\n\t\t\tposition: relative;\n\t\t\tfont-family: var(--fx-font-family);\n\t\t\tfont-size: var(--fx-font-size);\n\t\t\tvertical-align: middle;\n\t\t}\n\t\t/* Full width: o host estica até o pai; o controle interno com\n\t\t atributo full (ou largura herdada) acompanha. */\n\t\t:host([full]) {\n\t\t\tdisplay: block;\n\t\t\twidth: 100%;\n\t\t}\n\t\t.wrapper {\n\t\t\tposition: relative;\n\t\t\tdisplay: inline-block;\n\t\t\twidth: 100%;\n\t\t}\n\t\t/* Caixa do campo: referência de posicionamento da label flutuante\n (isolada da mensagem de erro, que cresce o wrapper). */\n\t\t.field-box {\n\t\t\tposition: relative;\n\t\t\tdisplay: inline-block;\n\t\t\twidth: 100%;\n\t\t}\n\t\t:host([variant=\"in\"]) .field-box {\n\t\t\tpadding-top: var(--fx-space-xs, 6px);\n\t\t}\n\n\t\t/* ---- label base (variant=\"on\", padrão): sobre a borda superior ---- */\n\t\t.flabel {\n\t\t\tposition: absolute;\n\t\t\tleft: var(--fx-space-md, 12px);\n\t\t\ttop: 0;\n\t\t\ttransform: translateY(-50%);\n\t\t\tfont-size: calc(var(--fx-font-size, 14px) - 3px);\n\t\t\tfont-weight: 600;\n\t\t\tcolor: var(--fx-text-muted, #94a3b8);\n\t\t\tbackground-color: var(--fx-surface-background, #fff);\n\t\t\tpadding: 0 4px;\n\t\t\tline-height: 1;\n\t\t\tborder-radius: 2px;\n\t\t\tpointer-events: none;\n\t\t\tz-index: 2;\n\t\t\twhite-space: nowrap;\n\t\t\ttransition:\n\t\t\t\ttop var(--fx-motion-duration-normal, 180ms)\n\t\t\t\t\tvar(--fx-motion-easing, ease-in-out),\n\t\t\t\ttransform var(--fx-motion-duration-normal, 180ms)\n\t\t\t\t\tvar(--fx-motion-easing, ease-in-out),\n\t\t\t\tfont-size var(--fx-motion-duration-normal, 180ms)\n\t\t\t\t\tvar(--fx-motion-easing, ease-in-out),\n\t\t\t\tcolor var(--fx-motion-duration-normal, 180ms)\n\t\t\t\t\tvar(--fx-motion-easing, ease-in-out);\n\t\t}\n\t\t:host([active]) .flabel {\n\t\t\tcolor: var(--fx-color-primary, #4f46e5);\n\t\t}\n\n\t\t/* ---- variant=\"in\": label como placeholder dentro, sobe ao focar/valor ---- */\n\t\t:host([variant=\"in\"]) .flabel {\n\t\t\ttop: 50%;\n\t\t\ttransform: translateY(-50%);\n\t\t\tfont-size: var(--fx-font-size, 14px);\n\t\t\tfont-weight: var(--fx-font-weight, 400);\n\t\t\tbackground: transparent;\n\t\t\tpadding: 0;\n\t\t}\n\t\t:host([variant=\"in\"][active]) .flabel {\n\t\t\ttop: 0;\n\t\t\ttransform: translateY(-50%);\n\t\t\tfont-size: calc(var(--fx-font-size, 14px) - 3px);\n\t\t\tfont-weight: 600;\n\t\t\tbackground-color: var(--fx-surface-background, #fff);\n\t\t\tpadding: 0 5px;\n\t\t\tcolor: var(--fx-color-primary, #4f46e5);\n\t\t}\n\n\t\t/* ---- variant=\"in\" com ícone dentro do campo (fx-input icon):\n\t\t enquanto a label funciona como placeholder (sem foco/valor), ela\n\t\t começa DEPOIS do glifo (mesma métrica de padding do fx-input).\n\t\t Ao subir (active), volta ao offset padrão da borda. ---- */\n\t\t:host([variant=\"in\"]) .flabel.icon-indent {\n\t\t\tleft: calc(\n\t\t\t\tvar(--fx-space-md, 12px) +\n\t\t\t\tvar(--fx-input-icon-size, calc(var(--fx-font-size, 14px) + 6px)) +\n\t\t\t\tvar(--fx-space-sm, 8px)\n\t\t\t);\n\t\t}\n\t\t:host([variant=\"in\"][active]) .flabel.icon-indent {\n\t\t\tleft: var(--fx-space-md, 12px);\n\t\t}\n\n\t\t/* ---- variant=\"over\": label estática ACIMA do campo (fora, em fluxo) ---- */\n\t\t:host([variant=\"over\"]) {\n\t\t\tdisplay: block;\n\t\t}\n\t\t:host([variant=\"over\"]) .flabel {\n\t\t\tposition: static;\n\t\t\tdisplay: block;\n\t\t\tmargin-bottom: var(--fx-space-xs, 4px);\n\t\t\tbackground: transparent;\n\t\t\tpadding: 0;\n\t\t\tfont-size: calc(var(--fx-font-size, 14px) - 3px);\n\t\t\tfont-weight: 600;\n\t\t\twhite-space: normal;\n\t\t}\n\n\t\t/* ---- estados de erro / sucesso ---- */\n\t\t:host([error]) .flabel,\n\t\t:host([invalid]) .flabel {\n\t\t\tcolor: var(--fx-color-danger, #dc2626);\n\t\t}\n\t\t:host([success]) .flabel,\n\t\t:host([valid]) .flabel {\n\t\t\tcolor: var(--fx-color-success, #10b981);\n\t\t}\n\n\t\t/* ---- mensagem de erro sob o campo (fonte menor) ---- */\n\t\t.error-message {\n\t\t\tdisplay: none;\n\t\t\tmargin-top: var(--fx-space-xs, 4px);\n\t\t\tmargin-left: var(--fx-space-md, 12px);\n\t\t\tfont-size: calc(var(--fx-font-size, 14px) - 3px);\n\t\t\tfont-weight: 500;\n\t\t\tcolor: var(--fx-color-danger, #dc2626);\n\t\t\tline-height: 1.2;\n\t\t}\n\t\t:host([error]) .error-message,\n\t\t:host([invalid]) .error-message {\n\t\t\tdisplay: block;\n\t\t}\n\t`;\n\tprivate targetControl: HTMLElement | null = null;\n\tprivate observer: MutationObserver | null = null;\n\tprivate listenersReady = false;\n\t/** <label> adotada do light DOM — vive no Shadow DOM após o 1º render. */\n\tprivate _label: HTMLElement | null = null;\n\tprivate _labelClickBound = false;\n\t/** Observa o light DOM para readotar uma <label> recriada pelo framework. */\n\tprivate _labelObserver?: MutationObserver;\n\n\tprotected override connectedCallback(): void {\n\t\tsuper.connectedCallback();\n\t\tthis._labelObserver = new MutationObserver(() => {\n\t\t\tconst label = this.findLabel();\n\t\t\tif (label && label !== this._label) this.render();\n\t\t});\n\t\tthis._labelObserver.observe(this, { childList: true });\n\t}\n\n\tprotected render(): void {\n\t\tconst control = this.findControl();\n\t\t// Adota a <label> do light DOM (na 1ª renderização, ou se o consumidor\n\t\t// trocar por outra depois). Uma vez movida, o render seguinte não a\n\t\t// encontra no light DOM — a referência `_label` é reutilizada.\n\t\tconst lightLabel = this.findLabel();\n\t\tif (lightLabel) this._label = lightLabel;\n\t\tconst label = this._label;\n\t\tconst isOver = this.getAttribute(\"variant\") === \"over\";\n\n\t\tthis.setTemplate(`\n <div class=\"wrapper\" part=\"wrapper\">\n <div class=\"field-box\" part=\"field\">\n <slot></slot>\n </div>\n <div class=\"error-message\" part=\"error\"></div>\n </div>\n `);\n\n\t\t// A label original é INSERIDA no Shadow DOM (move o próprio elemento —\n\t\t// não é uma cópia). `setTemplate` reconstrói o template a cada render e\n\t\t// a label desanexada é reinserida no novo wrapper, com estado intacto.\n\t\tif (label) {\n\t\t\tlabel.classList.add(\"flabel\");\n\t\t\tlabel.setAttribute(\"part\", \"label\");\n\t\t\tconst wrapper = this.root.querySelector(\".wrapper\");\n\t\t\tconst fieldBox = this.root.querySelector(\".field-box\");\n\t\t\tif (wrapper && fieldBox) {\n\t\t\t\tif (isOver) wrapper.insertBefore(label, fieldBox);\n\t\t\t\telse fieldBox.appendChild(label);\n\t\t\t}\n\t\t\t// `for` não cruza a fronteira do shadow (o id do controle vive no\n\t\t\t// light DOM): o clique na label foca o campo manualmente.\n\t\t\tif (!this._labelClickBound) {\n\t\t\t\tthis._labelClickBound = true;\n\t\t\t\tlabel.addEventListener(\"click\", (e) => {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\t(this.targetControl as HTMLElement | null)?.focus?.();\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tthis.attachEvents();\n\t\tthis.syncControlReference(control);\n\t\tthis.syncState();\n\t\tthis.applyError();\n\t\tthis.applyFull();\n\t\tthis.applyIcon();\n\t\tthis.syncIconIndent();\n\t}\n\n\tprotected override disconnectedCallback(): void {\n\t\tsuper.disconnectedCallback();\n\t\tthis.observer?.disconnect();\n\t\tthis._labelObserver?.disconnect();\n\t\tthis._labelObserver = undefined;\n\t}\n\n\t/** Campo de controle = qualquer filho direto que não seja label. */\n\tprivate findControl(): HTMLElement | null {\n\t\treturn (\n\t\t\t(Array.from(this.children).find(\n\t\t\t\t(n) => n.tagName.toLowerCase() !== \"label\",\n\t\t\t) as HTMLElement) ?? null\n\t\t);\n\t}\n\n\t/** Label = filho direto <label>. */\n\tprivate findLabel(): HTMLElement | null {\n\t\treturn (\n\t\t\t(Array.from(this.children).find(\n\t\t\t\t(n) => n.tagName.toLowerCase() === \"label\",\n\t\t\t) as HTMLElement) ?? null\n\t\t);\n\t}\n\n\tprivate attachEvents(): void {\n\t\tconst slot = this.root.querySelector(\"slot\");\n\t\tif (slot) {\n\t\t\tslot.addEventListener(\"slotchange\", () => {\n\t\t\t\t// Se o usuário trocar o controle/label em tempo de execução, re-sincroniza.\n\t\t\t\tconst control = this.findControl();\n\t\t\t\tthis.syncControlReference(control);\n\t\t\t\tthis.syncState();\n\t\t\t\tthis.applyError();\n\t\t\t\tthis.applyFull();\n\t\t\t});\n\t\t}\n\n\t\tif (this.listenersReady) return;\n\t\tthis.listenersReady = true;\n\n\t\tthis.addEventListener(\"focusin\", () => this.syncState());\n\t\tthis.addEventListener(\"focusout\", () =>\n\t\t\tsetTimeout(() => this.syncState(), 60),\n\t\t);\n\t\tthis.addEventListener(\"input\", () => this.syncState());\n\t\tthis.addEventListener(\"change\", () => this.syncState());\n\t}\n\n\t/** Observa mudanças de atributos do controle (value, open, values...). */\n\tprivate syncControlReference(\n\t\tcontrol: HTMLElement | null = this.targetControl,\n\t): void {\n\t\tif (control !== this.targetControl) {\n\t\t\tthis.observer?.disconnect();\n\t\t\tthis.observer = null;\n\t\t\tthis.targetControl = control;\n\t\t\tif (control) {\n\t\t\t\tthis.observer = new MutationObserver(() => {\n\t\t\t\t\tthis.syncState();\n\t\t\t\t\tthis.syncIconIndent();\n\t\t\t\t});\n\t\t\t\tthis.observer.observe(control, {\n\t\t\t\t\tattributes: true,\n\t\t\t\t\tattributeFilter: [\"value\", \"values\", \"start\", \"end\", \"open\", \"icon\", \"icon-pos\"],\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate syncState(): void {\n\t\tif (this.targetControl && !this.targetControl.isConnected) {\n\t\t\tthis.targetControl = null;\n\t\t\tthis.observer?.disconnect();\n\t\t\tthis.observer = null;\n\t\t}\n\n\t\tif (!this.targetControl) {\n\t\t\tthis.removeAttribute(\"active\");\n\t\t\tthis.removeAttribute(\"focus\");\n\t\t\treturn;\n\t\t}\n\n\t\tconst c = this.targetControl as any;\n\t\tconst attrValue = c.getAttribute\n\t\t\t? (c.getAttribute(\"value\") ?? \"\").trim()\n\t\t\t: \"\";\n\t\tconst attrValues = c.getAttribute\n\t\t\t? (c.getAttribute(\"values\") ?? \"\").trim()\n\t\t\t: \"\";\n\t\tconst hasValue = Boolean(\n\t\t\t(typeof c.value === \"string\" && c.value.trim() !== \"\") ||\n\t\t\t(Array.isArray(c.values) && c.values.length > 0) ||\n\t\t\tattrValue !== \"\" ||\n\t\t\tattrValues !== \"\" ||\n\t\t\t(c.hasAttribute &&\n\t\t\t\t(c.hasAttribute(\"open\") || c.hasAttribute(\"start\"))),\n\t\t);\n\n\t\tconst focused = this.isFocusedInside();\n\t\tif (hasValue || focused) {\n\t\t\tthis.setAttribute(\"active\", \"\");\n\t\t\tif (focused) this.setAttribute(\"focus\", \"\");\n\t\t\telse this.removeAttribute(\"focus\");\n\t\t} else {\n\t\t\tthis.removeAttribute(\"active\");\n\t\t\tthis.removeAttribute(\"focus\");\n\t\t}\n\t}\n\n\t/**\n\t * variant=\"in\" + ícone à esquerda dentro do campo (fx-input icon):\n\t * enquanto a label é placeholder ela precisa começar depois do glifo.\n\t * Detecta via atributos icon/icon-pos (ou slot icon) do controle.\n\t */\n\tprivate syncIconIndent(): void {\n\t\tconst label = this.root.querySelector(\".flabel\");\n\t\tif (!label) return;\n\t\tconst c = this.targetControl;\n\t\tconst hasLeftIcon = Boolean(\n\t\t\tc &&\n\t\t\t(c.hasAttribute(\"icon\") || c.querySelector(':scope > [slot=\"icon\"]')) &&\n\t\t\tc.getAttribute(\"icon-pos\") !== \"right\",\n\t\t);\n\t\tlabel.classList.toggle(\"icon-indent\", hasLeftIcon);\n\t}\n\n\tprivate applyFull(): void {\n\t\t// Espelha o full no controle interno: o CSS :host([full]) do floatlabel\n\t\t// estica apenas o HOST — sem isso o campo interno (ex.: fx-input com\n\t\t// width 260px fixa) não acompanharia o container.\n\t\tif (\n\t\t\tthis.targetControl &&\n\t\t\ttypeof this.targetControl.setAttribute === \"function\"\n\t\t) {\n\t\t\tif (this.hasAttr(\"full\")) {\n\t\t\t\tthis.targetControl.setAttribute(\"full\", \"\");\n\t\t\t} else {\n\t\t\t\tthis.targetControl.removeAttribute(\"full\");\n\t\t\t}\n\t\t\t}\n\t}\n\n\tprivate applyIcon(): void {\n\t\tif (\n\t\t\tthis.targetControl &&\n\t\t\ttypeof this.targetControl.setAttribute === \"function\"\n\t\t) {\n\t\t\t// Só propaga icon/icon-pos se o FLOATLABEL possuir o atributo.\n\t\t\t// Se o ícone foi pondo diretamente no controle (ex.: <fx-input icon=\"lock\">),\n\t\t\t// não remove — deixa o controle manter o seu próprio ícone.\n\t\t\tif (this.hasAttr(\"icon\")) {\n\t\t\t\tconst icon = this.getAttr(\"icon\");\n\t\t\t\tconst iconPos = this.getAttr(\"icon-pos\");\n\t\t\t\tif (icon !== \"\") this.targetControl.setAttribute(\"icon\", icon);\n\t\t\t\telse this.targetControl.setAttribute(\"icon\", \"\");\n\t\t\t\tif (iconPos && iconPos !== \"left\") this.targetControl.setAttribute(\"icon-pos\", iconPos);\n\t\t\t\telse this.targetControl.removeAttribute(\"icon-pos\");\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate applyError(): void {\n\t\tconst hasError = this.hasAttr(\"error\") || this.hasAttr(\"invalid\");\n\t\tconst errMsg = this.root.querySelector(\n\t\t\t\".error-message\",\n\t\t) as HTMLElement | null;\n\t\tif (errMsg) {\n\t\t\terrMsg.textContent = hasError\n\t\t\t\t? this.getAttribute(\"error-text\")?.trim() || \"Valor inválido\"\n\t\t\t\t: \"\";\n\t\t}\n\n\t\t// Espelha o estado no controle interno para que a borda também fique vermelha/verde.\n\t\tif (\n\t\t\tthis.targetControl &&\n\t\t\ttypeof this.targetControl.setAttribute === \"function\"\n\t\t) {\n\t\t\tconst t = this.targetControl;\n\t\t\tif (hasError) {\n\t\t\t\tt.setAttribute(\"error\", \"\");\n\t\t\t\tt.removeAttribute(\"success\");\n\t\t\t} else if (this.hasAttr(\"success\") || this.hasAttr(\"valid\")) {\n\t\t\t\tt.setAttribute(\"success\", \"\");\n\t\t\t\tt.removeAttribute(\"error\");\n\t\t\t} else {\n\t\t\t\tt.removeAttribute(\"error\");\n\t\t\t\tt.removeAttribute(\"success\");\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate isWithin(activeEl: Element): boolean {\n\t\tlet current: Element | null = activeEl;\n\t\twhile (current && current !== this) {\n\t\t\tcurrent = current.parentElement;\n\t\t}\n\t\treturn current === this;\n\t}\n\n\tprivate isFocusedInside(): boolean {\n\t\tconst activeEl = (document as Document).activeElement;\n\t\treturn Boolean(activeEl && this.isWithin(activeEl));\n\t}\n}\n\nexport function defineFxFloatlabel(): typeof FxFloatlabel {\n\treturn defineElement(\"fx-floatlabel\", FxFloatlabel);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"floatlabel.js","sources":["../../../src/components/floatlabel/floatlabel.ts"],"sourcesContent":["import { FxElement } from \"../../core/base\";\nimport { css } from \"../../core/css\";\nimport { defineElement } from \"../../core/define\";\n\n/**\n * Rótulo flutuante .\n *\n * Envolve um campo de formulário (fx-input, fx-select, fx-multiselect,\n * fx-datepicker, ...) + um <label>. A label se comporta como placeholder\n * quando o campo está vazio e \"sobe\" quando o campo é focado, contém valor\n * ou abre dropdown.\n *\n * - variant=\"on\" (padrão): label sobre a borda superior\n * - variant=\"in\" : label como placeholder interno, sobe ao focar/valor\n * - variant=\"over\" : label estática acima do campo\n *\n * - error / invalid: label + borda em vermelho, mensagem menor abaixo.\n * - success / valid: label + borda em verde.\n *\n * A <label> do light DOM é MOVIDA para dentro do Shadow DOM (como `.flabel`)\n * na primeira renderização — a partir daí NÃO existe cópia no light DOM.\n * Ocultá-la com `hidden` (solução anterior) era frágil: o consumidor, o\n * framework ou uma folha de estilo podiam remover o atributo e a label\n * original reaparecia embaixo do campo, quebrando o floatlabel. Mover o\n * elemento é estrutural: não há nada removível lá fora.\n */\nexport class FxFloatlabel extends FxElement {\n\tstatic override get observedAttributes(): string[] {\n\t\treturn [\"variant\", \"error\", \"invalid\", \"success\", \"valid\", \"full\", \"icon\", \"icon-pos\", \"error-text\"];\n\t}\n\n\tget error(): boolean {\n\t\treturn this.hasAttr(\"error\");\n\t}\n\tset error(value: boolean) {\n\t\tthis.toggleAttr(\"error\", Boolean(value));\n\t}\n\n\tget invalid(): boolean {\n\t\treturn this.hasAttr(\"invalid\");\n\t}\n\tset invalid(value: boolean) {\n\t\tthis.toggleAttr(\"invalid\", Boolean(value));\n\t}\n\n\tget success(): boolean {\n\t\treturn this.hasAttr(\"success\");\n\t}\n\tset success(value: boolean) {\n\t\tthis.toggleAttr(\"success\", Boolean(value));\n\t}\n\n\tget valid(): boolean {\n\t\treturn this.hasAttr(\"valid\");\n\t}\n\tset valid(value: boolean) {\n\t\tthis.toggleAttr(\"valid\", Boolean(value));\n\t}\n\n\tget full(): boolean {\n\t\treturn this.hasAttr(\"full\");\n\t}\n\tset full(value: boolean) {\n\t\tthis.toggleAttr(\"full\", Boolean(value));\n\t}\n\n\tget errorText(): string {\n\t\treturn this.getAttr(\"error-text\");\n\t}\n\tset errorText(value: string | null | undefined) {\n\t\tthis.setAttribute(\"error-text\", value == null ? \"\" : String(value));\n\t}\n\t// 'active' e 'focus' NÃO entram em observedAttributes: togglá-los apenas\n\t// atualiza CSS via :host([...]), sem re-render destrutivo (mantém o foco\n\t// do campo). 'active' levanta a label; 'focus' é o que a destaca.\n\n\tstatic override styles = css`\n\t\t:host {\n\t\t\tdisplay: inline-block;\n\t\t\tposition: relative;\n\t\t\tfont-family: var(--fx-font-family);\n\t\t\tfont-size: var(--fx-font-size);\n\t\t\tvertical-align: middle;\n\t\t\t/* Cor da label em UM único lugar. active (valor OU foco OU\n\t\t\t dropdown) só posiciona; focus (foco OU dropdown) só destaca —\n\t\t\t assim a label acompanha a borda, que só fica primária em foco. */\n\t\t\t--_flabel-color: var(--fx-text-muted, #94a3b8);\n\t\t}\n\t\t/* Full width: o host estica até o pai; o controle interno com\n\t\t atributo full (ou largura herdada) acompanha. */\n\t\t:host([full]) {\n\t\t\tdisplay: block;\n\t\t\twidth: 100%;\n\t\t}\n\t\t.wrapper {\n\t\t\tposition: relative;\n\t\t\tdisplay: inline-block;\n\t\t\twidth: 100%;\n\t\t}\n\t\t/* Caixa do campo: referência de posicionamento da label flutuante\n (isolada da mensagem de erro, que cresce o wrapper). */\n\t\t.field-box {\n\t\t\tposition: relative;\n\t\t\tdisplay: inline-block;\n\t\t\twidth: 100%;\n\t\t}\n\t\t:host([variant=\"in\"]) .field-box {\n\t\t\tpadding-top: var(--fx-space-xs, 6px);\n\t\t}\n\n\t\t/* ---- label base (variant=\"on\", padrão): sobre a borda superior ---- */\n\t\t.flabel {\n\t\t\tposition: absolute;\n\t\t\tleft: var(--fx-space-md, 12px);\n\t\t\ttop: 0;\n\t\t\ttransform: translateY(-50%);\n\t\t\tfont-size: calc(var(--fx-font-size, 14px) - 3px);\n\t\t\tfont-weight: 600;\n\t\t\tcolor: var(--_flabel-color);\n\t\t\tbackground-color: var(--fx-surface-background, #fff);\n\t\t\tpadding: 0 4px;\n\t\t\tline-height: 1;\n\t\t\tborder-radius: 2px;\n\t\t\tpointer-events: none;\n\t\t\tz-index: 2;\n\t\t\twhite-space: nowrap;\n\t\t\ttransition:\n\t\t\t\ttop var(--fx-motion-duration-normal, 180ms)\n\t\t\t\t\tvar(--fx-motion-easing, ease-in-out),\n\t\t\t\ttransform var(--fx-motion-duration-normal, 180ms)\n\t\t\t\t\tvar(--fx-motion-easing, ease-in-out),\n\t\t\t\tfont-size var(--fx-motion-duration-normal, 180ms)\n\t\t\t\t\tvar(--fx-motion-easing, ease-in-out),\n\t\t\t\tcolor var(--fx-motion-duration-normal, 180ms)\n\t\t\t\t\tvar(--fx-motion-easing, ease-in-out);\n\t\t}\n\t\t/* Destacada = foco (ou dropdown aberto). NÃO usar [active]: ele\n\t\t também é verdadeiro com valor e sem foco — era o que deixava a\n\t\t label primária com a borda neutra. */\n\t\t:host([focus]) {\n\t\t\t--_flabel-color: var(--fx-color-primary, #4f46e5);\n\t\t}\n\n\t\t/* ---- variant=\"in\": label como placeholder dentro, sobe ao focar/valor ---- */\n\t\t:host([variant=\"in\"]) .flabel {\n\t\t\ttop: 50%;\n\t\t\ttransform: translateY(-50%);\n\t\t\tfont-size: var(--fx-font-size, 14px);\n\t\t\tfont-weight: var(--fx-font-weight, 400);\n\t\t\tbackground: transparent;\n\t\t\tpadding: 0;\n\t\t}\n\t\t:host([variant=\"in\"][active]) .flabel {\n\t\t\ttop: 0;\n\t\t\ttransform: translateY(-50%);\n\t\t\tfont-size: calc(var(--fx-font-size, 14px) - 3px);\n\t\t\tfont-weight: 600;\n\t\t\tbackground-color: var(--fx-surface-background, #fff);\n\t\t\tpadding: 0 5px;\n\t\t\t/* Sem color aqui: a especificidade desta regra\n\t\t\t (variant + active) venceria :host([error])/:host([focus]). */\n\t\t}\n\n\t\t/* ---- variant=\"in\" com ícone dentro do campo (fx-input icon):\n\t\t enquanto a label funciona como placeholder (sem foco/valor), ela\n\t\t começa DEPOIS do glifo (mesma métrica de padding do fx-input).\n\t\t Ao subir (active), volta ao offset padrão da borda. ---- */\n\t\t:host([variant=\"in\"]) .flabel.icon-indent {\n\t\t\tleft: calc(\n\t\t\t\tvar(--fx-space-md, 12px) +\n\t\t\t\tvar(--fx-input-icon-size, calc(var(--fx-font-size, 14px) + 6px)) +\n\t\t\t\tvar(--fx-space-sm, 8px)\n\t\t\t);\n\t\t}\n\t\t:host([variant=\"in\"][active]) .flabel.icon-indent {\n\t\t\tleft: var(--fx-space-md, 12px);\n\t\t}\n\n\t\t/* ---- variant=\"over\": label estática ACIMA do campo (fora, em fluxo) ---- */\n\t\t:host([variant=\"over\"]) {\n\t\t\tdisplay: block;\n\t\t}\n\t\t:host([variant=\"over\"]) .flabel {\n\t\t\tposition: static;\n\t\t\tdisplay: block;\n\t\t\tmargin-bottom: var(--fx-space-xs, 4px);\n\t\t\tbackground: transparent;\n\t\t\tpadding: 0;\n\t\t\tfont-size: calc(var(--fx-font-size, 14px) - 3px);\n\t\t\tfont-weight: 600;\n\t\t\twhite-space: normal;\n\t\t\t/* Fora do campo, a label pode receber clique: o listener do\n\t\t\t render() foca o controle (nas variantes on/in o\n\t\t\t pointer-events: none é intencional, para não bloquear a borda). */\n\t\t\tpointer-events: auto;\n\t\t}\n\n\t\t/* ---- estados de erro / sucesso ----\n\t\t Declarados DEPOIS de :host([focus]) e com a mesma especificidade:\n\t\t a validação vence o foco pela ordem, sem depender de acidente. */\n\t\t:host([error]),\n\t\t:host([invalid]) {\n\t\t\t--_flabel-color: var(--fx-color-danger, #dc2626);\n\t\t}\n\t\t:host([success]),\n\t\t:host([valid]) {\n\t\t\t--_flabel-color: var(--fx-color-success, #10b981);\n\t\t}\n\n\t\t/* ---- mensagem de erro sob o campo (fonte menor) ---- */\n\t\t.error-message {\n\t\t\tdisplay: none;\n\t\t\tmargin-top: var(--fx-space-xs, 4px);\n\t\t\tmargin-left: var(--fx-space-md, 12px);\n\t\t\tfont-size: calc(var(--fx-font-size, 14px) - 3px);\n\t\t\tfont-weight: 500;\n\t\t\tcolor: var(--fx-color-danger, #dc2626);\n\t\t\tline-height: 1.2;\n\t\t}\n\t\t:host([error]) .error-message,\n\t\t:host([invalid]) .error-message {\n\t\t\tdisplay: block;\n\t\t}\n\t`;\n\tprivate targetControl: HTMLElement | null = null;\n\tprivate observer: MutationObserver | null = null;\n\tprivate listenersReady = false;\n\t/** <label> adotada do light DOM — vive no Shadow DOM após o 1º render. */\n\tprivate _label: HTMLElement | null = null;\n\tprivate _labelClickBound = false;\n\t/** Observa o light DOM para readotar uma <label> recriada pelo framework. */\n\tprivate _labelObserver?: MutationObserver;\n\t/** Timer do `focusout`: confirma o estado no próximo tick (foco já movido). */\n\tprivate _syncTimer: ReturnType<typeof setTimeout> | undefined;\n\n\tprotected override connectedCallback(): void {\n\t\tsuper.connectedCallback();\n\t\tthis._labelObserver = new MutationObserver(() => {\n\t\t\tconst label = this.findLabel();\n\t\t\tif (label && label !== this._label) this.render();\n\t\t});\n\t\tthis._labelObserver.observe(this, { childList: true });\n\t}\n\n\tprotected render(): void {\n\t\tconst control = this.findControl();\n\t\t// Adota a <label> do light DOM (na 1ª renderização, ou se o consumidor\n\t\t// trocar por outra depois). Uma vez movida, o render seguinte não a\n\t\t// encontra no light DOM — a referência `_label` é reutilizada.\n\t\tconst lightLabel = this.findLabel();\n\t\tif (lightLabel) this._label = lightLabel;\n\t\tconst label = this._label;\n\t\tconst isOver = this.getAttribute(\"variant\") === \"over\";\n\n\t\tthis.setTemplate(`\n <div class=\"wrapper\" part=\"wrapper\">\n <div class=\"field-box\" part=\"field\">\n <slot></slot>\n </div>\n <div class=\"error-message\" part=\"error\"></div>\n </div>\n `);\n\n\t\t// A label original é INSERIDA no Shadow DOM (move o próprio elemento —\n\t\t// não é uma cópia). `setTemplate` reconstrói o template a cada render e\n\t\t// a label desanexada é reinserida no novo wrapper, com estado intacto.\n\t\tif (label) {\n\t\t\tlabel.classList.add(\"flabel\");\n\t\t\tlabel.setAttribute(\"part\", \"label\");\n\t\t\tconst wrapper = this.root.querySelector(\".wrapper\");\n\t\t\tconst fieldBox = this.root.querySelector(\".field-box\");\n\t\t\tif (wrapper && fieldBox) {\n\t\t\t\tif (isOver) wrapper.insertBefore(label, fieldBox);\n\t\t\t\telse fieldBox.appendChild(label);\n\t\t\t}\n\t\t\t// `for` não cruza a fronteira do shadow (o id do controle vive no\n\t\t\t// light DOM): o clique na label foca o campo manualmente.\n\t\t\tif (!this._labelClickBound) {\n\t\t\t\tthis._labelClickBound = true;\n\t\t\t\tlabel.addEventListener(\"click\", (e) => {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\t(this.targetControl as HTMLElement | null)?.focus?.();\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tthis.attachEvents();\n\t\tthis.syncControlReference(control);\n\t\tthis.syncState();\n\t\tthis.applyError();\n\t\tthis.applyFull();\n\t\tthis.applyIcon();\n\t\tthis.syncIconIndent();\n\t}\n\n\tprotected override disconnectedCallback(): void {\n\t\tsuper.disconnectedCallback();\n\t\tthis.cancelScheduledSync();\n\t\tthis.observer?.disconnect();\n\t\tthis._labelObserver?.disconnect();\n\t\tthis._labelObserver = undefined;\n\t}\n\n\t/** Campo de controle = qualquer filho direto que não seja label. */\n\tprivate findControl(): HTMLElement | null {\n\t\treturn (\n\t\t\t(Array.from(this.children).find(\n\t\t\t\t(n) => n.tagName.toLowerCase() !== \"label\",\n\t\t\t) as HTMLElement) ?? null\n\t\t);\n\t}\n\n\t/** Label = filho direto <label>. */\n\tprivate findLabel(): HTMLElement | null {\n\t\treturn (\n\t\t\t(Array.from(this.children).find(\n\t\t\t\t(n) => n.tagName.toLowerCase() === \"label\",\n\t\t\t) as HTMLElement) ?? null\n\t\t);\n\t}\n\n\tprivate attachEvents(): void {\n\t\tconst slot = this.root.querySelector(\"slot\");\n\t\tif (slot) {\n\t\t\tslot.addEventListener(\"slotchange\", () => {\n\t\t\t\t// Se o usuário trocar o controle/label em tempo de execução, re-sincroniza.\n\t\t\t\tconst control = this.findControl();\n\t\t\t\tthis.syncControlReference(control);\n\t\t\t\tthis.syncState();\n\t\t\t\tthis.applyError();\n\t\t\t\tthis.applyFull();\n\t\t\t});\n\t\t}\n\n\t\tif (this.listenersReady) return;\n\t\tthis.listenersReady = true;\n\n\t\tthis.addEventListener(\"focusin\", () => {\n\t\t\t// Um foco novo invalida o `focusout` pendente: sem isso o\n\t\t\t// sync atrasado poderia reaplicar o estado anterior.\n\t\t\tthis.cancelScheduledSync();\n\t\t\tthis.syncState();\n\t\t});\n\t\tthis.addEventListener(\"focusout\", () => this.scheduleSync());\n\t\tthis.addEventListener(\"input\", () => this.syncState());\n\t\tthis.addEventListener(\"change\", () => this.syncState());\n\t}\n\n\t/** Reavalia o estado no próximo tick (o foco já saiu do campo). */\n\tprivate scheduleSync(): void {\n\t\tthis.cancelScheduledSync();\n\t\tthis._syncTimer = setTimeout(() => {\n\t\t\tthis._syncTimer = undefined;\n\t\t\tthis.syncState();\n\t\t}, 0);\n\t}\n\n\tprivate cancelScheduledSync(): void {\n\t\tif (this._syncTimer !== undefined) {\n\t\t\tclearTimeout(this._syncTimer);\n\t\t\tthis._syncTimer = undefined;\n\t\t}\n\t}\n\n\t/** Observa mudanças de atributos do controle (value, open, values...). */\n\tprivate syncControlReference(\n\t\tcontrol: HTMLElement | null = this.targetControl,\n\t): void {\n\t\tif (control !== this.targetControl) {\n\t\t\tthis.observer?.disconnect();\n\t\t\tthis.observer = null;\n\t\t\tthis.targetControl = control;\n\t\t\tif (control) {\n\t\t\t\tthis.observer = new MutationObserver(() => {\n\t\t\t\t\tthis.syncState();\n\t\t\t\t\tthis.syncIconIndent();\n\t\t\t\t});\n\t\t\t\tthis.observer.observe(control, {\n\t\t\t\t\tattributes: true,\n\t\t\t\t\tattributeFilter: [\"value\", \"values\", \"start\", \"end\", \"open\", \"icon\", \"icon-pos\"],\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate syncState(): void {\n\t\tif (this.targetControl && !this.targetControl.isConnected) {\n\t\t\tthis.targetControl = null;\n\t\t\tthis.observer?.disconnect();\n\t\t\tthis.observer = null;\n\t\t}\n\n\t\tif (!this.targetControl) {\n\t\t\tthis.removeAttribute(\"active\");\n\t\t\tthis.removeAttribute(\"focus\");\n\t\t\treturn;\n\t\t}\n\n\t\tconst c = this.targetControl as any;\n\t\tconst attrValue = c.getAttribute\n\t\t\t? (c.getAttribute(\"value\") ?? \"\").trim()\n\t\t\t: \"\";\n\t\tconst attrValues = c.getAttribute\n\t\t\t? (c.getAttribute(\"values\") ?? \"\").trim()\n\t\t\t: \"\";\n\t\t// `open` = dropdown/calendário aberto; `start` = data escolhida em\n\t\t// componentes de range (é VALOR, não \"aberto\").\n\t\tconst isOpen = Boolean(c.hasAttribute?.(\"open\"));\n\t\tconst hasValue = Boolean(\n\t\t\t(typeof c.value === \"string\" && c.value.trim() !== \"\") ||\n\t\t\t(Array.isArray(c.values) && c.values.length > 0) ||\n\t\t\tattrValue !== \"\" ||\n\t\t\tattrValues !== \"\" ||\n\t\t\t(c.hasAttribute && c.hasAttribute(\"start\")),\n\t\t);\n\n\t\tconst focused = this.isFocusedInside();\n\t\t// `active` só levanta a label (valor, foco ou dropdown aberto);\n\t\t// `focus` é o que a destaca no CSS — e inclui o dropdown aberto\n\t\t// para o destaque não depender de onde o foco está.\n\t\tconst highlighted = focused || isOpen;\n\n\t\tif (hasValue || highlighted) this.setAttribute(\"active\", \"\");\n\t\telse this.removeAttribute(\"active\");\n\n\t\tif (highlighted) this.setAttribute(\"focus\", \"\");\n\t\telse this.removeAttribute(\"focus\");\n\t}\n\n\t/**\n\t * variant=\"in\" + ícone à esquerda dentro do campo (fx-input icon):\n\t * enquanto a label é placeholder ela precisa começar depois do glifo.\n\t * Detecta via atributos icon/icon-pos (ou slot icon) do controle.\n\t */\n\tprivate syncIconIndent(): void {\n\t\tconst label = this.root.querySelector(\".flabel\");\n\t\tif (!label) return;\n\t\tconst c = this.targetControl;\n\t\tconst hasLeftIcon = Boolean(\n\t\t\tc &&\n\t\t\t(c.hasAttribute(\"icon\") || c.querySelector(':scope > [slot=\"icon\"]')) &&\n\t\t\tc.getAttribute(\"icon-pos\") !== \"right\",\n\t\t);\n\t\tlabel.classList.toggle(\"icon-indent\", hasLeftIcon);\n\t}\n\n\tprivate applyFull(): void {\n\t\t// Espelha o full no controle interno: o CSS :host([full]) do floatlabel\n\t\t// estica apenas o HOST — sem isso o campo interno (ex.: fx-input com\n\t\t// width 260px fixa) não acompanharia o container.\n\t\tif (\n\t\t\tthis.targetControl &&\n\t\t\ttypeof this.targetControl.setAttribute === \"function\"\n\t\t) {\n\t\t\tif (this.hasAttr(\"full\")) {\n\t\t\t\tthis.targetControl.setAttribute(\"full\", \"\");\n\t\t\t} else {\n\t\t\t\tthis.targetControl.removeAttribute(\"full\");\n\t\t\t}\n\t\t\t}\n\t}\n\n\tprivate applyIcon(): void {\n\t\tif (\n\t\t\tthis.targetControl &&\n\t\t\ttypeof this.targetControl.setAttribute === \"function\"\n\t\t) {\n\t\t\t// Só propaga icon/icon-pos se o FLOATLABEL possuir o atributo.\n\t\t\t// Se o ícone foi pondo diretamente no controle (ex.: <fx-input icon=\"lock\">),\n\t\t\t// não remove — deixa o controle manter o seu próprio ícone.\n\t\t\tif (this.hasAttr(\"icon\")) {\n\t\t\t\tconst icon = this.getAttr(\"icon\");\n\t\t\t\tconst iconPos = this.getAttr(\"icon-pos\");\n\t\t\t\tif (icon !== \"\") this.targetControl.setAttribute(\"icon\", icon);\n\t\t\t\telse this.targetControl.setAttribute(\"icon\", \"\");\n\t\t\t\tif (iconPos && iconPos !== \"left\") this.targetControl.setAttribute(\"icon-pos\", iconPos);\n\t\t\t\telse this.targetControl.removeAttribute(\"icon-pos\");\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate applyError(): void {\n\t\tconst hasError = this.hasAttr(\"error\") || this.hasAttr(\"invalid\");\n\t\tconst errMsg = this.root.querySelector(\n\t\t\t\".error-message\",\n\t\t) as HTMLElement | null;\n\t\tif (errMsg) {\n\t\t\terrMsg.textContent = hasError\n\t\t\t\t? this.getAttribute(\"error-text\")?.trim() || \"Valor inválido\"\n\t\t\t\t: \"\";\n\t\t}\n\n\t\t// Espelha o estado no controle interno para que a borda também fique vermelha/verde.\n\t\tif (\n\t\t\tthis.targetControl &&\n\t\t\ttypeof this.targetControl.setAttribute === \"function\"\n\t\t) {\n\t\t\tconst t = this.targetControl;\n\t\t\tif (hasError) {\n\t\t\t\tt.setAttribute(\"error\", \"\");\n\t\t\t\tt.removeAttribute(\"success\");\n\t\t\t} else if (this.hasAttr(\"success\") || this.hasAttr(\"valid\")) {\n\t\t\t\tt.setAttribute(\"success\", \"\");\n\t\t\t\tt.removeAttribute(\"error\");\n\t\t\t} else {\n\t\t\t\tt.removeAttribute(\"error\");\n\t\t\t\tt.removeAttribute(\"success\");\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate isWithin(activeEl: Element): boolean {\n\t\tlet current: Element | null = activeEl;\n\t\twhile (current && current !== this) {\n\t\t\tcurrent = current.parentElement;\n\t\t}\n\t\treturn current === this;\n\t}\n\n\tprivate isFocusedInside(): boolean {\n\t\tconst activeEl = (document as Document).activeElement;\n\t\treturn Boolean(activeEl && this.isWithin(activeEl));\n\t}\n}\n\nexport function defineFxFloatlabel(): typeof FxFloatlabel {\n\treturn defineElement(\"fx-floatlabel\", FxFloatlabel);\n}\n"],"names":[],"mappings":"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"}
@@ -12,6 +12,17 @@ import type { FxInputType } from '../../core/jsx';
12
12
  * size, placeholder, disabled, readonly, min, max, step, autofocus,
13
13
  * clearable, full (largura 100% acompanhando o elemento pai), icon (nome do
14
14
  * glifo Fenix Icons ou emoji/texto livre) e icon-pos (left|right, padrão left).
15
+ *
16
+ * Autofill: o <input> real vive no Shadow DOM, então `autocomplete` precisa ser
17
+ * REPASSADO ao campo interno — sem isso o navegador aplica o default `on` e
18
+ * preenche o campo com credenciais salvas (heurística "primeiro campo de texto
19
+ * = usuário"). O default aqui é `off` (mesma escolha do <fx-autocomplete>) e o
20
+ * atributo declarado no host vence. Quando o autofill for desejado, use os
21
+ * tokens semânticos: autocomplete="username", "current-password",
22
+ * "new-password", "one-time-code", "email", "street-address", … O Chrome
23
+ * IGNORA `off` em type="password" — para login use "current-password" (e
24
+ * "new-password" no cadastro/troca de senha). `name` e `id` também são
25
+ * repassados ao campo interno (melhoram a classificação do navegador).
15
26
  * Largura: o default (260px; sm 220px / lg 300px) fica no HOST via tokens
16
27
  * --fx-input-width(-sm|-lg) — CSS externo, classes e style inline no elemento
17
28
  * vencem o default sem precisar de atributo.
@@ -1 +1 @@
1
- {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../../src/components/input/input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAKxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AA4BlD;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,OAAQ,SAAQ,aAAa;IACxC,OAAgB,MAAM,SAuIpB;IAMF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAOjD;IAED,+CAA+C;IAC/C,IAAa,IAAI,IAAI,WAAW,CAE/B;IACD,IAAa,IAAI,CAAC,KAAK,EAAE,WAAW,EAEnC;IAED,wCAAwC;IACxC,IAAI,IAAI,IAAI,MAAM,CAGjB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,EAErB;IAED,IAAI,KAAK,IAAI,MAAM,CAElB;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,EAMlD;IAED,IAAI,QAAQ,IAAI,OAAO,CAEtB;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAE1B;IAED,IAAI,QAAQ,IAAI,OAAO,CAEtB;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAE1B;IAED,IAAI,SAAS,IAAI,OAAO,CAEvB;IACD,IAAI,SAAS,CAAC,KAAK,EAAE,OAAO,EAE3B;IAED,IAAI,IAAI,IAAI,OAAO,CAElB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,EAEtB;cAEkB,MAAM,IAAI,IAAI;IAgGjC,yEAAyE;cACtD,mBAAmB,IAAI,IAAI;CAO/C;AAED,wBAAgB,aAAa,IAAI,OAAO,OAAO,CAE9C"}
1
+ {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../../src/components/input/input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAKxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AA4BlD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,qBAAa,OAAQ,SAAQ,aAAa;IACxC,OAAgB,MAAM,SAuIpB;IAMF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAWjD;IAED,+CAA+C;IAC/C,IAAa,IAAI,IAAI,WAAW,CAE/B;IACD,IAAa,IAAI,CAAC,KAAK,EAAE,WAAW,EAEnC;IAED,wCAAwC;IACxC,IAAI,IAAI,IAAI,MAAM,CAGjB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,EAErB;IAED,IAAI,KAAK,IAAI,MAAM,CAElB;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,EAMlD;IAED,IAAI,QAAQ,IAAI,OAAO,CAEtB;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAE1B;IAED,IAAI,QAAQ,IAAI,OAAO,CAEtB;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAE1B;IAED,IAAI,SAAS,IAAI,OAAO,CAEvB;IACD,IAAI,SAAS,CAAC,KAAK,EAAE,OAAO,EAE3B;IAED,IAAI,IAAI,IAAI,OAAO,CAElB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,EAEtB;cAEkB,MAAM,IAAI,IAAI;IA0GjC,yEAAyE;cACtD,mBAAmB,IAAI,IAAI;CAO/C;AAED,wBAAgB,aAAa,IAAI,OAAO,OAAO,CAE9C"}
@@ -39,6 +39,12 @@ const _FxInput = class _FxInput extends FxFormElement {
39
39
  "step",
40
40
  "clearable",
41
41
  "full",
42
+ // `autocomplete` é observado porque ele vive no campo INTERNO (autofill
43
+ // do navegador): mudar o atributo no host precisa refletir no <input>.
44
+ // `name`/`id` idem — os dois descem para o campo interno.
45
+ "autocomplete",
46
+ "name",
47
+ "id",
42
48
  "icon",
43
49
  "icon-pos",
44
50
  "error",
@@ -102,6 +108,9 @@ const _FxInput = class _FxInput extends FxFormElement {
102
108
  const min = this.getAttr("min");
103
109
  const max = this.getAttr("max");
104
110
  const step = this.getAttr("step");
111
+ const autocomplete = this.getAttr("autocomplete", "off");
112
+ const name = this.getAttr("name");
113
+ const id = this.getAttr("id");
105
114
  const icon = this.getAttr("icon");
106
115
  const iconPos = this.getAttr("icon-pos", "left") === "right" ? "right" : "left";
107
116
  const slottedIcon = this.querySelector('[slot="icon"]');
@@ -112,6 +121,8 @@ const _FxInput = class _FxInput extends FxFormElement {
112
121
  ${useIconBox ? `<div class="field-icon icon-${iconPos}">` : ""}
113
122
  ${useIconBox && iconPos === "left" ? iconContent : ""}
114
123
  <input class="field" part="input" type="${esc(type)}"
124
+ ${name ? `name="${esc(name)}"` : ""} ${id ? `id="${esc(id)}"` : ""}
125
+ autocomplete="${esc(autocomplete)}"
115
126
  ${placeholder ? `placeholder="${esc(placeholder)}"` : ""}
116
127
  ${min ? `min="${esc(min)}"` : ""} ${max ? `max="${esc(max)}"` : ""} ${step ? `step="${esc(step)}"` : ""}
117
128
  />
@@ -1 +1 @@
1
- {"version":3,"file":"input.js","sources":["../../../src/components/input/input.ts"],"sourcesContent":["import { FxFormElement } from '../../core/form-element';\nimport { css } from '../../core/css';\nimport { defineElement } from '../../core/define';\nimport { esc } from '../../core/sanitize';\nimport { FENIX_ICON_BASE_CSS, fenixIconHtml } from '../../icons/base-css';\nimport type { FxInputType } from '../../core/jsx';\n\n/**\n * Tipos nativos aceitos pelo <fx-input>. Os tipos com semântica própria\n * (file, checkbox, radio, submit, reset, button, image) continuam fora:\n * eles não fazem sentido no componente de texto.\n */\nconst INPUT_TYPES = new Set([\n 'text',\n 'number',\n 'password',\n 'email',\n 'tel',\n 'url',\n 'search',\n 'date',\n 'time',\n 'datetime-local',\n 'month',\n 'week',\n 'color',\n]);\n\nfunction normalizeInputType(value: string): string {\n const type = (value || 'text').toLowerCase();\n return INPUT_TYPES.has(type) ? type : 'text';\n}\n\n/**\n * <fx-input> — Campo de texto estilizado com os tokens do tema.\n *\n * Form-Associated Custom Element: dentro de um <form> entra no FormData\n * (via atributo `name`), recebe reset/disable do form, é alvo de\n * `<label for>`/`autofocus` e o Enter submete o form.\n *\n * Atributos: type (text|number|password|email|tel|url|search|date|time|\n * datetime-local|month|week|color), value, name,\n * size, placeholder, disabled, readonly, min, max, step, autofocus,\n * clearable, full (largura 100% acompanhando o elemento pai), icon (nome do\n * glifo Fenix Icons ou emoji/texto livre) e icon-pos (left|right, padrão left).\n * Largura: o default (260px; sm 220px / lg 300px) fica no HOST via tokens\n * --fx-input-width(-sm|-lg) — CSS externo, classes e style inline no elemento\n * vencem o default sem precisar de atributo.\n * Slots: `icon` (ícone customizado no lugar do atributo).\n * Eventos: `input`, `change` e `valueChange` (composed, detail: { value }) —\n * `input` aciona o v-model do Vue e `valueChange` o [(value)] do Angular.\n */\nexport class FxInput extends FxFormElement {\n static override styles = css`\n :host {\n display: inline-block;\n vertical-align: middle;\n /* Largura padrão no HOST (e não no .field interno): assim CSS externo,\n classes do framework (ex.: w-full) e style inline no elemento vencem\n este default naturalmente — regras do documento têm precedência sobre\n :host. Default global trocável via token: --fx-input-width (-sm/-lg). */\n width: var(--fx-input-width, 260px);\n vertical-align: middle;\n font-family: var(--fx-font-family);\n font-size: var(--fx-font-size);\n }\n .field {\n font-family: inherit;\n font-size: inherit;\n /* Altura determinística: com line-height fixo, o padding vertical cabe no\n token --fx-size-* e a caixa fica EXATAMENTE no tamanho padrão\n (sm 32 / md 40 / lg 48), igual para todos os campos. */\n line-height: var(--fx-font-line-height);\n min-height: var(--fx-size-md);\n font-weight: var(--fx-font-weight);\n color: var(--fx-text-default);\n background-color: var(--fx-surface-background);\n border: 1px solid var(--fx-border-default);\n border-radius: var(--fx-radius-md);\n padding: var(--fx-space-sm) var(--fx-space-lg);\n /* Acompanha a largura definida no :host. */\n width: 100%;\n box-sizing: border-box;\n transition:\n border-color var(--fx-motion-duration-normal) var(--fx-motion-easing),\n box-shadow var(--fx-motion-duration-normal) var(--fx-motion-easing);\n }\n .field::placeholder { color: var(--fx-text-muted); opacity: 1; }\n .field:hover { border-color: var(--fx-border-hover); }\n .field:focus-visible {\n outline: none;\n border-color: var(--fx-color-primary);\n box-shadow: var(--fx-effect-focus-ring, none);\n }\n .field:disabled,\n .field[readonly] {\n opacity: 0.55;\n cursor: not-allowed;\n background-color: var(--fx-surface-surface-hover);\n }\n /* Validação: borda sempre; o brilho (anel) segue o token do preset\n --fx-effect-error-ring, que acompanha effect.focus-ring — anel\n desligado ⇒ erro só com a borda vermelha, ligado ⇒ soma o brilho. */\n :host([error]) .field,\n :host([invalid]) .field,\n :host([error]) .field:focus-visible,\n :host([invalid]) .field:focus-visible {\n border-color: var(--fx-color-danger, #dc2626);\n box-shadow: var(--fx-effect-error-ring, 0 0 0 3px color-mix(in srgb, var(--fx-color-danger, #dc2626) 18%, transparent));\n }\n :host([success]) .field,\n :host([valid]) .field,\n :host([success]) .field:focus-visible,\n :host([valid]) .field:focus-visible {\n border-color: var(--fx-color-success, #16a34a);\n box-shadow: var(--fx-effect-success-ring, 0 0 0 3px color-mix(in srgb, var(--fx-color-success, #16a34a) 18%, transparent));\n }\n :host([size='sm']) { width: var(--fx-input-width-sm, 220px); }\n :host([size='sm']) .field { padding: var(--fx-space-xs) var(--fx-space-md); font-size: var(--fx-font-size); min-height: var(--fx-size-sm); }\n :host([size='lg']) { width: var(--fx-input-width-lg, 300px); }\n :host([size='lg']) .field { padding: var(--fx-space-sm) var(--fx-space-xl); font-size: calc(var(--fx-font-size) + 4px); min-height: var(--fx-size-lg); }\n /* Full width: o host estica até o pai e o campo interno acompanha\n (usar com um container de largura controlada, ex. w-full no Vue). */\n :host([full]) { display: block; width: 100%; }\n :host([full]) .field { width: 100%; }\n /* Clearable */\n :host([clearable]) { position: relative; display: inline-flex; }\n :host([clearable][full]) { display: block; }\n .wrap { position: relative; display: inline-flex; align-items: center; width: 100%; }\n :host([full]) .wrap { display: flex; width: 100%; }\n :host([clearable]) .field { padding-right: var(--fx-space-xl); }\n :host([clearable][full]) .field { flex: 1 1 auto; }\n /* Ícones (attr icon + slot icon) — DENTRO do campo, sobre o padding\n (padrão Material/PrimeVue). Tamanho ajustável via --fx-input-icon-size. */\n .field-icon {\n position: relative;\n display: inline-flex;\n box-sizing: border-box;\n width: 100%;\n }\n .field-icon .field { flex: 1 1 auto; min-width: 0; }\n :host([full]) .field-icon { display: flex; width: 100%; }\n .field-icon .fx-icon,\n .field-icon ::slotted([slot='icon']) {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-size: var(--fx-input-icon-size, calc(var(--fx-font-size) + 6px));\n line-height: 1;\n color: var(--fx-text-muted);\n pointer-events: none;\n z-index: 1;\n }\n .field-icon.icon-left .fx-icon,\n .field-icon.icon-left ::slotted([slot='icon']) { left: var(--fx-space-md); }\n .field-icon.icon-right .fx-icon,\n .field-icon.icon-right ::slotted([slot='icon']) { right: var(--fx-space-md); }\n /* padding = posição do ícone + largura + folga extra para o texto\n não colar no glifo. */\n .field-icon.icon-left .field {\n padding-left: calc(var(--fx-input-icon-size, calc(var(--fx-font-size) + 6px)) + var(--fx-space-md) + var(--fx-space-sm));\n }\n .field-icon.icon-right .field {\n padding-right: calc(var(--fx-input-icon-size, calc(var(--fx-font-size) + 6px)) + var(--fx-space-md) + var(--fx-space-sm));\n }\n /* icon-pos right + clearable: desloca o × para não sobrepor o ícone. */\n .field-icon.icon-right + .clear {\n right: calc(var(--fx-input-icon-size, calc(var(--fx-font-size) + 6px)) + var(--fx-space-lg));\n }\n .clear {\n position: absolute;\n right: var(--fx-space-xs);\n border: none;\n background: transparent;\n color: var(--fx-text-muted);\n font-size: calc(var(--fx-font-size) + 4px);\n line-height: 1;\n cursor: pointer;\n padding: 0 var(--fx-space-xs);\n border-radius: var(--fx-radius-full);\n }\n .clear:hover { color: var(--fx-color-danger); }\n .clear[hidden] { display: none; }\n /* Base dos glifos Fenix Icons (o @font-face vem de @wrrdev/fenix-ui/icons). */\n ${FENIX_ICON_BASE_CSS}\n `;\n\n // `value` fica FORA da observação: refleti-lo a cada tecla não pode\n // re-renderizar o template, senão o campo perde o foco ao digitar.\n // `error`/`success` (+ aliases `invalid`/`valid`) PRECISAM ser observados:\n // é assim que o toggle no playground / setAttribute no submit re-renderiza.\n static override get observedAttributes(): string[] {\n return [\n 'type', 'size', 'placeholder',\n 'disabled', 'readonly', 'min', 'max', 'step',\n 'clearable', 'full',\n 'icon', 'icon-pos', 'error', 'invalid', 'success', 'valid',\n ];\n }\n\n /** Tipo do input interno. Padrão: `'text'`. */\n override get type(): FxInputType {\n return normalizeInputType(this.getAttr('type', 'text')) as FxInputType;\n }\n override set type(value: FxInputType) {\n this.setAttribute('type', normalizeInputType(value));\n }\n\n /** Tamanho do campo. Padrão: `'md'`. */\n get size(): string {\n const s = this.getAttr('size', 'md');\n return s === 'sm' || s === 'lg' ? s : 'md';\n }\n set size(value: string) {\n this.setAttribute('size', value);\n }\n\n get value(): string {\n return this.getAttr('value');\n }\n set value(value: string | number | null | undefined) {\n this.setAttribute('value', value == null ? '' : String(value));\n // `value` NÃO é observado (re-render a cada tecla perderia o foco): o\n // campo interno é sincronizado aqui, sem re-render, preservando foco/cursor.\n this.syncInternalControl();\n this.updateFormValue();\n }\n\n get disabled(): boolean {\n return this.hasAttr('disabled');\n }\n set disabled(value: boolean) {\n this.toggleAttr('disabled', Boolean(value));\n }\n\n get readonly(): boolean {\n return this.hasAttr('readonly');\n }\n set readonly(value: boolean) {\n this.toggleAttr('readonly', Boolean(value));\n }\n\n get clearable(): boolean {\n return this.hasAttr('clearable');\n }\n set clearable(value: boolean) {\n this.toggleAttr('clearable', Boolean(value));\n }\n\n get full(): boolean {\n return this.hasAttr('full');\n }\n set full(value: boolean) {\n this.toggleAttr('full', Boolean(value));\n }\n\n protected override render(): void {\n const type = this.type;\n const placeholder = this.getAttr('placeholder');\n const readonly = this.hasAttr('readonly');\n const disabled = this.hasAttr('disabled');\n const min = this.getAttr('min');\n const max = this.getAttr('max');\n const step = this.getAttr('step');\n const icon = this.getAttr('icon');\n const iconPos = this.getAttr('icon-pos', 'left') === 'right' ? 'right' : 'left';\n // Slot `icon` vence o atributo `icon`; sem nenhum dos dois, sem ícone.\n const slottedIcon = this.querySelector<HTMLElement>('[slot=\"icon\"]');\n const iconContent = slottedIcon\n ? '<slot name=\"icon\" part=\"icon\"></slot>'\n : (icon ? fenixIconHtml(icon) : '');\n const useIconBox = Boolean(iconContent);\n\n this.setTemplate(`\n ${this.hasAttr('clearable') ? '<div class=\"wrap\" part=\"wrap\">' : ''}\n ${useIconBox ? `<div class=\"field-icon icon-${iconPos}\">` : ''}\n ${useIconBox && iconPos === 'left' ? iconContent : ''}\n <input class=\"field\" part=\"input\" type=\"${esc(type)}\"\n ${placeholder ? `placeholder=\"${esc(placeholder)}\"` : ''}\n ${min ? `min=\"${esc(min)}\"` : ''} ${max ? `max=\"${esc(max)}\"` : ''} ${step ? `step=\"${esc(step)}\"` : ''}\n />\n ${useIconBox && iconPos === 'right' ? iconContent : ''}\n ${useIconBox ? '</div>' : ''}\n ${this.hasAttr('clearable') ? '<button type=\"button\" class=\"clear\" part=\"clear\" aria-label=\"Limpar\" tabindex=\"-1\">×</button></div>' : ''}\n `);\n\n const field = this.root.querySelector<HTMLInputElement>('.field');\n if (!field) return;\n field.value = this.getAttr('value');\n if (disabled) field.setAttribute('disabled', '');\n if (readonly) field.setAttribute('readonly', '');\n\n // Cada interação emite UM `input` (v-model) + `valueChange` (Angular).\n // O `change` só existe no evento nativo de mudança/limpar.\n const notifyInput = (): void => {\n this.value = field.value;\n this.emitValueEvents();\n };\n const notifyChange = (): void => {\n this.value = field.value;\n this.dispatchEvent(\n new CustomEvent('change', {\n bubbles: true,\n composed: true,\n detail: { value: field.value },\n }),\n );\n };\n // Bloqueia o evento nativo (composed, sem detail) para que só o\n // CustomEvent com detail chegue aos consumidores.\n field.addEventListener('input', (e) => { e.stopPropagation(); notifyInput(); });\n field.addEventListener('change', (e) => { e.stopPropagation(); notifyChange(); });\n\n // Enter submete o form: o <input> interno vive no Shadow DOM e NÃO se\n // associa ao <form> do light DOM (a fronteira do shadow corta a associação\n // por árvore) — por isso a submissão implícita é acionada manualmente.\n // Ouvintes de submit no form (ex.: submit.prevent de frameworks) seguem\n // recebendo o evento normalmente.\n field.addEventListener('keydown', (e) => {\n if (e.key !== 'Enter' || e.isComposing) return;\n if (!this.form) return;\n e.preventDefault();\n this.form.requestSubmit();\n });\n\n // Clearable: botão × que limpa o campo e emite input/change vazios.\n const clearBtn = this.root.querySelector<HTMLButtonElement>('.clear');\n const syncClear = (): void => {\n clearBtn?.toggleAttribute('hidden', field.value === '');\n };\n syncClear();\n clearBtn?.addEventListener('click', () => {\n field.value = '';\n syncClear();\n this.value = '';\n this.emitValueEvents();\n this.dispatchEvent(\n new CustomEvent('change', {\n bubbles: true,\n composed: true,\n detail: { value: '' },\n }),\n );\n field.focus();\n });\n field.addEventListener('input', syncClear);\n\n // Publica name/value no form (ElementInternals) a cada render — cobre o\n // estado inicial e mudanças de atributos observados.\n this.updateFormValue();\n }\n\n /** Empurra o atributo `value` para o campo interno sem re-renderizar. */\n protected override syncInternalControl(): void {\n const field = this.root.querySelector<HTMLInputElement>('.field');\n const value = this.getAttr('value');\n const type = this.type;\n if (field && field.type !== type) field.type = type;\n if (field && field.value !== value) field.value = value;\n }\n}\n\nexport function defineFxInput(): typeof FxInput {\n return defineElement('fx-input', FxInput);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"input.js","sources":["../../../src/components/input/input.ts"],"sourcesContent":["import { FxFormElement } from '../../core/form-element';\nimport { css } from '../../core/css';\nimport { defineElement } from '../../core/define';\nimport { esc } from '../../core/sanitize';\nimport { FENIX_ICON_BASE_CSS, fenixIconHtml } from '../../icons/base-css';\nimport type { FxInputType } from '../../core/jsx';\n\n/**\n * Tipos nativos aceitos pelo <fx-input>. Os tipos com semântica própria\n * (file, checkbox, radio, submit, reset, button, image) continuam fora:\n * eles não fazem sentido no componente de texto.\n */\nconst INPUT_TYPES = new Set([\n 'text',\n 'number',\n 'password',\n 'email',\n 'tel',\n 'url',\n 'search',\n 'date',\n 'time',\n 'datetime-local',\n 'month',\n 'week',\n 'color',\n]);\n\nfunction normalizeInputType(value: string): string {\n const type = (value || 'text').toLowerCase();\n return INPUT_TYPES.has(type) ? type : 'text';\n}\n\n/**\n * <fx-input> — Campo de texto estilizado com os tokens do tema.\n *\n * Form-Associated Custom Element: dentro de um <form> entra no FormData\n * (via atributo `name`), recebe reset/disable do form, é alvo de\n * `<label for>`/`autofocus` e o Enter submete o form.\n *\n * Atributos: type (text|number|password|email|tel|url|search|date|time|\n * datetime-local|month|week|color), value, name,\n * size, placeholder, disabled, readonly, min, max, step, autofocus,\n * clearable, full (largura 100% acompanhando o elemento pai), icon (nome do\n * glifo Fenix Icons ou emoji/texto livre) e icon-pos (left|right, padrão left).\n *\n * Autofill: o <input> real vive no Shadow DOM, então `autocomplete` precisa ser\n * REPASSADO ao campo interno — sem isso o navegador aplica o default `on` e\n * preenche o campo com credenciais salvas (heurística \"primeiro campo de texto\n * = usuário\"). O default aqui é `off` (mesma escolha do <fx-autocomplete>) e o\n * atributo declarado no host vence. Quando o autofill for desejado, use os\n * tokens semânticos: autocomplete=\"username\", \"current-password\",\n * \"new-password\", \"one-time-code\", \"email\", \"street-address\", … O Chrome\n * IGNORA `off` em type=\"password\" — para login use \"current-password\" (e\n * \"new-password\" no cadastro/troca de senha). `name` e `id` também são\n * repassados ao campo interno (melhoram a classificação do navegador).\n * Largura: o default (260px; sm 220px / lg 300px) fica no HOST via tokens\n * --fx-input-width(-sm|-lg) — CSS externo, classes e style inline no elemento\n * vencem o default sem precisar de atributo.\n * Slots: `icon` (ícone customizado no lugar do atributo).\n * Eventos: `input`, `change` e `valueChange` (composed, detail: { value }) —\n * `input` aciona o v-model do Vue e `valueChange` o [(value)] do Angular.\n */\nexport class FxInput extends FxFormElement {\n static override styles = css`\n :host {\n display: inline-block;\n vertical-align: middle;\n /* Largura padrão no HOST (e não no .field interno): assim CSS externo,\n classes do framework (ex.: w-full) e style inline no elemento vencem\n este default naturalmente — regras do documento têm precedência sobre\n :host. Default global trocável via token: --fx-input-width (-sm/-lg). */\n width: var(--fx-input-width, 260px);\n vertical-align: middle;\n font-family: var(--fx-font-family);\n font-size: var(--fx-font-size);\n }\n .field {\n font-family: inherit;\n font-size: inherit;\n /* Altura determinística: com line-height fixo, o padding vertical cabe no\n token --fx-size-* e a caixa fica EXATAMENTE no tamanho padrão\n (sm 32 / md 40 / lg 48), igual para todos os campos. */\n line-height: var(--fx-font-line-height);\n min-height: var(--fx-size-md);\n font-weight: var(--fx-font-weight);\n color: var(--fx-text-default);\n background-color: var(--fx-surface-background);\n border: 1px solid var(--fx-border-default);\n border-radius: var(--fx-radius-md);\n padding: var(--fx-space-sm) var(--fx-space-lg);\n /* Acompanha a largura definida no :host. */\n width: 100%;\n box-sizing: border-box;\n transition:\n border-color var(--fx-motion-duration-normal) var(--fx-motion-easing),\n box-shadow var(--fx-motion-duration-normal) var(--fx-motion-easing);\n }\n .field::placeholder { color: var(--fx-text-muted); opacity: 1; }\n .field:hover { border-color: var(--fx-border-hover); }\n .field:focus-visible {\n outline: none;\n border-color: var(--fx-color-primary);\n box-shadow: var(--fx-effect-focus-ring, none);\n }\n .field:disabled,\n .field[readonly] {\n opacity: 0.55;\n cursor: not-allowed;\n background-color: var(--fx-surface-surface-hover);\n }\n /* Validação: borda sempre; o brilho (anel) segue o token do preset\n --fx-effect-error-ring, que acompanha effect.focus-ring — anel\n desligado ⇒ erro só com a borda vermelha, ligado ⇒ soma o brilho. */\n :host([error]) .field,\n :host([invalid]) .field,\n :host([error]) .field:focus-visible,\n :host([invalid]) .field:focus-visible {\n border-color: var(--fx-color-danger, #dc2626);\n box-shadow: var(--fx-effect-error-ring, 0 0 0 3px color-mix(in srgb, var(--fx-color-danger, #dc2626) 18%, transparent));\n }\n :host([success]) .field,\n :host([valid]) .field,\n :host([success]) .field:focus-visible,\n :host([valid]) .field:focus-visible {\n border-color: var(--fx-color-success, #16a34a);\n box-shadow: var(--fx-effect-success-ring, 0 0 0 3px color-mix(in srgb, var(--fx-color-success, #16a34a) 18%, transparent));\n }\n :host([size='sm']) { width: var(--fx-input-width-sm, 220px); }\n :host([size='sm']) .field { padding: var(--fx-space-xs) var(--fx-space-md); font-size: var(--fx-font-size); min-height: var(--fx-size-sm); }\n :host([size='lg']) { width: var(--fx-input-width-lg, 300px); }\n :host([size='lg']) .field { padding: var(--fx-space-sm) var(--fx-space-xl); font-size: calc(var(--fx-font-size) + 4px); min-height: var(--fx-size-lg); }\n /* Full width: o host estica até o pai e o campo interno acompanha\n (usar com um container de largura controlada, ex. w-full no Vue). */\n :host([full]) { display: block; width: 100%; }\n :host([full]) .field { width: 100%; }\n /* Clearable */\n :host([clearable]) { position: relative; display: inline-flex; }\n :host([clearable][full]) { display: block; }\n .wrap { position: relative; display: inline-flex; align-items: center; width: 100%; }\n :host([full]) .wrap { display: flex; width: 100%; }\n :host([clearable]) .field { padding-right: var(--fx-space-xl); }\n :host([clearable][full]) .field { flex: 1 1 auto; }\n /* Ícones (attr icon + slot icon) — DENTRO do campo, sobre o padding\n (padrão Material/PrimeVue). Tamanho ajustável via --fx-input-icon-size. */\n .field-icon {\n position: relative;\n display: inline-flex;\n box-sizing: border-box;\n width: 100%;\n }\n .field-icon .field { flex: 1 1 auto; min-width: 0; }\n :host([full]) .field-icon { display: flex; width: 100%; }\n .field-icon .fx-icon,\n .field-icon ::slotted([slot='icon']) {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-size: var(--fx-input-icon-size, calc(var(--fx-font-size) + 6px));\n line-height: 1;\n color: var(--fx-text-muted);\n pointer-events: none;\n z-index: 1;\n }\n .field-icon.icon-left .fx-icon,\n .field-icon.icon-left ::slotted([slot='icon']) { left: var(--fx-space-md); }\n .field-icon.icon-right .fx-icon,\n .field-icon.icon-right ::slotted([slot='icon']) { right: var(--fx-space-md); }\n /* padding = posição do ícone + largura + folga extra para o texto\n não colar no glifo. */\n .field-icon.icon-left .field {\n padding-left: calc(var(--fx-input-icon-size, calc(var(--fx-font-size) + 6px)) + var(--fx-space-md) + var(--fx-space-sm));\n }\n .field-icon.icon-right .field {\n padding-right: calc(var(--fx-input-icon-size, calc(var(--fx-font-size) + 6px)) + var(--fx-space-md) + var(--fx-space-sm));\n }\n /* icon-pos right + clearable: desloca o × para não sobrepor o ícone. */\n .field-icon.icon-right + .clear {\n right: calc(var(--fx-input-icon-size, calc(var(--fx-font-size) + 6px)) + var(--fx-space-lg));\n }\n .clear {\n position: absolute;\n right: var(--fx-space-xs);\n border: none;\n background: transparent;\n color: var(--fx-text-muted);\n font-size: calc(var(--fx-font-size) + 4px);\n line-height: 1;\n cursor: pointer;\n padding: 0 var(--fx-space-xs);\n border-radius: var(--fx-radius-full);\n }\n .clear:hover { color: var(--fx-color-danger); }\n .clear[hidden] { display: none; }\n /* Base dos glifos Fenix Icons (o @font-face vem de @wrrdev/fenix-ui/icons). */\n ${FENIX_ICON_BASE_CSS}\n `;\n\n // `value` fica FORA da observação: refleti-lo a cada tecla não pode\n // re-renderizar o template, senão o campo perde o foco ao digitar.\n // `error`/`success` (+ aliases `invalid`/`valid`) PRECISAM ser observados:\n // é assim que o toggle no playground / setAttribute no submit re-renderiza.\n static override get observedAttributes(): string[] {\n return [\n 'type', 'size', 'placeholder',\n 'disabled', 'readonly', 'min', 'max', 'step',\n 'clearable', 'full',\n // `autocomplete` é observado porque ele vive no campo INTERNO (autofill\n // do navegador): mudar o atributo no host precisa refletir no <input>.\n // `name`/`id` idem — os dois descem para o campo interno.\n 'autocomplete', 'name', 'id',\n 'icon', 'icon-pos', 'error', 'invalid', 'success', 'valid',\n ];\n }\n\n /** Tipo do input interno. Padrão: `'text'`. */\n override get type(): FxInputType {\n return normalizeInputType(this.getAttr('type', 'text')) as FxInputType;\n }\n override set type(value: FxInputType) {\n this.setAttribute('type', normalizeInputType(value));\n }\n\n /** Tamanho do campo. Padrão: `'md'`. */\n get size(): string {\n const s = this.getAttr('size', 'md');\n return s === 'sm' || s === 'lg' ? s : 'md';\n }\n set size(value: string) {\n this.setAttribute('size', value);\n }\n\n get value(): string {\n return this.getAttr('value');\n }\n set value(value: string | number | null | undefined) {\n this.setAttribute('value', value == null ? '' : String(value));\n // `value` NÃO é observado (re-render a cada tecla perderia o foco): o\n // campo interno é sincronizado aqui, sem re-render, preservando foco/cursor.\n this.syncInternalControl();\n this.updateFormValue();\n }\n\n get disabled(): boolean {\n return this.hasAttr('disabled');\n }\n set disabled(value: boolean) {\n this.toggleAttr('disabled', Boolean(value));\n }\n\n get readonly(): boolean {\n return this.hasAttr('readonly');\n }\n set readonly(value: boolean) {\n this.toggleAttr('readonly', Boolean(value));\n }\n\n get clearable(): boolean {\n return this.hasAttr('clearable');\n }\n set clearable(value: boolean) {\n this.toggleAttr('clearable', Boolean(value));\n }\n\n get full(): boolean {\n return this.hasAttr('full');\n }\n set full(value: boolean) {\n this.toggleAttr('full', Boolean(value));\n }\n\n protected override render(): void {\n const type = this.type;\n const placeholder = this.getAttr('placeholder');\n const readonly = this.hasAttr('readonly');\n const disabled = this.hasAttr('disabled');\n const min = this.getAttr('min');\n const max = this.getAttr('max');\n const step = this.getAttr('step');\n // Autofill: quem o navegador enxerga é o <input> interno, então o atributo\n // do HOST é repassado; sem ele, `off` (evita o preenchimento heurístico de\n // credenciais — ver o JSDoc da classe).\n const autocomplete = this.getAttr('autocomplete', 'off');\n // `name`/`id` também descem (classificação do navegador). O `name` do host\n // continua sendo o que entra no FormData via ElementInternals.\n const name = this.getAttr('name');\n const id = this.getAttr('id');\n const icon = this.getAttr('icon');\n const iconPos = this.getAttr('icon-pos', 'left') === 'right' ? 'right' : 'left';\n // Slot `icon` vence o atributo `icon`; sem nenhum dos dois, sem ícone.\n const slottedIcon = this.querySelector<HTMLElement>('[slot=\"icon\"]');\n const iconContent = slottedIcon\n ? '<slot name=\"icon\" part=\"icon\"></slot>'\n : (icon ? fenixIconHtml(icon) : '');\n const useIconBox = Boolean(iconContent);\n\n this.setTemplate(`\n ${this.hasAttr('clearable') ? '<div class=\"wrap\" part=\"wrap\">' : ''}\n ${useIconBox ? `<div class=\"field-icon icon-${iconPos}\">` : ''}\n ${useIconBox && iconPos === 'left' ? iconContent : ''}\n <input class=\"field\" part=\"input\" type=\"${esc(type)}\"\n ${name ? `name=\"${esc(name)}\"` : ''} ${id ? `id=\"${esc(id)}\"` : ''}\n autocomplete=\"${esc(autocomplete)}\"\n ${placeholder ? `placeholder=\"${esc(placeholder)}\"` : ''}\n ${min ? `min=\"${esc(min)}\"` : ''} ${max ? `max=\"${esc(max)}\"` : ''} ${step ? `step=\"${esc(step)}\"` : ''}\n />\n ${useIconBox && iconPos === 'right' ? iconContent : ''}\n ${useIconBox ? '</div>' : ''}\n ${this.hasAttr('clearable') ? '<button type=\"button\" class=\"clear\" part=\"clear\" aria-label=\"Limpar\" tabindex=\"-1\">×</button></div>' : ''}\n `);\n\n const field = this.root.querySelector<HTMLInputElement>('.field');\n if (!field) return;\n field.value = this.getAttr('value');\n if (disabled) field.setAttribute('disabled', '');\n if (readonly) field.setAttribute('readonly', '');\n\n // Cada interação emite UM `input` (v-model) + `valueChange` (Angular).\n // O `change` só existe no evento nativo de mudança/limpar.\n const notifyInput = (): void => {\n this.value = field.value;\n this.emitValueEvents();\n };\n const notifyChange = (): void => {\n this.value = field.value;\n this.dispatchEvent(\n new CustomEvent('change', {\n bubbles: true,\n composed: true,\n detail: { value: field.value },\n }),\n );\n };\n // Bloqueia o evento nativo (composed, sem detail) para que só o\n // CustomEvent com detail chegue aos consumidores.\n field.addEventListener('input', (e) => { e.stopPropagation(); notifyInput(); });\n field.addEventListener('change', (e) => { e.stopPropagation(); notifyChange(); });\n\n // Enter submete o form: o <input> interno vive no Shadow DOM e NÃO se\n // associa ao <form> do light DOM (a fronteira do shadow corta a associação\n // por árvore) — por isso a submissão implícita é acionada manualmente.\n // Ouvintes de submit no form (ex.: submit.prevent de frameworks) seguem\n // recebendo o evento normalmente.\n field.addEventListener('keydown', (e) => {\n if (e.key !== 'Enter' || e.isComposing) return;\n if (!this.form) return;\n e.preventDefault();\n this.form.requestSubmit();\n });\n\n // Clearable: botão × que limpa o campo e emite input/change vazios.\n const clearBtn = this.root.querySelector<HTMLButtonElement>('.clear');\n const syncClear = (): void => {\n clearBtn?.toggleAttribute('hidden', field.value === '');\n };\n syncClear();\n clearBtn?.addEventListener('click', () => {\n field.value = '';\n syncClear();\n this.value = '';\n this.emitValueEvents();\n this.dispatchEvent(\n new CustomEvent('change', {\n bubbles: true,\n composed: true,\n detail: { value: '' },\n }),\n );\n field.focus();\n });\n field.addEventListener('input', syncClear);\n\n // Publica name/value no form (ElementInternals) a cada render — cobre o\n // estado inicial e mudanças de atributos observados.\n this.updateFormValue();\n }\n\n /** Empurra o atributo `value` para o campo interno sem re-renderizar. */\n protected override syncInternalControl(): void {\n const field = this.root.querySelector<HTMLInputElement>('.field');\n const value = this.getAttr('value');\n const type = this.type;\n if (field && field.type !== type) field.type = type;\n if (field && field.value !== value) field.value = value;\n }\n}\n\nexport function defineFxInput(): typeof FxInput {\n return defineElement('fx-input', FxInput);\n}\n"],"names":[],"mappings":"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"}
@@ -188,7 +188,7 @@ const _FxMultiselect = class _FxMultiselect extends FxFormElement {
188
188
  <span class="count">${chips.length} selecionado${chips.length === 1 ? "" : "s"}</span>
189
189
  ${this.hasAttr("clearable") && chips.length ? '<button type="button" class="clear-all">Limpar tudo</button>' : ""}
190
190
  </div>
191
- ${this.hasAttr("searchable") ? `<input class="search" part="search" type="text" placeholder="${esc(this.getAttr("search-placeholder", "Pesquisar…"))}">` : ""}
191
+ ${this.hasAttr("searchable") ? `<input class="search" part="search" type="text" autocomplete="off" placeholder="${esc(this.getAttr("search-placeholder", "Pesquisar…"))}">` : ""}
192
192
  <ul class="list">
193
193
  ${filtered.map((o) => `
194
194
  <li><button type="button" class="opt" role="option" data-value="${esc(o.value)}"