@wrrdev/fenix-ui 1.1.1 → 1.1.3

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 (36) hide show
  1. package/README.md +5 -4
  2. package/dist/_virtual/preload-helper.js +6 -3
  3. package/dist/_virtual/preload-helper.js.map +1 -1
  4. package/dist/cdn.d.ts +2 -1
  5. package/dist/cdn.d.ts.map +1 -1
  6. package/dist/components/accordion/accordion.d.ts.map +1 -1
  7. package/dist/components/accordion/accordion.js +1 -0
  8. package/dist/components/accordion/accordion.js.map +1 -1
  9. package/dist/components/alert/alert.js +2 -3
  10. package/dist/components/alert/alert.js.map +1 -1
  11. package/dist/components/confirmpopup/confirmpopup.js +2 -3
  12. package/dist/components/confirmpopup/confirmpopup.js.map +1 -1
  13. package/dist/components/dialog/dialog.d.ts.map +1 -1
  14. package/dist/components/dialog/dialog.js +11 -3
  15. package/dist/components/dialog/dialog.js.map +1 -1
  16. package/dist/components/slider/slider.d.ts +3 -0
  17. package/dist/components/slider/slider.d.ts.map +1 -1
  18. package/dist/components/slider/slider.js +10 -0
  19. package/dist/components/slider/slider.js.map +1 -1
  20. package/dist/components/timeline/timeline.d.ts +2 -1
  21. package/dist/components/timeline/timeline.d.ts.map +1 -1
  22. package/dist/components/timeline/timeline.js +21 -5
  23. package/dist/components/timeline/timeline.js.map +1 -1
  24. package/dist/components/toast/toast.d.ts +7 -1
  25. package/dist/components/toast/toast.d.ts.map +1 -1
  26. package/dist/components/toast/toast.js +31 -8
  27. package/dist/components/toast/toast.js.map +1 -1
  28. package/dist/core/jsx.d.ts +2 -0
  29. package/dist/core/jsx.d.ts.map +1 -1
  30. package/dist/core/jsx.js.map +1 -1
  31. package/dist/docs/app.d.ts.map +1 -1
  32. package/dist/docs/componentes/toast.doc.d.ts.map +1 -1
  33. package/dist/fenix-ui.umd.min.js +115 -78
  34. package/dist/fenix-ui3.esm.js +79 -19
  35. package/dist/fenix-ui3.esm.js.map +1 -1
  36. package/package.json +2 -2
package/README.md CHANGED
@@ -18,7 +18,7 @@ import { FenixUI } from '@wrrdev/fenix-ui'; // API de tema/tokens (índice)
18
18
  FenixUI.theme('dark');
19
19
  ```
20
20
 
21
- > 📦 npm: [`@wrrdev/fenix-ui`](https://www.npmjs.com/package/@wrrdev/fenix-ui) — **v1.1.1**, acesso público.
21
+ > 📦 npm: [`@wrrdev/fenix-ui`](https://www.npmjs.com/package/@wrrdev/fenix-ui) — **v1.1.3**, acesso público.
22
22
  > Subpaths disponíveis: `./theme`, `./tokens`, `./jsx`, `./vue`, `./button`, `./badge`, `./spinner`, `./select`, `./input`, `./switch`, `./textarea`, `./checkbox`, `./radio`, `./calendar`, `./datepicker`, `./multiselect`, `./table`, `./floatlabel`, `./dialog`, `./toast`, `./tooltip`, `./tabs`, `./progress`, `./skeleton`, `./alert`, `./drawer`, `./dropdown`, `./sidebar`, `./pagination`, `./autocomplete`, `./auto-import` e o curinga `./components/*`.
23
23
 
24
24
 
@@ -65,7 +65,7 @@ Carregue o bundle **UMD** único: ele registra todos os componentes e expõe os
65
65
  <fx-toast></fx-toast>
66
66
 
67
67
  <!--
68
- 🔗 Links diretos para CDN (versão 1.1.1):
68
+ 🔗 Links diretos para CDN (versão 1.1.3):
69
69
  • https://cdn.jsdelivr.net/npm/@wrrdev/fenix-ui@latest/dist/fenix-ui.umd.min.js
70
70
  • https://unpkg.com/@wrrdev/fenix-ui@latest/dist/fenix-ui.umd.min.js
71
71
  -->
@@ -294,8 +294,9 @@ ative o modo estrito do Volar no `tsconfig.json`:
294
294
  > Sem `strictTemplates`, o Vue não reporta atributos desconhecidos de elementos nativos
295
295
  > (comportamento padrão do Volar) — mas o autocomplete das propriedades continua funcionando.
296
296
  >
297
- > **Para Nuxt:** use `plugins/fenix-ui.client.ts` e configure
298
- > `nuxtApp.vueApp.config.compilerOptions.isCustomElement` no plugin.
297
+ > **Para Nuxt:** `isCustomElement` é opção de compilação — configure em `nuxt.config.ts`
298
+ > (`vue: { compilerOptions: { isCustomElement: (tag) => tag.startsWith('fx-') } }`) e use um
299
+ > plugin `plugins/fenix-ui.client.ts` apenas para os imports (componentes, tema e tipos Volar).
299
300
 
300
301
  ## Componentes (fase 1)
301
302
 
@@ -1,9 +1,12 @@
1
- const scriptRel = "modulepreload";
1
+ const scriptRel = function detectScriptRel() {
2
+ const relList = typeof document !== "undefined" && document.createElement("link").relList;
3
+ return relList && relList.supports && relList.supports("modulepreload") ? "modulepreload" : "preload";
4
+ }();
2
5
  const assetsURL = function(dep, importerUrl) {
3
6
  return new URL(dep, importerUrl).href;
4
7
  };
5
8
  const seen = {};
6
- const __vitePreload = function preload(baseModule, deps, importerUrl) {
9
+ const __fenixPreload = function preload(baseModule, deps, importerUrl) {
7
10
  let promise = Promise.resolve();
8
11
  if (deps && deps.length > 0) {
9
12
  const links = document.getElementsByTagName("link");
@@ -71,6 +74,6 @@ const __vitePreload = function preload(baseModule, deps, importerUrl) {
71
74
  });
72
75
  };
73
76
  export {
74
- __vitePreload
77
+ __fenixPreload
75
78
  };
76
79
  //# sourceMappingURL=preload-helper.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"preload-helper.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"preload-helper.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/dist/cdn.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Entrada para o bundle CDN/UMD (`fenix-ui.umd.min.js`).
3
- * Importa e registra todos os componentes de uma vez.
3
+ * Importa e registra todos os componentes (incl. a biblioteca de ícones) de uma vez.
4
4
  */
5
5
  import './index';
6
+ import './icons';
6
7
  //# sourceMappingURL=cdn.d.ts.map
