@wrrdev/fenix-ui 1.1.6 → 1.1.7

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 (85) hide show
  1. package/README.md +7 -2
  2. package/dist/components/autocomplete/autocomplete.d.ts.map +1 -1
  3. package/dist/components/autocomplete/autocomplete.js +9 -6
  4. package/dist/components/autocomplete/autocomplete.js.map +1 -1
  5. package/dist/components/button/button.d.ts.map +1 -1
  6. package/dist/components/button/button.js +5 -3
  7. package/dist/components/button/button.js.map +1 -1
  8. package/dist/components/datepicker/datepicker.d.ts.map +1 -1
  9. package/dist/components/datepicker/datepicker.js +11 -6
  10. package/dist/components/datepicker/datepicker.js.map +1 -1
  11. package/dist/components/fileupload/fileupload.d.ts +1 -1
  12. package/dist/components/fileupload/fileupload.d.ts.map +1 -1
  13. package/dist/components/fileupload/fileupload.js +5 -3
  14. package/dist/components/fileupload/fileupload.js.map +1 -1
  15. package/dist/components/icon/icon.d.ts +40 -0
  16. package/dist/components/icon/icon.d.ts.map +1 -0
  17. package/dist/components/icon/index.d.ts +8 -0
  18. package/dist/components/icon/index.d.ts.map +1 -0
  19. package/dist/components/input/input.d.ts.map +1 -1
  20. package/dist/components/input/input.js +12 -6
  21. package/dist/components/input/input.js.map +1 -1
  22. package/dist/components/knob/knob.d.ts +1 -1
  23. package/dist/components/knob/knob.d.ts.map +1 -1
  24. package/dist/components/knob/knob.js +3 -1
  25. package/dist/components/knob/knob.js.map +1 -1
  26. package/dist/components/multiselect/multiselect.d.ts.map +1 -1
  27. package/dist/components/multiselect/multiselect.js +8 -3
  28. package/dist/components/multiselect/multiselect.js.map +1 -1
  29. package/dist/components/orderlist/orderlist.js +2 -2
  30. package/dist/components/orderlist/orderlist.js.map +1 -1
  31. package/dist/components/picklist/picklist.js +2 -2
  32. package/dist/components/picklist/picklist.js.map +1 -1
  33. package/dist/components/select/select.d.ts.map +1 -1
  34. package/dist/components/select/select.js +9 -3
  35. package/dist/components/select/select.js.map +1 -1
  36. package/dist/components/textarea/textarea.d.ts.map +1 -1
  37. package/dist/components/textarea/textarea.js +7 -3
  38. package/dist/components/textarea/textarea.js.map +1 -1
  39. package/dist/components/toggle-button-group/toggle-button-group.d.ts.map +1 -1
  40. package/dist/components/toggle-button-group/toggle-button-group.js +3 -1
  41. package/dist/components/toggle-button-group/toggle-button-group.js.map +1 -1
  42. package/dist/core/jsx.d.ts +22 -0
  43. package/dist/core/jsx.d.ts.map +1 -1
  44. package/dist/core/jsx.js.map +1 -1
  45. package/dist/core/theme.d.ts.map +1 -1
  46. package/dist/core/theme.js +12 -0
  47. package/dist/core/theme.js.map +1 -1
  48. package/dist/core/tokens.d.ts +4 -0
  49. package/dist/core/tokens.d.ts.map +1 -1
  50. package/dist/core/tokens.js +9 -1
  51. package/dist/core/tokens.js.map +1 -1
  52. package/dist/core/vue.d.ts +3 -1
  53. package/dist/core/vue.d.ts.map +1 -1
  54. package/dist/core/vue.js.map +1 -1
  55. package/dist/docs/app.d.ts.map +1 -1
  56. package/dist/docs/componentes/icon.doc.d.ts +9 -0
  57. package/dist/docs/componentes/icon.doc.d.ts.map +1 -0
  58. package/dist/docs/componentes/index.d.ts.map +1 -1
  59. package/dist/fenix-ui.umd.min.js +168 -131
  60. package/dist/fenix-ui2.esm.js.map +1 -1
  61. package/dist/fenix-ui3.esm.js +32 -5
  62. package/dist/fenix-ui3.esm.js.map +1 -1
  63. package/dist/fenix-ui4.esm.js +97 -40
  64. package/dist/fenix-ui4.esm.js.map +1 -1
  65. package/dist/fenix-ui5.esm.js +1 -0
  66. package/dist/fenix-ui5.esm.js.map +1 -1
  67. package/dist/icons/font.d.ts +26 -0
  68. package/dist/icons/font.d.ts.map +1 -0
  69. package/dist/icons/font.js +42 -0
  70. package/dist/icons/font.js.map +1 -0
  71. package/dist/icons/index.d.ts +3 -1
  72. package/dist/icons/index.d.ts.map +1 -1
  73. package/dist/icons/index.js +11 -13
  74. package/dist/icons/index.js.map +1 -1
  75. package/dist/icons/name-union.d.ts +11 -0
  76. package/dist/icons/name-union.d.ts.map +1 -0
  77. package/dist/icons/names.d.ts +0 -1
  78. package/dist/icons/names.d.ts.map +1 -1
  79. package/dist/icons/names.js.map +1 -1
  80. package/dist/icons/types.d.ts +14 -0
  81. package/dist/icons/types.d.ts.map +1 -0
  82. package/dist/plugins/auto-import.d.ts.map +1 -1
  83. package/dist/plugins/auto-import.js +1 -0
  84. package/dist/plugins/auto-import.js.map +1 -1
  85. package/package.json +5 -1
