rl-core-front 0.18.5 → 0.18.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rl-core-front",
3
- "version": "0.18.5",
3
+ "version": "0.18.7",
4
4
  "description": "Telas e componentes Next.js do core: login com 2FA, usuários, RBAC, auditoria, logs e listagens com filtro dinâmico",
5
5
  "author": "Rodrigo Liberti",
6
6
  "license": "MIT",
@@ -34,6 +34,7 @@ import {
34
34
  import type {
35
35
  CSSProperties,
36
36
  JSX,
37
+ MouseEvent as ReactMouseEvent,
37
38
  PointerEvent as ReactPointerEvent,
38
39
  } from "react";
39
40
  import { Fragment, useEffect, useMemo, useRef, useState } from "react";
@@ -468,9 +469,40 @@ const CELL_MAX_WIDTH = "24rem";
468
469
  * cortaria botão de ação. A que declara `wrap` também: nela a quebra é o
469
470
  * desenho.
470
471
  */
471
- function cellStyle(columnDef: {
472
- meta?: unknown;
473
- }): { className?: string; style?: CSSProperties } {
472
+ /** A célula (ou o que ela tem dentro) não coube e está cortada. */
473
+ function isClipped(cell: HTMLElement): boolean {
474
+ if (cell.scrollWidth > cell.clientWidth) {
475
+ return true;
476
+ }
477
+
478
+ return Array.from(cell.children).some(
479
+ (child) => child.scrollWidth > child.clientWidth,
480
+ );
481
+ }
482
+
483
+ /**
484
+ * Abre a célula sob o cursor — se houver o que abrir.
485
+ *
486
+ * A medição acontece aqui, e não em cada render: enquanto ninguém passa o
487
+ * mouse, isto não custa nada. E mexer na `dataset` em vez de subir estado
488
+ * evita re-renderizar a tabela inteira a cada célula que o ponteiro cruza.
489
+ */
490
+ function expandIfClipped(event: ReactMouseEvent<HTMLTableCellElement>): void {
491
+ if (isClipped(event.currentTarget)) {
492
+ event.currentTarget.dataset.expand = "true";
493
+ }
494
+ }
495
+
496
+ function collapse(event: ReactMouseEvent<HTMLTableCellElement>): void {
497
+ delete event.currentTarget.dataset.expand;
498
+ }
499
+
500
+ function cellStyle(columnDef: { meta?: unknown }): {
501
+ className?: string;
502
+ style?: CSSProperties;
503
+ onMouseEnter?: (event: ReactMouseEvent<HTMLTableCellElement>) => void;
504
+ onMouseLeave?: (event: ReactMouseEvent<HTMLTableCellElement>) => void;
505
+ } {
474
506
  const meta = columnDef.meta as DataTableColumnMeta | undefined;
475
507
 
476
508
  if (meta?.shrink || meta?.wrap) {
@@ -486,9 +518,25 @@ function cellStyle(columnDef: {
486
518
  o filho e não a célula. Repetindo o corte no filho direto, as reticências
487
519
  aparecem nos dois casos.
488
520
  */
521
+ /*
522
+ E o mouse em cima devolve o texto inteiro — mas **só na célula que está de
523
+ fato cortada**.
524
+
525
+ Com `hover:` puro, passar o mouse por uma célula que já cabia inteira a
526
+ fazia quebrar em duas linhas do mesmo jeito, e a linha inteira pulava sob o
527
+ cursor. CSS não sabe se houve corte; quem sabe é o layout já calculado, daí
528
+ a medição no `mouseenter` — que não custa render nenhum enquanto ninguém
529
+ passa o mouse. O `data-expand` liga as duas regras abaixo.
530
+
531
+ Sem `title`, que só aparece depois de um segundo parado, e sem tooltip
532
+ flutuante, que sairia da tabela e taparia a linha de baixo.
533
+ */
489
534
  return {
490
- className: "truncate [&>*]:truncate",
535
+ className:
536
+ "truncate [&>*]:truncate data-[expand=true]:whitespace-normal data-[expand=true]:[&>*]:whitespace-normal",
491
537
  style: { maxWidth: meta?.maxWidth ?? CELL_MAX_WIDTH },
538
+ onMouseEnter: expandIfClipped,
539
+ onMouseLeave: collapse,
492
540
  };
493
541
  }
494
542