@wrrdev/fenix-ui 1.1.7 → 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 +18 -3
- package/dist/assets/{base-css-Be_r8aTo.js → font-CF0TXsAP.js} +39 -3
- package/dist/assets/font-CF0TXsAP.js.map +1 -0
- 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/icon/icon.js +79 -0
- package/dist/components/icon/icon.js.map +1 -0
- package/dist/components/icon/index.js +7 -0
- package/dist/components/icon/index.js.map +1 -0
- 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 +199 -116
- package/dist/fenix-ui2.esm.js.map +1 -1
- package/dist/fenix-ui3.esm.js +5 -36
- package/dist/fenix-ui3.esm.js.map +1 -1
- package/dist/fenix-ui4.esm.js +326 -45
- package/dist/fenix-ui4.esm.js.map +1 -1
- package/dist/fenix-ui5.esm.js +44 -16
- package/dist/fenix-ui5.esm.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/plugins/auto-import.d.ts +19 -2
- package/dist/plugins/auto-import.d.ts.map +1 -1
- package/dist/plugins/auto-import.js +43 -15
- package/dist/plugins/auto-import.js.map +1 -1
- package/dist/plugins/index.d.ts +5 -0
- package/dist/plugins/index.d.ts.map +1 -1
- package/dist/plugins/index.js +1 -1
- package/dist/plugins/index.js.map +1 -1
- package/package.json +3 -2
- package/dist/assets/base-css-Be_r8aTo.js.map +0 -1
package/dist/fenix-ui4.esm.js
CHANGED
|
@@ -4,9 +4,9 @@ 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;
|
|
8
|
-
import { a as FENIX_ICON_BASE_CSS, f as fenixIconHtml, e as esc, i as isFenixIconName } from "./assets/
|
|
9
|
-
import { s,
|
|
7
|
+
var _FxToast_instances, syncProgress_fn, render_fn;
|
|
8
|
+
import { a as FENIX_ICON_BASE_CSS, f as fenixIconHtml, e as esc, l as loadFenixIconsFont, i as isFenixIconName } from "./assets/font-CF0TXsAP.js";
|
|
9
|
+
import { s, g } from "./assets/font-CF0TXsAP.js";
|
|
10
10
|
const lightTokens = {
|
|
11
11
|
color: {
|
|
12
12
|
primary: "#c2410c",
|
|
@@ -1967,9 +1967,9 @@ const _FxCalendar = class _FxCalendar extends FxElement {
|
|
|
1967
1967
|
<div class="grid ${this.view}">${cells}</div>
|
|
1968
1968
|
`);
|
|
1969
1969
|
this.root.querySelectorAll("[data-nav]").forEach(
|
|
1970
|
-
(
|
|
1970
|
+
(b) => b.addEventListener(
|
|
1971
1971
|
"click",
|
|
1972
|
-
() => this.navigate(Number(
|
|
1972
|
+
() => this.navigate(Number(b.dataset.nav))
|
|
1973
1973
|
)
|
|
1974
1974
|
);
|
|
1975
1975
|
const gotoBtn = this.root.querySelector("[data-goto]");
|
|
@@ -1978,21 +1978,21 @@ const _FxCalendar = class _FxCalendar extends FxElement {
|
|
|
1978
1978
|
this.render();
|
|
1979
1979
|
});
|
|
1980
1980
|
this.root.querySelectorAll("[data-day]").forEach(
|
|
1981
|
-
(
|
|
1981
|
+
(b) => b.addEventListener(
|
|
1982
1982
|
"click",
|
|
1983
|
-
() => this.pickDay(Number(
|
|
1983
|
+
() => this.pickDay(Number(b.dataset.day))
|
|
1984
1984
|
)
|
|
1985
1985
|
);
|
|
1986
1986
|
this.root.querySelectorAll("[data-month]").forEach(
|
|
1987
|
-
(
|
|
1988
|
-
this.cursor.m = Number(
|
|
1987
|
+
(b) => b.addEventListener("click", () => {
|
|
1988
|
+
this.cursor.m = Number(b.dataset.month);
|
|
1989
1989
|
this.view = "days";
|
|
1990
1990
|
this.render();
|
|
1991
1991
|
})
|
|
1992
1992
|
);
|
|
1993
1993
|
this.root.querySelectorAll("[data-year]").forEach(
|
|
1994
|
-
(
|
|
1995
|
-
this.cursor.y = Number(
|
|
1994
|
+
(b) => b.addEventListener("click", () => {
|
|
1995
|
+
this.cursor.y = Number(b.dataset.year);
|
|
1996
1996
|
this.view = "months";
|
|
1997
1997
|
this.render();
|
|
1998
1998
|
})
|
|
@@ -2403,7 +2403,7 @@ const _FxDatepicker = class _FxDatepicker extends FxElement {
|
|
|
2403
2403
|
if (Number.isNaN(d.getTime())) return null;
|
|
2404
2404
|
const [y, m, day] = iso.split("-").map((n) => parseInt(n, 10));
|
|
2405
2405
|
if (d.getFullYear() !== y || d.getMonth() + 1 !== m || d.getDate() !== day) return null;
|
|
2406
|
-
const cmp = (a,
|
|
2406
|
+
const cmp = (a, b) => a.split("T")[0].localeCompare(b.split("T")[0]);
|
|
2407
2407
|
const min = this.getAttr("min");
|
|
2408
2408
|
const max = this.getAttr("max");
|
|
2409
2409
|
if (min && cmp(iso, min) < 0) return null;
|
|
@@ -2430,9 +2430,9 @@ const _FxDatepicker = class _FxDatepicker extends FxElement {
|
|
|
2430
2430
|
this.setAttribute("start", this.withTime(parsed));
|
|
2431
2431
|
this.removeAttribute("end");
|
|
2432
2432
|
} else {
|
|
2433
|
-
const [a,
|
|
2433
|
+
const [a, b] = [this.getAttr("start").split("T")[0], parsed].sort();
|
|
2434
2434
|
this.setAttribute("start", this.withTime(a));
|
|
2435
|
-
this.setAttribute("end", this.withTime(
|
|
2435
|
+
this.setAttribute("end", this.withTime(b));
|
|
2436
2436
|
}
|
|
2437
2437
|
this.emitChange({ start: this.getAttr("start"), end: this.getAttr("end") });
|
|
2438
2438
|
} else {
|
|
@@ -3301,12 +3301,16 @@ const _FxTable = class _FxTable extends FxElement {
|
|
|
3301
3301
|
"rows",
|
|
3302
3302
|
"rows-options",
|
|
3303
3303
|
"striped",
|
|
3304
|
+
"hover",
|
|
3305
|
+
"toolbar",
|
|
3304
3306
|
"empty-message",
|
|
3305
3307
|
"pagination-position",
|
|
3306
3308
|
"lazy",
|
|
3307
3309
|
"total",
|
|
3308
3310
|
"loading",
|
|
3309
|
-
"loading-message"
|
|
3311
|
+
"loading-message",
|
|
3312
|
+
"sort-field",
|
|
3313
|
+
"sort-order"
|
|
3310
3314
|
];
|
|
3311
3315
|
}
|
|
3312
3316
|
get data() {
|
|
@@ -3335,7 +3339,7 @@ const _FxTable = class _FxTable extends FxElement {
|
|
|
3335
3339
|
}
|
|
3336
3340
|
get columns() {
|
|
3337
3341
|
return [...this.querySelectorAll("fx-column")].map((c) => {
|
|
3338
|
-
const tpl =
|
|
3342
|
+
const tpl = this._resolveCellTemplate(c);
|
|
3339
3343
|
const direct = tpl ? void 0 : c.innerHTML.trim();
|
|
3340
3344
|
const align = c.getAttribute("align") ?? "left";
|
|
3341
3345
|
return {
|
|
@@ -3349,13 +3353,65 @@ const _FxTable = class _FxTable extends FxElement {
|
|
|
3349
3353
|
};
|
|
3350
3354
|
});
|
|
3351
3355
|
}
|
|
3356
|
+
/**
|
|
3357
|
+
* Resolve o template de célula de uma `<fx-column>`, em ordem de prioridade:
|
|
3358
|
+
*
|
|
3359
|
+
* 1. `<fx-cell>` — **recomendado**. Tag própria, sem significado especial
|
|
3360
|
+
* para Vue/React/Angular/Svelte: nenhum framework a intercepta, então o
|
|
3361
|
+
* `innerHTML` sempre chega intacto ao componente. O light DOM do
|
|
3362
|
+
* `<fx-table>` não é exibido (a tabela não usa `<slot>`), então o
|
|
3363
|
+
* conteúdo-fonte nunca aparece na tela.
|
|
3364
|
+
* 2. `template="#id"` (ou `template="id"`) — aponta para um `<template>`
|
|
3365
|
+
* declarado **fora** da tabela, útil em React/Angular, onde é mais
|
|
3366
|
+
* simples manter o markup num único lugar.
|
|
3367
|
+
* 3. `<template>` dentro da coluna — forma **legada**, mantida por
|
|
3368
|
+
* compatibilidade. Em Vue 3 ela vira um bloco do compilador e em React os
|
|
3369
|
+
* filhos são gerenciados pelo framework; nos dois casos o `innerHTML`
|
|
3370
|
+
* chega vazio e a célula não renderiza. Prefira `<fx-cell>`.
|
|
3371
|
+
*/
|
|
3372
|
+
_resolveCellTemplate(c) {
|
|
3373
|
+
const cell = c.querySelector(":scope > fx-cell");
|
|
3374
|
+
if (cell) return cell;
|
|
3375
|
+
const ref = c.getAttribute("template");
|
|
3376
|
+
if (ref) {
|
|
3377
|
+
const alvo = this._resolveRef(ref);
|
|
3378
|
+
if (alvo) return alvo;
|
|
3379
|
+
}
|
|
3380
|
+
return c.querySelector("template");
|
|
3381
|
+
}
|
|
3352
3382
|
get toolbarTemplate() {
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
);
|
|
3383
|
+
const bar = this.querySelector(":scope > fx-toolbar");
|
|
3384
|
+
if (bar) return bar;
|
|
3385
|
+
const ref = this.getAttr("toolbar");
|
|
3386
|
+
if (ref) {
|
|
3387
|
+
const alvo = this._resolveRef(ref);
|
|
3388
|
+
if (alvo) return alvo;
|
|
3389
|
+
}
|
|
3390
|
+
return this.querySelector('template[slot="toolbar"]');
|
|
3391
|
+
}
|
|
3392
|
+
/**
|
|
3393
|
+
* Resolve `ref` para um elemento: `#id`/`id` ⇒ `getElementById` no
|
|
3394
|
+
* documento; qualquer outro valor é tratado como seletor CSS relativo à
|
|
3395
|
+
* própria tabela. Valores inválidos devolvem `null` (sem exceção).
|
|
3396
|
+
*/
|
|
3397
|
+
_resolveRef(ref) {
|
|
3398
|
+
const valor = ref.trim();
|
|
3399
|
+
if (!valor) return null;
|
|
3400
|
+
const doc = this.ownerDocument;
|
|
3401
|
+
if (valor.startsWith("#")) return doc?.getElementById(valor.slice(1)) ?? null;
|
|
3402
|
+
if (/^[.#[>]/.test(valor)) {
|
|
3403
|
+
try {
|
|
3404
|
+
return this.querySelector(valor);
|
|
3405
|
+
} catch {
|
|
3406
|
+
return null;
|
|
3407
|
+
}
|
|
3408
|
+
}
|
|
3409
|
+
return doc?.getElementById(valor) ?? null;
|
|
3356
3410
|
}
|
|
3357
3411
|
connectedCallback() {
|
|
3358
3412
|
this._parseDataAttribute();
|
|
3413
|
+
this._parseSortAttributes();
|
|
3414
|
+
loadFenixIconsFont();
|
|
3359
3415
|
super.connectedCallback();
|
|
3360
3416
|
this._columnObserver = new MutationObserver(() => this.render());
|
|
3361
3417
|
this._columnObserver.observe(this, { childList: true, subtree: true });
|
|
@@ -3364,6 +3420,13 @@ const _FxTable = class _FxTable extends FxElement {
|
|
|
3364
3420
|
this._columnObserver?.disconnect();
|
|
3365
3421
|
super.disconnectedCallback();
|
|
3366
3422
|
}
|
|
3423
|
+
/** Ordenação inicial via `sort-field` / `sort-order` (documentados na API). */
|
|
3424
|
+
_parseSortAttributes() {
|
|
3425
|
+
const field = this.getAttr("sort-field");
|
|
3426
|
+
if (field) this.sortField = field;
|
|
3427
|
+
const order = this.getAttr("sort-order");
|
|
3428
|
+
if (order === "asc" || order === "desc") this.sortDir = order === "asc" ? 1 : -1;
|
|
3429
|
+
}
|
|
3367
3430
|
_parseDataAttribute() {
|
|
3368
3431
|
if (!this._data.length) {
|
|
3369
3432
|
try {
|
|
@@ -3399,8 +3462,8 @@ const _FxTable = class _FxTable extends FxElement {
|
|
|
3399
3462
|
}
|
|
3400
3463
|
const total = this.lazy ? this.total : out.length;
|
|
3401
3464
|
if (this.sortField) {
|
|
3402
|
-
out.sort((a,
|
|
3403
|
-
const av = a[this.sortField], bv =
|
|
3465
|
+
out.sort((a, b) => {
|
|
3466
|
+
const av = a[this.sortField], bv = b[this.sortField];
|
|
3404
3467
|
if (typeof av === "number" && typeof bv === "number")
|
|
3405
3468
|
return (av - bv) * this.sortDir;
|
|
3406
3469
|
return String(av ?? "").localeCompare(String(bv ?? ""), "pt-BR") * this.sortDir;
|
|
@@ -3447,11 +3510,11 @@ const _FxTable = class _FxTable extends FxElement {
|
|
|
3447
3510
|
const pagerHtml = !paginated ? "" : `
|
|
3448
3511
|
<div class="pager" part="pager">
|
|
3449
3512
|
<span class="info">Página ${this.page + 1} de ${pages} · ${total} registros</span>
|
|
3450
|
-
<button type="button" class="pg-btn" data-pg="first" ${this.page === 0 ? "disabled" : ""}
|
|
3451
|
-
<button type="button" class="pg-btn" data-pg="prev" ${this.page === 0 ? "disabled" : ""}
|
|
3513
|
+
<button type="button" class="pg-btn" part="first" aria-label="Primeira página" data-pg="first" ${this.page === 0 ? "disabled" : ""}>${fenixIconHtml("first_page")}</button>
|
|
3514
|
+
<button type="button" class="pg-btn" part="prev" aria-label="Página anterior" data-pg="prev" ${this.page === 0 ? "disabled" : ""}>${fenixIconHtml("navigate_before")}</button>
|
|
3452
3515
|
${Array.from({ length: pages }, (_, p) => `<button type="button" class="pg-btn" data-pg="${p}" aria-current="${p === this.page}">${p + 1}</button>`).join("")}
|
|
3453
|
-
<button type="button" class="pg-btn" data-pg="next" ${this.page >= pages - 1 ? "disabled" : ""}
|
|
3454
|
-
<button type="button" class="pg-btn" data-pg="last" ${this.page >= pages - 1 ? "disabled" : ""}
|
|
3516
|
+
<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>
|
|
3517
|
+
<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>
|
|
3455
3518
|
<label class="info">${esc("Por página:")}
|
|
3456
3519
|
<fx-select class="rows-sel" size="sm" value="${this.rowsPerPage}" aria-label="Itens por página">${this.getAttr(
|
|
3457
3520
|
"rows-options",
|
|
@@ -3588,6 +3651,7 @@ const _FxTable = class _FxTable extends FxElement {
|
|
|
3588
3651
|
}
|
|
3589
3652
|
};
|
|
3590
3653
|
_FxTable.styles = css`
|
|
3654
|
+
${FENIX_ICON_BASE_CSS}
|
|
3591
3655
|
:host {
|
|
3592
3656
|
display: block;
|
|
3593
3657
|
font-family: var(--fx-font-family);
|
|
@@ -3664,17 +3728,14 @@ _FxTable.styles = css`
|
|
|
3664
3728
|
transition: background-color var(--fx-motion-duration-fast)
|
|
3665
3729
|
var(--fx-motion-easing);
|
|
3666
3730
|
}
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
var(--fx-color-primary) 8%,
|
|
3671
|
-
transparent
|
|
3672
|
-
);
|
|
3673
|
-
}
|
|
3731
|
+
/* Listrado: alterna a superfície (cinza). Antes usava
|
|
3732
|
+
--fx-surface-background, que é a MESMA cor do fundo do :host e
|
|
3733
|
+
portanto pintava branco sobre branco (listrado invisível). */
|
|
3674
3734
|
:host([striped]) tbody tr:nth-child(even) {
|
|
3675
|
-
background: var(--fx-surface-
|
|
3735
|
+
background: var(--fx-surface-surface, #f8fafc);
|
|
3676
3736
|
}
|
|
3677
|
-
|
|
3737
|
+
/* O hover é opt-in via atributo (o clique na linha continua sempre ativo). */
|
|
3738
|
+
:host([hover]) tbody tr:hover {
|
|
3678
3739
|
background: color-mix(
|
|
3679
3740
|
in srgb,
|
|
3680
3741
|
var(--fx-color-primary) 8%,
|
|
@@ -3704,6 +3765,9 @@ _FxTable.styles = css`
|
|
|
3704
3765
|
font-size: calc(var(--fx-font-size) - 2px);
|
|
3705
3766
|
}
|
|
3706
3767
|
.pg-btn {
|
|
3768
|
+
display: inline-flex;
|
|
3769
|
+
align-items: center;
|
|
3770
|
+
justify-content: center;
|
|
3707
3771
|
min-width: var(--fx-size-sm);
|
|
3708
3772
|
height: var(--fx-size-sm);
|
|
3709
3773
|
font: inherit;
|
|
@@ -3717,6 +3781,12 @@ _FxTable.styles = css`
|
|
|
3717
3781
|
transition: border-color var(--fx-motion-duration-fast)
|
|
3718
3782
|
var(--fx-motion-easing);
|
|
3719
3783
|
}
|
|
3784
|
+
/* O glifo precisa de 1px a mais que o dígito: a altura de traço do ícone é
|
|
3785
|
+
maior que a do número, então igualar os dois font-size deixa a seta
|
|
3786
|
+
visivelmente maior que o texto. */
|
|
3787
|
+
.pg-btn .fx-icon {
|
|
3788
|
+
font-size: calc(var(--fx-font-size) - 1px);
|
|
3789
|
+
}
|
|
3720
3790
|
.pg-btn:hover:not(:disabled):not([aria-current="true"]) {
|
|
3721
3791
|
border-color: var(--fx-color-primary);
|
|
3722
3792
|
color: var(--fx-color-primary);
|
|
@@ -5465,6 +5535,75 @@ function defineFxAvatar() {
|
|
|
5465
5535
|
return defineElement("fx-avatar", FxAvatar);
|
|
5466
5536
|
}
|
|
5467
5537
|
defineFxAvatar();
|
|
5538
|
+
const _FxIcon = class _FxIcon extends FxElement {
|
|
5539
|
+
static get observedAttributes() {
|
|
5540
|
+
return ["name", "size", "label", "fill", "bold"];
|
|
5541
|
+
}
|
|
5542
|
+
/** Nome do glifo (ou texto livre/emoji). */
|
|
5543
|
+
get name() {
|
|
5544
|
+
return this.getAttr("name");
|
|
5545
|
+
}
|
|
5546
|
+
set name(value) {
|
|
5547
|
+
this.setAttribute("name", value);
|
|
5548
|
+
}
|
|
5549
|
+
/** Tamanho: '' (herda 1em) | 'sm' | 'md' | 'lg' | 'xl'. */
|
|
5550
|
+
get size() {
|
|
5551
|
+
return this.getAttr("size");
|
|
5552
|
+
}
|
|
5553
|
+
set size(value) {
|
|
5554
|
+
if (value) this.setAttribute("size", value);
|
|
5555
|
+
else this.removeAttribute("size");
|
|
5556
|
+
}
|
|
5557
|
+
/** Nome acessível; vazio = ícone decorativo (aria-hidden). */
|
|
5558
|
+
get label() {
|
|
5559
|
+
return this.getAttr("label");
|
|
5560
|
+
}
|
|
5561
|
+
set label(value) {
|
|
5562
|
+
if (value) this.setAttribute("label", value);
|
|
5563
|
+
else this.removeAttribute("label");
|
|
5564
|
+
}
|
|
5565
|
+
connectedCallback() {
|
|
5566
|
+
loadFenixIconsFont();
|
|
5567
|
+
super.connectedCallback();
|
|
5568
|
+
}
|
|
5569
|
+
render() {
|
|
5570
|
+
const name = this.getAttr("name").trim();
|
|
5571
|
+
const label = this.getAttr("label").trim();
|
|
5572
|
+
const a11y = label ? `role="img" aria-label="${esc(label)}"` : 'aria-hidden="true"';
|
|
5573
|
+
if (!name) {
|
|
5574
|
+
this.setTemplate(`<span class="icon" part="icon" ${a11y}></span>`);
|
|
5575
|
+
return;
|
|
5576
|
+
}
|
|
5577
|
+
const inner = isFenixIconName(name) ? `<i class="icon fx-icon" part="icon" ${a11y}>${esc(name)}</i>` : `<span class="icon" part="icon" ${a11y}>${esc(name)}</span>`;
|
|
5578
|
+
this.setTemplate(inner);
|
|
5579
|
+
}
|
|
5580
|
+
};
|
|
5581
|
+
_FxIcon.styles = css`
|
|
5582
|
+
:host {
|
|
5583
|
+
display: inline-flex;
|
|
5584
|
+
align-items: center;
|
|
5585
|
+
justify-content: center;
|
|
5586
|
+
vertical-align: middle;
|
|
5587
|
+
line-height: 1;
|
|
5588
|
+
color: currentColor;
|
|
5589
|
+
font-size: var(--fx-icon-size, 1em);
|
|
5590
|
+
}
|
|
5591
|
+
:host([size='sm']) { font-size: var(--fx-icon-size-sm, 16px); }
|
|
5592
|
+
:host([size='md']) { font-size: var(--fx-icon-size-md, 20px); }
|
|
5593
|
+
:host([size='lg']) { font-size: var(--fx-icon-size-lg, 24px); }
|
|
5594
|
+
:host([size='xl']) { font-size: var(--fx-icon-size-xl, 32px); }
|
|
5595
|
+
:host([hidden]) { display: none; }
|
|
5596
|
+
.icon { display: inline-block; }
|
|
5597
|
+
/* Variantes da fonte (FILL/wght): vencem a classe base .fx-icon. */
|
|
5598
|
+
:host([fill]) .icon { font-variation-settings: 'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 24; }
|
|
5599
|
+
:host([bold]) .icon { font-variation-settings: 'FILL' 0, 'wght' 600, 'GRAD' 0, 'opsz' 24; }
|
|
5600
|
+
${FENIX_ICON_BASE_CSS}
|
|
5601
|
+
`;
|
|
5602
|
+
let FxIcon = _FxIcon;
|
|
5603
|
+
function defineFxIcon() {
|
|
5604
|
+
return defineElement("fx-icon", FxIcon);
|
|
5605
|
+
}
|
|
5606
|
+
defineFxIcon();
|
|
5468
5607
|
const _FxCard = class _FxCard extends FxElement {
|
|
5469
5608
|
static get observedAttributes() {
|
|
5470
5609
|
return ["variant", "radius", "size", "padded", "heading"];
|
|
@@ -7084,6 +7223,48 @@ const CARD_CSS = `
|
|
|
7084
7223
|
color: var(--fx-text-muted, #64748b); font-size: 15px; padding: 2px 4px; border-radius: 4px;
|
|
7085
7224
|
}
|
|
7086
7225
|
.close:hover { color: var(--fx-color-danger, #f43f5e); background: var(--fx-surface-surface-hover, rgba(0,0,0,.05)); }
|
|
7226
|
+
|
|
7227
|
+
/* --- Barra de contagem regressiva (atributo progress) ---
|
|
7228
|
+
Fica na base do card e esvazia durante a duração, na cor do kind (--kind) —
|
|
7229
|
+
ou seja, acompanha success/error/warning/info sem configuração extra.
|
|
7230
|
+
|
|
7231
|
+
O lado é configurável pelo atributo progress-origin (padrão: left):
|
|
7232
|
+
left → a barra drena da direita para a esquerda (ancorada à esquerda)
|
|
7233
|
+
right → a barra drena da esquerda para a direita (ancorada à direita)
|
|
7234
|
+
A origem entra como custom property, então os keyframes são compartilhados.
|
|
7235
|
+
|
|
7236
|
+
Usa escalaX em vez de width: a animação escreve só na compositor, sem
|
|
7237
|
+
reflow por frame. */
|
|
7238
|
+
.card { position: relative; overflow: hidden; }
|
|
7239
|
+
.progress {
|
|
7240
|
+
position: absolute;
|
|
7241
|
+
left: 0;
|
|
7242
|
+
bottom: 0;
|
|
7243
|
+
width: 100%;
|
|
7244
|
+
height: 3px;
|
|
7245
|
+
background: var(--kind);
|
|
7246
|
+
transform-origin: var(--toast-progress-origin, left center);
|
|
7247
|
+
transform: scaleX(1);
|
|
7248
|
+
border-radius: 0 0 var(--fx-radius-md, 8px) var(--fx-radius-md, 8px);
|
|
7249
|
+
pointer-events: none;
|
|
7250
|
+
will-change: transform;
|
|
7251
|
+
}
|
|
7252
|
+
.progress.run { animation: fx-toast-drain var(--toast-duration, 4000ms) linear forwards; }
|
|
7253
|
+
/* No modo hover a animação fica parada até o cursor/foco entrar no card. */
|
|
7254
|
+
.card:hover .progress.run,
|
|
7255
|
+
.card:focus-within .progress.run { animation-play-state: running; }
|
|
7256
|
+
@keyframes fx-toast-drain {
|
|
7257
|
+
from { transform: scaleX(1); }
|
|
7258
|
+
to { transform: scaleX(0); }
|
|
7259
|
+
}
|
|
7260
|
+
/* A barra só começa a correr no 2º frame: no 1º ela já apareceria zerada
|
|
7261
|
+
(o elemento acabou de ser inserido e a animação aplica o estado final). */
|
|
7262
|
+
.card.entering .progress { animation: none; }
|
|
7263
|
+
/* Ao dispensar, congela a barra: ela some junto com o card em .2s. */
|
|
7264
|
+
.card.leaving .progress { animation-play-state: paused; }
|
|
7265
|
+
@media (prefers-reduced-motion: reduce) {
|
|
7266
|
+
.progress.run { animation-duration: 0.01ms; }
|
|
7267
|
+
}
|
|
7087
7268
|
`;
|
|
7088
7269
|
class FxToast extends HTMLElement {
|
|
7089
7270
|
constructor() {
|
|
@@ -7093,7 +7274,51 @@ class FxToast extends HTMLElement {
|
|
|
7093
7274
|
this.attachShadow({ mode: "open" });
|
|
7094
7275
|
}
|
|
7095
7276
|
static get observedAttributes() {
|
|
7096
|
-
return ["kind", "title", "message", "duration", "icon", "mode"];
|
|
7277
|
+
return ["kind", "title", "message", "duration", "icon", "mode", "progress", "progress-origin"];
|
|
7278
|
+
}
|
|
7279
|
+
/**
|
|
7280
|
+
* Exibe a barra de contagem regressiva na base do card.
|
|
7281
|
+
*
|
|
7282
|
+
* A barra esvazia da esquerda para a direita durante exatamente `duration`
|
|
7283
|
+
* e usa a cor do `kind`. Com `duration="0"` (toast fixo) a barra é
|
|
7284
|
+
* omitida — não há tempo restante a representar.
|
|
7285
|
+
*
|
|
7286
|
+
* - `'always'` (ou atributo vazio): barra sempre correndo.
|
|
7287
|
+
* - `'hover'`: a barra só corre enquanto o cursor estiver sobre o toast;
|
|
7288
|
+
* ao sair, a animação pausa, então dá tempo de ler a mensagem.
|
|
7289
|
+
* - `'paused'`: barra visível, porém parada.
|
|
7290
|
+
*/
|
|
7291
|
+
get progress() {
|
|
7292
|
+
if (!this.hasAttribute("progress")) return void 0;
|
|
7293
|
+
const v = this.getAttribute("progress");
|
|
7294
|
+
return v === "hover" || v === "paused" ? v : "always";
|
|
7295
|
+
}
|
|
7296
|
+
set progress(value) {
|
|
7297
|
+
if (value) this.setAttribute("progress", value);
|
|
7298
|
+
else this.removeAttribute("progress");
|
|
7299
|
+
}
|
|
7300
|
+
/**
|
|
7301
|
+
* Lado a partir do qual a barra esvazia.
|
|
7302
|
+
*
|
|
7303
|
+
* - `'left'` (padrão): a barra fica ancorada à esquerda e drena da direita
|
|
7304
|
+
* para a esquerda.
|
|
7305
|
+
* - `'right'`: a barra fica ancorada à direita e drena da esquerda para a
|
|
7306
|
+
* direita (espelhado).
|
|
7307
|
+
*
|
|
7308
|
+
* Só tem efeito junto com `progress`; qualquer valor fora da lista cai em
|
|
7309
|
+
* `'left'`.
|
|
7310
|
+
*/
|
|
7311
|
+
get progressOrigin() {
|
|
7312
|
+
return this.getAttribute("progress-origin") === "right" ? "right" : "left";
|
|
7313
|
+
}
|
|
7314
|
+
set progressOrigin(value) {
|
|
7315
|
+
this.setAttribute("progress-origin", value);
|
|
7316
|
+
}
|
|
7317
|
+
/** Duração efetiva em ms (0 = fixo). Mesma regra usada no timer. */
|
|
7318
|
+
get safeDuration() {
|
|
7319
|
+
const dur = Number(this.getAttribute("duration") ?? "4000");
|
|
7320
|
+
if (dur === 0) return 0;
|
|
7321
|
+
return Math.max(Number.isNaN(dur) ? 4e3 : dur, 1e3);
|
|
7097
7322
|
}
|
|
7098
7323
|
/** Esquema de cores forçado do card: 'light' | 'dark' | undefined (segue o tema). */
|
|
7099
7324
|
get mode() {
|
|
@@ -7106,16 +7331,21 @@ class FxToast extends HTMLElement {
|
|
|
7106
7331
|
}
|
|
7107
7332
|
connectedCallback() {
|
|
7108
7333
|
if (!this.shadowRoot.firstChild) __privateMethod(this, _FxToast_instances, render_fn).call(this);
|
|
7109
|
-
const
|
|
7110
|
-
|
|
7111
|
-
if (!Number.isNaN(safe) && safe > 0 && !this.timer) {
|
|
7334
|
+
const safe = this.safeDuration;
|
|
7335
|
+
if (safe > 0 && !this.timer) {
|
|
7112
7336
|
this.timer = setTimeout(() => this.dismiss(), safe);
|
|
7113
7337
|
}
|
|
7338
|
+
__privateMethod(this, _FxToast_instances, syncProgress_fn).call(this);
|
|
7114
7339
|
}
|
|
7115
7340
|
disconnectedCallback() {
|
|
7116
7341
|
if (this.timer) clearTimeout(this.timer);
|
|
7117
7342
|
this.timer = null;
|
|
7118
7343
|
}
|
|
7344
|
+
attributeChangedCallback(name) {
|
|
7345
|
+
if (name === "duration" || name === "progress" || name === "progress-origin" || name === "kind") {
|
|
7346
|
+
__privateMethod(this, _FxToast_instances, syncProgress_fn).call(this);
|
|
7347
|
+
}
|
|
7348
|
+
}
|
|
7119
7349
|
dismiss() {
|
|
7120
7350
|
if (this.timer) clearTimeout(this.timer);
|
|
7121
7351
|
this.timer = null;
|
|
@@ -7129,6 +7359,36 @@ class FxToast extends HTMLElement {
|
|
|
7129
7359
|
}
|
|
7130
7360
|
}
|
|
7131
7361
|
_FxToast_instances = new WeakSet();
|
|
7362
|
+
/**
|
|
7363
|
+
* Aplica (ou remove) a barra de contagem regressiva.
|
|
7364
|
+
*
|
|
7365
|
+
* A barra só existe com `progress` e `duration > 0`. O tempo da animação
|
|
7366
|
+
* vem de `--toast-duration`, sempre igual ao do `setTimeout` que fecha o
|
|
7367
|
+
* toast — assim a barra e o desaparecimento nunca desalinham.
|
|
7368
|
+
*/
|
|
7369
|
+
syncProgress_fn = function() {
|
|
7370
|
+
const card = this.shadowRoot?.querySelector(".card");
|
|
7371
|
+
if (!card) return;
|
|
7372
|
+
const bar = this.shadowRoot.querySelector(".progress");
|
|
7373
|
+
const mode = this.progress;
|
|
7374
|
+
const dur = this.safeDuration;
|
|
7375
|
+
const shouldShow = !!mode && dur > 0;
|
|
7376
|
+
if (!shouldShow) {
|
|
7377
|
+
bar?.remove();
|
|
7378
|
+
card.classList.remove("entering");
|
|
7379
|
+
return;
|
|
7380
|
+
}
|
|
7381
|
+
if (!bar) {
|
|
7382
|
+
this.shadowRoot.querySelector(".card").insertAdjacentHTML("beforeend", '<span class="progress" part="progress" aria-hidden="true"></span>');
|
|
7383
|
+
}
|
|
7384
|
+
const el = this.shadowRoot.querySelector(".progress");
|
|
7385
|
+
el.style.setProperty("--toast-duration", `${dur}ms`);
|
|
7386
|
+
el.style.setProperty("--toast-progress-origin", `${this.progressOrigin} center`);
|
|
7387
|
+
el.classList.remove("run");
|
|
7388
|
+
if (mode !== "paused") el.classList.add("run");
|
|
7389
|
+
card.classList.add("entering");
|
|
7390
|
+
requestAnimationFrame(() => requestAnimationFrame(() => card.classList.remove("entering")));
|
|
7391
|
+
};
|
|
7132
7392
|
render_fn = function() {
|
|
7133
7393
|
const kind = this.getAttribute("kind") || "info";
|
|
7134
7394
|
const title = this.getAttribute("title") ?? "";
|
|
@@ -7198,6 +7458,8 @@ class ToastApi {
|
|
|
7198
7458
|
el.setAttribute("position", o.position ?? "top-right");
|
|
7199
7459
|
el.setAttribute("duration", String(o.duration ?? 4e3));
|
|
7200
7460
|
if (o.mode) el.setAttribute("mode", o.mode);
|
|
7461
|
+
if (o.progress) el.setAttribute("progress", o.progress);
|
|
7462
|
+
if (o.progressOrigin) el.setAttribute("progress-origin", o.progressOrigin);
|
|
7201
7463
|
regionFor(o.position ?? "top-right").appendChild(el);
|
|
7202
7464
|
this.map.set(id, el);
|
|
7203
7465
|
return id;
|
|
@@ -8295,6 +8557,10 @@ _FxDrawer.styles = css`
|
|
|
8295
8557
|
position: sticky;
|
|
8296
8558
|
top: 0;
|
|
8297
8559
|
background: var(--fx-surface-background);
|
|
8560
|
+
/* O conteúdo do drawer (ex.: abas da customização de tema)
|
|
8561
|
+
rola por trás do header: sem z-index o texto passava POR CIMA
|
|
8562
|
+
e o header parecia transparente. */
|
|
8563
|
+
z-index: 1;
|
|
8298
8564
|
}
|
|
8299
8565
|
.title {
|
|
8300
8566
|
font-weight: 700;
|
|
@@ -8359,6 +8625,10 @@ const _FxPagination = class _FxPagination extends FxElement {
|
|
|
8359
8625
|
get pages() {
|
|
8360
8626
|
return Math.max(1, Math.ceil(this.total / this.rows));
|
|
8361
8627
|
}
|
|
8628
|
+
connectedCallback() {
|
|
8629
|
+
loadFenixIconsFont();
|
|
8630
|
+
super.connectedCallback();
|
|
8631
|
+
}
|
|
8362
8632
|
render() {
|
|
8363
8633
|
const pages = this.pages;
|
|
8364
8634
|
const current = Math.min(Math.max(1, this.page), pages);
|
|
@@ -8369,11 +8639,13 @@ const _FxPagination = class _FxPagination extends FxElement {
|
|
|
8369
8639
|
const to = Math.min(current * this.rows, this.total);
|
|
8370
8640
|
this.setTemplate(`
|
|
8371
8641
|
<span class="info">${this.total ? `${from}-${to} de ${this.total}` : "0 itens"}</span>
|
|
8372
|
-
<button type="button" class="nav" part="
|
|
8642
|
+
<button type="button" class="nav" part="first" aria-label="Primeira página" data-go="1" ${current <= 1 ? "disabled" : ""}>${fenixIconHtml("first_page")}</button>
|
|
8643
|
+
<button type="button" class="nav" part="prev" aria-label="Página anterior" data-go="${current - 1}" ${current <= 1 ? "disabled" : ""}>${fenixIconHtml("navigate_before")}</button>
|
|
8373
8644
|
${window_[0] !== 1 && pages > 5 ? `<button type="button" class="nav" data-go="1">1</button>` : ""}
|
|
8374
8645
|
${window_.map((p) => `<button type="button" class="nav ${p === current ? "active" : ""}" data-go="${p}">${p}</button>`).join("")}
|
|
8375
8646
|
${window_[window_.length - 1] !== pages && pages > 5 ? `<button type="button" class="nav" data-go="${pages}">${pages}</button>` : ""}
|
|
8376
|
-
<button type="button" class="nav" part="next" data-go="${current + 1}" ${current >= pages ? "disabled" : ""}
|
|
8647
|
+
<button type="button" class="nav" part="next" aria-label="Próxima página" data-go="${current + 1}" ${current >= pages ? "disabled" : ""}>${fenixIconHtml("navigate_next")}</button>
|
|
8648
|
+
<button type="button" class="nav" part="last" aria-label="Última página" data-go="${pages}" ${current >= pages ? "disabled" : ""}>${fenixIconHtml("last_page")}</button>
|
|
8377
8649
|
${opts.length ? `
|
|
8378
8650
|
<fx-select class="rows-sel" part="rows" size="sm" value="${this.rows}" aria-label="Itens por página">
|
|
8379
8651
|
${opts.map((o) => `<option value="${esc(o)}">${esc(o)}</option>`).join("")}
|
|
@@ -8409,6 +8681,7 @@ const _FxPagination = class _FxPagination extends FxElement {
|
|
|
8409
8681
|
}
|
|
8410
8682
|
};
|
|
8411
8683
|
_FxPagination.styles = css`
|
|
8684
|
+
${FENIX_ICON_BASE_CSS}
|
|
8412
8685
|
:host {
|
|
8413
8686
|
display: flex;
|
|
8414
8687
|
align-items: center;
|
|
@@ -8420,6 +8693,9 @@ _FxPagination.styles = css`
|
|
|
8420
8693
|
:host([position='center']) { justify-content: center; }
|
|
8421
8694
|
:host([position='right']) { justify-content: flex-end; }
|
|
8422
8695
|
.nav {
|
|
8696
|
+
display: inline-flex;
|
|
8697
|
+
align-items: center;
|
|
8698
|
+
justify-content: center;
|
|
8423
8699
|
min-width: var(--fx-size-sm);
|
|
8424
8700
|
height: var(--fx-size-sm);
|
|
8425
8701
|
border: 1px solid var(--fx-border-default);
|
|
@@ -8434,6 +8710,10 @@ _FxPagination.styles = css`
|
|
|
8434
8710
|
border-color var(--fx-motion-duration-fast) var(--fx-motion-easing),
|
|
8435
8711
|
background var(--fx-motion-duration-fast) var(--fx-motion-easing);
|
|
8436
8712
|
}
|
|
8713
|
+
/* O glifo precisa de 1px a mais que o dígito: a altura de traço do ícone é
|
|
8714
|
+
maior que a do número, então igualar os dois font-size deixa a seta
|
|
8715
|
+
visivelmente maior que o texto. */
|
|
8716
|
+
.nav .fx-icon { font-size: calc(var(--fx-font-size) - 1px); }
|
|
8437
8717
|
.nav:hover:not([disabled]):not(.active) { border-color: var(--fx-color-primary); color: var(--fx-color-primary); }
|
|
8438
8718
|
.nav[disabled] { opacity: 0.5; cursor: not-allowed; }
|
|
8439
8719
|
.nav.active {
|
|
@@ -9451,7 +9731,7 @@ const _FxOrderList = class _FxOrderList extends FxElement {
|
|
|
9451
9731
|
_handleMoveAction(action) {
|
|
9452
9732
|
if (!this._selection.length) return;
|
|
9453
9733
|
const displayData = this._getDisplayData();
|
|
9454
|
-
const selectedIndices = this._selection.map((s2) => displayData.findIndex((d) => this._getItemKey(d, -1) === this._getItemKey(s2, -1))).filter((i) => i >= 0).sort((a,
|
|
9734
|
+
const selectedIndices = this._selection.map((s2) => displayData.findIndex((d) => this._getItemKey(d, -1) === this._getItemKey(s2, -1))).filter((i) => i >= 0).sort((a, b) => a - b);
|
|
9455
9735
|
if (selectedIndices.length === 0) return;
|
|
9456
9736
|
switch (action) {
|
|
9457
9737
|
case "top":
|
|
@@ -9476,7 +9756,7 @@ const _FxOrderList = class _FxOrderList extends FxElement {
|
|
|
9476
9756
|
items.push(this._data[actualIdx]);
|
|
9477
9757
|
actualIndices.push(actualIdx);
|
|
9478
9758
|
}
|
|
9479
|
-
actualIndices.sort((a,
|
|
9759
|
+
actualIndices.sort((a, b) => b - a).forEach((i) => this._data.splice(i, 1));
|
|
9480
9760
|
const insertIdx = this._getActualIndex(0);
|
|
9481
9761
|
this._data.splice(insertIdx, 0, ...items);
|
|
9482
9762
|
this._applyFilter();
|
|
@@ -9492,7 +9772,7 @@ const _FxOrderList = class _FxOrderList extends FxElement {
|
|
|
9492
9772
|
items.push(this._data[actualIdx]);
|
|
9493
9773
|
actualIndices.push(actualIdx);
|
|
9494
9774
|
}
|
|
9495
|
-
actualIndices.sort((a,
|
|
9775
|
+
actualIndices.sort((a, b) => b - a).forEach((i) => this._data.splice(i, 1));
|
|
9496
9776
|
const displayData = this._getDisplayData();
|
|
9497
9777
|
const insertIdx = this._getActualIndex(displayData.length - 1);
|
|
9498
9778
|
this._data.splice(insertIdx + 1, 0, ...items);
|
|
@@ -9504,7 +9784,7 @@ const _FxOrderList = class _FxOrderList extends FxElement {
|
|
|
9504
9784
|
_moveSelectedByOne(indices, delta) {
|
|
9505
9785
|
const displayData = this._getDisplayData();
|
|
9506
9786
|
if (displayData.length === 0) return;
|
|
9507
|
-
const actualIndices = indices.map((idx) => this._getActualIndex(idx)).filter((idx) => idx >= 0).sort((a,
|
|
9787
|
+
const actualIndices = indices.map((idx) => this._getActualIndex(idx)).filter((idx) => idx >= 0).sort((a, b) => a - b);
|
|
9508
9788
|
if (actualIndices.length === 0) return;
|
|
9509
9789
|
if (delta < 0 && actualIndices[0] <= 0) return;
|
|
9510
9790
|
if (delta > 0 && actualIndices[actualIndices.length - 1] >= this._data.length - 1) return;
|
|
@@ -10676,6 +10956,7 @@ export {
|
|
|
10676
10956
|
FxEmptyState,
|
|
10677
10957
|
FxFileUpload,
|
|
10678
10958
|
FxFloatlabel,
|
|
10959
|
+
FxIcon,
|
|
10679
10960
|
FxInput,
|
|
10680
10961
|
FxKnob,
|
|
10681
10962
|
FxMenu,
|
|
@@ -10722,7 +11003,7 @@ export {
|
|
|
10722
11003
|
resetTheme,
|
|
10723
11004
|
s as sanitizeData,
|
|
10724
11005
|
setTokens,
|
|
10725
|
-
|
|
11006
|
+
g as stripTags,
|
|
10726
11007
|
theme,
|
|
10727
11008
|
themePresets,
|
|
10728
11009
|
tokenCssVars
|