@wrrdev/fenix-ui 1.0.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 (247) hide show
  1. package/README.md +117 -0
  2. package/dist/cdn.d.ts +6 -0
  3. package/dist/cdn.d.ts.map +1 -0
  4. package/dist/components/alert/alert.d.ts +14 -0
  5. package/dist/components/alert/alert.d.ts.map +1 -0
  6. package/dist/components/alert/alert.js +74 -0
  7. package/dist/components/alert/alert.js.map +1 -0
  8. package/dist/components/alert/index.d.ts +8 -0
  9. package/dist/components/alert/index.d.ts.map +1 -0
  10. package/dist/components/alert/index.js +7 -0
  11. package/dist/components/alert/index.js.map +1 -0
  12. package/dist/components/autocomplete/autocomplete.d.ts +20 -0
  13. package/dist/components/autocomplete/autocomplete.d.ts.map +1 -0
  14. package/dist/components/autocomplete/autocomplete.js +144 -0
  15. package/dist/components/autocomplete/autocomplete.js.map +1 -0
  16. package/dist/components/autocomplete/index.d.ts +8 -0
  17. package/dist/components/autocomplete/index.d.ts.map +1 -0
  18. package/dist/components/autocomplete/index.js +7 -0
  19. package/dist/components/autocomplete/index.js.map +1 -0
  20. package/dist/components/badge/badge.d.ts +14 -0
  21. package/dist/components/badge/badge.d.ts.map +1 -0
  22. package/dist/components/badge/badge.js +46 -0
  23. package/dist/components/badge/badge.js.map +1 -0
  24. package/dist/components/badge/index.d.ts +2 -0
  25. package/dist/components/badge/index.d.ts.map +1 -0
  26. package/dist/components/badge/index.js +7 -0
  27. package/dist/components/badge/index.js.map +1 -0
  28. package/dist/components/button/button.d.ts +30 -0
  29. package/dist/components/button/button.d.ts.map +1 -0
  30. package/dist/components/button/button.js +194 -0
  31. package/dist/components/button/button.js.map +1 -0
  32. package/dist/components/button/index.d.ts +2 -0
  33. package/dist/components/button/index.d.ts.map +1 -0
  34. package/dist/components/button/index.js +7 -0
  35. package/dist/components/button/index.js.map +1 -0
  36. package/dist/components/calendar/calendar.d.ts +39 -0
  37. package/dist/components/calendar/calendar.d.ts.map +1 -0
  38. package/dist/components/calendar/calendar.js +346 -0
  39. package/dist/components/calendar/calendar.js.map +1 -0
  40. package/dist/components/calendar/index.d.ts +2 -0
  41. package/dist/components/calendar/index.d.ts.map +1 -0
  42. package/dist/components/calendar/index.js +7 -0
  43. package/dist/components/calendar/index.js.map +1 -0
  44. package/dist/components/checkbox/checkbox.d.ts +24 -0
  45. package/dist/components/checkbox/checkbox.d.ts.map +1 -0
  46. package/dist/components/checkbox/checkbox.js +142 -0
  47. package/dist/components/checkbox/checkbox.js.map +1 -0
  48. package/dist/components/checkbox/index.d.ts +2 -0
  49. package/dist/components/checkbox/index.d.ts.map +1 -0
  50. package/dist/components/checkbox/index.js +7 -0
  51. package/dist/components/checkbox/index.js.map +1 -0
  52. package/dist/components/datepicker/datepicker.d.ts +62 -0
  53. package/dist/components/datepicker/datepicker.d.ts.map +1 -0
  54. package/dist/components/datepicker/datepicker.js +441 -0
  55. package/dist/components/datepicker/datepicker.js.map +1 -0
  56. package/dist/components/datepicker/index.d.ts +3 -0
  57. package/dist/components/datepicker/index.d.ts.map +1 -0
  58. package/dist/components/datepicker/index.js +8 -0
  59. package/dist/components/datepicker/index.js.map +1 -0
  60. package/dist/components/dialog/dialog.d.ts +19 -0
  61. package/dist/components/dialog/dialog.d.ts.map +1 -0
  62. package/dist/components/dialog/dialog.js +134 -0
  63. package/dist/components/dialog/dialog.js.map +1 -0
  64. package/dist/components/dialog/index.d.ts +8 -0
  65. package/dist/components/dialog/index.d.ts.map +1 -0
  66. package/dist/components/dialog/index.js +7 -0
  67. package/dist/components/dialog/index.js.map +1 -0
  68. package/dist/components/drawer/drawer.d.ts +27 -0
  69. package/dist/components/drawer/drawer.d.ts.map +1 -0
  70. package/dist/components/drawer/drawer.js +195 -0
  71. package/dist/components/drawer/drawer.js.map +1 -0
  72. package/dist/components/drawer/index.d.ts +8 -0
  73. package/dist/components/drawer/index.d.ts.map +1 -0
  74. package/dist/components/drawer/index.js +7 -0
  75. package/dist/components/drawer/index.js.map +1 -0
  76. package/dist/components/dropdown/dropdown.d.ts +28 -0
  77. package/dist/components/dropdown/dropdown.d.ts.map +1 -0
  78. package/dist/components/dropdown/dropdown.js +137 -0
  79. package/dist/components/dropdown/dropdown.js.map +1 -0
  80. package/dist/components/dropdown/index.d.ts +9 -0
  81. package/dist/components/dropdown/index.d.ts.map +1 -0
  82. package/dist/components/dropdown/index.js +9 -0
  83. package/dist/components/dropdown/index.js.map +1 -0
  84. package/dist/components/floatlabel/floatlabel.d.ts +42 -0
  85. package/dist/components/floatlabel/floatlabel.d.ts.map +1 -0
  86. package/dist/components/floatlabel/floatlabel.js +270 -0
  87. package/dist/components/floatlabel/floatlabel.js.map +1 -0
  88. package/dist/components/floatlabel/index.d.ts +2 -0
  89. package/dist/components/floatlabel/index.d.ts.map +1 -0
  90. package/dist/components/floatlabel/index.js +7 -0
  91. package/dist/components/floatlabel/index.js.map +1 -0
  92. package/dist/components/input/index.d.ts +2 -0
  93. package/dist/components/input/index.d.ts.map +1 -0
  94. package/dist/components/input/index.js +7 -0
  95. package/dist/components/input/index.js.map +1 -0
  96. package/dist/components/input/input.d.ts +22 -0
  97. package/dist/components/input/input.d.ts.map +1 -0
  98. package/dist/components/input/input.js +169 -0
  99. package/dist/components/input/input.js.map +1 -0
  100. package/dist/components/multiselect/index.d.ts +2 -0
  101. package/dist/components/multiselect/index.d.ts.map +1 -0
  102. package/dist/components/multiselect/index.js +7 -0
  103. package/dist/components/multiselect/index.js.map +1 -0
  104. package/dist/components/multiselect/multiselect.d.ts +32 -0
  105. package/dist/components/multiselect/multiselect.d.ts.map +1 -0
  106. package/dist/components/multiselect/multiselect.js +389 -0
  107. package/dist/components/multiselect/multiselect.js.map +1 -0
  108. package/dist/components/pagination/index.d.ts +8 -0
  109. package/dist/components/pagination/index.d.ts.map +1 -0
  110. package/dist/components/pagination/index.js +7 -0
  111. package/dist/components/pagination/index.js.map +1 -0
  112. package/dist/components/pagination/pagination.d.ts +23 -0
  113. package/dist/components/pagination/pagination.d.ts.map +1 -0
  114. package/dist/components/pagination/pagination.js +121 -0
  115. package/dist/components/pagination/pagination.js.map +1 -0
  116. package/dist/components/progress/index.d.ts +8 -0
  117. package/dist/components/progress/index.d.ts.map +1 -0
  118. package/dist/components/progress/index.js +7 -0
  119. package/dist/components/progress/index.js.map +1 -0
  120. package/dist/components/progress/progress.d.ts +18 -0
  121. package/dist/components/progress/progress.d.ts.map +1 -0
  122. package/dist/components/progress/progress.js +99 -0
  123. package/dist/components/progress/progress.js.map +1 -0
  124. package/dist/components/radio/index.d.ts +2 -0
  125. package/dist/components/radio/index.d.ts.map +1 -0
  126. package/dist/components/radio/index.js +7 -0
  127. package/dist/components/radio/index.js.map +1 -0
  128. package/dist/components/radio/radio.d.ts +23 -0
  129. package/dist/components/radio/radio.d.ts.map +1 -0
  130. package/dist/components/radio/radio.js +133 -0
  131. package/dist/components/radio/radio.js.map +1 -0
  132. package/dist/components/select/index.d.ts +2 -0
  133. package/dist/components/select/index.d.ts.map +1 -0
  134. package/dist/components/select/index.js +7 -0
  135. package/dist/components/select/index.js.map +1 -0
  136. package/dist/components/select/select.d.ts +36 -0
  137. package/dist/components/select/select.d.ts.map +1 -0
  138. package/dist/components/select/select.js +287 -0
  139. package/dist/components/select/select.js.map +1 -0
  140. package/dist/components/skeleton/index.d.ts +8 -0
  141. package/dist/components/skeleton/index.d.ts.map +1 -0
  142. package/dist/components/skeleton/index.js +7 -0
  143. package/dist/components/skeleton/index.js.map +1 -0
  144. package/dist/components/skeleton/skeleton.d.ts +13 -0
  145. package/dist/components/skeleton/skeleton.d.ts.map +1 -0
  146. package/dist/components/skeleton/skeleton.js +57 -0
  147. package/dist/components/skeleton/skeleton.js.map +1 -0
  148. package/dist/components/spinner/index.d.ts +2 -0
  149. package/dist/components/spinner/index.d.ts.map +1 -0
  150. package/dist/components/spinner/index.js +7 -0
  151. package/dist/components/spinner/index.js.map +1 -0
  152. package/dist/components/spinner/spinner.d.ts +16 -0
  153. package/dist/components/spinner/spinner.d.ts.map +1 -0
  154. package/dist/components/spinner/spinner.js +50 -0
  155. package/dist/components/spinner/spinner.js.map +1 -0
  156. package/dist/components/switch/index.d.ts +2 -0
  157. package/dist/components/switch/index.d.ts.map +1 -0
  158. package/dist/components/switch/index.js +7 -0
  159. package/dist/components/switch/index.js.map +1 -0
  160. package/dist/components/switch/switch.d.ts +22 -0
  161. package/dist/components/switch/switch.d.ts.map +1 -0
  162. package/dist/components/switch/switch.js +115 -0
  163. package/dist/components/switch/switch.js.map +1 -0
  164. package/dist/components/table/index.d.ts +2 -0
  165. package/dist/components/table/index.d.ts.map +1 -0
  166. package/dist/components/table/index.js +7 -0
  167. package/dist/components/table/index.js.map +1 -0
  168. package/dist/components/table/table.d.ts +38 -0
  169. package/dist/components/table/table.d.ts.map +1 -0
  170. package/dist/components/table/table.js +258 -0
  171. package/dist/components/table/table.js.map +1 -0
  172. package/dist/components/tabs/index.d.ts +9 -0
  173. package/dist/components/tabs/index.d.ts.map +1 -0
  174. package/dist/components/tabs/index.js +9 -0
  175. package/dist/components/tabs/index.js.map +1 -0
  176. package/dist/components/tabs/tabs.d.ts +38 -0
  177. package/dist/components/tabs/tabs.d.ts.map +1 -0
  178. package/dist/components/tabs/tabs.js +162 -0
  179. package/dist/components/tabs/tabs.js.map +1 -0
  180. package/dist/components/textarea/index.d.ts +8 -0
  181. package/dist/components/textarea/index.d.ts.map +1 -0
  182. package/dist/components/textarea/index.js +7 -0
  183. package/dist/components/textarea/index.js.map +1 -0
  184. package/dist/components/textarea/textarea.d.ts +19 -0
  185. package/dist/components/textarea/textarea.d.ts.map +1 -0
  186. package/dist/components/textarea/textarea.js +109 -0
  187. package/dist/components/textarea/textarea.js.map +1 -0
  188. package/dist/components/toast/index.d.ts +8 -0
  189. package/dist/components/toast/index.d.ts.map +1 -0
  190. package/dist/components/toast/index.js +8 -0
  191. package/dist/components/toast/index.js.map +1 -0
  192. package/dist/components/toast/toast.d.ts +40 -0
  193. package/dist/components/toast/toast.d.ts.map +1 -0
  194. package/dist/components/toast/toast.js +176 -0
  195. package/dist/components/toast/toast.js.map +1 -0
  196. package/dist/components/tooltip/index.d.ts +8 -0
  197. package/dist/components/tooltip/index.d.ts.map +1 -0
  198. package/dist/components/tooltip/index.js +7 -0
  199. package/dist/components/tooltip/index.js.map +1 -0
  200. package/dist/components/tooltip/tooltip.d.ts +14 -0
  201. package/dist/components/tooltip/tooltip.d.ts.map +1 -0
  202. package/dist/components/tooltip/tooltip.js +86 -0
  203. package/dist/components/tooltip/tooltip.js.map +1 -0
  204. package/dist/core/base.d.ts +29 -0
  205. package/dist/core/base.d.ts.map +1 -0
  206. package/dist/core/base.js +41 -0
  207. package/dist/core/base.js.map +1 -0
  208. package/dist/core/css.d.ts +6 -0
  209. package/dist/core/css.d.ts.map +1 -0
  210. package/dist/core/css.js +11 -0
  211. package/dist/core/css.js.map +1 -0
  212. package/dist/core/define.d.ts +8 -0
  213. package/dist/core/define.d.ts.map +1 -0
  214. package/dist/core/define.js +10 -0
  215. package/dist/core/define.js.map +1 -0
  216. package/dist/core/presets.d.ts +40 -0
  217. package/dist/core/presets.d.ts.map +1 -0
  218. package/dist/core/presets.js +80 -0
  219. package/dist/core/presets.js.map +1 -0
  220. package/dist/core/theme.d.ts +47 -0
  221. package/dist/core/theme.d.ts.map +1 -0
  222. package/dist/core/theme.js +76 -0
  223. package/dist/core/theme.js.map +1 -0
  224. package/dist/core/tokens.d.ts +36 -0
  225. package/dist/core/tokens.d.ts.map +1 -0
  226. package/dist/core/tokens.js +83 -0
  227. package/dist/core/tokens.js.map +1 -0
  228. package/dist/docs/app.d.ts +37 -0
  229. package/dist/docs/app.d.ts.map +1 -0
  230. package/dist/fenix-ui.esm.js +4471 -0
  231. package/dist/fenix-ui.esm.js.map +1 -0
  232. package/dist/fenix-ui.umd.min.js +2022 -0
  233. package/dist/fenix-ui2.esm.js +82 -0
  234. package/dist/fenix-ui2.esm.js.map +1 -0
  235. package/dist/index.d.ts +39 -0
  236. package/dist/index.d.ts.map +1 -0
  237. package/dist/index.js +107 -0
  238. package/dist/index.js.map +1 -0
  239. package/dist/plugins/auto-import.d.ts +18 -0
  240. package/dist/plugins/auto-import.d.ts.map +1 -0
  241. package/dist/plugins/auto-import.js +69 -0
  242. package/dist/plugins/auto-import.js.map +1 -0
  243. package/dist/plugins/index.d.ts +25 -0
  244. package/dist/plugins/index.d.ts.map +1 -0
  245. package/dist/plugins/index.js +21 -0
  246. package/dist/plugins/index.js.map +1 -0
  247. package/package.json +169 -0
