@wrrdev/fenix-ui 1.1.8 → 1.1.9
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.
- package/README.md +2 -2
- package/dist/components/drawer/drawer.d.ts.map +1 -1
- package/dist/components/drawer/drawer.js +4 -0
- package/dist/components/drawer/drawer.js.map +1 -1
- package/dist/components/pagination/pagination.d.ts +1 -0
- package/dist/components/pagination/pagination.d.ts.map +1 -1
- package/dist/components/pagination/pagination.js +18 -2
- package/dist/components/pagination/pagination.js.map +1 -1
- package/dist/components/table/table.d.ts +38 -4
- package/dist/components/table/table.d.ts.map +1 -1
- package/dist/components/table/table.js +90 -18
- package/dist/components/table/table.js.map +1 -1
- package/dist/components/toast/toast.d.ts +46 -1
- package/dist/components/toast/toast.d.ts.map +1 -1
- package/dist/components/toast/toast.js +128 -5
- package/dist/components/toast/toast.js.map +1 -1
- package/dist/core/jsx.d.ts +63 -1
- package/dist/core/jsx.d.ts.map +1 -1
- package/dist/core/jsx.js.map +1 -1
- package/dist/core/vue.d.ts +7 -1
- package/dist/core/vue.d.ts.map +1 -1
- package/dist/core/vue.js.map +1 -1
- package/dist/docs/app.d.ts +2 -6
- package/dist/docs/app.d.ts.map +1 -1
- package/dist/docs/componentes/table.doc.d.ts.map +1 -1
- package/dist/docs/componentes/toast.doc.d.ts.map +1 -1
- package/dist/docs/router.d.ts +17 -0
- package/dist/docs/router.d.ts.map +1 -0
- package/dist/docs/shell.d.ts +43 -0
- package/dist/docs/shell.d.ts.map +1 -0
- package/dist/docs/ui/code.d.ts +12 -0
- package/dist/docs/ui/code.d.ts.map +1 -0
- package/dist/docs/ui/kit.d.ts +18 -0
- package/dist/docs/ui/kit.d.ts.map +1 -0
- package/dist/docs/ui/tabs.d.ts +23 -0
- package/dist/docs/ui/tabs.d.ts.map +1 -0
- package/dist/fenix-ui.umd.min.js +179 -116
- package/dist/fenix-ui2.esm.js.map +1 -1
- package/dist/fenix-ui4.esm.js +237 -26
- package/dist/fenix-ui4.esm.js.map +1 -1
- package/dist/fenix-ui5.esm.js +4 -1
- package/dist/fenix-ui5.esm.js.map +1 -1
- package/dist/plugins/auto-import.d.ts.map +1 -1
- package/dist/plugins/auto-import.js +4 -1
- package/dist/plugins/auto-import.js.map +1 -1
- package/package.json +3 -2
|
@@ -1 +1 @@
|
|
|
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
|
+
{"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 { FENIX_ICON_BASE_CSS, fenixIconHtml } from '../../icons/base-css';\nimport { loadFenixIconsFont } from '../../icons/font';\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: <fx-cell>R$ {{value}}</fx-cell> para render customizado\n * ou conteúdo direto (HTML + {{ }}) como template alternativo\n * </fx-column>\n *\n * IMPORTANTE (frameworks): use <fx-cell>, NÃO <template>. A tag nativa\n * <template> é reservada — o Vue 3 a transforma em bloco do compilador e o\n * React gerencia os filhos, então o innerHTML chega vazio. <fx-cell> é uma\n * tag própria, sem significado especial para nenhum framework. A forma\n * antiga com <template> continua funcionando (compatibilidade) e há ainda\n * a opção `template=\"#id\"` apontando para um <template> externo.\n *\n * Toolbar (opcional):\n * <fx-toolbar>\n * <input data-search-fields=\"nome,cargo\" placeholder=\"Buscar…\">\n * <button>Nova ação</button>\n * </fx-toolbar>\n * (legado ainda aceito: <template slot=\"toolbar\">…</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, hover, empty-message, lazy, total, loading, loading-message,\n * sort-field, sort-order.\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${FENIX_ICON_BASE_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\t/* Listrado: alterna a superfície (cinza). Antes usava\n\t\t --fx-surface-background, que é a MESMA cor do fundo do :host e\n\t\t portanto pintava branco sobre branco (listrado invisível). */\n\t\t:host([striped]) tbody tr:nth-child(even) {\n\t\t\tbackground: var(--fx-surface-surface, #f8fafc);\n\t\t}\n\t\t/* O hover é opt-in via atributo (o clique na linha continua sempre ativo). */\n\t\t:host([hover]) 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\tdisplay: inline-flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\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/* O glifo precisa de 1px a mais que o dígito: a altura de traço do ícone é\n\t\t maior que a do número, então igualar os dois font-size deixa a seta\n\t\t visivelmente maior que o texto. */\n\t\t.pg-btn .fx-icon {\n\t\t\tfont-size: calc(var(--fx-font-size) - 1px);\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\"hover\",\n\t\t\t\"toolbar\",\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\t\"sort-field\",\n\t\t\t\"sort-order\",\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?: HTMLElement;\n\t\tdirectTemplate?: string;\n\t}[] {\n\t\treturn [...this.querySelectorAll(\"fx-column\")].map((c) => {\n\t\t\tconst tpl = this._resolveCellTemplate(c);\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\t/**\n\t * Resolve o template de célula de uma `<fx-column>`, em ordem de prioridade:\n\t *\n\t * 1. `<fx-cell>` — **recomendado**. Tag própria, sem significado especial\n\t * para Vue/React/Angular/Svelte: nenhum framework a intercepta, então o\n\t * `innerHTML` sempre chega intacto ao componente. O light DOM do\n\t * `<fx-table>` não é exibido (a tabela não usa `<slot>`), então o\n\t * conteúdo-fonte nunca aparece na tela.\n\t * 2. `template=\"#id\"` (ou `template=\"id\"`) — aponta para um `<template>`\n\t * declarado **fora** da tabela, útil em React/Angular, onde é mais\n\t * simples manter o markup num único lugar.\n\t * 3. `<template>` dentro da coluna — forma **legada**, mantida por\n\t * compatibilidade. Em Vue 3 ela vira um bloco do compilador e em React os\n\t * filhos são gerenciados pelo framework; nos dois casos o `innerHTML`\n\t * chega vazio e a célula não renderiza. Prefira `<fx-cell>`.\n\t */\n\tprivate _resolveCellTemplate(c: Element): HTMLElement | null {\n\t\tconst cell = c.querySelector<HTMLElement>(\":scope > fx-cell\");\n\t\tif (cell) return cell;\n\t\tconst ref = c.getAttribute(\"template\");\n\t\tif (ref) {\n\t\t\tconst alvo = this._resolveRef(ref);\n\t\t\tif (alvo) return alvo;\n\t\t}\n\t\treturn c.querySelector<HTMLElement>(\"template\");\n\t}\n\n\tprivate get toolbarTemplate(): HTMLElement | null {\n\t\t// Mesma lógica da célula: `<fx-toolbar>` > `toolbar=\"#id\"` > legado.\n\t\tconst bar = this.querySelector<HTMLElement>(\":scope > fx-toolbar\");\n\t\tif (bar) return bar;\n\t\tconst ref = this.getAttr(\"toolbar\");\n\t\tif (ref) {\n\t\t\tconst alvo = this._resolveRef(ref);\n\t\t\tif (alvo) return alvo;\n\t\t}\n\t\treturn this.querySelector<HTMLElement>('template[slot=\"toolbar\"]');\n\t}\n\n\t/**\n\t * Resolve `ref` para um elemento: `#id`/`id` ⇒ `getElementById` no\n\t * documento; qualquer outro valor é tratado como seletor CSS relativo à\n\t * própria tabela. Valores inválidos devolvem `null` (sem exceção).\n\t */\n\tprivate _resolveRef(ref: string): HTMLElement | null {\n\t\tconst valor = ref.trim();\n\t\tif (!valor) return null;\n\t\tconst doc = this.ownerDocument;\n\t\tif (valor.startsWith('#')) return doc?.getElementById(valor.slice(1)) ?? null;\n\t\tif (/^[.#[>]/.test(valor)) {\n\t\t\ttry {\n\t\t\t\treturn this.querySelector<HTMLElement>(valor);\n\t\t\t} catch {\n\t\t\t\treturn null; // seletor inválido — degrada para o próximo fallback\n\t\t\t}\n\t\t}\n\t\treturn doc?.getElementById(valor) ?? null;\n\t}\n\n\tprotected override connectedCallback(): void {\n\t\tthis._parseDataAttribute();\n\t\tthis._parseSortAttributes();\n\t\t// O pager usa glifos da Fenix Icons: garante o @font-face mesmo quando o\n\t\t// app não importou `@wrrdev/fenix-ui/icons` (idempotente).\n\t\tloadFenixIconsFont();\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\t/** Ordenação inicial via `sort-field` / `sort-order` (documentados na API). */\n\tprivate _parseSortAttributes(): void {\n\t\tconst field = this.getAttr(\"sort-field\");\n\t\tif (field) this.sortField = field;\n\t\tconst order = this.getAttr(\"sort-order\");\n\t\tif (order === \"asc\" || order === \"desc\") this.sortDir = order === \"asc\" ? 1 : -1;\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?: HTMLElement;\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\" part=\"first\" aria-label=\"Primeira página\" data-pg=\"first\" ${this.page === 0 ? \"disabled\" : \"\"}>${fenixIconHtml(\"first_page\")}</button>\n <button type=\"button\" class=\"pg-btn\" part=\"prev\" aria-label=\"Página anterior\" data-pg=\"prev\" ${this.page === 0 ? \"disabled\" : \"\"}>${fenixIconHtml(\"navigate_before\")}</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\" part=\"next\" aria-label=\"Próxima página\" data-pg=\"next\" ${this.page >= pages - 1 ? \"disabled\" : \"\"}>${fenixIconHtml(\"navigate_next\")}</button>\n <button type=\"button\" class=\"pg-btn\" part=\"last\" aria-label=\"Última página\" data-pg=\"last\" ${this.page >= pages - 1 ? \"disabled\" : \"\"}>${fenixIconHtml(\"last_page\")}</button>\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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"}
|
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
* Atributos: kind (success|error|info|warning), title, message,
|
|
5
5
|
* position (top-left|top-center|top-right|bottom-left|bottom-center|bottom-right),
|
|
6
6
|
* duration (ms; 0 = fixo até fechar), mode ('light'|'dark' — força o esquema de
|
|
7
|
-
* cores do card independentemente do tema global)
|
|
7
|
+
* cores do card independentemente do tema global), progress (booleano ou
|
|
8
|
+
* 'always'|'hover'|'paused' — barra de contagem regressiva na cor do kind),
|
|
9
|
+
* progress-origin (left|right — lado pelo qual a barra esvazia; padrão left).
|
|
8
10
|
*/
|
|
9
11
|
declare const POSITIONS: readonly ["top-left", "top-center", "top-right", "bottom-left", "bottom-center", "bottom-right"];
|
|
10
12
|
export type ToastPosition = (typeof POSITIONS)[number];
|
|
@@ -12,6 +14,35 @@ type ToastKind = 'success' | 'error' | 'info' | 'warning';
|
|
|
12
14
|
export declare class FxToast extends HTMLElement {
|
|
13
15
|
#private;
|
|
14
16
|
static get observedAttributes(): string[];
|
|
17
|
+
/**
|
|
18
|
+
* Exibe a barra de contagem regressiva na base do card.
|
|
19
|
+
*
|
|
20
|
+
* A barra esvazia da esquerda para a direita durante exatamente `duration`
|
|
21
|
+
* e usa a cor do `kind`. Com `duration="0"` (toast fixo) a barra é
|
|
22
|
+
* omitida — não há tempo restante a representar.
|
|
23
|
+
*
|
|
24
|
+
* - `'always'` (ou atributo vazio): barra sempre correndo.
|
|
25
|
+
* - `'hover'`: a barra só corre enquanto o cursor estiver sobre o toast;
|
|
26
|
+
* ao sair, a animação pausa, então dá tempo de ler a mensagem.
|
|
27
|
+
* - `'paused'`: barra visível, porém parada.
|
|
28
|
+
*/
|
|
29
|
+
get progress(): 'always' | 'hover' | 'paused' | undefined;
|
|
30
|
+
set progress(value: 'always' | 'hover' | 'paused' | undefined);
|
|
31
|
+
/**
|
|
32
|
+
* Lado a partir do qual a barra esvazia.
|
|
33
|
+
*
|
|
34
|
+
* - `'left'` (padrão): a barra fica ancorada à esquerda e drena da direita
|
|
35
|
+
* para a esquerda.
|
|
36
|
+
* - `'right'`: a barra fica ancorada à direita e drena da esquerda para a
|
|
37
|
+
* direita (espelhado).
|
|
38
|
+
*
|
|
39
|
+
* Só tem efeito junto com `progress`; qualquer valor fora da lista cai em
|
|
40
|
+
* `'left'`.
|
|
41
|
+
*/
|
|
42
|
+
get progressOrigin(): 'left' | 'right';
|
|
43
|
+
set progressOrigin(value: 'left' | 'right');
|
|
44
|
+
/** Duração efetiva em ms (0 = fixo). Mesma regra usada no timer. */
|
|
45
|
+
private get safeDuration();
|
|
15
46
|
/** Esquema de cores forçado do card: 'light' | 'dark' | undefined (segue o tema). */
|
|
16
47
|
get mode(): 'light' | 'dark' | undefined;
|
|
17
48
|
set mode(value: 'light' | 'dark' | undefined);
|
|
@@ -19,6 +50,7 @@ export declare class FxToast extends HTMLElement {
|
|
|
19
50
|
constructor();
|
|
20
51
|
connectedCallback(): void;
|
|
21
52
|
disconnectedCallback(): void;
|
|
53
|
+
attributeChangedCallback(name: string): void;
|
|
22
54
|
dismiss(): void;
|
|
23
55
|
}
|
|
24
56
|
export interface ToastOptions {
|
|
@@ -27,6 +59,19 @@ export interface ToastOptions {
|
|
|
27
59
|
position?: ToastPosition;
|
|
28
60
|
/** Tempo em ms até sumir. 0 = fixo até fechar. Padrão: 4000 */
|
|
29
61
|
duration?: number;
|
|
62
|
+
/**
|
|
63
|
+
* Barra de contagem regressiva na base do card, na cor do `kind`.
|
|
64
|
+
* `'always'` (padrão) corre sempre; `'hover'` só enquanto o cursor estiver
|
|
65
|
+
* sobre o toast; `'paused'` exibe a barra cheia, porém imóvel.
|
|
66
|
+
* Sem efeito com `duration: 0` (não há tempo restante a representar).
|
|
67
|
+
*/
|
|
68
|
+
progress?: 'always' | 'hover' | 'paused';
|
|
69
|
+
/**
|
|
70
|
+
* Lado a partir do qual a barra esvazia. `'left'` (padrão) deixa a barra
|
|
71
|
+
* ancorada à esquerda; `'right'` a ancora à direita (espelhado).
|
|
72
|
+
* Só tem efeito junto com `progress`.
|
|
73
|
+
*/
|
|
74
|
+
progressOrigin?: 'left' | 'right';
|
|
30
75
|
/** Força o esquema de cores do card, independentemente do tema global. */
|
|
31
76
|
mode?: 'light' | 'dark';
|
|
32
77
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toast.d.ts","sourceRoot":"","sources":["../../../src/components/toast/toast.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"toast.d.ts","sourceRoot":"","sources":["../../../src/components/toast/toast.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,QAAA,MAAM,SAAS,kGAGL,CAAC;AACX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AACvD,KAAK,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;AA6H1D,qBAAa,OAAQ,SAAQ,WAAW;;IACtC,MAAM,KAAK,kBAAkB,aAE5B;IAED;;;;;;;;;;;OAWG;IACH,IAAI,QAAQ,IAAI,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAIxD;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,EAG5D;IAED;;;;;;;;;;OAUG;IACH,IAAI,cAAc,IAAI,MAAM,GAAG,OAAO,CAErC;IACD,IAAI,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,EAEzC;IAED,oEAAoE;IACpE,OAAO,KAAK,YAAY,GAIvB;IAED,qFAAqF;IACrF,IAAI,IAAI,IAAI,OAAO,GAAG,MAAM,GAAG,SAAS,CAGvC;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,EAG3C;IAED,OAAO,CAAC,KAAK,CAA8C;;IAO3D,iBAAiB;IAWjB,oBAAoB;IAKpB,wBAAwB,CAAC,IAAI,EAAE,MAAM;IA6CrC,OAAO;CAqCR;AA8BD,MAAM,WAAW,YAAY;IAC3B,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;IACzC;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAClC,0EAA0E;IAC1E,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CACzB;AAED,cAAM,QAAQ;IACZ,OAAO,CAAC,GAAG,CAAK;IAChB,OAAO,CAAC,GAAG,CAA8B;IAEzC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,YAAY,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,MAAM;IAqBxG,KAAK,CAAC,EAAE,EAAE,MAAM;IAKhB,OAAO,GAAI,GAAG,MAAM,EAAE,IAAI,MAAM,EAAE,IAAI,YAAY,YAAmC;IACrF,KAAK,GAAI,GAAG,MAAM,EAAE,IAAI,MAAM,EAAE,IAAI,YAAY,YAAiC;IACjF,IAAI,GAAI,GAAG,MAAM,EAAE,IAAI,MAAM,EAAE,IAAI,YAAY,YAAgC;IAC/E,OAAO,GAAI,GAAG,MAAM,EAAE,IAAI,MAAM,EAAE,IAAI,YAAY,YAAmC;CACtF;AAED,eAAO,MAAM,UAAU,UAAiB,CAAC;AAIzC,wBAAgB,aAAa,SAE5B"}
|
|
@@ -4,7 +4,7 @@ var __typeError = (msg) => {
|
|
|
4
4
|
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
5
5
|
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
6
6
|
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
7
|
-
var _FxToast_instances, render_fn;
|
|
7
|
+
var _FxToast_instances, syncProgress_fn, render_fn;
|
|
8
8
|
import { __fenixPreload } from "../../_virtual/preload-helper.js";
|
|
9
9
|
const KIND_COLOR = {
|
|
10
10
|
success: "var(--fx-color-success, #10b981)",
|
|
@@ -82,6 +82,48 @@ const CARD_CSS = `
|
|
|
82
82
|
color: var(--fx-text-muted, #64748b); font-size: 15px; padding: 2px 4px; border-radius: 4px;
|
|
83
83
|
}
|
|
84
84
|
.close:hover { color: var(--fx-color-danger, #f43f5e); background: var(--fx-surface-surface-hover, rgba(0,0,0,.05)); }
|
|
85
|
+
|
|
86
|
+
/* --- Barra de contagem regressiva (atributo progress) ---
|
|
87
|
+
Fica na base do card e esvazia durante a duração, na cor do kind (--kind) —
|
|
88
|
+
ou seja, acompanha success/error/warning/info sem configuração extra.
|
|
89
|
+
|
|
90
|
+
O lado é configurável pelo atributo progress-origin (padrão: left):
|
|
91
|
+
left → a barra drena da direita para a esquerda (ancorada à esquerda)
|
|
92
|
+
right → a barra drena da esquerda para a direita (ancorada à direita)
|
|
93
|
+
A origem entra como custom property, então os keyframes são compartilhados.
|
|
94
|
+
|
|
95
|
+
Usa escalaX em vez de width: a animação escreve só na compositor, sem
|
|
96
|
+
reflow por frame. */
|
|
97
|
+
.card { position: relative; overflow: hidden; }
|
|
98
|
+
.progress {
|
|
99
|
+
position: absolute;
|
|
100
|
+
left: 0;
|
|
101
|
+
bottom: 0;
|
|
102
|
+
width: 100%;
|
|
103
|
+
height: 3px;
|
|
104
|
+
background: var(--kind);
|
|
105
|
+
transform-origin: var(--toast-progress-origin, left center);
|
|
106
|
+
transform: scaleX(1);
|
|
107
|
+
border-radius: 0 0 var(--fx-radius-md, 8px) var(--fx-radius-md, 8px);
|
|
108
|
+
pointer-events: none;
|
|
109
|
+
will-change: transform;
|
|
110
|
+
}
|
|
111
|
+
.progress.run { animation: fx-toast-drain var(--toast-duration, 4000ms) linear forwards; }
|
|
112
|
+
/* No modo hover a animação fica parada até o cursor/foco entrar no card. */
|
|
113
|
+
.card:hover .progress.run,
|
|
114
|
+
.card:focus-within .progress.run { animation-play-state: running; }
|
|
115
|
+
@keyframes fx-toast-drain {
|
|
116
|
+
from { transform: scaleX(1); }
|
|
117
|
+
to { transform: scaleX(0); }
|
|
118
|
+
}
|
|
119
|
+
/* A barra só começa a correr no 2º frame: no 1º ela já apareceria zerada
|
|
120
|
+
(o elemento acabou de ser inserido e a animação aplica o estado final). */
|
|
121
|
+
.card.entering .progress { animation: none; }
|
|
122
|
+
/* Ao dispensar, congela a barra: ela some junto com o card em .2s. */
|
|
123
|
+
.card.leaving .progress { animation-play-state: paused; }
|
|
124
|
+
@media (prefers-reduced-motion: reduce) {
|
|
125
|
+
.progress.run { animation-duration: 0.01ms; }
|
|
126
|
+
}
|
|
85
127
|
`;
|
|
86
128
|
class FxToast extends HTMLElement {
|
|
87
129
|
constructor() {
|
|
@@ -91,7 +133,51 @@ class FxToast extends HTMLElement {
|
|
|
91
133
|
this.attachShadow({ mode: "open" });
|
|
92
134
|
}
|
|
93
135
|
static get observedAttributes() {
|
|
94
|
-
return ["kind", "title", "message", "duration", "icon", "mode"];
|
|
136
|
+
return ["kind", "title", "message", "duration", "icon", "mode", "progress", "progress-origin"];
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Exibe a barra de contagem regressiva na base do card.
|
|
140
|
+
*
|
|
141
|
+
* A barra esvazia da esquerda para a direita durante exatamente `duration`
|
|
142
|
+
* e usa a cor do `kind`. Com `duration="0"` (toast fixo) a barra é
|
|
143
|
+
* omitida — não há tempo restante a representar.
|
|
144
|
+
*
|
|
145
|
+
* - `'always'` (ou atributo vazio): barra sempre correndo.
|
|
146
|
+
* - `'hover'`: a barra só corre enquanto o cursor estiver sobre o toast;
|
|
147
|
+
* ao sair, a animação pausa, então dá tempo de ler a mensagem.
|
|
148
|
+
* - `'paused'`: barra visível, porém parada.
|
|
149
|
+
*/
|
|
150
|
+
get progress() {
|
|
151
|
+
if (!this.hasAttribute("progress")) return void 0;
|
|
152
|
+
const v = this.getAttribute("progress");
|
|
153
|
+
return v === "hover" || v === "paused" ? v : "always";
|
|
154
|
+
}
|
|
155
|
+
set progress(value) {
|
|
156
|
+
if (value) this.setAttribute("progress", value);
|
|
157
|
+
else this.removeAttribute("progress");
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Lado a partir do qual a barra esvazia.
|
|
161
|
+
*
|
|
162
|
+
* - `'left'` (padrão): a barra fica ancorada à esquerda e drena da direita
|
|
163
|
+
* para a esquerda.
|
|
164
|
+
* - `'right'`: a barra fica ancorada à direita e drena da esquerda para a
|
|
165
|
+
* direita (espelhado).
|
|
166
|
+
*
|
|
167
|
+
* Só tem efeito junto com `progress`; qualquer valor fora da lista cai em
|
|
168
|
+
* `'left'`.
|
|
169
|
+
*/
|
|
170
|
+
get progressOrigin() {
|
|
171
|
+
return this.getAttribute("progress-origin") === "right" ? "right" : "left";
|
|
172
|
+
}
|
|
173
|
+
set progressOrigin(value) {
|
|
174
|
+
this.setAttribute("progress-origin", value);
|
|
175
|
+
}
|
|
176
|
+
/** Duração efetiva em ms (0 = fixo). Mesma regra usada no timer. */
|
|
177
|
+
get safeDuration() {
|
|
178
|
+
const dur = Number(this.getAttribute("duration") ?? "4000");
|
|
179
|
+
if (dur === 0) return 0;
|
|
180
|
+
return Math.max(Number.isNaN(dur) ? 4e3 : dur, 1e3);
|
|
95
181
|
}
|
|
96
182
|
/** Esquema de cores forçado do card: 'light' | 'dark' | undefined (segue o tema). */
|
|
97
183
|
get mode() {
|
|
@@ -104,16 +190,21 @@ class FxToast extends HTMLElement {
|
|
|
104
190
|
}
|
|
105
191
|
connectedCallback() {
|
|
106
192
|
if (!this.shadowRoot.firstChild) __privateMethod(this, _FxToast_instances, render_fn).call(this);
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
if (!Number.isNaN(safe) && safe > 0 && !this.timer) {
|
|
193
|
+
const safe = this.safeDuration;
|
|
194
|
+
if (safe > 0 && !this.timer) {
|
|
110
195
|
this.timer = setTimeout(() => this.dismiss(), safe);
|
|
111
196
|
}
|
|
197
|
+
__privateMethod(this, _FxToast_instances, syncProgress_fn).call(this);
|
|
112
198
|
}
|
|
113
199
|
disconnectedCallback() {
|
|
114
200
|
if (this.timer) clearTimeout(this.timer);
|
|
115
201
|
this.timer = null;
|
|
116
202
|
}
|
|
203
|
+
attributeChangedCallback(name) {
|
|
204
|
+
if (name === "duration" || name === "progress" || name === "progress-origin" || name === "kind") {
|
|
205
|
+
__privateMethod(this, _FxToast_instances, syncProgress_fn).call(this);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
117
208
|
dismiss() {
|
|
118
209
|
if (this.timer) clearTimeout(this.timer);
|
|
119
210
|
this.timer = null;
|
|
@@ -127,6 +218,36 @@ class FxToast extends HTMLElement {
|
|
|
127
218
|
}
|
|
128
219
|
}
|
|
129
220
|
_FxToast_instances = new WeakSet();
|
|
221
|
+
/**
|
|
222
|
+
* Aplica (ou remove) a barra de contagem regressiva.
|
|
223
|
+
*
|
|
224
|
+
* A barra só existe com `progress` e `duration > 0`. O tempo da animação
|
|
225
|
+
* vem de `--toast-duration`, sempre igual ao do `setTimeout` que fecha o
|
|
226
|
+
* toast — assim a barra e o desaparecimento nunca desalinham.
|
|
227
|
+
*/
|
|
228
|
+
syncProgress_fn = function() {
|
|
229
|
+
const card = this.shadowRoot?.querySelector(".card");
|
|
230
|
+
if (!card) return;
|
|
231
|
+
const bar = this.shadowRoot.querySelector(".progress");
|
|
232
|
+
const mode = this.progress;
|
|
233
|
+
const dur = this.safeDuration;
|
|
234
|
+
const shouldShow = !!mode && dur > 0;
|
|
235
|
+
if (!shouldShow) {
|
|
236
|
+
bar?.remove();
|
|
237
|
+
card.classList.remove("entering");
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
if (!bar) {
|
|
241
|
+
this.shadowRoot.querySelector(".card").insertAdjacentHTML("beforeend", '<span class="progress" part="progress" aria-hidden="true"></span>');
|
|
242
|
+
}
|
|
243
|
+
const el = this.shadowRoot.querySelector(".progress");
|
|
244
|
+
el.style.setProperty("--toast-duration", `${dur}ms`);
|
|
245
|
+
el.style.setProperty("--toast-progress-origin", `${this.progressOrigin} center`);
|
|
246
|
+
el.classList.remove("run");
|
|
247
|
+
if (mode !== "paused") el.classList.add("run");
|
|
248
|
+
card.classList.add("entering");
|
|
249
|
+
requestAnimationFrame(() => requestAnimationFrame(() => card.classList.remove("entering")));
|
|
250
|
+
};
|
|
130
251
|
render_fn = function() {
|
|
131
252
|
const kind = this.getAttribute("kind") || "info";
|
|
132
253
|
const title = this.getAttribute("title") ?? "";
|
|
@@ -196,6 +317,8 @@ class ToastApi {
|
|
|
196
317
|
el.setAttribute("position", o.position ?? "top-right");
|
|
197
318
|
el.setAttribute("duration", String(o.duration ?? 4e3));
|
|
198
319
|
if (o.mode) el.setAttribute("mode", o.mode);
|
|
320
|
+
if (o.progress) el.setAttribute("progress", o.progress);
|
|
321
|
+
if (o.progressOrigin) el.setAttribute("progress-origin", o.progressOrigin);
|
|
199
322
|
regionFor(o.position ?? "top-right").appendChild(el);
|
|
200
323
|
this.map.set(id, el);
|
|
201
324
|
return id;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"mappings":"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","names":[],"ignoreList":[],"sources":["../../../src/components/toast/toast.ts"],"sourcesContent":["/**\n * <fx-toast> — notificações imperativas com posição e duração configuráveis.\n *\n * Atributos: kind (success|error|info|warning), title, message,\n * position (top-left|top-center|top-right|bottom-left|bottom-center|bottom-right),\n * duration (ms; 0 = fixo até fechar), mode ('light'|'dark' — força o esquema de\n * cores do card independentemente do tema global).\n */\nconst POSITIONS = [\n 'top-left', 'top-center', 'top-right',\n 'bottom-left', 'bottom-center', 'bottom-right',\n] as const;\nexport type ToastPosition = (typeof POSITIONS)[number];\ntype ToastKind = 'success' | 'error' | 'info' | 'warning';\n\nconst KIND_COLOR: Record<ToastKind, string> = {\n success: 'var(--fx-color-success, #10b981)',\n error: 'var(--fx-color-danger, #f43f5e)',\n info: 'var(--fx-color-info, #0ea5e9)',\n warning: 'var(--fx-color-warning, #f59e0b)',\n};\n\n/** Ícone exibido no lugar da bolinha, conforme a variante. */\nconst KIND_ICON: Record<ToastKind, string> = {\n success: '✓',\n error: '✕',\n warning: '!',\n info: 'i',\n};\n\nconst CARD_CSS = `\n:host { display: contents; pointer-events: auto; }\n/* Modo explícito: sobrepõe os tokens herdados do tema global SOMENTE neste card. */\n:host([mode='dark']) {\n --fx-surface-background: #1e293b;\n --fx-text-default: #f1f5f9;\n --fx-text-muted: #94a3b8;\n --fx-border-default: #334155;\n --fx-shadow-lg: 0 10px 30px rgba(0, 0, 0, .5);\n --fx-surface-surface-hover: rgba(255, 255, 255, .08);\n}\n:host([mode='light']) {\n --fx-surface-background: #ffffff;\n --fx-text-default: #1e293b;\n --fx-text-muted: #64748b;\n --fx-border-default: #e2e8f0;\n --fx-shadow-lg: 0 10px 30px rgba(0, 0, 0, .14);\n --fx-surface-surface-hover: rgba(0, 0, 0, .05);\n}\n.fx-icon {\n font-family: var(--fx-icon-font, 'Fenix Icons');\n font-weight: normal;\n font-style: normal;\n line-height: 1;\n letter-spacing: normal;\n display: inline-block;\n white-space: nowrap;\n direction: ltr;\n font-variation-settings: 'FILL' 0, 'wght' 500, 'GRAD' 0, 'opsz' 24;\n -webkit-font-smoothing: antialiased;\n user-select: none;\n}\n.card {\n display: flex; align-items: flex-start; gap: 10px;\n min-width: 260px; max-width: 360px;\n background: var(--fx-surface-background, #fff);\n color: var(--fx-text-default, #1e293b);\n border: 1px solid var(--fx-border-default, #e2e8f0);\n border-left: 4px solid var(--kind);\n border-radius: var(--fx-radius-md, 8px);\n box-shadow: var(--fx-shadow-lg, 0 10px 30px rgba(0,0,0,.14));\n padding: var(--fx-space-sm, 8px) var(--fx-space-md, 12px);\n font-family: inherit;\n animation: fx-toast-in .25s ease;\n}\n@keyframes fx-toast-in { from { opacity: 0; transform: translateY(-6px); } }\n.card.leaving { opacity: 0; transition: opacity .2s ease; }\n.icon {\n width: 22px; height: 22px; border-radius: 50%;\n background: var(--kind);\n color: #fff;\n display: flex; align-items: center; justify-content: center;\n font-size: 12px; font-weight: 700;\n flex: none; margin-top: 2px;\n user-select: none;\n}\n.body { flex: 1; min-width: 0; }\n.title { font-weight: 600; font-size: 14px; }\n.msg { font-size: calc(var(--fx-font-size, 14px) - 2px); color: var(--fx-text-muted, #64748b); margin-top: 2px; word-break: break-word; white-space: pre-line; }\n.close {\n all: unset; cursor: pointer; flex: none; line-height: 1;\n color: var(--fx-text-muted, #64748b); font-size: 15px; padding: 2px 4px; border-radius: 4px;\n}\n.close:hover { color: var(--fx-color-danger, #f43f5e); background: var(--fx-surface-surface-hover, rgba(0,0,0,.05)); }\n`;\n\nexport class FxToast extends HTMLElement {\n static get observedAttributes() {\n return ['kind', 'title', 'message', 'duration', 'icon', 'mode'];\n }\n\n /** Esquema de cores forçado do card: 'light' | 'dark' | undefined (segue o tema). */\n get mode(): 'light' | 'dark' | undefined {\n const m = this.getAttribute('mode');\n return m === 'light' || m === 'dark' ? m : undefined;\n }\n set mode(value: 'light' | 'dark' | undefined) {\n if (value) this.setAttribute('mode', value);\n else this.removeAttribute('mode');\n }\n\n private timer: ReturnType<typeof setTimeout> | null = null;\n\n constructor() {\n super();\n this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback() {\n if (!this.shadowRoot!.firstChild) this.#render();\n const dur = Number(this.getAttribute('duration') ?? '4000');\n // Durações mínimas: valores muito baixos (ex.: digitação parcial no\n // playground) são elevados para 1s; 0 permanece fixo até fechar.\n const safe = dur === 0 ? 0 : Math.max(Number.isNaN(dur) ? 4000 : dur, 1000);\n if (!Number.isNaN(safe) && safe > 0 && !this.timer) {\n this.timer = setTimeout(() => this.dismiss(), safe);\n }\n }\n\n disconnectedCallback() {\n if (this.timer) clearTimeout(this.timer);\n this.timer = null;\n }\n\n dismiss() {\n if (this.timer) clearTimeout(this.timer);\n this.timer = null;\n const card = this.shadowRoot!.querySelector('.card');\n if (card) {\n card.classList.add('leaving');\n setTimeout(() => this.remove(), 200);\n } else {\n this.remove();\n }\n }\n\n #render() {\n const kind = (this.getAttribute('kind') || 'info') as ToastKind;\n const title = this.getAttribute('title') ?? '';\n const msg = this.getAttribute('message') ?? '';\n const color = KIND_COLOR[kind] ?? KIND_COLOR.info;\n const iconName = this.getAttribute('icon');\n const isFxIcon = !!iconName && /^[a-z][a-z0-9_]*$/.test(iconName);\n if (isFxIcon) void import('../../icons');\n const iconContent = isFxIcon ? iconName : KIND_ICON[kind] ?? KIND_ICON.info;\n this.shadowRoot!.innerHTML = `\n <style>${CARD_CSS}</style>\n <div class=\"card\" style=\"--kind:${color}\" role=\"status\" part=\"card\">\n <span class=\"icon${isFxIcon ? ' fx-icon' : ''}\">${iconContent}</span>\n <div class=\"body\">\n ${title ? '<div class=\"title\"></div>' : ''}\n ${msg ? '<div class=\"msg\"></div>' : ''}\n </div>\n <button class=\"close\" aria-label=\"Fechar\">✕</button>\n </div>`;\n const t = this.shadowRoot!.querySelector<HTMLElement>('.title');\n const m = this.shadowRoot!.querySelector<HTMLElement>('.msg');\n if (t) t.textContent = title;\n if (m) m.textContent = msg;\n this.shadowRoot!.querySelector('.close')!.addEventListener('click', () => this.dismiss());\n }\n}\n\n/* ---------- Regiões por posição na tela ---------- */\nfunction regionFor(position: ToastPosition): HTMLElement {\n let region = document.querySelector<HTMLElement>(`[data-fx-toast-region=\"${position}\"]`);\n if (!region) {\n region = document.createElement('div');\n region.setAttribute('data-fx-toast-region', position);\n const [vertical, horizontal] = position.split('-') as [string, string];\n const style = region.style as CSSStyleDeclaration & Record<string, string>;\n style.position = 'fixed';\n style[vertical] = '16px';\n if (horizontal === 'center') {\n style.left = '50%';\n style.transform = 'translateX(-50%)';\n } else {\n style[horizontal] = '16px';\n }\n style.display = 'flex';\n style.flexDirection = 'column';\n style.gap = '8px';\n style.zIndex = '1100';\n style.pointerEvents = 'none';\n // Os cards reabilitam pointer-events via `:host { pointer-events: auto }` (herança),\n // sem necessidade de MutationObserver.\n document.body.appendChild(region);\n }\n return region;\n}\n\nexport interface ToastOptions {\n /** Texto secundário (também aceito como 2º argumento dos métodos). */\n message?: string;\n position?: ToastPosition;\n /** Tempo em ms até sumir. 0 = fixo até fechar. Padrão: 4000 */\n duration?: number;\n /** Força o esquema de cores do card, independentemente do tema global. */\n mode?: 'light' | 'dark';\n}\n\nclass ToastApi {\n private seq = 0;\n private map = new Map<number, FxToast>();\n\n push(kind: ToastKind, title: string, messageOrOpts?: string | ToastOptions, opts?: ToastOptions): number {\n const id = ++this.seq;\n // Assinaturas suportadas:\n // push(kind, title, options)\n // push(kind, title, message, options) <- usada pela doc e mais intuitiva\n const message = typeof messageOrOpts === 'string' ? messageOrOpts : messageOrOpts?.message;\n const o: ToastOptions = { ...(typeof messageOrOpts === 'object' && messageOrOpts ? messageOrOpts : undefined), ...opts };\n const el = document.createElement('fx-toast') as FxToast;\n el.setAttribute('kind', kind);\n el.setAttribute('title', title);\n if (message) el.setAttribute('message', message);\n el.setAttribute('position', o.position ?? 'top-right');\n el.setAttribute('duration', String(o.duration ?? 4000));\n if (o.mode) el.setAttribute('mode', o.mode);\n regionFor(o.position ?? 'top-right').appendChild(el);\n this.map.set(id, el);\n return id;\n }\n\n close(id: number) {\n this.map.get(id)?.dismiss();\n this.map.delete(id);\n }\n\n success = (t: string, m?: string, o?: ToastOptions) => this.push('success', t, m, o);\n error = (t: string, m?: string, o?: ToastOptions) => this.push('error', t, m, o);\n info = (t: string, m?: string, o?: ToastOptions) => this.push('info', t, m, o);\n warning = (t: string, m?: string, o?: ToastOptions) => this.push('warning', t, m, o);\n}\n\nexport const FenixToast = new ToastApi();\n// Exposto globalmente para uso em HTML puro (onclick=\"FenixToast.success(...)\")\n(globalThis as unknown as Record<string, unknown>).FenixToast = FenixToast;\n\nexport function defineFxToast() {\n if (!customElements.get('fx-toast')) customElements.define('fx-toast', FxToast);\n}\n\n"],"file":"components/toast/toast.js"}
|
|
1
|
+
{"version":3,"mappings":"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","names":[],"ignoreList":[],"sources":["../../../src/components/toast/toast.ts"],"sourcesContent":["/**\n * <fx-toast> — notificações imperativas com posição e duração configuráveis.\n *\n * Atributos: kind (success|error|info|warning), title, message,\n * position (top-left|top-center|top-right|bottom-left|bottom-center|bottom-right),\n * duration (ms; 0 = fixo até fechar), mode ('light'|'dark' — força o esquema de\n * cores do card independentemente do tema global), progress (booleano ou\n * 'always'|'hover'|'paused' — barra de contagem regressiva na cor do kind),\n * progress-origin (left|right — lado pelo qual a barra esvazia; padrão left).\n */\nconst POSITIONS = [\n 'top-left', 'top-center', 'top-right',\n 'bottom-left', 'bottom-center', 'bottom-right',\n] as const;\nexport type ToastPosition = (typeof POSITIONS)[number];\ntype ToastKind = 'success' | 'error' | 'info' | 'warning';\n\nconst KIND_COLOR: Record<ToastKind, string> = {\n success: 'var(--fx-color-success, #10b981)',\n error: 'var(--fx-color-danger, #f43f5e)',\n info: 'var(--fx-color-info, #0ea5e9)',\n warning: 'var(--fx-color-warning, #f59e0b)',\n};\n\n/** Ícone exibido no lugar da bolinha, conforme a variante. */\nconst KIND_ICON: Record<ToastKind, string> = {\n success: '✓',\n error: '✕',\n warning: '!',\n info: 'i',\n};\n\nconst CARD_CSS = `\n:host { display: contents; pointer-events: auto; }\n/* Modo explícito: sobrepõe os tokens herdados do tema global SOMENTE neste card. */\n:host([mode='dark']) {\n --fx-surface-background: #1e293b;\n --fx-text-default: #f1f5f9;\n --fx-text-muted: #94a3b8;\n --fx-border-default: #334155;\n --fx-shadow-lg: 0 10px 30px rgba(0, 0, 0, .5);\n --fx-surface-surface-hover: rgba(255, 255, 255, .08);\n}\n:host([mode='light']) {\n --fx-surface-background: #ffffff;\n --fx-text-default: #1e293b;\n --fx-text-muted: #64748b;\n --fx-border-default: #e2e8f0;\n --fx-shadow-lg: 0 10px 30px rgba(0, 0, 0, .14);\n --fx-surface-surface-hover: rgba(0, 0, 0, .05);\n}\n.fx-icon {\n font-family: var(--fx-icon-font, 'Fenix Icons');\n font-weight: normal;\n font-style: normal;\n line-height: 1;\n letter-spacing: normal;\n display: inline-block;\n white-space: nowrap;\n direction: ltr;\n font-variation-settings: 'FILL' 0, 'wght' 500, 'GRAD' 0, 'opsz' 24;\n -webkit-font-smoothing: antialiased;\n user-select: none;\n}\n.card {\n display: flex; align-items: flex-start; gap: 10px;\n min-width: 260px; max-width: 360px;\n background: var(--fx-surface-background, #fff);\n color: var(--fx-text-default, #1e293b);\n border: 1px solid var(--fx-border-default, #e2e8f0);\n border-left: 4px solid var(--kind);\n border-radius: var(--fx-radius-md, 8px);\n box-shadow: var(--fx-shadow-lg, 0 10px 30px rgba(0,0,0,.14));\n padding: var(--fx-space-sm, 8px) var(--fx-space-md, 12px);\n font-family: inherit;\n animation: fx-toast-in .25s ease;\n}\n@keyframes fx-toast-in { from { opacity: 0; transform: translateY(-6px); } }\n.card.leaving { opacity: 0; transition: opacity .2s ease; }\n.icon {\n width: 22px; height: 22px; border-radius: 50%;\n background: var(--kind);\n color: #fff;\n display: flex; align-items: center; justify-content: center;\n font-size: 12px; font-weight: 700;\n flex: none; margin-top: 2px;\n user-select: none;\n}\n.body { flex: 1; min-width: 0; }\n.title { font-weight: 600; font-size: 14px; }\n.msg { font-size: calc(var(--fx-font-size, 14px) - 2px); color: var(--fx-text-muted, #64748b); margin-top: 2px; word-break: break-word; white-space: pre-line; }\n.close {\n all: unset; cursor: pointer; flex: none; line-height: 1;\n color: var(--fx-text-muted, #64748b); font-size: 15px; padding: 2px 4px; border-radius: 4px;\n}\n.close:hover { color: var(--fx-color-danger, #f43f5e); background: var(--fx-surface-surface-hover, rgba(0,0,0,.05)); }\n\n/* --- Barra de contagem regressiva (atributo progress) ---\n Fica na base do card e esvazia durante a duração, na cor do kind (--kind) —\n ou seja, acompanha success/error/warning/info sem configuração extra.\n\n O lado é configurável pelo atributo progress-origin (padrão: left):\n left → a barra drena da direita para a esquerda (ancorada à esquerda)\n right → a barra drena da esquerda para a direita (ancorada à direita)\n A origem entra como custom property, então os keyframes são compartilhados.\n\n Usa escalaX em vez de width: a animação escreve só na compositor, sem\n reflow por frame. */\n.card { position: relative; overflow: hidden; }\n.progress {\n position: absolute;\n left: 0;\n bottom: 0;\n width: 100%;\n height: 3px;\n background: var(--kind);\n transform-origin: var(--toast-progress-origin, left center);\n transform: scaleX(1);\n border-radius: 0 0 var(--fx-radius-md, 8px) var(--fx-radius-md, 8px);\n pointer-events: none;\n will-change: transform;\n}\n.progress.run { animation: fx-toast-drain var(--toast-duration, 4000ms) linear forwards; }\n/* No modo hover a animação fica parada até o cursor/foco entrar no card. */\n.card:hover .progress.run,\n.card:focus-within .progress.run { animation-play-state: running; }\n@keyframes fx-toast-drain {\n from { transform: scaleX(1); }\n to { transform: scaleX(0); }\n}\n/* A barra só começa a correr no 2º frame: no 1º ela já apareceria zerada\n (o elemento acabou de ser inserido e a animação aplica o estado final). */\n.card.entering .progress { animation: none; }\n/* Ao dispensar, congela a barra: ela some junto com o card em .2s. */\n.card.leaving .progress { animation-play-state: paused; }\n@media (prefers-reduced-motion: reduce) {\n .progress.run { animation-duration: 0.01ms; }\n}\n`;\n\nexport class FxToast extends HTMLElement {\n static get observedAttributes() {\n return ['kind', 'title', 'message', 'duration', 'icon', 'mode', 'progress', 'progress-origin'];\n }\n\n /**\n * Exibe a barra de contagem regressiva na base do card.\n *\n * A barra esvazia da esquerda para a direita durante exatamente `duration`\n * e usa a cor do `kind`. Com `duration=\"0\"` (toast fixo) a barra é\n * omitida — não há tempo restante a representar.\n *\n * - `'always'` (ou atributo vazio): barra sempre correndo.\n * - `'hover'`: a barra só corre enquanto o cursor estiver sobre o toast;\n * ao sair, a animação pausa, então dá tempo de ler a mensagem.\n * - `'paused'`: barra visível, porém parada.\n */\n get progress(): 'always' | 'hover' | 'paused' | undefined {\n if (!this.hasAttribute('progress')) return undefined;\n const v = this.getAttribute('progress');\n return v === 'hover' || v === 'paused' ? v : 'always';\n }\n set progress(value: 'always' | 'hover' | 'paused' | undefined) {\n if (value) this.setAttribute('progress', value);\n else this.removeAttribute('progress');\n }\n\n /**\n * Lado a partir do qual a barra esvazia.\n *\n * - `'left'` (padrão): a barra fica ancorada à esquerda e drena da direita\n * para a esquerda.\n * - `'right'`: a barra fica ancorada à direita e drena da esquerda para a\n * direita (espelhado).\n *\n * Só tem efeito junto com `progress`; qualquer valor fora da lista cai em\n * `'left'`.\n */\n get progressOrigin(): 'left' | 'right' {\n return this.getAttribute('progress-origin') === 'right' ? 'right' : 'left';\n }\n set progressOrigin(value: 'left' | 'right') {\n this.setAttribute('progress-origin', value);\n }\n\n /** Duração efetiva em ms (0 = fixo). Mesma regra usada no timer. */\n private get safeDuration(): number {\n const dur = Number(this.getAttribute('duration') ?? '4000');\n if (dur === 0) return 0;\n return Math.max(Number.isNaN(dur) ? 4000 : dur, 1000);\n }\n\n /** Esquema de cores forçado do card: 'light' | 'dark' | undefined (segue o tema). */\n get mode(): 'light' | 'dark' | undefined {\n const m = this.getAttribute('mode');\n return m === 'light' || m === 'dark' ? m : undefined;\n }\n set mode(value: 'light' | 'dark' | undefined) {\n if (value) this.setAttribute('mode', value);\n else this.removeAttribute('mode');\n }\n\n private timer: ReturnType<typeof setTimeout> | null = null;\n\n constructor() {\n super();\n this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback() {\n if (!this.shadowRoot!.firstChild) this.#render();\n // Durações mínimas: valores muito baixos (ex.: digitação parcial no\n // playground) são elevados para 1s; 0 permanece fixo até fechar.\n const safe = this.safeDuration;\n if (safe > 0 && !this.timer) {\n this.timer = setTimeout(() => this.dismiss(), safe);\n }\n this.#syncProgress();\n }\n\n disconnectedCallback() {\n if (this.timer) clearTimeout(this.timer);\n this.timer = null;\n }\n\n attributeChangedCallback(name: string) {\n // A duração é lida em dois lugares (timer + barra): se mudar com o toast\n // na tela, ambos precisam se realinhar.\n if (name === 'duration' || name === 'progress' || name === 'progress-origin' || name === 'kind') {\n this.#syncProgress();\n }\n }\n\n /**\n * Aplica (ou remove) a barra de contagem regressiva.\n *\n * A barra só existe com `progress` e `duration > 0`. O tempo da animação\n * vem de `--toast-duration`, sempre igual ao do `setTimeout` que fecha o\n * toast — assim a barra e o desaparecimento nunca desalinham.\n */\n #syncProgress(): void {\n const card = this.shadowRoot?.querySelector<HTMLElement>('.card');\n if (!card) return;\n const bar = this.shadowRoot!.querySelector<HTMLElement>('.progress');\n const mode = this.progress;\n const dur = this.safeDuration;\n const shouldShow = !!mode && dur > 0;\n\n if (!shouldShow) {\n bar?.remove();\n card.classList.remove('entering');\n return;\n }\n if (!bar) {\n this.shadowRoot!.querySelector('.card')!.insertAdjacentHTML('beforeend', '<span class=\"progress\" part=\"progress\" aria-hidden=\"true\"></span>');\n }\n const el = this.shadowRoot!.querySelector<HTMLElement>('.progress')!;\n el.style.setProperty('--toast-duration', `${dur}ms`);\n // `left` (padrão) => origem à esquerda; `right` espelha a drenagem.\n el.style.setProperty('--toast-progress-origin', `${this.progressOrigin} center`);\n el.classList.remove('run');\n // `paused` mantém a barra cheia e imóvel; `always` e `hover` deixam a\n // animação correr (no `hover`, o CSS só a dispara sob :hover do host).\n if (mode !== 'paused') el.classList.add('run');\n // 1 frame sem animação para o browser registrar o estado inicial cheio\n // antes de a barra começar a esvaziar.\n card.classList.add('entering');\n requestAnimationFrame(() => requestAnimationFrame(() => card.classList.remove('entering')));\n }\n\n dismiss() {\n if (this.timer) clearTimeout(this.timer);\n this.timer = null;\n const card = this.shadowRoot!.querySelector('.card');\n if (card) {\n card.classList.add('leaving');\n setTimeout(() => this.remove(), 200);\n } else {\n this.remove();\n }\n }\n\n #render() {\n const kind = (this.getAttribute('kind') || 'info') as ToastKind;\n const title = this.getAttribute('title') ?? '';\n const msg = this.getAttribute('message') ?? '';\n const color = KIND_COLOR[kind] ?? KIND_COLOR.info;\n const iconName = this.getAttribute('icon');\n const isFxIcon = !!iconName && /^[a-z][a-z0-9_]*$/.test(iconName);\n if (isFxIcon) void import('../../icons');\n const iconContent = isFxIcon ? iconName : KIND_ICON[kind] ?? KIND_ICON.info;\n this.shadowRoot!.innerHTML = `\n <style>${CARD_CSS}</style>\n <div class=\"card\" style=\"--kind:${color}\" role=\"status\" part=\"card\">\n <span class=\"icon${isFxIcon ? ' fx-icon' : ''}\">${iconContent}</span>\n <div class=\"body\">\n ${title ? '<div class=\"title\"></div>' : ''}\n ${msg ? '<div class=\"msg\"></div>' : ''}\n </div>\n <button class=\"close\" aria-label=\"Fechar\">✕</button>\n </div>`;\n const t = this.shadowRoot!.querySelector<HTMLElement>('.title');\n const m = this.shadowRoot!.querySelector<HTMLElement>('.msg');\n if (t) t.textContent = title;\n if (m) m.textContent = msg;\n this.shadowRoot!.querySelector('.close')!.addEventListener('click', () => this.dismiss());\n }\n}\n\n/* ---------- Regiões por posição na tela ---------- */\nfunction regionFor(position: ToastPosition): HTMLElement {\n let region = document.querySelector<HTMLElement>(`[data-fx-toast-region=\"${position}\"]`);\n if (!region) {\n region = document.createElement('div');\n region.setAttribute('data-fx-toast-region', position);\n const [vertical, horizontal] = position.split('-') as [string, string];\n const style = region.style as CSSStyleDeclaration & Record<string, string>;\n style.position = 'fixed';\n style[vertical] = '16px';\n if (horizontal === 'center') {\n style.left = '50%';\n style.transform = 'translateX(-50%)';\n } else {\n style[horizontal] = '16px';\n }\n style.display = 'flex';\n style.flexDirection = 'column';\n style.gap = '8px';\n style.zIndex = '1100';\n style.pointerEvents = 'none';\n // Os cards reabilitam pointer-events via `:host { pointer-events: auto }` (herança),\n // sem necessidade de MutationObserver.\n document.body.appendChild(region);\n }\n return region;\n}\n\nexport interface ToastOptions {\n /** Texto secundário (também aceito como 2º argumento dos métodos). */\n message?: string;\n position?: ToastPosition;\n /** Tempo em ms até sumir. 0 = fixo até fechar. Padrão: 4000 */\n duration?: number;\n /**\n * Barra de contagem regressiva na base do card, na cor do `kind`.\n * `'always'` (padrão) corre sempre; `'hover'` só enquanto o cursor estiver\n * sobre o toast; `'paused'` exibe a barra cheia, porém imóvel.\n * Sem efeito com `duration: 0` (não há tempo restante a representar).\n */\n progress?: 'always' | 'hover' | 'paused';\n /**\n * Lado a partir do qual a barra esvazia. `'left'` (padrão) deixa a barra\n * ancorada à esquerda; `'right'` a ancora à direita (espelhado).\n * Só tem efeito junto com `progress`.\n */\n progressOrigin?: 'left' | 'right';\n /** Força o esquema de cores do card, independentemente do tema global. */\n mode?: 'light' | 'dark';\n}\n\nclass ToastApi {\n private seq = 0;\n private map = new Map<number, FxToast>();\n\n push(kind: ToastKind, title: string, messageOrOpts?: string | ToastOptions, opts?: ToastOptions): number {\n const id = ++this.seq;\n // Assinaturas suportadas:\n // push(kind, title, options)\n // push(kind, title, message, options) <- usada pela doc e mais intuitiva\n const message = typeof messageOrOpts === 'string' ? messageOrOpts : messageOrOpts?.message;\n const o: ToastOptions = { ...(typeof messageOrOpts === 'object' && messageOrOpts ? messageOrOpts : undefined), ...opts };\n const el = document.createElement('fx-toast') as FxToast;\n el.setAttribute('kind', kind);\n el.setAttribute('title', title);\n if (message) el.setAttribute('message', message);\n el.setAttribute('position', o.position ?? 'top-right');\n el.setAttribute('duration', String(o.duration ?? 4000));\n if (o.mode) el.setAttribute('mode', o.mode);\n if (o.progress) el.setAttribute('progress', o.progress);\n if (o.progressOrigin) el.setAttribute('progress-origin', o.progressOrigin);\n regionFor(o.position ?? 'top-right').appendChild(el);\n this.map.set(id, el);\n return id;\n }\n\n close(id: number) {\n this.map.get(id)?.dismiss();\n this.map.delete(id);\n }\n\n success = (t: string, m?: string, o?: ToastOptions) => this.push('success', t, m, o);\n error = (t: string, m?: string, o?: ToastOptions) => this.push('error', t, m, o);\n info = (t: string, m?: string, o?: ToastOptions) => this.push('info', t, m, o);\n warning = (t: string, m?: string, o?: ToastOptions) => this.push('warning', t, m, o);\n}\n\nexport const FenixToast = new ToastApi();\n// Exposto globalmente para uso em HTML puro (onclick=\"FenixToast.success(...)\")\n(globalThis as unknown as Record<string, unknown>).FenixToast = FenixToast;\n\nexport function defineFxToast() {\n if (!customElements.get('fx-toast')) customElements.define('fx-toast', FxToast);\n}\n\n"],"file":"components/toast/toast.js"}
|
package/dist/core/jsx.d.ts
CHANGED
|
@@ -165,10 +165,51 @@ export interface FxTableProps extends FxElementProps {
|
|
|
165
165
|
rows?: number;
|
|
166
166
|
'rows-options'?: string;
|
|
167
167
|
striped?: boolean;
|
|
168
|
+
hover?: boolean;
|
|
168
169
|
'empty-message'?: string;
|
|
169
170
|
'pagination-position'?: FxPaginationPosition;
|
|
170
171
|
total?: number;
|
|
171
172
|
page?: number;
|
|
173
|
+
lazy?: boolean;
|
|
174
|
+
loading?: boolean;
|
|
175
|
+
'loading-message'?: string;
|
|
176
|
+
'sort-field'?: string;
|
|
177
|
+
'sort-order'?: 'asc' | 'desc' | '';
|
|
178
|
+
/** Referência ao markup da toolbar: `#id`/`id` de um elemento fora da tabela. */
|
|
179
|
+
toolbar?: string;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* <fx-column> — declaração de coluna (light DOM do <fx-table>).
|
|
183
|
+
*
|
|
184
|
+
* O template de célula vai em `<fx-cell>` (tag imune a Vue/React/Angular) ou,
|
|
185
|
+
* em markup estático, em `template="#id"`. A forma antiga com `<template>`
|
|
186
|
+
* dentro da coluna continua aceita.
|
|
187
|
+
*/
|
|
188
|
+
export interface FxColumnProps extends FxElementProps {
|
|
189
|
+
field?: string;
|
|
190
|
+
header?: string;
|
|
191
|
+
sortable?: boolean;
|
|
192
|
+
filterable?: boolean;
|
|
193
|
+
align?: 'left' | 'center' | 'right' | 'justify' | 'start' | 'end';
|
|
194
|
+
/** Referência a um elemento de template: `#id` ou `id`. */
|
|
195
|
+
template?: string;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* <fx-cell> — template de renderização de uma célula.
|
|
199
|
+
*
|
|
200
|
+
* Substitui o `<template>` nativo, que é interceptado por Vue/React/Angular.
|
|
201
|
+
* Aceita expressões `{{ }}`, pipes e acesso a `row.*`. Não tem atributos
|
|
202
|
+
* próprios: o conteúdo vem de `children`.
|
|
203
|
+
*/
|
|
204
|
+
export interface FxCellProps extends FxElementProps {
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* <fx-toolbar> — barra de ações acima do header do <fx-table>.
|
|
208
|
+
*
|
|
209
|
+
* Substitui `<template slot="toolbar">`. Inputs com `data-search-fields`
|
|
210
|
+
* viram busca global. Sem atributos próprios.
|
|
211
|
+
*/
|
|
212
|
+
export interface FxToolbarProps extends FxElementProps {
|
|
172
213
|
}
|
|
173
214
|
export interface FxFloatlabelProps extends FxElementProps {
|
|
174
215
|
variant?: FxFloatlabelVariant;
|
|
@@ -198,7 +239,22 @@ export interface FxToastProps extends FxElementProps {
|
|
|
198
239
|
position?: FxToastPosition;
|
|
199
240
|
/** Força o esquema de cores do card independentemente do tema global. */
|
|
200
241
|
mode?: 'light' | 'dark';
|
|
201
|
-
|
|
242
|
+
/**
|
|
243
|
+
* Barra de contagem regressiva na base do card, na cor do `kind`.
|
|
244
|
+
* Vazio ou `'always'` = corre sempre; `'hover'` = só sob cursor/foco;
|
|
245
|
+
* `'paused'` = barra cheia e imóvel. Sem efeito com `duration: 0`.
|
|
246
|
+
*/
|
|
247
|
+
progress?: FxToastProgress | boolean;
|
|
248
|
+
/**
|
|
249
|
+
* Lado a partir do qual a barra esvazia. `'left'` (padrão) ancora a barra à
|
|
250
|
+
* esquerda; `'right'` a ancora à direita (espelhado). Exige `progress`.
|
|
251
|
+
*/
|
|
252
|
+
'progress-origin'?: FxToastOrigin;
|
|
253
|
+
}
|
|
254
|
+
/** Modos da barra de contagem regressiva do <fx-toast>. */
|
|
255
|
+
export type FxToastProgress = 'always' | 'hover' | 'paused';
|
|
256
|
+
/** Lado pelo qual a barra de contagem do <fx-toast> esvazia. */
|
|
257
|
+
export type FxToastOrigin = 'left' | 'right';
|
|
202
258
|
export interface FxTooltipProps extends FxElementProps {
|
|
203
259
|
content?: string;
|
|
204
260
|
position?: FxTooltipPosition;
|
|
@@ -444,6 +500,9 @@ export interface FxJsxIntrinsicElements {
|
|
|
444
500
|
'fx-calendar': FxCalendarProps;
|
|
445
501
|
'fx-datepicker': FxDatepickerProps;
|
|
446
502
|
'fx-table': FxTableProps;
|
|
503
|
+
'fx-column': FxColumnProps;
|
|
504
|
+
'fx-cell': FxCellProps;
|
|
505
|
+
'fx-toolbar': FxToolbarProps;
|
|
447
506
|
'fx-floatlabel': FxFloatlabelProps;
|
|
448
507
|
'fx-dialog': FxDialogProps;
|
|
449
508
|
'fx-drawer': FxDrawerProps;
|
|
@@ -507,6 +566,9 @@ declare global {
|
|
|
507
566
|
'fx-accordion-panel': HTMLElement;
|
|
508
567
|
'fx-orderlist': HTMLElement;
|
|
509
568
|
'fx-picklist': HTMLElement;
|
|
569
|
+
'fx-column': HTMLElement;
|
|
570
|
+
'fx-cell': HTMLElement;
|
|
571
|
+
'fx-toolbar': HTMLElement;
|
|
510
572
|
}
|
|
511
573
|
}
|
|
512
574
|
//# sourceMappingURL=jsx.d.ts.map
|