@@ -53,7 +53,15 @@ const lightTokens = {
53
53
  /** '0' desativa o efeito ripple do botão. */
54
54
  ripple: "1",
55
55
  /** Anel de foco dos campos de formulário. Use 'none' para campos sem sobra. */
56
- "focus-ring": "0 0 0 3px color-mix(in srgb, var(--fx-color-primary) 22%, transparent)"
56
+ "focus-ring": "0 0 0 3px color-mix(in srgb, var(--fx-color-primary) 22%, transparent)",
57
+ /**
58
+ * Brilho dos estados `error`/`invalid`. Acompanha `focus-ring`: quando o
59
+ * anel de foco está desligado, `applyTokens` força 'none' — o erro segue
60
+ * visível pela borda (border-color) e pela mensagem, mas sem o anel.
61
+ */
62
+ "error-ring": "0 0 0 3px color-mix(in srgb, var(--fx-color-danger, #dc2626) 18%, transparent)",
63
+ /** Brilho dos estados `success`/`valid` — acompanha `focus-ring` igualmente. */
64
+ "success-ring": "0 0 0 3px color-mix(in srgb, var(--fx-color-success, #16a34a) 18%, transparent)"
57
65
  },
58
66
  z: { base: "auto", dropdown: "1000", modal: "1100", toast: "1200" }
59
67
  };
