@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.
Files changed (46) hide show
  1. package/README.md +2 -2
  2. package/dist/components/drawer/drawer.d.ts.map +1 -1
  3. package/dist/components/drawer/drawer.js +4 -0
  4. package/dist/components/drawer/drawer.js.map +1 -1
  5. package/dist/components/pagination/pagination.d.ts +1 -0
  6. package/dist/components/pagination/pagination.d.ts.map +1 -1
  7. package/dist/components/pagination/pagination.js +18 -2
  8. package/dist/components/pagination/pagination.js.map +1 -1
  9. package/dist/components/table/table.d.ts +38 -4
  10. package/dist/components/table/table.d.ts.map +1 -1
  11. package/dist/components/table/table.js +90 -18
  12. package/dist/components/table/table.js.map +1 -1
  13. package/dist/components/toast/toast.d.ts +46 -1
  14. package/dist/components/toast/toast.d.ts.map +1 -1
  15. package/dist/components/toast/toast.js +128 -5
  16. package/dist/components/toast/toast.js.map +1 -1
  17. package/dist/core/jsx.d.ts +63 -1
  18. package/dist/core/jsx.d.ts.map +1 -1
  19. package/dist/core/jsx.js.map +1 -1
  20. package/dist/core/vue.d.ts +7 -1
  21. package/dist/core/vue.d.ts.map +1 -1
  22. package/dist/core/vue.js.map +1 -1
  23. package/dist/docs/app.d.ts +2 -6
  24. package/dist/docs/app.d.ts.map +1 -1
  25. package/dist/docs/componentes/table.doc.d.ts.map +1 -1
  26. package/dist/docs/componentes/toast.doc.d.ts.map +1 -1
  27. package/dist/docs/router.d.ts +17 -0
  28. package/dist/docs/router.d.ts.map +1 -0
  29. package/dist/docs/shell.d.ts +43 -0
  30. package/dist/docs/shell.d.ts.map +1 -0
  31. package/dist/docs/ui/code.d.ts +12 -0
  32. package/dist/docs/ui/code.d.ts.map +1 -0
  33. package/dist/docs/ui/kit.d.ts +18 -0
  34. package/dist/docs/ui/kit.d.ts.map +1 -0
  35. package/dist/docs/ui/tabs.d.ts +23 -0
  36. package/dist/docs/ui/tabs.d.ts.map +1 -0
  37. package/dist/fenix-ui.umd.min.js +179 -116
  38. package/dist/fenix-ui2.esm.js.map +1 -1
  39. package/dist/fenix-ui4.esm.js +237 -26
  40. package/dist/fenix-ui4.esm.js.map +1 -1
  41. package/dist/fenix-ui5.esm.js +4 -1
  42. package/dist/fenix-ui5.esm.js.map +1 -1
  43. package/dist/plugins/auto-import.d.ts.map +1 -1
  44. package/dist/plugins/auto-import.js +4 -1
  45. package/dist/plugins/auto-import.js.map +1 -1
  46. package/package.json +3 -2