@@ -0,0 +1,287 @@
1
+ import { FxElement } from "../../core/base.js";
2
+ import { css } from "../../core/css.js";
3
+ import { defineElement } from "../../core/define.js";
4
+ const _FxSelect = class _FxSelect extends FxElement {
5
+ // `value` fica FORA da observação: refleti-lo no change não pode
6
+ // re-renderizar o template e fechar o dropdown.
7
+ static get observedAttributes() {
8
+ return ["size", "disabled", "placeholder", "searchable", "clearable", "error", "success"];
9
+ }
10
+ /** Tamanho do campo. Padrão: `'md'`. */
11
+ get size() {
12
+ const s = this.getAttr("size", "md");
13
+ return s === "sm" || s === "lg" ? s : "md";
14
+ }
15
+ set size(value) {
16
+ this.setAttribute("size", value);
17
+ }
18
+ get value() {
19
+ return this.getAttr("value");
20
+ }
21
+ set value(value) {
22
+ this.setAttribute("value", value);
23
+ }
24
+ get disabled() {
25
+ return this.hasAttr("disabled");
26
+ }
27
+ set disabled(value) {
28
+ this.toggleAttr("disabled", Boolean(value));
29
+ }
30
+ get options() {
31
+ return [...this.querySelectorAll("option")].map((o) => ({
32
+ value: o.getAttribute("value") ?? o.textContent?.trim() ?? "",
33
+ label: o.textContent?.trim() ?? ""
34
+ }));
35
+ }
36
+ connectedCallback() {
37
+ super.connectedCallback();
38
+ this.observer = new MutationObserver(() => this.render());
39
+ this.observer.observe(this, { childList: true, subtree: true, characterData: true });
40
+ this.docListener = (e) => {
41
+ if (!this.hasAttr("open")) return;
42
+ if (e.composedPath().includes(this)) return;
43
+ this.removeAttribute("open");
44
+ this.render();
45
+ };
46
+ document.addEventListener("click", this.docListener);
47
+ }
48
+ disconnectedCallback() {
49
+ super.disconnectedCallback();
50
+ this.observer?.disconnect();
51
+ if (this.docListener) document.removeEventListener("click", this.docListener);
52
+ }
53
+ select(value) {
54
+ this.value = value;
55
+ this.removeAttribute("open");
56
+ this.render();
57
+ this.dispatchEvent(
58
+ new CustomEvent("change", { bubbles: true, composed: true, detail: { value } })
59
+ );
60
+ }
61
+ render() {
62
+ const prevOpen = this.hasAttr("open");
63
+ const prevSearch = this.root.querySelector(".search");
64
+ const search = prevSearch?.value ?? "";
65
+ const searchFocused = prevSearch != null && this.root.activeElement === prevSearch;
66
+ const caretPos = searchFocused ? prevSearch.selectionStart : null;
67
+ const opts = this.options;
68
+ let current = this.getAttr("value");
69
+ if (!current) {
70
+ const explicit = this.querySelector("option[selected]");
71
+ current = explicit?.getAttribute("value") ?? explicit?.textContent?.trim() ?? "";
72
+ }
73
+ const selectedLabel = opts.find((o) => o.value === current)?.label ?? "";
74
+ const placeholder = this.getAttr("placeholder", "Selecione…");
75
+ const filtered = search ? opts.filter((o) => o.label.toLowerCase().includes(search.toLowerCase())) : opts;
76
+ this.setTemplate(`
77
+ <span class="trigger" part="trigger" role="button" tabindex="${this.disabled ? -1 : 0}" aria-haspopup="listbox" aria-expanded="${prevOpen}">
78
+ <span class="${selectedLabel ? "label" : "placeholder"}">${selectedLabel || placeholder}</span>
79
+ <span class="actions">
80
+ ${this.hasAttr("clearable") && current ? '<button type="button" class="clear" part="clear" aria-label="Limpar">×</button>' : ""}
81
+ <span class="caret">▼</span>
82
+ </span>
83
+ </span>
84
+ <div class="panel" part="panel" role="listbox">
85
+ ${this.hasAttr("searchable") ? `<input class="search" part="search" type="text" placeholder="${this.getAttr("search-placeholder", "Pesquisar…")}">` : ""}
86
+ ${filtered.map((o) => `
87
+ <button type="button" class="opt" role="option" data-value="${o.value}"
88
+ aria-selected="${o.value === current}">${o.label}</button>`).join("")}
89
+ ${filtered.length === 0 ? `<div class="empty">${this.getAttr("no-results", "Nenhum resultado")}</div>` : ""}
90
+ </div>
91
+ `);
92
+ if (prevOpen) this.setAttribute("open", "");
93
+ const searchInput = this.root.querySelector(".search");
94
+ if (searchInput) {
95
+ searchInput.value = search;
96
+ searchInput.addEventListener("input", () => this.render());
97
+ searchInput.addEventListener("click", (e) => e.stopPropagation());
98
+ if (searchFocused) {
99
+ searchInput.focus();
100
+ try {
101
+ searchInput.setSelectionRange(caretPos, caretPos);
102
+ } catch {
103
+ }
104
+ }
105
+ }
106
+ const trigger = this.root.querySelector(".trigger");
107
+ if (!trigger) return;
108
+ if (this.disabled) trigger.setAttribute("aria-disabled", "true");
109
+ trigger.addEventListener("click", (e) => {
110
+ if (this.disabled) return;
111
+ if (e.target.closest(".clear")) return;
112
+ this.toggleAttribute("open");
113
+ this.render();
114
+ this.root.querySelector(".search")?.focus();
115
+ });
116
+ trigger.addEventListener("keydown", (e) => {
117
+ if (e.key === "Enter" || e.key === " ") {
118
+ e.preventDefault();
119
+ trigger.click();
120
+ }
121
+ });
122
+ this.root.querySelector(".clear")?.addEventListener("click", (e) => {
123
+ e.stopPropagation();
124
+ this.value = "";
125
+ this.removeAttribute("open");
126
+ this.render();
127
+ this.dispatchEvent(
128
+ new CustomEvent("change", { bubbles: true, composed: true, detail: { value: "" } })
129
+ );
130
+ });
131
+ this.root.querySelectorAll(".opt").forEach((opt) => {
132
+ opt.addEventListener("click", () => this.select(opt.dataset.value));
133
+ });
134
+ }
135
+ };
136
+ _FxSelect.styles = css`
137
+ :host {
138
+ display: inline-block;
139
+ vertical-align: middle;
140
+ font-family: var(--fx-font-family);
141
+ font-size: var(--fx-font-size);
142
+ position: relative;
143
+ }
144
+ .trigger {
145
+ display: inline-flex;
146
+ align-items: center;
147
+ justify-content: space-between;
148
+ gap: var(--fx-space-sm);
149
+ box-sizing: border-box;
150
+ min-height: var(--fx-size-md);
151
+ min-width: 200px;
152
+ font: inherit;
153
+ font-weight: var(--fx-font-weight);
154
+ color: var(--fx-text-default);
155
+ text-align: left;
156
+ background-color: var(--fx-surface-background);
157
+ border: 1px solid var(--fx-border-default);
158
+ border-radius: var(--fx-radius-md);
159
+ padding: var(--fx-space-xs) var(--fx-space-md);
160
+ cursor: pointer;
161
+ transition:
162
+ border-color var(--fx-motion-duration-normal) var(--fx-motion-easing),
163
+ box-shadow var(--fx-motion-duration-normal) var(--fx-motion-easing);
164
+ }
165
+ .trigger:hover { border-color: var(--fx-border-hover); }
166
+ .trigger:focus-visible,
167
+ :host([open]) .trigger {
168
+ outline: none;
169
+ border-color: var(--fx-color-primary);
170
+ box-shadow: var(--fx-effect-focus-ring, none);
171
+ }
172
+ :host([size='sm']) .trigger { min-width: 180px; min-height: var(--fx-size-sm); }
173
+ :host([size='lg']) .trigger { min-height: var(--fx-size-lg); font-size: calc(var(--fx-font-size) + 4px); }
174
+ /* Validação */
175
+ :host([error]) .trigger,
176
+ :host([invalid]) .trigger {
177
+ border-color: var(--fx-color-danger, #dc2626);
178
+ }
179
+ :host([error]) .trigger:focus-visible,
180
+ :host([invalid]) .trigger:focus-visible,
181
+ :host([error][open]) .trigger,
182
+ :host([invalid][open]) .trigger {
183
+ border-color: var(--fx-color-danger, #dc2626);
184
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--fx-color-danger, #dc2626) 18%, transparent);
185
+ }
186
+ :host([success]) .trigger,
187
+ :host([valid]) .trigger {
188
+ border-color: var(--fx-color-success, #16a34a);
189
+ }
190
+ :host([success]) .trigger:focus-visible,
191
+ :host([valid]) .trigger:focus-visible,
192
+ :host([success][open]) .trigger,
193
+ :host([valid][open]) .trigger {
194
+ border-color: var(--fx-color-success, #16a34a);
195
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--fx-color-success, #16a34a) 18%, transparent);
196
+ }
197
+ :host([disabled]) .trigger,
198
+ .trigger[aria-disabled='true'] { opacity: 0.55; cursor: not-allowed; background-color: var(--fx-surface-surface-hover); }
199
+ /* O rótulo encolhe (ellipsis) e os ícones NUNCA saem do campo. */
200
+ .label,
201
+ .placeholder {
202
+ flex: 1 1 auto;
203
+ min-width: 0;
204
+ overflow: hidden;
205
+ text-overflow: ellipsis;
206
+ white-space: nowrap;
207
+ }
208
+ .placeholder { color: var(--fx-text-muted); }
209
+ .actions {
210
+ display: inline-flex;
211
+ align-items: center;
212
+ gap: var(--fx-space-xs, 8px);
213
+ flex-shrink: 0;
214
+ }
215
+ .caret { font-size: calc(var(--fx-font-size) - 3px); color: var(--fx-text-muted); pointer-events: none; }
216
+
217
+ /* Painel do dropdown */
218
+ .panel {
219
+ position: absolute;
220
+ top: calc(100% + 4px);
221
+ left: 0;
222
+ z-index: var(--fx-z-dropdown, 1000);
223
+ width: max(100%, 220px);
224
+ max-height: 260px;
225
+ overflow-y: auto;
226
+ display: none;
227
+ background: var(--fx-surface-background);
228
+ border: 1px solid var(--fx-border-default);
229
+ border-radius: var(--fx-radius-md);
230
+ box-shadow: var(--fx-shadow-lg);
231
+ }
232
+ :host([open]) .panel { display: block; }
233
+ .search {
234
+ position: sticky;
235
+ top: 0;
236
+ width: 100%;
237
+ box-sizing: border-box;
238
+ font: inherit;
239
+ color: var(--fx-text-default);
240
+ background: var(--fx-surface-background);
241
+ border: none;
242
+ border-bottom: 1px solid var(--fx-border-default);
243
+ padding: var(--fx-space-sm) var(--fx-space-md);
244
+ outline: none;
245
+ }
246
+ .opt {
247
+ display: block;
248
+ width: 100%;
249
+ text-align: left;
250
+ font: inherit;
251
+ color: var(--fx-text-default);
252
+ background: none;
253
+ border: none;
254
+ padding: var(--fx-space-sm) var(--fx-space-md);
255
+ cursor: pointer;
256
+ }
257
+ /* Hover e selecionado com a cor primária do tema (igual ao multiselect). */
258
+ .opt:hover { background: color-mix(in srgb, var(--fx-color-primary) 12%, transparent); }
259
+ .opt[aria-selected='true'] {
260
+ background: color-mix(in srgb, var(--fx-color-primary) 18%, transparent);
261
+ color: var(--fx-color-primary);
262
+ font-weight: var(--fx-font-weight);
263
+ }
264
+ .empty { padding: var(--fx-space-sm) var(--fx-space-md); color: var(--fx-text-muted); }
265
+
266
+ /* Clearable */
267
+ .clear {
268
+ border: none;
269
+ background: transparent;
270
+ color: var(--fx-text-muted);
271
+ font-size: calc(var(--fx-font-size) + 2px);
272
+ line-height: 1;
273
+ cursor: pointer;
274
+ padding: 0;
275
+ }
276
+ .clear:hover { color: var(--fx-color-danger); }
277
+ .clear[hidden] { display: none; }
278
+ `;
279
+ let FxSelect = _FxSelect;
280
+ function defineFxSelect() {
281
+ return defineElement("fx-select", FxSelect);
282
+ }
283
+ export {
284
+ FxSelect,
285
+ defineFxSelect
286
+ };
287
+ //# sourceMappingURL=select.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"select.js","sources":["../../../src/components/select/select.ts"],"sourcesContent":["import { FxElement } from '../../core/base';\r\nimport { css } from '../../core/css';\r\nimport { defineElement } from '../../core/define';\r\n\r\n/**\r\n * <fx-select> — Campo de seleção com dropdown customizado.\r\n *\r\n * Escreva os filhos como `<option>` nativos no light DOM; eles são\r\n * espelhados automaticamente (MutationObserver):\r\n *\r\n * <fx-select value=\"b\" searchable clearable>\r\n * <option value=\"a\">Opção A</option>\r\n * <option value=\"b\">Opção B</option>\r\n * </fx-select>\r\n *\r\n * Atributos: value, size (sm|md|lg), disabled, placeholder,\r\n * searchable, clearable, search-placeholder, no-results.\r\n * Evento: `change` (composed, detail: { value }).\r\n */\r\nexport class FxSelect extends FxElement {\r\n static override styles = css`\r\n :host {\r\n display: inline-block;\r\n vertical-align: middle;\r\n font-family: var(--fx-font-family);\r\n font-size: var(--fx-font-size);\r\n position: relative;\r\n }\r\n .trigger {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n gap: var(--fx-space-sm);\r\n box-sizing: border-box;\r\n min-height: var(--fx-size-md);\r\n min-width: 200px;\r\n font: inherit;\r\n font-weight: var(--fx-font-weight);\r\n color: var(--fx-text-default);\r\n text-align: left;\r\n background-color: var(--fx-surface-background);\r\n border: 1px solid var(--fx-border-default);\r\n border-radius: var(--fx-radius-md);\r\n padding: var(--fx-space-xs) var(--fx-space-md);\r\n cursor: pointer;\r\n transition:\r\n border-color var(--fx-motion-duration-normal) var(--fx-motion-easing),\r\n box-shadow var(--fx-motion-duration-normal) var(--fx-motion-easing);\r\n }\r\n .trigger:hover { border-color: var(--fx-border-hover); }\r\n .trigger:focus-visible,\r\n :host([open]) .trigger {\r\n outline: none;\r\n border-color: var(--fx-color-primary);\r\n box-shadow: var(--fx-effect-focus-ring, none);\r\n }\r\n :host([size='sm']) .trigger { min-width: 180px; min-height: var(--fx-size-sm); }\r\n :host([size='lg']) .trigger { min-height: var(--fx-size-lg); font-size: calc(var(--fx-font-size) + 4px); }\r\n /* Validação */\r\n :host([error]) .trigger,\r\n :host([invalid]) .trigger {\r\n border-color: var(--fx-color-danger, #dc2626);\r\n }\r\n :host([error]) .trigger:focus-visible,\r\n :host([invalid]) .trigger:focus-visible,\r\n :host([error][open]) .trigger,\r\n :host([invalid][open]) .trigger {\r\n border-color: var(--fx-color-danger, #dc2626);\r\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--fx-color-danger, #dc2626) 18%, transparent);\r\n }\r\n :host([success]) .trigger,\r\n :host([valid]) .trigger {\r\n border-color: var(--fx-color-success, #16a34a);\r\n }\r\n :host([success]) .trigger:focus-visible,\r\n :host([valid]) .trigger:focus-visible,\r\n :host([success][open]) .trigger,\r\n :host([valid][open]) .trigger {\r\n border-color: var(--fx-color-success, #16a34a);\r\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--fx-color-success, #16a34a) 18%, transparent);\r\n }\r\n :host([disabled]) .trigger,\r\n .trigger[aria-disabled='true'] { opacity: 0.55; cursor: not-allowed; background-color: var(--fx-surface-surface-hover); }\r\n /* O rótulo encolhe (ellipsis) e os ícones NUNCA saem do campo. */\r\n .label,\r\n .placeholder {\r\n flex: 1 1 auto;\r\n min-width: 0;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n }\r\n .placeholder { color: var(--fx-text-muted); }\r\n .actions {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: var(--fx-space-xs, 8px);\r\n flex-shrink: 0;\r\n }\r\n .caret { font-size: calc(var(--fx-font-size) - 3px); color: var(--fx-text-muted); pointer-events: none; }\r\n\r\n /* Painel do dropdown */\r\n .panel {\r\n position: absolute;\r\n top: calc(100% + 4px);\r\n left: 0;\r\n z-index: var(--fx-z-dropdown, 1000);\r\n width: max(100%, 220px);\r\n max-height: 260px;\r\n overflow-y: auto;\r\n display: none;\r\n background: var(--fx-surface-background);\r\n border: 1px solid var(--fx-border-default);\r\n border-radius: var(--fx-radius-md);\r\n box-shadow: var(--fx-shadow-lg);\r\n }\r\n :host([open]) .panel { display: block; }\r\n .search {\r\n position: sticky;\r\n top: 0;\r\n width: 100%;\r\n box-sizing: border-box;\r\n font: inherit;\r\n color: var(--fx-text-default);\r\n background: var(--fx-surface-background);\r\n border: none;\r\n border-bottom: 1px solid var(--fx-border-default);\r\n padding: var(--fx-space-sm) var(--fx-space-md);\r\n outline: none;\r\n }\r\n .opt {\r\n display: block;\r\n width: 100%;\r\n text-align: left;\r\n font: inherit;\r\n color: var(--fx-text-default);\r\n background: none;\r\n border: none;\r\n padding: var(--fx-space-sm) var(--fx-space-md);\r\n cursor: pointer;\r\n }\r\n /* Hover e selecionado com a cor primária do tema (igual ao multiselect). */\r\n .opt:hover { background: color-mix(in srgb, var(--fx-color-primary) 12%, transparent); }\r\n .opt[aria-selected='true'] {\r\n background: color-mix(in srgb, var(--fx-color-primary) 18%, transparent);\r\n color: var(--fx-color-primary);\r\n font-weight: var(--fx-font-weight);\r\n }\r\n .empty { padding: var(--fx-space-sm) var(--fx-space-md); color: var(--fx-text-muted); }\r\n\r\n /* Clearable */\r\n .clear {\r\n border: none;\r\n background: transparent;\r\n color: var(--fx-text-muted);\r\n font-size: calc(var(--fx-font-size) + 2px);\r\n line-height: 1;\r\n cursor: pointer;\r\n padding: 0;\r\n }\r\n .clear:hover { color: var(--fx-color-danger); }\r\n .clear[hidden] { display: none; }\r\n `;\r\n\r\n // `value` fica FORA da observação: refleti-lo no change não pode\r\n // re-renderizar o template e fechar o dropdown.\r\n static override get observedAttributes(): string[] {\r\n return ['size', 'disabled', 'placeholder', 'searchable', 'clearable', 'error', 'success'];\r\n }\r\n\r\n private observer?: MutationObserver;\r\n private docListener?: (e: Event) => void;\r\n\r\n /** Tamanho do campo. Padrão: `'md'`. */\r\n get size(): string {\r\n const s = this.getAttr('size', 'md');\r\n return s === 'sm' || s === 'lg' ? s : 'md';\r\n }\r\n set size(value: string) {\r\n this.setAttribute('size', value);\r\n }\r\n\r\n get value(): string {\r\n return this.getAttr('value');\r\n }\r\n set value(value: string) {\r\n this.setAttribute('value', value);\r\n }\r\n\r\n get disabled(): boolean {\r\n return this.hasAttr('disabled');\r\n }\r\n set disabled(value: boolean) {\r\n this.toggleAttr('disabled', Boolean(value));\r\n }\r\n\r\n private get options(): { value: string; label: string }[] {\r\n return [...this.querySelectorAll('option')].map((o) => ({\r\n value: o.getAttribute('value') ?? o.textContent?.trim() ?? '',\r\n label: o.textContent?.trim() ?? '',\r\n }));\r\n }\r\n\r\n protected override connectedCallback(): void {\r\n super.connectedCallback();\r\n // Espelha mudanças nas <option> do light DOM.\r\n this.observer = new MutationObserver(() => this.render());\r\n this.observer.observe(this, { childList: true, subtree: true, characterData: true });\r\n // Fecha o dropdown ao clicar fora.\r\n this.docListener = (e: Event) => {\r\n if (!this.hasAttr('open')) return;\r\n if (e.composedPath().includes(this)) return;\r\n this.removeAttribute('open');\r\n this.render();\r\n };\r\n document.addEventListener('click', this.docListener);\r\n }\r\n\r\n protected override disconnectedCallback(): void {\r\n super.disconnectedCallback();\r\n this.observer?.disconnect();\r\n if (this.docListener) document.removeEventListener('click', this.docListener);\r\n }\r\n\r\n private select(value: string): void {\r\n this.value = value;\r\n this.removeAttribute('open');\r\n this.render();\r\n this.dispatchEvent(\r\n new CustomEvent('change', { bubbles: true, composed: true, detail: { value } }),\r\n );\r\n }\r\n\r\n protected override render(): void {\r\n const prevOpen = this.hasAttr('open');\r\n const prevSearch = this.root.querySelector<HTMLInputElement>('.search');\r\n // Estado do campo de busca antes de re-renderizar (valor, foco e cursor).\r\n const search = prevSearch?.value ?? '';\r\n const searchFocused =\r\n prevSearch != null && this.root.activeElement === prevSearch;\r\n const caretPos = searchFocused ? prevSearch!.selectionStart : null;\r\n\r\n const opts = this.options;\r\n let current = this.getAttr('value');\r\n if (!current) {\r\n const explicit = this.querySelector('option[selected]');\r\n current = explicit?.getAttribute('value') ?? explicit?.textContent?.trim() ?? '';\r\n }\r\n const selectedLabel = opts.find((o) => o.value === current)?.label ?? '';\r\n const placeholder = this.getAttr('placeholder', 'Selecione…');\r\n\r\n const filtered = search\r\n ? opts.filter((o) => o.label.toLowerCase().includes(search.toLowerCase()))\r\n : opts;\r\n\r\n this.setTemplate(`\r\n <span class=\"trigger\" part=\"trigger\" role=\"button\" tabindex=\"${this.disabled ? -1 : 0}\" aria-haspopup=\"listbox\" aria-expanded=\"${prevOpen}\">\r\n <span class=\"${selectedLabel ? 'label' : 'placeholder'}\">${selectedLabel || placeholder}</span>\r\n <span class=\"actions\">\r\n ${this.hasAttr('clearable') && current ? '<button type=\"button\" class=\"clear\" part=\"clear\" aria-label=\"Limpar\">×</button>' : ''}\r\n <span class=\"caret\">▼</span>\r\n </span>\r\n </span>\r\n <div class=\"panel\" part=\"panel\" role=\"listbox\">\r\n ${this.hasAttr('searchable') ? `<input class=\"search\" part=\"search\" type=\"text\" placeholder=\"${this.getAttr('search-placeholder', 'Pesquisar…')}\">` : ''}\r\n ${filtered.map((o) => `\r\n <button type=\"button\" class=\"opt\" role=\"option\" data-value=\"${o.value}\"\r\n aria-selected=\"${o.value === current}\">${o.label}</button>`).join('')}\r\n ${filtered.length === 0 ? `<div class=\"empty\">${this.getAttr('no-results', 'Nenhum resultado')}</div>` : ''}\r\n </div>\r\n `);\r\n\r\n if (prevOpen) this.setAttribute('open', '');\r\n const searchInput = this.root.querySelector<HTMLInputElement>('.search');\r\n if (searchInput) {\r\n searchInput.value = search;\r\n searchInput.addEventListener('input', () => this.render());\r\n searchInput.addEventListener('click', (e) => e.stopPropagation());\r\n // Re-render não pode roubar o foco nem perder a posição do cursor.\r\n if (searchFocused) {\r\n searchInput.focus();\r\n try { searchInput.setSelectionRange(caretPos!, caretPos!); } catch { /* type=text sempre suporta */ }\r\n }\r\n }\r\n\r\n const trigger = this.root.querySelector<HTMLElement>('.trigger');\r\n if (!trigger) return;\r\n if (this.disabled) trigger.setAttribute('aria-disabled', 'true');\r\n\r\n trigger.addEventListener('click', (e) => {\r\n if (this.disabled) return;\r\n if ((e.target as HTMLElement).closest('.clear')) return;\r\n this.toggleAttribute('open');\r\n this.render();\r\n this.root.querySelector<HTMLInputElement>('.search')?.focus();\r\n });\r\n\r\n // Teclado: Enter/Espaço abrem o dropdown.\r\n trigger.addEventListener('keydown', (e) => {\r\n if (e.key === 'Enter' || e.key === ' ') {\r\n e.preventDefault();\r\n trigger.click();\r\n }\r\n });\r\n\r\n // Limpar.\r\n this.root.querySelector('.clear')?.addEventListener('click', (e) => {\r\n e.stopPropagation();\r\n this.value = '';\r\n this.removeAttribute('open');\r\n this.render();\r\n this.dispatchEvent(\r\n new CustomEvent('change', { bubbles: true, composed: true, detail: { value: '' } }),\r\n );\r\n });\r\n\r\n // Escolher opção.\r\n this.root.querySelectorAll<HTMLElement>('.opt').forEach((opt) => {\r\n opt.addEventListener('click', () => this.select(opt.dataset.value!));\r\n });\r\n }\r\n}\r\n\r\nexport function defineFxSelect(): typeof FxSelect {\r\n return defineElement('fx-select', FxSelect);\r\n}\r\n\r\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { FxSkeleton } from './skeleton';
2
+ export { FxSkeleton };
3
+ declare global {
4
+ interface HTMLElementTagNameMap {
5
+ 'fx-skeleton': FxSkeleton;
6
+ }
7
+ }
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/skeleton/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAoB,MAAM,YAAY,CAAC;AAE1D,OAAO,EAAE,UAAU,EAAE,CAAC;AAKtB,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,aAAa,EAAE,UAAU,CAAC;KAC3B;CACF"}
@@ -0,0 +1,7 @@
1
+ import { defineFxSkeleton } from "./skeleton.js";
2
+ import { FxSkeleton } from "./skeleton.js";
3
+ defineFxSkeleton();
4
+ export {
5
+ FxSkeleton
6
+ };
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../../src/components/skeleton/index.ts"],"sourcesContent":["import { FxSkeleton, defineFxSkeleton } from './skeleton';\n\nexport { FxSkeleton };\n\n\ndefineFxSkeleton();\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'fx-skeleton': FxSkeleton;\n }\n}\n\r\n\r\n"],"names":[],"mappings":";;AAKA,iBAAA;"}
@@ -0,0 +1,13 @@
1
+ import { FxElement } from '../../core/base';
2
+ /**
3
+ * <fx-skeleton> — Placeholder animado para carregamento de conteúdo.
4
+ *
5
+ * Atributos: variant (text|circle|rect, padrão text), width, height, lines (para text).
6
+ */
7
+ export declare class FxSkeleton extends FxElement {
8
+ static styles: string;
9
+ static get observedAttributes(): string[];
10
+ protected render(): void;
11
+ }
12
+ export declare function defineFxSkeleton(): typeof FxSkeleton;
13
+ //# sourceMappingURL=skeleton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skeleton.d.ts","sourceRoot":"","sources":["../../../src/components/skeleton/skeleton.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C;;;;GAIG;AACH,qBAAa,UAAW,SAAQ,SAAS;IACvC,OAAgB,MAAM,SAkBpB;IAEF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAEjD;cAEkB,MAAM,IAAI,IAAI;CAyBlC;AAED,wBAAgB,gBAAgB,IAAI,OAAO,UAAU,CAEpD"}
@@ -0,0 +1,57 @@
1
+ import { FxElement } from "../../core/base.js";
2
+ import { css } from "../../core/css.js";
3
+ import { defineElement } from "../../core/define.js";
4
+ const _FxSkeleton = class _FxSkeleton extends FxElement {
5
+ static get observedAttributes() {
6
+ return ["variant", "width", "height", "lines"];
7
+ }
8
+ render() {
9
+ const variant = this.getAttr("variant", "text");
10
+ const width = this.getAttr("width");
11
+ const height = this.getAttr("height");
12
+ const style = `${width ? `width:${width};` : ""}${height ? `height:${height};` : ""}`;
13
+ if (variant === "circle") {
14
+ const size = height || width || "40px";
15
+ const diameter = !style.includes("height") ? `width:${size};height:${size};` : style;
16
+ this.setTemplate(`<div class="bone circle" part="bone" style="${diameter}"></div>`);
17
+ return;
18
+ }
19
+ if (variant === "rect") {
20
+ const s = style || "width:100%;height:80px;";
21
+ this.setTemplate(`<div class="bone" part="bone" style="${s}"></div>`);
22
+ return;
23
+ }
24
+ const lines = Number(this.getAttr("lines", "3")) || 3;
25
+ this.setTemplate(`
26
+ ${Array.from({ length: lines }, () => '<div class="bone text"></div>').join("")}
27
+ `);
28
+ }
29
+ };
30
+ _FxSkeleton.styles = css`
31
+ :host { display: block; width: 100%; min-width: 80px; font-family: var(--fx-font-family); }
32
+ .bone {
33
+ background: linear-gradient(
34
+ 90deg,
35
+ var(--fx-surface-surface-hover) 25%,
36
+ color-mix(in srgb, var(--fx-surface-surface-hover) 55%, var(--fx-surface-background)) 50%,
37
+ var(--fx-surface-surface-hover) 75%
38
+ );
39
+ background-size: 200% 100%;
40
+ animation: shimmer 1.4s ease-in-out infinite;
41
+ border-radius: var(--fx-radius-sm);
42
+ }
43
+ @keyframes shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }
44
+ .bone[hidden] { display: none; }
45
+ .text { height: 12px; width: 100%; margin-bottom: var(--fx-space-sm); }
46
+ .text:last-of-type { width: 60%; margin-bottom: 0; }
47
+ .circle { border-radius: var(--fx-radius-full); }
48
+ `;
49
+ let FxSkeleton = _FxSkeleton;
50
+ function defineFxSkeleton() {
51
+ return defineElement("fx-skeleton", FxSkeleton);
52
+ }
53
+ export {
54
+ FxSkeleton,
55
+ defineFxSkeleton
56
+ };
57
+ //# sourceMappingURL=skeleton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skeleton.js","sources":["../../../src/components/skeleton/skeleton.ts"],"sourcesContent":["import { FxElement } from '../../core/base';\nimport { css } from '../../core/css';\nimport { defineElement } from '../../core/define';\n\n/**\n * <fx-skeleton> — Placeholder animado para carregamento de conteúdo.\n *\n * Atributos: variant (text|circle|rect, padrão text), width, height, lines (para text).\n */\nexport class FxSkeleton extends FxElement {\n static override styles = css`\n :host { display: block; width: 100%; min-width: 80px; font-family: var(--fx-font-family); }\n .bone {\n background: linear-gradient(\n 90deg,\n var(--fx-surface-surface-hover) 25%,\n color-mix(in srgb, var(--fx-surface-surface-hover) 55%, var(--fx-surface-background)) 50%,\n var(--fx-surface-surface-hover) 75%\n );\n background-size: 200% 100%;\n animation: shimmer 1.4s ease-in-out infinite;\n border-radius: var(--fx-radius-sm);\n }\n @keyframes shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }\n .bone[hidden] { display: none; }\n .text { height: 12px; width: 100%; margin-bottom: var(--fx-space-sm); }\n .text:last-of-type { width: 60%; margin-bottom: 0; }\n .circle { border-radius: var(--fx-radius-full); }\n `;\n\n static override get observedAttributes(): string[] {\n return ['variant', 'width', 'height', 'lines'];\n }\n\n protected override render(): void {\n const variant = this.getAttr('variant', 'text');\n const width = this.getAttr('width');\n const height = this.getAttr('height');\n const style = `${width ? `width:${width};` : ''}${height ? `height:${height};` : ''}`;\n\n if (variant === 'circle') {\n const size = height || width || '40px';\n const diameter = !style.includes('height') ? `width:${size};height:${size};` : style;\n this.setTemplate(`<div class=\"bone circle\" part=\"bone\" style=\"${diameter}\"></div>`);\n return;\n }\n\n if (variant === 'rect') {\n const s = style || 'width:100%;height:80px;';\n this.setTemplate(`<div class=\"bone\" part=\"bone\" style=\"${s}\"></div>`);\n return;\n }\n\n // text (padrão): N linhas\n const lines = Number(this.getAttr('lines', '3')) || 3;\n this.setTemplate(`\n ${Array.from({ length: lines }, () => '<div class=\"bone text\"></div>').join('')}\n `);\n }\n}\n\nexport function defineFxSkeleton(): typeof FxSkeleton {\n return defineElement('fx-skeleton', FxSkeleton);\n}\n"],"names":[],"mappings":";;;AASO,MAAM,cAAN,MAAM,oBAAmB,UAAU;AAAA,EAqBxC,WAAoB,qBAA+B;AACjD,WAAO,CAAC,WAAW,SAAS,UAAU,OAAO;AAAA,EAC/C;AAAA,EAEmB,SAAe;AAChC,UAAM,UAAU,KAAK,QAAQ,WAAW,MAAM;AAC9C,UAAM,QAAQ,KAAK,QAAQ,OAAO;AAClC,UAAM,SAAS,KAAK,QAAQ,QAAQ;AACpC,UAAM,QAAQ,GAAG,QAAQ,SAAS,KAAK,MAAM,EAAE,GAAG,SAAS,UAAU,MAAM,MAAM,EAAE;AAEnF,QAAI,YAAY,UAAU;AACxB,YAAM,OAAO,UAAU,SAAS;AAChC,YAAM,WAAW,CAAC,MAAM,SAAS,QAAQ,IAAI,SAAS,IAAI,WAAW,IAAI,MAAM;AAC/E,WAAK,YAAY,+CAA+C,QAAQ,UAAU;AAClF;AAAA,IACF;AAEA,QAAI,YAAY,QAAQ;AACtB,YAAM,IAAI,SAAS;AACnB,WAAK,YAAY,wCAAwC,CAAC,UAAU;AACpE;AAAA,IACF;AAGA,UAAM,QAAQ,OAAO,KAAK,QAAQ,SAAS,GAAG,CAAC,KAAK;AACpD,SAAK,YAAY;AAAA,QACb,MAAM,KAAK,EAAE,QAAQ,MAAA,GAAS,MAAM,+BAA+B,EAAE,KAAK,EAAE,CAAC;AAAA,KAChF;AAAA,EACH;AACF;AAjDE,YAAgB,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AADpB,IAAM,aAAN;AAoDA,SAAS,mBAAsC;AACpD,SAAO,cAAc,eAAe,UAAU;AAChD;"}
@@ -0,0 +1,2 @@
1
+ export { FxSpinner } from './spinner';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/spinner/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { defineFxSpinner } from "./spinner.js";
2
+ import { FxSpinner } from "./spinner.js";
3
+ defineFxSpinner();
4
+ export {
5
+ FxSpinner
6
+ };
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../../src/components/spinner/index.ts"],"sourcesContent":["import { defineFxSpinner } from './spinner';\n\n// Reexporta a classe para uso programático.\nexport { FxSpinner } from './spinner';\n\n// Auto-registro ao importar o subpath `@wrrdev/fenix-ui/spinner`.\ndefineFxSpinner();"],"names":[],"mappings":";;AAMA,gBAAA;"}
@@ -0,0 +1,16 @@
1
+ import { FxElement } from '../../core/base';
2
+ /**
3
+ * <fx-spinner> — Indicador de progresso indeterminado.
4
+ *
5
+ * Atributos: size (sm|md|lg).
6
+ */
7
+ export declare class FxSpinner extends FxElement {
8
+ static styles: string;
9
+ static get observedAttributes(): string[];
10
+ /** Tamanho do spinner. Padrão: `'md'`. */
11
+ get size(): string;
12
+ set size(value: string);
13
+ protected render(): void;
14
+ }
15
+ export declare function defineFxSpinner(): typeof FxSpinner;
16
+ //# sourceMappingURL=spinner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spinner.d.ts","sourceRoot":"","sources":["../../../src/components/spinner/spinner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C;;;;GAIG;AACH,qBAAa,SAAU,SAAQ,SAAS;IACtC,OAAgB,MAAM,SAqBpB;IAEF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAEjD;IAED,0CAA0C;IAC1C,IAAI,IAAI,IAAI,MAAM,CAGjB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,EAErB;cAEkB,MAAM,IAAI,IAAI;CAGlC;AAED,wBAAgB,eAAe,IAAI,OAAO,SAAS,CAElD"}
@@ -0,0 +1,50 @@
1
+ import { FxElement } from "../../core/base.js";
2
+ import { css } from "../../core/css.js";
3
+ import { defineElement } from "../../core/define.js";
4
+ const _FxSpinner = class _FxSpinner extends FxElement {
5
+ static get observedAttributes() {
6
+ return ["size"];
7
+ }
8
+ /** Tamanho do spinner. Padrão: `'md'`. */
9
+ get size() {
10
+ const s = this.getAttr("size", "md");
11
+ return s === "sm" || s === "lg" ? s : "md";
12
+ }
13
+ set size(value) {
14
+ this.setAttribute("size", value);
15
+ }
16
+ render() {
17
+ this.setTemplate(`<span class="spinner" part="spinner" role="status" aria-label="Carregando"></span>`);
18
+ }
19
+ };
20
+ _FxSpinner.styles = css`
21
+ :host {
22
+ display: inline-block;
23
+ vertical-align: middle;
24
+ }
25
+ /* Escala: sm 16px · md 24px (padrão) · lg 32px */
26
+ .spinner {
27
+ display: inline-block;
28
+ width: var(--fx-space-xl, 20px);
29
+ height: var(--fx-space-xl, 20px);
30
+ border: 2px solid var(--fx-border-default, #e2e8f0);
31
+ border-top-color: var(--fx-color-primary, #2563eb);
32
+ border-radius: var(--fx-radius-full, 9999px);
33
+ animation: fx-spin 0.8s linear infinite;
34
+ }
35
+ :host([size='sm']) .spinner { width: var(--fx-space-lg, 16px); height: var(--fx-space-lg, 16px); }
36
+ :host([size='lg']) .spinner { width: 32px; height: 32px; border-width: 3px; }
37
+ @keyframes fx-spin { to { transform: rotate(360deg); } }
38
+ @media (prefers-reduced-motion: reduce) {
39
+ .spinner { animation-duration: 2.5s; }
40
+ }
41
+ `;
42
+ let FxSpinner = _FxSpinner;
43
+ function defineFxSpinner() {
44
+ return defineElement("fx-spinner", FxSpinner);
45
+ }
46
+ export {
47
+ FxSpinner,
48
+ defineFxSpinner
49
+ };
50
+ //# sourceMappingURL=spinner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spinner.js","sources":["../../../src/components/spinner/spinner.ts"],"sourcesContent":["import { FxElement } from '../../core/base';\nimport { css } from '../../core/css';\nimport { defineElement } from '../../core/define';\n\n/**\n * <fx-spinner> — Indicador de progresso indeterminado.\n *\n * Atributos: size (sm|md|lg).\n */\nexport class FxSpinner extends FxElement {\n static override styles = css`\n :host {\n display: inline-block;\n vertical-align: middle;\n }\n /* Escala: sm 16px · md 24px (padrão) · lg 32px */\n .spinner {\n display: inline-block;\n width: var(--fx-space-xl, 20px);\n height: var(--fx-space-xl, 20px);\n border: 2px solid var(--fx-border-default, #e2e8f0);\n border-top-color: var(--fx-color-primary, #2563eb);\n border-radius: var(--fx-radius-full, 9999px);\n animation: fx-spin 0.8s linear infinite;\n }\n :host([size='sm']) .spinner { width: var(--fx-space-lg, 16px); height: var(--fx-space-lg, 16px); }\n :host([size='lg']) .spinner { width: 32px; height: 32px; border-width: 3px; }\n @keyframes fx-spin { to { transform: rotate(360deg); } }\n @media (prefers-reduced-motion: reduce) {\n .spinner { animation-duration: 2.5s; }\n }\n `;\n\n static override get observedAttributes(): string[] {\n return ['size'];\n }\n\n /** Tamanho do spinner. 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 protected override render(): void {\n this.setTemplate(`<span class=\"spinner\" part=\"spinner\" role=\"status\" aria-label=\"Carregando\"></span>`);\n }\n}\n\nexport function defineFxSpinner(): typeof FxSpinner {\n return defineElement('fx-spinner', FxSpinner);\n}"],"names":[],"mappings":";;;AASO,MAAM,aAAN,MAAM,mBAAkB,UAAU;AAAA,EAwBvC,WAAoB,qBAA+B;AACjD,WAAO,CAAC,MAAM;AAAA,EAChB;AAAA;AAAA,EAGA,IAAI,OAAe;AACjB,UAAM,IAAI,KAAK,QAAQ,QAAQ,IAAI;AACnC,WAAO,MAAM,QAAQ,MAAM,OAAO,IAAI;AAAA,EACxC;AAAA,EACA,IAAI,KAAK,OAAe;AACtB,SAAK,aAAa,QAAQ,KAAK;AAAA,EACjC;AAAA,EAEmB,SAAe;AAChC,SAAK,YAAY,oFAAoF;AAAA,EACvG;AACF;AAvCE,WAAgB,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AADpB,IAAM,YAAN;AA0CA,SAAS,kBAAoC;AAClD,SAAO,cAAc,cAAc,SAAS;AAC9C;"}
@@ -0,0 +1,2 @@
1
+ export { FxSwitch } from './switch';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/switch/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { defineFxSwitch } from "./switch.js";
2
+ import { FxSwitch } from "./switch.js";
3
+ defineFxSwitch();
4
+ export {
5
+ FxSwitch
6
+ };
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../../src/components/switch/index.ts"],"sourcesContent":["import { defineFxSwitch } from './switch';\n\n// Reexporta a classe para uso programático (instanceof, herança).\nexport { FxSwitch } from './switch';\n\n// Auto-registro ao importar o subpath `@wrrdev/fenix-ui/switch`.\ndefineFxSwitch();\n"],"names":[],"mappings":";;AAMA,eAAA;"}
@@ -0,0 +1,22 @@
1
+ import { FxElement } from '../../core/base';
2
+ /**
3
+ * <fx-switch> — Interruptor ligado/desligado (role="switch").
4
+ *
5
+ * O texto do slot (light DOM) é o rótulo clicável.
6
+ * Atributos: checked, disabled, size (sm|md|lg).
7
+ * Evento: `change` (composed, detail: { checked }).
8
+ */
9
+ export declare class FxSwitch extends FxElement {
10
+ static styles: string;
11
+ static get observedAttributes(): string[];
12
+ /** Tamanho da trilha. Padrão: `'md'`. */
13
+ get size(): string;
14
+ set size(value: string);
15
+ get checked(): boolean;
16
+ set checked(value: boolean);
17
+ get disabled(): boolean;
18
+ set disabled(value: boolean);
19
+ protected render(): void;
20
+ }
21
+ export declare function defineFxSwitch(): typeof FxSwitch;
22
+ //# sourceMappingURL=switch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"switch.d.ts","sourceRoot":"","sources":["../../../src/components/switch/switch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C;;;;;;GAMG;AACH,qBAAa,QAAS,SAAQ,SAAS;IACrC,OAAgB,MAAM,SAsDpB;IAEF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAEjD;IAED,yCAAyC;IACzC,IAAI,IAAI,IAAI,MAAM,CAGjB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,EAErB;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAEzB;IAED,IAAI,QAAQ,IAAI,OAAO,CAEtB;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAE1B;cAEkB,MAAM,IAAI,IAAI;CAwBlC;AAED,wBAAgB,cAAc,IAAI,OAAO,QAAQ,CAEhD"}