rl-core-front 0.15.2 → 0.15.4

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.15.2",
3
+ "version": "0.15.4",
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",
@@ -202,6 +202,14 @@ export function DataTable<T extends RowData>({
202
202
  */
203
203
  const [dragOffset, setDragOffset] = useState(0);
204
204
  const dragStartY = useRef(0);
205
+ /*
206
+ A altura da linha na mão, medida no momento em que ela é pega.
207
+
208
+ É o tanto que as linhas do caminho se afastam para abrir o buraco onde ela
209
+ vai cair. Medida e não fixa: a altura de uma linha depende do conteúdo, e um
210
+ número chutado abriria um vão maior ou menor que a linha que vem.
211
+ */
212
+ const [dragHeight, setDragHeight] = useState(0);
205
213
 
206
214
  const { hiddenColumns, saveHiddenColumns } = useColumnVisibility(storageKey);
207
215
  const columnVisibility = useMemo<ColumnVisibilityState>(() => {
@@ -282,6 +290,9 @@ export function DataTable<T extends RowData>({
282
290
  // A captura mantém os eventos na alça mesmo com o dedo já longe dela;
283
291
  // sem ela, o arrasto morre no primeiro pixel fora do botão.
284
292
  event.currentTarget.setPointerCapture(event.pointerId);
293
+ setDragHeight(
294
+ event.currentTarget.closest("tr")?.getBoundingClientRect().height ?? 0,
295
+ );
285
296
  dragStartY.current = event.clientY;
286
297
  setDragOffset(0);
287
298
  setDraggedRow(rowId);
@@ -289,35 +300,36 @@ export function DataTable<T extends RowData>({
289
300
  };
290
301
 
291
302
  /**
292
- * Que linha está embaixo do ponteiro.
303
+ * Onde a linha está agora: quantas linhas ela já subiu ou desceu.
293
304
  *
294
- * Pelo ponto e não pelo alvo do evento: com a captura ativa, todo `move`
295
- * chega na alça de origem, e é o `elementFromPoint` que sabe onde o dedo
296
- * está de verdade.
305
+ * Conta pelo deslocamento, e não por quem está embaixo do ponteiro. Quem
306
+ * está embaixo do ponteiro é a **própria linha arrastada** ela viaja com o
307
+ * dedo —, e perguntar ao ponto devolvia origem e destino iguais: o arrasto
308
+ * terminava sem gravar nada. Além disso as linhas paradas se movem para
309
+ * abrir o vão, então o que o ponto responde muda durante o gesto e a
310
+ * escolha do destino ficaria oscilando entre duas linhas.
297
311
  */
298
312
  const moveRowDrag = (event: ReactPointerEvent<HTMLButtonElement>): void => {
299
- if (!draggedRow) {
313
+ if (!draggedRow || dragHeight === 0) {
300
314
  return;
301
315
  }
302
316
 
303
- setDragOffset(event.clientY - dragStartY.current);
317
+ const offset = event.clientY - dragStartY.current;
318
+ setDragOffset(offset);
304
319
 
305
- const under = document
306
- .elementFromPoint(event.clientX, event.clientY)
307
- ?.closest("tr[data-row-id]");
308
- const id = under?.getAttribute("data-row-id");
320
+ const rows = table.getRowModel().rows;
321
+ const from = rows.findIndex((row) => row.id === draggedRow);
322
+ // Meia linha de deslocamento já troca de lugar: é o ponto em que a linha
323
+ // arrastada cobre mais a vizinha do que o próprio lugar de origem.
324
+ const destino = Math.min(
325
+ Math.max(from + Math.round(offset / dragHeight), 0),
326
+ rows.length - 1,
327
+ );
309
328
 
310
- if (id) {
311
- setTargetRow(id);
312
- }
329
+ setTargetRow(rows[destino]?.id ?? draggedRow);
313
330
  };
314
331
 
315
- /**
316
- * Onde a linha saiu e onde ela está agora, na página desenhada.
317
- *
318
- * Os dois só para saber de que lado a guia de destino aparece — descendo,
319
- * embaixo do alvo; subindo, em cima dele.
320
- */
332
+ /** Onde a linha saiu e onde ela está agora, na página desenhada. */
321
333
  const draggedIndex = table
322
334
  .getRowModel()
323
335
  .rows.findIndex((row) => row.id === draggedRow);
@@ -325,6 +337,30 @@ export function DataTable<T extends RowData>({
325
337
  .getRowModel()
326
338
  .rows.findIndex((row) => row.id === targetRow);
327
339
 
340
+ /**
341
+ * Quanto uma linha parada se desloca para abrir o buraco.
342
+ *
343
+ * As linhas entre a origem e o destino sobem (ou descem) a altura de uma
344
+ * linha, e o vão aparece exatamente onde a linha vai cair. É isso que
345
+ * responde "para onde isto está indo" durante o gesto — um traço de destino
346
+ * diz o mesmo em teoria, mas exige ler a tabela para achá-lo.
347
+ */
348
+ const rowShift = (index: number): number => {
349
+ if (draggedRow === null || draggedIndex < 0 || targetIndex < 0) {
350
+ return 0;
351
+ }
352
+
353
+ if (index > draggedIndex && index <= targetIndex) {
354
+ return -dragHeight;
355
+ }
356
+
357
+ if (index >= targetIndex && index < draggedIndex) {
358
+ return dragHeight;
359
+ }
360
+
361
+ return 0;
362
+ };
363
+
328
364
  /** Soltou: avisa quem chamou e devolve a tabela ao estado parado. */
329
365
  const endRowDrag = (): void => {
330
366
  if (draggedRow && targetRow && draggedRow !== targetRow) {
@@ -467,17 +503,9 @@ export function DataTable<T extends RowData>({
467
503
  </TableRow>
468
504
  )}
469
505
  {!loading &&
470
- table.getRowModel().rows.map((row) => {
506
+ table.getRowModel().rows.map((row, index) => {
471
507
  const dragging = draggedRow === row.id;
472
- // A guia aparece do lado para onde a linha está indo: descendo,
473
- // embaixo do alvo; subindo, em cima dele. É ela que responde
474
- // "onde isto vai cair" antes de soltar.
475
- const guide =
476
- draggedRow !== null && targetRow === row.id && !dragging
477
- ? targetIndex > draggedIndex
478
- ? "border-b-2 border-b-primary"
479
- : "border-t-2 border-t-primary"
480
- : undefined;
508
+ const shift = dragging ? 0 : rowShift(index);
481
509
 
482
510
  return (
483
511
  <TableRow
@@ -487,14 +515,30 @@ export function DataTable<T extends RowData>({
487
515
  // A linha viaja com o dedo, destacada do resto da tabela —
488
516
  // é o que diz que o arrasto pegou, e qual linha pegou.
489
517
  dragging &&
490
- "relative z-20 bg-card shadow-lg ring-1 ring-primary/50 [&>td]:opacity-90",
518
+ "relative z-20 bg-card shadow-xl ring-1 ring-primary/50",
491
519
  draggedRow !== null && "select-none",
492
- guide,
520
+ /*
521
+ A transição existe só enquanto o arrasto dura, e só nas
522
+ linhas paradas: na que segue o dedo ela viraria atraso,
523
+ e depois de soltar ela animaria a volta ao zero por
524
+ cima da lista já reordenada — dois movimentos ao mesmo
525
+ tempo, que é o tremor que se vê ao largar a linha.
526
+ */
527
+ draggedRow !== null &&
528
+ !dragging &&
529
+ "transition-transform duration-200",
493
530
  )}
494
531
  style={
495
532
  dragging
496
- ? { transform: `translateY(${dragOffset}px)` }
497
- : undefined
533
+ ? {
534
+ // O `scale` é o "levantou da mesa": a linha na mão
535
+ // fica maior que as paradas, como o card que sai
536
+ // da coluna no quadro.
537
+ transform: `translateY(${dragOffset}px) scale(1.01)`,
538
+ }
539
+ : shift !== 0
540
+ ? { transform: `translateY(${shift}px)` }
541
+ : undefined
498
542
  }
499
543
  >
500
544
  {reorderable && (