@@ -1 +1 @@
1
- {"version":3,"file":"fenix-ui2.esm.js","sources":["../src/core/vue.ts"],"sourcesContent":["/**\n * Tipagem de componentes <fx-*> para Vue 3 (Volar / vue-tsc).\n *\n * Este módulo é OPT-IN: importe `@wrrdev/fenix-ui/vue` uma única vez\n * (ex.: no `main.ts`) para habilitar autocomplete + validação de atributos\n * dos elementos `fx-*` nos templates SFC.\n *\n * - `IntrinsicElementAttributes` (Vue 3.5+): ponto oficial de extensão para\n * elementos nativos/custom — alimenta `NativeElements` e o\n * `JSX.IntrinsicElements` usado pelo Volar para tags com hífen.\n * - `GlobalComponents`: registro adicional como componentes globais.\n */\nimport type {\n FxAutocompleteProps,\n FxAccordionPanelProps,\n FxAccordionProps,\n FxAlertProps,\n FxAvatarProps,\n FxBadgeProps,\n FxBreadcrumbProps,\n FxButtonProps,\n FxCalendarProps,\n FxCardProps,\n FxCarouselProps,\n FxCheckboxProps,\n FxChipProps,\n FxConfirmPopupProps,\n FxDatepickerProps,\n FxDialogProps,\n FxDropdownItemProps,\n FxDropdownProps,\n FxDrawerProps,\n FxEmptyStateProps,\n FxFileUploadProps,\n FxFloatlabelProps,\n FxIconProps,\n FxInputProps,\n FxKnobProps,\n FxMenuProps,\n FxMultiselectProps,\n FxOrderListProps,\n FxPaginationProps,\n FxPasswordStrengthProps,\n FxPickListProps,\n FxPopoverProps,\n FxProgressProps,\n FxRadioProps,\n FxRatingProps,\n FxSelectProps,\n FxSkeletonProps,\n FxSliderProps,\n FxSpinnerProps,\n FxStepperProps,\n FxSwitchProps,\n FxTableProps,\n FxTabPanelProps,\n FxTabsProps,\n FxTextareaProps,\n FxTimelineProps,\n FxToastProps,\n FxToggleButtonGroupProps,\n FxTooltipProps,\n FxTreeProps,\n} from './jsx';\n\nimport type {} from '@vue/runtime-dom';\n\ntype FxComp<P> = import('vue').FunctionalComponent<P>;\n\ndeclare module '@vue/runtime-core' {\n interface GlobalComponents {\n 'fx-button': FxComp<FxButtonProps>;\n 'fx-badge': FxComp<FxBadgeProps>;\n 'fx-spinner': FxComp<FxSpinnerProps>;\n 'fx-input': FxComp<FxInputProps>;\n 'fx-select': FxComp<FxSelectProps>;\n 'fx-switch': FxComp<FxSwitchProps>;\n 'fx-checkbox': FxComp<FxCheckboxProps>;\n 'fx-radio': FxComp<FxRadioProps>;\n 'fx-textarea': FxComp<FxTextareaProps>;\n 'fx-multiselect': FxComp<FxMultiselectProps>;\n 'fx-calendar': FxComp<FxCalendarProps>;\n 'fx-datepicker': FxComp<FxDatepickerProps>;\n 'fx-table': FxComp<FxTableProps>;\n 'fx-floatlabel': FxComp<FxFloatlabelProps>;\n 'fx-dialog': FxComp<FxDialogProps>;\n 'fx-drawer': FxComp<FxDrawerProps>;\n 'fx-toast': FxComp<FxToastProps>;\n 'fx-tooltip': FxComp<FxTooltipProps>;\n 'fx-tabs': FxComp<FxTabsProps>;\n 'fx-tab-panel': FxComp<FxTabPanelProps>;\n 'fx-progress': FxComp<FxProgressProps>;\n 'fx-skeleton': FxComp<FxSkeletonProps>;\n 'fx-alert': FxComp<FxAlertProps>;\n 'fx-dropdown': FxComp<FxDropdownProps>;\n 'fx-dropdown-item': FxComp<FxDropdownItemProps>;\n 'fx-pagination': FxComp<FxPaginationProps>;\n 'fx-autocomplete': FxComp<FxAutocompleteProps>;\n 'fx-fileupload': FxComp<FxFileUploadProps>;\n 'fx-slider': FxComp<FxSliderProps>;\n 'fx-chip': FxComp<FxChipProps>;\n 'fx-avatar': FxComp<FxAvatarProps>;\n 'fx-icon': FxComp<FxIconProps>;\n 'fx-card': FxComp<FxCardProps>;\n 'fx-breadcrumb': FxComp<FxBreadcrumbProps>;\n 'fx-popover': FxComp<FxPopoverProps>;\n 'fx-stepper': FxComp<FxStepperProps>;\n 'fx-rating': FxComp<FxRatingProps>;\n 'fx-menu': FxComp<FxMenuProps>;\n 'fx-toggle-button-group': FxComp<FxToggleButtonGroupProps>;\n 'fx-empty-state': FxComp<FxEmptyStateProps>;\n 'fx-password-strength': FxComp<FxPasswordStrengthProps>;\n 'fx-timeline': FxComp<FxTimelineProps>;\n 'fx-carousel': FxComp<FxCarouselProps>;\n 'fx-tree': FxComp<FxTreeProps>;\n 'fx-confirmpopup': FxComp<FxConfirmPopupProps>;\n 'fx-knob': FxComp<FxKnobProps>;\n 'fx-accordion': FxComp<FxAccordionProps>;\n 'fx-accordion-panel': FxComp<FxAccordionPanelProps>;\n 'fx-orderlist': FxComp<FxOrderListProps>;\n 'fx-picklist': FxComp<FxPickListProps>;\n }\n}\n\ndeclare module '@vue/runtime-dom' {\n interface IntrinsicElementAttributes {\n 'fx-button': FxButtonProps;\n 'fx-badge': FxBadgeProps;\n 'fx-spinner': FxSpinnerProps;\n 'fx-input': FxInputProps;\n 'fx-select': FxSelectProps;\n 'fx-switch': FxSwitchProps;\n 'fx-checkbox': FxCheckboxProps;\n 'fx-radio': FxRadioProps;\n 'fx-textarea': FxTextareaProps;\n 'fx-multiselect': FxMultiselectProps;\n 'fx-calendar': FxCalendarProps;\n 'fx-datepicker': FxDatepickerProps;\n 'fx-table': FxTableProps;\n 'fx-floatlabel': FxFloatlabelProps;\n 'fx-dialog': FxDialogProps;\n 'fx-drawer': FxDrawerProps;\n 'fx-toast': FxToastProps;\n 'fx-tooltip': FxTooltipProps;\n 'fx-tabs': FxTabsProps;\n 'fx-tab-panel': FxTabPanelProps;\n 'fx-progress': FxProgressProps;\n 'fx-skeleton': FxSkeletonProps;\n 'fx-alert': FxAlertProps;\n 'fx-dropdown': FxDropdownProps;\n 'fx-dropdown-item': FxDropdownItemProps;\n 'fx-pagination': FxPaginationProps;\n 'fx-autocomplete': FxAutocompleteProps;\n 'fx-fileupload': FxFileUploadProps;\n 'fx-slider': FxSliderProps;\n 'fx-chip': FxChipProps;\n 'fx-avatar': FxAvatarProps;\n 'fx-icon': FxIconProps;\n 'fx-card': FxCardProps;\n 'fx-breadcrumb': FxBreadcrumbProps;\n 'fx-popover': FxPopoverProps;\n 'fx-stepper': FxStepperProps;\n 'fx-rating': FxRatingProps;\n 'fx-menu': FxMenuProps;\n 'fx-toggle-button-group': FxToggleButtonGroupProps;\n 'fx-empty-state': FxEmptyStateProps;\n 'fx-password-strength': FxPasswordStrengthProps;\n 'fx-timeline': FxTimelineProps;\n 'fx-carousel': FxCarouselProps;\n 'fx-tree': FxTreeProps;\n 'fx-confirmpopup': FxConfirmPopupProps;\n 'fx-knob': FxKnobProps;\n 'fx-accordion': FxAccordionProps;\n 'fx-accordion-panel': FxAccordionPanelProps;\n 'fx-orderlist': FxOrderListProps;\n 'fx-picklist': FxPickListProps;\n }\n}\n\n/** Marcador para `import '@wrrdev/fenix-ui/vue'` funcionar como side-effect import. */\nexport const FX_VUE_TYPES = true as const;\n\n/** Reexporta os tipos nomeados de props para consumidores Vue. */\nexport type * from './jsx';\n\n"],"names":[],"mappings":"AAoLO,MAAM,eAAe;"}
1
+ {"version":3,"file":"fenix-ui2.esm.js","sources":["../src/core/vue.ts"],"sourcesContent":["/**\n * Tipagem de componentes <fx-*> para Vue 3 (Volar / vue-tsc).\n *\n * Este módulo é OPT-IN: importe `@wrrdev/fenix-ui/vue` uma única vez\n * (ex.: no `main.ts`) para habilitar autocomplete + validação de atributos\n * dos elementos `fx-*` nos templates SFC.\n *\n * - `IntrinsicElementAttributes` (Vue 3.5+): ponto oficial de extensão para\n * elementos nativos/custom — alimenta `NativeElements` e o\n * `JSX.IntrinsicElements` usado pelo Volar para tags com hífen.\n * - `GlobalComponents`: registro adicional como componentes globais.\n */\nimport type {\n FxAutocompleteProps,\n FxAccordionPanelProps,\n FxAccordionProps,\n FxAlertProps,\n FxAvatarProps,\n FxBadgeProps,\n FxBreadcrumbProps,\n FxButtonProps,\n FxCalendarProps,\n FxCardProps,\n FxCarouselProps,\n FxCellProps,\n FxCheckboxProps,\n FxChipProps,\n FxColumnProps,\n FxConfirmPopupProps,\n FxDatepickerProps,\n FxDialogProps,\n FxDropdownItemProps,\n FxDropdownProps,\n FxDrawerProps,\n FxEmptyStateProps,\n FxFileUploadProps,\n FxFloatlabelProps,\n FxIconProps,\n FxInputProps,\n FxKnobProps,\n FxMenuProps,\n FxMultiselectProps,\n FxOrderListProps,\n FxPaginationProps,\n FxPasswordStrengthProps,\n FxPickListProps,\n FxPopoverProps,\n FxProgressProps,\n FxRadioProps,\n FxRatingProps,\n FxSelectProps,\n FxSkeletonProps,\n FxSliderProps,\n FxSpinnerProps,\n FxStepperProps,\n FxSwitchProps,\n FxTableProps,\n FxTabPanelProps,\n FxTabsProps,\n FxTextareaProps,\n FxTimelineProps,\n FxToastProps,\n FxToggleButtonGroupProps,\n FxToolbarProps,\n FxTooltipProps,\n FxTreeProps,\n} from './jsx';\n\nimport type {} from '@vue/runtime-dom';\n\ntype FxComp<P> = import('vue').FunctionalComponent<P>;\n\ndeclare module '@vue/runtime-core' {\n interface GlobalComponents {\n 'fx-button': FxComp<FxButtonProps>;\n 'fx-badge': FxComp<FxBadgeProps>;\n 'fx-spinner': FxComp<FxSpinnerProps>;\n 'fx-input': FxComp<FxInputProps>;\n 'fx-select': FxComp<FxSelectProps>;\n 'fx-switch': FxComp<FxSwitchProps>;\n 'fx-checkbox': FxComp<FxCheckboxProps>;\n 'fx-radio': FxComp<FxRadioProps>;\n 'fx-textarea': FxComp<FxTextareaProps>;\n 'fx-multiselect': FxComp<FxMultiselectProps>;\n 'fx-calendar': FxComp<FxCalendarProps>;\n 'fx-datepicker': FxComp<FxDatepickerProps>;\n 'fx-table': FxComp<FxTableProps>;\n 'fx-column': FxComp<FxColumnProps>;\n 'fx-cell': FxComp<FxCellProps>;\n 'fx-toolbar': FxComp<FxToolbarProps>;\n 'fx-floatlabel': FxComp<FxFloatlabelProps>;\n 'fx-dialog': FxComp<FxDialogProps>;\n 'fx-drawer': FxComp<FxDrawerProps>;\n 'fx-toast': FxComp<FxToastProps>;\n 'fx-tooltip': FxComp<FxTooltipProps>;\n 'fx-tabs': FxComp<FxTabsProps>;\n 'fx-tab-panel': FxComp<FxTabPanelProps>;\n 'fx-progress': FxComp<FxProgressProps>;\n 'fx-skeleton': FxComp<FxSkeletonProps>;\n 'fx-alert': FxComp<FxAlertProps>;\n 'fx-dropdown': FxComp<FxDropdownProps>;\n 'fx-dropdown-item': FxComp<FxDropdownItemProps>;\n 'fx-pagination': FxComp<FxPaginationProps>;\n 'fx-autocomplete': FxComp<FxAutocompleteProps>;\n 'fx-fileupload': FxComp<FxFileUploadProps>;\n 'fx-slider': FxComp<FxSliderProps>;\n 'fx-chip': FxComp<FxChipProps>;\n 'fx-avatar': FxComp<FxAvatarProps>;\n 'fx-icon': FxComp<FxIconProps>;\n 'fx-card': FxComp<FxCardProps>;\n 'fx-breadcrumb': FxComp<FxBreadcrumbProps>;\n 'fx-popover': FxComp<FxPopoverProps>;\n 'fx-stepper': FxComp<FxStepperProps>;\n 'fx-rating': FxComp<FxRatingProps>;\n 'fx-menu': FxComp<FxMenuProps>;\n 'fx-toggle-button-group': FxComp<FxToggleButtonGroupProps>;\n 'fx-empty-state': FxComp<FxEmptyStateProps>;\n 'fx-password-strength': FxComp<FxPasswordStrengthProps>;\n 'fx-timeline': FxComp<FxTimelineProps>;\n 'fx-carousel': FxComp<FxCarouselProps>;\n 'fx-tree': FxComp<FxTreeProps>;\n 'fx-confirmpopup': FxComp<FxConfirmPopupProps>;\n 'fx-knob': FxComp<FxKnobProps>;\n 'fx-accordion': FxComp<FxAccordionProps>;\n 'fx-accordion-panel': FxComp<FxAccordionPanelProps>;\n 'fx-orderlist': FxComp<FxOrderListProps>;\n 'fx-picklist': FxComp<FxPickListProps>;\n }\n}\n\ndeclare module '@vue/runtime-dom' {\n interface IntrinsicElementAttributes {\n 'fx-button': FxButtonProps;\n 'fx-badge': FxBadgeProps;\n 'fx-spinner': FxSpinnerProps;\n 'fx-input': FxInputProps;\n 'fx-select': FxSelectProps;\n 'fx-switch': FxSwitchProps;\n 'fx-checkbox': FxCheckboxProps;\n 'fx-radio': FxRadioProps;\n 'fx-textarea': FxTextareaProps;\n 'fx-multiselect': FxMultiselectProps;\n 'fx-calendar': FxCalendarProps;\n 'fx-datepicker': FxDatepickerProps;\n 'fx-table': FxTableProps;\n 'fx-column': FxColumnProps;\n 'fx-cell': FxCellProps;\n 'fx-toolbar': FxToolbarProps;\n 'fx-floatlabel': FxFloatlabelProps;\n 'fx-dialog': FxDialogProps;\n 'fx-drawer': FxDrawerProps;\n 'fx-toast': FxToastProps;\n 'fx-tooltip': FxTooltipProps;\n 'fx-tabs': FxTabsProps;\n 'fx-tab-panel': FxTabPanelProps;\n 'fx-progress': FxProgressProps;\n 'fx-skeleton': FxSkeletonProps;\n 'fx-alert': FxAlertProps;\n 'fx-dropdown': FxDropdownProps;\n 'fx-dropdown-item': FxDropdownItemProps;\n 'fx-pagination': FxPaginationProps;\n 'fx-autocomplete': FxAutocompleteProps;\n 'fx-fileupload': FxFileUploadProps;\n 'fx-slider': FxSliderProps;\n 'fx-chip': FxChipProps;\n 'fx-avatar': FxAvatarProps;\n 'fx-icon': FxIconProps;\n 'fx-card': FxCardProps;\n 'fx-breadcrumb': FxBreadcrumbProps;\n 'fx-popover': FxPopoverProps;\n 'fx-stepper': FxStepperProps;\n 'fx-rating': FxRatingProps;\n 'fx-menu': FxMenuProps;\n 'fx-toggle-button-group': FxToggleButtonGroupProps;\n 'fx-empty-state': FxEmptyStateProps;\n 'fx-password-strength': FxPasswordStrengthProps;\n 'fx-timeline': FxTimelineProps;\n 'fx-carousel': FxCarouselProps;\n 'fx-tree': FxTreeProps;\n 'fx-confirmpopup': FxConfirmPopupProps;\n 'fx-knob': FxKnobProps;\n 'fx-accordion': FxAccordionProps;\n 'fx-accordion-panel': FxAccordionPanelProps;\n 'fx-orderlist': FxOrderListProps;\n 'fx-picklist': FxPickListProps;\n }\n}\n\n/** Marcador para `import '@wrrdev/fenix-ui/vue'` funcionar como side-effect import. */\nexport const FX_VUE_TYPES = true as const;\n\n/** Reexporta os tipos nomeados de props para consumidores Vue. */\nexport type * from './jsx';\n\n"],"names":[],"mappings":"AA6LO,MAAM,eAAe;"}
@@ -4,8 +4,8 @@ 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, l as loadFenixIconsFont } from "./assets/font-CF0TXsAP.js";
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
9
  import { s, g } from "./assets/font-CF0TXsAP.js";
