@wrrdev/fenix-ui 1.1.8 → 1.1.10

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 (50) hide show
  1. package/README.md +2 -2
  2. package/dist/components/drawer/drawer.d.ts.map +1 -1
  3. package/dist/components/drawer/drawer.js +4 -0
  4. package/dist/components/drawer/drawer.js.map +1 -1
  5. package/dist/components/pagination/pagination.d.ts +1 -0
  6. package/dist/components/pagination/pagination.d.ts.map +1 -1
  7. package/dist/components/pagination/pagination.js +18 -2
  8. package/dist/components/pagination/pagination.js.map +1 -1
  9. package/dist/components/table/table.d.ts +60 -4
  10. package/dist/components/table/table.d.ts.map +1 -1
  11. package/dist/components/table/table.js +96 -18
  12. package/dist/components/table/table.js.map +1 -1
  13. package/dist/components/toast/toast.d.ts +46 -1
  14. package/dist/components/toast/toast.d.ts.map +1 -1
  15. package/dist/components/toast/toast.js +128 -5
  16. package/dist/components/toast/toast.js.map +1 -1
  17. package/dist/core/jsx.d.ts +84 -1
  18. package/dist/core/jsx.d.ts.map +1 -1
  19. package/dist/core/jsx.js.map +1 -1
  20. package/dist/core/vue.d.ts +7 -1
  21. package/dist/core/vue.d.ts.map +1 -1
  22. package/dist/core/vue.js.map +1 -1
  23. package/dist/docs/app.d.ts +2 -6
  24. package/dist/docs/app.d.ts.map +1 -1
  25. package/dist/docs/componentes/table-cell-rules.d.ts +3 -0
  26. package/dist/docs/componentes/table-cell-rules.d.ts.map +1 -0
  27. package/dist/docs/componentes/table.doc.d.ts.map +1 -1
  28. package/dist/docs/componentes/toast.doc.d.ts.map +1 -1
  29. package/dist/docs/router.d.ts +17 -0
  30. package/dist/docs/router.d.ts.map +1 -0
  31. package/dist/docs/shell.d.ts +43 -0
  32. package/dist/docs/shell.d.ts.map +1 -0
  33. package/dist/docs/types.d.ts +9 -0
  34. package/dist/docs/types.d.ts.map +1 -1
  35. package/dist/docs/ui/code.d.ts +12 -0
  36. package/dist/docs/ui/code.d.ts.map +1 -0
  37. package/dist/docs/ui/kit.d.ts +18 -0
  38. package/dist/docs/ui/kit.d.ts.map +1 -0
  39. package/dist/docs/ui/tabs.d.ts +23 -0
  40. package/dist/docs/ui/tabs.d.ts.map +1 -0
  41. package/dist/fenix-ui.umd.min.js +179 -116
  42. package/dist/fenix-ui2.esm.js.map +1 -1
  43. package/dist/fenix-ui4.esm.js +243 -26
  44. package/dist/fenix-ui4.esm.js.map +1 -1
  45. package/dist/fenix-ui5.esm.js +4 -1
  46. package/dist/fenix-ui5.esm.js.map +1 -1
  47. package/dist/plugins/auto-import.d.ts.map +1 -1
  48. package/dist/plugins/auto-import.js +4 -1
  49. package/dist/plugins/auto-import.js.map +1 -1
  50. package/package.json +3 -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.8**, acesso público.
21
+ > 📦 npm: [`@wrrdev/fenix-ui`](https://www.npmjs.com/package/@wrrdev/fenix-ui) — **v1.1.10**, acesso público.
22
22
  > Subpaths disponíveis: `./theme`, `./tokens`, `./jsx`, `./vue`, `./react`, `./button`, `./badge`, `./spinner`, `./select`, `./input`, `./switch`, `./textarea`, `./checkbox`, `./radio`, `./calendar`, `./datepicker`, `./multiselect`, `./table`, `./floatlabel`, `./dialog`, `./toast`, `./tooltip`, `./tabs`, `./progress`, `./skeleton`, `./alert`, `./drawer`, `./dropdown`, `./icon`, `./icons`, `./pagination`, `./autocomplete`, `./knob`, `./orderlist`, `./picklist`, `./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.8):
68
+ 🔗 Links diretos para CDN (versão 1.1.10):
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
  -->
@@ -1 +1 @@
1
- {"version":3,"file":"drawer.d.ts","sourceRoot":"","sources":["../../../src/components/drawer/drawer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAK5C;;;;;;;;;GASG;AACH,qBAAa,QAAS,SAAQ,SAAS;IACtC,OAAgB,MAAM,SAsHpB;IAEF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAEjD;IAED,IAAI,IAAI,IAAI,OAAO,CAElB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,EAEtB;IAED,IAAa,KAAK,IAAI,MAAM,CAE3B;IACD,IAAa,KAAK,CAAC,CAAC,EAAE,MAAM,EAE3B;IAED,IAAI,QAAQ,IAAI,MAAM,CAGrB;IACD,IAAI,QAAQ,CAAC,CAAC,EAAE,MAAM,EAErB;cAEkB,MAAM,IAAI,IAAI;cAwBd,iBAAiB,IAAI,IAAI;cAYzB,oBAAoB,IAAI,IAAI;IAM/C,OAAO,CAAC,UAAU,CAAwC;IAC1D,OAAO,CAAC,kBAAkB,CAA4B;IAEtD,OAAO,CAAC,MAAM,CAOZ;IAEF,2DAA2D;IAC3D,OAAO,CAAC,UAAU;IAmBlB,OAAO,CAAC,aAAa;CAIrB;AAED,wBAAgB,cAAc,IAAI,OAAO,QAAQ,CAEhD"}
1
+ {"version":3,"file":"drawer.d.ts","sourceRoot":"","sources":["../../../src/components/drawer/drawer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAK5C;;;;;;;;;GASG;AACH,qBAAa,QAAS,SAAQ,SAAS;IACtC,OAAgB,MAAM,SA0HpB;IAEF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAEjD;IAED,IAAI,IAAI,IAAI,OAAO,CAElB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,EAEtB;IAED,IAAa,KAAK,IAAI,MAAM,CAE3B;IACD,IAAa,KAAK,CAAC,CAAC,EAAE,MAAM,EAE3B;IAED,IAAI,QAAQ,IAAI,MAAM,CAGrB;IACD,IAAI,QAAQ,CAAC,CAAC,EAAE,MAAM,EAErB;cAEkB,MAAM,IAAI,IAAI;cAwBd,iBAAiB,IAAI,IAAI;cAYzB,oBAAoB,IAAI,IAAI;IAM/C,OAAO,CAAC,UAAU,CAAwC;IAC1D,OAAO,CAAC,kBAAkB,CAA4B;IAEtD,OAAO,CAAC,MAAM,CAOZ;IAEF,2DAA2D;IAC3D,OAAO,CAAC,UAAU;IAmBlB,OAAO,CAAC,aAAa;CAIrB;AAED,wBAAgB,cAAc,IAAI,OAAO,QAAQ,CAEhD"}
@@ -184,6 +184,10 @@ _FxDrawer.styles = css`
184
184
  position: sticky;
185
185
  top: 0;
186
186
  background: var(--fx-surface-background);
187
+ /* O conteúdo do drawer (ex.: abas da customização de tema)
188
+ rola por trás do header: sem z-index o texto passava POR CIMA
189
+ e o header parecia transparente. */
190
+ z-index: 1;
187
191
  }
