@wrrdev/fenix-ui 1.0.14 → 1.0.15

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 (111) hide show
  1. package/README.md +332 -332
  2. package/dist/components/accordion/accordion.d.ts +1 -0
  3. package/dist/components/accordion/accordion.d.ts.map +1 -1
  4. package/dist/components/accordion/accordion.js +18 -13
  5. package/dist/components/accordion/accordion.js.map +1 -1
  6. package/dist/components/accordion/index.js.map +1 -1
  7. package/dist/components/alert/alert.d.ts.map +1 -1
  8. package/dist/components/alert/alert.js +2 -1
  9. package/dist/components/alert/alert.js.map +1 -1
  10. package/dist/components/alert/index.js.map +1 -1
  11. package/dist/components/autocomplete/autocomplete.d.ts +3 -0
  12. package/dist/components/autocomplete/autocomplete.d.ts.map +1 -1
  13. package/dist/components/autocomplete/autocomplete.js +28 -4
  14. package/dist/components/autocomplete/autocomplete.js.map +1 -1
  15. package/dist/components/autocomplete/index.js.map +1 -1
  16. package/dist/components/datepicker/datepicker.d.ts.map +1 -1
  17. package/dist/components/datepicker/datepicker.js +7 -6
  18. package/dist/components/datepicker/datepicker.js.map +1 -1
  19. package/dist/components/dialog/dialog.d.ts +4 -0
  20. package/dist/components/dialog/dialog.d.ts.map +1 -1
  21. package/dist/components/dialog/dialog.js +42 -4
  22. package/dist/components/dialog/dialog.js.map +1 -1
  23. package/dist/components/dialog/index.js.map +1 -1
  24. package/dist/components/drawer/drawer.d.ts +5 -0
  25. package/dist/components/drawer/drawer.d.ts.map +1 -1
  26. package/dist/components/drawer/drawer.js +49 -15
  27. package/dist/components/drawer/drawer.js.map +1 -1
  28. package/dist/components/dropdown/dropdown.d.ts +5 -0
  29. package/dist/components/dropdown/dropdown.d.ts.map +1 -1
  30. package/dist/components/dropdown/dropdown.js +34 -10
  31. package/dist/components/dropdown/dropdown.js.map +1 -1
  32. package/dist/components/input/input.d.ts.map +1 -1
  33. package/dist/components/input/input.js +4 -3
  34. package/dist/components/input/input.js.map +1 -1
  35. package/dist/components/knob/index.js.map +1 -1
  36. package/dist/components/knob/knob.d.ts +2 -0
  37. package/dist/components/knob/knob.d.ts.map +1 -1
  38. package/dist/components/knob/knob.js +15 -3
  39. package/dist/components/knob/knob.js.map +1 -1
  40. package/dist/components/multiselect/multiselect.d.ts +2 -0
  41. package/dist/components/multiselect/multiselect.d.ts.map +1 -1
  42. package/dist/components/multiselect/multiselect.js +38 -8
  43. package/dist/components/multiselect/multiselect.js.map +1 -1
  44. package/dist/components/orderlist/orderlist.d.ts.map +1 -1
  45. package/dist/components/orderlist/orderlist.js +1 -3
  46. package/dist/components/orderlist/orderlist.js.map +1 -1
  47. package/dist/components/pagination/index.js.map +1 -1
  48. package/dist/components/pagination/pagination.d.ts +1 -0
  49. package/dist/components/pagination/pagination.d.ts.map +1 -1
  50. package/dist/components/pagination/pagination.js +19 -8
  51. package/dist/components/pagination/pagination.js.map +1 -1
  52. package/dist/components/picklist/picklist.d.ts.map +1 -1
  53. package/dist/components/picklist/picklist.js +1 -3
  54. package/dist/components/picklist/picklist.js.map +1 -1
  55. package/dist/components/progress/index.js.map +1 -1
  56. package/dist/components/progress/progress.d.ts.map +1 -1
  57. package/dist/components/progress/progress.js +2 -1
  58. package/dist/components/progress/progress.js.map +1 -1
  59. package/dist/components/radio/radio.js +1 -1
  60. package/dist/components/radio/radio.js.map +1 -1
  61. package/dist/components/select/select.d.ts +2 -0
  62. package/dist/components/select/select.d.ts.map +1 -1
  63. package/dist/components/select/select.js +36 -5
  64. package/dist/components/select/select.js.map +1 -1
  65. package/dist/components/skeleton/index.js.map +1 -1
  66. package/dist/components/skeleton/skeleton.d.ts +2 -0
  67. package/dist/components/skeleton/skeleton.d.ts.map +1 -1
  68. package/dist/components/skeleton/skeleton.js +7 -2
  69. package/dist/components/skeleton/skeleton.js.map +1 -1
  70. package/dist/components/table/expr.d.ts +38 -0
  71. package/dist/components/table/expr.d.ts.map +1 -0
  72. package/dist/components/table/expr.js +429 -0
  73. package/dist/components/table/expr.js.map +1 -0
  74. package/dist/components/table/table.d.ts +26 -8
  75. package/dist/components/table/table.d.ts.map +1 -1
  76. package/dist/components/table/table.js +402 -140
  77. package/dist/components/table/table.js.map +1 -1
  78. package/dist/components/tabs/tabs.d.ts.map +1 -1
  79. package/dist/components/tabs/tabs.js +3 -2
  80. package/dist/components/tabs/tabs.js.map +1 -1
  81. package/dist/components/textarea/index.js.map +1 -1
  82. package/dist/components/textarea/textarea.d.ts.map +1 -1
  83. package/dist/components/textarea/textarea.js +4 -3
  84. package/dist/components/textarea/textarea.js.map +1 -1
  85. package/dist/components/toast/index.js.map +1 -1
  86. package/dist/components/tooltip/directive.js.map +1 -1
  87. package/dist/components/tooltip/index.js.map +1 -1
  88. package/dist/components/tooltip/tooltip.d.ts.map +1 -1
  89. package/dist/components/tooltip/tooltip.js +2 -1
  90. package/dist/components/tooltip/tooltip.js.map +1 -1
  91. package/dist/core/jsx.js.map +1 -1
  92. package/dist/core/presets.js.map +1 -1
  93. package/dist/core/sanitize.d.ts +36 -0
  94. package/dist/core/sanitize.d.ts.map +1 -0
  95. package/dist/core/sanitize.js +37 -0
  96. package/dist/core/sanitize.js.map +1 -0
  97. package/dist/core/tokens.js.map +1 -1
  98. package/dist/core/vue.js.map +1 -1
  99. package/dist/docs/app.d.ts.map +1 -1
  100. package/dist/docs/componentes/table.doc.d.ts.map +1 -1
  101. package/dist/fenix-ui.esm.js.map +1 -1
  102. package/dist/fenix-ui.umd.min.js +339 -208
  103. package/dist/fenix-ui2.esm.js +1156 -243
  104. package/dist/fenix-ui2.esm.js.map +1 -1
  105. package/dist/fenix-ui3.esm.js.map +1 -1
  106. package/dist/index.d.ts +2 -1
  107. package/dist/index.d.ts.map +1 -1
  108. package/dist/index.js +4 -0
  109. package/dist/index.js.map +1 -1
  110. package/dist/plugins/auto-import.js.map +1 -1
  111. package/package.json +212 -212