10
10
  const lightTokens = {
11
11
  color: {
@@ -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 = c.querySelector("template");
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
- return this.querySelector(
3354
- 'template[slot="toolbar"]'
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 {
@@ -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" : ""}>«</button>
3451
- <button type="button" class="pg-btn" data-pg="prev" ${this.page === 0 ? "disabled" : ""}>‹</button>
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" : ""}>›</button>
3454
- <button type="button" class="pg-btn" data-pg="last" ${this.page >= pages - 1 ? "disabled" : ""}>»</button>
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
- tbody tr:hover {
3668
- background: color-mix(
3669
- in srgb,
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-background);
3735
+ background: var(--fx-surface-surface, #f8fafc);
3676
3736
  }
3677
- :host([striped]) tbody tr:hover {
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);
@@ -7153,6 +7223,48 @@ const CARD_CSS = `
7153
7223
  color: var(--fx-text-muted, #64748b); font-size: 15px; padding: 2px 4px; border-radius: 4px;
7154
7224
  }
7155
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
+ }
7156
7268
  `;
7157
7269
  class FxToast extends HTMLElement {
7158
7270
  constructor() {
@@ -7162,7 +7274,51 @@ class FxToast extends HTMLElement {
7162
7274
  this.attachShadow({ mode: "open" });
7163
7275
  }
7164
7276
  static get observedAttributes() {
7165
- 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);
7166
7322
  }
7167
7323
  /** Esquema de cores forçado do card: 'light' | 'dark' | undefined (segue o tema). */
7168
7324
  get mode() {
@@ -7175,16 +7331,21 @@ class FxToast extends HTMLElement {
7175
7331
  }
7176
7332
  connectedCallback() {
7177
7333
  if (!this.shadowRoot.firstChild) __privateMethod(this, _FxToast_instances, render_fn).call(this);
7178
- const dur = Number(this.getAttribute("duration") ?? "4000");
7179
- const safe = dur === 0 ? 0 : Math.max(Number.isNaN(dur) ? 4e3 : dur, 1e3);
7180
- if (!Number.isNaN(safe) && safe > 0 && !this.timer) {
7334
+ const safe = this.safeDuration;
7335
+ if (safe > 0 && !this.timer) {
7181
7336
  this.timer = setTimeout(() => this.dismiss(), safe);
7182
7337
  }
7338
+ __privateMethod(this, _FxToast_instances, syncProgress_fn).call(this);
7183
7339
  }
7184
7340
  disconnectedCallback() {
7185
7341
  if (this.timer) clearTimeout(this.timer);
7186
7342
  this.timer = null;
7187
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
+ }
7188
7349
  dismiss() {
7189
7350
  if (this.timer) clearTimeout(this.timer);
7190
7351
  this.timer = null;
@@ -7198,6 +7359,36 @@ class FxToast extends HTMLElement {
7198
7359
  }
7199
7360
  }
7200
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
+ };
7201
7392
  render_fn = function() {
7202
7393
  const kind = this.getAttribute("kind") || "info";
7203
7394
  const title = this.getAttribute("title") ?? "";
@@ -7267,6 +7458,8 @@ class ToastApi {
7267
7458
  el.setAttribute("position", o.position ?? "top-right");
7268
7459
  el.setAttribute("duration", String(o.duration ?? 4e3));
7269
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);
7270
7463
  regionFor(o.position ?? "top-right").appendChild(el);
7271
7464
  this.map.set(id, el);
7272
7465
  return id;
@@ -8364,6 +8557,10 @@ _FxDrawer.styles = css`
8364
8557
  position: sticky;
8365
8558
  top: 0;
8366
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;
8367
8564
  }
8368
8565
  .title {
8369
8566
  font-weight: 700;
@@ -8428,6 +8625,10 @@ const _FxPagination = class _FxPagination extends FxElement {
8428
8625
  get pages() {
8429
8626
  return Math.max(1, Math.ceil(this.total / this.rows));
8430
8627
  }
8628
+ connectedCallback() {
8629
+ loadFenixIconsFont();
8630
+ super.connectedCallback();
8631
+ }
8431
8632
  render() {
8432
8633
  const pages = this.pages;
8433
8634
  const current = Math.min(Math.max(1, this.page), pages);
@@ -8438,11 +8639,13 @@ const _FxPagination = class _FxPagination extends FxElement {
8438
8639
  const to = Math.min(current * this.rows, this.total);
8439
8640
  this.setTemplate(`
8440
8641
  <span class="info">${this.total ? `${from}-${to} de ${this.total}` : "0 itens"}</span>
8441
- <button type="button" class="nav" part="prev" data-go="${current - 1}" ${current <= 1 ? "disabled" : ""}>‹</button>
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>
8442
8644
  ${window_[0] !== 1 && pages > 5 ? `<button type="button" class="nav" data-go="1">1</button>` : ""}
8443
8645
  ${window_.map((p) => `<button type="button" class="nav ${p === current ? "active" : ""}" data-go="${p}">${p}</button>`).join("")}
8444
8646
  ${window_[window_.length - 1] !== pages && pages > 5 ? `<button type="button" class="nav" data-go="${pages}">${pages}</button>` : ""}
8445
- <button type="button" class="nav" part="next" data-go="${current + 1}" ${current >= pages ? "disabled" : ""}>›</button>
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>
8446
8649
  ${opts.length ? `
8447
8650
  <fx-select class="rows-sel" part="rows" size="sm" value="${this.rows}" aria-label="Itens por página">
8448
8651
  ${opts.map((o) => `<option value="${esc(o)}">${esc(o)}</option>`).join("")}
@@ -8478,6 +8681,7 @@ const _FxPagination = class _FxPagination extends FxElement {
8478
8681
  }
8479
8682
  };
8480
8683
  _FxPagination.styles = css`
8684
+ ${FENIX_ICON_BASE_CSS}
8481
8685
  :host {
8482
8686
  display: flex;
8483
8687
  align-items: center;
@@ -8489,6 +8693,9 @@ _FxPagination.styles = css`
8489
8693
  :host([position='center']) { justify-content: center; }
8490
8694
  :host([position='right']) { justify-content: flex-end; }
8491
8695
  .nav {
8696
+ display: inline-flex;
8697
+ align-items: center;
8698
+ justify-content: center;
8492
8699
  min-width: var(--fx-size-sm);
8493
8700
  height: var(--fx-size-sm);
8494
8701
  border: 1px solid var(--fx-border-default);
@@ -8503,6 +8710,10 @@ _FxPagination.styles = css`
8503
8710
  border-color var(--fx-motion-duration-fast) var(--fx-motion-easing),
8504
8711
  background var(--fx-motion-duration-fast) var(--fx-motion-easing);
8505
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); }
8506
8717
  .nav:hover:not([disabled]):not(.active) { border-color: var(--fx-color-primary); color: var(--fx-color-primary); }
8507
8718
  .nav[disabled] { opacity: 0.5; cursor: not-allowed; }
8508
8719
  .nav.active {