188
192
  .title {
189
193
  font-weight: 700;
@@ -1 +1 @@
1
- {"version":3,"file":"drawer.js","sources":["../../../src/components/drawer/drawer.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-drawer> — Painel deslizante (drawer) com overlay.\n *\n * Atributos:\n * - position: 'left' | 'right' | 'top' | 'bottom' (padrão: right);\n * - title: texto do cabeçalho;\n * - open: exibe o drawer.\n * Conteúdo: livre, via slot.\n * Eventos: `open` e `close` (composed). Fecha por ESC ou clique no overlay.\n */\nexport class FxDrawer extends FxElement {\n\tstatic override styles = css`\n\t\t:host {\n\t\t\tdisplay: contents;\n\t\t\tfont-family: var(--fx-font-family);\n\t\t\tfont-size: var(--fx-font-size);\n\t\t\tcolor: var(--fx-text-default);\n\t\t}\n\t\t.overlay {\n\t\t\tdisplay: none;\n\t\t\tposition: fixed;\n\t\t\tinset: 0;\n\t\t\tbackground: color-mix(\n\t\t\t\tin srgb,\n\t\t\t\tvar(--fx-text-default, #000) 45%,\n\t\t\t\ttransparent\n\t\t\t);\n\t\t\tbackdrop-filter: blur(3px);\n\t\t\t-webkit-backdrop-filter: blur(3px);\n\t\t\tz-index: var(--fx-z-overlay, 1090);\n\t\t\tanimation: fade var(--fx-motion-duration-fast) var(--fx-motion-easing);\n\t\t}\n\t\t:host([open]) .overlay {\n\t\t\tdisplay: block;\n\t\t}\n\n\t\t.panel {\n\t\t\tposition: fixed;\n\t\t\tbackground: var(--fx-surface-background);\n\t\t\tbox-shadow: var(--fx-shadow-xl);\n\t\t\tz-index: var(--fx-z-modal, 1000);\n\t\t\tdisplay: flex;\n\t\t\tflex-direction: column;\n\t\t\toverflow: auto;\n\t\t}\n\t\t:host(:not([open])) .panel {\n\t\t\tdisplay: none;\n\t\t}\n\t\t:host([open]) .panel {\n\t\t\tdisplay: flex;\n\t\t}\n\t\t/* left / right — altura total, largura mínima fixa e expansível */\n\t\t:host([position=\"left\"]) .panel,\n\t\t:host(:not([position])) .panel,\n\t\t:host([position=\"right\"]) .panel {\n\t\t\ttop: 0;\n\t\t\tbottom: 0;\n\t\t\twidth: var(--fx-drawer-width, 360px);\n\t\t\tmin-width: 300px;\n\t\t\tmax-width: 90vw;\n\t\t}\n\t\t:host([position=\"left\"]) .panel {\n\t\t\tleft: 0;\n\t\t}\n\t\t:host([position=\"right\"]) .panel,\n\t\t:host(:not([position])) .panel {\n\t\t\tright: 0;\n\t\t}\n\n\t\t/* top / bottom — largura total, altura mínima fixa e expansível */\n\t\t:host([position=\"top\"]) .panel,\n\t\t:host([position=\"bottom\"]) .panel {\n\t\t\tleft: 0;\n\t\t\tright: 0;\n\t\t\theight: var(--fx-drawer-height, 280px);\n\t\t\tmin-height: 180px;\n\t\t\tmax-height: 85vh;\n\t\t}\n\t\t:host([position=\"top\"]) .panel {\n\t\t\ttop: 0;\n\t\t}\n\t\t:host([position=\"bottom\"]) .panel {\n\t\t\tbottom: 0;\n\t\t}\n\n\t\t.header {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tgap: var(--fx-space-sm);\n\t\t\tmin-height: var(--fx-size-lg);\n\t\t\tpadding: var(--fx-space-sm) var(--fx-space-md);\n\t\t\tborder-bottom: 1px solid var(--fx-border-default);\n\t\t\tflex: none;\n\t\t\tposition: sticky;\n\t\t\ttop: 0;\n\t\t\tbackground: var(--fx-surface-background);\n\t\t}\n\t\t.title {\n\t\t\tfont-weight: 700;\n\t\t\tflex: 1;\n\t\t\toverflow: hidden;\n\t\t\ttext-overflow: ellipsis;\n\t\t\twhite-space: nowrap;\n\t\t}\n\t\t.close {\n\t\t\tborder: none;\n\t\t\tbackground: transparent;\n\t\t\tcursor: pointer;\n\t\t\tcolor: var(--fx-text-muted);\n\t\t\twidth: 28px;\n\t\t\theight: 28px;\n\t\t\tline-height: 1;\n\t\t\tborder-radius: var(--fx-radius-sm);\n\t\t\tfont-size: 16px;\n\t\t\ttransition: background var(--fx-motion-duration-fast)\n\t\t\t\tvar(--fx-motion-easing);\n\t\t}\n\t\t.close:hover {\n\t\t\tbackground: color-mix(\n\t\t\t\tin srgb,\n\t\t\t\tvar(--fx-color-danger) 14%,\n\t\t\t\tvar(--fx-surface-background)\n\t\t\t);\n\t\t\tcolor: var(--fx-color-danger);\n\t\t}\n\t\t.body {\n\t\t\tpadding: var(--fx-space-md);\n\t\t\tflex: 1;\n\t\t}\n\t`;\n\n\tstatic override get observedAttributes(): string[] {\n\t\treturn [\"open\", \"title\", \"position\"];\n\t}\n\n\tget open(): boolean {\n\t\treturn this.hasAttr(\"open\");\n\t}\n\tset open(value: boolean) {\n\t\tthis.toggleAttr(\"open\", value);\n\t}\n\n\toverride get title(): string {\n\t\treturn this.getAttr(\"title\");\n\t}\n\toverride set title(v: string) {\n\t\tthis.setAttribute(\"title\", v);\n\t}\n\n\tget position(): string {\n\t\tconst p = this.getAttr(\"position\");\n\t\treturn [\"left\", \"right\", \"top\", \"bottom\"].includes(p) ? p : \"right\";\n\t}\n\tset position(v: string) {\n\t\tthis.setAttribute(\"position\", v);\n\t}\n\n\tprotected override render(): void {\n\t\tconst title = this.getAttr(\"title\");\n\n\t\tthis.setTemplate(`\n <div class=\"overlay\" part=\"overlay\"></div>\n <div class=\"panel\" part=\"panel\" role=\"dialog\" aria-modal=\"true\" aria-label=\"${esc(title || \"Drawer\")}\" tabindex=\"-1\">\n ${title !== \"\" ? `<div class=\"header\" part=\"header\"><span class=\"title\">${esc(title)}</span><button type=\"button\" class=\"close\" part=\"close\" aria-label=\"Fechar\">✕</button></div>` : \"\"}\n <div class=\"body\" part=\"body\"><slot></slot></div>\n </div>\n `);\n\n\t\tthis.root.querySelector(\".overlay\")?.addEventListener(\"click\", this._close);\n\t\tthis.root.querySelector(\".close\")?.addEventListener(\"click\", this._close);\n\n\t\tif (this.open) {\n\t\t\trequestAnimationFrame(() => {\n\t\t\t\tif (this._previouslyFocused === null) {\n\t\t\t\t\tthis._previouslyFocused = document.activeElement as HTMLElement | null;\n\t\t\t\t}\n\t\t\t\tthis.root.querySelector<HTMLElement>(\".panel\")?.focus();\n\t\t\t});\n\t\t}\n\t}\n\n\tprotected override connectedCallback(): void {\n\t\tsuper.connectedCallback?.();\n\t\tthis._onKeydown = (e: KeyboardEvent) => {\n\t\t\tif (e.key === \"Escape\" && this.open) {\n\t\t\t\tthis._close();\n\t\t\t} else if (e.key === \"Tab\" && this.open) {\n\t\t\t\tthis._trapFocus(e);\n\t\t\t}\n\t\t};\n\t\tdocument.addEventListener(\"keydown\", this._onKeydown);\n\t}\n\n\tprotected override disconnectedCallback(): void {\n\t\tdocument.removeEventListener(\"keydown\", this._onKeydown);\n\t\tthis._restoreFocus();\n\t\tsuper.disconnectedCallback?.();\n\t}\n\n\tprivate _onKeydown: (e: KeyboardEvent) => void = () => {};\n\tprivate _previouslyFocused: HTMLElement | null = null;\n\n\tprivate _close = (): void => {\n\t\tif (!this.open) return;\n\t\tthis.open = false;\n\t\tthis._restoreFocus();\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent(\"close\", { bubbles: true, composed: true }),\n\t\t);\n\t};\n\n\t/** Mantém o foco dentro do drawer (WCAG 2.4.3 / 2.1.2). */\n\tprivate _trapFocus(e: KeyboardEvent): void {\n\t\tconst panel = this.root.querySelector<HTMLElement>(\".panel\");\n\t\tif (!panel) return;\n\t\tconst focusables = panel.querySelectorAll<HTMLElement>(\n\t\t\t'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])',\n\t\t);\n\t\tif (!focusables.length) return;\n\t\tconst first = focusables[0];\n\t\tconst last = focusables[focusables.length - 1];\n\t\tconst active = this.root.activeElement;\n\t\tif (e.shiftKey && (active === first || active === panel)) {\n\t\t\te.preventDefault();\n\t\t\tlast.focus();\n\t\t} else if (!e.shiftKey && active === last) {\n\t\t\te.preventDefault();\n\t\t\tfirst.focus();\n\t\t}\n\t}\n\n\tprivate _restoreFocus(): void {\n\t\tif (this._previouslyFocused?.isConnected) this._previouslyFocused.focus();\n\t\tthis._previouslyFocused = null;\n\t}\n}\n\nexport function defineFxDrawer(): typeof FxDrawer {\n return defineElement('fx-drawer', FxDrawer);\n}"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"drawer.js","sources":["../../../src/components/drawer/drawer.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-drawer> — Painel deslizante (drawer) com overlay.\n *\n * Atributos:\n * - position: 'left' | 'right' | 'top' | 'bottom' (padrão: right);\n * - title: texto do cabeçalho;\n * - open: exibe o drawer.\n * Conteúdo: livre, via slot.\n * Eventos: `open` e `close` (composed). Fecha por ESC ou clique no overlay.\n */\nexport class FxDrawer extends FxElement {\n\tstatic override styles = css`\n\t\t:host {\n\t\t\tdisplay: contents;\n\t\t\tfont-family: var(--fx-font-family);\n\t\t\tfont-size: var(--fx-font-size);\n\t\t\tcolor: var(--fx-text-default);\n\t\t}\n\t\t.overlay {\n\t\t\tdisplay: none;\n\t\t\tposition: fixed;\n\t\t\tinset: 0;\n\t\t\tbackground: color-mix(\n\t\t\t\tin srgb,\n\t\t\t\tvar(--fx-text-default, #000) 45%,\n\t\t\t\ttransparent\n\t\t\t);\n\t\t\tbackdrop-filter: blur(3px);\n\t\t\t-webkit-backdrop-filter: blur(3px);\n\t\t\tz-index: var(--fx-z-overlay, 1090);\n\t\t\tanimation: fade var(--fx-motion-duration-fast) var(--fx-motion-easing);\n\t\t}\n\t\t:host([open]) .overlay {\n\t\t\tdisplay: block;\n\t\t}\n\n\t\t.panel {\n\t\t\tposition: fixed;\n\t\t\tbackground: var(--fx-surface-background);\n\t\t\tbox-shadow: var(--fx-shadow-xl);\n\t\t\tz-index: var(--fx-z-modal, 1000);\n\t\t\tdisplay: flex;\n\t\t\tflex-direction: column;\n\t\t\toverflow: auto;\n\t\t}\n\t\t:host(:not([open])) .panel {\n\t\t\tdisplay: none;\n\t\t}\n\t\t:host([open]) .panel {\n\t\t\tdisplay: flex;\n\t\t}\n\t\t/* left / right — altura total, largura mínima fixa e expansível */\n\t\t:host([position=\"left\"]) .panel,\n\t\t:host(:not([position])) .panel,\n\t\t:host([position=\"right\"]) .panel {\n\t\t\ttop: 0;\n\t\t\tbottom: 0;\n\t\t\twidth: var(--fx-drawer-width, 360px);\n\t\t\tmin-width: 300px;\n\t\t\tmax-width: 90vw;\n\t\t}\n\t\t:host([position=\"left\"]) .panel {\n\t\t\tleft: 0;\n\t\t}\n\t\t:host([position=\"right\"]) .panel,\n\t\t:host(:not([position])) .panel {\n\t\t\tright: 0;\n\t\t}\n\n\t\t/* top / bottom — largura total, altura mínima fixa e expansível */\n\t\t:host([position=\"top\"]) .panel,\n\t\t:host([position=\"bottom\"]) .panel {\n\t\t\tleft: 0;\n\t\t\tright: 0;\n\t\t\theight: var(--fx-drawer-height, 280px);\n\t\t\tmin-height: 180px;\n\t\t\tmax-height: 85vh;\n\t\t}\n\t\t:host([position=\"top\"]) .panel {\n\t\t\ttop: 0;\n\t\t}\n\t\t:host([position=\"bottom\"]) .panel {\n\t\t\tbottom: 0;\n\t\t}\n\n\t\t.header {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tgap: var(--fx-space-sm);\n\t\t\tmin-height: var(--fx-size-lg);\n\t\t\tpadding: var(--fx-space-sm) var(--fx-space-md);\n\t\t\tborder-bottom: 1px solid var(--fx-border-default);\n\t\t\tflex: none;\n\t\t\tposition: sticky;\n\t\t\ttop: 0;\n\t\t\tbackground: var(--fx-surface-background);\n\t\t\t/* O conteúdo do drawer (ex.: abas da customização de tema)\n\t\t\t rola por trás do header: sem z-index o texto passava POR CIMA\n\t\t\t e o header parecia transparente. */\n\t\t\tz-index: 1;\n\t\t}\n\t\t.title {\n\t\t\tfont-weight: 700;\n\t\t\tflex: 1;\n\t\t\toverflow: hidden;\n\t\t\ttext-overflow: ellipsis;\n\t\t\twhite-space: nowrap;\n\t\t}\n\t\t.close {\n\t\t\tborder: none;\n\t\t\tbackground: transparent;\n\t\t\tcursor: pointer;\n\t\t\tcolor: var(--fx-text-muted);\n\t\t\twidth: 28px;\n\t\t\theight: 28px;\n\t\t\tline-height: 1;\n\t\t\tborder-radius: var(--fx-radius-sm);\n\t\t\tfont-size: 16px;\n\t\t\ttransition: background var(--fx-motion-duration-fast)\n\t\t\t\tvar(--fx-motion-easing);\n\t\t}\n\t\t.close:hover {\n\t\t\tbackground: color-mix(\n\t\t\t\tin srgb,\n\t\t\t\tvar(--fx-color-danger) 14%,\n\t\t\t\tvar(--fx-surface-background)\n\t\t\t);\n\t\t\tcolor: var(--fx-color-danger);\n\t\t}\n\t\t.body {\n\t\t\tpadding: var(--fx-space-md);\n\t\t\tflex: 1;\n\t\t}\n\t`;\n\n\tstatic override get observedAttributes(): string[] {\n\t\treturn [\"open\", \"title\", \"position\"];\n\t}\n\n\tget open(): boolean {\n\t\treturn this.hasAttr(\"open\");\n\t}\n\tset open(value: boolean) {\n\t\tthis.toggleAttr(\"open\", value);\n\t}\n\n\toverride get title(): string {\n\t\treturn this.getAttr(\"title\");\n\t}\n\toverride set title(v: string) {\n\t\tthis.setAttribute(\"title\", v);\n\t}\n\n\tget position(): string {\n\t\tconst p = this.getAttr(\"position\");\n\t\treturn [\"left\", \"right\", \"top\", \"bottom\"].includes(p) ? p : \"right\";\n\t}\n\tset position(v: string) {\n\t\tthis.setAttribute(\"position\", v);\n\t}\n\n\tprotected override render(): void {\n\t\tconst title = this.getAttr(\"title\");\n\n\t\tthis.setTemplate(`\n <div class=\"overlay\" part=\"overlay\"></div>\n <div class=\"panel\" part=\"panel\" role=\"dialog\" aria-modal=\"true\" aria-label=\"${esc(title || \"Drawer\")}\" tabindex=\"-1\">\n ${title !== \"\" ? `<div class=\"header\" part=\"header\"><span class=\"title\">${esc(title)}</span><button type=\"button\" class=\"close\" part=\"close\" aria-label=\"Fechar\">✕</button></div>` : \"\"}\n <div class=\"body\" part=\"body\"><slot></slot></div>\n </div>\n `);\n\n\t\tthis.root.querySelector(\".overlay\")?.addEventListener(\"click\", this._close);\n\t\tthis.root.querySelector(\".close\")?.addEventListener(\"click\", this._close);\n\n\t\tif (this.open) {\n\t\t\trequestAnimationFrame(() => {\n\t\t\t\tif (this._previouslyFocused === null) {\n\t\t\t\t\tthis._previouslyFocused = document.activeElement as HTMLElement | null;\n\t\t\t\t}\n\t\t\t\tthis.root.querySelector<HTMLElement>(\".panel\")?.focus();\n\t\t\t});\n\t\t}\n\t}\n\n\tprotected override connectedCallback(): void {\n\t\tsuper.connectedCallback?.();\n\t\tthis._onKeydown = (e: KeyboardEvent) => {\n\t\t\tif (e.key === \"Escape\" && this.open) {\n\t\t\t\tthis._close();\n\t\t\t} else if (e.key === \"Tab\" && this.open) {\n\t\t\t\tthis._trapFocus(e);\n\t\t\t}\n\t\t};\n\t\tdocument.addEventListener(\"keydown\", this._onKeydown);\n\t}\n\n\tprotected override disconnectedCallback(): void {\n\t\tdocument.removeEventListener(\"keydown\", this._onKeydown);\n\t\tthis._restoreFocus();\n\t\tsuper.disconnectedCallback?.();\n\t}\n\n\tprivate _onKeydown: (e: KeyboardEvent) => void = () => {};\n\tprivate _previouslyFocused: HTMLElement | null = null;\n\n\tprivate _close = (): void => {\n\t\tif (!this.open) return;\n\t\tthis.open = false;\n\t\tthis._restoreFocus();\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent(\"close\", { bubbles: true, composed: true }),\n\t\t);\n\t};\n\n\t/** Mantém o foco dentro do drawer (WCAG 2.4.3 / 2.1.2). */\n\tprivate _trapFocus(e: KeyboardEvent): void {\n\t\tconst panel = this.root.querySelector<HTMLElement>(\".panel\");\n\t\tif (!panel) return;\n\t\tconst focusables = panel.querySelectorAll<HTMLElement>(\n\t\t\t'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])',\n\t\t);\n\t\tif (!focusables.length) return;\n\t\tconst first = focusables[0];\n\t\tconst last = focusables[focusables.length - 1];\n\t\tconst active = this.root.activeElement;\n\t\tif (e.shiftKey && (active === first || active === panel)) {\n\t\t\te.preventDefault();\n\t\t\tlast.focus();\n\t\t} else if (!e.shiftKey && active === last) {\n\t\t\te.preventDefault();\n\t\t\tfirst.focus();\n\t\t}\n\t}\n\n\tprivate _restoreFocus(): void {\n\t\tif (this._previouslyFocused?.isConnected) this._previouslyFocused.focus();\n\t\tthis._previouslyFocused = null;\n\t}\n}\n\nexport function defineFxDrawer(): typeof FxDrawer {\n return defineElement('fx-drawer', FxDrawer);\n}"],"names":[],"mappings":"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"}
@@ -17,6 +17,7 @@ export declare class FxPagination extends FxElement {
17
17
  get rows(): number;
18
18
  set rows(v: number);
19
19
  private get pages();
20
+ protected connectedCallback(): void;
20
21
  protected render(): void;
21
22
  private emit;
22
23
  }
@@ -1 +1 @@
1
- {"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../../../src/components/pagination/pagination.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C,OAAO,WAAW,CAAC;AAEnB;;;;;;GAMG;AACH,qBAAa,YAAa,SAAQ,SAAS;IACzC,OAAgB,MAAM,SA2CpB;IAEF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAEjD;IAED,IAAI,IAAI,IAAI,MAAM,CAAmD;IACrE,IAAI,IAAI,CAAC,CAAC,EAAE,MAAM,EAA2C;IAC7D,IAAI,KAAK,IAAI,MAAM,CAAoD;IACvE,IAAI,KAAK,CAAC,CAAC,EAAE,MAAM,EAA4C;IAC/D,IAAI,IAAI,IAAI,MAAM,CAAqD;IACvE,IAAI,IAAI,CAAC,CAAC,EAAE,MAAM,EAA2C;IAE7D,OAAO,KAAK,KAAK,GAEhB;cAEkB,MAAM,IAAI,IAAI;IAgDjC,OAAO,CAAC,IAAI;CAMb;AAED,wBAAgB,kBAAkB,IAAI,OAAO,YAAY,CAExD"}
1
+ {"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../../../src/components/pagination/pagination.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAM5C,OAAO,WAAW,CAAC;AAEnB;;;;;;GAMG;AACH,qBAAa,YAAa,SAAQ,SAAS;IACzC,OAAgB,MAAM,SAmDpB;IAEF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAEjD;IAED,IAAI,IAAI,IAAI,MAAM,CAAmD;IACrE,IAAI,IAAI,CAAC,CAAC,EAAE,MAAM,EAA2C;IAC7D,IAAI,KAAK,IAAI,MAAM,CAAoD;IACvE,IAAI,KAAK,CAAC,CAAC,EAAE,MAAM,EAA4C;IAC/D,IAAI,IAAI,IAAI,MAAM,CAAqD;IACvE,IAAI,IAAI,CAAC,CAAC,EAAE,MAAM,EAA2C;IAE7D,OAAO,KAAK,KAAK,GAEhB;cAEkB,iBAAiB,IAAI,IAAI;cAOzB,MAAM,IAAI,IAAI;IAkDjC,OAAO,CAAC,IAAI;CAMb;AAED,wBAAgB,kBAAkB,IAAI,OAAO,YAAY,CAExD"}
@@ -2,6 +2,8 @@ import { FxElement } from "../../core/base.js";
2
2
  import { css } from "../../core/css.js";
3
3
  import { defineElement } from "../../core/define.js";
4
4
  import { esc } from "../../core/sanitize.js";
5
+ import { FENIX_ICON_BASE_CSS, fenixIconHtml } from "../../icons/base-css.js";
6
+ import { loadFenixIconsFont } from "../../icons/font.js";
5
7
  import "../select/index.js";
6
8
  const _FxPagination = class _FxPagination extends FxElement {
7
9
  static get observedAttributes() {
@@ -28,6 +30,10 @@ const _FxPagination = class _FxPagination extends FxElement {
28
30
  get pages() {
29
31
  return Math.max(1, Math.ceil(this.total / this.rows));
30
32
  }
33
+ connectedCallback() {
34
+ loadFenixIconsFont();
35
+ super.connectedCallback();
36
+ }
31
37
  render() {
32
38
  const pages = this.pages;
33
39
  const current = Math.min(Math.max(1, this.page), pages);
@@ -38,11 +44,13 @@ const _FxPagination = class _FxPagination extends FxElement {
38
44
  const to = Math.min(current * this.rows, this.total);
39
45
  this.setTemplate(`
40
46
  <span class="info">${this.total ? `${from}-${to} de ${this.total}` : "0 itens"}</span>
41
- <button type="button" class="nav" part="prev" data-go="${current - 1}" ${current <= 1 ? "disabled" : ""}>‹</button>
47
+ <button type="button" class="nav" part="first" aria-label="Primeira página" data-go="1" ${current <= 1 ? "disabled" : ""}>${fenixIconHtml("first_page")}</button>
48
+ <button type="button" class="nav" part="prev" aria-label="Página anterior" data-go="${current - 1}" ${current <= 1 ? "disabled" : ""}>${fenixIconHtml("navigate_before")}</button>
42
49
  ${window_[0] !== 1 && pages > 5 ? `<button type="button" class="nav" data-go="1">1</button>` : ""}
43
50
  ${window_.map((p) => `<button type="button" class="nav ${p === current ? "active" : ""}" data-go="${p}">${p}</button>`).join("")}
44
51
  ${window_[window_.length - 1] !== pages && pages > 5 ? `<button type="button" class="nav" data-go="${pages}">${pages}</button>` : ""}
45
- <button type="button" class="nav" part="next" data-go="${current + 1}" ${current >= pages ? "disabled" : ""}>›</button>
52
+ <button type="button" class="nav" part="next" aria-label="Próxima página" data-go="${current + 1}" ${current >= pages ? "disabled" : ""}>${fenixIconHtml("navigate_next")}</button>
53
+ <button type="button" class="nav" part="last" aria-label="Última página" data-go="${pages}" ${current >= pages ? "disabled" : ""}>${fenixIconHtml("last_page")}</button>
46
54
  ${opts.length ? `
47
55
  <fx-select class="rows-sel" part="rows" size="sm" value="${this.rows}" aria-label="Itens por página">
48
56
  ${opts.map((o) => `<option value="${esc(o)}">${esc(o)}</option>`).join("")}
@@ -78,6 +86,7 @@ const _FxPagination = class _FxPagination extends FxElement {
78
86
  }
79
87
  };
80
88
  _FxPagination.styles = css`
89
+ ${FENIX_ICON_BASE_CSS}
81
90
  :host {
82
91
  display: flex;
83
92
  align-items: center;
@@ -89,6 +98,9 @@ _FxPagination.styles = css`
89
98
  :host([position='center']) { justify-content: center; }
90
99
  :host([position='right']) { justify-content: flex-end; }
91
100
  .nav {
101
+ display: inline-flex;
102
+ align-items: center;
103
+ justify-content: center;
92
104
  min-width: var(--fx-size-sm);
93
105
  height: var(--fx-size-sm);
94
106
  border: 1px solid var(--fx-border-default);
@@ -103,6 +115,10 @@ _FxPagination.styles = css`
103
115
  border-color var(--fx-motion-duration-fast) var(--fx-motion-easing),
104
116
  background var(--fx-motion-duration-fast) var(--fx-motion-easing);
105
117
  }
118
+ /* O glifo precisa de 1px a mais que o dígito: a altura de traço do ícone é
119
+ maior que a do número, então igualar os dois font-size deixa a seta
120
+ visivelmente maior que o texto. */
121
+ .nav .fx-icon { font-size: calc(var(--fx-font-size) - 1px); }
106
122
  .nav:hover:not([disabled]):not(.active) { border-color: var(--fx-color-primary); color: var(--fx-color-primary); }
107
123
  .nav[disabled] { opacity: 0.5; cursor: not-allowed; }
108
124
  .nav.active {
@@ -1 +1 @@
1
- {"version":3,"file":"pagination.js","sources":["../../../src/components/pagination/pagination.ts"],"sourcesContent":["import { FxElement } from '../../core/base';\nimport { css } from '../../core/css';\nimport { defineElement } from '../../core/define';\nimport { esc } from '../../core/sanitize';\nimport '../select';\n\n/**\n * <fx-pagination> — Paginação standalone.\n *\n * Atributos: page (atual), total (itens), rows (por página), rows-options,\n * position (left|center|right).\n * Evento: `page-change` (composed, detail: { page, rows }).\n */\nexport class FxPagination extends FxElement {\n static override styles = css`\n :host {\n display: flex;\n align-items: center;\n gap: var(--fx-space-sm);\n font-family: var(--fx-font-family);\n font-size: var(--fx-font-size);\n color: var(--fx-text-default);\n }\n :host([position='center']) { justify-content: center; }\n :host([position='right']) { justify-content: flex-end; }\n .nav {\n min-width: var(--fx-size-sm);\n height: var(--fx-size-sm);\n border: 1px solid var(--fx-border-default);\n background: var(--fx-surface-background);\n color: var(--fx-text-default);\n font-family: inherit;\n font-size: calc(var(--fx-font-size) - 2px);\n border-radius: var(--fx-radius-sm);\n cursor: pointer;\n padding: 0 var(--fx-space-sm);\n transition:\n border-color var(--fx-motion-duration-fast) var(--fx-motion-easing),\n background var(--fx-motion-duration-fast) var(--fx-motion-easing);\n }\n .nav:hover:not([disabled]):not(.active) { border-color: var(--fx-color-primary); color: var(--fx-color-primary); }\n .nav[disabled] { opacity: 0.5; cursor: not-allowed; }\n .nav.active {\n background: var(--fx-color-primary);\n border-color: var(--fx-color-primary);\n color: #fff;\n font-weight: 600;\n }\n .info { color: var(--fx-text-muted); font-size: calc(var(--fx-font-size) - 2px); }\n fx-select { vertical-align: middle; }\n fx-select::part(trigger) {\n min-width: 64px !important;\n min-height: var(--fx-size-sm) !important;\n padding: 0 var(--fx-space-sm) !important;\n border-radius: var(--fx-radius-sm) !important;\n font-size: calc(var(--fx-font-size) - 2px) !important;\n }\n `;\n\n static override get observedAttributes(): string[] {\n return ['page', 'total', 'rows', 'rows-options', 'position'];\n }\n\n get page(): number { return Number(this.getAttr('page', '1')) || 1; }\n set page(v: number) { this.setAttribute('page', String(v)); }\n get total(): number { return Number(this.getAttr('total', '0')) || 0; }\n set total(v: number) { this.setAttribute('total', String(v)); }\n get rows(): number { return Number(this.getAttr('rows', '10')) || 10; }\n set rows(v: number) { this.setAttribute('rows', String(v)); }\n\n private get pages(): number {\n return Math.max(1, Math.ceil(this.total / this.rows));\n }\n\n protected override render(): void {\n const pages = this.pages;\n const current = Math.min(Math.max(1, this.page), pages);\n const opts = (this.getAttr('rows-options', '5,10,20,50') || '').split(',').map((s) => s.trim()).filter(Boolean);\n\n // Janela de páginas: mostra até 5 com elipses simplificada\n const window_: number[] = [];\n for (let p = Math.max(1, current - 2); p <= Math.min(pages, current + 2); p++) window_.push(p);\n\n const from = total0(current, this.rows);\n const to = Math.min(current * this.rows, this.total);\n\n this.setTemplate(`\n <span class=\"info\">${this.total ? `${from}-${to} de ${this.total}` : '0 itens'}</span>\n <button type=\"button\" class=\"nav\" part=\"prev\" data-go=\"${current - 1}\" ${current <= 1 ? 'disabled' : ''}>‹</button>\n ${window_[0] !== 1 && pages > 5 ? `<button type=\"button\" class=\"nav\" data-go=\"1\">1</button>` : ''}\n ${window_.map((p) => `<button type=\"button\" class=\"nav ${p === current ? 'active' : ''}\" data-go=\"${p}\">${p}</button>`).join('')}\n ${window_[window_.length - 1] !== pages && pages > 5 ? `<button type=\"button\" class=\"nav\" data-go=\"${pages}\">${pages}</button>` : ''}\n <button type=\"button\" class=\"nav\" part=\"next\" data-go=\"${current + 1}\" ${current >= pages ? 'disabled' : ''}>›</button>\n ${opts.length ? `\n <fx-select class=\"rows-sel\" part=\"rows\" size=\"sm\" value=\"${this.rows}\" aria-label=\"Itens por página\">\n ${opts.map((o) => `<option value=\"${esc(o)}\">${esc(o)}</option>`).join('')}\n </fx-select>` : ''}\n `);\n\n function total0(page: number, rows: number): number {\n return (page - 1) * rows + 1;\n }\n\n this.root.querySelectorAll<HTMLButtonElement>('.nav[data-go]').forEach((btn) => {\n btn.addEventListener('click', () => {\n const target = Number(btn.dataset.go);\n if (target >= 1 && target <= pages && target !== current) {\n this.page = target;\n this.emit();\n }\n });\n });\n const sel = this.root.querySelector<HTMLElement>('fx-select.rows-sel');\n sel?.addEventListener('change', (e) => {\n const value = Number((e as CustomEvent).detail?.value);\n if (!value || value === this.rows) return;\n this.rows = value;\n this.page = 1;\n this.emit();\n });\n }\n\n private emit(): void {\n this.dispatchEvent(new CustomEvent('page-change', {\n bubbles: true, composed: true,\n detail: { page: this.page, rows: this.rows },\n }));\n }\n}\n\nexport function defineFxPagination(): typeof FxPagination {\n return defineElement('fx-pagination', FxPagination);\n}\n"],"names":[],"mappings":";;;;;AAaO,MAAM,gBAAN,MAAM,sBAAqB,UAAU;AAAA,EA8C1C,WAAoB,qBAA+B;AACjD,WAAO,CAAC,QAAQ,SAAS,QAAQ,gBAAgB,UAAU;AAAA,EAC7D;AAAA,EAEA,IAAI,OAAe;AAAE,WAAO,OAAO,KAAK,QAAQ,QAAQ,GAAG,CAAC,KAAK;AAAA,EAAG;AAAA,EACpE,IAAI,KAAK,GAAW;AAAE,SAAK,aAAa,QAAQ,OAAO,CAAC,CAAC;AAAA,EAAG;AAAA,EAC5D,IAAI,QAAgB;AAAE,WAAO,OAAO,KAAK,QAAQ,SAAS,GAAG,CAAC,KAAK;AAAA,EAAG;AAAA,EACtE,IAAI,MAAM,GAAW;AAAE,SAAK,aAAa,SAAS,OAAO,CAAC,CAAC;AAAA,EAAG;AAAA,EAC9D,IAAI,OAAe;AAAE,WAAO,OAAO,KAAK,QAAQ,QAAQ,IAAI,CAAC,KAAK;AAAA,EAAI;AAAA,EACtE,IAAI,KAAK,GAAW;AAAE,SAAK,aAAa,QAAQ,OAAO,CAAC,CAAC;AAAA,EAAG;AAAA,EAE5D,IAAY,QAAgB;AAC1B,WAAO,KAAK,IAAI,GAAG,KAAK,KAAK,KAAK,QAAQ,KAAK,IAAI,CAAC;AAAA,EACtD;AAAA,EAEmB,SAAe;AAChC,UAAM,QAAQ,KAAK;AACnB,UAAM,UAAU,KAAK,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK;AACtD,UAAM,QAAQ,KAAK,QAAQ,gBAAgB,YAAY,KAAK,IAAI,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,OAAO;AAG9G,UAAM,UAAoB,CAAA;AAC1B,aAAS,IAAI,KAAK,IAAI,GAAG,UAAU,CAAC,GAAG,KAAK,KAAK,IAAI,OAAO,UAAU,CAAC,GAAG,IAAK,SAAQ,KAAK,CAAC;AAE7F,UAAM,OAAO,OAAO,SAAS,KAAK,IAAI;AACtC,UAAM,KAAK,KAAK,IAAI,UAAU,KAAK,MAAM,KAAK,KAAK;AAEnD,SAAK,YAAY;AAAA,2BACM,KAAK,QAAQ,GAAG,IAAI,IAAI,EAAE,OAAO,KAAK,KAAK,KAAK,SAAS;AAAA,+DACrB,UAAU,CAAC,KAAK,WAAW,IAAI,aAAa,EAAE;AAAA,QACrG,QAAQ,CAAC,MAAM,KAAK,QAAQ,IAAI,6DAA6D,EAAE;AAAA,QAC/F,QAAQ,IAAI,CAAC,MAAM,oCAAoC,MAAM,UAAU,WAAW,EAAE,cAAc,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,EAAE,CAAC;AAAA,QAC9H,QAAQ,QAAQ,SAAS,CAAC,MAAM,SAAS,QAAQ,IAAI,8CAA8C,KAAK,KAAK,KAAK,cAAc,EAAE;AAAA,+DAC3E,UAAU,CAAC,KAAK,WAAW,QAAQ,aAAa,EAAE;AAAA,QACzG,KAAK,SAAS;AAAA,mEAC6C,KAAK,IAAI;AAAA,YAChE,KAAK,IAAI,CAAC,MAAM,kBAAkB,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,WAAW,EAAE,KAAK,EAAE,CAAC;AAAA,wBAC5D,EAAE;AAAA,KACrB;AAED,aAAS,OAAO,MAAc,MAAsB;AAClD,cAAQ,OAAO,KAAK,OAAO;AAAA,IAC7B;AAEA,SAAK,KAAK,iBAAoC,eAAe,EAAE,QAAQ,CAAC,QAAQ;AAC9E,UAAI,iBAAiB,SAAS,MAAM;AAClC,cAAM,SAAS,OAAO,IAAI,QAAQ,EAAE;AACpC,YAAI,UAAU,KAAK,UAAU,SAAS,WAAW,SAAS;AACxD,eAAK,OAAO;AACZ,eAAK,KAAA;AAAA,QACP;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AACD,UAAM,MAAM,KAAK,KAAK,cAA2B,oBAAoB;AACrE,SAAK,iBAAiB,UAAU,CAAC,MAAM;AACrC,YAAM,QAAQ,OAAQ,EAAkB,QAAQ,KAAK;AACrD,UAAI,CAAC,SAAS,UAAU,KAAK,KAAM;AACnC,WAAK,OAAO;AACZ,WAAK,OAAO;AACZ,WAAK,KAAA;AAAA,IACP,CAAC;AAAA,EACH;AAAA,EAEQ,OAAa;AACnB,SAAK,cAAc,IAAI,YAAY,eAAe;AAAA,MAChD,SAAS;AAAA,MAAM,UAAU;AAAA,MACzB,QAAQ,EAAE,MAAM,KAAK,MAAM,MAAM,KAAK,KAAA;AAAA,IAAK,CAC5C,CAAC;AAAA,EACJ;AACF;AAlHE,cAAgB,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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AADpB,IAAM,eAAN;AAqHA,SAAS,qBAA0C;AACxD,SAAO,cAAc,iBAAiB,YAAY;AACpD;"}
1
+ {"version":3,"file":"pagination.js","sources":["../../../src/components/pagination/pagination.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, fenixIconHtml } from '../../icons/base-css';\nimport { loadFenixIconsFont } from '../../icons/font';\nimport '../select';\n\n/**\n * <fx-pagination> — Paginação standalone.\n *\n * Atributos: page (atual), total (itens), rows (por página), rows-options,\n * position (left|center|right).\n * Evento: `page-change` (composed, detail: { page, rows }).\n */\nexport class FxPagination extends FxElement {\n static override styles = css`\n ${FENIX_ICON_BASE_CSS}\n :host {\n display: flex;\n align-items: center;\n gap: var(--fx-space-sm);\n font-family: var(--fx-font-family);\n font-size: var(--fx-font-size);\n color: var(--fx-text-default);\n }\n :host([position='center']) { justify-content: center; }\n :host([position='right']) { justify-content: flex-end; }\n .nav {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: var(--fx-size-sm);\n height: var(--fx-size-sm);\n border: 1px solid var(--fx-border-default);\n background: var(--fx-surface-background);\n color: var(--fx-text-default);\n font-family: inherit;\n font-size: calc(var(--fx-font-size) - 2px);\n border-radius: var(--fx-radius-sm);\n cursor: pointer;\n padding: 0 var(--fx-space-sm);\n transition:\n border-color var(--fx-motion-duration-fast) var(--fx-motion-easing),\n background var(--fx-motion-duration-fast) var(--fx-motion-easing);\n }\n /* O glifo precisa de 1px a mais que o dígito: a altura de traço do ícone é\n maior que a do número, então igualar os dois font-size deixa a seta\n visivelmente maior que o texto. */\n .nav .fx-icon { font-size: calc(var(--fx-font-size) - 1px); }\n .nav:hover:not([disabled]):not(.active) { border-color: var(--fx-color-primary); color: var(--fx-color-primary); }\n .nav[disabled] { opacity: 0.5; cursor: not-allowed; }\n .nav.active {\n background: var(--fx-color-primary);\n border-color: var(--fx-color-primary);\n color: #fff;\n font-weight: 600;\n }\n .info { color: var(--fx-text-muted); font-size: calc(var(--fx-font-size) - 2px); }\n fx-select { vertical-align: middle; }\n fx-select::part(trigger) {\n min-width: 64px !important;\n min-height: var(--fx-size-sm) !important;\n padding: 0 var(--fx-space-sm) !important;\n border-radius: var(--fx-radius-sm) !important;\n font-size: calc(var(--fx-font-size) - 2px) !important;\n }\n `;\n\n static override get observedAttributes(): string[] {\n return ['page', 'total', 'rows', 'rows-options', 'position'];\n }\n\n get page(): number { return Number(this.getAttr('page', '1')) || 1; }\n set page(v: number) { this.setAttribute('page', String(v)); }\n get total(): number { return Number(this.getAttr('total', '0')) || 0; }\n set total(v: number) { this.setAttribute('total', String(v)); }\n get rows(): number { return Number(this.getAttr('rows', '10')) || 10; }\n set rows(v: number) { this.setAttribute('rows', String(v)); }\n\n private get pages(): number {\n return Math.max(1, Math.ceil(this.total / this.rows));\n }\n\n protected override connectedCallback(): void {\n // O pager usa glifos da Fenix Icons: garante o @font-face mesmo quando o\n // app não importou `@wrrdev/fenix-ui/icons` (idempotente).\n loadFenixIconsFont();\n super.connectedCallback();\n }\n\n protected override render(): void {\n const pages = this.pages;\n const current = Math.min(Math.max(1, this.page), pages);\n const opts = (this.getAttr('rows-options', '5,10,20,50') || '').split(',').map((s) => s.trim()).filter(Boolean);\n\n // Janela de páginas: mostra até 5 com elipses simplificada\n const window_: number[] = [];\n for (let p = Math.max(1, current - 2); p <= Math.min(pages, current + 2); p++) window_.push(p);\n\n const from = total0(current, this.rows);\n const to = Math.min(current * this.rows, this.total);\n\n this.setTemplate(`\n <span class=\"info\">${this.total ? `${from}-${to} de ${this.total}` : '0 itens'}</span>\n <button type=\"button\" class=\"nav\" part=\"first\" aria-label=\"Primeira página\" data-go=\"1\" ${current <= 1 ? 'disabled' : ''}>${fenixIconHtml('first_page')}</button>\n <button type=\"button\" class=\"nav\" part=\"prev\" aria-label=\"Página anterior\" data-go=\"${current - 1}\" ${current <= 1 ? 'disabled' : ''}>${fenixIconHtml('navigate_before')}</button>\n ${window_[0] !== 1 && pages > 5 ? `<button type=\"button\" class=\"nav\" data-go=\"1\">1</button>` : ''}\n ${window_.map((p) => `<button type=\"button\" class=\"nav ${p === current ? 'active' : ''}\" data-go=\"${p}\">${p}</button>`).join('')}\n ${window_[window_.length - 1] !== pages && pages > 5 ? `<button type=\"button\" class=\"nav\" data-go=\"${pages}\">${pages}</button>` : ''}\n <button type=\"button\" class=\"nav\" part=\"next\" aria-label=\"Próxima página\" data-go=\"${current + 1}\" ${current >= pages ? 'disabled' : ''}>${fenixIconHtml('navigate_next')}</button>\n <button type=\"button\" class=\"nav\" part=\"last\" aria-label=\"Última página\" data-go=\"${pages}\" ${current >= pages ? 'disabled' : ''}>${fenixIconHtml('last_page')}</button>\n ${opts.length ? `\n <fx-select class=\"rows-sel\" part=\"rows\" size=\"sm\" value=\"${this.rows}\" aria-label=\"Itens por página\">\n ${opts.map((o) => `<option value=\"${esc(o)}\">${esc(o)}</option>`).join('')}\n </fx-select>` : ''}\n `);\n\n function total0(page: number, rows: number): number {\n return (page - 1) * rows + 1;\n }\n\n this.root.querySelectorAll<HTMLButtonElement>('.nav[data-go]').forEach((btn) => {\n btn.addEventListener('click', () => {\n const target = Number(btn.dataset.go);\n if (target >= 1 && target <= pages && target !== current) {\n this.page = target;\n this.emit();\n }\n });\n });\n const sel = this.root.querySelector<HTMLElement>('fx-select.rows-sel');\n sel?.addEventListener('change', (e) => {\n const value = Number((e as CustomEvent).detail?.value);\n if (!value || value === this.rows) return;\n this.rows = value;\n this.page = 1;\n this.emit();\n });\n }\n\n private emit(): void {\n this.dispatchEvent(new CustomEvent('page-change', {\n bubbles: true, composed: true,\n detail: { page: this.page, rows: this.rows },\n }));\n }\n}\n\nexport function defineFxPagination(): typeof FxPagination {\n return defineElement('fx-pagination', FxPagination);\n}\n"],"names":[],"mappings":"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"}
@@ -7,20 +7,45 @@ import "../select";
7
7
  *
8
8
  * Colunas (light DOM):
9
9
  * <fx-column field="nome" header="Nome" sortable filterable align="left">
10
- * opcional: <template>R$ {{value}}</template> para render customizado
10
+ * opcional: <fx-cell>R$ {{value}}</fx-cell> para render customizado
11
11
  * ou conteúdo direto (HTML + {{ }}) como template alternativo
12
12
  * </fx-column>
13
13
  *
14
+ * IMPORTANTE (frameworks): use <fx-cell>, NÃO <template>. A tag nativa
15
+ * <template> é reservada — o Vue 3 a transforma em bloco do compilador e o
16
+ * React gerencia os filhos, então o innerHTML chega vazio. <fx-cell> é uma
17
+ * tag própria, sem significado especial para nenhum framework. A forma
18
+ * antiga com <template> continua funcionando (compatibilidade) e há ainda
19
+ * a opção `template="#id"` apontando para um <template> externo.
20
+ *
21
+ * ⚠️ REGRA DO v-pre (Vue) — o conteúdo do <fx-cell> é TEXTO CRU:
22
+ * {{ }} é avaliado pelo motor de expressões do <fx-table> (./expr.ts) e
23
+ * NÃO pelo Vue. Sem `v-pre`, o compilador do Vue consome a interpolação
24
+ * antes: emite `_toDisplayString(_ctx.value | _ctx.number)`, o conteúdo
25
+ * chega sem as chaves no innerHTML e o vue-tsc acusa `value`/`number`
26
+ * inexistentes no escopo. → SEMPRE use <fx-cell v-pre> no Vue.
27
+ *
28
+ * Cada framework tem a sua neutralização (todas verificadas por compilador):
29
+ * - Vue 3 / Nuxt .... v-pre <fx-cell v-pre>{{ value }}</fx-cell>
30
+ * - React / JSX ..... string JS <fx-cell>{'{{ value }}'}</fx-cell>
31
+ * (o `{{ }}` solto é ERRO de sintaxe no parser JSX)
32
+ * - Angular ......... ngNonBindable <fx-cell ngNonBindable>…</fx-cell>
33
+ * - Svelte .......... string JS ou entidades HTML
34
+ * {'{{ value }}'} ou &lbrace;&lbrace; value &rbrace;&rbrace;
35
+ * - HTML/CDN/JSF/JSP nada <fx-cell>{{ value }}</fx-cell>
36
+ *
14
37
  * Toolbar (opcional):
15
- * <template slot="toolbar">
38
+ * <fx-toolbar>
16
39
  * <input data-search-fields="nome,cargo" placeholder="Buscar…">
17
40
  * <button>Nova ação</button>
18
- * </template>
41
+ * </fx-toolbar>
42
+ * (legado ainda aceito: <template slot="toolbar">…</template>)
19
43
  *
20
44
  * Dados: propriedade `data` (array de objetos) ou atributo `data` (JSON).
21
45
  *
22
46
  * Atributos: pagination, rows, rows-options, pagination-position (left|center|right),
23
- * striped, empty-message, lazy, total, loading, loading-message.
47
+ * striped, hover, empty-message, lazy, total, loading, loading-message,
48
+ * sort-field, sort-order.
24
49
  * Eventos: page-change, sort-change, row-click, filter-change (todos composed).
25
50
  */
26
51
  export declare class FxTable extends FxElement {
@@ -42,9 +67,40 @@ export declare class FxTable extends FxElement {
42
67
  set rowsPerPage(value: number);
43
68
  get lazy(): boolean;
44
69
  private get columns();
70
+ /**
71
+ * Resolve o template de célula de uma `<fx-column>`, em ordem de prioridade:
72
+ *
73
+ * 1. `<fx-cell>` — **recomendado**. Tag própria, sem significado especial
74
+ * para Vue/React/Angular/Svelte: nenhum framework a intercepta, então o
75
+ * `innerHTML` sempre chega intacto ao componente. O light DOM do
76
+ * `<fx-table>` não é exibido (a tabela não usa `<slot>`), então o
77
+ * conteúdo-fonte nunca aparece na tela.
78
+ *
79
+ * ⚠️ O conteúdo é TEXTO CRU para o motor de expressões: o `{{ }}` NÃO é
80
+ * interpretado pelo framework hospedeiro. Cada um precisa neutralizar a
81
+ * própria sintaxe antes (ver o cabeçalho do arquivo): `v-pre` no Vue,
82
+ * `{'{{ }}'}` no JSX, `ngNonBindable` no Angular, string/entidades no
83
+ * Svelte. Sem isso o template não chega ao `renderCell`.
84
+ * 2. `template="#id"` (ou `template="id"`) — aponta para um `<template>`
85
+ * declarado **fora** da tabela, útil em React/Angular, onde é mais
86
+ * simples manter o markup num único lugar.
87
+ * 3. `<template>` dentro da coluna — forma **legada**, mantida por
88
+ * compatibilidade. Em Vue 3 ela vira um bloco do compilador e em React os
89
+ * filhos são gerenciados pelo framework; nos dois casos o `innerHTML`
90
+ * chega vazio e a célula não renderiza. Prefira `<fx-cell>`.
91
+ */
92
+ private _resolveCellTemplate;
45
93
  private get toolbarTemplate();
94
+ /**
95
+ * Resolve `ref` para um elemento: `#id`/`id` ⇒ `getElementById` no
96
+ * documento; qualquer outro valor é tratado como seletor CSS relativo à
97
+ * própria tabela. Valores inválidos devolvem `null` (sem exceção).
98
+ */
99
+ private _resolveRef;
46
100
  protected connectedCallback(): void;
47
101
  protected disconnectedCallback(): void;
102
+ /** Ordenação inicial via `sort-field` / `sort-order` (documentados na API). */
103
+ private _parseSortAttributes;
48
104
  private _parseDataAttribute;
49
105
  private computeRows;
50
106
  private _getSearchFields;
@@ -1 +1 @@
1
- {"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../../src/components/table/table.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAK5C,OAAO,WAAW,CAAC;AAEnB;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,OAAQ,SAAQ,SAAS;IACrC,OAAgB,MAAM,SA0MpB;IAEF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAajD;IAED,OAAO,CAAC,KAAK,CAAiC;IAC9C,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,SAAS,CAAM;IACvB,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,eAAe,CAAC,CAAmB;IAE3C,IAAI,IAAI,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAEpC;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAGxC;IAED,IAAI,KAAK,IAAI,MAAM,CAElB;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAGtB;IAED,IAAI,WAAW,IAAI,MAAM,CAGxB;IACD,IAAI,WAAW,CAAC,KAAK,EAAE,MAAM,EAE5B;IAED,IAAI,IAAI,IAAI,OAAO,CAElB;IAED,OAAO,KAAK,OAAO,GAuBlB;IAED,OAAO,KAAK,eAAe,GAI1B;cAEkB,iBAAiB,IAAI,IAAI;cAOzB,oBAAoB,IAAI,IAAI;IAK/C,OAAO,CAAC,mBAAmB;IAgB3B,OAAO,CAAC,WAAW;IAiDnB,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,QAAQ;cAaG,MAAM,IAAI,IAAI;IAyNjC,OAAO,CAAC,qBAAqB;CAM7B;AAED,wBAAgB,aAAa,IAAI,OAAO,OAAO,CAE9C"}
1
+ {"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../../src/components/table/table.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAO5C,OAAO,WAAW,CAAC;AAEnB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,qBAAa,OAAQ,SAAQ,SAAS;IACrC,OAAgB,MAAM,SAiNpB;IAEF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAiBjD;IAED,OAAO,CAAC,KAAK,CAAiC;IAC9C,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,SAAS,CAAM;IACvB,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,eAAe,CAAC,CAAmB;IAE3C,IAAI,IAAI,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAEpC;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAGxC;IAED,IAAI,KAAK,IAAI,MAAM,CAElB;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAGtB;IAED,IAAI,WAAW,IAAI,MAAM,CAGxB;IACD,IAAI,WAAW,CAAC,KAAK,EAAE,MAAM,EAE5B;IAED,IAAI,IAAI,IAAI,OAAO,CAElB;IAED,OAAO,KAAK,OAAO,GAuBlB;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,OAAO,CAAC,oBAAoB;IAW5B,OAAO,KAAK,eAAe,GAU1B;IAED;;;;OAIG;IACH,OAAO,CAAC,WAAW;cAeA,iBAAiB,IAAI,IAAI;cAWzB,oBAAoB,IAAI,IAAI;IAK/C,+EAA+E;IAC/E,OAAO,CAAC,oBAAoB;IAO5B,OAAO,CAAC,mBAAmB;IAgB3B,OAAO,CAAC,WAAW;IAiDnB,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,QAAQ;cAaG,MAAM,IAAI,IAAI;IAyNjC,OAAO,CAAC,qBAAqB;CAM7B;AAED,wBAAgB,aAAa,IAAI,OAAO,OAAO,CAE9C"}
@@ -2,6 +2,8 @@ import { FxElement } from "../../core/base.js";
2
2
  import { css } from "../../core/css.js";
3
3
  import { defineElement } from "../../core/define.js";
4
4
  import { esc } from "../../core/sanitize.js";
5
+ import { FENIX_ICON_BASE_CSS, fenixIconHtml } from "../../icons/base-css.js";
6
+ import { loadFenixIconsFont } from "../../icons/font.js";
5
7
  import { renderCell } from "./expr.js";
6
8
  import "../select/index.js";
7
9
  const _FxTable = class _FxTable extends FxElement {
@@ -20,12 +22,16 @@ const _FxTable = class _FxTable extends FxElement {
20
22
  "rows",
21
23
  "rows-options",
22
24
  "striped",
25
+ "hover",
26
+ "toolbar",
23
27
  "empty-message",
24
28
  "pagination-position",
25
29
  "lazy",
26
30
  "total",
27
31
  "loading",
28
- "loading-message"
32
+ "loading-message",
33
+ "sort-field",
34
+ "sort-order"
29
35
  ];
30
36
  }
31
37
  get data() {
@@ -54,7 +60,7 @@ const _FxTable = class _FxTable extends FxElement {
54
60
  }
55
61
  get columns() {
56
62
  return [...this.querySelectorAll("fx-column")].map((c) => {
57
- const tpl = c.querySelector("template");
63
+ const tpl = this._resolveCellTemplate(c);
58
64
  const direct = tpl ? void 0 : c.innerHTML.trim();
59
65
  const align = c.getAttribute("align") ?? "left";
60
66
  return {
@@ -68,13 +74,71 @@ const _FxTable = class _FxTable extends FxElement {
68
74
  };
69
75
  });
70
76
  }
77
+ /**
78
+ * Resolve o template de célula de uma `<fx-column>`, em ordem de prioridade:
79
+ *
80
+ * 1. `<fx-cell>` — **recomendado**. Tag própria, sem significado especial
81
+ * para Vue/React/Angular/Svelte: nenhum framework a intercepta, então o
82
+ * `innerHTML` sempre chega intacto ao componente. O light DOM do
83
+ * `<fx-table>` não é exibido (a tabela não usa `<slot>`), então o
84
+ * conteúdo-fonte nunca aparece na tela.
85
+ *
86
+ * ⚠️ O conteúdo é TEXTO CRU para o motor de expressões: o `{{ }}` NÃO é
87
+ * interpretado pelo framework hospedeiro. Cada um precisa neutralizar a
88
+ * própria sintaxe antes (ver o cabeçalho do arquivo): `v-pre` no Vue,
89
+ * `{'{{ }}'}` no JSX, `ngNonBindable` no Angular, string/entidades no
90
+ * Svelte. Sem isso o template não chega ao `renderCell`.
91
+ * 2. `template="#id"` (ou `template="id"`) — aponta para um `<template>`
92
+ * declarado **fora** da tabela, útil em React/Angular, onde é mais
93
+ * simples manter o markup num único lugar.
94
+ * 3. `<template>` dentro da coluna — forma **legada**, mantida por
95
+ * compatibilidade. Em Vue 3 ela vira um bloco do compilador e em React os
96
+ * filhos são gerenciados pelo framework; nos dois casos o `innerHTML`
97
+ * chega vazio e a célula não renderiza. Prefira `<fx-cell>`.
98
+ */
99
+ _resolveCellTemplate(c) {
100
+ const cell = c.querySelector(":scope > fx-cell");
101
+ if (cell) return cell;
102
+ const ref = c.getAttribute("template");
103
+ if (ref) {
104
+ const alvo = this._resolveRef(ref);
105
+ if (alvo) return alvo;
106
+ }
107
+ return c.querySelector("template");
108
+ }
71
109
  get toolbarTemplate() {
72
- return this.querySelector(
73
- 'template[slot="toolbar"]'
74
- );
110
+ const bar = this.querySelector(":scope > fx-toolbar");
111
+ if (bar) return bar;
112
+ const ref = this.getAttr("toolbar");
113
+ if (ref) {
114
+ const alvo = this._resolveRef(ref);
115
+ if (alvo) return alvo;
116
+ }
117
+ return this.querySelector('template[slot="toolbar"]');
118
+ }
119
+ /**
120
+ * Resolve `ref` para um elemento: `#id`/`id` ⇒ `getElementById` no
121
+ * documento; qualquer outro valor é tratado como seletor CSS relativo à
122
+ * própria tabela. Valores inválidos devolvem `null` (sem exceção).
123
+ */
124
+ _resolveRef(ref) {
125
+ const valor = ref.trim();
126
+ if (!valor) return null;
127
+ const doc = this.ownerDocument;
128
+ if (valor.startsWith("#")) return doc?.getElementById(valor.slice(1)) ?? null;
129
+ if (/^[.#[>]/.test(valor)) {
130
+ try {
131
+ return this.querySelector(valor);
132
+ } catch {
133
+ return null;
134
+ }
135
+ }
136
+ return doc?.getElementById(valor) ?? null;
75
137
  }
76
138
  connectedCallback() {
77
139
  this._parseDataAttribute();
140
+ this._parseSortAttributes();
141
+ loadFenixIconsFont();
78
142
  super.connectedCallback();
79
143
  this._columnObserver = new MutationObserver(() => this.render());
80
144
  this._columnObserver.observe(this, { childList: true, subtree: true });
@@ -83,6 +147,13 @@ const _FxTable = class _FxTable extends FxElement {
83
147
  this._columnObserver?.disconnect();
84
148
  super.disconnectedCallback();
85
149
  }
150
+ /** Ordenação inicial via `sort-field` / `sort-order` (documentados na API). */
151
+ _parseSortAttributes() {
152
+ const field = this.getAttr("sort-field");
153
+ if (field) this.sortField = field;
154
+ const order = this.getAttr("sort-order");
155
+ if (order === "asc" || order === "desc") this.sortDir = order === "asc" ? 1 : -1;
156
+ }
86
157
  _parseDataAttribute() {
87
158
  if (!this._data.length) {
88
159
  try {
@@ -166,11 +237,11 @@ const _FxTable = class _FxTable extends FxElement {
166
237
  const pagerHtml = !paginated ? "" : `
167
238
  <div class="pager" part="pager">
168
239
  <span class="info">Página ${this.page + 1} de ${pages} · ${total} registros</span>
169
- <button type="button" class="pg-btn" data-pg="first" ${this.page === 0 ? "disabled" : ""}>«</button>
170
- <button type="button" class="pg-btn" data-pg="prev" ${this.page === 0 ? "disabled" : ""}>‹</button>
240
+ <button type="button" class="pg-btn" part="first" aria-label="Primeira página" data-pg="first" ${this.page === 0 ? "disabled" : ""}>${fenixIconHtml("first_page")}</button>
241
+ <button type="button" class="pg-btn" part="prev" aria-label="Página anterior" data-pg="prev" ${this.page === 0 ? "disabled" : ""}>${fenixIconHtml("navigate_before")}</button>
171
242
  ${Array.from({ length: pages }, (_, p) => `<button type="button" class="pg-btn" data-pg="${p}" aria-current="${p === this.page}">${p + 1}</button>`).join("")}
172
- <button type="button" class="pg-btn" data-pg="next" ${this.page >= pages - 1 ? "disabled" : ""}>›</button>
173
- <button type="button" class="pg-btn" data-pg="last" ${this.page >= pages - 1 ? "disabled" : ""}>»</button>
243
+ <button type="button" class="pg-btn" part="next" aria-label="Próxima página" data-pg="next" ${this.page >= pages - 1 ? "disabled" : ""}>${fenixIconHtml("navigate_next")}</button>
244
+ <button type="button" class="pg-btn" part="last" aria-label="Última página" data-pg="last" ${this.page >= pages - 1 ? "disabled" : ""}>${fenixIconHtml("last_page")}</button>
174
245
  <label class="info">${esc("Por página:")}
175
246
  <fx-select class="rows-sel" size="sm" value="${this.rowsPerPage}" aria-label="Itens por página">${this.getAttr(
176
247
  "rows-options",
@@ -307,6 +378,7 @@ const _FxTable = class _FxTable extends FxElement {
307
378
  }
308
379
  };
309
380
  _FxTable.styles = css`
381
+ ${FENIX_ICON_BASE_CSS}
310
382
  :host {
311
383
  display: block;
312
384
  font-family: var(--fx-font-family);
@@ -383,17 +455,14 @@ _FxTable.styles = css`
383
455
  transition: background-color var(--fx-motion-duration-fast)
384
456
  var(--fx-motion-easing);
385
457
  }
386
- tbody tr:hover {
387
- background: color-mix(
388
- in srgb,
389
- var(--fx-color-primary) 8%,
390
- transparent
391
- );
392
- }
458
+ /* Listrado: alterna a superfície (cinza). Antes usava
459
+ --fx-surface-background, que é a MESMA cor do fundo do :host e
460
+ portanto pintava branco sobre branco (listrado invisível). */
393
461
  :host([striped]) tbody tr:nth-child(even) {
394
- background: var(--fx-surface-background);
462
+ background: var(--fx-surface-surface, #f8fafc);
395
463
  }
396
- :host([striped]) tbody tr:hover {
464
+ /* O hover é opt-in via atributo (o clique na linha continua sempre ativo). */
465
+ :host([hover]) tbody tr:hover {
397
466
  background: color-mix(
398
467
  in srgb,
399
468
  var(--fx-color-primary) 8%,
@@ -423,6 +492,9 @@ _FxTable.styles = css`
423
492
  font-size: calc(var(--fx-font-size) - 2px);
424
493
  }
425
494
  .pg-btn {
495
+ display: inline-flex;
496
+ align-items: center;
497
+ justify-content: center;
426
498
  min-width: var(--fx-size-sm);
427
499
  height: var(--fx-size-sm);
428
500
  font: inherit;
@@ -436,6 +508,12 @@ _FxTable.styles = css`
436
508
  transition: border-color var(--fx-motion-duration-fast)
437
509
  var(--fx-motion-easing);
438
510
  }
511
+ /* O glifo precisa de 1px a mais que o dígito: a altura de traço do ícone é
512
+ maior que a do número, então igualar os dois font-size deixa a seta
513
+ visivelmente maior que o texto. */
514
+ .pg-btn .fx-icon {
515
+ font-size: calc(var(--fx-font-size) - 1px);
516
+ }
439
517
  .pg-btn:hover:not(:disabled):not([aria-current="true"]) {
440
518
  border-color: var(--fx-color-primary);
441
519
  color: var(--fx-color-primary);