@@ -1 +1 @@
1
- {"version":3,"file":"table.js","sources":["../../../src/components/table/table.ts"],"sourcesContent":["import { FxElement } from '../../core/base';\r\nimport { css } from '../../core/css';\r\nimport { defineElement } from '../../core/define';\r\n\r\n/**\r\n * <fx-table> — Tabela de dados estilo DataTable (dados + colunas configuráveis,\r\n * ordenação, filtros por coluna, paginação personalizável).\r\n *\r\n * Colunas (light DOM):\r\n * <fx-column field=\"nome\" header=\"Nome\" sortable filterable align=\"left\">\r\n * opcional: <template>R$ {{value}}</template> para render customizado\r\n * </fx-column>\r\n *\r\n * Dados: propriedade `data` (array de objetos) ou atributo `data` (JSON).\r\n *\r\n * Atributos: pagination, rows, rows-options, pagination-position (left|center|right),\r\n * striped, empty-message.\r\n * Eventos: page-change, sort-change, row-click (todos composed).\r\n */\r\nexport class FxTable extends FxElement {\r\n static override styles = css`\r\n :host {\r\n display: block;\r\n font-family: var(--fx-font-family);\r\n font-size: var(--fx-font-size);\r\n color: var(--fx-text-default);\r\n }\r\n .scroll { overflow-x: auto; border: 1px solid var(--fx-border-default); border-radius: var(--fx-radius-md); }\r\n table { width: 100%; border-collapse: collapse; }\r\n th {\r\n text-align: left;\r\n padding: var(--fx-space-sm) var(--fx-space-md);\r\n background: var(--fx-surface-background);\r\n border-bottom: 2px solid var(--fx-border-default);\r\n white-space: nowrap;\r\n user-select: none;\r\n }\r\n th.sortable { cursor: pointer; }\r\n th.sortable:hover { color: var(--fx-color-primary); }\r\n .sort-ind { font-size: calc(var(--fx-font-size) - 4px); margin-left: var(--fx-space-3xs, 2px); }\r\n .filter-row th { padding: var(--fx-space-3xs, 4px) var(--fx-space-md) var(--fx-space-sm); border-bottom-width: 1px; }\r\n .filter {\r\n width: 100%;\r\n box-sizing: border-box;\r\n font: inherit;\r\n font-size: calc(var(--fx-font-size) - 2px);\r\n color: var(--fx-text-default);\r\n background: var(--fx-surface-background);\r\n border: 1px solid var(--fx-border-default);\r\n border-radius: var(--fx-radius-sm);\r\n padding: var(--fx-space-3xs, 4px) var(--fx-space-xs);\r\n outline: none;\r\n }\r\n .filter:focus { border-color: var(--fx-color-primary); box-shadow: var(--fx-effect-focus-ring, none); }\r\n td {\r\n padding: var(--fx-space-sm) var(--fx-space-md);\r\n border-bottom: 1px solid var(--fx-border-default);\r\n }\r\n tbody tr { cursor: pointer; transition: background-color var(--fx-motion-duration-fast) var(--fx-motion-easing); }\r\n tbody tr:hover { background: color-mix(in srgb, var(--fx-color-primary) 8%, transparent); }\r\n :host([striped]) tbody tr:nth-child(even) { background: var(--fx-surface-background); }\r\n :host([striped]) tbody tr:hover { background: color-mix(in srgb, var(--fx-color-primary) 8%, transparent); }\r\n .empty { text-align: center; padding: var(--fx-space-xl); color: var(--fx-text-muted); }\r\n .pager {\r\n display: flex;\r\n align-items: center;\r\n gap: var(--fx-space-sm);\r\n flex-wrap: wrap;\r\n padding: var(--fx-space-sm) 0;\r\n }\r\n :host([pagination-position='center']) .pager { justify-content: center; }\r\n :host([pagination-position='right']) .pager { justify-content: flex-end; }\r\n .pager .info { color: var(--fx-text-muted); font-size: calc(var(--fx-font-size) - 2px); }\r\n .pg-btn {\r\n font: inherit;\r\n font-size: calc(var(--fx-font-size) - 2px);\r\n color: var(--fx-text-default);\r\n background: var(--fx-surface-background);\r\n border: 1px solid var(--fx-border-default);\r\n border-radius: var(--fx-radius-sm);\r\n padding: var(--fx-space-3xs, 4px) var(--fx-space-sm);\r\n cursor: pointer;\r\n transition: border-color var(--fx-motion-duration-fast) var(--fx-motion-easing);\r\n }\r\n .pg-btn:hover:not(:disabled) { border-color: var(--fx-color-primary); color: var(--fx-color-primary); }\r\n .pg-btn:disabled { opacity: 0.5; cursor: not-allowed; }\r\n .pg-btn[aria-current='true'] {\r\n background: var(--fx-color-primary);\r\n border-color: var(--fx-color-primary);\r\n color: #fff;\r\n font-weight: var(--fx-font-weight);\r\n }\r\n .rows-sel {\r\n font: inherit;\r\n font-size: calc(var(--fx-font-size) - 2px);\r\n color: var(--fx-text-default);\r\n background: var(--fx-surface-background);\r\n border: 1px solid var(--fx-border-default);\r\n border-radius: var(--fx-radius-sm);\r\n padding: 2px var(--fx-space-xs);\r\n outline: none;\r\n }\r\n `;\r\n\r\n static override get observedAttributes(): string[] {\r\n return ['pagination', 'rows', 'rows-options', 'striped', 'empty-message', 'pagination-position'];\r\n }\r\n\r\n /** Dados da tabela (array de objetos). */\r\n data: Record<string, unknown>[] = [];\r\n private page = 0;\r\n private sortField = '';\r\n private sortDir: 1 | -1 = 1;\r\n private filters: Record<string, string> = {};\r\n\r\n get rowsPerPage(): number {\r\n const r = Number(this.getAttr('rows', '10'));\r\n return r > 0 ? r : 10;\r\n }\r\n set rowsPerPage(value: number) {\r\n this.setAttribute('rows', String(value));\r\n }\r\n\r\n /** Colunas declaradas no light DOM (<fx-column>). */\r\n private get columns(): {\r\n field: string; header: string; sortable: boolean; filterable: boolean;\r\n align: string; template?: HTMLTemplateElement;\r\n }[] {\r\n return [...this.querySelectorAll('fx-column')].map((c) => ({\r\n field: c.getAttribute('field') ?? '',\r\n header: c.getAttribute('header') ?? c.getAttribute('field') ?? '',\r\n sortable: c.hasAttribute('sortable'),\r\n filterable: c.hasAttribute('filterable'),\r\n align: c.getAttribute('align') ?? 'left',\r\n template: c.querySelector('template') ?? undefined,\r\n }));\r\n }\r\n\r\n protected override connectedCallback(): void {\r\n super.connectedCallback();\r\n // Tenta carregar JSON do atributo data se `data` não foi setado via JS.\r\n if (!this.data.length) {\r\n try {\r\n const json = this.getAttr('data');\r\n if (json) this.data = JSON.parse(json);\r\n } catch { /* atributo inválido — ignora */ }\r\n }\r\n // Observa mudanças nas colunas (light DOM).\r\n new MutationObserver(() => this.render()).observe(this, { childList: true, subtree: true });\r\n }\r\n\r\n /** Pipeline: filtra → ordena → pagina. */\r\n private computeRows(): { rows: Record<string, unknown>[]; total: number } {\r\n let out = [...this.data];\r\n for (const [field, term] of Object.entries(this.filters)) {\r\n if (!term) continue;\r\n const t = term.toLowerCase();\r\n out = out.filter((r) => String(r[field] ?? '').toLowerCase().includes(t));\r\n }\r\n const total = out.length;\r\n if (this.sortField) {\r\n out.sort((a, b) => {\r\n const av = a[this.sortField], bv = b[this.sortField];\r\n if (typeof av === 'number' && typeof bv === 'number') return (av - bv) * this.sortDir;\r\n return String(av ?? '').localeCompare(String(bv ?? ''), 'pt-BR') * this.sortDir;\r\n });\r\n }\r\n if (this.hasAttr('pagination')) {\r\n const start = this.page * this.rowsPerPage;\r\n out = out.slice(start, start + this.rowsPerPage);\r\n }\r\n return { rows: out, total };\r\n }\r\n\r\n /** Célula: template customizado ({{value}}, {{campo}}, {{row}}) ou valor direto. */\r\n private cellHtml(col: { field: string; template?: HTMLTemplateElement }, row: Record<string, unknown>): string {\r\n const value = row[col.field];\r\n if (col.template) {\r\n return col.template.innerHTML.replace(/\\{\\{(\\w+)\\}\\}/g, (_, k: string) =>\r\n k === 'value' ? String(value ?? '') : k === 'row' ? '' : String(row[k] ?? ''));\r\n }\r\n return String(value ?? '');\r\n }\r\n\r\n protected override render(): void {\r\n const cols = this.columns.filter((c) => c.field);\r\n const { rows, total } = this.computeRows();\r\n const paginated = this.hasAttr('pagination');\r\n const pages = Math.max(1, Math.ceil(total / this.rowsPerPage));\r\n if (this.page >= pages) this.page = pages - 1;\r\n\r\n const headHtml = cols.map((c) => {\r\n const ind = this.sortField === c.field ? (this.sortDir === 1 ? '▲' : '▼') : '';\r\n return `<th part=\"header\" class=\"${c.sortable ? 'sortable' : ''}\" style=\"text-align:${c.align}\" data-field=\"${c.field}\">${c.header}${ind ? `<span class=\"sort-ind\">${ind}</span>` : ''}</th>`;\r\n }).join('');\r\n\r\n const filterRow = cols.some((c) => c.filterable)\r\n ? `<tr class=\"filter-row\">${cols.map((c) => `<th style=\"text-align:${c.align}\">${c.filterable ? `<input class=\"filter\" data-field=\"${c.field}\" placeholder=\"Filtrar…\" value=\"${this.filters[c.field] ?? ''}\">` : ''}</th>`).join('')}</tr>`\r\n : '';\r\n\r\n const bodyHtml = rows.length\r\n ? rows.map((row, i) => `<tr part=\"row\" data-index=\"${i}\">${cols.map((c) => `<td part=\"cell\" style=\"text-align:${c.align}\">${this.cellHtml(c, row)}</td>`).join('')}</tr>`).join('')\r\n : `<tr><td class=\"empty\" colspan=\"${cols.length || 1}\">${this.getAttr('empty-message', 'Nenhum registro encontrado')}</td></tr>`;\r\n\r\n const pagerHtml = !paginated ? '' : `\r\n <div class=\"pager\" part=\"pager\">\r\n <span class=\"info\">Página ${this.page + 1} de ${pages} · ${total} registros</span>\r\n <button type=\"button\" class=\"pg-btn\" data-pg=\"first\" ${this.page === 0 ? 'disabled' : ''}>«</button>\r\n <button type=\"button\" class=\"pg-btn\" data-pg=\"prev\" ${this.page === 0 ? 'disabled' : ''}>‹</button>\r\n ${Array.from({ length: pages }, (_, p) => `<button type=\"button\" class=\"pg-btn\" data-pg=\"${p}\" aria-current=\"${p === this.page}\">${p + 1}</button>`).join('')}\r\n <button type=\"button\" class=\"pg-btn\" data-pg=\"next\" ${this.page >= pages - 1 ? 'disabled' : ''}>›</button>\r\n <button type=\"button\" class=\"pg-btn\" data-pg=\"last\" ${this.page >= pages - 1 ? 'disabled' : ''}>»</button>\r\n <label class=\"info\">Por página:\r\n <select class=\"rows-sel\">${(this.getAttr('rows-options', '5,10,20,50')).split(',').map((n) => n.trim()).map((n) => `<option value=\"${n}\" ${Number(n) === this.rowsPerPage ? 'selected' : ''}>${n}</option>`).join('')}</select>\r\n </label>\r\n </div>`;\r\n\r\n this.setTemplate(`\r\n <div class=\"scroll\">\r\n <table part=\"table\">\r\n <thead><tr>${headHtml}</tr>${filterRow}</thead>\r\n <tbody>${bodyHtml}</tbody>\r\n </table>\r\n </div>\r\n ${pagerHtml}\r\n `);\r\n\r\n // Ordenação.\r\n this.root.querySelectorAll<HTMLTableCellElement>('th.sortable').forEach((th) => {\r\n th.addEventListener('click', () => {\r\n const f = th.dataset.field!;\r\n if (this.sortField === f) this.sortDir = this.sortDir === 1 ? -1 : 1;\r\n else { this.sortField = f; this.sortDir = 1; }\r\n this.render();\r\n this.dispatchEvent(new CustomEvent('sort-change', { bubbles: true, composed: true,\r\n detail: { field: this.sortField, direction: this.sortDir === 1 ? 'asc' : 'desc' } }));\r\n });\r\n });\r\n\r\n // Filtros (preserva foco/caret ao digitar).\r\n this.root.querySelectorAll<HTMLInputElement>('.filter').forEach((inp) => {\r\n inp.addEventListener('input', () => {\r\n this.filters[inp.dataset.field!] = inp.value;\r\n this.page = 0;\r\n const field = inp.dataset.field!;\r\n const pos = inp.selectionStart;\r\n this.render();\r\n const again = this.root.querySelector<HTMLInputElement>(`.filter[data-field=\"${field}\"]`);\r\n if (again) { again.focus(); again.setSelectionRange(pos, pos); }\r\n });\r\n inp.addEventListener('click', (e) => e.stopPropagation());\r\n });\r\n\r\n // Paginação.\r\n this.root.querySelectorAll<HTMLButtonElement>('.pg-btn').forEach((btn) => {\r\n btn.addEventListener('click', () => {\r\n const pg = btn.dataset.pg!;\r\n this.page = pg === 'first' ? 0 : pg === 'prev' ? Math.max(0, this.page - 1)\r\n : pg === 'next' ? Math.min(pages - 1, this.page + 1)\r\n : pg === 'last' ? pages - 1 : Number(pg);\r\n this.render();\r\n this.dispatchEvent(new CustomEvent('page-change', { bubbles: true, composed: true,\r\n detail: { page: this.page + 1, pages, rowsPerPage: this.rowsPerPage, total } }));\r\n });\r\n });\r\n this.root.querySelector<HTMLSelectElement>('.rows-sel')?.addEventListener('change', (e) => {\r\n this.rowsPerPage = Number((e.target as HTMLSelectElement).value);\r\n this.page = 0;\r\n this.render();\r\n });\r\n\r\n // Clique na linha.\r\n this.root.querySelectorAll<HTMLTableRowElement>('tbody tr[data-index]').forEach((tr) => {\r\n tr.addEventListener('click', () => {\r\n this.dispatchEvent(new CustomEvent('row-click', { bubbles: true, composed: true,\r\n detail: { row: rows[Number(tr.dataset.index)], index: Number(tr.dataset.index) } }));\r\n });\r\n });\r\n }\r\n}\r\n\r\nexport function defineFxTable(): typeof FxTable {\r\n return defineElement('fx-table', FxTable);\r\n}\r\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"table.js","sources":["../../../src/components/table/table.ts"],"sourcesContent":["import { FxElement } from '../../core/base';\nimport { css } from '../../core/css';\nimport { defineElement } from '../../core/define';\nimport { esc } from \"../../core/sanitize\";\nimport { renderCell } from \"./expr\";\nimport \"../select\";\n\n/**\n * <fx-table> — Tabela de dados estilo DataTable (dados + colunas configuráveis,\n * ordenação, filtros por coluna, paginação personalizável, busca global na toolbar\n * e modo lazy para busca no servidor).\n *\n * Colunas (light DOM):\n * <fx-column field=\"nome\" header=\"Nome\" sortable filterable align=\"left\">\n * opcional: <template>R$ {{value}}</template> para render customizado\n * ou conteúdo direto (HTML + {{ }}) como template alternativo\n * </fx-column>\n *\n * Toolbar (opcional):\n * <template slot=\"toolbar\">\n * <input data-search-fields=\"nome,cargo\" placeholder=\"Buscar…\">\n * <button>Nova ação</button>\n * </template>\n *\n * Dados: propriedade `data` (array de objetos) ou atributo `data` (JSON).\n *\n * Atributos: pagination, rows, rows-options, pagination-position (left|center|right),\n * striped, empty-message, lazy, total, loading, loading-message.\n * Eventos: page-change, sort-change, row-click, filter-change (todos composed).\n */\nexport class FxTable extends FxElement {\n\tstatic override styles = css`\n\t\t:host {\n\t\t\tdisplay: block;\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\tbackground: var(--fx-surface-background);\n\t\t}\n\t\t.table-wrap {\n\t\t\tposition: relative;\n\t\t}\n\t\t.scroll {\n\t\t\toverflow-x: auto;\n\t\t\tborder: 1px solid var(--fx-border-default);\n\t\t\tborder-radius: var(--fx-radius-md);\n\t\t}\n\t\ttable {\n\t\t\twidth: 100%;\n\t\t\tborder-collapse: collapse;\n\t\t}\n\t\tth {\n\t\t\ttext-align: left;\n\t\t\tpadding: var(--fx-space-sm) var(--fx-space-md);\n\t\t\tbackground: var(--fx-surface-surface);\n\t\t\tborder-bottom: 2px solid var(--fx-border-default);\n\t\t\twhite-space: nowrap;\n\t\t\tuser-select: none;\n\t\t}\n\t\tth.sortable {\n\t\t\tcursor: pointer;\n\t\t}\n\t\tth.sortable:hover {\n\t\t\tcolor: var(--fx-color-primary);\n\t\t}\n\t\t.sort-ind {\n\t\t\tfont-size: calc(var(--fx-font-size) - 4px);\n\t\t\tmargin-left: var(--fx-space-3xs, 2px);\n\t\t\topacity: 0.45;\n\t\t\ttransition: opacity var(--fx-motion-duration-fast)\n\t\t\t\tvar(--fx-motion-easing);\n\t\t}\n\t\tth.sortable:hover .sort-ind {\n\t\t\topacity: 0.85;\n\t\t}\n\t\t.sort-ind.active {\n\t\t\topacity: 1;\n\t\t\tcolor: var(--fx-color-primary);\n\t\t}\n\t\t.filter-row th {\n\t\t\tpadding: var(--fx-space-3xs, 4px) var(--fx-space-md) var(--fx-space-sm);\n\t\t\tborder-bottom-width: 1px;\n\t\t}\n\t\t.filter {\n\t\t\twidth: 100%;\n\t\t\tbox-sizing: border-box;\n\t\t\tfont: inherit;\n\t\t\tfont-size: calc(var(--fx-font-size) - 2px);\n\t\t\tcolor: var(--fx-text-default);\n\t\t\tbackground: var(--fx-surface-background);\n\t\t\tborder: 1px solid var(--fx-border-default);\n\t\t\tborder-radius: var(--fx-radius-sm);\n\t\t\tpadding: var(--fx-space-3xs, 4px) var(--fx-space-xs);\n\t\t\toutline: none;\n\t\t}\n\t\t.filter:focus {\n\t\t\tborder-color: var(--fx-color-primary);\n\t\t\tbox-shadow: var(--fx-effect-focus-ring, none);\n\t\t}\n\t\ttd {\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}\n\t\ttbody tr {\n\t\t\tcursor: pointer;\n\t\t\ttransition: background-color var(--fx-motion-duration-fast)\n\t\t\t\tvar(--fx-motion-easing);\n\t\t}\n\t\ttbody tr:hover {\n\t\t\tbackground: color-mix(\n\t\t\t\tin srgb,\n\t\t\t\tvar(--fx-color-primary) 8%,\n\t\t\t\ttransparent\n\t\t\t);\n\t\t}\n\t\t:host([striped]) tbody tr:nth-child(even) {\n\t\t\tbackground: var(--fx-surface-background);\n\t\t}\n\t\t:host([striped]) tbody tr:hover {\n\t\t\tbackground: color-mix(\n\t\t\t\tin srgb,\n\t\t\t\tvar(--fx-color-primary) 8%,\n\t\t\t\ttransparent\n\t\t\t);\n\t\t}\n\t\t.empty {\n\t\t\ttext-align: center;\n\t\t\tpadding: var(--fx-space-xl);\n\t\t\tcolor: var(--fx-text-muted);\n\t\t}\n\t\t.pager {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tgap: var(--fx-space-sm);\n\t\t\tflex-wrap: wrap;\n\t\t\tpadding: var(--fx-space-sm) 0;\n\t\t}\n\t\t:host([pagination-position=\"center\"]) .pager {\n\t\t\tjustify-content: center;\n\t\t}\n\t\t:host([pagination-position=\"right\"]) .pager {\n\t\t\tjustify-content: flex-end;\n\t\t}\n\t\t.pager .info {\n\t\t\tcolor: var(--fx-text-muted);\n\t\t\tfont-size: calc(var(--fx-font-size) - 2px);\n\t\t}\n\t\t.pg-btn {\n\t\t\tmin-width: var(--fx-size-sm);\n\t\t\theight: var(--fx-size-sm);\n\t\t\tfont: inherit;\n\t\t\tfont-size: calc(var(--fx-font-size) - 2px);\n\t\t\tcolor: var(--fx-text-default);\n\t\t\tbackground: var(--fx-surface-background);\n\t\t\tborder: 1px solid var(--fx-border-default);\n\t\t\tborder-radius: var(--fx-radius-sm);\n\t\t\tpadding: var(--fx-space-3xs, 4px) var(--fx-space-sm);\n\t\t\tcursor: pointer;\n\t\t\ttransition: border-color var(--fx-motion-duration-fast)\n\t\t\t\tvar(--fx-motion-easing);\n\t\t}\n\t\t.pg-btn:hover:not(:disabled):not([aria-current=\"true\"]) {\n\t\t\tborder-color: var(--fx-color-primary);\n\t\t\tcolor: var(--fx-color-primary);\n\t\t}\n\t\t.pg-btn:disabled {\n\t\t\topacity: 0.5;\n\t\t\tcursor: not-allowed;\n\t\t}\n\t\t.pg-btn[aria-current=\"true\"] {\n\t\t\tbackground: var(--fx-color-primary);\n\t\t\tborder-color: var(--fx-color-primary);\n\t\t\tcolor: #fff;\n\t\t\tfont-weight: var(--fx-font-weight);\n\t\t}\n\t\tfx-select {\n\t\t\tvertical-align: middle;\n\t\t}\n\t\tfx-select::part(trigger) {\n\t\t\tmin-width: 64px !important;\n\t\t\tmin-height: var(--fx-size-sm) !important;\n\t\t\tpadding: 0 var(--fx-space-sm) !important;\n\t\t\tborder-radius: var(--fx-radius-sm) !important;\n\t\t\tfont-size: calc(var(--fx-font-size) - 2px) !important;\n\t\t}\n\t\t.toolbar {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tgap: var(--fx-space-sm);\n\t\t\tflex-wrap: wrap;\n\t\t\tpadding: var(--fx-space-sm) var(--fx-space-md);\n\t\t\tborder: 1px solid var(--fx-border-default);\n\t\t\tborder-bottom: none;\n\t\t\tborder-radius: var(--fx-radius-md) var(--fx-radius-md) 0 0;\n\t\t\tbackground: var(--fx-surface-background);\n\t\t}\n\t\t.toolbar:empty {\n\t\t\tdisplay: none;\n\t\t}\n\t\t.loading-overlay {\n\t\t\tposition: absolute;\n\t\t\tinset: 0;\n\t\t\tdisplay: flex;\n\t\t\tflex-direction: column;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\tgap: var(--fx-space-sm);\n\t\t\tbackground: color-mix(\n\t\t\t\tin srgb,\n\t\t\t\tvar(--fx-surface-background) 85%,\n\t\t\t\ttransparent\n\t\t\t);\n\t\t\tbackdrop-filter: blur(2px);\n\t\t\tz-index: 10;\n\t\t\tborder-radius: var(--fx-radius-md);\n\t\t}\n\t\t.tbl-spinner {\n\t\t\twidth: 32px;\n\t\t\theight: 32px;\n\t\t\tborder: 3px solid var(--fx-border-default);\n\t\t\tborder-top-color: var(--fx-color-primary);\n\t\t\tborder-radius: 50%;\n\t\t\tanimation: tbl-spin 1s linear infinite;\n\t\t}\n\t\t@keyframes tbl-spin {\n\t\t\tto {\n\t\t\t\ttransform: rotate(360deg);\n\t\t\t}\n\t\t}\n\t\t.loading-text {\n\t\t\tcolor: var(--fx-text-muted);\n\t\t\tfont-size: calc(var(--fx-font-size) - 1px);\n\t\t}\n\t`;\n\n\tstatic override get observedAttributes(): string[] {\n\t\treturn [\n\t\t\t\"pagination\",\n\t\t\t\"rows\",\n\t\t\t\"rows-options\",\n\t\t\t\"striped\",\n\t\t\t\"empty-message\",\n\t\t\t\"pagination-position\",\n\t\t\t\"lazy\",\n\t\t\t\"total\",\n\t\t\t\"loading\",\n\t\t\t\"loading-message\",\n\t\t];\n\t}\n\n\tprivate _data: Record<string, unknown>[] = [];\n\tprivate _total?: number;\n\tprivate page = 0;\n\tprivate sortField = \"\";\n\tprivate sortDir: 1 | -1 = 1;\n\tprivate filters: Record<string, string> = {};\n\tprivate globalSearch = \"\";\n\tprivate _columnObserver?: MutationObserver;\n\n\tget data(): Record<string, unknown>[] {\n\t\treturn this._data;\n\t}\n\tset data(value: Record<string, unknown>[]) {\n\t\tthis._data = Array.isArray(value) ? value : [];\n\t\tthis.render();\n\t}\n\n\tget total(): number {\n\t\treturn this._total ?? this._data.length;\n\t}\n\tset total(value: number) {\n\t\tthis._total = value;\n\t\tthis.setAttribute(\"total\", String(value));\n\t}\n\n\tget rowsPerPage(): number {\n\t\tconst r = Number(this.getAttr(\"rows\", \"10\"));\n\t\treturn r > 0 ? r : 10;\n\t}\n\tset rowsPerPage(value: number) {\n\t\tthis.setAttribute(\"rows\", String(value));\n\t}\n\n\tget lazy(): boolean {\n\t\treturn this.hasAttr(\"lazy\");\n\t}\n\n\tprivate get columns(): {\n\t\tfield: string;\n\t\theader: string;\n\t\tsortable: boolean;\n\t\tfilterable: boolean;\n\t\talign: string;\n\t\ttemplate?: HTMLTemplateElement;\n\t\tdirectTemplate?: string;\n\t}[] {\n\t\treturn [...this.querySelectorAll(\"fx-column\")].map((c) => {\n\t\t\tconst tpl = c.querySelector(\"template\");\n\t\t\tconst direct = tpl ? undefined : c.innerHTML.trim();\n\t\t\tconst align = c.getAttribute(\"align\") ?? \"left\";\n\t\t\treturn {\n\t\t\t\tfield: c.getAttribute(\"field\") ?? \"\",\n\t\t\t\theader: c.getAttribute(\"header\") ?? c.getAttribute(\"field\") ?? \"\",\n\t\t\t\tsortable: c.hasAttribute(\"sortable\"),\n\t\t\t\tfilterable: c.hasAttribute(\"filterable\"),\n\t\t\t\talign: [\"left\", \"center\", \"right\", \"justify\", \"start\", \"end\"].includes(align) ? align : \"left\",\n\t\t\t\ttemplate: tpl ?? undefined,\n\t\t\t\tdirectTemplate: direct || undefined,\n\t\t\t};\n\t\t});\n\t}\n\n\tprivate get toolbarTemplate(): HTMLTemplateElement | null {\n\t\treturn this.querySelector(\n\t\t\t'template[slot=\"toolbar\"]',\n\t\t) as HTMLTemplateElement | null;\n\t}\n\n\tprotected override connectedCallback(): void {\n\t\tthis._parseDataAttribute();\n\t\tsuper.connectedCallback();\n\t\tthis._columnObserver = new MutationObserver(() => this.render());\n\t\tthis._columnObserver.observe(this, { childList: true, subtree: true });\n\t}\n\n\tprotected override disconnectedCallback(): void {\n\t\tthis._columnObserver?.disconnect();\n\t\tsuper.disconnectedCallback();\n\t}\n\n\tprivate _parseDataAttribute(): void {\n\t\tif (!this._data.length) {\n\t\t\ttry {\n\t\t\t\tconst json = this.getAttr(\"data\");\n\t\t\t\tif (json) this._data = JSON.parse(json);\n\t\t\t} catch {\n\t\t\t\t/* atributo invalido - ignora */\n\t\t\t}\n\t\t}\n\t\tconst totalAttr = this.getAttr(\"total\");\n\t\tif (totalAttr) {\n\t\t\tconst n = Number(totalAttr);\n\t\t\tif (!isNaN(n)) this._total = n;\n\t\t}\n\t}\n\n\tprivate computeRows(): { rows: Record<string, unknown>[]; total: number } {\n\t\tlet out = [...this._data];\n\n\t\tfor (const [field, term] of Object.entries(this.filters)) {\n\t\t\tif (!term) continue;\n\t\t\tconst t = term.toLowerCase();\n\t\t\tout = out.filter((r) =>\n\t\t\t\tString(r[field] ?? \"\")\n\t\t\t\t\t.toLowerCase()\n\t\t\t\t\t.includes(t),\n\t\t\t);\n\t\t}\n\n\t\tif (this.globalSearch) {\n\t\t\tconst t = this.globalSearch.toLowerCase();\n\t\t\tconst searchFields = this._getSearchFields();\n\t\t\tout = out.filter((r) => {\n\t\t\t\tconst fields = searchFields.length ? searchFields : Object.keys(r);\n\t\t\t\treturn fields.some((f) =>\n\t\t\t\t\tString(r[f] ?? \"\")\n\t\t\t\t\t\t.toLowerCase()\n\t\t\t\t\t\t.includes(t),\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\n\t\tconst total = this.lazy ? this.total : out.length;\n\n\t\tif (this.sortField) {\n\t\t\tout.sort((a, b) => {\n\t\t\t\tconst av = a[this.sortField],\n\t\t\t\t\tbv = b[this.sortField];\n\t\t\t\tif (typeof av === \"number\" && typeof bv === \"number\")\n\t\t\t\t\treturn (av - bv) * this.sortDir;\n\t\t\t\treturn (\n\t\t\t\t\tString(av ?? \"\").localeCompare(String(bv ?? \"\"), \"pt-BR\") *\n\t\t\t\t\tthis.sortDir\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\n\t\tif (this.hasAttr(\"pagination\") && !this.lazy) {\n\t\t\tconst start = this.page * this.rowsPerPage;\n\t\t\tout = out.slice(start, start + this.rowsPerPage);\n\t\t}\n\n\t\treturn { rows: out, total };\n\t}\n\n\tprivate _getSearchFields(): string[] {\n\t\tconst input = this.root.querySelector<HTMLInputElement>(\n\t\t\t\"[data-search-fields]\",\n\t\t);\n\t\tif (!input) return [];\n\t\tconst attr = input.getAttribute(\"data-search-fields\");\n\t\tif (attr === null) return [];\n\t\treturn attr\n\t\t\t.split(\",\")\n\t\t\t.map((s) => s.trim())\n\t\t\t.filter(Boolean);\n\t}\n\n\tprivate cellHtml(\n\t\tcol: {\n\t\t\tfield: string;\n\t\t\ttemplate?: HTMLTemplateElement;\n\t\t\tdirectTemplate?: string;\n\t\t},\n\t\trow: Record<string, unknown>,\n\t): string {\n\t\tconst template = col.template?.innerHTML ?? col.directTemplate;\n\t\tif (template) return renderCell(template, row, col.field);\n\t\treturn esc(String(row[col.field] ?? \"\"));\n\t}\n\n\tprotected override render(): void {\n\t\tconst cols = this.columns.filter((c) => c.field);\n\t\tconst { rows, total } = this.computeRows();\n\t\tconst paginated = this.hasAttr(\"pagination\");\n\t\tconst pages = Math.max(1, Math.ceil(total / this.rowsPerPage));\n\t\tif (this.page >= pages) this.page = pages - 1;\n\n\t\tconst toolbar = this.toolbarTemplate;\n\t\tconst toolbarHtml = toolbar\n\t\t\t? `<div class=\"toolbar\" part=\"toolbar\">${toolbar.innerHTML}</div>`\n\t\t\t: \"\";\n\n\t\tconst headHtml = cols\n\t\t\t.map((c) => {\n\t\t\t\tconst isSorted = this.sortField === c.field;\n\t\t\t\tconst ind = isSorted\n\t\t\t\t\t? this.sortDir === 1\n\t\t\t\t\t\t? \"▲\"\n\t\t\t\t\t\t: \"▼\"\n\t\t\t\t\t: c.sortable\n\t\t\t\t\t\t? \"⇅\"\n\t\t\t\t\t\t: \"\";\n\t\t\t\tconst activeClass = isSorted ? \"active\" : \"\";\n\t\t\t\treturn `<th part=\"header\" class=\"${c.sortable ? \"sortable\" : \"\"}\" style=\"text-align:${c.align}\" data-field=\"${esc(c.field)}\">${esc(c.header)}${ind ? `<span class=\"sort-ind ${activeClass}\">${ind}</span>` : \"\"}</th>`;\n\t\t\t})\n\t\t\t.join(\"\");\n\n\t\tconst filterRow = cols.some((c) => c.filterable)\n\t\t\t? `<tr class=\"filter-row\">${cols.map((c) => `<th style=\"text-align:${c.align}\">${c.filterable ? `<input class=\"filter\" data-field=\"${esc(c.field)}\" placeholder=\"${esc(\"Filtrar…\")}\" value=\"${esc(this.filters[c.field] ?? \"\")}\">` : \"\"}</th>`).join(\"\")}</tr>`\n\t\t\t: \"\";\n\n\t\tconst bodyHtml = rows.length\n\t\t\t? rows\n\t\t\t\t\t.map(\n\t\t\t\t\t\t(row, i) =>\n\t\t\t\t\t\t\t`<tr part=\"row\" data-index=\"${i}\">${cols.map((c) => `<td part=\"cell\" style=\"text-align:${c.align}\">${this.cellHtml(c, row)}</td>`).join(\"\")}</tr>`,\n\t\t\t\t\t)\n\t\t\t\t\t.join(\"\")\n\t\t\t: `<tr><td class=\"empty\" colspan=\"${cols.length || 1}\">${esc(this.getAttr(\"empty-message\", \"Nenhum registro encontrado\"))}</td></tr>`;\n\n\t\tconst pagerHtml = !paginated\n\t\t\t? \"\"\n\t\t\t: `\n <div class=\"pager\" part=\"pager\">\n <span class=\"info\">Página ${this.page + 1} de ${pages} · ${total} registros</span>\n <button type=\"button\" class=\"pg-btn\" data-pg=\"first\" ${this.page === 0 ? \"disabled\" : \"\"}>«</button>\n <button type=\"button\" class=\"pg-btn\" data-pg=\"prev\" ${this.page === 0 ? \"disabled\" : \"\"}>‹</button>\n ${Array.from({ length: pages }, (_, p) => `<button type=\"button\" class=\"pg-btn\" data-pg=\"${p}\" aria-current=\"${p === this.page}\">${p + 1}</button>`).join(\"\")}\n <button type=\"button\" class=\"pg-btn\" data-pg=\"next\" ${this.page >= pages - 1 ? \"disabled\" : \"\"}>›</button>\n <button type=\"button\" class=\"pg-btn\" data-pg=\"last\" ${this.page >= pages - 1 ? \"disabled\" : \"\"}>»</button>\n <label class=\"info\">${esc(\"Por página:\")}\n <fx-select class=\"rows-sel\" size=\"sm\" value=\"${this.rowsPerPage}\" aria-label=\"Itens por página\">${this.getAttr(\n\t\t\t\t\t\"rows-options\",\n\t\t\t\t\t\"5,10,20,50\",\n\t\t\t\t)\n\t\t\t\t\t.split(\",\")\n\t\t\t\t\t.map((n) => n.trim())\n\t\t\t\t\t.map((n) => `<option value=\"${esc(n)}\">${esc(n)}</option>`)\n\t\t\t\t\t.join(\"\")}</fx-select>\n </label>\n </div>`;\n\n\t\tconst loading = this.hasAttr(\"loading\");\n\t\tconst loadingHtml = loading\n\t\t\t? `<div class=\"loading-overlay\" part=\"loading-overlay\"><div class=\"tbl-spinner\" part=\"spinner\"></div><span class=\"loading-text\">${esc(this.getAttr(\"loading-message\", \"Carregando…\"))}</span></div>`\n\t\t\t: \"\";\n\n\t\tthis.setTemplate(`\n ${toolbarHtml}\n <div class=\"table-wrap\">\n <div class=\"scroll\">\n <table part=\"table\">\n <thead><tr>${headHtml}</tr>${filterRow}</thead>\n <tbody>${bodyHtml}</tbody>\n </table>\n </div>\n ${loadingHtml}\n </div>\n ${pagerHtml}\n `);\n\n\t\t// Ordenação.\n\t\tthis.root\n\t\t\t.querySelectorAll<HTMLTableCellElement>(\"th.sortable\")\n\t\t\t.forEach((th) => {\n\t\t\t\tth.addEventListener(\"click\", () => {\n\t\t\t\t\tconst f = th.dataset.field!;\n\t\t\t\t\tif (this.sortField === f)\n\t\t\t\t\t\tthis.sortDir = this.sortDir === 1 ? -1 : 1;\n\t\t\t\t\telse {\n\t\t\t\t\t\tthis.sortField = f;\n\t\t\t\t\t\tthis.sortDir = 1;\n\t\t\t\t\t}\n\t\t\t\t\tthis.render();\n\t\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\t\tnew CustomEvent(\"sort-change\", {\n\t\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\t\tcomposed: true,\n\t\t\t\t\t\t\tdetail: {\n\t\t\t\t\t\t\t\tfield: this.sortField,\n\t\t\t\t\t\t\t\tdirection: this.sortDir === 1 ? \"asc\" : \"desc\",\n\t\t\t\t\t\t\t\tlazy: this.lazy,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t});\n\n\t\t// Filtros (preserva foco/caret ao digitar).\n\t\tthis.root.querySelectorAll<HTMLInputElement>(\".filter\").forEach((inp) => {\n\t\t\tinp.addEventListener(\"input\", () => {\n\t\t\t\tconst field = inp.dataset.field!;\n\t\t\t\tconst value = inp.value;\n\t\t\t\tconst pos = inp.selectionStart;\n\t\t\t\tthis.filters[field] = value;\n\t\t\t\tthis.page = 0;\n\t\t\t\tthis.render();\n\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\tnew CustomEvent(\"filter-change\", {\n\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\tcomposed: true,\n\t\t\t\t\t\tdetail: { field, value, lazy: this.lazy },\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tconst again = this.root.querySelector<HTMLInputElement>(\n\t\t\t\t\t`.filter[data-field=\"${esc(field)}\"]`,\n\t\t\t\t);\n\t\t\t\tif (again) {\n\t\t\t\t\tagain.focus();\n\t\t\t\t\tagain.setSelectionRange(pos, pos);\n\t\t\t\t}\n\t\t\t});\n\t\t\tinp.addEventListener(\"click\", (e) => e.stopPropagation());\n\t\t});\n\n\t\t// Busca global da toolbar.\n\t\tthis.root\n\t\t\t.querySelectorAll<HTMLInputElement>(\"[data-search-fields]\")\n\t\t\t.forEach((inp) => {\n\t\t\t\tinp.addEventListener(\"input\", () => {\n\t\t\t\t\tthis.globalSearch = inp.value;\n\t\t\t\t\tthis.page = 0;\n\t\t\t\t\tconst pos = inp.selectionStart;\n\t\t\t\t\tthis.render();\n\t\t\t\t\tconst again = this.root.querySelector<HTMLInputElement>(\n\t\t\t\t\t\t\"[data-search-fields]\",\n\t\t\t\t\t);\n\t\t\t\t\tif (again) {\n\t\t\t\t\t\tagain.focus();\n\t\t\t\t\t\tagain.setSelectionRange(pos, pos);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t});\n\n\t\t// Paginação.\n\t\tthis.root\n\t\t\t.querySelectorAll<HTMLButtonElement>(\".pg-btn\")\n\t\t\t.forEach((btn) => {\n\t\t\t\tbtn.addEventListener(\"click\", () => {\n\t\t\t\t\tconst pg = btn.dataset.pg!;\n\t\t\t\t\tthis.page =\n\t\t\t\t\t\tpg === \"first\"\n\t\t\t\t\t\t\t? 0\n\t\t\t\t\t\t\t: pg === \"prev\"\n\t\t\t\t\t\t\t\t? Math.max(0, this.page - 1)\n\t\t\t\t\t\t\t\t: pg === \"next\"\n\t\t\t\t\t\t\t\t\t? Math.min(pages - 1, this.page + 1)\n\t\t\t\t\t\t\t\t\t: pg === \"last\"\n\t\t\t\t\t\t\t\t\t\t? pages - 1\n\t\t\t\t\t\t\t\t\t\t: Number(pg);\n\t\t\t\t\tthis.render();\n\t\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\t\tnew CustomEvent(\"page-change\", {\n\t\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\t\tcomposed: true,\n\t\t\t\t\t\t\tdetail: {\n\t\t\t\t\t\t\t\tpage: this.page + 1,\n\t\t\t\t\t\t\t\tpages,\n\t\t\t\t\t\t\t\trowsPerPage: this.rowsPerPage,\n\t\t\t\t\t\t\t\ttotal,\n\t\t\t\t\t\t\t\tlazy: this.lazy,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t});\n\t\tthis.root\n\t\t\t.querySelector<HTMLElement>(\"fx-select.rows-sel\")\n\t\t\t?.addEventListener(\"change\", (e) => {\n\t\t\t\tconst value = Number((e as CustomEvent).detail?.value);\n\t\t\t\tif (!value || value === this.rowsPerPage) return;\n\t\t\t\tthis.rowsPerPage = value;\n\t\t\t\tthis.page = 0;\n\t\t\t\tthis.render();\n\t\t\t});\n\n\t\t// Clique na linha.\n\t\tthis.root\n\t\t\t.querySelectorAll<HTMLTableRowElement>(\"tbody tr[data-index]\")\n\t\t\t.forEach((tr) => {\n\t\t\t\ttr.addEventListener(\"click\", () => {\n\t\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\t\tnew CustomEvent(\"row-click\", {\n\t\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\t\tcomposed: true,\n\t\t\t\t\t\t\tdetail: {\n\t\t\t\t\t\t\t\trow: rows[Number(tr.dataset.index)],\n\t\t\t\t\t\t\t\tindex: Number(tr.dataset.index),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t});\n\n\t\tthis._restoreToolbarSearch();\n\t}\n\n\tprivate _restoreToolbarSearch(): void {\n\t\tconst input = this.root.querySelector<HTMLInputElement>(\n\t\t\t\"[data-search-fields]\",\n\t\t);\n\t\tif (input && this.globalSearch) input.value = this.globalSearch;\n\t}\n}\n\nexport function defineFxTable(): typeof FxTable {\n return defineElement('fx-table', FxTable);\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"tabs.d.ts","sourceRoot":"","sources":["../../../src/components/tabs/tabs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C;;;;;;;;;;;;GAYG;AACH,qBAAa,MAAO,SAAQ,SAAS;IACnC,OAAgB,MAAM,SAmDpB;IAEF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAEjD;IAED,IAAI,KAAK,IAAI,MAAM,CAAkC;IACrD,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAAwC;cAE5C,MAAM,IAAI,IAAI;IAwCjC,2EAA2E;IAC3E,OAAO,KAAK,MAAM,GAWjB;CACF;AAED;;GAEG;AACH,qBAAa,UAAW,SAAQ,SAAS;IACvC,OAAgB,MAAM,SAGpB;IAEF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAEjD;IAED,IAAI,GAAG,IAAI,MAAM,CAAgC;IACjD;;+CAE2C;IAC3C,IAAI,GAAG,CAAC,KAAK,EAAE,MAAM,EAAsC;IAE3D,IAAI,OAAO,IAAI,OAAO,CAAoC;IAC1D,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAAwC;cAE/C,MAAM,IAAI,IAAI;IAqBjC,OAAO,CAAC,YAAY,CAAS;CAC9B;AAED,wBAAgB,YAAY,IAAI,OAAO,MAAM,CAE5C;AACD,wBAAgB,gBAAgB,IAAI,OAAO,UAAU,CAEpD"}
1
+ {"version":3,"file":"tabs.d.ts","sourceRoot":"","sources":["../../../src/components/tabs/tabs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAK5C;;;;;;;;;;;;GAYG;AACH,qBAAa,MAAO,SAAQ,SAAS;IACnC,OAAgB,MAAM,SAmDpB;IAEF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAEjD;IAED,IAAI,KAAK,IAAI,MAAM,CAAkC;IACrD,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAAwC;cAE5C,MAAM,IAAI,IAAI;IAwCjC,2EAA2E;IAC3E,OAAO,KAAK,MAAM,GAWjB;CACF;AAED;;GAEG;AACH,qBAAa,UAAW,SAAQ,SAAS;IACvC,OAAgB,MAAM,SAGpB;IAEF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAEjD;IAED,IAAI,GAAG,IAAI,MAAM,CAAgC;IACjD;;+CAE2C;IAC3C,IAAI,GAAG,CAAC,KAAK,EAAE,MAAM,EAAsC;IAE3D,IAAI,OAAO,IAAI,OAAO,CAAoC;IAC1D,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAAwC;cAE/C,MAAM,IAAI,IAAI;IAqBjC,OAAO,CAAC,YAAY,CAAS;CAC9B;AAED,wBAAgB,YAAY,IAAI,OAAO,MAAM,CAE5C;AACD,wBAAgB,gBAAgB,IAAI,OAAO,UAAU,CAEpD"}
@@ -1,6 +1,7 @@
1
1
  import { FxElement } from "../../core/base.js";
2
2
  import { css } from "../../core/css.js";
3
3
  import { defineElement } from "../../core/define.js";
4
+ import { esc } from "../../core/sanitize.js";
4
5
  const _FxTabs = class _FxTabs extends FxElement {
5
6
  static get observedAttributes() {
6
7
  return ["value"];
@@ -20,8 +21,8 @@ const _FxTabs = class _FxTabs extends FxElement {
20
21
  const tabId = t.getAttribute("tab") ?? "";
21
22
  const disabled = t.hasAttribute("disabled");
22
23
  return `<button type="button" class="tab" role="tab" part="tab"
23
- data-tab="${tabId}" aria-selected="${tabId === active}"
24
- ${disabled ? 'aria-disabled="true" data-disabled="true"' : ""}>${t.textContent?.trim()}</button>`;
24
+ data-tab="${esc(tabId)}" aria-selected="${tabId === active}"
25
+ ${disabled ? 'aria-disabled="true" data-disabled="true"' : ""}>${esc(t.textContent?.trim() ?? "")}</button>`;
25
26
  }).join("")}
26
27
  </div>
27
28
  <slot></slot>
@@ -1 +1 @@
1
- {"version":3,"file":"tabs.js","sources":["../../../src/components/tabs/tabs.ts"],"sourcesContent":["import { FxElement } from '../../core/base';\nimport { css } from '../../core/css';\nimport { defineElement } from '../../core/define';\n\n/**\n * <fx-tabs> — Navegação por abas.\n *\n * Atributos: value (aba ativa, corresponde ao attr `tab` de cada fx-tab-panel).\n * Uso:\n * <fx-tabs value=\"a\">\n * <fx-tab tab=\"a\">Aba A</fx-tab>\n * <fx-tab tab=\"b\">Aba B</fx-tab>\n * </fx-tabs>\n * <fx-tab-panel tab=\"a\">…</fx-tab-panel>\n * <fx-tab-panel tab=\"b\">…</fx-tab-panel>\n * Evento: `change` (composed, detail: { value }).\n */\nexport class FxTabs extends FxElement {\n static override styles = css`\n :host {\n display: block;\n font-family: var(--fx-font-family);\n }\n .list {\n display: flex;\n gap: var(--fx-space-xs);\n border-bottom: 2px solid var(--fx-border-default);\n }\n .tab {\n border: none;\n background: transparent;\n font-family: inherit;\n font-size: var(--fx-font-size);\n color: var(--fx-text-muted);\n padding: var(--fx-space-md) var(--fx-space-lg);\n cursor: pointer;\n position: relative;\n transition: color var(--fx-motion-duration-fast) var(--fx-motion-easing);\n }\n .tab::after {\n content: '';\n position: absolute;\n left: 0; right: 0; bottom: -2px;\n height: 2px;\n background: transparent;\n transition: background var(--fx-motion-duration-fast) var(--fx-motion-easing);\n }\n .tab:hover { color: var(--fx-text-default); }\n .tab[data-disabled] {\n color: var(--fx-border-default);\n cursor: not-allowed;\n opacity: 0.6;\n }\n .tab[data-disabled]:hover { color: var(--fx-border-default); }\n .tab[aria-selected='true'] {\n color: var(--fx-color-primary);\n font-weight: 600;\n }\n .tab[aria-selected='true']::after { background: var(--fx-color-primary); }\n .tab:focus-visible {\n outline: none;\n box-shadow: var(--fx-effect-focus-ring, none);\n border-radius: var(--fx-radius-sm);\n }\n /* Os <fx-tab> originais são renderizados como botões no shadow DOM.\n Sem isto, o <slot> os projetaria de novo como texto cru abaixo das abas. */\n ::slotted(fx-tab) {\n display: none !important;\n }\n `;\n\n static override get observedAttributes(): string[] {\n return ['value'];\n }\n\n get value(): string { return this.getAttr('value'); }\n set value(value: string) { this.setAttribute('value', value); }\n\n protected override render(): void {\n const tabs = Array.from(this.querySelectorAll<HTMLElement>('fx-tab'));\n const active = this.value || tabs[0]?.getAttribute('tab') || '';\n\n this.setTemplate(`\n <div class=\"list\" role=\"tablist\">\n ${tabs.map((t) => {\n const tabId = t.getAttribute('tab') ?? '';\n const disabled = t.hasAttribute('disabled');\n return `<button type=\"button\" class=\"tab\" role=\"tab\" part=\"tab\"\n data-tab=\"${tabId}\" aria-selected=\"${tabId === active}\"\n ${disabled ? 'aria-disabled=\"true\" data-disabled=\"true\"' : ''}>${t.textContent?.trim()}</button>`;\n }).join('')}\n </div>\n <slot></slot>\n `);\n\n // Sincroniza apenas os painéis DESTE conjunto de abas\n // (dentro do host ou irmãos seguintes — nunca global).\n // IMPORTANTE: manipula o atributo `hidden` DIRETAMENTE (nunca a\n // propriedade `.visible`), porque escrever a propriedade em um\n // elemento ainda não upgradeado cria uma own property que faz\n // shadowing dos accessors do prototype para sempre.\n this.panels.forEach((p) => {\n const show = p.getAttribute('tab') === active;\n if (show) p.removeAttribute('hidden');\n else p.setAttribute('hidden', '');\n });\n\n this.root.querySelectorAll<HTMLButtonElement>('.tab').forEach((btn) => {\n btn.addEventListener('click', () => {\n if (btn.hasAttribute('data-disabled')) return;\n this.value = btn.dataset.tab ?? '';\n this.dispatchEvent(\n new CustomEvent('change', { bubbles: true, composed: true, detail: { value: this.value } }),\n );\n });\n });\n }\n\n /** Painéis associados: descendentes do host ou irmãos seguintes no DOM. */\n private get panels(): FxTabPanel[] {\n const inside = Array.from(this.querySelectorAll<FxTabPanel>('fx-tab-panel'));\n if (inside.length) return inside;\n const out: FxTabPanel[] = [];\n let el = this.nextElementSibling;\n while (el && !el.matches('fx-tabs')) {\n if (el.matches('fx-tab-panel')) out.push(el as FxTabPanel);\n else out.push(...Array.from(el.querySelectorAll<FxTabPanel>(':scope > fx-tab-panel')));\n el = el.nextElementSibling;\n }\n return out;\n }\n}\n\n/**\n * <fx-tab-panel> — Painel de conteúdo associado a uma aba.\n */\nexport class FxTabPanel extends FxElement {\n static override styles = css`\n :host { display: block; padding: var(--fx-space-lg) 0; font-family: var(--fx-font-family); color: var(--fx-text-default); }\n :host([hidden]) { display: none; }\n `;\n\n static override get observedAttributes(): string[] {\n return ['tab'];\n }\n\n get tab(): string { return this.getAttr('tab'); }\n /** Setter necessário: o Vue (patchDOMProp) seta `tab` como PROPRIEDADE\n * (pois o getter existe no prototype) — sem ele o atributo nunca é\n * aplicado e o painel nunca é exibido. */\n set tab(value: string) { this.setAttribute('tab', value); }\n\n get visible(): boolean { return !this.hasAttr('hidden'); }\n set visible(value: boolean) { this.toggleAttr('hidden', !value); }\n\n protected override render(): void {\n this.setTemplate('<slot></slot>');\n if (!this._initialized) {\n // Estado inicial: visível apenas se for a aba ativa do owner.\n // (usa atributo direto — ver comentário em FxTabs.render)\n const owner =\n (this.closest<FxTabs>('fx-tabs')) ??\n (() => {\n let el = this.previousElementSibling;\n while (el) {\n if (el.matches('fx-tabs')) return el as FxTabs;\n el = el.previousElementSibling;\n }\n return null;\n })();\n const active = owner ? (owner.getAttribute('value') || '') : '';\n if (this.getAttribute('tab') !== active) this.setAttribute('hidden', '');\n this._initialized = true;\n }\n }\n\n private _initialized = false;\n}\n\nexport function defineFxTabs(): typeof FxTabs {\n return defineElement('fx-tabs', FxTabs);\n}\nexport function defineFxTabPanel(): typeof FxTabPanel {\n return defineElement('fx-tab-panel', FxTabPanel);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tabs.js","sources":["../../../src/components/tabs/tabs.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-tabs> — Navegação por abas.\n *\n * Atributos: value (aba ativa, corresponde ao attr `tab` de cada fx-tab-panel).\n * Uso:\n * <fx-tabs value=\"a\">\n * <fx-tab tab=\"a\">Aba A</fx-tab>\n * <fx-tab tab=\"b\">Aba B</fx-tab>\n * </fx-tabs>\n * <fx-tab-panel tab=\"a\">…</fx-tab-panel>\n * <fx-tab-panel tab=\"b\">…</fx-tab-panel>\n * Evento: `change` (composed, detail: { value }).\n */\nexport class FxTabs extends FxElement {\n static override styles = css`\n :host {\n display: block;\n font-family: var(--fx-font-family);\n }\n .list {\n display: flex;\n gap: var(--fx-space-xs);\n border-bottom: 2px solid var(--fx-border-default);\n }\n .tab {\n border: none;\n background: transparent;\n font-family: inherit;\n font-size: var(--fx-font-size);\n color: var(--fx-text-muted);\n padding: var(--fx-space-md) var(--fx-space-lg);\n cursor: pointer;\n position: relative;\n transition: color var(--fx-motion-duration-fast) var(--fx-motion-easing);\n }\n .tab::after {\n content: '';\n position: absolute;\n left: 0; right: 0; bottom: -2px;\n height: 2px;\n background: transparent;\n transition: background var(--fx-motion-duration-fast) var(--fx-motion-easing);\n }\n .tab:hover { color: var(--fx-text-default); }\n .tab[data-disabled] {\n color: var(--fx-border-default);\n cursor: not-allowed;\n opacity: 0.6;\n }\n .tab[data-disabled]:hover { color: var(--fx-border-default); }\n .tab[aria-selected='true'] {\n color: var(--fx-color-primary);\n font-weight: 600;\n }\n .tab[aria-selected='true']::after { background: var(--fx-color-primary); }\n .tab:focus-visible {\n outline: none;\n box-shadow: var(--fx-effect-focus-ring, none);\n border-radius: var(--fx-radius-sm);\n }\n /* Os <fx-tab> originais são renderizados como botões no shadow DOM.\n Sem isto, o <slot> os projetaria de novo como texto cru abaixo das abas. */\n ::slotted(fx-tab) {\n display: none !important;\n }\n `;\n\n static override get observedAttributes(): string[] {\n return ['value'];\n }\n\n get value(): string { return this.getAttr('value'); }\n set value(value: string) { this.setAttribute('value', value); }\n\n protected override render(): void {\n const tabs = Array.from(this.querySelectorAll<HTMLElement>('fx-tab'));\n const active = this.value || tabs[0]?.getAttribute('tab') || '';\n\n this.setTemplate(`\n <div class=\"list\" role=\"tablist\">\n ${tabs.map((t) => {\n const tabId = t.getAttribute('tab') ?? '';\n const disabled = t.hasAttribute('disabled');\n return `<button type=\"button\" class=\"tab\" role=\"tab\" part=\"tab\"\n data-tab=\"${esc(tabId)}\" aria-selected=\"${tabId === active}\"\n ${disabled ? 'aria-disabled=\"true\" data-disabled=\"true\"' : ''}>${esc(t.textContent?.trim() ?? '')}</button>`;\n }).join('')}\n </div>\n <slot></slot>\n `);\n\n // Sincroniza apenas os painéis DESTE conjunto de abas\n // (dentro do host ou irmãos seguintes — nunca global).\n // IMPORTANTE: manipula o atributo `hidden` DIRETAMENTE (nunca a\n // propriedade `.visible`), porque escrever a propriedade em um\n // elemento ainda não upgradeado cria uma own property que faz\n // shadowing dos accessors do prototype para sempre.\n this.panels.forEach((p) => {\n const show = p.getAttribute('tab') === active;\n if (show) p.removeAttribute('hidden');\n else p.setAttribute('hidden', '');\n });\n\n this.root.querySelectorAll<HTMLButtonElement>('.tab').forEach((btn) => {\n btn.addEventListener('click', () => {\n if (btn.hasAttribute('data-disabled')) return;\n this.value = btn.dataset.tab ?? '';\n this.dispatchEvent(\n new CustomEvent('change', { bubbles: true, composed: true, detail: { value: this.value } }),\n );\n });\n });\n }\n\n /** Painéis associados: descendentes do host ou irmãos seguintes no DOM. */\n private get panels(): FxTabPanel[] {\n const inside = Array.from(this.querySelectorAll<FxTabPanel>('fx-tab-panel'));\n if (inside.length) return inside;\n const out: FxTabPanel[] = [];\n let el = this.nextElementSibling;\n while (el && !el.matches('fx-tabs')) {\n if (el.matches('fx-tab-panel')) out.push(el as FxTabPanel);\n else out.push(...Array.from(el.querySelectorAll<FxTabPanel>(':scope > fx-tab-panel')));\n el = el.nextElementSibling;\n }\n return out;\n }\n}\n\n/**\n * <fx-tab-panel> — Painel de conteúdo associado a uma aba.\n */\nexport class FxTabPanel extends FxElement {\n static override styles = css`\n :host { display: block; padding: var(--fx-space-lg) 0; font-family: var(--fx-font-family); color: var(--fx-text-default); }\n :host([hidden]) { display: none; }\n `;\n\n static override get observedAttributes(): string[] {\n return ['tab'];\n }\n\n get tab(): string { return this.getAttr('tab'); }\n /** Setter necessário: o Vue (patchDOMProp) seta `tab` como PROPRIEDADE\n * (pois o getter existe no prototype) — sem ele o atributo nunca é\n * aplicado e o painel nunca é exibido. */\n set tab(value: string) { this.setAttribute('tab', value); }\n\n get visible(): boolean { return !this.hasAttr('hidden'); }\n set visible(value: boolean) { this.toggleAttr('hidden', !value); }\n\n protected override render(): void {\n this.setTemplate('<slot></slot>');\n if (!this._initialized) {\n // Estado inicial: visível apenas se for a aba ativa do owner.\n // (usa atributo direto — ver comentário em FxTabs.render)\n const owner =\n (this.closest<FxTabs>('fx-tabs')) ??\n (() => {\n let el = this.previousElementSibling;\n while (el) {\n if (el.matches('fx-tabs')) return el as FxTabs;\n el = el.previousElementSibling;\n }\n return null;\n })();\n const active = owner ? (owner.getAttribute('value') || '') : '';\n if (this.getAttribute('tab') !== active) this.setAttribute('hidden', '');\n this._initialized = true;\n }\n }\n\n private _initialized = false;\n}\n\nexport function defineFxTabs(): typeof FxTabs {\n return defineElement('fx-tabs', FxTabs);\n}\nexport function defineFxTabPanel(): typeof FxTabPanel {\n return defineElement('fx-tab-panel', FxTabPanel);\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../src/components/textarea/index.ts"],"sourcesContent":["import { FxTextarea, defineFxTextarea } from './textarea';\n\n// Reexporta a classe para uso programático (ex.: instanceof, herança).\nexport { FxTextarea };\n\n\n// Auto-registro: basta importar o subpath `@wrrdev/fenix-ui/textarea`\n// para que o componente seja definido no CustomElementRegistry.\ndefineFxTextarea();\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'fx-textarea': FxTextarea;\n }\n}\n\r\n\r\n"],"names":[],"mappings":";;AAQA,iBAAA;"}
1
+ {"version":3,"file":"index.js","sources":["../../../src/components/textarea/index.ts"],"sourcesContent":["import { FxTextarea, defineFxTextarea } from './textarea';\n\n// Reexporta a classe para uso programático (ex.: instanceof, herança).\nexport { FxTextarea };\n\n\n// Auto-registro: basta importar o subpath `@wrrdev/fenix-ui/textarea`\n// para que o componente seja definido no CustomElementRegistry.\ndefineFxTextarea();\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'fx-textarea': FxTextarea;\n }\n}\n\n\n"],"names":[],"mappings":";;AAQA,iBAAA;"}
@@ -1 +1 @@
1
- {"version":3,"file":"textarea.d.ts","sourceRoot":"","sources":["../../../src/components/textarea/textarea.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C;;;;;;GAMG;AACH,qBAAa,UAAW,SAAQ,SAAS;IACvC,OAAgB,MAAM,SA+CpB;IAEF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAEjD;IAED,IAAI,IAAI,IAAI,MAAM,CAGjB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,EAAuC;IAE7D,IAAI,KAAK,IAAI,MAAM,CAAkC;IACrD,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAAwC;cAE5C,MAAM,IAAI,IAAI;CA8BlC;AAED,wBAAgB,gBAAgB,IAAI,OAAO,UAAU,CAEpD"}
1
+ {"version":3,"file":"textarea.d.ts","sourceRoot":"","sources":["../../../src/components/textarea/textarea.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAK5C;;;;;;GAMG;AACH,qBAAa,UAAW,SAAQ,SAAS;IACvC,OAAgB,MAAM,SA+CpB;IAEF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAEjD;IAED,IAAI,IAAI,IAAI,MAAM,CAGjB;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,EAAuC;IAE7D,IAAI,KAAK,IAAI,MAAM,CAAkC;IACrD,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAAwC;cAE5C,MAAM,IAAI,IAAI;CA8BlC;AAED,wBAAgB,gBAAgB,IAAI,OAAO,UAAU,CAEpD"}
@@ -1,6 +1,7 @@
1
1
  import { FxElement } from "../../core/base.js";
2
2
  import { css } from "../../core/css.js";
3
3
  import { defineElement } from "../../core/define.js";
4
+ import { esc } from "../../core/sanitize.js";
4
5
  const _FxTextarea = class _FxTextarea extends FxElement {
5
6
  static get observedAttributes() {
6
7
  return ["size", "placeholder", "disabled", "readonly", "rows", "maxlength"];
@@ -25,9 +26,9 @@ const _FxTextarea = class _FxTextarea extends FxElement {
25
26
  const rows = this.getAttr("rows");
26
27
  const maxlength = this.getAttr("maxlength");
27
28
  this.setTemplate(`<textarea class="field" part="textarea"
28
- ${placeholder ? `placeholder="${placeholder}"` : ""}
29
- ${rows ? `rows="${rows}"` : ""}
30
- ${maxlength ? `maxlength="${maxlength}"` : ""}
29
+ ${placeholder ? `placeholder="${esc(placeholder)}"` : ""}
30
+ ${rows ? `rows="${esc(rows)}"` : ""}
31
+ ${maxlength ? `maxlength="${esc(maxlength)}"` : ""}
31
32
  ></textarea>`);
32
33
  const field = this.root.querySelector(".field");
33
34
  if (!field) return;
@@ -1 +1 @@
1
- {"version":3,"file":"textarea.js","sources":["../../../src/components/textarea/textarea.ts"],"sourcesContent":["import { FxElement } from '../../core/base';\nimport { css } from '../../core/css';\nimport { defineElement } from '../../core/define';\n\n/**\n * <fx-textarea> — Área de texto multilinha estilizada com os tokens do tema.\n *\n * Atributos: value, size (sm|md|lg), placeholder, disabled, readonly,\n * rows, maxlength.\n * Eventos: `input` e `change` (composed, detail: { value }).\n */\nexport class FxTextarea extends FxElement {\n static override styles = css`\n :host {\n display: inline-block;\n vertical-align: middle;\n font-family: var(--fx-font-family);\n font-size: var(--fx-font-size);\n }\n .field {\n font-family: inherit;\n font-size: inherit;\n font-weight: var(--fx-font-weight);\n color: var(--fx-text-default);\n background-color: var(--fx-surface-background);\n border: 1px solid var(--fx-border-default);\n border-radius: var(--fx-radius-md);\n padding: var(--fx-space-md) var(--fx-space-lg);\n width: 260px;\n min-height: calc(var(--fx-size-md) + 40px);\n resize: vertical;\n box-sizing: border-box;\n transition:\n border-color var(--fx-motion-duration-normal) var(--fx-motion-easing),\n box-shadow var(--fx-motion-duration-normal) var(--fx-motion-easing);\n }\n .field::placeholder { color: var(--fx-text-muted); opacity: 1; }\n .field:hover { border-color: var(--fx-border-hover); }\n .field:focus-visible {\n outline: none;\n border-color: var(--fx-color-primary);\n box-shadow: var(--fx-effect-focus-ring, none);\n }\n .field:disabled,\n .field[readonly] {\n opacity: 0.55;\n cursor: not-allowed;\n background-color: var(--fx-surface-surface-hover);\n }\n :host([error]) .field, :host([invalid]) .field {\n border-color: var(--fx-color-danger, #dc2626);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--fx-color-danger, #dc2626) 18%, transparent);\n }\n :host([success]) .field, :host([valid]) .field {\n border-color: var(--fx-color-success, #16a34a);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--fx-color-success, #16a34a) 18%, transparent);\n }\n :host([size='sm']) .field { width: 220px; min-height: var(--fx-size-sm); padding: var(--fx-space-sm) var(--fx-space-md); }\n :host([size='lg']) .field { width: 300px; min-height: calc(var(--fx-size-lg) + 80px); }\n `;\n\n static override get observedAttributes(): string[] {\n return ['size', 'placeholder', 'disabled', 'readonly', 'rows', 'maxlength'];\n }\n\n get size(): string {\n const s = this.getAttr('size', 'md');\n return s === 'sm' || s === 'lg' ? s : 'md';\n }\n set size(value: string) { this.setAttribute('size', value); }\n\n get value(): string { return this.getAttr('value'); }\n set value(value: string) { this.setAttribute('value', value); }\n\n protected override render(): void {\n const placeholder = this.getAttr('placeholder');\n const readonly = this.hasAttr('readonly');\n const disabled = this.hasAttr('disabled');\n const rows = this.getAttr('rows');\n const maxlength = this.getAttr('maxlength');\n\n this.setTemplate(`<textarea class=\"field\" part=\"textarea\"\n ${placeholder ? `placeholder=\"${placeholder}\"` : ''}\n ${rows ? `rows=\"${rows}\"` : ''}\n ${maxlength ? `maxlength=\"${maxlength}\"` : ''}\n ></textarea>`);\n\n const field = this.root.querySelector<HTMLTextAreaElement>('.field');\n if (!field) return;\n field.value = this.getAttr('value');\n if (disabled) field.setAttribute('disabled', '');\n if (readonly) field.setAttribute('readonly', '');\n\n const emit = (event: string): void => {\n this.value = field.value;\n this.dispatchEvent(\n new CustomEvent(event, { bubbles: true, composed: true, detail: { value: field.value } }),\n );\n };\n // Bloqueia o evento nativo (composed, sem detail) para que só o\n // CustomEvent com detail chegue aos consumidores.\n field.addEventListener('input', (e) => { e.stopPropagation(); emit('input'); });\n field.addEventListener('change', (e) => { e.stopPropagation(); emit('change'); });\n }\n}\n\nexport function defineFxTextarea(): typeof FxTextarea {\n return defineElement('fx-textarea', FxTextarea);\n}\n"],"names":[],"mappings":";;;AAWO,MAAM,cAAN,MAAM,oBAAmB,UAAU;AAAA,EAkDxC,WAAoB,qBAA+B;AACjD,WAAO,CAAC,QAAQ,eAAe,YAAY,YAAY,QAAQ,WAAW;AAAA,EAC5E;AAAA,EAEA,IAAI,OAAe;AACjB,UAAM,IAAI,KAAK,QAAQ,QAAQ,IAAI;AACnC,WAAO,MAAM,QAAQ,MAAM,OAAO,IAAI;AAAA,EACxC;AAAA,EACA,IAAI,KAAK,OAAe;AAAE,SAAK,aAAa,QAAQ,KAAK;AAAA,EAAG;AAAA,EAE5D,IAAI,QAAgB;AAAE,WAAO,KAAK,QAAQ,OAAO;AAAA,EAAG;AAAA,EACpD,IAAI,MAAM,OAAe;AAAE,SAAK,aAAa,SAAS,KAAK;AAAA,EAAG;AAAA,EAE3C,SAAe;AAChC,UAAM,cAAc,KAAK,QAAQ,aAAa;AAC9C,UAAM,WAAW,KAAK,QAAQ,UAAU;AACxC,UAAM,WAAW,KAAK,QAAQ,UAAU;AACxC,UAAM,OAAO,KAAK,QAAQ,MAAM;AAChC,UAAM,YAAY,KAAK,QAAQ,WAAW;AAE1C,SAAK,YAAY;AAAA,QACb,cAAc,gBAAgB,WAAW,MAAM,EAAE;AAAA,QACjD,OAAO,SAAS,IAAI,MAAM,EAAE;AAAA,QAC5B,YAAY,cAAc,SAAS,MAAM,EAAE;AAAA,iBAClC;AAEb,UAAM,QAAQ,KAAK,KAAK,cAAmC,QAAQ;AACnE,QAAI,CAAC,MAAO;AACZ,UAAM,QAAQ,KAAK,QAAQ,OAAO;AAClC,QAAI,SAAU,OAAM,aAAa,YAAY,EAAE;AAC/C,QAAI,SAAU,OAAM,aAAa,YAAY,EAAE;AAE/C,UAAM,OAAO,CAAC,UAAwB;AACpC,WAAK,QAAQ,MAAM;AACnB,WAAK;AAAA,QACH,IAAI,YAAY,OAAO,EAAE,SAAS,MAAM,UAAU,MAAM,QAAQ,EAAE,OAAO,MAAM,MAAA,GAAS;AAAA,MAAA;AAAA,IAE5F;AAGA,UAAM,iBAAiB,SAAS,CAAC,MAAM;AAAE,QAAE,gBAAA;AAAmB,WAAK,OAAO;AAAA,IAAG,CAAC;AAC9E,UAAM,iBAAiB,UAAU,CAAC,MAAM;AAAE,QAAE,gBAAA;AAAmB,WAAK,QAAQ;AAAA,IAAG,CAAC;AAAA,EAClF;AACF;AA5FE,YAAgB,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;AAAA;AAAA;AAAA;AAAA;AADpB,IAAM,aAAN;AA+FA,SAAS,mBAAsC;AACpD,SAAO,cAAc,eAAe,UAAU;AAChD;"}
1
+ {"version":3,"file":"textarea.js","sources":["../../../src/components/textarea/textarea.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-textarea> — Área de texto multilinha estilizada com os tokens do tema.\n *\n * Atributos: value, size (sm|md|lg), placeholder, disabled, readonly,\n * rows, maxlength.\n * Eventos: `input` e `change` (composed, detail: { value }).\n */\nexport class FxTextarea extends FxElement {\n static override styles = css`\n :host {\n display: inline-block;\n vertical-align: middle;\n font-family: var(--fx-font-family);\n font-size: var(--fx-font-size);\n }\n .field {\n font-family: inherit;\n font-size: inherit;\n font-weight: var(--fx-font-weight);\n color: var(--fx-text-default);\n background-color: var(--fx-surface-background);\n border: 1px solid var(--fx-border-default);\n border-radius: var(--fx-radius-md);\n padding: var(--fx-space-md) var(--fx-space-lg);\n width: 260px;\n min-height: calc(var(--fx-size-md) + 40px);\n resize: vertical;\n box-sizing: border-box;\n transition:\n border-color var(--fx-motion-duration-normal) var(--fx-motion-easing),\n box-shadow var(--fx-motion-duration-normal) var(--fx-motion-easing);\n }\n .field::placeholder { color: var(--fx-text-muted); opacity: 1; }\n .field:hover { border-color: var(--fx-border-hover); }\n .field:focus-visible {\n outline: none;\n border-color: var(--fx-color-primary);\n box-shadow: var(--fx-effect-focus-ring, none);\n }\n .field:disabled,\n .field[readonly] {\n opacity: 0.55;\n cursor: not-allowed;\n background-color: var(--fx-surface-surface-hover);\n }\n :host([error]) .field, :host([invalid]) .field {\n border-color: var(--fx-color-danger, #dc2626);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--fx-color-danger, #dc2626) 18%, transparent);\n }\n :host([success]) .field, :host([valid]) .field {\n border-color: var(--fx-color-success, #16a34a);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--fx-color-success, #16a34a) 18%, transparent);\n }\n :host([size='sm']) .field { width: 220px; min-height: var(--fx-size-sm); padding: var(--fx-space-sm) var(--fx-space-md); }\n :host([size='lg']) .field { width: 300px; min-height: calc(var(--fx-size-lg) + 80px); }\n `;\n\n static override get observedAttributes(): string[] {\n return ['size', 'placeholder', 'disabled', 'readonly', 'rows', 'maxlength'];\n }\n\n get size(): string {\n const s = this.getAttr('size', 'md');\n return s === 'sm' || s === 'lg' ? s : 'md';\n }\n set size(value: string) { this.setAttribute('size', value); }\n\n get value(): string { return this.getAttr('value'); }\n set value(value: string) { this.setAttribute('value', value); }\n\n protected override render(): void {\n const placeholder = this.getAttr('placeholder');\n const readonly = this.hasAttr('readonly');\n const disabled = this.hasAttr('disabled');\n const rows = this.getAttr('rows');\n const maxlength = this.getAttr('maxlength');\n\n this.setTemplate(`<textarea class=\"field\" part=\"textarea\"\n ${placeholder ? `placeholder=\"${esc(placeholder)}\"` : ''}\n ${rows ? `rows=\"${esc(rows)}\"` : ''}\n ${maxlength ? `maxlength=\"${esc(maxlength)}\"` : ''}\n ></textarea>`);\n\n const field = this.root.querySelector<HTMLTextAreaElement>('.field');\n if (!field) return;\n field.value = this.getAttr('value');\n if (disabled) field.setAttribute('disabled', '');\n if (readonly) field.setAttribute('readonly', '');\n\n const emit = (event: string): void => {\n this.value = field.value;\n this.dispatchEvent(\n new CustomEvent(event, { bubbles: true, composed: true, detail: { value: field.value } }),\n );\n };\n // Bloqueia o evento nativo (composed, sem detail) para que só o\n // CustomEvent com detail chegue aos consumidores.\n field.addEventListener('input', (e) => { e.stopPropagation(); emit('input'); });\n field.addEventListener('change', (e) => { e.stopPropagation(); emit('change'); });\n }\n}\n\nexport function defineFxTextarea(): typeof FxTextarea {\n return defineElement('fx-textarea', FxTextarea);\n}\n"],"names":[],"mappings":";;;;AAYO,MAAM,cAAN,MAAM,oBAAmB,UAAU;AAAA,EAkDxC,WAAoB,qBAA+B;AACjD,WAAO,CAAC,QAAQ,eAAe,YAAY,YAAY,QAAQ,WAAW;AAAA,EAC5E;AAAA,EAEA,IAAI,OAAe;AACjB,UAAM,IAAI,KAAK,QAAQ,QAAQ,IAAI;AACnC,WAAO,MAAM,QAAQ,MAAM,OAAO,IAAI;AAAA,EACxC;AAAA,EACA,IAAI,KAAK,OAAe;AAAE,SAAK,aAAa,QAAQ,KAAK;AAAA,EAAG;AAAA,EAE5D,IAAI,QAAgB;AAAE,WAAO,KAAK,QAAQ,OAAO;AAAA,EAAG;AAAA,EACpD,IAAI,MAAM,OAAe;AAAE,SAAK,aAAa,SAAS,KAAK;AAAA,EAAG;AAAA,EAE3C,SAAe;AAChC,UAAM,cAAc,KAAK,QAAQ,aAAa;AAC9C,UAAM,WAAW,KAAK,QAAQ,UAAU;AACxC,UAAM,WAAW,KAAK,QAAQ,UAAU;AACxC,UAAM,OAAO,KAAK,QAAQ,MAAM;AAChC,UAAM,YAAY,KAAK,QAAQ,WAAW;AAE1C,SAAK,YAAY;AAAA,QACb,cAAc,gBAAgB,IAAI,WAAW,CAAC,MAAM,EAAE;AAAA,QACtD,OAAO,SAAS,IAAI,IAAI,CAAC,MAAM,EAAE;AAAA,QACjC,YAAY,cAAc,IAAI,SAAS,CAAC,MAAM,EAAE;AAAA,iBACvC;AAEb,UAAM,QAAQ,KAAK,KAAK,cAAmC,QAAQ;AACnE,QAAI,CAAC,MAAO;AACZ,UAAM,QAAQ,KAAK,QAAQ,OAAO;AAClC,QAAI,SAAU,OAAM,aAAa,YAAY,EAAE;AAC/C,QAAI,SAAU,OAAM,aAAa,YAAY,EAAE;AAE/C,UAAM,OAAO,CAAC,UAAwB;AACpC,WAAK,QAAQ,MAAM;AACnB,WAAK;AAAA,QACH,IAAI,YAAY,OAAO,EAAE,SAAS,MAAM,UAAU,MAAM,QAAQ,EAAE,OAAO,MAAM,MAAA,GAAS;AAAA,MAAA;AAAA,IAE5F;AAGA,UAAM,iBAAiB,SAAS,CAAC,MAAM;AAAE,QAAE,gBAAA;AAAmB,WAAK,OAAO;AAAA,IAAG,CAAC;AAC9E,UAAM,iBAAiB,UAAU,CAAC,MAAM;AAAE,QAAE,gBAAA;AAAmB,WAAK,QAAQ;AAAA,IAAG,CAAC;AAAA,EAClF;AACF;AA5FE,YAAgB,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;AAAA;AAAA;AAAA;AAAA;AADpB,IAAM,aAAN;AA+FA,SAAS,mBAAsC;AACpD,SAAO,cAAc,eAAe,UAAU;AAChD;"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../src/components/toast/index.ts"],"sourcesContent":["import { FxToast, FenixToast, defineFxToast } from './toast';\n\nexport { FxToast, FenixToast };\n\n\ndefineFxToast();\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'fx-toast': FxToast;\n }\n}\n\r\n\r\n"],"names":[],"mappings":";;AAKA,cAAA;"}
1
+ {"version":3,"file":"index.js","sources":["../../../src/components/toast/index.ts"],"sourcesContent":["import { FxToast, FenixToast, defineFxToast } from './toast';\n\nexport { FxToast, FenixToast };\n\n\ndefineFxToast();\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'fx-toast': FxToast;\n }\n}\n\n\n"],"names":[],"mappings":";;AAKA,cAAA;"}
@@ -1 +1 @@
1
- {"version":3,"file":"directive.js","sources":["../../../src/components/tooltip/directive.ts"],"sourcesContent":["/**\r\n * Diretiva fx-tooltip — Aplica tooltip em qualquer elemento HTML.\r\n *\r\n * Uso:\r\n * <div fx-tooltip=\"Texto simples\">Div com tooltip</div>\r\n * <button fx-tooltip=\"Clique\" fx-tooltip-position=\"bottom\">Botão</button>\r\n * <span fx-tooltip=\"<strong>HTML</strong>\" fx-tooltip-html>Texto</span>\r\n *\r\n * Atributos:\r\n * fx-tooltip — Conteúdo do tooltip (texto ou HTML)\r\n * fx-tooltip-position — Posição: top | bottom | left | right (padrão: top)\r\n * fx-tooltip-html — Se presente, trata o conteúdo como HTML\r\n */\r\n\r\nexport interface FxTooltipConfig {\r\n position: 'top' | 'bottom' | 'left' | 'right';\r\n html: boolean;\r\n}\r\n\r\nconst DEFAULT_CONFIG: FxTooltipConfig = {\r\n position: 'top',\r\n html: false,\r\n};\r\n\r\n/**\r\n * Classe que gerencia o comportamento de tooltip em um elemento.\r\n */\r\nclass TooltipBehavior {\r\n private element: HTMLElement;\r\n private tooltipElement: HTMLSpanElement | null = null;\r\n private config: FxTooltipConfig;\r\n private showTimeout: number | null = null;\r\n private hideTimeout: number | null = null;\r\n\r\n constructor(element: HTMLElement) {\r\n this.element = element;\r\n this.config = this.parseConfig();\r\n this.init();\r\n }\r\n\r\n private parseConfig(): FxTooltipConfig {\r\n const position = this.element.getAttribute('fx-tooltip-position') as FxTooltipConfig['position'];\r\n return {\r\n position: position && ['top', 'bottom', 'left', 'right'].includes(position) ? position : DEFAULT_CONFIG.position,\r\n html: this.element.hasAttribute('fx-tooltip-html'),\r\n };\r\n }\r\n\r\n private init(): void {\r\n const computedStyle = window.getComputedStyle(this.element);\r\n if (computedStyle.position === 'static') {\r\n this.element.style.position = 'relative';\r\n }\r\n this.createTooltipElement();\r\n this.element.addEventListener('mouseenter', this.show);\r\n this.element.addEventListener('mouseleave', this.hide);\r\n this.element.addEventListener('focus', this.show);\r\n this.element.addEventListener('blur', this.hide);\r\n }\r\n\r\n private createTooltipElement(): void {\r\n const content = this.element.getAttribute('fx-tooltip');\r\n if (!content) return;\r\n this.tooltipElement = document.createElement('span');\r\n this.tooltipElement.setAttribute('role', 'tooltip');\r\n this.tooltipElement.setAttribute('data-fx-tooltip', '');\r\n this.tooltipElement.className = `fx-tooltip-bubble fx-tooltip-${this.config.position}`;\r\n if (this.config.html) {\r\n this.tooltipElement.innerHTML = content;\r\n } else {\r\n this.tooltipElement.textContent = content;\r\n }\r\n this.element.appendChild(this.tooltipElement);\r\n }\r\n\r\n private show = (): void => {\r\n if (this.hideTimeout) {\r\n clearTimeout(this.hideTimeout);\r\n this.hideTimeout = null;\r\n }\r\n this.showTimeout = window.setTimeout(() => {\r\n if (this.tooltipElement) {\r\n this.tooltipElement.classList.add('fx-tooltip-visible');\r\n }\r\n }, 100);\r\n };\r\n\r\n private hide = (): void => {\r\n if (this.showTimeout) {\r\n clearTimeout(this.showTimeout);\r\n this.showTimeout = null;\r\n }\r\n this.hideTimeout = window.setTimeout(() => {\r\n if (this.tooltipElement) {\r\n this.tooltipElement.classList.remove('fx-tooltip-visible');\r\n }\r\n }, 50);\r\n };\r\n\r\n public update(): void {\r\n this.config = this.parseConfig();\r\n if (this.tooltipElement) {\r\n this.tooltipElement.remove();\r\n this.tooltipElement = null;\r\n }\r\n this.createTooltipElement();\r\n }\r\n\r\n public destroy(): void {\r\n this.element.removeEventListener('mouseenter', this.show);\r\n this.element.removeEventListener('mouseleave', this.hide);\r\n this.element.removeEventListener('focus', this.show);\r\n this.element.removeEventListener('blur', this.hide);\r\n if (this.showTimeout) clearTimeout(this.showTimeout);\r\n if (this.hideTimeout) clearTimeout(this.hideTimeout);\r\n if (this.tooltipElement) {\r\n this.tooltipElement.remove();\r\n this.tooltipElement = null;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Gerencia todas as instâncias de tooltip no documento.\r\n */\r\nclass FxTooltipManager {\r\n private static instance: FxTooltipManager | null = null;\r\n private observer: MutationObserver | null = null;\r\n private behaviors: Map<HTMLElement, TooltipBehavior> = new Map();\r\n private injectedStyles: HTMLStyleElement | null = null;\r\n\r\n private constructor() {\r\n this.injectStyles();\r\n this.observe();\r\n this.processExistingElements();\r\n }\r\n\r\n public static getInstance(): FxTooltipManager {\r\n if (!FxTooltipManager.instance) {\r\n FxTooltipManager.instance = new FxTooltipManager();\r\n }\r\n return FxTooltipManager.instance;\r\n }\r\n\r\n private injectStyles(): void {\r\n if (document.getElementById('fx-tooltip-directive-styles')) return;\r\n this.injectedStyles = document.createElement('style');\r\n this.injectedStyles.id = 'fx-tooltip-directive-styles';\r\n this.injectedStyles.textContent = getTooltipStyles();\r\n document.head.appendChild(this.injectedStyles);\r\n }\r\n\r\n private observe(): void {\r\n this.observer = new MutationObserver((mutations) => {\r\n for (const mutation of mutations) {\r\n if (mutation.type === 'childList') {\r\n mutation.addedNodes.forEach((node) => {\r\n if (node instanceof HTMLElement) {\r\n this.processElement(node);\r\n node.querySelectorAll<HTMLElement>('[fx-tooltip]').forEach((el) => this.processElement(el));\r\n }\r\n });\r\n }\r\n if (mutation.type === 'attributes' && mutation.target instanceof HTMLElement) {\r\n const target = mutation.target;\r\n if (target.hasAttribute('fx-tooltip')) {\r\n this.processElement(target);\r\n } else if (this.behaviors.has(target)) {\r\n this.removeBehavior(target);\r\n }\r\n }\r\n }\r\n });\r\n this.observer.observe(document.body, {\r\n childList: true,\r\n subtree: true,\r\n attributes: true,\r\n attributeFilter: ['fx-tooltip', 'fx-tooltip-position', 'fx-tooltip-html'],\r\n });\r\n }\r\n\r\n private processExistingElements(): void {\r\n document.querySelectorAll<HTMLElement>('[fx-tooltip]').forEach((el) => this.processElement(el));\r\n }\r\n\r\n private processElement(element: HTMLElement): void {\r\n if (!element.hasAttribute('fx-tooltip')) {\r\n this.removeBehavior(element);\r\n return;\r\n }\r\n if (this.behaviors.has(element)) {\r\n this.behaviors.get(element)!.update();\r\n } else {\r\n this.behaviors.set(element, new TooltipBehavior(element));\r\n }\r\n }\r\n\r\n private removeBehavior(element: HTMLElement): void {\r\n const behavior = this.behaviors.get(element);\r\n if (behavior) {\r\n behavior.destroy();\r\n this.behaviors.delete(element);\r\n }\r\n }\r\n\r\n public destroy(): void {\r\n if (this.observer) {\r\n this.observer.disconnect();\r\n this.observer = null;\r\n }\r\n this.behaviors.forEach((behavior) => behavior.destroy());\r\n this.behaviors.clear();\r\n if (this.injectedStyles) {\r\n this.injectedStyles.remove();\r\n this.injectedStyles = null;\r\n }\r\n FxTooltipManager.instance = null;\r\n }\r\n}\r\n\r\n/**\r\n * Retorna os estilos CSS para os tooltips.\r\n */\r\nfunction getTooltipStyles(): string {\r\n return /* css */ `\r\n [fx-tooltip] {\r\n position: relative;\r\n }\r\n\r\n .fx-tooltip-bubble {\r\n position: absolute;\r\n background: var(--fx-text-default, #1e293b);\r\n color: var(--fx-surface-background, #fff);\r\n font-family: var(--fx-font-family, system-ui, -apple-system, sans-serif);\r\n font-size: calc(var(--fx-font-size, 14px) - 2px);\r\n line-height: 1.45;\r\n padding: var(--fx-space-xs, 4px) var(--fx-space-md, 12px);\r\n border-radius: var(--fx-radius-sm, 4px);\r\n box-shadow: var(--fx-shadow-md, 0 4px 6px -1px rgba(0, 0, 0, 0.1));\r\n width: max-content;\r\n min-width: 60px;\r\n max-width: var(--fx-tooltip-max-width, 320px);\r\n white-space: normal;\r\n text-align: center;\r\n opacity: 0;\r\n visibility: hidden;\r\n transition: opacity var(--fx-motion-duration-fast, 150ms) var(--fx-motion-easing, ease);\r\n z-index: var(--fx-z-tooltip, 1050);\r\n pointer-events: none;\r\n }\r\n\r\n .fx-tooltip-bubble.fx-tooltip-visible {\r\n opacity: 1;\r\n visibility: visible;\r\n }\r\n\r\n .fx-tooltip-top {\r\n bottom: calc(100% + 6px);\r\n left: 50%;\r\n transform: translateX(-50%);\r\n }\r\n .fx-tooltip-top::after {\r\n content: '';\r\n position: absolute;\r\n top: 100%;\r\n left: 50%;\r\n transform: translateX(-50%);\r\n border: 5px solid transparent;\r\n border-top-color: var(--fx-text-default, #1e293b);\r\n }\r\n\r\n .fx-tooltip-bottom {\r\n top: calc(100% + 6px);\r\n left: 50%;\r\n transform: translateX(-50%);\r\n bottom: auto;\r\n }\r\n .fx-tooltip-bottom::after {\r\n content: '';\r\n position: absolute;\r\n bottom: 100%;\r\n left: 50%;\r\n transform: translateX(-50%);\r\n border: 5px solid transparent;\r\n border-bottom-color: var(--fx-text-default, #1e293b);\r\n }\r\n\r\n .fx-tooltip-left {\r\n right: calc(100% + 6px);\r\n top: 50%;\r\n transform: translateY(-50%);\r\n left: auto;\r\n bottom: auto;\r\n }\r\n .fx-tooltip-left::after {\r\n content: '';\r\n position: absolute;\r\n top: 50%;\r\n left: 100%;\r\n transform: translateY(-50%);\r\n border: 5px solid transparent;\r\n border-left-color: var(--fx-text-default, #1e293b);\r\n }\r\n\r\n .fx-tooltip-right {\r\n left: calc(100% + 6px);\r\n top: 50%;\r\n transform: translateY(-50%);\r\n right: auto;\r\n bottom: auto;\r\n }\r\n .fx-tooltip-right::after {\r\n content: '';\r\n position: absolute;\r\n top: 50%;\r\n right: 100%;\r\n transform: translateY(-50%);\r\n border: 5px solid transparent;\r\n border-right-color: var(--fx-text-default, #1e293b);\r\n }\r\n `;\r\n}\r\n\r\n/**\r\n * Inicializa a diretiva fx-tooltip.\r\n * Deve ser chamado uma vez na aplicação.\r\n *\r\n * @example\r\n * import { defineFxTooltipDirective } from '@wrrdev/fenix-ui/tooltip';\r\n * defineFxTooltipDirective();\r\n */\r\nexport function defineFxTooltipDirective(): void {\r\n if (typeof window === 'undefined') return;\r\n if (document.readyState === 'loading') {\r\n document.addEventListener('DOMContentLoaded', () => {\r\n FxTooltipManager.getInstance();\r\n });\r\n } else {\r\n FxTooltipManager.getInstance();\r\n }\r\n}\r\n\r\n/**\r\n * Destrói a diretiva fx-tooltip e limpa todos os recursos.\r\n */\r\nexport function destroyFxTooltipDirective(): void {\r\n FxTooltipManager.getInstance().destroy();\r\n}\r\n\r\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"directive.js","sources":["../../../src/components/tooltip/directive.ts"],"sourcesContent":["/**\n * Diretiva fx-tooltip — Aplica tooltip em qualquer elemento HTML.\n *\n * Uso:\n * <div fx-tooltip=\"Texto simples\">Div com tooltip</div>\n * <button fx-tooltip=\"Clique\" fx-tooltip-position=\"bottom\">Botão</button>\n * <span fx-tooltip=\"<strong>HTML</strong>\" fx-tooltip-html>Texto</span>\n *\n * Atributos:\n * fx-tooltip — Conteúdo do tooltip (texto ou HTML)\n * fx-tooltip-position — Posição: top | bottom | left | right (padrão: top)\n * fx-tooltip-html — Se presente, trata o conteúdo como HTML\n */\n\nexport interface FxTooltipConfig {\n position: 'top' | 'bottom' | 'left' | 'right';\n html: boolean;\n}\n\nconst DEFAULT_CONFIG: FxTooltipConfig = {\n position: 'top',\n html: false,\n};\n\n/**\n * Classe que gerencia o comportamento de tooltip em um elemento.\n */\nclass TooltipBehavior {\n private element: HTMLElement;\n private tooltipElement: HTMLSpanElement | null = null;\n private config: FxTooltipConfig;\n private showTimeout: number | null = null;\n private hideTimeout: number | null = null;\n\n constructor(element: HTMLElement) {\n this.element = element;\n this.config = this.parseConfig();\n this.init();\n }\n\n private parseConfig(): FxTooltipConfig {\n const position = this.element.getAttribute('fx-tooltip-position') as FxTooltipConfig['position'];\n return {\n position: position && ['top', 'bottom', 'left', 'right'].includes(position) ? position : DEFAULT_CONFIG.position,\n html: this.element.hasAttribute('fx-tooltip-html'),\n };\n }\n\n private init(): void {\n const computedStyle = window.getComputedStyle(this.element);\n if (computedStyle.position === 'static') {\n this.element.style.position = 'relative';\n }\n this.createTooltipElement();\n this.element.addEventListener('mouseenter', this.show);\n this.element.addEventListener('mouseleave', this.hide);\n this.element.addEventListener('focus', this.show);\n this.element.addEventListener('blur', this.hide);\n }\n\n private createTooltipElement(): void {\n const content = this.element.getAttribute('fx-tooltip');\n if (!content) return;\n this.tooltipElement = document.createElement('span');\n this.tooltipElement.setAttribute('role', 'tooltip');\n this.tooltipElement.setAttribute('data-fx-tooltip', '');\n this.tooltipElement.className = `fx-tooltip-bubble fx-tooltip-${this.config.position}`;\n if (this.config.html) {\n this.tooltipElement.innerHTML = content;\n } else {\n this.tooltipElement.textContent = content;\n }\n this.element.appendChild(this.tooltipElement);\n }\n\n private show = (): void => {\n if (this.hideTimeout) {\n clearTimeout(this.hideTimeout);\n this.hideTimeout = null;\n }\n this.showTimeout = window.setTimeout(() => {\n if (this.tooltipElement) {\n this.tooltipElement.classList.add('fx-tooltip-visible');\n }\n }, 100);\n };\n\n private hide = (): void => {\n if (this.showTimeout) {\n clearTimeout(this.showTimeout);\n this.showTimeout = null;\n }\n this.hideTimeout = window.setTimeout(() => {\n if (this.tooltipElement) {\n this.tooltipElement.classList.remove('fx-tooltip-visible');\n }\n }, 50);\n };\n\n public update(): void {\n this.config = this.parseConfig();\n if (this.tooltipElement) {\n this.tooltipElement.remove();\n this.tooltipElement = null;\n }\n this.createTooltipElement();\n }\n\n public destroy(): void {\n this.element.removeEventListener('mouseenter', this.show);\n this.element.removeEventListener('mouseleave', this.hide);\n this.element.removeEventListener('focus', this.show);\n this.element.removeEventListener('blur', this.hide);\n if (this.showTimeout) clearTimeout(this.showTimeout);\n if (this.hideTimeout) clearTimeout(this.hideTimeout);\n if (this.tooltipElement) {\n this.tooltipElement.remove();\n this.tooltipElement = null;\n }\n }\n}\n\n/**\n * Gerencia todas as instâncias de tooltip no documento.\n */\nclass FxTooltipManager {\n private static instance: FxTooltipManager | null = null;\n private observer: MutationObserver | null = null;\n private behaviors: Map<HTMLElement, TooltipBehavior> = new Map();\n private injectedStyles: HTMLStyleElement | null = null;\n\n private constructor() {\n this.injectStyles();\n this.observe();\n this.processExistingElements();\n }\n\n public static getInstance(): FxTooltipManager {\n if (!FxTooltipManager.instance) {\n FxTooltipManager.instance = new FxTooltipManager();\n }\n return FxTooltipManager.instance;\n }\n\n private injectStyles(): void {\n if (document.getElementById('fx-tooltip-directive-styles')) return;\n this.injectedStyles = document.createElement('style');\n this.injectedStyles.id = 'fx-tooltip-directive-styles';\n this.injectedStyles.textContent = getTooltipStyles();\n document.head.appendChild(this.injectedStyles);\n }\n\n private observe(): void {\n this.observer = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n if (mutation.type === 'childList') {\n mutation.addedNodes.forEach((node) => {\n if (node instanceof HTMLElement) {\n this.processElement(node);\n node.querySelectorAll<HTMLElement>('[fx-tooltip]').forEach((el) => this.processElement(el));\n }\n });\n }\n if (mutation.type === 'attributes' && mutation.target instanceof HTMLElement) {\n const target = mutation.target;\n if (target.hasAttribute('fx-tooltip')) {\n this.processElement(target);\n } else if (this.behaviors.has(target)) {\n this.removeBehavior(target);\n }\n }\n }\n });\n this.observer.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['fx-tooltip', 'fx-tooltip-position', 'fx-tooltip-html'],\n });\n }\n\n private processExistingElements(): void {\n document.querySelectorAll<HTMLElement>('[fx-tooltip]').forEach((el) => this.processElement(el));\n }\n\n private processElement(element: HTMLElement): void {\n if (!element.hasAttribute('fx-tooltip')) {\n this.removeBehavior(element);\n return;\n }\n if (this.behaviors.has(element)) {\n this.behaviors.get(element)!.update();\n } else {\n this.behaviors.set(element, new TooltipBehavior(element));\n }\n }\n\n private removeBehavior(element: HTMLElement): void {\n const behavior = this.behaviors.get(element);\n if (behavior) {\n behavior.destroy();\n this.behaviors.delete(element);\n }\n }\n\n public destroy(): void {\n if (this.observer) {\n this.observer.disconnect();\n this.observer = null;\n }\n this.behaviors.forEach((behavior) => behavior.destroy());\n this.behaviors.clear();\n if (this.injectedStyles) {\n this.injectedStyles.remove();\n this.injectedStyles = null;\n }\n FxTooltipManager.instance = null;\n }\n}\n\n/**\n * Retorna os estilos CSS para os tooltips.\n */\nfunction getTooltipStyles(): string {\n return /* css */ `\n [fx-tooltip] {\n position: relative;\n }\n\n .fx-tooltip-bubble {\n position: absolute;\n background: var(--fx-text-default, #1e293b);\n color: var(--fx-surface-background, #fff);\n font-family: var(--fx-font-family, system-ui, -apple-system, sans-serif);\n font-size: calc(var(--fx-font-size, 14px) - 2px);\n line-height: 1.45;\n padding: var(--fx-space-xs, 4px) var(--fx-space-md, 12px);\n border-radius: var(--fx-radius-sm, 4px);\n box-shadow: var(--fx-shadow-md, 0 4px 6px -1px rgba(0, 0, 0, 0.1));\n width: max-content;\n min-width: 60px;\n max-width: var(--fx-tooltip-max-width, 320px);\n white-space: normal;\n text-align: center;\n opacity: 0;\n visibility: hidden;\n transition: opacity var(--fx-motion-duration-fast, 150ms) var(--fx-motion-easing, ease);\n z-index: var(--fx-z-tooltip, 1050);\n pointer-events: none;\n }\n\n .fx-tooltip-bubble.fx-tooltip-visible {\n opacity: 1;\n visibility: visible;\n }\n\n .fx-tooltip-top {\n bottom: calc(100% + 6px);\n left: 50%;\n transform: translateX(-50%);\n }\n .fx-tooltip-top::after {\n content: '';\n position: absolute;\n top: 100%;\n left: 50%;\n transform: translateX(-50%);\n border: 5px solid transparent;\n border-top-color: var(--fx-text-default, #1e293b);\n }\n\n .fx-tooltip-bottom {\n top: calc(100% + 6px);\n left: 50%;\n transform: translateX(-50%);\n bottom: auto;\n }\n .fx-tooltip-bottom::after {\n content: '';\n position: absolute;\n bottom: 100%;\n left: 50%;\n transform: translateX(-50%);\n border: 5px solid transparent;\n border-bottom-color: var(--fx-text-default, #1e293b);\n }\n\n .fx-tooltip-left {\n right: calc(100% + 6px);\n top: 50%;\n transform: translateY(-50%);\n left: auto;\n bottom: auto;\n }\n .fx-tooltip-left::after {\n content: '';\n position: absolute;\n top: 50%;\n left: 100%;\n transform: translateY(-50%);\n border: 5px solid transparent;\n border-left-color: var(--fx-text-default, #1e293b);\n }\n\n .fx-tooltip-right {\n left: calc(100% + 6px);\n top: 50%;\n transform: translateY(-50%);\n right: auto;\n bottom: auto;\n }\n .fx-tooltip-right::after {\n content: '';\n position: absolute;\n top: 50%;\n right: 100%;\n transform: translateY(-50%);\n border: 5px solid transparent;\n border-right-color: var(--fx-text-default, #1e293b);\n }\n `;\n}\n\n/**\n * Inicializa a diretiva fx-tooltip.\n * Deve ser chamado uma vez na aplicação.\n *\n * @example\n * import { defineFxTooltipDirective } from '@wrrdev/fenix-ui/tooltip';\n * defineFxTooltipDirective();\n */\nexport function defineFxTooltipDirective(): void {\n if (typeof window === 'undefined') return;\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => {\n FxTooltipManager.getInstance();\n });\n } else {\n FxTooltipManager.getInstance();\n }\n}\n\n/**\n * Destrói a diretiva fx-tooltip e limpa todos os recursos.\n */\nexport function destroyFxTooltipDirective(): void {\n FxTooltipManager.getInstance().destroy();\n}\n\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../src/components/tooltip/index.ts"],"sourcesContent":["import { FxTooltip, defineFxTooltip } from './tooltip';\r\nimport { defineFxTooltipDirective, destroyFxTooltipDirective } from './directive';\r\n\r\nexport { FxTooltip, defineFxTooltipDirective, destroyFxTooltipDirective };\r\n\r\ndefineFxTooltip();\r\n\r\ndeclare global {\r\n interface HTMLElementTagNameMap {\r\n 'fx-tooltip': FxTooltip;\r\n }\r\n}\r\n"],"names":[],"mappings":";;;AAKA,gBAAA;"}
1
+ {"version":3,"file":"index.js","sources":["../../../src/components/tooltip/index.ts"],"sourcesContent":["import { FxTooltip, defineFxTooltip } from './tooltip';\nimport { defineFxTooltipDirective, destroyFxTooltipDirective } from './directive';\n\nexport { FxTooltip, defineFxTooltipDirective, destroyFxTooltipDirective };\n\ndefineFxTooltip();\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'fx-tooltip': FxTooltip;\n }\n}\n"],"names":[],"mappings":";;;AAKA,gBAAA;"}
@@ -1 +1 @@
1
- {"version":3,"file":"tooltip.d.ts","sourceRoot":"","sources":["../../../src/components/tooltip/tooltip.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C;;;;;GAKG;AACH,qBAAa,SAAU,SAAQ,SAAS;IACtC,OAAgB,MAAM,SA6DpB;IAEF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAEjD;cAEkB,MAAM,IAAI,IAAI;CAOlC;AAED,wBAAgB,eAAe,IAAI,OAAO,SAAS,CAElD"}
1
+ {"version":3,"file":"tooltip.d.ts","sourceRoot":"","sources":["../../../src/components/tooltip/tooltip.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAK5C;;;;;GAKG;AACH,qBAAa,SAAU,SAAQ,SAAS;IACtC,OAAgB,MAAM,SA6DpB;IAEF,WAAoB,kBAAkB,IAAI,MAAM,EAAE,CAEjD;cAEkB,MAAM,IAAI,IAAI;CAOlC;AAED,wBAAgB,eAAe,IAAI,OAAO,SAAS,CAElD"}
@@ -1,6 +1,7 @@
1
1
  import { FxElement } from "../../core/base.js";
2
2
  import { css } from "../../core/css.js";
3
3
  import { defineElement } from "../../core/define.js";
4
+ import { esc } from "../../core/sanitize.js";
4
5
  const _FxTooltip = class _FxTooltip extends FxElement {
5
6
  static get observedAttributes() {
6
7
  return ["content", "position"];
@@ -9,7 +10,7 @@ const _FxTooltip = class _FxTooltip extends FxElement {
9
10
  const content = this.getAttr("content");
10
11
  this.setTemplate(`
11
12
  <slot></slot>
12
- <span class="bubble" part="bubble" role="tooltip">${content}</span>
13
+ <span class="bubble" part="bubble" role="tooltip">${esc(content)}</span>
13
14
  `);
14
15
  }
15
16
  };
@@ -1 +1 @@
1
- {"version":3,"file":"tooltip.js","sources":["../../../src/components/tooltip/tooltip.ts"],"sourcesContent":["import { FxElement } from '../../core/base';\nimport { css } from '../../core/css';\nimport { defineElement } from '../../core/define';\n\n/**\n * <fx-tooltip> — Dica flutuante ao passar o mouse/focar no elemento.\n *\n * Atributos: content (texto da dica), position (top|bottom|left|right, padrão top).\n * Slot padrão: elemento que dispara a dica.\n */\nexport class FxTooltip extends FxElement {\n static override styles = css`\n :host {\n position: relative;\n display: inline-flex;\n font-family: var(--fx-font-family);\n }\n .bubble {\n position: absolute;\n background: var(--fx-text-default, #1e293b);\n color: var(--fx-surface-background, #fff);\n font-size: calc(var(--fx-font-size, 14px) - 2px);\n line-height: 1.45;\n padding: var(--fx-space-xs) var(--fx-space-md);\n border-radius: var(--fx-radius-sm);\n box-shadow: var(--fx-shadow-md);\n width: max-content;\n min-width: 60px;\n max-width: var(--fx-tooltip-max-width, 320px);\n white-space: normal;\n text-align: center;\n opacity: 0;\n visibility: hidden;\n transition: opacity var(--fx-motion-duration-fast) var(--fx-motion-easing);\n z-index: var(--fx-z-tooltip, 1050);\n pointer-events: none;\n }\n :host(:hover) .bubble,\n :host(:focus-within) .bubble {\n opacity: 1;\n visibility: visible;\n }\n /* position top (padrão) */\n .bubble { bottom: calc(100% + 6px); left: 50%; transform: translateX(-50%); }\n .bubble::after {\n content: '';\n position: absolute;\n top: 100%;\n left: 50%;\n transform: translateX(-50%);\n border: 5px solid transparent;\n border-top-color: var(--fx-text-default, #1e293b);\n }\n /* bottom */\n :host([position='bottom']) .bubble { bottom: auto; top: calc(100% + 6px); }\n :host([position='bottom']) .bubble::after { top: auto; bottom: 100%; border-top-color: transparent; border-bottom-color: var(--fx-text-default, #1e293b); }\n /* left */\n :host([position='left']) .bubble {\n right: calc(100% + 6px); left: auto; top: 50%; bottom: auto; transform: translateY(-50%);\n }\n :host([position='left']) .bubble::after {\n top: 50%; left: 100%; transform: translateY(-50%);\n border: 5px solid transparent; border-left-color: var(--fx-text-default, #1e293b);\n }\n /* right */\n :host([position='right']) .bubble {\n right: auto; left: calc(100% + 6px); top: 50%; bottom: auto; transform: translateY(-50%);\n }\n :host([position='right']) .bubble::after {\n top: 50%; left: auto; right: 100%; transform: translateY(-50%);\n border: 5px solid transparent; border-right-color: var(--fx-text-default, #1e293b);\n }\n `;\n\n static override get observedAttributes(): string[] {\n return ['content', 'position'];\n }\n\n protected override render(): void {\n const content = this.getAttr('content');\n this.setTemplate(`\n <slot></slot>\n <span class=\"bubble\" part=\"bubble\" role=\"tooltip\">${content}</span>\n `);\n }\n}\n\nexport function defineFxTooltip(): typeof FxTooltip {\n return defineElement('fx-tooltip', FxTooltip);\n}\n"],"names":[],"mappings":";;;AAUO,MAAM,aAAN,MAAM,mBAAkB,UAAU;AAAA,EAgEvC,WAAoB,qBAA+B;AACjD,WAAO,CAAC,WAAW,UAAU;AAAA,EAC/B;AAAA,EAEmB,SAAe;AAChC,UAAM,UAAU,KAAK,QAAQ,SAAS;AACtC,SAAK,YAAY;AAAA;AAAA,0DAEqC,OAAO;AAAA,KAC5D;AAAA,EACH;AACF;AA1EE,WAAgB,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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AADpB,IAAM,YAAN;AA6EA,SAAS,kBAAoC;AAClD,SAAO,cAAc,cAAc,SAAS;AAC9C;"}
1
+ {"version":3,"file":"tooltip.js","sources":["../../../src/components/tooltip/tooltip.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-tooltip> — Dica flutuante ao passar o mouse/focar no elemento.\n *\n * Atributos: content (texto da dica), position (top|bottom|left|right, padrão top).\n * Slot padrão: elemento que dispara a dica.\n */\nexport class FxTooltip extends FxElement {\n static override styles = css`\n :host {\n position: relative;\n display: inline-flex;\n font-family: var(--fx-font-family);\n }\n .bubble {\n position: absolute;\n background: var(--fx-text-default, #1e293b);\n color: var(--fx-surface-background, #fff);\n font-size: calc(var(--fx-font-size, 14px) - 2px);\n line-height: 1.45;\n padding: var(--fx-space-xs) var(--fx-space-md);\n border-radius: var(--fx-radius-sm);\n box-shadow: var(--fx-shadow-md);\n width: max-content;\n min-width: 60px;\n max-width: var(--fx-tooltip-max-width, 320px);\n white-space: normal;\n text-align: center;\n opacity: 0;\n visibility: hidden;\n transition: opacity var(--fx-motion-duration-fast) var(--fx-motion-easing);\n z-index: var(--fx-z-tooltip, 1050);\n pointer-events: none;\n }\n :host(:hover) .bubble,\n :host(:focus-within) .bubble {\n opacity: 1;\n visibility: visible;\n }\n /* position top (padrão) */\n .bubble { bottom: calc(100% + 6px); left: 50%; transform: translateX(-50%); }\n .bubble::after {\n content: '';\n position: absolute;\n top: 100%;\n left: 50%;\n transform: translateX(-50%);\n border: 5px solid transparent;\n border-top-color: var(--fx-text-default, #1e293b);\n }\n /* bottom */\n :host([position='bottom']) .bubble { bottom: auto; top: calc(100% + 6px); }\n :host([position='bottom']) .bubble::after { top: auto; bottom: 100%; border-top-color: transparent; border-bottom-color: var(--fx-text-default, #1e293b); }\n /* left */\n :host([position='left']) .bubble {\n right: calc(100% + 6px); left: auto; top: 50%; bottom: auto; transform: translateY(-50%);\n }\n :host([position='left']) .bubble::after {\n top: 50%; left: 100%; transform: translateY(-50%);\n border: 5px solid transparent; border-left-color: var(--fx-text-default, #1e293b);\n }\n /* right */\n :host([position='right']) .bubble {\n right: auto; left: calc(100% + 6px); top: 50%; bottom: auto; transform: translateY(-50%);\n }\n :host([position='right']) .bubble::after {\n top: 50%; left: auto; right: 100%; transform: translateY(-50%);\n border: 5px solid transparent; border-right-color: var(--fx-text-default, #1e293b);\n }\n `;\n\n static override get observedAttributes(): string[] {\n return ['content', 'position'];\n }\n\n protected override render(): void {\n const content = this.getAttr('content');\n this.setTemplate(`\n <slot></slot>\n <span class=\"bubble\" part=\"bubble\" role=\"tooltip\">${esc(content)}</span>\n `);\n }\n}\n\nexport function defineFxTooltip(): typeof FxTooltip {\n return defineElement('fx-tooltip', FxTooltip);\n}\n"],"names":[],"mappings":";;;;AAWO,MAAM,aAAN,MAAM,mBAAkB,UAAU;AAAA,EAgEvC,WAAoB,qBAA+B;AACjD,WAAO,CAAC,WAAW,UAAU;AAAA,EAC/B;AAAA,EAEmB,SAAe;AAChC,UAAM,UAAU,KAAK,QAAQ,SAAS;AACtC,SAAK,YAAY;AAAA;AAAA,0DAEqC,IAAI,OAAO,CAAC;AAAA,KACjE;AAAA,EACH;AACF;AA1EE,WAAgB,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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AADpB,IAAM,YAAN;AA6EA,SAAS,kBAAoC;AAClD,SAAO,cAAc,cAAc,SAAS;AAC9C;"}
@@ -1 +1 @@
1
- {"version":3,"file":"jsx.js","sources":["../../src/core/jsx.ts"],"sourcesContent":["/**\r\n * Tipagens de propriedades + augmentations JSX do FenixUI.\r\n *\r\n * Importar este módulo — diretamente (`@wrrdev/fenix-ui/jsx`) ou via o\r\n * índice principal (`@wrrdev/fenix-ui`) — habilita, no TypeScript:\r\n *\r\n * 1. autocomplete + validação de atributos em templates JSX/TSX;\r\n * 2. tipos nomeados (`FxButtonProps`, `FxInputProps`, …) para wrappers ou código imperativo.\r\n *\r\n * A biblioteca NÃO depende de React/Vue: os atributos comuns\r\n * (`className`, `onClick`, `style`, `children`, …) são aceitos via assinatura\r\n * de índice, funcionando com qualquer runtime JSX.\r\n */\r\n\r\nimport type { FxElementProps, FxSize } from './types';\r\n\r\n/** Marcador de runtime: permite `import '@wrrdev/fenix-ui/jsx'` como side-effect import. */\r\nexport const FX_JSX_TYPES = true as const;\r\n\r\n/* Uniões auxiliares (variants, enums) */\r\nexport type FxButtonVariant = 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | 'ghost' | 'outline';\r\nexport type FxBadgeVariant = 'default' | 'primary' | 'success' | 'warning' | 'danger' | 'info';\r\nexport type FxAlertVariant = 'info' | 'success' | 'warning' | 'danger';\r\nexport type FxProgressVariant = 'primary' | 'success' | 'warning' | 'danger';\r\nexport type FxSkeletonVariant = 'text' | 'circle' | 'rect';\r\nexport type FxFloatlabelVariant = 'on' | 'in' | 'over';\r\nexport type FxInputType = 'text' | 'number' | 'email' | 'password' | 'search' | 'tel' | 'url';\r\nexport type FxFieldStatus = 'error' | 'invalid' | 'success' | 'valid';\r\nexport type FxToastKind = 'success' | 'error' | 'info' | 'warning';\r\nexport type FxToastPosition = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';\r\nexport type FxTooltipPosition = 'top' | 'bottom' | 'left' | 'right';\r\nexport type FxDrawerPosition = 'left' | 'right' | 'top' | 'bottom';\r\nexport type FxDropdownPosition = 'left' | 'center' | 'right' | 'bottom-left' | 'bottom-right';\r\nexport type FxPaginationPosition = 'left' | 'center' | 'right';\r\n\r\n/* Props por componente */\r\nexport interface FxButtonProps extends FxElementProps {\r\n variant?: FxButtonVariant;\r\n type?: 'button' | 'submit' | 'reset';\r\n size?: FxSize;\r\n loading?: boolean;\r\n full?: boolean;\r\n}\r\nexport interface FxBadgeProps extends FxElementProps {\r\n variant?: FxBadgeVariant;\r\n round?: boolean;\r\n}\r\nexport interface FxSpinnerProps extends FxElementProps { size?: FxSize; }\r\nexport interface FxInputProps extends FxElementProps {\r\n type?: FxInputType;\r\n size?: FxSize;\r\n placeholder?: string;\r\n readonly?: boolean;\r\n min?: string | number;\r\n max?: string | number;\r\n step?: string | number;\r\n clearable?: boolean;\r\n error?: boolean;\r\n invalid?: boolean;\r\n success?: boolean;\r\n valid?: boolean;\r\n}\r\nexport interface FxSelectProps extends FxElementProps {\r\n value?: string;\r\n size?: FxSize;\r\n placeholder?: string;\r\n searchable?: boolean;\r\n clearable?: boolean;\r\n 'search-placeholder'?: string;\r\n 'no-results'?: string;\r\n error?: boolean;\r\n invalid?: boolean;\r\n success?: boolean;\r\n valid?: boolean;\r\n}\r\nexport interface FxSwitchProps extends FxElementProps { checked?: boolean; size?: FxSize; }\r\nexport interface FxCheckboxProps extends FxElementProps {\r\n checked?: boolean;\r\n indeterminate?: boolean;\r\n value?: string;\r\n size?: FxSize;\r\n}\r\nexport interface FxRadioProps extends FxElementProps {\r\n checked?: boolean;\r\n value?: string;\r\n name?: string;\r\n size?: FxSize;\r\n}\r\nexport interface FxTextareaProps extends FxElementProps {\r\n value?: string;\r\n size?: FxSize;\r\n placeholder?: string;\r\n readonly?: boolean;\r\n rows?: number;\r\n maxlength?: number;\r\n error?: boolean;\r\n invalid?: boolean;\r\n success?: boolean;\r\n valid?: boolean;\r\n}\r\nexport interface FxMultiselectProps extends FxElementProps {\r\n values?: string;\r\n size?: FxSize;\r\n placeholder?: string;\r\n searchable?: boolean;\r\n clearable?: boolean;\r\n open?: boolean;\r\n error?: boolean;\r\n invalid?: boolean;\r\n success?: boolean;\r\n valid?: boolean;\r\n}\r\nexport interface FxCalendarProps extends FxElementProps {\r\n value?: string;\r\n start?: string;\r\n end?: string;\r\n min?: string;\r\n max?: string;\r\n mode?: 'single' | 'range' | 'multiple';\r\n values?: string;\r\n locale?: string;\r\n disabled?: boolean;\r\n}\r\nexport interface FxDatepickerProps extends FxElementProps {\r\n value?: string;\r\n start?: string;\r\n end?: string;\r\n values?: string;\r\n mode?: 'single' | 'range' | 'multiple';\r\n min?: string;\r\n max?: string;\r\n placeholder?: string;\r\n size?: FxSize;\r\n format?: string;\r\n 'show-time'?: boolean;\r\n 'free-text'?: boolean;\r\n clearable?: boolean;\r\n error?: boolean;\r\n invalid?: boolean;\r\n success?: boolean;\r\n valid?: boolean;\r\n}\r\nexport interface FxTableProps extends FxElementProps {\r\n pagination?: boolean;\r\n rows?: number;\r\n 'rows-options'?: string;\r\n striped?: boolean;\r\n 'empty-message'?: string;\r\n 'pagination-position'?: FxPaginationPosition;\r\n total?: number;\r\n page?: number;\r\n}\r\nexport interface FxFloatlabelProps extends FxElementProps {\r\n variant?: FxFloatlabelVariant;\r\n error?: boolean;\r\n invalid?: boolean;\r\n success?: boolean;\r\n valid?: boolean;\r\n active?: boolean;\r\n 'error-text'?: string;\r\n}\r\nexport interface FxDialogProps extends FxElementProps { open?: boolean; size?: FxSize; heading?: string; }\r\nexport interface FxDrawerProps extends FxElementProps { open?: boolean; title?: string; position?: FxDrawerPosition; }\r\nexport interface FxToastProps extends FxElementProps {\r\n kind?: FxToastKind;\r\n title?: string;\r\n message?: string;\r\n duration?: number;\r\n position?: FxToastPosition;\r\n}\r\nexport interface FxTooltipProps extends FxElementProps { content?: string; position?: FxTooltipPosition; }\r\nexport interface FxTabsProps extends FxElementProps { value?: string; }\r\nexport interface FxTabPanelProps extends FxElementProps { tab?: string; hidden?: boolean; }\r\nexport interface FxProgressProps extends FxElementProps {\r\n value?: number;\r\n indeterminate?: boolean;\r\n variant?: FxProgressVariant;\r\n label?: string;\r\n 'hide-label'?: boolean;\r\n size?: FxSize;\r\n}\r\nexport interface FxSkeletonProps extends FxElementProps {\r\n variant?: FxSkeletonVariant;\r\n width?: string;\r\n height?: string;\r\n lines?: number;\r\n}\r\nexport interface FxAlertProps extends FxElementProps { variant?: FxAlertVariant; title?: string; dismissible?: boolean; }\r\nexport interface FxDropdownProps extends FxElementProps { label?: string; position?: FxDropdownPosition; open?: boolean; }\r\nexport interface FxDropdownItemProps extends FxElementProps { value?: string; }\r\nexport interface FxPaginationProps extends FxElementProps {\r\n page?: number;\r\n total?: number;\r\n rows?: number;\r\n 'rows-options'?: string;\r\n position?: FxPaginationPosition;\r\n}\r\nexport interface FxAutocompleteProps extends FxElementProps {\r\n value?: string;\r\n size?: FxSize;\r\n placeholder?: string;\r\n source?: string;\r\n disabled?: boolean;\r\n 'min-chars'?: number;\r\n}\r\n/* Augmentation global de JSX (React/TSX, Preact, Vue JSX, …).\r\n Cada tag fx-* recebe autocomplete + validação de atributos. */\r\ndeclare global {\r\n namespace JSX {\r\n interface IntrinsicElements {\r\n 'fx-button': FxButtonProps;\r\n 'fx-badge': FxBadgeProps;\r\n 'fx-spinner': FxSpinnerProps;\r\n 'fx-input': FxInputProps;\r\n 'fx-select': FxSelectProps;\r\n 'fx-switch': FxSwitchProps;\r\n 'fx-checkbox': FxCheckboxProps;\r\n 'fx-radio': FxRadioProps;\r\n 'fx-textarea': FxTextareaProps;\r\n 'fx-multiselect': FxMultiselectProps;\r\n 'fx-calendar': FxCalendarProps;\r\n 'fx-datepicker': FxDatepickerProps;\r\n 'fx-table': FxTableProps;\r\n 'fx-floatlabel': FxFloatlabelProps;\r\n 'fx-dialog': FxDialogProps;\r\n 'fx-drawer': FxDrawerProps;\r\n 'fx-toast': FxToastProps;\r\n 'fx-tooltip': FxTooltipProps;\r\n 'fx-tabs': FxTabsProps;\r\n 'fx-tab-panel': FxTabPanelProps;\r\n 'fx-progress': FxProgressProps;\r\n 'fx-skeleton': FxSkeletonProps;\r\n 'fx-alert': FxAlertProps;\r\n 'fx-dropdown': FxDropdownProps;\r\n 'fx-dropdown-item': FxDropdownItemProps;\r\n 'fx-pagination': FxPaginationProps;\r\n 'fx-autocomplete': FxAutocompleteProps;\r\n }\r\n }\r\n}\r\n\r\n/* Tipagem imperativa: document.createElement('fx-...').\r\n As tags abaixo não declaradas nos próprios componentes ganham tipagem aqui;\r\n as demais (alert, dialog, drawer, dropdown, pagination, progress, skeleton,\r\n tabs, textarea, toast, tooltip, autocomplete) já são tipadas com a classe\r\n concreta nos respectivos index.ts. */\r\ndeclare global {\r\n interface HTMLElementTagNameMap {\r\n 'fx-button': HTMLElement;\r\n 'fx-badge': HTMLElement;\r\n 'fx-spinner': HTMLElement;\r\n 'fx-input': HTMLElement;\r\n 'fx-select': HTMLElement;\r\n 'fx-switch': HTMLElement;\r\n 'fx-checkbox': HTMLElement;\r\n 'fx-radio': HTMLElement;\r\n 'fx-multiselect': HTMLElement;\r\n 'fx-calendar': HTMLElement;\r\n 'fx-datepicker': HTMLElement;\r\n 'fx-table': HTMLElement;\r\n 'fx-floatlabel': HTMLElement;\r\n }\r\n}\r\n"],"names":[],"mappings":"AAiBO,MAAM,eAAe;"}
1
+ {"version":3,"file":"jsx.js","sources":["../../src/core/jsx.ts"],"sourcesContent":["/**\n * Tipagens de propriedades + augmentations JSX do FenixUI.\n *\n * Importar este módulo — diretamente (`@wrrdev/fenix-ui/jsx`) ou via o\n * índice principal (`@wrrdev/fenix-ui`) — habilita, no TypeScript:\n *\n * 1. autocomplete + validação de atributos em templates JSX/TSX;\n * 2. tipos nomeados (`FxButtonProps`, `FxInputProps`, …) para wrappers ou código imperativo.\n *\n * A biblioteca NÃO depende de React/Vue: os atributos comuns\n * (`className`, `onClick`, `style`, `children`, …) são aceitos via assinatura\n * de índice, funcionando com qualquer runtime JSX.\n */\n\nimport type { FxElementProps, FxSize } from './types';\n\n/** Marcador de runtime: permite `import '@wrrdev/fenix-ui/jsx'` como side-effect import. */\nexport const FX_JSX_TYPES = true as const;\n\n/* Uniões auxiliares (variants, enums) */\nexport type FxButtonVariant = 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | 'ghost' | 'outline';\nexport type FxBadgeVariant = 'default' | 'primary' | 'success' | 'warning' | 'danger' | 'info';\nexport type FxAlertVariant = 'info' | 'success' | 'warning' | 'danger';\nexport type FxProgressVariant = 'primary' | 'success' | 'warning' | 'danger';\nexport type FxSkeletonVariant = 'text' | 'circle' | 'rect';\nexport type FxFloatlabelVariant = 'on' | 'in' | 'over';\nexport type FxInputType = 'text' | 'number' | 'email' | 'password' | 'search' | 'tel' | 'url';\nexport type FxFieldStatus = 'error' | 'invalid' | 'success' | 'valid';\nexport type FxToastKind = 'success' | 'error' | 'info' | 'warning';\nexport type FxToastPosition = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';\nexport type FxTooltipPosition = 'top' | 'bottom' | 'left' | 'right';\nexport type FxDrawerPosition = 'left' | 'right' | 'top' | 'bottom';\nexport type FxDropdownPosition = 'left' | 'center' | 'right' | 'bottom-left' | 'bottom-right';\nexport type FxPaginationPosition = 'left' | 'center' | 'right';\n\n/* Props por componente */\nexport interface FxButtonProps extends FxElementProps {\n variant?: FxButtonVariant;\n type?: 'button' | 'submit' | 'reset';\n size?: FxSize;\n loading?: boolean;\n full?: boolean;\n}\nexport interface FxBadgeProps extends FxElementProps {\n variant?: FxBadgeVariant;\n round?: boolean;\n}\nexport interface FxSpinnerProps extends FxElementProps { size?: FxSize; }\nexport interface FxInputProps extends FxElementProps {\n type?: FxInputType;\n size?: FxSize;\n placeholder?: string;\n readonly?: boolean;\n min?: string | number;\n max?: string | number;\n step?: string | number;\n clearable?: boolean;\n error?: boolean;\n invalid?: boolean;\n success?: boolean;\n valid?: boolean;\n}\nexport interface FxSelectProps extends FxElementProps {\n value?: string;\n size?: FxSize;\n placeholder?: string;\n searchable?: boolean;\n clearable?: boolean;\n 'search-placeholder'?: string;\n 'no-results'?: string;\n error?: boolean;\n invalid?: boolean;\n success?: boolean;\n valid?: boolean;\n}\nexport interface FxSwitchProps extends FxElementProps { checked?: boolean; size?: FxSize; }\nexport interface FxCheckboxProps extends FxElementProps {\n checked?: boolean;\n indeterminate?: boolean;\n value?: string;\n size?: FxSize;\n}\nexport interface FxRadioProps extends FxElementProps {\n checked?: boolean;\n value?: string;\n name?: string;\n size?: FxSize;\n}\nexport interface FxTextareaProps extends FxElementProps {\n value?: string;\n size?: FxSize;\n placeholder?: string;\n readonly?: boolean;\n rows?: number;\n maxlength?: number;\n error?: boolean;\n invalid?: boolean;\n success?: boolean;\n valid?: boolean;\n}\nexport interface FxMultiselectProps extends FxElementProps {\n values?: string;\n size?: FxSize;\n placeholder?: string;\n searchable?: boolean;\n clearable?: boolean;\n open?: boolean;\n error?: boolean;\n invalid?: boolean;\n success?: boolean;\n valid?: boolean;\n}\nexport interface FxCalendarProps extends FxElementProps {\n value?: string;\n start?: string;\n end?: string;\n min?: string;\n max?: string;\n mode?: 'single' | 'range' | 'multiple';\n values?: string;\n locale?: string;\n disabled?: boolean;\n}\nexport interface FxDatepickerProps extends FxElementProps {\n value?: string;\n start?: string;\n end?: string;\n values?: string;\n mode?: 'single' | 'range' | 'multiple';\n min?: string;\n max?: string;\n placeholder?: string;\n size?: FxSize;\n format?: string;\n 'show-time'?: boolean;\n 'free-text'?: boolean;\n clearable?: boolean;\n error?: boolean;\n invalid?: boolean;\n success?: boolean;\n valid?: boolean;\n}\nexport interface FxTableProps extends FxElementProps {\n pagination?: boolean;\n rows?: number;\n 'rows-options'?: string;\n striped?: boolean;\n 'empty-message'?: string;\n 'pagination-position'?: FxPaginationPosition;\n total?: number;\n page?: number;\n}\nexport interface FxFloatlabelProps extends FxElementProps {\n variant?: FxFloatlabelVariant;\n error?: boolean;\n invalid?: boolean;\n success?: boolean;\n valid?: boolean;\n active?: boolean;\n 'error-text'?: string;\n}\nexport interface FxDialogProps extends FxElementProps { open?: boolean; size?: FxSize; heading?: string; }\nexport interface FxDrawerProps extends FxElementProps { open?: boolean; title?: string; position?: FxDrawerPosition; }\nexport interface FxToastProps extends FxElementProps {\n kind?: FxToastKind;\n title?: string;\n message?: string;\n duration?: number;\n position?: FxToastPosition;\n}\nexport interface FxTooltipProps extends FxElementProps { content?: string; position?: FxTooltipPosition; }\nexport interface FxTabsProps extends FxElementProps { value?: string; }\nexport interface FxTabPanelProps extends FxElementProps { tab?: string; hidden?: boolean; }\nexport interface FxProgressProps extends FxElementProps {\n value?: number;\n indeterminate?: boolean;\n variant?: FxProgressVariant;\n label?: string;\n 'hide-label'?: boolean;\n size?: FxSize;\n}\nexport interface FxSkeletonProps extends FxElementProps {\n variant?: FxSkeletonVariant;\n width?: string;\n height?: string;\n lines?: number;\n}\nexport interface FxAlertProps extends FxElementProps { variant?: FxAlertVariant; title?: string; dismissible?: boolean; }\nexport interface FxDropdownProps extends FxElementProps { label?: string; position?: FxDropdownPosition; open?: boolean; }\nexport interface FxDropdownItemProps extends FxElementProps { value?: string; }\nexport interface FxPaginationProps extends FxElementProps {\n page?: number;\n total?: number;\n rows?: number;\n 'rows-options'?: string;\n position?: FxPaginationPosition;\n}\nexport interface FxAutocompleteProps extends FxElementProps {\n value?: string;\n size?: FxSize;\n placeholder?: string;\n source?: string;\n disabled?: boolean;\n 'min-chars'?: number;\n}\n/* Augmentation global de JSX (React/TSX, Preact, Vue JSX, …).\n Cada tag fx-* recebe autocomplete + validação de atributos. */\ndeclare global {\n namespace JSX {\n interface IntrinsicElements {\n 'fx-button': FxButtonProps;\n 'fx-badge': FxBadgeProps;\n 'fx-spinner': FxSpinnerProps;\n 'fx-input': FxInputProps;\n 'fx-select': FxSelectProps;\n 'fx-switch': FxSwitchProps;\n 'fx-checkbox': FxCheckboxProps;\n 'fx-radio': FxRadioProps;\n 'fx-textarea': FxTextareaProps;\n 'fx-multiselect': FxMultiselectProps;\n 'fx-calendar': FxCalendarProps;\n 'fx-datepicker': FxDatepickerProps;\n 'fx-table': FxTableProps;\n 'fx-floatlabel': FxFloatlabelProps;\n 'fx-dialog': FxDialogProps;\n 'fx-drawer': FxDrawerProps;\n 'fx-toast': FxToastProps;\n 'fx-tooltip': FxTooltipProps;\n 'fx-tabs': FxTabsProps;\n 'fx-tab-panel': FxTabPanelProps;\n 'fx-progress': FxProgressProps;\n 'fx-skeleton': FxSkeletonProps;\n 'fx-alert': FxAlertProps;\n 'fx-dropdown': FxDropdownProps;\n 'fx-dropdown-item': FxDropdownItemProps;\n 'fx-pagination': FxPaginationProps;\n 'fx-autocomplete': FxAutocompleteProps;\n }\n }\n}\n\n/* Tipagem imperativa: document.createElement('fx-...').\n As tags abaixo não declaradas nos próprios componentes ganham tipagem aqui;\n as demais (alert, dialog, drawer, dropdown, pagination, progress, skeleton,\n tabs, textarea, toast, tooltip, autocomplete) já são tipadas com a classe\n concreta nos respectivos index.ts. */\ndeclare global {\n interface HTMLElementTagNameMap {\n 'fx-button': HTMLElement;\n 'fx-badge': HTMLElement;\n 'fx-spinner': HTMLElement;\n 'fx-input': HTMLElement;\n 'fx-select': HTMLElement;\n 'fx-switch': HTMLElement;\n 'fx-checkbox': HTMLElement;\n 'fx-radio': HTMLElement;\n 'fx-multiselect': HTMLElement;\n 'fx-calendar': HTMLElement;\n 'fx-datepicker': HTMLElement;\n 'fx-table': HTMLElement;\n 'fx-floatlabel': HTMLElement;\n }\n}\n"],"names":[],"mappings":"AAiBO,MAAM,eAAe;"}
@@ -1 +1 @@
1
- {"version":3,"file":"presets.js","sources":["../../src/core/presets.ts"],"sourcesContent":["/**\r\n * Presets de tema prontos para uso.\r\n *\r\n * Cada preset é um override parcial profundo sobre os tokens base.\r\n * Combina com o modo claro/escuro: `applyPreset('seiya', 'dark')`.\r\n */\r\n\r\nimport { configure } from './theme';\r\nimport { type DeepPartial, type FenixTokens } from './tokens';\r\n\r\nexport interface FenixPreset {\r\n /** Identificador usado em `applyPreset(name)`. */\r\n name: string;\r\n /** Rótulo amigável para UIs (documentação/seletor). */\r\n label: string;\r\n /** Override parcial de tokens aplicado sobre o tema base. */\r\n tokens: DeepPartial<FenixTokens>;\r\n}\r\n\r\nconst registry = new Map<string, FenixPreset>();\r\n\r\nfunction register(preset: FenixPreset): FenixPreset {\r\n registry.set(preset.name, preset);\r\n return preset;\r\n}\r\n\r\n/* ------------------------------------------------------------------ */\r\n/* Cavaleiros do Zodíaco ✨ */\r\n/* ------------------------------------------------------------------ */\r\n\r\nexport const themePresets = {\r\n\tfenix: register({\r\n\t\tname: \"fenix\",\r\n\t\tlabel: \"Fenix (padrão)\",\r\n\t\ttokens: {},\r\n\t}),\r\n\tseiya: register({\r\n\t\tname: \"seiya\",\r\n\t\tlabel: \"Seiya\",\r\n\t\ttokens: {\r\n\t\t\tcolor: {\r\n\t\t\t\tprimary: \"#e11d48\",\r\n\t\t\t\tsecondary: \"#fb7185\",\r\n\t\t\t\tinfo: \"#f43f5e\",\r\n\t\t\t\tdanger: \"#be123c\",\r\n\t\t\t},\r\n\t\t\tradius: { sm: \"6px\", md: \"10px\", lg: \"16px\" },\r\n\t\t\teffect: {\r\n\t\t\t\t\"focus-ring\": \"none\",\r\n\t\t\t},\r\n\t\t},\r\n\t}),\r\n\tshiryu: register({\r\n\t\tname: \"shiryu\",\r\n\t\tlabel: \"Shiryu\",\r\n\t\ttokens: {\r\n\t\t\tcolor: {\r\n\t\t\t\tprimary: \"#0d9488\",\r\n\t\t\t\tsecondary: \"#2dd4bf\",\r\n\t\t\t\tsuccess: \"#059669\",\r\n\t\t\t\tinfo: \"#14b8a6\",\r\n\t\t\t},\r\n\t\t\tradius: { sm: \"4px\", md: \"8px\", lg: \"14px\" },\r\n\t\t\teffect: {\r\n\t\t\t\t\"focus-ring\": \"none\",\r\n\t\t\t},\r\n\t\t},\r\n\t}),\r\n\thyoga: register({\r\n\t\tname: \"hyoga\",\r\n\t\tlabel: \"Hyoga\",\r\n\t\ttokens: {\r\n\t\t\tcolor: {\r\n\t\t\t\tprimary: \"#0284c7\",\r\n\t\t\t\tsecondary: \"#38bdf8\",\r\n\t\t\t\tinfo: \"#06b6d4\",\r\n\t\t\t\tdanger: \"#e11d48\",\r\n\t\t\t},\r\n\t\t\tsurface: { surface: \"#f0f9ff\", \"surface-hover\": \"#e0f2fe\" },\r\n\t\t\tradius: { sm: \"8px\", md: \"12px\", lg: \"18px\" },\r\n\t\t},\r\n\t}),\r\n\tshun: register({\r\n\t\tname: \"shun\",\r\n\t\tlabel: \"Shun\",\r\n\t\ttokens: {\r\n\t\t\tcolor: {\r\n\t\t\t\tprimary: \"#db2777\",\r\n\t\t\t\tsecondary: \"#f472b6\",\r\n\t\t\t\tinfo: \"#ec4899\",\r\n\t\t\t\twarning: \"#c026d3\",\r\n\t\t\t},\r\n\t\t\tradius: { sm: \"10px\", md: \"14px\", lg: \"20px\" },\r\n\t\t},\r\n\t}),\r\n\tikki: register({\r\n\t\tname: \"ikki\",\r\n\t\tlabel: \"Ikki\",\r\n\t\ttokens: {\r\n\t\t\tcolor: {\r\n\t\t\t\tprimary: \"#ea580c\",\r\n\t\t\t\tsecondary: \"#fb923c\",\r\n\t\t\t\tdanger: \"#dc2626\",\r\n\t\t\t\twarning: \"#f59e0b\",\r\n\t\t\t},\r\n\t\t\tradius: { sm: \"2px\", md: \"4px\", lg: \"6px\" },\r\n\t\t},\r\n\t}),\r\n\taiolia: register({\r\n\t\tname: \"aiolia\",\r\n\t\tlabel: \"Aiolia\",\r\n\t\ttokens: {\r\n\t\t\tcolor: {\r\n\t\t\t\tprimary: \"#b45309\",\r\n\t\t\t\tsecondary: \"#f59e0b\",\r\n\t\t\t\twarning: \"#eab308\",\r\n\t\t\t\tinfo: \"#84cc16\",\r\n\t\t\t},\r\n\t\t\tradius: { sm: \"6px\", md: \"12px\", lg: \"20px\" },\r\n\t\t\teffect: {\r\n\t\t\t\t\"focus-ring\": \"none\",\r\n\t\t\t},\r\n\t\t},\r\n\t}),\r\n} as const;\r\n\r\n/** Lista todos os presets registrados (inclui os customizados). */\r\nexport function listPresets(): FenixPreset[] {\r\n return [...registry.values()];\r\n}\r\n\r\n/**\r\n * Registra um preset personalizado, tornando-o disponível em `applyPreset`.\r\n * Útil para o usuário criar seu próprio tema e reutilizá-lo na aplicação.\r\n */\r\nexport function defineCustomPreset(\r\n name: string,\r\n label: string,\r\n tokens: DeepPartial<FenixTokens>,\r\n): FenixPreset {\r\n return register({ name, label, tokens });\r\n}\r\n\r\n/**\r\n * Aplica um preset + modo de cor em runtime.\r\n * @returns o estado ativo ({ theme }) repassado por `configure`.\r\n */\r\nexport function applyPreset(\r\n presetName: string,\r\n mode: 'light' | 'dark' = 'light',\r\n): { theme: 'light' | 'dark'; preset: string } {\r\n const preset = registry.get(presetName) ?? registry.get('fenix')!;\r\n const state = configure({ theme: mode, tokens: preset.tokens });\r\n return { ...state, preset: preset.name };\r\n}"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"presets.js","sources":["../../src/core/presets.ts"],"sourcesContent":["/**\n * Presets de tema prontos para uso.\n *\n * Cada preset é um override parcial profundo sobre os tokens base.\n * Combina com o modo claro/escuro: `applyPreset('seiya', 'dark')`.\n */\n\nimport { configure } from './theme';\nimport { type DeepPartial, type FenixTokens } from './tokens';\n\nexport interface FenixPreset {\n /** Identificador usado em `applyPreset(name)`. */\n name: string;\n /** Rótulo amigável para UIs (documentação/seletor). */\n label: string;\n /** Override parcial de tokens aplicado sobre o tema base. */\n tokens: DeepPartial<FenixTokens>;\n}\n\nconst registry = new Map<string, FenixPreset>();\n\nfunction register(preset: FenixPreset): FenixPreset {\n registry.set(preset.name, preset);\n return preset;\n}\n\n/* ------------------------------------------------------------------ */\n/* Cavaleiros do Zodíaco ✨ */\n/* ------------------------------------------------------------------ */\n\nexport const themePresets = {\n\tfenix: register({\n\t\tname: \"fenix\",\n\t\tlabel: \"Fenix (padrão)\",\n\t\ttokens: {},\n\t}),\n\tseiya: register({\n\t\tname: \"seiya\",\n\t\tlabel: \"Seiya\",\n\t\ttokens: {\n\t\t\tcolor: {\n\t\t\t\tprimary: \"#e11d48\",\n\t\t\t\tsecondary: \"#fb7185\",\n\t\t\t\tinfo: \"#f43f5e\",\n\t\t\t\tdanger: \"#be123c\",\n\t\t\t},\n\t\t\tradius: { sm: \"6px\", md: \"10px\", lg: \"16px\" },\n\t\t\teffect: {\n\t\t\t\t\"focus-ring\": \"none\",\n\t\t\t},\n\t\t},\n\t}),\n\tshiryu: register({\n\t\tname: \"shiryu\",\n\t\tlabel: \"Shiryu\",\n\t\ttokens: {\n\t\t\tcolor: {\n\t\t\t\tprimary: \"#0d9488\",\n\t\t\t\tsecondary: \"#2dd4bf\",\n\t\t\t\tsuccess: \"#059669\",\n\t\t\t\tinfo: \"#14b8a6\",\n\t\t\t},\n\t\t\tradius: { sm: \"4px\", md: \"8px\", lg: \"14px\" },\n\t\t\teffect: {\n\t\t\t\t\"focus-ring\": \"none\",\n\t\t\t},\n\t\t},\n\t}),\n\thyoga: register({\n\t\tname: \"hyoga\",\n\t\tlabel: \"Hyoga\",\n\t\ttokens: {\n\t\t\tcolor: {\n\t\t\t\tprimary: \"#0284c7\",\n\t\t\t\tsecondary: \"#38bdf8\",\n\t\t\t\tinfo: \"#06b6d4\",\n\t\t\t\tdanger: \"#e11d48\",\n\t\t\t},\n\t\t\tsurface: { surface: \"#f0f9ff\", \"surface-hover\": \"#e0f2fe\" },\n\t\t\tradius: { sm: \"8px\", md: \"12px\", lg: \"18px\" },\n\t\t},\n\t}),\n\tshun: register({\n\t\tname: \"shun\",\n\t\tlabel: \"Shun\",\n\t\ttokens: {\n\t\t\tcolor: {\n\t\t\t\tprimary: \"#db2777\",\n\t\t\t\tsecondary: \"#f472b6\",\n\t\t\t\tinfo: \"#ec4899\",\n\t\t\t\twarning: \"#c026d3\",\n\t\t\t},\n\t\t\tradius: { sm: \"10px\", md: \"14px\", lg: \"20px\" },\n\t\t},\n\t}),\n\tikki: register({\n\t\tname: \"ikki\",\n\t\tlabel: \"Ikki\",\n\t\ttokens: {\n\t\t\tcolor: {\n\t\t\t\tprimary: \"#ea580c\",\n\t\t\t\tsecondary: \"#fb923c\",\n\t\t\t\tdanger: \"#dc2626\",\n\t\t\t\twarning: \"#f59e0b\",\n\t\t\t},\n\t\t\tradius: { sm: \"2px\", md: \"4px\", lg: \"6px\" },\n\t\t},\n\t}),\n\taiolia: register({\n\t\tname: \"aiolia\",\n\t\tlabel: \"Aiolia\",\n\t\ttokens: {\n\t\t\tcolor: {\n\t\t\t\tprimary: \"#b45309\",\n\t\t\t\tsecondary: \"#f59e0b\",\n\t\t\t\twarning: \"#eab308\",\n\t\t\t\tinfo: \"#84cc16\",\n\t\t\t},\n\t\t\tradius: { sm: \"6px\", md: \"12px\", lg: \"20px\" },\n\t\t\teffect: {\n\t\t\t\t\"focus-ring\": \"none\",\n\t\t\t},\n\t\t},\n\t}),\n} as const;\n\n/** Lista todos os presets registrados (inclui os customizados). */\nexport function listPresets(): FenixPreset[] {\n return [...registry.values()];\n}\n\n/**\n * Registra um preset personalizado, tornando-o disponível em `applyPreset`.\n * Útil para o usuário criar seu próprio tema e reutilizá-lo na aplicação.\n */\nexport function defineCustomPreset(\n name: string,\n label: string,\n tokens: DeepPartial<FenixTokens>,\n): FenixPreset {\n return register({ name, label, tokens });\n}\n\n/**\n * Aplica um preset + modo de cor em runtime.\n * @returns o estado ativo ({ theme }) repassado por `configure`.\n */\nexport function applyPreset(\n presetName: string,\n mode: 'light' | 'dark' = 'light',\n): { theme: 'light' | 'dark'; preset: string } {\n const preset = registry.get(presetName) ?? registry.get('fenix')!;\n const state = configure({ theme: mode, tokens: preset.tokens });\n return { ...state, preset: preset.name };\n}"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Sanitização de strings para injeção segura em HTML.
3
+ *
4
+ * Previne XSS ao escapar caracteres especiais antes de usar innerHTML.
5
+ * Use SEMPRE que dados externos (API, usuário) forem injetados no DOM.
6
+ */
7
+ /**
8
+ * Escapa caracteres especiais de HTML para prevenir XSS.
9
+ *
10
+ * @param value - Valor a ser escapado (convertido para string)
11
+ * @returns String segura para innerHTML
12
+ *
13
+ * @example
14
+ * // Seguro contra XSS
15
+ * const userInput = '<img src=x onerror=alert(1)>';
16
+ * element.innerHTML = `<div>${esc(userInput)}</div>`;
17
+ * // Resultado: &lt;img src=x onerror=alert(1)&gt;
18
+ */
19
+ export declare function esc(value: unknown): string;
20
+ /**
21
+ * Remove todas as tags HTML da string (strip tags).
22
+ * Use quando quiser apenas texto puro, sem nenhuma marcação.
23
+ *
24
+ * @param html - String potencialmente contendo HTML
25
+ * @returns String sem tags HTML
26
+ */
27
+ export declare function stripTags(html: string): string;
28
+ /**
29
+ * Sanitiza um objeto de dados recursivamente.
30
+ * Útil para sanitizar arrays de registros antes de renderizar.
31
+ *
32
+ * @param data - Objeto ou array a ser sanitizado
33
+ * @returns Cópia sanitizada do objeto
34
+ */
35
+ export declare function sanitizeData<T>(data: T): T;
36
+ //# sourceMappingURL=sanitize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../src/core/sanitize.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAiBH;;;;;;;;;;;GAWG;AACH,wBAAgB,GAAG,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAG1C;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,CAY1C"}
@@ -0,0 +1,37 @@
1
+ const HTML_ENTITIES = {
2
+ "&": "&amp;",
3
+ "<": "&lt;",
4
+ ">": "&gt;",
5
+ '"': "&quot;",
6
+ "'": "&#39;",
7
+ "/": "&#x2F;",
8
+ "`": "&#x60;",
9
+ "=": "&#x3D;"
10
+ };
11
+ const SANITIZE_REGEX = /[&<>"'`=/]/g;
12
+ function esc(value) {
13
+ if (value == null) return "";
14
+ return String(value).replace(SANITIZE_REGEX, (char) => HTML_ENTITIES[char] || char);
15
+ }
16
+ function stripTags(html) {
17
+ return html.replace(/<[^>]*>/g, "");
18
+ }
19
+ function sanitizeData(data) {
20
+ if (data == null) return data;
21
+ if (typeof data === "string") return esc(data);
22
+ if (Array.isArray(data)) return data.map(sanitizeData);
23
+ if (typeof data === "object") {
24
+ const result = {};
25
+ for (const [key, value] of Object.entries(data)) {
26
+ result[key] = sanitizeData(value);
27
+ }
28
+ return result;
29
+ }
30
+ return data;
31
+ }
32
+ export {
33
+ esc,
34
+ sanitizeData,
35
+ stripTags
36
+ };
37
+ //# sourceMappingURL=sanitize.js.map