package/dist/cdn.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cdn.d.ts","sourceRoot":"","sources":["../src/cdn.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,SAAS,CAAC"}
1
+ {"version":3,"file":"cdn.d.ts","sourceRoot":"","sources":["../src/cdn.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,SAAS,CAAC;AACjB,OAAO,SAAS,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"accordion.d.ts","sourceRoot":"","sources":["../../../src/components/accordion/accordion.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAK5C;;;;;;;;GAQG;AACH,qBAAa,gBAAiB,SAAQ,SAAS;IAC7C,OAAgB,MAAM,SAoEpB;IAEF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAEjD;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IACD,IAAI,MAAM,CAAC,CAAC,EAAE,MAAM,EAEnB;IAED,IAAI,KAAK,IAAI,MAAM,CAElB;IACD,IAAI,KAAK,CAAC,CAAC,EAAE,MAAM,EAElB;IAED,IAAI,QAAQ,IAAI,OAAO,CAEtB;IACD,IAAI,QAAQ,CAAC,CAAC,EAAE,OAAO,EAEtB;IAED,IAAI,QAAQ,IAAI,OAAO,CAEtB;IACD,IAAI,QAAQ,CAAC,CAAC,EAAE,OAAO,EAEtB;cAEkB,iBAAiB,IAAI,IAAI;cAuBzB,oBAAoB,IAAI,IAAI;IAK/C,OAAO,CAAC,GAAG,CAAiC;IAC5C,OAAO,CAAC,sBAAsB,CAAS;cAEpB,MAAM,IAAI,IAAI;CAwBlC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,WAAY,SAAQ,SAAS;IACxC,OAAgB,MAAM,SAapB;IAEF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAEjD;IAED,IAAI,QAAQ,IAAI,OAAO,CAEtB;IACD,IAAI,QAAQ,CAAC,CAAC,EAAE,OAAO,EAEtB;IAED,iCAAiC;IACjC,IAAI,MAAM,IAAI,MAAM,EAAE,CAErB;IACD,IAAI,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,EAErB;cAEkB,iBAAiB,IAAI,IAAI;cASzB,oBAAoB,IAAI,IAAI;IAK/C,OAAO,CAAC,SAAS,CAAiC;cAE/B,MAAM,IAAI,IAAI;IAUjC,6DAA6D;IAC7D,OAAO,KAAK,MAAM,GAEjB;IAED,OAAO,CAAC,KAAK;IAsBb,OAAO,CAAC,YAAY,CAAS;IAE7B,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,kBAAkB,CAAS;IAEnC,mEAAmE;IACnE,MAAM,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI;IAqBrC,iCAAiC;IACjC,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAKzB,kCAAkC;IAClC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;CAI3B;AAED,wBAAgB,iBAAiB,IAAI,OAAO,WAAW,CAEtD;AAED,wBAAgB,sBAAsB,IAAI,OAAO,gBAAgB,CAEhE"}
1
+ {"version":3,"file":"accordion.d.ts","sourceRoot":"","sources":["../../../src/components/accordion/accordion.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAK5C;;;;;;;;GAQG;AACH,qBAAa,gBAAiB,SAAQ,SAAS;IAC7C,OAAgB,MAAM,SAoEpB;IAEF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAEjD;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IACD,IAAI,MAAM,CAAC,CAAC,EAAE,MAAM,EAEnB;IAED,IAAI,KAAK,IAAI,MAAM,CAElB;IACD,IAAI,KAAK,CAAC,CAAC,EAAE,MAAM,EAElB;IAED,IAAI,QAAQ,IAAI,OAAO,CAEtB;IACD,IAAI,QAAQ,CAAC,CAAC,EAAE,OAAO,EAEtB;IAED,IAAI,QAAQ,IAAI,OAAO,CAEtB;IACD,IAAI,QAAQ,CAAC,CAAC,EAAE,OAAO,EAEtB;cAEkB,iBAAiB,IAAI,IAAI;cAuBzB,oBAAoB,IAAI,IAAI;IAM/C,OAAO,CAAC,GAAG,CAAiC;IAC5C,OAAO,CAAC,sBAAsB,CAAS;cAEpB,MAAM,IAAI,IAAI;CAwBlC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,WAAY,SAAQ,SAAS;IACxC,OAAgB,MAAM,SAapB;IAEF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAEjD;IAED,IAAI,QAAQ,IAAI,OAAO,CAEtB;IACD,IAAI,QAAQ,CAAC,CAAC,EAAE,OAAO,EAEtB;IAED,iCAAiC;IACjC,IAAI,MAAM,IAAI,MAAM,EAAE,CAErB;IACD,IAAI,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,EAErB;cAEkB,iBAAiB,IAAI,IAAI;cASzB,oBAAoB,IAAI,IAAI;IAK/C,OAAO,CAAC,SAAS,CAAiC;cAE/B,MAAM,IAAI,IAAI;IAUjC,6DAA6D;IAC7D,OAAO,KAAK,MAAM,GAEjB;IAED,OAAO,CAAC,KAAK;IAsBb,OAAO,CAAC,YAAY,CAAS;IAE7B,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,kBAAkB,CAAS;IAEnC,mEAAmE;IACnE,MAAM,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI;IAqBrC,iCAAiC;IACjC,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAKzB,kCAAkC;IAClC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;CAI3B;AAED,wBAAgB,iBAAiB,IAAI,OAAO,WAAW,CAEtD;AAED,wBAAgB,sBAAsB,IAAI,OAAO,gBAAgB,CAEhE"}
@@ -58,6 +58,7 @@ const _FxAccordionPanel = class _FxAccordionPanel extends FxElement {
58
58
  disconnectedCallback() {
59
59
  this._mo?.disconnect();
60
60
  this._mo = null;
61
+ super.disconnectedCallback();
61
62
  }
62
63
  render() {
63
64
  this.setTemplate(`
@@ -1 +1 @@
1
- {"version":3,"file":"accordion.js","sources":["../../../src/components/accordion/accordion.ts"],"sourcesContent":["import { FxElement } from '../../core/base';\nimport { css } from '../../core/css';\nimport { defineElement } from '../../core/define';\nimport { esc } from '../../core/sanitize';\n\n/**\n * <fx-accordion-panel> — Painel individual do accordion.\n *\n * Atributos:\n * - header: titulo exibido no cabecalho (ou use o slot \"header\").\n * - value: identificador unico do painel (usado pelo fx-accordion).\n * - expanded: presenca indica painel aberto (controlado pelo fx-accordion).\n * - disabled: impede a abertura do painel.\n */\nexport class FxAccordionPanel extends FxElement {\n static override styles = css`\n :host {\n display: block;\n font-family: var(--fx-font-family);\n font-size: var(--fx-font-size);\n color: var(--fx-text-default);\n }\n /* A borda fica no wrapper interno (nao no :host): regras do documento\n externo (ex.: preflight do Tailwind com border-width: 0) vencem as\n regras :host do shadow tree, o que apagaria a linha divisoria. */\n .panel {\n border-bottom: 1px solid var(--fx-border-default);\n }\n :host(:last-child) .panel { border-bottom: none; }\n :host([disabled]) { opacity: 0.6; pointer-events: none; }\n .header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--fx-space-md);\n width: 100%;\n box-sizing: border-box;\n padding: var(--fx-space-lg, 20px) var(--fx-space-md, 14px);\n border: none;\n background: transparent;\n font-family: inherit;\n font-size: inherit;\n font-weight: 500;\n color: var(--fx-text-muted);\n text-align: left;\n cursor: pointer;\n transition: color var(--fx-motion-duration-fast, 150ms) var(--fx-motion-easing, ease),\n background var(--fx-motion-duration-fast, 150ms) var(--fx-motion-easing, ease);\n }\n .header:hover { color: var(--fx-text-default); }\n .header:focus-visible {\n outline: none;\n box-shadow: var(--fx-effect-focus-ring, none);\n border-radius: var(--fx-radius-sm, 4px);\n }\n :host([expanded]) .header {\n color: var(--fx-text-default);\n font-weight: 700;\n }\n .header-text { flex: 1; min-width: 0; }\n .chevron {\n flex-shrink: 0;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n color: var(--fx-text-muted);\n transition: transform var(--fx-motion-duration-normal, 250ms) var(--fx-motion-easing, ease);\n }\n :host([expanded]) .chevron { transform: rotate(180deg); color: var(--fx-color-primary); }\n .content {\n display: grid;\n grid-template-rows: 0fr;\n transition: grid-template-rows var(--fx-motion-duration-normal, 250ms) var(--fx-motion-easing, ease);\n }\n :host([expanded]) .content { grid-template-rows: 1fr; }\n .content-inner { overflow: hidden; }\n .content-pad {\n padding: 0 var(--fx-space-md, 14px) var(--fx-space-lg, 20px);\n color: var(--fx-text-muted);\n line-height: 1.6;\n }\n `;\n\n static override get observedAttributes(): string[] {\n return ['header', 'expanded', 'disabled'];\n }\n\n get header(): string {\n return this.getAttr('header', '');\n }\n set header(v: string) {\n this.setAttribute('header', v);\n }\n\n get value(): string {\n return this.getAttr('value', '');\n }\n set value(v: string) {\n this.setAttribute('value', v);\n }\n\n get expanded(): boolean {\n return this.hasAttr('expanded');\n }\n set expanded(v: boolean) {\n this.toggleAttr('expanded', v);\n }\n\n get disabled(): boolean {\n return this.hasAttr('disabled');\n }\n set disabled(v: boolean) {\n this.toggleAttr('disabled', v);\n }\n\n protected override connectedCallback(): void {\n super.connectedCallback();\n // O clique vem do shadow root; composedPath() revela o alvo real.\n if (!this._clickListenerAttached) {\n this._clickListenerAttached = true;\n this.addEventListener('click', (e) => {\n const path = e.composedPath() as HTMLElement[];\n if (!path.some((el) => el.classList?.contains('header'))) return;\n if (this.disabled) return;\n this.dispatchEvent(\n new CustomEvent('fx-accordion-toggle', {\n bubbles: true,\n composed: true,\n detail: { panel: this },\n }),\n );\n });\n }\n // Re-render quando o atributo expanded muda (para aria-expanded).\n this._mo = new MutationObserver(() => this.render());\n this._mo.observe(this, { attributes: true, attributeFilter: ['expanded', 'header', 'disabled'] });\n }\n\n protected override disconnectedCallback(): void {\n this._mo?.disconnect();\n this._mo = null;\n }\n\n private _mo: MutationObserver | null = null;\n private _clickListenerAttached = false;\n\n protected override render(): void {\n this.setTemplate(`\n <div class=\"panel\" part=\"panel\">\n <button type=\"button\" class=\"header\" part=\"header\" role=\"button\"\n aria-expanded=\"${this.expanded}\"\n ${this.disabled ? 'aria-disabled=\"true\"' : ''}>\n <span class=\"header-text\" part=\"header-text\">\n <slot name=\"header\">${esc(this.header)}</slot>\n </span>\n <span class=\"chevron\" part=\"chevron\" aria-hidden=\"true\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polyline points=\"6 9 12 15 18 9\"></polyline>\n </svg>\n </span>\n </button>\n <div class=\"content\" part=\"content\" role=\"region\">\n <div class=\"content-inner\">\n <div class=\"content-pad\" part=\"content-pad\"><slot></slot></div>\n </div>\n </div>\n </div>\n `);\n }\n}\n\n/**\n * <fx-accordion> — Conjunto de paineis expansivos (estilo PrimeVue).\n *\n * Por padrao (modo single) abrir um painel fecha os outros.\n * Adicione o atributo `multiple` para permitir varios paineis abertos.\n *\n * Uso:\n * <fx-accordion value=\"p1\">\n * <fx-accordion-panel value=\"p1\" header=\"Titulo 1\">Conteudo…</fx-accordion-panel>\n * <fx-accordion-panel value=\"p2\" header=\"Titulo 2\">Conteudo…</fx-accordion-panel>\n * </fx-accordion>\n *\n * Atributos:\n * - value: valor(es) ativo(s), separados por virgula no modo multiple.\n * - multiple: permite manter varios paineis abertos ao mesmo tempo.\n *\n * Evento: `change` (composed, detail: { value: string[] }).\n */\nexport class FxAccordion extends FxElement {\n static override styles = css`\n :host {\n display: block;\n font-family: var(--fx-font-family);\n font-size: var(--fx-font-size);\n }\n .accordion {\n background: var(--fx-surface-background, #ffffff);\n border: 1px solid var(--fx-border-default);\n border-radius: var(--fx-radius-md, 8px);\n overflow: hidden;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);\n }\n `;\n\n static override get observedAttributes(): string[] {\n return ['value', 'multiple'];\n }\n\n get multiple(): boolean {\n return this.hasAttr('multiple');\n }\n set multiple(v: boolean) {\n this.toggleAttr('multiple', v);\n }\n\n /** Valores ativos como array. */\n get values(): string[] {\n return this.getAttr('value', '').split(',').map(s => s.trim()).filter(Boolean);\n }\n set values(v: string[]) {\n this.setAttribute('value', v.join(','));\n }\n\n protected override connectedCallback(): void {\n this._observer = new MutationObserver(() => this._sync());\n this._observer.observe(this, { childList: true, subtree: true });\n super.connectedCallback();\n // Os paineis filhos podem ainda nao estar upgradados no primeiro sync;\n // reagenda para depois da fila de upgrade de custom elements.\n queueMicrotask(() => this._sync());\n }\n\n protected override disconnectedCallback(): void {\n this._observer?.disconnect();\n this._observer = null;\n }\n\n private _observer: MutationObserver | null = null;\n\n protected override render(): void {\n this.setTemplate(`\n <div class=\"accordion\" part=\"accordion\">\n <slot></slot>\n </div>\n `);\n this._sync();\n this._attachListeners();\n }\n\n /** Painéis do accordion (filhos diretos ou descendentes). */\n private get panels(): FxAccordionPanel[] {\n return Array.from(this.querySelectorAll<FxAccordionPanel>('fx-accordion-panel'));\n }\n\n private _sync(): void {\n const actives = this.values;\n // Leitura via getAttribute (nao via getters) porque os paineis filhos\n // podem ainda nao estar upgradados quando o accordion conecta.\n const panels = Array.from(this.querySelectorAll('fx-accordion-panel'));\n // Apenas na conexao inicial (sem valor definido): abre o primeiro painel.\n if (!this._initialized && actives.length === 0 && panels.length > 0) {\n this._initialized = true;\n const first = panels.find((p) => !p.hasAttribute('disabled'));\n if (first) {\n this.values = [first.getAttribute('value') || '0'];\n return;\n }\n }\n this._initialized = true;\n panels.forEach((p, i) => {\n const v = p.getAttribute('value') || String(i);\n if (!p.hasAttribute('value')) p.setAttribute('value', v);\n p.toggleAttribute('expanded', actives.includes(v));\n });\n }\n\n private _initialized = false;\n\n private _attachListeners(): void {\n if (this._listenersAttached) return;\n this._listenersAttached = true;\n // O painel emite 'fx-accordion-toggle' a partir do proprio host\n // (event retargeting do Shadow DOM impede usar closest('.header') aqui).\n this.addEventListener('fx-accordion-toggle', (e) => {\n const panel = (e as CustomEvent).detail?.panel as FxAccordionPanel | undefined;\n if (!panel || panel.disabled) return;\n this.toggle(panel);\n });\n }\n\n private _listenersAttached = false;\n\n /** Abre/fecha um painel respeitando o modo (single | multiple). */\n toggle(panel: FxAccordionPanel): void {\n const v = panel.value;\n let actives = this.values;\n if (panel.expanded) {\n actives = actives.filter(a => a !== v);\n } else if (this.multiple) {\n actives = [...actives, v];\n } else {\n actives = [v];\n }\n this.values = actives;\n this._sync();\n this.dispatchEvent(\n new CustomEvent('change', {\n bubbles: true,\n composed: true,\n detail: { value: actives },\n }),\n );\n }\n\n /** Abre um painel pelo valor. */\n open(value: string): void {\n const panel = this.panels.find((p, i) => (p.value || String(i)) === value);\n if (panel && !panel.expanded) this.toggle(panel);\n }\n\n /** Fecha um painel pelo valor. */\n close(value: string): void {\n const panel = this.panels.find((p, i) => (p.value || String(i)) === value);\n if (panel && panel.expanded) this.toggle(panel);\n }\n}\n\nexport function defineFxAccordion(): typeof FxAccordion {\n return defineElement('fx-accordion', FxAccordion);\n}\n\nexport function defineFxAccordionPanel(): typeof FxAccordionPanel {\n return defineElement('fx-accordion-panel', FxAccordionPanel);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"accordion.js","sources":["../../../src/components/accordion/accordion.ts"],"sourcesContent":["import { FxElement } from '../../core/base';\nimport { css } from '../../core/css';\nimport { defineElement } from '../../core/define';\nimport { esc } from '../../core/sanitize';\n\n/**\n * <fx-accordion-panel> — Painel individual do accordion.\n *\n * Atributos:\n * - header: titulo exibido no cabecalho (ou use o slot \"header\").\n * - value: identificador unico do painel (usado pelo fx-accordion).\n * - expanded: presenca indica painel aberto (controlado pelo fx-accordion).\n * - disabled: impede a abertura do painel.\n */\nexport class FxAccordionPanel extends FxElement {\n static override styles = css`\n :host {\n display: block;\n font-family: var(--fx-font-family);\n font-size: var(--fx-font-size);\n color: var(--fx-text-default);\n }\n /* A borda fica no wrapper interno (nao no :host): regras do documento\n externo (ex.: preflight do Tailwind com border-width: 0) vencem as\n regras :host do shadow tree, o que apagaria a linha divisoria. */\n .panel {\n border-bottom: 1px solid var(--fx-border-default);\n }\n :host(:last-child) .panel { border-bottom: none; }\n :host([disabled]) { opacity: 0.6; pointer-events: none; }\n .header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--fx-space-md);\n width: 100%;\n box-sizing: border-box;\n padding: var(--fx-space-lg, 20px) var(--fx-space-md, 14px);\n border: none;\n background: transparent;\n font-family: inherit;\n font-size: inherit;\n font-weight: 500;\n color: var(--fx-text-muted);\n text-align: left;\n cursor: pointer;\n transition: color var(--fx-motion-duration-fast, 150ms) var(--fx-motion-easing, ease),\n background var(--fx-motion-duration-fast, 150ms) var(--fx-motion-easing, ease);\n }\n .header:hover { color: var(--fx-text-default); }\n .header:focus-visible {\n outline: none;\n box-shadow: var(--fx-effect-focus-ring, none);\n border-radius: var(--fx-radius-sm, 4px);\n }\n :host([expanded]) .header {\n color: var(--fx-text-default);\n font-weight: 700;\n }\n .header-text { flex: 1; min-width: 0; }\n .chevron {\n flex-shrink: 0;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n color: var(--fx-text-muted);\n transition: transform var(--fx-motion-duration-normal, 250ms) var(--fx-motion-easing, ease);\n }\n :host([expanded]) .chevron { transform: rotate(180deg); color: var(--fx-color-primary); }\n .content {\n display: grid;\n grid-template-rows: 0fr;\n transition: grid-template-rows var(--fx-motion-duration-normal, 250ms) var(--fx-motion-easing, ease);\n }\n :host([expanded]) .content { grid-template-rows: 1fr; }\n .content-inner { overflow: hidden; }\n .content-pad {\n padding: 0 var(--fx-space-md, 14px) var(--fx-space-lg, 20px);\n color: var(--fx-text-muted);\n line-height: 1.6;\n }\n `;\n\n static override get observedAttributes(): string[] {\n return ['header', 'expanded', 'disabled'];\n }\n\n get header(): string {\n return this.getAttr('header', '');\n }\n set header(v: string) {\n this.setAttribute('header', v);\n }\n\n get value(): string {\n return this.getAttr('value', '');\n }\n set value(v: string) {\n this.setAttribute('value', v);\n }\n\n get expanded(): boolean {\n return this.hasAttr('expanded');\n }\n set expanded(v: boolean) {\n this.toggleAttr('expanded', v);\n }\n\n get disabled(): boolean {\n return this.hasAttr('disabled');\n }\n set disabled(v: boolean) {\n this.toggleAttr('disabled', v);\n }\n\n protected override connectedCallback(): void {\n super.connectedCallback();\n // O clique vem do shadow root; composedPath() revela o alvo real.\n if (!this._clickListenerAttached) {\n this._clickListenerAttached = true;\n this.addEventListener('click', (e) => {\n const path = e.composedPath() as HTMLElement[];\n if (!path.some((el) => el.classList?.contains('header'))) return;\n if (this.disabled) return;\n this.dispatchEvent(\n new CustomEvent('fx-accordion-toggle', {\n bubbles: true,\n composed: true,\n detail: { panel: this },\n }),\n );\n });\n }\n // Re-render quando o atributo expanded muda (para aria-expanded).\n this._mo = new MutationObserver(() => this.render());\n this._mo.observe(this, { attributes: true, attributeFilter: ['expanded', 'header', 'disabled'] });\n }\n\n protected override disconnectedCallback(): void {\n this._mo?.disconnect();\n this._mo = null;\n super.disconnectedCallback();\n }\n\n private _mo: MutationObserver | null = null;\n private _clickListenerAttached = false;\n\n protected override render(): void {\n this.setTemplate(`\n <div class=\"panel\" part=\"panel\">\n <button type=\"button\" class=\"header\" part=\"header\" role=\"button\"\n aria-expanded=\"${this.expanded}\"\n ${this.disabled ? 'aria-disabled=\"true\"' : ''}>\n <span class=\"header-text\" part=\"header-text\">\n <slot name=\"header\">${esc(this.header)}</slot>\n </span>\n <span class=\"chevron\" part=\"chevron\" aria-hidden=\"true\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polyline points=\"6 9 12 15 18 9\"></polyline>\n </svg>\n </span>\n </button>\n <div class=\"content\" part=\"content\" role=\"region\">\n <div class=\"content-inner\">\n <div class=\"content-pad\" part=\"content-pad\"><slot></slot></div>\n </div>\n </div>\n </div>\n `);\n }\n}\n\n/**\n * <fx-accordion> — Conjunto de paineis expansivos (estilo PrimeVue).\n *\n * Por padrao (modo single) abrir um painel fecha os outros.\n * Adicione o atributo `multiple` para permitir varios paineis abertos.\n *\n * Uso:\n * <fx-accordion value=\"p1\">\n * <fx-accordion-panel value=\"p1\" header=\"Titulo 1\">Conteudo…</fx-accordion-panel>\n * <fx-accordion-panel value=\"p2\" header=\"Titulo 2\">Conteudo…</fx-accordion-panel>\n * </fx-accordion>\n *\n * Atributos:\n * - value: valor(es) ativo(s), separados por virgula no modo multiple.\n * - multiple: permite manter varios paineis abertos ao mesmo tempo.\n *\n * Evento: `change` (composed, detail: { value: string[] }).\n */\nexport class FxAccordion extends FxElement {\n static override styles = css`\n :host {\n display: block;\n font-family: var(--fx-font-family);\n font-size: var(--fx-font-size);\n }\n .accordion {\n background: var(--fx-surface-background, #ffffff);\n border: 1px solid var(--fx-border-default);\n border-radius: var(--fx-radius-md, 8px);\n overflow: hidden;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);\n }\n `;\n\n static override get observedAttributes(): string[] {\n return ['value', 'multiple'];\n }\n\n get multiple(): boolean {\n return this.hasAttr('multiple');\n }\n set multiple(v: boolean) {\n this.toggleAttr('multiple', v);\n }\n\n /** Valores ativos como array. */\n get values(): string[] {\n return this.getAttr('value', '').split(',').map(s => s.trim()).filter(Boolean);\n }\n set values(v: string[]) {\n this.setAttribute('value', v.join(','));\n }\n\n protected override connectedCallback(): void {\n this._observer = new MutationObserver(() => this._sync());\n this._observer.observe(this, { childList: true, subtree: true });\n super.connectedCallback();\n // Os paineis filhos podem ainda nao estar upgradados no primeiro sync;\n // reagenda para depois da fila de upgrade de custom elements.\n queueMicrotask(() => this._sync());\n }\n\n protected override disconnectedCallback(): void {\n this._observer?.disconnect();\n this._observer = null;\n }\n\n private _observer: MutationObserver | null = null;\n\n protected override render(): void {\n this.setTemplate(`\n <div class=\"accordion\" part=\"accordion\">\n <slot></slot>\n </div>\n `);\n this._sync();\n this._attachListeners();\n }\n\n /** Painéis do accordion (filhos diretos ou descendentes). */\n private get panels(): FxAccordionPanel[] {\n return Array.from(this.querySelectorAll<FxAccordionPanel>('fx-accordion-panel'));\n }\n\n private _sync(): void {\n const actives = this.values;\n // Leitura via getAttribute (nao via getters) porque os paineis filhos\n // podem ainda nao estar upgradados quando o accordion conecta.\n const panels = Array.from(this.querySelectorAll('fx-accordion-panel'));\n // Apenas na conexao inicial (sem valor definido): abre o primeiro painel.\n if (!this._initialized && actives.length === 0 && panels.length > 0) {\n this._initialized = true;\n const first = panels.find((p) => !p.hasAttribute('disabled'));\n if (first) {\n this.values = [first.getAttribute('value') || '0'];\n return;\n }\n }\n this._initialized = true;\n panels.forEach((p, i) => {\n const v = p.getAttribute('value') || String(i);\n if (!p.hasAttribute('value')) p.setAttribute('value', v);\n p.toggleAttribute('expanded', actives.includes(v));\n });\n }\n\n private _initialized = false;\n\n private _attachListeners(): void {\n if (this._listenersAttached) return;\n this._listenersAttached = true;\n // O painel emite 'fx-accordion-toggle' a partir do proprio host\n // (event retargeting do Shadow DOM impede usar closest('.header') aqui).\n this.addEventListener('fx-accordion-toggle', (e) => {\n const panel = (e as CustomEvent).detail?.panel as FxAccordionPanel | undefined;\n if (!panel || panel.disabled) return;\n this.toggle(panel);\n });\n }\n\n private _listenersAttached = false;\n\n /** Abre/fecha um painel respeitando o modo (single | multiple). */\n toggle(panel: FxAccordionPanel): void {\n const v = panel.value;\n let actives = this.values;\n if (panel.expanded) {\n actives = actives.filter(a => a !== v);\n } else if (this.multiple) {\n actives = [...actives, v];\n } else {\n actives = [v];\n }\n this.values = actives;\n this._sync();\n this.dispatchEvent(\n new CustomEvent('change', {\n bubbles: true,\n composed: true,\n detail: { value: actives },\n }),\n );\n }\n\n /** Abre um painel pelo valor. */\n open(value: string): void {\n const panel = this.panels.find((p, i) => (p.value || String(i)) === value);\n if (panel && !panel.expanded) this.toggle(panel);\n }\n\n /** Fecha um painel pelo valor. */\n close(value: string): void {\n const panel = this.panels.find((p, i) => (p.value || String(i)) === value);\n if (panel && panel.expanded) this.toggle(panel);\n }\n}\n\nexport function defineFxAccordion(): typeof FxAccordion {\n return defineElement('fx-accordion', FxAccordion);\n}\n\nexport function defineFxAccordionPanel(): typeof FxAccordionPanel {\n return defineElement('fx-accordion-panel', FxAccordionPanel);\n}\n"],"names":[],"mappings":"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"}
@@ -1,5 +1,4 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["../../icons/index.js","../../icons/names.js","../../icons/base-css.js"])))=>i.map(i=>d[i]);
2
- import { __vitePreload } from "../../_virtual/preload-helper.js";
1
+ import { __fenixPreload } from "../../_virtual/preload-helper.js";
3
2
  import { FxElement } from "../../core/base.js";
4
3
  import { css } from "../../core/css.js";
5
4
  import { defineElement } from "../../core/define.js";
@@ -13,7 +12,7 @@ const _FxAlert = class _FxAlert extends FxElement {
13
12
  const variant = this.getAttr("variant", "info");
14
13
  const title = this.getAttr("title");
15
14
  const iconName = this.getAttr("icon");
16
- if (isFenixIconName(iconName)) void __vitePreload(() => import("../../icons/index.js"), true ? __vite__mapDeps([0,1,2]) : void 0, import.meta.url);
15
+ if (isFenixIconName(iconName)) void __fenixPreload(() => import("../../icons/index.js"), true ? [] : void 0, import.meta.url);
17
16
  const icons = {
18
17
  info: "ℹ",
19
18
  success: "✓",
@@ -1 +1 @@
1
- {"version":3,"mappings":";;;;;;;AAaO,MAAM,WAAN,MAAM,iBAAgB,UAAU;AAAA,EAsCrC,WAAoB,qBAA+B;AACjD,WAAO,CAAC,WAAW,SAAS,eAAe,MAAM;AAAA,EACnD;AAAA,EAEmB,SAAe;AAChC,UAAM,UAAU,KAAK,QAAQ,WAAW,MAAM;AAC9C,UAAM,QAAQ,KAAK,QAAQ,OAAO;AAClC,UAAM,WAAW,KAAK,QAAQ,MAAM;AACpC,QAAI,gBAAgB,QAAQ,EAAG,0BAAK,OAAO,sBAAa;AACxD,UAAM,QAAgC;AAAA,MACpC,MAAM;AAAA,MAAK,SAAS;AAAA,MAAK,SAAS;AAAA,MAAK,QAAQ;AAAA;AAEjD,UAAM,WAAW,WACb,oBAAoB,gBAAgB,QAAQ,IAAI,aAAa,EAAE,oCAAoC,IAAI,QAAQ,CAAC,YAChH,sBAAsB,MAAM,OAAO,KAAK,GAAG;AAE/C,SAAK,YAAY;AAAA;AAAA,UAEX,QAAQ;AAAA;AAAA,YAEN,QAAQ,sBAAsB,IAAI,KAAK,CAAC,WAAW,EAAE;AAAA;AAAA;AAAA,UAGvD,KAAK,QAAQ,aAAa,IAAI,uEAAuE,EAAE;AAAA;AAAA,KAE5G;AAED,SAAK,KAAK,cAAc,QAAQ,GAAG,iBAAiB,SAAS,MAAM;AACjE,WAAK,SAAS;AACd,WAAK,cAAc,IAAI,YAAY,WAAW,EAAE,SAAS,MAAM,UAAU,MAAM,CAAC;AAAA,IAClF,CAAC;AAAA,EACH;AACF;AArEE,SAAgB,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAwBrB,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAzBlB,IAAM,UAAN;AAwEA,SAAS,gBAAgC;AAC9C,SAAO,cAAc,YAAY,OAAO;AAC1C","names":[],"ignoreList":[],"sources":["../../../src/components/alert/alert.ts"],"sourcesContent":["import { FxElement } from '../../core/base';\nimport { css } from '../../core/css';\nimport { defineElement } from '../../core/define';\nimport { esc } from '../../core/sanitize';\nimport { FENIX_ICON_BASE_CSS, isFenixIconName } from '../../icons/base-css';\n\n/**\n * <fx-alert> — Aviso inline com variantes semânticas.\n *\n * Atributos: variant (info|success|warning|danger, padrão info), title, dismissible,\n * icon (nome da Fenix Icons, ex.: icon=\"notification\" — substitui o glifo padrão).\n * Slot padrão: conteúdo da mensagem. Evento `dismiss`.\n */\nexport class FxAlert extends FxElement {\n static override styles = css`\n :host {\n display: block;\n font-family: var(--fx-font-family);\n --_color: var(--fx-color-primary);\n --_bg: color-mix(in srgb, var(--fx-color-primary) 10%, var(--fx-surface-background));\n }\n :host([variant='info']) { --_color: var(--fx-color-info); --_bg: color-mix(in srgb, var(--fx-color-info) 10%, var(--fx-surface-background)); }\n :host([variant='success']) { --_color: var(--fx-color-success); --_bg: color-mix(in srgb, var(--fx-color-success) 10%, var(--fx-surface-background)); }\n :host([variant='warning']) { --_color: var(--fx-color-warning); --_bg: color-mix(in srgb, var(--fx-color-warning) 12%, var(--fx-surface-background)); }\n :host([variant='danger']) { --_color: var(--fx-color-danger); --_bg: color-mix(in srgb, var(--fx-color-danger) 10%, var(--fx-surface-background)); }\n .alert {\n display: flex;\n align-items: flex-start;\n gap: var(--fx-space-md);\n background: var(--_bg);\n border: 1px solid color-mix(in srgb, var(--_color) 30%, transparent);\n border-radius: var(--fx-radius-md);\n padding: var(--fx-space-md) var(--fx-space-lg);\n font-size: var(--fx-font-size);\n color: var(--fx-text-default);\n }\n :host([hidden]) { display: none; }\n .icon { color: var(--_color); font-weight: bold; line-height: 1.4; }\n ${FENIX_ICON_BASE_CSS}\n .icon.fx-icon { font-size: 20px; line-height: 1.2; }\n .content { flex: 1; }\n .title { font-weight: 600; }\n .body { margin-top: 2px; }\n .close {\n border: none; background: transparent; cursor: pointer;\n color: var(--fx-text-muted); font-size: calc(var(--fx-font-size) + 2px);\n line-height: 1; padding: 0; border-radius: var(--fx-radius-full);\n }\n .close:hover { color: var(--_color); }\n `;\n\n static override get observedAttributes(): string[] {\n return ['variant', 'title', 'dismissible', 'icon'];\n }\n\n protected override render(): void {\n const variant = this.getAttr('variant', 'info');\n const title = this.getAttr('title');\n const iconName = this.getAttr('icon');\n if (isFenixIconName(iconName)) void import('../../icons');\n const icons: Record<string, string> = {\n info: 'ℹ', success: '✓', warning: '⚠', danger: '✕',\n };\n const iconHtml = iconName\n ? `<span class=\"icon${isFenixIconName(iconName) ? ' fx-icon' : ''}\" part=\"icon\" aria-hidden=\"true\">${esc(iconName)}</span>`\n : `<span class=\"icon\">${icons[variant] ?? 'ℹ'}</span>`;\n\n this.setTemplate(`\n <div class=\"alert\" part=\"alert\" role=\"alert\">\n ${iconHtml}\n <div class=\"content\">\n ${title ? `<div class=\"title\">${esc(title)}</div>` : ''}\n <div class=\"body\"><slot></slot></div>\n </div>\n ${this.hasAttr('dismissible') ? '<button type=\"button\" class=\"close\" aria-label=\"Fechar\">×</button>' : ''}\n </div>\n `);\n\n this.root.querySelector('.close')?.addEventListener('click', () => {\n this.hidden = true;\n this.dispatchEvent(new CustomEvent('dismiss', { bubbles: true, composed: true }));\n });\n }\n}\n\nexport function defineFxAlert(): typeof FxAlert {\n return defineElement('fx-alert', FxAlert);\n}\n"],"file":"components/alert/alert.js"}
1
+ {"version":3,"mappings":";;;;;;AAaO,MAAM,WAAN,MAAM,iBAAgB,UAAU;AAAA,EAsCrC,WAAoB,qBAA+B;AACjD,WAAO,CAAC,WAAW,SAAS,eAAe,MAAM;AAAA,EACnD;AAAA,EAEmB,SAAe;AAChC,UAAM,UAAU,KAAK,QAAQ,WAAW,MAAM;AAC9C,UAAM,QAAQ,KAAK,QAAQ,OAAO;AAClC,UAAM,WAAW,KAAK,QAAQ,MAAM;AACpC,QAAI,gBAAgB,QAAQ,EAAG,0BAAK,OAAO,sBAAa;AACxD,UAAM,QAAgC;AAAA,MACpC,MAAM;AAAA,MAAK,SAAS;AAAA,MAAK,SAAS;AAAA,MAAK,QAAQ;AAAA;AAEjD,UAAM,WAAW,WACb,oBAAoB,gBAAgB,QAAQ,IAAI,aAAa,EAAE,oCAAoC,IAAI,QAAQ,CAAC,YAChH,sBAAsB,MAAM,OAAO,KAAK,GAAG;AAE/C,SAAK,YAAY;AAAA;AAAA,UAEX,QAAQ;AAAA;AAAA,YAEN,QAAQ,sBAAsB,IAAI,KAAK,CAAC,WAAW,EAAE;AAAA;AAAA;AAAA,UAGvD,KAAK,QAAQ,aAAa,IAAI,uEAAuE,EAAE;AAAA;AAAA,KAE5G;AAED,SAAK,KAAK,cAAc,QAAQ,GAAG,iBAAiB,SAAS,MAAM;AACjE,WAAK,SAAS;AACd,WAAK,cAAc,IAAI,YAAY,WAAW,EAAE,SAAS,MAAM,UAAU,MAAM,CAAC;AAAA,IAClF,CAAC;AAAA,EACH;AACF;AArEE,SAAgB,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAwBrB,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAzBlB,IAAM,UAAN;AAwEA,SAAS,gBAAgC;AAC9C,SAAO,cAAc,YAAY,OAAO;AAC1C","names":[],"ignoreList":[],"sources":["../../../src/components/alert/alert.ts"],"sourcesContent":["import { FxElement } from '../../core/base';\nimport { css } from '../../core/css';\nimport { defineElement } from '../../core/define';\nimport { esc } from '../../core/sanitize';\nimport { FENIX_ICON_BASE_CSS, isFenixIconName } from '../../icons/base-css';\n\n/**\n * <fx-alert> — Aviso inline com variantes semânticas.\n *\n * Atributos: variant (info|success|warning|danger, padrão info), title, dismissible,\n * icon (nome da Fenix Icons, ex.: icon=\"notification\" — substitui o glifo padrão).\n * Slot padrão: conteúdo da mensagem. Evento `dismiss`.\n */\nexport class FxAlert extends FxElement {\n static override styles = css`\n :host {\n display: block;\n font-family: var(--fx-font-family);\n --_color: var(--fx-color-primary);\n --_bg: color-mix(in srgb, var(--fx-color-primary) 10%, var(--fx-surface-background));\n }\n :host([variant='info']) { --_color: var(--fx-color-info); --_bg: color-mix(in srgb, var(--fx-color-info) 10%, var(--fx-surface-background)); }\n :host([variant='success']) { --_color: var(--fx-color-success); --_bg: color-mix(in srgb, var(--fx-color-success) 10%, var(--fx-surface-background)); }\n :host([variant='warning']) { --_color: var(--fx-color-warning); --_bg: color-mix(in srgb, var(--fx-color-warning) 12%, var(--fx-surface-background)); }\n :host([variant='danger']) { --_color: var(--fx-color-danger); --_bg: color-mix(in srgb, var(--fx-color-danger) 10%, var(--fx-surface-background)); }\n .alert {\n display: flex;\n align-items: flex-start;\n gap: var(--fx-space-md);\n background: var(--_bg);\n border: 1px solid color-mix(in srgb, var(--_color) 30%, transparent);\n border-radius: var(--fx-radius-md);\n padding: var(--fx-space-md) var(--fx-space-lg);\n font-size: var(--fx-font-size);\n color: var(--fx-text-default);\n }\n :host([hidden]) { display: none; }\n .icon { color: var(--_color); font-weight: bold; line-height: 1.4; }\n ${FENIX_ICON_BASE_CSS}\n .icon.fx-icon { font-size: 20px; line-height: 1.2; }\n .content { flex: 1; }\n .title { font-weight: 600; }\n .body { margin-top: 2px; }\n .close {\n border: none; background: transparent; cursor: pointer;\n color: var(--fx-text-muted); font-size: calc(var(--fx-font-size) + 2px);\n line-height: 1; padding: 0; border-radius: var(--fx-radius-full);\n }\n .close:hover { color: var(--_color); }\n `;\n\n static override get observedAttributes(): string[] {\n return ['variant', 'title', 'dismissible', 'icon'];\n }\n\n protected override render(): void {\n const variant = this.getAttr('variant', 'info');\n const title = this.getAttr('title');\n const iconName = this.getAttr('icon');\n if (isFenixIconName(iconName)) void import('../../icons');\n const icons: Record<string, string> = {\n info: 'ℹ', success: '✓', warning: '⚠', danger: '✕',\n };\n const iconHtml = iconName\n ? `<span class=\"icon${isFenixIconName(iconName) ? ' fx-icon' : ''}\" part=\"icon\" aria-hidden=\"true\">${esc(iconName)}</span>`\n : `<span class=\"icon\">${icons[variant] ?? 'ℹ'}</span>`;\n\n this.setTemplate(`\n <div class=\"alert\" part=\"alert\" role=\"alert\">\n ${iconHtml}\n <div class=\"content\">\n ${title ? `<div class=\"title\">${esc(title)}</div>` : ''}\n <div class=\"body\"><slot></slot></div>\n </div>\n ${this.hasAttr('dismissible') ? '<button type=\"button\" class=\"close\" aria-label=\"Fechar\">×</button>' : ''}\n </div>\n `);\n\n this.root.querySelector('.close')?.addEventListener('click', () => {\n this.hidden = true;\n this.dispatchEvent(new CustomEvent('dismiss', { bubbles: true, composed: true }));\n });\n }\n}\n\nexport function defineFxAlert(): typeof FxAlert {\n return defineElement('fx-alert', FxAlert);\n}\n"],"file":"components/alert/alert.js"}
@@ -1,5 +1,4 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["../../icons/index.js","../../icons/names.js","../../icons/base-css.js"])))=>i.map(i=>d[i]);
2
- import { __vitePreload } from "../../_virtual/preload-helper.js";
1
+ import { __fenixPreload } from "../../_virtual/preload-helper.js";
3
2
  import { FxElement } from "../../core/base.js";
4
3
  import { css } from "../../core/css.js";
5
4
  import { defineElement } from "../../core/define.js";
@@ -28,7 +27,7 @@ const _FxConfirmPopup = class _FxConfirmPopup extends FxElement {
28
27
  const message = this.getAttr("message");
29
28
  const icon = this.getAttr("icon");
30
29
  const iconIsFx = isFenixIconName(icon);
31
- if (iconIsFx) void __vitePreload(() => import("../../icons/index.js"), true ? __vite__mapDeps([0,1,2]) : void 0, import.meta.url);
30
+ if (iconIsFx) void __fenixPreload(() => import("../../icons/index.js"), true ? [] : void 0, import.meta.url);
32
31
  const acceptLabel = this.getAttr("accept-label", "Sim");
33
32
  const rejectLabel = this.getAttr("reject-label", "Não");
34
33
  this.setTemplate(`
@@ -1 +1 @@
1
- {"version":3,"mappings":"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","names":[],"ignoreList":[],"sources":["../../../src/components/confirmpopup/confirmpopup.ts"],"sourcesContent":["import { FxElement } from '../../core/base';\nimport { css } from '../../core/css';\nimport { defineElement } from '../../core/define';\nimport { esc } from '../../core/sanitize';\nimport { FENIX_ICON_BASE_CSS, isFenixIconName } from '../../icons/base-css';\n\n/**\n * <fx-confirmpopup> — Popup de confirmação não-modal ancorado em um elemento,\n * exibido acima ou abaixo dinamicamente (com flip automático quando não há\n * espaço na viewport), no estilo ConfirmPopup do PrimeVue.\n *\n * Atributos:\n * - target (seletor CSS do elemento âncora — obrigatório para abrir);\n * - message (texto da mensagem, quando o slot padrão não é usado);\n * - icon (emoji/glifo exibido antes da mensagem; se for um nome da Fenix Icons,\n * ex.: icon=\"help\", é renderizado com a fonte de ícones);\n * - accept-label / reject-label (textos dos botões padrão);\n * - position (top|bottom|auto — padrão `auto`, que faz flip conforme o espaço);\n * - open (exibe o popup).\n *\n * Slots:\n * - padrão: corpo da mensagem (template \"message\");\n * - `accept`: conteúdo do botão de confirmação (template \"accept\");\n * - `reject`: conteúdo do botão de rejeição (template \"reject\").\n *\n * Eventos (composed): `accept` e `reject` — ambos fecham o popup.\n */\nexport class FxConfirmPopup extends FxElement {\n static override styles = css`\n :host { display: contents; }\n .popup {\n position: fixed;\n margin: 0;\n background: var(--fx-surface-background);\n border: 1px solid var(--fx-border-default);\n border-radius: var(--fx-radius-md);\n box-shadow: var(--fx-shadow-lg);\n padding: var(--fx-space-md) var(--fx-space-lg);\n min-width: 220px;\n max-width: min(380px, calc(100vw - 24px));\n font-family: var(--fx-font-family);\n font-size: var(--fx-font-size);\n color: var(--fx-text-default);\n z-index: var(--fx-z-modal, 1100);\n animation: fxcp-pop var(--fx-motion-duration-fast, 150ms) var(--fx-motion-easing, ease);\n }\n .popup[hidden] { display: none; }\n @keyframes fxcp-pop { from { opacity: 0; transform: scale(0.96); } to { opacity: 1; transform: scale(1); } }\n /* seta indicadora */\n .popup::before {\n content: '';\n position: absolute;\n left: var(--fxcp-arrow-x, 50%);\n border: 7px solid transparent;\n }\n .popup[data-side='bottom']::before {\n top: -14px;\n border-bottom-color: var(--fx-border-default);\n }\n .popup[data-side='top']::before {\n bottom: -14px;\n border-top-color: var(--fx-border-default);\n }\n .popup::after {\n content: '';\n position: absolute;\n left: var(--fxcp-arrow-x, 50%);\n border: 6px solid transparent;\n }\n .popup[data-side='bottom']::after {\n top: -12px;\n border-bottom-color: var(--fx-surface-background);\n }\n .popup[data-side='top']::after {\n bottom: -12px;\n border-top-color: var(--fx-surface-background);\n }\n .message {\n display: flex;\n align-items: flex-start;\n gap: var(--fx-space-sm);\n }\n .icon { font-size: calc(var(--fx-font-size) + 4px); line-height: 1.2; }\n ${FENIX_ICON_BASE_CSS}\n .icon.fx-icon { font-size: calc(var(--fx-font-size) + 6px); color: var(--fx-color-primary); }\n .text { margin: 0; }\n footer {\n display: flex;\n justify-content: flex-end;\n gap: var(--fx-space-sm);\n margin-top: var(--fx-space-md);\n }\n footer button {\n font-family: var(--fx-font-family);\n font-size: calc(var(--fx-font-size) - 2px);\n padding: var(--fx-space-xs) var(--fx-space-md);\n border-radius: var(--fx-radius-sm);\n border: 1px solid var(--fx-border-default);\n background: var(--fx-surface-background);\n color: var(--fx-text-default);\n cursor: pointer;\n transition: background var(--fx-motion-duration-fast) var(--fx-motion-easing);\n }\n footer button:hover { background: var(--fx-surface-surface-hover, rgba(0, 0, 0, 0.04)); }\n footer button.accept {\n background: var(--fx-color-primary);\n border-color: var(--fx-color-primary);\n color: #fff;\n }\n footer button.accept:hover { filter: brightness(0.92); background: var(--fx-color-primary); }\n `;\n\n static override get observedAttributes(): string[] {\n return ['open', 'target', 'message', 'icon', 'accept-label', 'reject-label', 'position'];\n }\n\n get open(): boolean { return this.hasAttr('open'); }\n set open(value: boolean) { this.toggleAttr('open', value); }\n\n protected override render(): void {\n const message = this.getAttr('message');\n const icon = this.getAttr('icon');\n const iconIsFx = isFenixIconName(icon);\n if (iconIsFx) void import('../../icons');\n const acceptLabel = this.getAttr('accept-label', 'Sim');\n const rejectLabel = this.getAttr('reject-label', 'Não');\n\n this.setTemplate(`\n <div class=\"popup\" part=\"popup\" role=\"alertdialog\" aria-modal=\"false\" ${this.open ? '' : 'hidden'}>\n <div class=\"message\" part=\"message\">\n ${icon ? `<span class=\"icon${iconIsFx ? ' fx-icon' : ''}\" aria-hidden=\"true\">${esc(icon)}</span>` : ''}\n <p class=\"text\"><slot>${esc(message)}</slot></p>\n </div>\n <footer part=\"footer\">\n <slot name=\"reject\">\n <button type=\"button\" class=\"reject\" part=\"reject-button\">${esc(rejectLabel)}</button>\n </slot>\n <slot name=\"accept\">\n <button type=\"button\" class=\"accept\" part=\"accept-button\">${esc(acceptLabel)}</button>\n </slot>\n </footer>\n </div>\n `);\n\n if (!this.open) return;\n\n const popup = this.root.querySelector<HTMLElement>('.popup');\n if (!popup) return;\n\n const close = (event: 'accept' | 'reject'): void => {\n this.open = false;\n this._cleanup?.();\n this._cleanup = undefined;\n this._restoreFocus();\n this.dispatchEvent(new CustomEvent(event, { bubbles: true, composed: true }));\n };\n\n this.root.querySelector('.reject')?.addEventListener('click', () => close('reject'));\n this.root.querySelector('.accept')?.addEventListener('click', () => close('accept'));\n\n // ESC fecha (reject) — clique fora fecha (reject)\n const onKey = (e: KeyboardEvent): void => {\n if (e.key === 'Escape') { e.stopPropagation(); close('reject'); }\n };\n const onPointerDown = (e: MouseEvent): void => {\n const path = e.composedPath();\n const anchor = this._anchor();\n const hitAnchor = anchor ? path.includes(anchor) : false;\n if (!path.includes(popup) && !hitAnchor) close('reject');\n };\n document.addEventListener('keydown', onKey);\n document.addEventListener('pointerdown', onPointerDown, true);\n this._cleanup = () => {\n document.removeEventListener('keydown', onKey);\n document.removeEventListener('pointerdown', onPointerDown, true);\n };\n\n this._position(popup);\n this._previouslyFocused = document.activeElement as HTMLElement | null;\n requestAnimationFrame(() => {\n this.root.querySelector<HTMLElement>('button.accept')?.focus();\n });\n }\n\n private _cleanup?: () => void;\n private _previouslyFocused: HTMLElement | null = null;\n\n private _anchor(): HTMLElement | null {\n const selector = this.getAttr('target');\n if (!selector) return null;\n try {\n return document.querySelector<HTMLElement>(selector);\n } catch {\n return null;\n }\n }\n\n /**\n * Posiciona o popup fixo junto ao âncora, acima ou abaixo dinamicamente:\n * `position=\"auto\"` (padrão) prefere abaixo e faz flip para cima quando\n * não há espaço; `top`/`bottom` forçam o lado.\n */\n private _position(popup: HTMLElement): void {\n const anchor = this._anchor();\n if (!anchor) return;\n popup.hidden = false;\n\n const a = anchor.getBoundingClientRect();\n const p = popup.getBoundingClientRect();\n const gap = 8;\n const margin = 8;\n\n let side: 'top' | 'bottom';\n const pos = this.getAttr('position', 'auto');\n if (pos === 'top') side = 'top';\n else if (pos === 'bottom') side = 'bottom';\n else side = a.bottom + gap + p.height <= window.innerHeight - margin ? 'bottom' : 'top';\n\n // clamp horizontal para nunca sair da viewport\n const left = Math.min(\n Math.max(margin, a.left + a.width / 2 - p.width / 2),\n window.innerWidth - p.width - margin,\n );\n const top = side === 'bottom' ? a.bottom + gap : a.top - gap - p.height;\n\n popup.dataset.side = side;\n popup.style.left = `${Math.round(left)}px`;\n popup.style.top = `${Math.round(Math.max(margin, top))}px`;\n // posição da seta relativa ao popup\n const arrowX = Math.min(Math.max(a.left + a.width / 2 - left, 16), p.width - 16);\n popup.style.setProperty('--fxcp-arrow-x', `${Math.round(arrowX)}px`);\n }\n\n private _restoreFocus(): void {\n if (this._previouslyFocused?.isConnected) this._previouslyFocused.focus();\n this._previouslyFocused = null;\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n // reposiciona em scroll/resize enquanto aberto\n window.addEventListener('scroll', this._onReposition, true);\n window.addEventListener('resize', this._onReposition);\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n window.removeEventListener('scroll', this._onReposition, true);\n window.removeEventListener('resize', this._onReposition);\n this._cleanup?.();\n this._cleanup = undefined;\n this._restoreFocus();\n }\n\n private _onReposition = (): void => {\n if (!this.open) return;\n const popup = this.root.querySelector<HTMLElement>('.popup');\n if (popup && !popup.hidden) this._position(popup);\n };\n}\n\nexport function defineFxConfirmPopup(): typeof FxConfirmPopup {\n return defineElement('fx-confirmpopup', FxConfirmPopup);\n}\n\n"],"file":"components/confirmpopup/confirmpopup.js"}
1
+ {"version":3,"mappings":"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","names":[],"ignoreList":[],"sources":["../../../src/components/confirmpopup/confirmpopup.ts"],"sourcesContent":["import { FxElement } from '../../core/base';\nimport { css } from '../../core/css';\nimport { defineElement } from '../../core/define';\nimport { esc } from '../../core/sanitize';\nimport { FENIX_ICON_BASE_CSS, isFenixIconName } from '../../icons/base-css';\n\n/**\n * <fx-confirmpopup> — Popup de confirmação não-modal ancorado em um elemento,\n * exibido acima ou abaixo dinamicamente (com flip automático quando não há\n * espaço na viewport), no estilo ConfirmPopup do PrimeVue.\n *\n * Atributos:\n * - target (seletor CSS do elemento âncora — obrigatório para abrir);\n * - message (texto da mensagem, quando o slot padrão não é usado);\n * - icon (emoji/glifo exibido antes da mensagem; se for um nome da Fenix Icons,\n * ex.: icon=\"help\", é renderizado com a fonte de ícones);\n * - accept-label / reject-label (textos dos botões padrão);\n * - position (top|bottom|auto — padrão `auto`, que faz flip conforme o espaço);\n * - open (exibe o popup).\n *\n * Slots:\n * - padrão: corpo da mensagem (template \"message\");\n * - `accept`: conteúdo do botão de confirmação (template \"accept\");\n * - `reject`: conteúdo do botão de rejeição (template \"reject\").\n *\n * Eventos (composed): `accept` e `reject` — ambos fecham o popup.\n */\nexport class FxConfirmPopup extends FxElement {\n static override styles = css`\n :host { display: contents; }\n .popup {\n position: fixed;\n margin: 0;\n background: var(--fx-surface-background);\n border: 1px solid var(--fx-border-default);\n border-radius: var(--fx-radius-md);\n box-shadow: var(--fx-shadow-lg);\n padding: var(--fx-space-md) var(--fx-space-lg);\n min-width: 220px;\n max-width: min(380px, calc(100vw - 24px));\n font-family: var(--fx-font-family);\n font-size: var(--fx-font-size);\n color: var(--fx-text-default);\n z-index: var(--fx-z-modal, 1100);\n animation: fxcp-pop var(--fx-motion-duration-fast, 150ms) var(--fx-motion-easing, ease);\n }\n .popup[hidden] { display: none; }\n @keyframes fxcp-pop { from { opacity: 0; transform: scale(0.96); } to { opacity: 1; transform: scale(1); } }\n /* seta indicadora */\n .popup::before {\n content: '';\n position: absolute;\n left: var(--fxcp-arrow-x, 50%);\n border: 7px solid transparent;\n }\n .popup[data-side='bottom']::before {\n top: -14px;\n border-bottom-color: var(--fx-border-default);\n }\n .popup[data-side='top']::before {\n bottom: -14px;\n border-top-color: var(--fx-border-default);\n }\n .popup::after {\n content: '';\n position: absolute;\n left: var(--fxcp-arrow-x, 50%);\n border: 6px solid transparent;\n }\n .popup[data-side='bottom']::after {\n top: -12px;\n border-bottom-color: var(--fx-surface-background);\n }\n .popup[data-side='top']::after {\n bottom: -12px;\n border-top-color: var(--fx-surface-background);\n }\n .message {\n display: flex;\n align-items: flex-start;\n gap: var(--fx-space-sm);\n }\n .icon { font-size: calc(var(--fx-font-size) + 4px); line-height: 1.2; }\n ${FENIX_ICON_BASE_CSS}\n .icon.fx-icon { font-size: calc(var(--fx-font-size) + 6px); color: var(--fx-color-primary); }\n .text { margin: 0; }\n footer {\n display: flex;\n justify-content: flex-end;\n gap: var(--fx-space-sm);\n margin-top: var(--fx-space-md);\n }\n footer button {\n font-family: var(--fx-font-family);\n font-size: calc(var(--fx-font-size) - 2px);\n padding: var(--fx-space-xs) var(--fx-space-md);\n border-radius: var(--fx-radius-sm);\n border: 1px solid var(--fx-border-default);\n background: var(--fx-surface-background);\n color: var(--fx-text-default);\n cursor: pointer;\n transition: background var(--fx-motion-duration-fast) var(--fx-motion-easing);\n }\n footer button:hover { background: var(--fx-surface-surface-hover, rgba(0, 0, 0, 0.04)); }\n footer button.accept {\n background: var(--fx-color-primary);\n border-color: var(--fx-color-primary);\n color: #fff;\n }\n footer button.accept:hover { filter: brightness(0.92); background: var(--fx-color-primary); }\n `;\n\n static override get observedAttributes(): string[] {\n return ['open', 'target', 'message', 'icon', 'accept-label', 'reject-label', 'position'];\n }\n\n get open(): boolean { return this.hasAttr('open'); }\n set open(value: boolean) { this.toggleAttr('open', value); }\n\n protected override render(): void {\n const message = this.getAttr('message');\n const icon = this.getAttr('icon');\n const iconIsFx = isFenixIconName(icon);\n if (iconIsFx) void import('../../icons');\n const acceptLabel = this.getAttr('accept-label', 'Sim');\n const rejectLabel = this.getAttr('reject-label', 'Não');\n\n this.setTemplate(`\n <div class=\"popup\" part=\"popup\" role=\"alertdialog\" aria-modal=\"false\" ${this.open ? '' : 'hidden'}>\n <div class=\"message\" part=\"message\">\n ${icon ? `<span class=\"icon${iconIsFx ? ' fx-icon' : ''}\" aria-hidden=\"true\">${esc(icon)}</span>` : ''}\n <p class=\"text\"><slot>${esc(message)}</slot></p>\n </div>\n <footer part=\"footer\">\n <slot name=\"reject\">\n <button type=\"button\" class=\"reject\" part=\"reject-button\">${esc(rejectLabel)}</button>\n </slot>\n <slot name=\"accept\">\n <button type=\"button\" class=\"accept\" part=\"accept-button\">${esc(acceptLabel)}</button>\n </slot>\n </footer>\n </div>\n `);\n\n if (!this.open) return;\n\n const popup = this.root.querySelector<HTMLElement>('.popup');\n if (!popup) return;\n\n const close = (event: 'accept' | 'reject'): void => {\n this.open = false;\n this._cleanup?.();\n this._cleanup = undefined;\n this._restoreFocus();\n this.dispatchEvent(new CustomEvent(event, { bubbles: true, composed: true }));\n };\n\n this.root.querySelector('.reject')?.addEventListener('click', () => close('reject'));\n this.root.querySelector('.accept')?.addEventListener('click', () => close('accept'));\n\n // ESC fecha (reject) — clique fora fecha (reject)\n const onKey = (e: KeyboardEvent): void => {\n if (e.key === 'Escape') { e.stopPropagation(); close('reject'); }\n };\n const onPointerDown = (e: MouseEvent): void => {\n const path = e.composedPath();\n const anchor = this._anchor();\n const hitAnchor = anchor ? path.includes(anchor) : false;\n if (!path.includes(popup) && !hitAnchor) close('reject');\n };\n document.addEventListener('keydown', onKey);\n document.addEventListener('pointerdown', onPointerDown, true);\n this._cleanup = () => {\n document.removeEventListener('keydown', onKey);\n document.removeEventListener('pointerdown', onPointerDown, true);\n };\n\n this._position(popup);\n this._previouslyFocused = document.activeElement as HTMLElement | null;\n requestAnimationFrame(() => {\n this.root.querySelector<HTMLElement>('button.accept')?.focus();\n });\n }\n\n private _cleanup?: () => void;\n private _previouslyFocused: HTMLElement | null = null;\n\n private _anchor(): HTMLElement | null {\n const selector = this.getAttr('target');\n if (!selector) return null;\n try {\n return document.querySelector<HTMLElement>(selector);\n } catch {\n return null;\n }\n }\n\n /**\n * Posiciona o popup fixo junto ao âncora, acima ou abaixo dinamicamente:\n * `position=\"auto\"` (padrão) prefere abaixo e faz flip para cima quando\n * não há espaço; `top`/`bottom` forçam o lado.\n */\n private _position(popup: HTMLElement): void {\n const anchor = this._anchor();\n if (!anchor) return;\n popup.hidden = false;\n\n const a = anchor.getBoundingClientRect();\n const p = popup.getBoundingClientRect();\n const gap = 8;\n const margin = 8;\n\n let side: 'top' | 'bottom';\n const pos = this.getAttr('position', 'auto');\n if (pos === 'top') side = 'top';\n else if (pos === 'bottom') side = 'bottom';\n else side = a.bottom + gap + p.height <= window.innerHeight - margin ? 'bottom' : 'top';\n\n // clamp horizontal para nunca sair da viewport\n const left = Math.min(\n Math.max(margin, a.left + a.width / 2 - p.width / 2),\n window.innerWidth - p.width - margin,\n );\n const top = side === 'bottom' ? a.bottom + gap : a.top - gap - p.height;\n\n popup.dataset.side = side;\n popup.style.left = `${Math.round(left)}px`;\n popup.style.top = `${Math.round(Math.max(margin, top))}px`;\n // posição da seta relativa ao popup\n const arrowX = Math.min(Math.max(a.left + a.width / 2 - left, 16), p.width - 16);\n popup.style.setProperty('--fxcp-arrow-x', `${Math.round(arrowX)}px`);\n }\n\n private _restoreFocus(): void {\n if (this._previouslyFocused?.isConnected) this._previouslyFocused.focus();\n this._previouslyFocused = null;\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n // reposiciona em scroll/resize enquanto aberto\n window.addEventListener('scroll', this._onReposition, true);\n window.addEventListener('resize', this._onReposition);\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n window.removeEventListener('scroll', this._onReposition, true);\n window.removeEventListener('resize', this._onReposition);\n this._cleanup?.();\n this._cleanup = undefined;\n this._restoreFocus();\n }\n\n private _onReposition = (): void => {\n if (!this.open) return;\n const popup = this.root.querySelector<HTMLElement>('.popup');\n if (popup && !popup.hidden) this._position(popup);\n };\n}\n\nexport function defineFxConfirmPopup(): typeof FxConfirmPopup {\n return defineElement('fx-confirmpopup', FxConfirmPopup);\n}\n\n"],"file":"components/confirmpopup/confirmpopup.js"}
@@ -1 +1 @@
1
- {"version":3,"file":"dialog.d.ts","sourceRoot":"","sources":["../../../src/components/dialog/dialog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAK5C;;;;;;GAMG;AACH,qBAAa,QAAS,SAAQ,SAAS;IACrC,OAAgB,MAAM,SAqEpB;IAEF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAEjD;IAED,IAAI,IAAI,IAAI,OAAO,CAAiC;IACpD,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,EAAqC;cAEzC,MAAM,IAAI,IAAI;IA8CjC,OAAO,CAAC,QAAQ,CAAC,CAAa;IAC9B,OAAO,CAAC,kBAAkB,CAA4B;IAEtD,0DAA0D;IAC1D,OAAO,CAAC,UAAU;IAmBlB,OAAO,CAAC,aAAa;IAKZ,oBAAoB,IAAI,IAAI;CAMtC;AAED,wBAAgB,cAAc,IAAI,OAAO,QAAQ,CAEhD"}
1
+ {"version":3,"file":"dialog.d.ts","sourceRoot":"","sources":["../../../src/components/dialog/dialog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAK5C;;;;;;GAMG;AACH,qBAAa,QAAS,SAAQ,SAAS;IACrC,OAAgB,MAAM,SA6EpB;IAEF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAEjD;IAED,IAAI,IAAI,IAAI,OAAO,CAAiC;IACpD,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,EAAqC;cAEzC,MAAM,IAAI,IAAI;IA8CjC,OAAO,CAAC,QAAQ,CAAC,CAAa;IAC9B,OAAO,CAAC,kBAAkB,CAA4B;IAEtD,0DAA0D;IAC1D,OAAO,CAAC,UAAU;IAmBlB,OAAO,CAAC,aAAa;IAKZ,oBAAoB,IAAI,IAAI;CAMtC;AAED,wBAAgB,cAAc,IAAI,OAAO,QAAQ,CAEhD"}
@@ -112,7 +112,8 @@ _FxDialog.styles = css`
112
112
  border: 1px solid var(--fx-border-default);
113
113
  border-radius: var(--fx-radius-lg);
114
114
  box-shadow: var(--fx-shadow-xl);
115
- width: min(560px, calc(100vw - 32px));
115
+ /* Largura customizável por instância: defina --fx-dialog-width no elemento. */
116
+ width: min(var(--fx-dialog-width, 560px), calc(100vw - 32px));
116
117
  max-height: calc(100vh - 64px);
117
118
  display: flex;
118
119
  flex-direction: column;
@@ -120,8 +121,15 @@ _FxDialog.styles = css`
120
121
  animation: pop var(--fx-motion-duration-normal) var(--fx-motion-easing);
121
122
  }
122
123
  @keyframes pop { from { opacity: 0; transform: scale(0.96); } to { opacity: 1; transform: scale(1); } }
123
- :host([size='sm']) .dialog { width: min(400px, calc(100vw - 32px)); }
124
- :host([size='lg']) .dialog { width: min(800px, calc(100vw - 32px)); }
124
+ :host([size='sm']) .dialog { width: min(var(--fx-dialog-width, 400px), calc(100vw - 32px)); }
125
+ :host([size='lg']) .dialog { width: min(var(--fx-dialog-width, 800px), calc(100vw - 32px)); }
126
+ /* Mobile: dialog ocupa praticamente toda a largura da tela. */
127
+ @media (max-width: 640px) {
128
+ .dialog, :host([size='sm']) .dialog, :host([size='lg']) .dialog {
129
+ width: calc(100vw - 16px);
130
+ max-width: calc(100vw - 16px);
131
+ }
132
+ }
125
133
  header {
126
134
  display: flex;
127
135
  align-items: center;
@@ -1 +1 @@
1
- {"version":3,"file":"dialog.js","sources":["../../../src/components/dialog/dialog.ts"],"sourcesContent":["import { FxElement } from '../../core/base';\nimport { css } from '../../core/css';\nimport { defineElement } from '../../core/define';\nimport { esc } from '../../core/sanitize';\n\n/**\n * <fx-dialog> — Janela modal com overlay, ESC para fechar e foco preso.\n *\n * Atributos: open, size (sm|md|lg), heading (título).\n * Slots: padrão (conteúdo), footer (botões de ação).\n * Eventos: `open`, `close` (composed).\n */\nexport class FxDialog extends FxElement {\n static override styles = css`\n :host { display: contents; }\n .overlay {\n position: fixed;\n inset: 0;\n background: color-mix(in srgb, var(--fx-text-default, #000) 45%, transparent);\n backdrop-filter: blur(3px);\n -webkit-backdrop-filter: blur(3px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: var(--fx-z-modal, 1100);\n animation: fade var(--fx-motion-duration-fast) var(--fx-motion-easing);\n }\n .overlay[hidden] { display: none; }\n @keyframes fade { from { opacity: 0; } to { opacity: 1; } }\n .dialog {\n background: var(--fx-surface-background);\n border: 1px solid var(--fx-border-default);\n border-radius: var(--fx-radius-lg);\n box-shadow: var(--fx-shadow-xl);\n width: min(560px, calc(100vw - 32px));\n max-height: calc(100vh - 64px);\n display: flex;\n flex-direction: column;\n font-family: var(--fx-font-family);\n animation: pop var(--fx-motion-duration-normal) var(--fx-motion-easing);\n }\n @keyframes pop { from { opacity: 0; transform: scale(0.96); } to { opacity: 1; transform: scale(1); } }\n :host([size='sm']) .dialog { width: min(400px, calc(100vw - 32px)); }\n :host([size='lg']) .dialog { width: min(800px, calc(100vw - 32px)); }\n header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--fx-space-lg) var(--fx-space-xl);\n border-bottom: 1px solid var(--fx-border-default);\n }\n h2 {\n margin: 0;\n font-size: calc(var(--fx-font-size) + 2px);\n font-weight: 600;\n color: var(--fx-text-default);\n }\n .close {\n border: none;\n background: transparent;\n color: var(--fx-text-muted);\n font-size: calc(var(--fx-font-size) + 6px);\n cursor: pointer;\n line-height: 1;\n padding: 0 var(--fx-space-xs);\n border-radius: var(--fx-radius-full);\n }\n .close:hover { color: var(--fx-color-danger); }\n .body {\n padding: var(--fx-space-lg) var(--fx-space-xl);\n overflow-y: auto;\n color: var(--fx-text-default);\n font-size: var(--fx-font-size);\n }\n footer {\n padding: var(--fx-space-md) var(--fx-space-xl);\n border-top: 1px solid var(--fx-border-default);\n display: flex;\n justify-content: flex-end;\n gap: var(--fx-space-sm);\n }\n footer[hidden] { display: none; }\n `;\n\n static override get observedAttributes(): string[] {\n return ['open', 'size', 'heading'];\n }\n\n get open(): boolean { return this.hasAttr('open'); }\n set open(value: boolean) { this.toggleAttr('open', value); }\n\n protected override render(): void {\n const isOpen = this.open;\n const heading = this.getAttr('heading');\n\n this.setTemplate(`\n <div class=\"overlay\" part=\"overlay\" ${isOpen ? '' : 'hidden'}>\n <div class=\"dialog\" role=\"dialog\" aria-modal=\"true\" aria-label=\"${esc(heading)}\" tabindex=\"-1\">\n <header>\n <h2>${esc(heading)}</h2>\n <button type=\"button\" class=\"close\" part=\"close\" aria-label=\"Fechar\">×</button>\n </header>\n <div class=\"body\"><slot></slot></div>\n <footer part=\"footer\"><slot name=\"footer\"></slot></footer>\n </div>\n </div>\n `);\n\n if (!isOpen) return;\n\n const overlay = this.root.querySelector<HTMLElement>('.overlay');\n const closeBtn = this.root.querySelector<HTMLButtonElement>('.close');\n const close = (): void => {\n this.open = false;\n this._cleanup?.();\n this._cleanup = undefined;\n this._restoreFocus();\n this.dispatchEvent(new CustomEvent('close', { bubbles: true, composed: true }));\n };\n overlay?.addEventListener('click', (e) => { if (e.target === overlay) close(); });\n closeBtn?.addEventListener('click', close);\n\n // ESC fecha + foco preso no diálogo\n const onKey = (e: KeyboardEvent): void => {\n if (e.key === 'Escape') { e.stopPropagation(); close(); return; }\n if (e.key === 'Tab') this._trapFocus(e);\n };\n document.addEventListener('keydown', onKey);\n this._cleanup = () => document.removeEventListener('keydown', onKey);\n\n requestAnimationFrame(() => {\n this._previouslyFocused = document.activeElement as HTMLElement | null;\n this.root.querySelector<HTMLElement>('.dialog')?.focus();\n });\n this.dispatchEvent(new CustomEvent('open', { bubbles: true, composed: true }));\n }\n\n private _cleanup?: () => void;\n private _previouslyFocused: HTMLElement | null = null;\n\n /** Mantém o foco dentro do modal (WCAG 2.4.3 / 2.1.2). */\n private _trapFocus(e: KeyboardEvent): void {\n const dialog = this.root.querySelector<HTMLElement>('.dialog');\n if (!dialog) return;\n const focusables = dialog.querySelectorAll<HTMLElement>(\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])',\n );\n if (!focusables.length) return;\n const first = focusables[0];\n const last = focusables[focusables.length - 1];\n const active = this.root.activeElement;\n if (e.shiftKey && (active === first || active === dialog)) {\n e.preventDefault();\n last.focus();\n } else if (!e.shiftKey && active === last) {\n e.preventDefault();\n first.focus();\n }\n }\n\n private _restoreFocus(): void {\n if (this._previouslyFocused?.isConnected) this._previouslyFocused.focus();\n this._previouslyFocused = null;\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._cleanup?.();\n this._cleanup = undefined;\n this._restoreFocus();\n }\n}\n\nexport function defineFxDialog(): typeof FxDialog {\n return defineElement('fx-dialog', FxDialog);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dialog.js","sources":["../../../src/components/dialog/dialog.ts"],"sourcesContent":["import { FxElement } from '../../core/base';\nimport { css } from '../../core/css';\nimport { defineElement } from '../../core/define';\nimport { esc } from '../../core/sanitize';\n\n/**\n * <fx-dialog> — Janela modal com overlay, ESC para fechar e foco preso.\n *\n * Atributos: open, size (sm|md|lg), heading (título).\n * Slots: padrão (conteúdo), footer (botões de ação).\n * Eventos: `open`, `close` (composed).\n */\nexport class FxDialog extends FxElement {\n static override styles = css`\n :host { display: contents; }\n .overlay {\n position: fixed;\n inset: 0;\n background: color-mix(in srgb, var(--fx-text-default, #000) 45%, transparent);\n backdrop-filter: blur(3px);\n -webkit-backdrop-filter: blur(3px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: var(--fx-z-modal, 1100);\n animation: fade var(--fx-motion-duration-fast) var(--fx-motion-easing);\n }\n .overlay[hidden] { display: none; }\n @keyframes fade { from { opacity: 0; } to { opacity: 1; } }\n .dialog {\n background: var(--fx-surface-background);\n border: 1px solid var(--fx-border-default);\n border-radius: var(--fx-radius-lg);\n box-shadow: var(--fx-shadow-xl);\n /* Largura customizável por instância: defina --fx-dialog-width no elemento. */\n width: min(var(--fx-dialog-width, 560px), calc(100vw - 32px));\n max-height: calc(100vh - 64px);\n display: flex;\n flex-direction: column;\n font-family: var(--fx-font-family);\n animation: pop var(--fx-motion-duration-normal) var(--fx-motion-easing);\n }\n @keyframes pop { from { opacity: 0; transform: scale(0.96); } to { opacity: 1; transform: scale(1); } }\n :host([size='sm']) .dialog { width: min(var(--fx-dialog-width, 400px), calc(100vw - 32px)); }\n :host([size='lg']) .dialog { width: min(var(--fx-dialog-width, 800px), calc(100vw - 32px)); }\n /* Mobile: dialog ocupa praticamente toda a largura da tela. */\n @media (max-width: 640px) {\n .dialog, :host([size='sm']) .dialog, :host([size='lg']) .dialog {\n width: calc(100vw - 16px);\n max-width: calc(100vw - 16px);\n }\n }\n header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--fx-space-lg) var(--fx-space-xl);\n border-bottom: 1px solid var(--fx-border-default);\n }\n h2 {\n margin: 0;\n font-size: calc(var(--fx-font-size) + 2px);\n font-weight: 600;\n color: var(--fx-text-default);\n }\n .close {\n border: none;\n background: transparent;\n color: var(--fx-text-muted);\n font-size: calc(var(--fx-font-size) + 6px);\n cursor: pointer;\n line-height: 1;\n padding: 0 var(--fx-space-xs);\n border-radius: var(--fx-radius-full);\n }\n .close:hover { color: var(--fx-color-danger); }\n .body {\n padding: var(--fx-space-lg) var(--fx-space-xl);\n overflow-y: auto;\n color: var(--fx-text-default);\n font-size: var(--fx-font-size);\n }\n footer {\n padding: var(--fx-space-md) var(--fx-space-xl);\n border-top: 1px solid var(--fx-border-default);\n display: flex;\n justify-content: flex-end;\n gap: var(--fx-space-sm);\n }\n footer[hidden] { display: none; }\n `;\n\n static override get observedAttributes(): string[] {\n return ['open', 'size', 'heading'];\n }\n\n get open(): boolean { return this.hasAttr('open'); }\n set open(value: boolean) { this.toggleAttr('open', value); }\n\n protected override render(): void {\n const isOpen = this.open;\n const heading = this.getAttr('heading');\n\n this.setTemplate(`\n <div class=\"overlay\" part=\"overlay\" ${isOpen ? '' : 'hidden'}>\n <div class=\"dialog\" role=\"dialog\" aria-modal=\"true\" aria-label=\"${esc(heading)}\" tabindex=\"-1\">\n <header>\n <h2>${esc(heading)}</h2>\n <button type=\"button\" class=\"close\" part=\"close\" aria-label=\"Fechar\">×</button>\n </header>\n <div class=\"body\"><slot></slot></div>\n <footer part=\"footer\"><slot name=\"footer\"></slot></footer>\n </div>\n </div>\n `);\n\n if (!isOpen) return;\n\n const overlay = this.root.querySelector<HTMLElement>('.overlay');\n const closeBtn = this.root.querySelector<HTMLButtonElement>('.close');\n const close = (): void => {\n this.open = false;\n this._cleanup?.();\n this._cleanup = undefined;\n this._restoreFocus();\n this.dispatchEvent(new CustomEvent('close', { bubbles: true, composed: true }));\n };\n overlay?.addEventListener('click', (e) => { if (e.target === overlay) close(); });\n closeBtn?.addEventListener('click', close);\n\n // ESC fecha + foco preso no diálogo\n const onKey = (e: KeyboardEvent): void => {\n if (e.key === 'Escape') { e.stopPropagation(); close(); return; }\n if (e.key === 'Tab') this._trapFocus(e);\n };\n document.addEventListener('keydown', onKey);\n this._cleanup = () => document.removeEventListener('keydown', onKey);\n\n requestAnimationFrame(() => {\n this._previouslyFocused = document.activeElement as HTMLElement | null;\n this.root.querySelector<HTMLElement>('.dialog')?.focus();\n });\n this.dispatchEvent(new CustomEvent('open', { bubbles: true, composed: true }));\n }\n\n private _cleanup?: () => void;\n private _previouslyFocused: HTMLElement | null = null;\n\n /** Mantém o foco dentro do modal (WCAG 2.4.3 / 2.1.2). */\n private _trapFocus(e: KeyboardEvent): void {\n const dialog = this.root.querySelector<HTMLElement>('.dialog');\n if (!dialog) return;\n const focusables = dialog.querySelectorAll<HTMLElement>(\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])',\n );\n if (!focusables.length) return;\n const first = focusables[0];\n const last = focusables[focusables.length - 1];\n const active = this.root.activeElement;\n if (e.shiftKey && (active === first || active === dialog)) {\n e.preventDefault();\n last.focus();\n } else if (!e.shiftKey && active === last) {\n e.preventDefault();\n first.focus();\n }\n }\n\n private _restoreFocus(): void {\n if (this._previouslyFocused?.isConnected) this._previouslyFocused.focus();\n this._previouslyFocused = null;\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._cleanup?.();\n this._cleanup = undefined;\n this._restoreFocus();\n }\n}\n\nexport function defineFxDialog(): typeof FxDialog {\n return defineElement('fx-dialog', FxDialog);\n}\n"],"names":[],"mappings":"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"}
@@ -23,6 +23,9 @@ export declare class FxSlider extends FxElement {
23
23
  private _pct;
24
24
  protected render(): void;
25
25
  private _dragging;
26
+ private _onMove?;
27
+ private _onUp?;
28
+ protected disconnectedCallback(): void;
26
29
  private _wrap;
27
30
  private _bindPointer;
28
31
  private _bindKeyboard;
@@ -1 +1 @@
1
- {"version":3,"file":"slider.d.ts","sourceRoot":"","sources":["../../../src/components/slider/slider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C;;;;;;;GAOG;AACH,qBAAa,QAAS,SAAQ,SAAS;IACrC,OAAgB,MAAM,SA8EpB;IAEF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAEjD;IAED,IAAI,GAAG,IAAI,MAAM,CAAgC;IACjD,IAAI,GAAG,IAAI,MAAM,CAAkC;IACnD,IAAI,IAAI,IAAI,MAAM,CAAiC;IAEnD,IAAI,KAAK,IAAI,MAAM,CAElB;IACD,IAAI,KAAK,CAAC,CAAC,EAAE,MAAM,EAKlB;IAED,OAAO,CAAC,IAAI;IAOZ,OAAO,CAAC,MAAM;IAId,4EAA4E;IAC5E,OAAO,CAAC,KAAK;IAMb,6DAA6D;IAC7D,OAAO,CAAC,IAAI;cAKO,MAAM,IAAI,IAAI;IAoBjC,OAAO,CAAC,SAAS,CAAS;IAE1B,OAAO,CAAC,KAAK;IAIb,OAAO,CAAC,YAAY;IA8CpB,OAAO,CAAC,aAAa;IA6BrB,2FAA2F;IAC3F,OAAO,CAAC,WAAW;CAiBpB;AAED,wBAAgB,cAAc,IAAI,OAAO,QAAQ,CAEhD"}
1
+ {"version":3,"file":"slider.d.ts","sourceRoot":"","sources":["../../../src/components/slider/slider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C;;;;;;;GAOG;AACH,qBAAa,QAAS,SAAQ,SAAS;IACrC,OAAgB,MAAM,SA8EpB;IAEF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAEjD;IAED,IAAI,GAAG,IAAI,MAAM,CAAgC;IACjD,IAAI,GAAG,IAAI,MAAM,CAAkC;IACnD,IAAI,IAAI,IAAI,MAAM,CAAiC;IAEnD,IAAI,KAAK,IAAI,MAAM,CAElB;IACD,IAAI,KAAK,CAAC,CAAC,EAAE,MAAM,EAKlB;IAED,OAAO,CAAC,IAAI;IAOZ,OAAO,CAAC,MAAM;IAId,4EAA4E;IAC5E,OAAO,CAAC,KAAK;IAMb,6DAA6D;IAC7D,OAAO,CAAC,IAAI;cAKO,MAAM,IAAI,IAAI;IAoBjC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,OAAO,CAAC,CAA4B;IAC5C,OAAO,CAAC,KAAK,CAAC,CAA4B;cAEvB,oBAAoB,IAAI,IAAI;IAU/C,OAAO,CAAC,KAAK;IAIb,OAAO,CAAC,YAAY;IAgDpB,OAAO,CAAC,aAAa;IA6BrB,2FAA2F;IAC3F,OAAO,CAAC,WAAW;CAiBpB;AAED,wBAAgB,cAAc,IAAI,OAAO,QAAQ,CAEhD"}
@@ -63,6 +63,14 @@ const _FxSlider = class _FxSlider extends FxElement {
63
63
  this._bindPointer();
64
64
  this._bindKeyboard();
65
65
  }
66
+ disconnectedCallback() {
67
+ super.disconnectedCallback();
68
+ if (this._dragging) {
69
+ this._dragging = false;
70
+ if (this._onMove) window.removeEventListener("pointermove", this._onMove);
71
+ if (this._onUp) window.removeEventListener("pointerup", this._onUp);
72
+ }
73
+ }
66
74
  _wrap() {
67
75
  return this.root.querySelector(".track-wrap");
68
76
  }
@@ -82,6 +90,7 @@ const _FxSlider = class _FxSlider extends FxElement {
82
90
  new CustomEvent("input", { bubbles: true, composed: true, detail: { value: this.value } })
83
91
  );
84
92
  };
93
+ this._onMove = move;
85
94
  const up = (e) => {
86
95
  if (!this._dragging) return;
87
96
  this._dragging = false;
@@ -94,6 +103,7 @@ const _FxSlider = class _FxSlider extends FxElement {
94
103
  new CustomEvent("change", { bubbles: true, composed: true, detail: { value: this.value } })
95
104
  );
96
105
  };
106
+ this._onUp = up;
97
107
  wrap.addEventListener("pointerdown", (e) => {
98
108
  if (this.hasAttr("disabled")) return;
99
109
  this._dragging = true;
@@ -1 +1 @@
1
- {"version":3,"file":"slider.js","sources":["../../../src/components/slider/slider.ts"],"sourcesContent":["import { FxElement } from '../../core/base';\nimport { css } from '../../core/css';\nimport { defineElement } from '../../core/define';\n\n/**\n * <fx-slider> — Controle deslizante para seleção de valor numérico em um intervalo.\n *\n * Atributos: min, max, step, value, size (sm|md|lg), disabled, show-value,\n * label (rótulo acima do trilho).\n * Eventos (composed): `input` (durante o arraste) e `change` (ao soltar) —\n * ambos com `detail: { value: number }`.\n */\nexport class FxSlider extends FxElement {\n static override styles = css`\n :host {\n display: block;\n font-family: var(--fx-font-family);\n font-size: var(--fx-font-size);\n --_track-h: 6px;\n --_thumb: 18px;\n }\n :host([size='sm']) { --_track-h: 4px; --_thumb: 14px; }\n :host([size='lg']) { --_track-h: 8px; --_thumb: 22px; }\n :host([disabled]) { opacity: 0.55; pointer-events: none; }\n\n .label {\n font-size: calc(var(--fx-font-size) - 2px);\n color: var(--fx-text-muted);\n margin-bottom: var(--fx-space-xs);\n display: flex;\n justify-content: space-between;\n gap: var(--fx-space-md);\n align-items: center;\n }\n .track-wrap {\n position: relative;\n display: flex;\n align-items: center;\n height: var(--_thumb);\n cursor: pointer;\n touch-action: none;\n }\n .track {\n width: 100%;\n height: var(--_track-h);\n border-radius: var(--fx-radius-full);\n background: var(--fx-surface-surface-hover, rgba(0, 0, 0, 0.08));\n overflow: hidden;\n }\n .fill {\n height: 100%;\n background: var(--fx-color-primary);\n border-radius: var(--fx-radius-full);\n }\n .thumb {\n position: absolute;\n top: 50%;\n width: var(--_thumb);\n height: var(--_thumb);\n border-radius: var(--fx-radius-full);\n background: var(--fx-surface-background);\n border: 2px solid var(--fx-color-primary);\n box-shadow: var(--fx-shadow-sm);\n transform: translate(-50%, -50%);\n transition: box-shadow var(--fx-motion-duration-fast) var(--fx-motion-easing);\n box-sizing: border-box;\n }\n .track-wrap:hover .thumb,\n .track-wrap.dragging .thumb { box-shadow: var(--fx-effect-focus-ring, none); }\n .track-wrap:focus-visible { outline: none; }\n .track-wrap:focus-visible .thumb {\n box-shadow: var(--fx-effect-focus-ring, none);\n }\n .value {\n position: absolute;\n bottom: calc(100% + 6px);\n transform: translateX(-50%);\n background: var(--fx-text-default, #1e293b);\n color: var(--fx-surface-background, #fff);\n font-size: calc(var(--fx-font-size) - 3px);\n font-weight: 600;\n padding: 2px var(--fx-space-xs);\n border-radius: var(--fx-radius-sm);\n white-space: nowrap;\n pointer-events: none;\n opacity: 0;\n transition: opacity var(--fx-motion-duration-fast) var(--fx-motion-easing);\n }\n .track-wrap:hover .value,\n .track-wrap.dragging .value,\n .track-wrap:focus-visible .value { opacity: 1; }\n `;\n\n static override get observedAttributes(): string[] {\n return ['min', 'max', 'step', 'size', 'disabled', 'show-value', 'label'];\n }\n\n get min(): number { return this._num('min', 0); }\n get max(): number { return this._num('max', 100); }\n get step(): number { return this._num('step', 1); }\n\n get value(): number {\n return this._clamp(this._num('value', this.min));\n }\n set value(v: number) {\n const snapped = this._snap(v);\n this.setAttribute('value', String(snapped));\n // atualiza visual sem re-render (preserva estado de drag/foco)\n if (this.isConnected) this._syncVisual();\n }\n\n private _num(attr: string, fallback: number): number {\n const raw = this.getAttribute(attr);\n if (raw === null || raw === '') return fallback;\n const n = Number(raw);\n return Number.isFinite(n) ? n : fallback;\n }\n\n private _clamp(v: number): number {\n return Math.min(this.max, Math.max(this.min, v));\n }\n\n /** Arredonda para o múltiplo de `step` mais próximo dentro do intervalo. */\n private _snap(v: number): number {\n const step = this.step || 1;\n const snapped = Math.round((this._clamp(v) - this.min) / step) * step + this.min;\n return Number(this._clamp(snapped).toFixed(10));\n }\n\n /** Percentual (0-100) do valor atual dentro do intervalo. */\n private _pct(): number {\n const span = this.max - this.min;\n return span <= 0 ? 0 : ((this.value - this.min) / span) * 100;\n }\n\n protected override render(): void {\n const pct = this._pct();\n const label = this.getAttr('label');\n const showValue = this.hasAttr('show-value');\n\n this.setTemplate(`\n ${label ? `<div class=\"label\" part=\"label\"><span>${label}</span>${showValue ? `<span>${this.value}</span>` : ''}</div>` : ''}\n <div class=\"track-wrap\" part=\"track\" tabindex=\"0\" role=\"slider\"\n aria-valuemin=\"${this.min}\" aria-valuemax=\"${this.max}\" aria-valuenow=\"${this.value}\"\n aria-label=\"${label || 'Slider'}\" ${this.hasAttr('disabled') ? 'aria-disabled=\"true\"' : ''}>\n <div class=\"track\"><div class=\"fill\" part=\"fill\" style=\"width: ${pct}%\"></div></div>\n <div class=\"thumb\" part=\"thumb\" style=\"left: ${pct}%\"></div>\n ${showValue ? `<span class=\"value\" style=\"left: ${pct}%\">${this.value}</span>` : ''}\n </div>\n `);\n\n this._bindPointer();\n this._bindKeyboard();\n }\n\n private _dragging = false;\n\n private _wrap(): HTMLElement | null {\n return this.root.querySelector<HTMLElement>('.track-wrap');\n }\n\n private _bindPointer(): void {\n const wrap = this._wrap();\n if (!wrap) return;\n\n const valueFromEvent = (e: PointerEvent): number => {\n const rect = wrap.getBoundingClientRect();\n const ratio = rect.width <= 0 ? 0 : (e.clientX - rect.left) / rect.width;\n return this.min + ratio * (this.max - this.min);\n };\n\n const move = (e: PointerEvent): void => {\n if (!this._dragging) return;\n this.value = valueFromEvent(e);\n this._syncVisual();\n this.dispatchEvent(\n new CustomEvent('input', { bubbles: true, composed: true, detail: { value: this.value } }),\n );\n };\n const up = (e: PointerEvent): void => {\n if (!this._dragging) return;\n this._dragging = false;\n wrap.classList.remove('dragging');\n window.removeEventListener('pointermove', move);\n window.removeEventListener('pointerup', up);\n this.value = valueFromEvent(e);\n this._syncVisual();\n this.dispatchEvent(\n new CustomEvent('change', { bubbles: true, composed: true, detail: { value: this.value } }),\n );\n };\n\n wrap.addEventListener('pointerdown', (e) => {\n if (this.hasAttr('disabled')) return;\n this._dragging = true;\n wrap.classList.add('dragging');\n wrap.focus();\n this.value = valueFromEvent(e);\n this._syncVisual();\n this.dispatchEvent(\n new CustomEvent('input', { bubbles: true, composed: true, detail: { value: this.value } }),\n );\n window.addEventListener('pointermove', move);\n window.addEventListener('pointerup', up);\n });\n }\n\n private _bindKeyboard(): void {\n const wrap = this._wrap();\n if (!wrap) return;\n wrap.addEventListener('keydown', (e) => {\n if (this.hasAttr('disabled')) return;\n const ev = e as KeyboardEvent;\n const big = (this.max - this.min) / 10;\n let next: number | null = null;\n switch (ev.key) {\n case 'ArrowRight': case 'ArrowUp': next = this.value + this.step; break;\n case 'ArrowLeft': case 'ArrowDown': next = this.value - this.step; break;\n case 'PageUp': next = this.value + big; break;\n case 'PageDown': next = this.value - big; break;\n case 'Home': next = this.min; break;\n case 'End': next = this.max; break;\n default: return;\n }\n ev.preventDefault();\n this.value = next;\n this._syncVisual();\n this.dispatchEvent(\n new CustomEvent('input', { bubbles: true, composed: true, detail: { value: this.value } }),\n );\n this.dispatchEvent(\n new CustomEvent('change', { bubbles: true, composed: true, detail: { value: this.value } }),\n );\n });\n }\n\n /** Atualiza fill/thumb/tooltip/aria sem re-renderizar o template (evita perder o drag). */\n private _syncVisual(): void {\n const pct = this._pct();\n const wrap = this._wrap();\n if (!wrap) return;\n const fill = wrap.querySelector<HTMLElement>('.fill');\n const thumb = wrap.querySelector<HTMLElement>('.thumb');\n const tip = wrap.querySelector<HTMLElement>('.value');\n if (fill) fill.style.width = `${pct}%`;\n if (thumb) thumb.style.left = `${pct}%`;\n if (tip) {\n tip.style.left = `${pct}%`;\n tip.textContent = String(this.value);\n }\n wrap.setAttribute('aria-valuenow', String(this.value));\n const labelPct = this.root.querySelector<HTMLElement>('.label span:last-child');\n if (labelPct) labelPct.textContent = String(this.value);\n }\n}\n\nexport function defineFxSlider(): typeof FxSlider {\n return defineElement('fx-slider', FxSlider);\n}\n\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"slider.js","sources":["../../../src/components/slider/slider.ts"],"sourcesContent":["import { FxElement } from '../../core/base';\nimport { css } from '../../core/css';\nimport { defineElement } from '../../core/define';\n\n/**\n * <fx-slider> — Controle deslizante para seleção de valor numérico em um intervalo.\n *\n * Atributos: min, max, step, value, size (sm|md|lg), disabled, show-value,\n * label (rótulo acima do trilho).\n * Eventos (composed): `input` (durante o arraste) e `change` (ao soltar) —\n * ambos com `detail: { value: number }`.\n */\nexport class FxSlider extends FxElement {\n static override styles = css`\n :host {\n display: block;\n font-family: var(--fx-font-family);\n font-size: var(--fx-font-size);\n --_track-h: 6px;\n --_thumb: 18px;\n }\n :host([size='sm']) { --_track-h: 4px; --_thumb: 14px; }\n :host([size='lg']) { --_track-h: 8px; --_thumb: 22px; }\n :host([disabled]) { opacity: 0.55; pointer-events: none; }\n\n .label {\n font-size: calc(var(--fx-font-size) - 2px);\n color: var(--fx-text-muted);\n margin-bottom: var(--fx-space-xs);\n display: flex;\n justify-content: space-between;\n gap: var(--fx-space-md);\n align-items: center;\n }\n .track-wrap {\n position: relative;\n display: flex;\n align-items: center;\n height: var(--_thumb);\n cursor: pointer;\n touch-action: none;\n }\n .track {\n width: 100%;\n height: var(--_track-h);\n border-radius: var(--fx-radius-full);\n background: var(--fx-surface-surface-hover, rgba(0, 0, 0, 0.08));\n overflow: hidden;\n }\n .fill {\n height: 100%;\n background: var(--fx-color-primary);\n border-radius: var(--fx-radius-full);\n }\n .thumb {\n position: absolute;\n top: 50%;\n width: var(--_thumb);\n height: var(--_thumb);\n border-radius: var(--fx-radius-full);\n background: var(--fx-surface-background);\n border: 2px solid var(--fx-color-primary);\n box-shadow: var(--fx-shadow-sm);\n transform: translate(-50%, -50%);\n transition: box-shadow var(--fx-motion-duration-fast) var(--fx-motion-easing);\n box-sizing: border-box;\n }\n .track-wrap:hover .thumb,\n .track-wrap.dragging .thumb { box-shadow: var(--fx-effect-focus-ring, none); }\n .track-wrap:focus-visible { outline: none; }\n .track-wrap:focus-visible .thumb {\n box-shadow: var(--fx-effect-focus-ring, none);\n }\n .value {\n position: absolute;\n bottom: calc(100% + 6px);\n transform: translateX(-50%);\n background: var(--fx-text-default, #1e293b);\n color: var(--fx-surface-background, #fff);\n font-size: calc(var(--fx-font-size) - 3px);\n font-weight: 600;\n padding: 2px var(--fx-space-xs);\n border-radius: var(--fx-radius-sm);\n white-space: nowrap;\n pointer-events: none;\n opacity: 0;\n transition: opacity var(--fx-motion-duration-fast) var(--fx-motion-easing);\n }\n .track-wrap:hover .value,\n .track-wrap.dragging .value,\n .track-wrap:focus-visible .value { opacity: 1; }\n `;\n\n static override get observedAttributes(): string[] {\n return ['min', 'max', 'step', 'size', 'disabled', 'show-value', 'label'];\n }\n\n get min(): number { return this._num('min', 0); }\n get max(): number { return this._num('max', 100); }\n get step(): number { return this._num('step', 1); }\n\n get value(): number {\n return this._clamp(this._num('value', this.min));\n }\n set value(v: number) {\n const snapped = this._snap(v);\n this.setAttribute('value', String(snapped));\n // atualiza visual sem re-render (preserva estado de drag/foco)\n if (this.isConnected) this._syncVisual();\n }\n\n private _num(attr: string, fallback: number): number {\n const raw = this.getAttribute(attr);\n if (raw === null || raw === '') return fallback;\n const n = Number(raw);\n return Number.isFinite(n) ? n : fallback;\n }\n\n private _clamp(v: number): number {\n return Math.min(this.max, Math.max(this.min, v));\n }\n\n /** Arredonda para o múltiplo de `step` mais próximo dentro do intervalo. */\n private _snap(v: number): number {\n const step = this.step || 1;\n const snapped = Math.round((this._clamp(v) - this.min) / step) * step + this.min;\n return Number(this._clamp(snapped).toFixed(10));\n }\n\n /** Percentual (0-100) do valor atual dentro do intervalo. */\n private _pct(): number {\n const span = this.max - this.min;\n return span <= 0 ? 0 : ((this.value - this.min) / span) * 100;\n }\n\n protected override render(): void {\n const pct = this._pct();\n const label = this.getAttr('label');\n const showValue = this.hasAttr('show-value');\n\n this.setTemplate(`\n ${label ? `<div class=\"label\" part=\"label\"><span>${label}</span>${showValue ? `<span>${this.value}</span>` : ''}</div>` : ''}\n <div class=\"track-wrap\" part=\"track\" tabindex=\"0\" role=\"slider\"\n aria-valuemin=\"${this.min}\" aria-valuemax=\"${this.max}\" aria-valuenow=\"${this.value}\"\n aria-label=\"${label || 'Slider'}\" ${this.hasAttr('disabled') ? 'aria-disabled=\"true\"' : ''}>\n <div class=\"track\"><div class=\"fill\" part=\"fill\" style=\"width: ${pct}%\"></div></div>\n <div class=\"thumb\" part=\"thumb\" style=\"left: ${pct}%\"></div>\n ${showValue ? `<span class=\"value\" style=\"left: ${pct}%\">${this.value}</span>` : ''}\n </div>\n `);\n\n this._bindPointer();\n this._bindKeyboard();\n }\n\n private _dragging = false;\n private _onMove?: (e: PointerEvent) => void;\n private _onUp?: (e: PointerEvent) => void;\n\n protected override disconnectedCallback(): void {\n super.disconnectedCallback();\n // Limpa listeners de janela se o elemento for removido durante um drag.\n if (this._dragging) {\n this._dragging = false;\n if (this._onMove) window.removeEventListener('pointermove', this._onMove);\n if (this._onUp) window.removeEventListener('pointerup', this._onUp);\n }\n }\n\n private _wrap(): HTMLElement | null {\n return this.root.querySelector<HTMLElement>('.track-wrap');\n }\n\n private _bindPointer(): void {\n const wrap = this._wrap();\n if (!wrap) return;\n\n const valueFromEvent = (e: PointerEvent): number => {\n const rect = wrap.getBoundingClientRect();\n const ratio = rect.width <= 0 ? 0 : (e.clientX - rect.left) / rect.width;\n return this.min + ratio * (this.max - this.min);\n };\n\n const move = (e: PointerEvent): void => {\n if (!this._dragging) return;\n this.value = valueFromEvent(e);\n this._syncVisual();\n this.dispatchEvent(\n new CustomEvent('input', { bubbles: true, composed: true, detail: { value: this.value } }),\n );\n };\n this._onMove = move;\n const up = (e: PointerEvent): void => {\n if (!this._dragging) return;\n this._dragging = false;\n wrap.classList.remove('dragging');\n window.removeEventListener('pointermove', move);\n window.removeEventListener('pointerup', up);\n this.value = valueFromEvent(e);\n this._syncVisual();\n this.dispatchEvent(\n new CustomEvent('change', { bubbles: true, composed: true, detail: { value: this.value } }),\n );\n };\n this._onUp = up;\n\n wrap.addEventListener('pointerdown', (e) => {\n if (this.hasAttr('disabled')) return;\n this._dragging = true;\n wrap.classList.add('dragging');\n wrap.focus();\n this.value = valueFromEvent(e);\n this._syncVisual();\n this.dispatchEvent(\n new CustomEvent('input', { bubbles: true, composed: true, detail: { value: this.value } }),\n );\n window.addEventListener('pointermove', move);\n window.addEventListener('pointerup', up);\n });\n }\n\n private _bindKeyboard(): void {\n const wrap = this._wrap();\n if (!wrap) return;\n wrap.addEventListener('keydown', (e) => {\n if (this.hasAttr('disabled')) return;\n const ev = e as KeyboardEvent;\n const big = (this.max - this.min) / 10;\n let next: number | null = null;\n switch (ev.key) {\n case 'ArrowRight': case 'ArrowUp': next = this.value + this.step; break;\n case 'ArrowLeft': case 'ArrowDown': next = this.value - this.step; break;\n case 'PageUp': next = this.value + big; break;\n case 'PageDown': next = this.value - big; break;\n case 'Home': next = this.min; break;\n case 'End': next = this.max; break;\n default: return;\n }\n ev.preventDefault();\n this.value = next;\n this._syncVisual();\n this.dispatchEvent(\n new CustomEvent('input', { bubbles: true, composed: true, detail: { value: this.value } }),\n );\n this.dispatchEvent(\n new CustomEvent('change', { bubbles: true, composed: true, detail: { value: this.value } }),\n );\n });\n }\n\n /** Atualiza fill/thumb/tooltip/aria sem re-renderizar o template (evita perder o drag). */\n private _syncVisual(): void {\n const pct = this._pct();\n const wrap = this._wrap();\n if (!wrap) return;\n const fill = wrap.querySelector<HTMLElement>('.fill');\n const thumb = wrap.querySelector<HTMLElement>('.thumb');\n const tip = wrap.querySelector<HTMLElement>('.value');\n if (fill) fill.style.width = `${pct}%`;\n if (thumb) thumb.style.left = `${pct}%`;\n if (tip) {\n tip.style.left = `${pct}%`;\n tip.textContent = String(this.value);\n }\n wrap.setAttribute('aria-valuenow', String(this.value));\n const labelPct = this.root.querySelector<HTMLElement>('.label span:last-child');\n if (labelPct) labelPct.textContent = String(this.value);\n }\n}\n\nexport function defineFxSlider(): typeof FxSlider {\n return defineElement('fx-slider', FxSlider);\n}\n\n"],"names":[],"mappings":"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"}
@@ -4,7 +4,8 @@ import { FxElement } from '../../core/base';
4
4
  *
5
5
  * Atributos: marker (glifo do marcador, padrão '●'), size (sm|md|lg).
6
6
  * Slot `item`: cada elemento com [slot="item"] vira um evento. Use os
7
- * atributos `time` (texto do horário/data) e `title` no item.
7
+ * atributos `time` (texto do horário/data), `title` e `icon` (glifo da
8
+ * fonte Fenix Icons, ex.: "check_circle") no item.
8
9
  *
9
10
  * Exemplo:
10
11
  * <fx-timeline>
@@ -1 +1 @@
1
- {"version":3,"file":"timeline.d.ts","sourceRoot":"","sources":["../../../src/components/timeline/timeline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAK5C;;;;;;;;;;;;GAYG;AACH,qBAAa,UAAW,SAAQ,SAAS;IACvC,OAAgB,MAAM,SA2FpB;IAEF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAEjD;cAEkB,MAAM,IAAI,IAAI;IAKjC;;;;OAIG;IACH,OAAO,CAAC,SAAS;IAoBjB,OAAO,CAAC,SAAS,CAAC,CAAmB;cAElB,iBAAiB,IAAI,IAAI;cAQzB,oBAAoB,IAAI,IAAI;CAKhD;AAED,wBAAgB,gBAAgB,IAAI,OAAO,UAAU,CAEpD"}
1
+ {"version":3,"file":"timeline.d.ts","sourceRoot":"","sources":["../../../src/components/timeline/timeline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAK5C;;;;;;;;;;;;;GAaG;AACH,qBAAa,UAAW,SAAQ,SAAS;IACvC,OAAgB,MAAM,SAuGpB;IAEF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAEjD;cAEkB,MAAM,IAAI,IAAI;IAKjC;;;;OAIG;IACH,OAAO,CAAC,SAAS;IA2BjB,OAAO,CAAC,SAAS,CAAC,CAAmB;cAElB,iBAAiB,IAAI,IAAI;cAQzB,oBAAoB,IAAI,IAAI;CAKhD;AAED,wBAAgB,gBAAgB,IAAI,OAAO,UAAU,CAEpD"}
@@ -1,3 +1,4 @@
1
+ import { __fenixPreload } from "../../_virtual/preload-helper.js";
1
2
  import { FxElement } from "../../core/base.js";
2
3
  import { css } from "../../core/css.js";
3
4
  import { defineElement } from "../../core/define.js";
@@ -28,8 +29,11 @@ const _FxTimeline = class _FxTimeline extends FxElement {
28
29
  time ? `<span class="time">${esc(time)}</span>` : "",
29
30
  title ? `<span class="title">${esc(title)}</span>` : ""
30
31
  ].join("");
31
- return `<li class="event" part="event"><span class="dot" part="marker" aria-hidden="true">${esc(marker)}</span><div class="head">${head}</div><div class="content">${item.innerHTML}</div></li>`;
32
+ const icon = item.getAttribute("icon");
33
+ const dot = icon ? `<span class="dot fx-icon" part="marker" aria-hidden="true">${esc(icon)}</span>` : `<span class="dot" part="marker" aria-hidden="true">${esc(marker)}</span>`;
34
+ return `<li class="event" part="event">${dot}<div class="head">${head}</div><div class="content">${item.innerHTML}</div></li>`;
32
35
  }).join("");
36
+ if (items.some((item) => item.hasAttribute("icon"))) void __fenixPreload(() => import("../../icons/index.js"), true ? [] : void 0, import.meta.url);
33
37
  }
34
38
  connectedCallback() {
35
39
  super.connectedCallback();
@@ -48,10 +52,10 @@ _FxTimeline.styles = css`
48
52
  display: block;
49
53
  font-family: var(--fx-font-family);
50
54
  font-size: var(--fx-font-size);
51
- --_marker: calc(var(--fx-font-size) - 1px);
55
+ --_marker: calc(var(--fx-font-size) + 6px);
52
56
  }
53
- :host([size='sm']) { --_marker: calc(var(--fx-font-size) - 3px); }
54
- :host([size='lg']) { --_marker: calc(var(--fx-font-size) + 2px); }
57
+ :host([size='sm']) { --_marker: calc(var(--fx-font-size) - 2px); }
58
+ :host([size='lg']) { --_marker: calc(var(--fx-font-size) + 14px); }
55
59
 
56
60
  .tl {
57
61
  list-style: none;
@@ -84,10 +88,22 @@ _FxTimeline.styles = css`
84
88
  display: inline-flex;
85
89
  align-items: center;
86
90
  justify-content: center;
87
- font-size: calc(var(--_marker) * 0.55);
91
+ font-size: calc(var(--_marker) * 0.5);
88
92
  color: var(--fx-color-primary);
89
93
  line-height: 1;
90
94
  }
95
+ /* marcador com ícone da fonte Fenix Icons (atributo icon no item) */
96
+ .dot.fx-icon {
97
+ font-family: var(--fx-icon-font, 'Fenix Icons');
98
+ font-weight: normal;
99
+ font-style: normal;
100
+ font-variation-settings: 'FILL' 0, 'wght' 500, 'GRAD' 0, 'opsz' 24;
101
+ -webkit-font-smoothing: antialiased;
102
+ user-select: none;
103
+ background: color-mix(in srgb, var(--fx-color-primary) 14%, transparent);
104
+ border-radius: 50%;
105
+ font-size: calc(var(--_marker) * 0.55);
106
+ }
91
107
  .head {
92
108
  display: flex;
93
109
  align-items: baseline;