@@ -113,6 +121,7 @@ function tokenCssVars(tokens) {
113
121
  function applyTokens(themeName, overrides, target = document.documentElement) {
114
122
  const base = themeName === "dark" ? darkTokens : defaultTokens;
115
123
  const finalTokens = deepMerge(base, overrides);
124
+ syncValidationRings(finalTokens, overrides);
116
125
  const vars = tokenCssVars(finalTokens);
117
126
  for (const [name, value] of Object.entries(vars)) {
118
127
  target.style.setProperty(name, value);
@@ -121,6 +130,17 @@ function applyTokens(themeName, overrides, target = document.documentElement) {
121
130
  window.dispatchEvent(new CustomEvent("fenix:theme", { detail: { theme: themeName, tokens: finalTokens } }));
122
131
  }
123
132
  }
133
+ const RING_OFF_VALUES = /* @__PURE__ */ new Set(["", "none", "0", "unset", "initial"]);
134
+ function syncValidationRings(tokens, overrides) {
135
+ const focusRing = String(tokens.effect["focus-ring"] ?? "").trim();
136
+ if (!RING_OFF_VALUES.has(focusRing)) return;
137
+ const explicit = (key2) => Boolean(overrides?.effect && Object.prototype.hasOwnProperty.call(overrides.effect, key2));
138
+ tokens.effect = {
139
+ ...tokens.effect,
140
+ "error-ring": explicit("error-ring") ? tokens.effect["error-ring"] : "none",
141
+ "success-ring": explicit("success-ring") ? tokens.effect["success-ring"] : "none"
142
+ };
143
+ }
124
144
  function configure(options = {}, target = document.documentElement) {
125
145
  if (options.theme) activeTheme = options.theme;
126
146
  if (options.tokens) activeOverrides = options.tokens;
@@ -419,7 +439,9 @@ _FxButton.styles = css`
419
439
  font-size: var(--fx-font-size);
420
440
  font-weight: var(--fx-font-weight);
421
441
  line-height: var(--fx-font-line-height);
422
- padding: var(--fx-space-md) var(--fx-space-xl);
442
+ /* Padding vertical limitado ao orçamento do token --fx-size-*: a altura
443
+ fica EXATAMENTE em sm 32 / md 40 / lg 48 (mesma medida dos campos). */
444
+ padding: var(--fx-space-sm) var(--fx-space-xl);
423
445
  border-radius: var(--fx-radius-md);
424
446
  border: 1px solid transparent;
425
447
  color: #fff;
@@ -442,8 +464,8 @@ _FxButton.styles = css`
442
464
 
443
465
  /* Tamanhos — alturas vindas dos tokens (personalizáveis por preset) */
444
466
  .btn { min-height: var(--fx-size-md); }
445
- :host([size='sm']) .btn { padding: var(--fx-space-sm) var(--fx-space-lg); font-size: var(--fx-font-size); min-height: var(--fx-size-sm); }
446
- :host([size='lg']) .btn { padding: var(--fx-space-lg) var(--fx-space-xl); font-size: calc(var(--fx-font-size) + 4px); min-height: var(--fx-size-lg); }
467
+ :host([size='sm']) .btn { padding: var(--fx-space-xs) var(--fx-space-lg); font-size: var(--fx-font-size); min-height: var(--fx-size-sm); }
468
+ :host([size='lg']) .btn { padding: var(--fx-space-sm) var(--fx-space-xl); font-size: calc(var(--fx-font-size) + 4px); min-height: var(--fx-size-lg); }
447
469
 
448
470
  /* Full width */
449
471
  :host([full]) .btn { width: 100%; }
@@ -781,6 +803,9 @@ _FxSelect.styles = css`
781
803
  /* Acompanha a largura definida no :host. */
782
804
  width: 100%;
783
805
  font: inherit;
806
+ /* Altura/linha determinísticas: a caixa fica no token --fx-size-*
807
+ (o line-height fixo impede que a herança da página estoure o min-height). */
808
+ line-height: var(--fx-font-line-height);
784
809
  font-weight: var(--fx-font-weight);
785
810
  color: var(--fx-text-default);
786
811
  text-align: left;
@@ -808,28 +833,31 @@ _FxSelect.styles = css`
808
833
  :host([full]) { min-width: 0; }
809
834
  :host([full]) .trigger { width: 100%; min-width: 0; }
810
835
  :host([full]) .panel { width: 100%; }
811
- /* Validação */
836
+ /* Validação — borda e brilho JÁ EM REPOUSO (igual ao fx-input); o
837
+ brilho segue --fx-effect-error-ring, que acompanha effect.focus-ring. */
812
838
  :host([error]) .trigger,
813
839
  :host([invalid]) .trigger {
814
840
  border-color: var(--fx-color-danger, #dc2626);
841
+ box-shadow: var(--fx-effect-error-ring, 0 0 0 3px color-mix(in srgb, var(--fx-color-danger, #dc2626) 18%, transparent));
815
842
  }
816
843
  :host([error]) .trigger:focus-visible,
817
844
  :host([invalid]) .trigger:focus-visible,
818
845
  :host([error][open]) .trigger,
819
846
  :host([invalid][open]) .trigger {
820
847
  border-color: var(--fx-color-danger, #dc2626);
821
- box-shadow: 0 0 0 3px color-mix(in srgb, var(--fx-color-danger, #dc2626) 18%, transparent);
848
+ box-shadow: var(--fx-effect-error-ring, 0 0 0 3px color-mix(in srgb, var(--fx-color-danger, #dc2626) 18%, transparent));
822
849
  }
823
850
  :host([success]) .trigger,
824
851
  :host([valid]) .trigger {
825
852
  border-color: var(--fx-color-success, #16a34a);
853
+ box-shadow: var(--fx-effect-success-ring, 0 0 0 3px color-mix(in srgb, var(--fx-color-success, #16a34a) 18%, transparent));
826
854
  }
827
855
  :host([success]) .trigger:focus-visible,
828
856
  :host([valid]) .trigger:focus-visible,
829
857
  :host([success][open]) .trigger,
830
858
  :host([valid][open]) .trigger {
831
859
  border-color: var(--fx-color-success, #16a34a);
832
- box-shadow: 0 0 0 3px color-mix(in srgb, var(--fx-color-success, #16a34a) 18%, transparent);
860
+ box-shadow: var(--fx-effect-success-ring, 0 0 0 3px color-mix(in srgb, var(--fx-color-success, #16a34a) 18%, transparent));
833
861
  }
834
862
  :host([disabled]) .trigger,
835
863
  .trigger[aria-disabled='true'] { opacity: 0.55; cursor: not-allowed; background-color: var(--fx-surface-surface-hover); }
@@ -1036,13 +1064,17 @@ _FxInput.styles = css`
1036
1064
  .field {
1037
1065
  font-family: inherit;
1038
1066
  font-size: inherit;
1067
+ /* Altura determinística: com line-height fixo, o padding vertical cabe no
1068
+ token --fx-size-* e a caixa fica EXATAMENTE no tamanho padrão
1069
+ (sm 32 / md 40 / lg 48), igual para todos os campos. */
1070
+ line-height: var(--fx-font-line-height);
1039
1071
  min-height: var(--fx-size-md);
1040
1072
  font-weight: var(--fx-font-weight);
1041
1073
  color: var(--fx-text-default);
1042
1074
  background-color: var(--fx-surface-background);
1043
1075
  border: 1px solid var(--fx-border-default);
1044
1076
  border-radius: var(--fx-radius-md);
1045
- padding: var(--fx-space-md) var(--fx-space-lg);
1077
+ padding: var(--fx-space-sm) var(--fx-space-lg);
1046
1078
  /* Acompanha a largura definida no :host. */
1047
1079
  width: 100%;
1048
1080
  box-sizing: border-box;
@@ -1063,25 +1095,27 @@ _FxInput.styles = css`
1063
1095
  cursor: not-allowed;
1064
1096
  background-color: var(--fx-surface-surface-hover);
1065
1097
  }
1066
- /* Validação: sobrescrevem a borda/foco via token do preset. */
1098
+ /* Validação: borda sempre; o brilho (anel) segue o token do preset
1099
+ --fx-effect-error-ring, que acompanha effect.focus-ring — anel
1100
+ desligado ⇒ erro só com a borda vermelha, ligado ⇒ soma o brilho. */
1067
1101
  :host([error]) .field,
1068
1102
  :host([invalid]) .field,
1069
1103
  :host([error]) .field:focus-visible,
1070
1104
  :host([invalid]) .field:focus-visible {
1071
1105
  border-color: var(--fx-color-danger, #dc2626);
1072
- box-shadow: 0 0 0 3px color-mix(in srgb, var(--fx-color-danger, #dc2626) 18%, transparent);
1106
+ box-shadow: var(--fx-effect-error-ring, 0 0 0 3px color-mix(in srgb, var(--fx-color-danger, #dc2626) 18%, transparent));
1073
1107
  }
1074
1108
  :host([success]) .field,
1075
1109
  :host([valid]) .field,
1076
1110
  :host([success]) .field:focus-visible,
1077
1111
  :host([valid]) .field:focus-visible {
1078
1112
  border-color: var(--fx-color-success, #16a34a);
1079
- box-shadow: 0 0 0 3px color-mix(in srgb, var(--fx-color-success, #16a34a) 18%, transparent);
1113
+ box-shadow: var(--fx-effect-success-ring, 0 0 0 3px color-mix(in srgb, var(--fx-color-success, #16a34a) 18%, transparent));
1080
1114
  }
1081
1115
  :host([size='sm']) { width: var(--fx-input-width-sm, 220px); }
1082
- :host([size='sm']) .field { padding: var(--fx-space-sm) var(--fx-space-md); font-size: var(--fx-font-size); min-height: var(--fx-size-sm); }
1116
+ :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); }
1083
1117
  :host([size='lg']) { width: var(--fx-input-width-lg, 300px); }
1084
- :host([size='lg']) .field { padding: var(--fx-space-lg) var(--fx-space-xl); font-size: calc(var(--fx-font-size) + 4px); min-height: var(--fx-size-lg); }
1118
+ :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); }
1085
1119
  /* Full width: o host estica até o pai e o campo interno acompanha
1086
1120
  (usar com um container de largura controlada, ex. w-full no Vue). */
1087
1121
  :host([full]) { display: block; width: 100%; }
@@ -1475,6 +1509,8 @@ _FxMultiselect.styles = css`
1475
1509
  min-height: var(--fx-size-md);
1476
1510
  padding: var(--fx-space-xs) var(--fx-space-md);
1477
1511
  font: inherit;
1512
+ /* Altura determinística: a caixa fica no token --fx-size-*. */
1513
+ line-height: var(--fx-font-line-height);
1478
1514
  color: var(--fx-text-default);
1479
1515
  background-color: var(--fx-surface-background);
1480
1516
  border: 1px solid var(--fx-border-default);
@@ -1500,28 +1536,31 @@ _FxMultiselect.styles = css`
1500
1536
  /* Full width: o host estica até o pai e o trigger acompanha. */
1501
1537
  :host([full]) { display: block; width: 100%; }
1502
1538
  :host([full]) .trigger { width: 100%; }
1503
- /* Validação */
1539
+ /* Validação — borda e brilho JÁ EM REPOUSO (igual ao fx-input); o brilho
1540
+ segue o token --fx-effect-error-ring, que acompanha effect.focus-ring. */
1504
1541
  :host([error]) .trigger,
1505
1542
  :host([invalid]) .trigger {
1506
1543
  border-color: var(--fx-color-danger, #dc2626);
1544
+ box-shadow: var(--fx-effect-error-ring, 0 0 0 3px color-mix(in srgb, var(--fx-color-danger, #dc2626) 18%, transparent));
1507
1545
  }
1508
1546
  :host([error]) .trigger:focus-visible,
1509
1547
  :host([invalid]) .trigger:focus-visible,
1510
1548
  :host([error][open]) .trigger,
1511
1549
  :host([invalid][open]) .trigger {
1512
1550
  border-color: var(--fx-color-danger, #dc2626);
1513
- box-shadow: 0 0 0 3px color-mix(in srgb, var(--fx-color-danger, #dc2626) 18%, transparent);
1551
+ box-shadow: var(--fx-effect-error-ring, 0 0 0 3px color-mix(in srgb, var(--fx-color-danger, #dc2626) 18%, transparent));
1514
1552
  }
1515
1553
  :host([success]) .trigger,
1516
1554
  :host([valid]) .trigger {
1517
1555
  border-color: var(--fx-color-success, #16a34a);
1556
+ box-shadow: var(--fx-effect-success-ring, 0 0 0 3px color-mix(in srgb, var(--fx-color-success, #16a34a) 18%, transparent));
1518
1557
  }
1519
1558
  :host([success]) .trigger:focus-visible,
1520
1559
  :host([valid]) .trigger:focus-visible,
1521
1560
  :host([success][open]) .trigger,
1522
1561
  :host([valid][open]) .trigger {
1523
1562
  border-color: var(--fx-color-success, #16a34a);
1524
- box-shadow: 0 0 0 3px color-mix(in srgb, var(--fx-color-success, #16a34a) 18%, transparent);
1563
+ box-shadow: var(--fx-effect-success-ring, 0 0 0 3px color-mix(in srgb, var(--fx-color-success, #16a34a) 18%, transparent));
1525
1564
  }
1526
1565
  .trigger:hover { border-color: var(--fx-border-hover); }
1527
1566
  .trigger:focus-visible {
@@ -2423,6 +2462,8 @@ _FxDatepicker.styles = css`
2423
2462
  min-height: var(--fx-size-md, 40px);
2424
2463
  min-width: 150px;
2425
2464
  padding: var(--fx-space-xs) var(--fx-space-md);
2465
+ /* Altura determinística: a caixa fica EXATAMENTE no token --fx-size-*. */
2466
+ line-height: var(--fx-font-line-height);
2426
2467
  background-color: var(--fx-surface-background);
2427
2468
  border: 1px solid var(--fx-border-default);
2428
2469
  border-radius: var(--fx-radius-md);
@@ -2431,9 +2472,9 @@ _FxDatepicker.styles = css`
2431
2472
  border-color var(--fx-motion-duration-normal) var(--fx-motion-easing),
2432
2473
  box-shadow var(--fx-motion-duration-normal) var(--fx-motion-easing);
2433
2474
  }
2434
- :host([size='sm']) .field { min-height: 32px; min-width: 180px; }
2435
- :host([size='md']) .field { min-height: 40px; }
2436
- :host([size='lg']) .field { min-height: 48px; min-width: 220px; font-size: calc(var(--fx-font-size) + 4px); }
2475
+ :host([size='sm']) .field { min-height: var(--fx-size-sm); min-width: 180px; }
2476
+ :host([size='md']) .field { min-height: var(--fx-size-md); }
2477
+ :host([size='lg']) .field { min-height: var(--fx-size-lg); min-width: 220px; font-size: calc(var(--fx-font-size) + 4px); }
2437
2478
  /* Range e multiple exibem mais de uma data: campo mais largo */
2438
2479
  :host([mode='range']) .field { min-width: 250px; }
2439
2480
  :host([mode='multiple']) .field { min-width: 220px; }
@@ -2444,28 +2485,31 @@ _FxDatepicker.styles = css`
2444
2485
  descartados para permitir layouts estreitos sob controle do pai). */
2445
2486
  :host([full]) { display: block; width: 100%; }
2446
2487
  :host([full]) .field { min-width: 0; }
2447
- /* Validação */
2488
+ /* Validação — borda e brilho JÁ EM REPOUSO (igual ao fx-input); o brilho
2489
+ segue o token --fx-effect-error-ring, que acompanha effect.focus-ring. */
2448
2490
  :host([error]) .field,
2449
2491
  :host([invalid]) .field {
2450
2492
  border-color: var(--fx-color-danger, #dc2626);
2493
+ box-shadow: var(--fx-effect-error-ring, 0 0 0 3px color-mix(in srgb, var(--fx-color-danger, #dc2626) 18%, transparent));
2451
2494
  }
2452
2495
  :host([error]) .field:focus-within,
2453
2496
  :host([invalid]) .field:focus-within,
2454
2497
  :host([error][open]) .field,
2455
2498
  :host([invalid][open]) .field {
2456
2499
  border-color: var(--fx-color-danger, #dc2626);
2457
- box-shadow: 0 0 0 3px color-mix(in srgb, var(--fx-color-danger, #dc2626) 18%, transparent);
2500
+ box-shadow: var(--fx-effect-error-ring, 0 0 0 3px color-mix(in srgb, var(--fx-color-danger, #dc2626) 18%, transparent));
2458
2501
  }
2459
2502
  :host([success]) .field,
2460
2503
  :host([valid]) .field {
2461
2504
  border-color: var(--fx-color-success, #16a34a);
2505
+ box-shadow: var(--fx-effect-success-ring, 0 0 0 3px color-mix(in srgb, var(--fx-color-success, #16a34a) 18%, transparent));
2462
2506
  }
2463
2507
  :host([success]) .field:focus-within,
2464
2508
  :host([valid]) .field:focus-within,
2465
2509
  :host([success][open]) .field,
2466
2510
  :host([valid][open]) .field {
2467
2511
  border-color: var(--fx-color-success, #16a34a);
2468
- box-shadow: 0 0 0 3px color-mix(in srgb, var(--fx-color-success, #16a34a) 18%, transparent);
2512
+ box-shadow: var(--fx-effect-success-ring, 0 0 0 3px color-mix(in srgb, var(--fx-color-success, #16a34a) 18%, transparent));
2469
2513
  }
2470
2514
  .field:hover { border-color: var(--fx-border-hover); }
2471
2515
  .field:focus-within {
@@ -4140,6 +4184,8 @@ _FxTextarea.styles = css`
4140
4184
  .field {
4141
4185
  font-family: inherit;
4142
4186
  font-size: inherit;
4187
+ /* Altura determinística: a caixa fica EXATAMENTE no token --fx-size-*. */
4188
+ line-height: var(--fx-font-line-height);
4143
4189
  font-weight: var(--fx-font-weight);
4144
4190
  color: var(--fx-text-default);
4145
4191
  background-color: var(--fx-surface-background);
@@ -4168,16 +4214,18 @@ _FxTextarea.styles = css`
4168
4214
  cursor: not-allowed;
4169
4215
  background-color: var(--fx-surface-surface-hover);
4170
4216
  }
4217
+ /* Validação: borda sempre; brilho (anel) via token que acompanha
4218
+ effect.focus-ring — desligado ⇒ erro só com a borda vermelha. */
4171
4219
  :host([error]) .field, :host([invalid]) .field {
4172
4220
  border-color: var(--fx-color-danger, #dc2626);
4173
- box-shadow: 0 0 0 3px color-mix(in srgb, var(--fx-color-danger, #dc2626) 18%, transparent);
4221
+ box-shadow: var(--fx-effect-error-ring, 0 0 0 3px color-mix(in srgb, var(--fx-color-danger, #dc2626) 18%, transparent));
4174
4222
  }
4175
4223
  :host([success]) .field, :host([valid]) .field {
4176
4224
  border-color: var(--fx-color-success, #16a34a);
4177
- box-shadow: 0 0 0 3px color-mix(in srgb, var(--fx-color-success, #16a34a) 18%, transparent);
4225
+ box-shadow: var(--fx-effect-success-ring, 0 0 0 3px color-mix(in srgb, var(--fx-color-success, #16a34a) 18%, transparent));
4178
4226
  }
4179
4227
  :host([size='sm']) { width: var(--fx-textarea-width-sm, 220px); }
4180
- :host([size='sm']) .field { min-height: var(--fx-size-sm); padding: var(--fx-space-sm) var(--fx-space-md); }
4228
+ :host([size='sm']) .field { min-height: var(--fx-size-sm); padding: var(--fx-space-xs) var(--fx-space-md); }
4181
4229
  :host([size='lg']) { width: var(--fx-textarea-width-lg, 300px); }
4182
4230
  :host([size='lg']) .field { min-height: calc(var(--fx-size-lg) + 80px); }
4183
4231
  /* Full width: o host estica até o pai e o campo interno acompanha. */
@@ -4824,10 +4872,12 @@ _FxFileUpload.styles = css`
4824
4872
  o botão sem precisar do full (host é shrink-to-fit por padrão). */
4825
4873
  width: 100%;
4826
4874
  min-height: var(--fx-size-md);
4827
- padding: var(--fx-space-md) var(--fx-space-lg);
4875
+ /* Padding vertical no orçamento do token --fx-size-* ⇒ altura padrão. */
4876
+ padding: var(--fx-space-sm) var(--fx-space-lg);
4828
4877
  font-family: inherit;
4829
4878
  font-size: inherit;
4830
4879
  font-weight: var(--fx-font-weight);
4880
+ line-height: var(--fx-font-line-height);
4831
4881
  color: var(--fx-text-default);
4832
4882
  background-color: var(--fx-surface-background);
4833
4883
  border: 1px solid var(--fx-border-default);
@@ -4854,8 +4904,8 @@ _FxFileUpload.styles = css`
4854
4904
  :host([severity='info']) .btn { background: var(--fx-color-info); border-color: transparent; color: #fff; }
4855
4905
  :host([severity]) .btn:hover { filter: brightness(0.88); }
4856
4906
  :host([severity]) .btn:focus-visible { border-color: transparent; }
4857
- :host([size='sm']) .btn { min-height: var(--fx-size-sm); padding: var(--fx-space-sm) var(--fx-space-md); font-size: calc(var(--fx-font-size) - 2px); }
4858
- :host([size='lg']) .btn { min-height: var(--fx-size-lg); padding: var(--fx-space-lg) var(--fx-space-xl); font-size: calc(var(--fx-font-size) + 4px); }
4907
+ :host([size='sm']) .btn { min-height: var(--fx-size-sm); padding: var(--fx-space-xs) var(--fx-space-md); font-size: calc(var(--fx-font-size) - 2px); }
4908
+ :host([size='lg']) .btn { min-height: var(--fx-size-lg); padding: var(--fx-space-sm) var(--fx-space-xl); font-size: calc(var(--fx-font-size) + 4px); }
4859
4909
  :host([size='sm']) .drop { min-height: 72px; }
4860
4910
  :host([size='lg']) .drop { min-height: 132px; }
4861
4911
 
@@ -6303,6 +6353,8 @@ _FxToggleButtonGroup.styles = css`
6303
6353
  min-height: var(--fx-size-md);
6304
6354
  padding: var(--fx-space-sm) var(--fx-space-lg);
6305
6355
  font-weight: var(--fx-font-weight);
6356
+ /* Altura determinística: a caixa fica EXATAMENTE no token --fx-size-*. */
6357
+ line-height: var(--fx-font-line-height);
6306
6358
  color: var(--fx-text-default);
6307
6359
  background: var(--fx-surface-background);
6308
6360
  border: 1px solid var(--fx-border-default);
@@ -6312,7 +6364,7 @@ _FxToggleButtonGroup.styles = css`
6312
6364
  transition: background var(--fx-motion-duration-fast) var(--fx-motion-easing), border-color var(--fx-motion-duration-fast) var(--fx-motion-easing), color var(--fx-motion-duration-fast) var(--fx-motion-easing);
6313
6365
  }
6314
6366
  :host([size='sm']) .option { min-height: var(--fx-size-sm); padding: var(--fx-space-xs) var(--fx-space-md); font-size: calc(var(--fx-font-size) - 2px); }
6315
- :host([size='lg']) .option { min-height: var(--fx-size-lg); padding: var(--fx-space-md) var(--fx-space-xl); font-size: calc(var(--fx-font-size) + 2px); }
6367
+ :host([size='lg']) .option { min-height: var(--fx-size-lg); padding: var(--fx-space-sm) var(--fx-space-xl); font-size: calc(var(--fx-font-size) + 2px); }
6316
6368
  .option:hover { border-color: var(--fx-color-primary); }
6317
6369
  .option.active {
6318
6370
  background: var(--fx-color-primary);
@@ -8515,12 +8567,14 @@ _FxAutocomplete.styles = css`
8515
8567
  .field {
8516
8568
  font-family: inherit;
8517
8569
  font-size: inherit;
8570
+ /* Altura determinística: a caixa fica EXATAMENTE no token --fx-size-*. */
8571
+ line-height: var(--fx-font-line-height);
8518
8572
  font-weight: var(--fx-font-weight);
8519
8573
  color: var(--fx-text-default);
8520
8574
  background-color: var(--fx-surface-background);
8521
8575
  border: 1px solid var(--fx-border-default);
8522
8576
  border-radius: var(--fx-radius-md);
8523
- padding: var(--fx-space-md) var(--fx-space-lg);
8577
+ padding: var(--fx-space-sm) var(--fx-space-lg);
8524
8578
  /* Acompanha a largura definida no :host. */
8525
8579
  width: 100%;
8526
8580
  min-height: var(--fx-size-md);
@@ -8537,22 +8591,23 @@ _FxAutocomplete.styles = css`
8537
8591
  box-shadow: var(--fx-effect-focus-ring, none);
8538
8592
  }
8539
8593
  :host([size='sm']) { width: var(--fx-autocomplete-width-sm, 220px); }
8540
- :host([size='sm']) .field { min-height: var(--fx-size-sm); padding: var(--fx-space-sm) var(--fx-space-md); }
8594
+ :host([size='sm']) .field { min-height: var(--fx-size-sm); padding: var(--fx-space-xs) var(--fx-space-md); }
8541
8595
  :host([size='lg']) { width: var(--fx-autocomplete-width-lg, 300px); }
8542
- :host([size='lg']) .field { min-height: var(--fx-size-lg); }
8596
+ :host([size='lg']) .field { min-height: var(--fx-size-lg); padding: var(--fx-space-sm) var(--fx-space-lg); }
8543
8597
  /* Full width: o host estica até o pai e o campo interno acompanha. */
8544
8598
  :host([full]) { display: block; width: 100%; }
8545
8599
  :host([full]) .field { width: 100%; }
8546
- /* Validação: sobrescrevem a borda/foco via token do preset. */
8600
+ /* Validação: borda sempre; brilho (anel) via token que acompanha
8601
+ effect.focus-ring — desligado ⇒ erro só com a borda vermelha. */
8547
8602
  :host([error]) .field,
8548
8603
  :host([invalid]) .field {
8549
8604
  border-color: var(--fx-color-danger, #dc2626);
8550
- box-shadow: 0 0 0 3px color-mix(in srgb, var(--fx-color-danger, #dc2626) 18%, transparent);
8605
+ box-shadow: var(--fx-effect-error-ring, 0 0 0 3px color-mix(in srgb, var(--fx-color-danger, #dc2626) 18%, transparent));
8551
8606
  }
8552
8607
  :host([success]) .field,
8553
8608
  :host([valid]) .field {
8554
8609
  border-color: var(--fx-color-success, #16a34a);
8555
- box-shadow: 0 0 0 3px color-mix(in srgb, var(--fx-color-success, #16a34a) 18%, transparent);
8610
+ box-shadow: var(--fx-effect-success-ring, 0 0 0 3px color-mix(in srgb, var(--fx-color-success, #16a34a) 18%, transparent));
8556
8611
  }
8557
8612
  .list {
8558
8613
  position: absolute;
@@ -8909,7 +8964,9 @@ _FxKnob.styles = css`
8909
8964
  outline: none;
8910
8965
  }
8911
8966
  .knob:focus-visible svg {
8912
- filter: drop-shadow(var(--fx-effect-focus-ring, 0 0 0 3px color-mix(in srgb, var(--fx-color-primary) 22%, transparent)));
8967
+ /* Mesmo fallback none dos demais componentes: sem motor de tema (ou com
8968
+ effect.focus-ring desligado) não há anel de foco. */
8969
+ filter: drop-shadow(var(--fx-effect-focus-ring, none));
8913
8970
  }
8914
8971
  `;
8915
8972
  let FxKnob = _FxKnob;
@@ -9515,7 +9572,7 @@ _FxOrderList.styles = css`
9515
9572
  .select-all-bar input[type="checkbox"] { width: 18px; height: 18px; accent-color: var(--orderlist-primary); cursor: pointer; }
9516
9573
  .filter-wrapper { margin-bottom: var(--fx-space-xs, 4px); }
9517
9574
  .filter-input { width: 100%; padding: var(--fx-space-sm, 10px) var(--fx-space-md, 14px); padding-left: 42px; border: 1.5px solid var(--orderlist-border); border-radius: var(--orderlist-radius); font-family: inherit; font-size: inherit; color: var(--orderlist-text); background: var(--orderlist-bg) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E") no-repeat 14px center; transition: var(--orderlist-transition); }
9518
- .filter-input:focus { outline: none; border-color: var(--orderlist-primary); box-shadow: 0 0 0 3px color-mix(in srgb, var(--orderlist-primary) 20%, transparent); }
9575
+ .filter-input:focus { outline: none; border-color: var(--orderlist-primary); box-shadow: var(--fx-effect-focus-ring, none); }
9519
9576
  .filter-input::placeholder { color: var(--orderlist-text-muted); }
9520
9577
  .main-row { display: flex; align-items: stretch; gap: var(--fx-space-sm, 8px); }
9521
9578
  .list { list-style: none; margin: 0; padding: 0; border: 1px solid var(--orderlist-border); border-radius: var(--orderlist-radius); overflow: hidden; box-shadow: var(--orderlist-shadow); max-height: 450px; overflow-y: auto; flex: 1; }
@@ -9558,7 +9615,7 @@ _FxOrderList.styles = css`
9558
9615
  button.control-btn { display: flex; align-items: center; justify-content: center; width: 42px; height: 38px; padding: 0; border: none; border-radius: 8px; background: transparent; color: var(--orderlist-text-muted); cursor: pointer; font-size: 16px; line-height: 1; transition: var(--orderlist-transition); position: relative; }
9559
9616
  button.control-btn:hover:not(:disabled) { background: var(--orderlist-bg-hover); color: var(--orderlist-primary); transform: scale(1.1); }
9560
9617
  button.control-btn:active:not(:disabled) { transform: scale(0.92); background: color-mix(in srgb, var(--orderlist-primary) 15%, transparent); }
9561
- button.control-btn:focus-visible { outline: none; box-shadow: 0 0 0 3px color-mix(in srgb, var(--orderlist-primary) 30%, transparent); }
9618
+ button.control-btn:focus-visible { outline: none; box-shadow: var(--fx-effect-focus-ring, none); }
9562
9619
  button.control-btn:disabled { opacity: 0.3; cursor: not-allowed; transform: none; }
9563
9620
  .control-btn-icon { font-size: 18px; line-height: 1; }
9564
9621
  /* Tooltip nos botoes */
@@ -10169,7 +10226,7 @@ _FxPickList.styles = css`
10169
10226
  .filter-input:focus {
10170
10227
  outline: none;
10171
10228
  border-color: var(--picklist-primary);
10172
- box-shadow: 0 0 0 3px color-mix(in srgb, var(--picklist-primary) 20%, transparent);
10229
+ box-shadow: var(--fx-effect-focus-ring, none);
10173
10230
  }
10174
10231
  .filter-input::placeholder {
10175
10232
  color: var(--picklist-text-muted);
@@ -10266,7 +10323,7 @@ _FxPickList.styles = css`
10266
10323
  }
10267
10324
  button.control-btn:focus-visible {
10268
10325
  outline: none;
10269
- box-shadow: 0 0 0 3px color-mix(in srgb, var(--picklist-primary) 30%, transparent);
10326
+ box-shadow: var(--fx-effect-focus-ring, none);
10270
10327
  }
10271
10328
  button.control-btn:disabled {
10272
10329
  opacity: 0.3;