@flowtomic/logic 0.1.0
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/dist/hooks/useMoblile/index.d.ts +2 -0
- package/dist/hooks/useMoblile/index.d.ts.map +1 -0
- package/dist/hooks/useMoblile/index.js +868 -0
- package/dist/hooks/useMoblile/useMobile.d.ts +2 -0
- package/dist/hooks/useMoblile/useMobile.d.ts.map +1 -0
- package/dist/hooks/useMoblile/useMobile.js +15 -0
- package/dist/hooks/useReactTableBack/index.d.ts +3 -0
- package/dist/hooks/useReactTableBack/index.d.ts.map +1 -0
- package/dist/hooks/useReactTableBack/index.js +1 -0
- package/dist/hooks/useReactTableBack/useReactTableBack.d.ts +102 -0
- package/dist/hooks/useReactTableBack/useReactTableBack.d.ts.map +1 -0
- package/dist/hooks/useReactTableBack/useReactTableBack.js +124 -0
- package/dist/hooks/useReactTableFront/index.d.ts +3 -0
- package/dist/hooks/useReactTableFront/index.d.ts.map +1 -0
- package/dist/hooks/useReactTableFront/index.js +1 -0
- package/dist/hooks/useReactTableFront/useReactTableFront.d.ts +90 -0
- package/dist/hooks/useReactTableFront/useReactTableFront.d.ts.map +1 -0
- package/dist/hooks/useReactTableFront/useReactTableFront.js +112 -0
- package/dist/hooks/useResizable/index.d.ts +3 -0
- package/dist/hooks/useResizable/index.d.ts.map +1 -0
- package/dist/hooks/useResizable/index.js +1 -0
- package/dist/hooks/useResizable/useResizable.d.ts +37 -0
- package/dist/hooks/useResizable/useResizable.d.ts.map +1 -0
- package/dist/hooks/useResizable/useResizable.js +116 -0
- package/dist/hooks/useStatCard/index.d.ts +3 -0
- package/dist/hooks/useStatCard/index.d.ts.map +1 -0
- package/dist/hooks/useStatCard/index.js +1 -0
- package/dist/hooks/useStatCard/useStatCard.d.ts +144 -0
- package/dist/hooks/useStatCard/useStatCard.d.ts.map +1 -0
- package/dist/hooks/useStatCard/useStatCard.js +126 -0
- package/dist/hooks/useThemeTransition/index.d.ts +3 -0
- package/dist/hooks/useThemeTransition/index.d.ts.map +1 -0
- package/dist/hooks/useThemeTransition/index.js +1 -0
- package/dist/hooks/useThemeTransition/useThemeTransition.d.ts +32 -0
- package/dist/hooks/useThemeTransition/useThemeTransition.d.ts.map +1 -0
- package/dist/hooks/useThemeTransition/useThemeTransition.js +35 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/package.json +54 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useMobile.d.ts","sourceRoot":"","sources":["../../../src/hooks/useMoblile/useMobile.ts"],"names":[],"mappings":"AAIA,wBAAgB,WAAW,YAc1B"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
const MOBILE_BREAKPOINT = 768;
|
|
3
|
+
export function useIsMobile() {
|
|
4
|
+
const [isMobile, setIsMobile] = React.useState(undefined);
|
|
5
|
+
React.useEffect(() => {
|
|
6
|
+
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
|
|
7
|
+
const onChange = () => {
|
|
8
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
9
|
+
};
|
|
10
|
+
mql.addEventListener("change", onChange);
|
|
11
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
12
|
+
return () => mql.removeEventListener("change", onChange);
|
|
13
|
+
}, []);
|
|
14
|
+
return !!isMobile;
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/useReactTableBack/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAC7F,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useReactTableBack } from "./useReactTableBack";
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useReactTableBack - Headless UI Hook
|
|
3
|
+
*
|
|
4
|
+
* Hook headless para TanStack Table com paginação e ordenação no backend (server-side).
|
|
5
|
+
* Fornece apenas: lógica, estado, processamento e API
|
|
6
|
+
* NÃO fornece: markup, styles ou implementações pré-construídas
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* function MyTable() {
|
|
11
|
+
* const { table, sorting, pagination, setPagination, paginationInfo } = useReactTableBack({
|
|
12
|
+
* data: pageData,
|
|
13
|
+
* columns: columnDefs,
|
|
14
|
+
* totalCount: 1000,
|
|
15
|
+
* onPaginationChange: ({ pageIndex, pageSize }) => {
|
|
16
|
+
* fetchData({ page: pageIndex + 1, pageSize });
|
|
17
|
+
* },
|
|
18
|
+
* onSortingChange: (sorting) => {
|
|
19
|
+
* fetchData({ sorting });
|
|
20
|
+
* },
|
|
21
|
+
* })
|
|
22
|
+
*
|
|
23
|
+
* return (
|
|
24
|
+
* <table>
|
|
25
|
+
* {/* Usar table.getHeaderGroups(), table.getRowModel(), etc. *\/}
|
|
26
|
+
* </table>
|
|
27
|
+
* )
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
import { type ColumnDef, type ColumnFiltersState, type PaginationState, type SortingState, type Table, type VisibilityState } from "@tanstack/react-table";
|
|
32
|
+
export interface UseReactTableBackOptions<T extends Record<string, unknown>> {
|
|
33
|
+
/** Dados da tabela (apenas da página atual) */
|
|
34
|
+
data: T[];
|
|
35
|
+
/** Definição das colunas */
|
|
36
|
+
columns: ColumnDef<T, unknown>[];
|
|
37
|
+
/** Total de itens no servidor (necessário para calcular páginas) */
|
|
38
|
+
totalCount: number;
|
|
39
|
+
/** Habilitar paginação */
|
|
40
|
+
enablePagination?: boolean;
|
|
41
|
+
/** Tamanho da página */
|
|
42
|
+
pageSize?: number;
|
|
43
|
+
/** Callback quando paginação muda */
|
|
44
|
+
onPaginationChange?: (pagination: {
|
|
45
|
+
pageIndex: number;
|
|
46
|
+
pageSize: number;
|
|
47
|
+
}) => void;
|
|
48
|
+
/** Habilitar ordenação */
|
|
49
|
+
enableSorting?: boolean;
|
|
50
|
+
/** Estado inicial de ordenação */
|
|
51
|
+
initialSorting?: SortingState;
|
|
52
|
+
/** Callback quando ordenação muda */
|
|
53
|
+
onSortingChange?: (sorting: SortingState) => void;
|
|
54
|
+
/** Estado inicial de filtros de coluna */
|
|
55
|
+
initialColumnFilters?: ColumnFiltersState;
|
|
56
|
+
/** Estado inicial de visibilidade de colunas */
|
|
57
|
+
initialColumnVisibility?: VisibilityState;
|
|
58
|
+
/** Habilitar seleção de linhas */
|
|
59
|
+
enableRowSelection?: boolean;
|
|
60
|
+
/** Callback quando a seleção muda */
|
|
61
|
+
onSelectionChange?: (selectedRows: T[]) => void;
|
|
62
|
+
}
|
|
63
|
+
export interface UseReactTableBackReturn<T extends Record<string, unknown>> {
|
|
64
|
+
/** Instância do TanStack Table */
|
|
65
|
+
table: Table<T>;
|
|
66
|
+
/** Estado de ordenação */
|
|
67
|
+
sorting: SortingState;
|
|
68
|
+
/** Função para atualizar ordenação */
|
|
69
|
+
setSorting: (sorting: SortingState | ((prev: SortingState) => SortingState)) => void;
|
|
70
|
+
/** Estado de paginação */
|
|
71
|
+
pagination: PaginationState;
|
|
72
|
+
/** Função para atualizar paginação */
|
|
73
|
+
setPagination: (pagination: PaginationState | ((prev: PaginationState) => PaginationState)) => void;
|
|
74
|
+
/** Estado de filtros de coluna */
|
|
75
|
+
columnFilters: ColumnFiltersState;
|
|
76
|
+
/** Função para atualizar filtros de coluna */
|
|
77
|
+
setColumnFilters: (filters: ColumnFiltersState | ((prev: ColumnFiltersState) => ColumnFiltersState)) => void;
|
|
78
|
+
/** Estado de filtro global (não usado em server-side, mas mantido para compatibilidade) */
|
|
79
|
+
globalFilter: string;
|
|
80
|
+
/** Função para atualizar filtro global (não usado em server-side, mas mantido para compatibilidade) */
|
|
81
|
+
setGlobalFilter: (filter: string) => void;
|
|
82
|
+
/** Estado de visibilidade de colunas */
|
|
83
|
+
columnVisibility: VisibilityState;
|
|
84
|
+
/** Função para atualizar visibilidade de colunas */
|
|
85
|
+
setColumnVisibility: (visibility: VisibilityState | ((prev: VisibilityState) => VisibilityState)) => void;
|
|
86
|
+
/** Estado de seleção de linhas */
|
|
87
|
+
rowSelection: Record<string, boolean>;
|
|
88
|
+
/** Função para atualizar seleção de linhas */
|
|
89
|
+
setRowSelection: (selection: Record<string, boolean> | ((prev: Record<string, boolean>) => Record<string, boolean>)) => void;
|
|
90
|
+
/** Informações de paginação calculadas */
|
|
91
|
+
paginationInfo: {
|
|
92
|
+
start: number;
|
|
93
|
+
end: number;
|
|
94
|
+
total: number;
|
|
95
|
+
pageCount: number;
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Hook Headless UI para TanStack Table com paginação/ordenação server-side
|
|
100
|
+
*/
|
|
101
|
+
export declare function useReactTableBack<T extends Record<string, unknown>>(options: UseReactTableBackOptions<T>): UseReactTableBackReturn<T>;
|
|
102
|
+
//# sourceMappingURL=useReactTableBack.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useReactTableBack.d.ts","sourceRoot":"","sources":["../../../src/hooks/useReactTableBack/useReactTableBack.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useReactTableBack - Headless UI Hook
|
|
3
|
+
*
|
|
4
|
+
* Hook headless para TanStack Table com paginação e ordenação no backend (server-side).
|
|
5
|
+
* Fornece apenas: lógica, estado, processamento e API
|
|
6
|
+
* NÃO fornece: markup, styles ou implementações pré-construídas
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* function MyTable() {
|
|
11
|
+
* const { table, sorting, pagination, setPagination, paginationInfo } = useReactTableBack({
|
|
12
|
+
* data: pageData,
|
|
13
|
+
* columns: columnDefs,
|
|
14
|
+
* totalCount: 1000,
|
|
15
|
+
* onPaginationChange: ({ pageIndex, pageSize }) => {
|
|
16
|
+
* fetchData({ page: pageIndex + 1, pageSize });
|
|
17
|
+
* },
|
|
18
|
+
* onSortingChange: (sorting) => {
|
|
19
|
+
* fetchData({ sorting });
|
|
20
|
+
* },
|
|
21
|
+
* })
|
|
22
|
+
*
|
|
23
|
+
* return (
|
|
24
|
+
* <table>
|
|
25
|
+
* {/* Usar table.getHeaderGroups(), table.getRowModel(), etc. *\/}
|
|
26
|
+
* </table>
|
|
27
|
+
* )
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
import { getCoreRowModel, useReactTable, } from "@tanstack/react-table";
|
|
32
|
+
import { useEffect, useMemo, useState } from "react";
|
|
33
|
+
/**
|
|
34
|
+
* Hook Headless UI para TanStack Table com paginação/ordenação server-side
|
|
35
|
+
*/
|
|
36
|
+
export function useReactTableBack(options) {
|
|
37
|
+
const { data, columns, totalCount, enablePagination = true, pageSize = 10, onPaginationChange, enableSorting = true, initialSorting = [], onSortingChange, initialColumnFilters = [], initialColumnVisibility = {}, enableRowSelection = false, onSelectionChange, } = options;
|
|
38
|
+
const [sorting, setSorting] = useState(initialSorting);
|
|
39
|
+
const [columnFilters, setColumnFilters] = useState(initialColumnFilters);
|
|
40
|
+
const [globalFilter, setGlobalFilter] = useState("");
|
|
41
|
+
const [columnVisibility, setColumnVisibility] = useState(initialColumnVisibility);
|
|
42
|
+
const [rowSelection, setRowSelection] = useState({});
|
|
43
|
+
const [pagination, setPagination] = useState({
|
|
44
|
+
pageIndex: 0,
|
|
45
|
+
pageSize,
|
|
46
|
+
});
|
|
47
|
+
// Notificar mudanças de paginação (server-side)
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (enablePagination && onPaginationChange) {
|
|
50
|
+
onPaginationChange({
|
|
51
|
+
pageIndex: pagination.pageIndex,
|
|
52
|
+
pageSize: pagination.pageSize,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}, [pagination, enablePagination, onPaginationChange]);
|
|
56
|
+
// Notificar mudanças de ordenação (server-side)
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
if (enableSorting && onSortingChange) {
|
|
59
|
+
onSortingChange(sorting);
|
|
60
|
+
}
|
|
61
|
+
}, [sorting, enableSorting, onSortingChange]);
|
|
62
|
+
const table = useReactTable({
|
|
63
|
+
data,
|
|
64
|
+
columns,
|
|
65
|
+
state: {
|
|
66
|
+
sorting: enableSorting ? sorting : undefined,
|
|
67
|
+
columnFilters,
|
|
68
|
+
columnVisibility,
|
|
69
|
+
rowSelection: enableRowSelection ? rowSelection : undefined,
|
|
70
|
+
pagination: enablePagination ? pagination : undefined,
|
|
71
|
+
},
|
|
72
|
+
onSortingChange: enableSorting ? setSorting : undefined,
|
|
73
|
+
onColumnFiltersChange: setColumnFilters,
|
|
74
|
+
onColumnVisibilityChange: setColumnVisibility,
|
|
75
|
+
onRowSelectionChange: enableRowSelection ? setRowSelection : undefined,
|
|
76
|
+
onPaginationChange: enablePagination ? setPagination : undefined,
|
|
77
|
+
getCoreRowModel: getCoreRowModel(),
|
|
78
|
+
enableSorting,
|
|
79
|
+
enableRowSelection,
|
|
80
|
+
// Server-side: manual pagination e sorting
|
|
81
|
+
manualPagination: enablePagination,
|
|
82
|
+
manualSorting: enableSorting,
|
|
83
|
+
// Total de páginas calculado do totalCount
|
|
84
|
+
pageCount: enablePagination && totalCount !== undefined
|
|
85
|
+
? Math.ceil(totalCount / pagination.pageSize)
|
|
86
|
+
: undefined,
|
|
87
|
+
});
|
|
88
|
+
// Notificar mudanças na seleção
|
|
89
|
+
useEffect(() => {
|
|
90
|
+
if (onSelectionChange && enableRowSelection) {
|
|
91
|
+
const selectedRows = table.getFilteredSelectedRowModel().rows.map((row) => row.original);
|
|
92
|
+
onSelectionChange(selectedRows);
|
|
93
|
+
}
|
|
94
|
+
}, [table, onSelectionChange, enableRowSelection]);
|
|
95
|
+
// Calcular informações de paginação
|
|
96
|
+
const paginationInfo = useMemo(() => {
|
|
97
|
+
const start = pagination.pageIndex * pagination.pageSize + 1;
|
|
98
|
+
const end = Math.min((pagination.pageIndex + 1) * pagination.pageSize, totalCount);
|
|
99
|
+
return {
|
|
100
|
+
start,
|
|
101
|
+
end,
|
|
102
|
+
total: totalCount,
|
|
103
|
+
pageCount: enablePagination && totalCount !== undefined
|
|
104
|
+
? Math.ceil(totalCount / pagination.pageSize)
|
|
105
|
+
: 1,
|
|
106
|
+
};
|
|
107
|
+
}, [pagination, totalCount, enablePagination]);
|
|
108
|
+
return {
|
|
109
|
+
table,
|
|
110
|
+
sorting,
|
|
111
|
+
setSorting,
|
|
112
|
+
pagination,
|
|
113
|
+
setPagination,
|
|
114
|
+
columnFilters,
|
|
115
|
+
setColumnFilters,
|
|
116
|
+
globalFilter,
|
|
117
|
+
setGlobalFilter,
|
|
118
|
+
columnVisibility,
|
|
119
|
+
setColumnVisibility,
|
|
120
|
+
rowSelection,
|
|
121
|
+
setRowSelection,
|
|
122
|
+
paginationInfo,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/useReactTableFront/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAChG,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useReactTableFront } from "./useReactTableFront";
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useReactTableFront - Headless UI Hook
|
|
3
|
+
*
|
|
4
|
+
* Hook headless para TanStack Table com paginação e ordenação no frontend (client-side).
|
|
5
|
+
* Fornece apenas: lógica, estado, processamento e API
|
|
6
|
+
* NÃO fornece: markup, styles ou implementações pré-construídas
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* function MyTable() {
|
|
11
|
+
* const { table, sorting, pagination, setPagination, paginationInfo } = useReactTableFront({
|
|
12
|
+
* data: allData,
|
|
13
|
+
* columns: columnDefs,
|
|
14
|
+
* enablePagination: true,
|
|
15
|
+
* enableSorting: true,
|
|
16
|
+
* })
|
|
17
|
+
*
|
|
18
|
+
* return (
|
|
19
|
+
* <table>
|
|
20
|
+
* {/* Usar table.getHeaderGroups(), table.getRowModel(), etc. *\/}
|
|
21
|
+
* </table>
|
|
22
|
+
* )
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
import { type ColumnDef, type ColumnFiltersState, type PaginationState, type SortingState, type Table, type VisibilityState } from "@tanstack/react-table";
|
|
27
|
+
export interface UseReactTableFrontOptions<T extends Record<string, unknown>> {
|
|
28
|
+
/** Dados da tabela */
|
|
29
|
+
data: T[];
|
|
30
|
+
/** Definição das colunas */
|
|
31
|
+
columns: ColumnDef<T, unknown>[];
|
|
32
|
+
/** Habilitar paginação */
|
|
33
|
+
enablePagination?: boolean;
|
|
34
|
+
/** Tamanho da página */
|
|
35
|
+
pageSize?: number;
|
|
36
|
+
/** Habilitar ordenação */
|
|
37
|
+
enableSorting?: boolean;
|
|
38
|
+
/** Estado inicial de ordenação */
|
|
39
|
+
initialSorting?: SortingState;
|
|
40
|
+
/** Habilitar filtro global */
|
|
41
|
+
enableGlobalFilter?: boolean;
|
|
42
|
+
/** Estado inicial de filtros de coluna */
|
|
43
|
+
initialColumnFilters?: ColumnFiltersState;
|
|
44
|
+
/** Estado inicial de visibilidade de colunas */
|
|
45
|
+
initialColumnVisibility?: VisibilityState;
|
|
46
|
+
/** Habilitar seleção de linhas */
|
|
47
|
+
enableRowSelection?: boolean;
|
|
48
|
+
/** Callback quando a seleção muda */
|
|
49
|
+
onSelectionChange?: (selectedRows: T[]) => void;
|
|
50
|
+
}
|
|
51
|
+
export interface UseReactTableFrontReturn<T extends Record<string, unknown>> {
|
|
52
|
+
/** Instância do TanStack Table */
|
|
53
|
+
table: Table<T>;
|
|
54
|
+
/** Estado de ordenação */
|
|
55
|
+
sorting: SortingState;
|
|
56
|
+
/** Função para atualizar ordenação */
|
|
57
|
+
setSorting: (sorting: SortingState | ((prev: SortingState) => SortingState)) => void;
|
|
58
|
+
/** Estado de paginação */
|
|
59
|
+
pagination: PaginationState;
|
|
60
|
+
/** Função para atualizar paginação */
|
|
61
|
+
setPagination: (pagination: PaginationState | ((prev: PaginationState) => PaginationState)) => void;
|
|
62
|
+
/** Estado de filtros de coluna */
|
|
63
|
+
columnFilters: ColumnFiltersState;
|
|
64
|
+
/** Função para atualizar filtros de coluna */
|
|
65
|
+
setColumnFilters: (filters: ColumnFiltersState | ((prev: ColumnFiltersState) => ColumnFiltersState)) => void;
|
|
66
|
+
/** Estado de filtro global */
|
|
67
|
+
globalFilter: string;
|
|
68
|
+
/** Função para atualizar filtro global */
|
|
69
|
+
setGlobalFilter: (filter: string) => void;
|
|
70
|
+
/** Estado de visibilidade de colunas */
|
|
71
|
+
columnVisibility: VisibilityState;
|
|
72
|
+
/** Função para atualizar visibilidade de colunas */
|
|
73
|
+
setColumnVisibility: (visibility: VisibilityState | ((prev: VisibilityState) => VisibilityState)) => void;
|
|
74
|
+
/** Estado de seleção de linhas */
|
|
75
|
+
rowSelection: Record<string, boolean>;
|
|
76
|
+
/** Função para atualizar seleção de linhas */
|
|
77
|
+
setRowSelection: (selection: Record<string, boolean> | ((prev: Record<string, boolean>) => Record<string, boolean>)) => void;
|
|
78
|
+
/** Informações de paginação calculadas */
|
|
79
|
+
paginationInfo: {
|
|
80
|
+
start: number;
|
|
81
|
+
end: number;
|
|
82
|
+
total: number;
|
|
83
|
+
pageCount: number;
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Hook Headless UI para TanStack Table com paginação/ordenação client-side
|
|
88
|
+
*/
|
|
89
|
+
export declare function useReactTableFront<T extends Record<string, unknown>>(options: UseReactTableFrontOptions<T>): UseReactTableFrontReturn<T>;
|
|
90
|
+
//# sourceMappingURL=useReactTableFront.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useReactTableFront.d.ts","sourceRoot":"","sources":["../../../src/hooks/useReactTableFront/useReactTableFront.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useReactTableFront - Headless UI Hook
|
|
3
|
+
*
|
|
4
|
+
* Hook headless para TanStack Table com paginação e ordenação no frontend (client-side).
|
|
5
|
+
* Fornece apenas: lógica, estado, processamento e API
|
|
6
|
+
* NÃO fornece: markup, styles ou implementações pré-construídas
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* function MyTable() {
|
|
11
|
+
* const { table, sorting, pagination, setPagination, paginationInfo } = useReactTableFront({
|
|
12
|
+
* data: allData,
|
|
13
|
+
* columns: columnDefs,
|
|
14
|
+
* enablePagination: true,
|
|
15
|
+
* enableSorting: true,
|
|
16
|
+
* })
|
|
17
|
+
*
|
|
18
|
+
* return (
|
|
19
|
+
* <table>
|
|
20
|
+
* {/* Usar table.getHeaderGroups(), table.getRowModel(), etc. *\/}
|
|
21
|
+
* </table>
|
|
22
|
+
* )
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
import { getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable, } from "@tanstack/react-table";
|
|
27
|
+
import { useEffect, useMemo, useState } from "react";
|
|
28
|
+
/**
|
|
29
|
+
* Hook Headless UI para TanStack Table com paginação/ordenação client-side
|
|
30
|
+
*/
|
|
31
|
+
export function useReactTableFront(options) {
|
|
32
|
+
const { data, columns, enablePagination = true, pageSize = 10, enableSorting = true, initialSorting = [], enableGlobalFilter = true, initialColumnFilters = [], initialColumnVisibility = {}, enableRowSelection = false, onSelectionChange, } = options;
|
|
33
|
+
const [sorting, setSorting] = useState(initialSorting);
|
|
34
|
+
const [columnFilters, setColumnFilters] = useState(initialColumnFilters);
|
|
35
|
+
const [globalFilter, setGlobalFilter] = useState("");
|
|
36
|
+
const [columnVisibility, setColumnVisibility] = useState(initialColumnVisibility);
|
|
37
|
+
const [rowSelection, setRowSelection] = useState({});
|
|
38
|
+
const [pagination, setPagination] = useState({
|
|
39
|
+
pageIndex: 0,
|
|
40
|
+
pageSize,
|
|
41
|
+
});
|
|
42
|
+
const table = useReactTable({
|
|
43
|
+
data,
|
|
44
|
+
columns,
|
|
45
|
+
state: {
|
|
46
|
+
sorting: enableSorting ? sorting : undefined,
|
|
47
|
+
columnFilters,
|
|
48
|
+
globalFilter: enableGlobalFilter ? globalFilter : undefined,
|
|
49
|
+
columnVisibility,
|
|
50
|
+
rowSelection: enableRowSelection ? rowSelection : undefined,
|
|
51
|
+
pagination: enablePagination ? pagination : undefined,
|
|
52
|
+
},
|
|
53
|
+
onSortingChange: enableSorting ? setSorting : undefined,
|
|
54
|
+
onColumnFiltersChange: setColumnFilters,
|
|
55
|
+
onGlobalFilterChange: enableGlobalFilter ? setGlobalFilter : undefined,
|
|
56
|
+
onColumnVisibilityChange: setColumnVisibility,
|
|
57
|
+
onRowSelectionChange: enableRowSelection ? setRowSelection : undefined,
|
|
58
|
+
onPaginationChange: enablePagination ? setPagination : undefined,
|
|
59
|
+
getCoreRowModel: getCoreRowModel(),
|
|
60
|
+
getFilteredRowModel: getFilteredRowModel(),
|
|
61
|
+
getPaginationRowModel: enablePagination ? getPaginationRowModel() : undefined,
|
|
62
|
+
getSortedRowModel: enableSorting ? getSortedRowModel() : undefined,
|
|
63
|
+
enableSorting,
|
|
64
|
+
enableRowSelection,
|
|
65
|
+
manualPagination: false,
|
|
66
|
+
manualSorting: false,
|
|
67
|
+
});
|
|
68
|
+
// Notificar mudanças na seleção
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
if (onSelectionChange && enableRowSelection) {
|
|
71
|
+
const selectedRows = table.getFilteredSelectedRowModel().rows.map((row) => row.original);
|
|
72
|
+
onSelectionChange(selectedRows);
|
|
73
|
+
}
|
|
74
|
+
}, [table, onSelectionChange, enableRowSelection]);
|
|
75
|
+
// Calcular informações de paginação
|
|
76
|
+
const paginationInfo = useMemo(() => {
|
|
77
|
+
const filteredCount = table.getFilteredRowModel().rows.length;
|
|
78
|
+
// Se a paginação estiver desabilitada, retornar valores padrão
|
|
79
|
+
if (!enablePagination) {
|
|
80
|
+
return {
|
|
81
|
+
start: 1,
|
|
82
|
+
end: filteredCount,
|
|
83
|
+
total: filteredCount,
|
|
84
|
+
pageCount: 1,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const start = pagination.pageIndex * pagination.pageSize + 1;
|
|
88
|
+
const end = Math.min((pagination.pageIndex + 1) * pagination.pageSize, filteredCount);
|
|
89
|
+
return {
|
|
90
|
+
start,
|
|
91
|
+
end,
|
|
92
|
+
total: filteredCount,
|
|
93
|
+
pageCount: table.getPageCount(),
|
|
94
|
+
};
|
|
95
|
+
}, [table, pagination, enablePagination]);
|
|
96
|
+
return {
|
|
97
|
+
table,
|
|
98
|
+
sorting,
|
|
99
|
+
setSorting,
|
|
100
|
+
pagination,
|
|
101
|
+
setPagination,
|
|
102
|
+
columnFilters,
|
|
103
|
+
setColumnFilters,
|
|
104
|
+
globalFilter,
|
|
105
|
+
setGlobalFilter,
|
|
106
|
+
columnVisibility,
|
|
107
|
+
setColumnVisibility,
|
|
108
|
+
rowSelection,
|
|
109
|
+
setRowSelection,
|
|
110
|
+
paginationInfo,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/useResizable/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useResizable } from "./useResizable";
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useResizable - Headless UI Hook
|
|
3
|
+
*
|
|
4
|
+
* Fornece apenas: lógica, estado, processamento e API para componentes resizable
|
|
5
|
+
* NÃO fornece: markup, styles ou implementações pré-construídas
|
|
6
|
+
*
|
|
7
|
+
* Padrão Headless UI: você controla o markup e styles
|
|
8
|
+
*/
|
|
9
|
+
import type React from "react";
|
|
10
|
+
import type { ImperativePanelHandle } from "react-resizable-panels";
|
|
11
|
+
export interface UseResizableOptions {
|
|
12
|
+
sidebarOpen: boolean;
|
|
13
|
+
setSidebarOpen: (open: boolean) => void;
|
|
14
|
+
side?: "left" | "right";
|
|
15
|
+
persistKey?: string;
|
|
16
|
+
defaultSidebarPct?: number;
|
|
17
|
+
minPx?: number;
|
|
18
|
+
maxPct?: number;
|
|
19
|
+
maxPxCap?: number;
|
|
20
|
+
mobileDrawer?: boolean;
|
|
21
|
+
tinySizePx?: number;
|
|
22
|
+
snapThreshold?: number;
|
|
23
|
+
}
|
|
24
|
+
export interface UseResizableReturn {
|
|
25
|
+
handleDoubleClick: () => void;
|
|
26
|
+
shouldUseMobileDrawer: boolean;
|
|
27
|
+
containerRef: React.RefObject<HTMLDivElement | null>;
|
|
28
|
+
autoSaveId: string;
|
|
29
|
+
handleLayout: (sizes: number[]) => void;
|
|
30
|
+
sidebarPanelRef: React.RefObject<ImperativePanelHandle>;
|
|
31
|
+
sidebarSize: number;
|
|
32
|
+
minSize: number;
|
|
33
|
+
maxSize: number;
|
|
34
|
+
handleResizeEnd: () => void;
|
|
35
|
+
}
|
|
36
|
+
export declare function useResizable({ sidebarOpen, setSidebarOpen, side, persistKey, defaultSidebarPct, minPx, maxPct, maxPxCap, mobileDrawer, tinySizePx, snapThreshold, }: UseResizableOptions): UseResizableReturn;
|
|
37
|
+
//# sourceMappingURL=useResizable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useResizable.d.ts","sourceRoot":"","sources":["../../../src/hooks/useResizable/useResizable.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAEpE,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACxC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IACrD,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACxC,eAAe,EAAE,KAAK,CAAC,SAAS,CAAC,qBAAqB,CAAC,CAAC;IACxD,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,IAAI,CAAC;CAC7B;AAID,wBAAgB,YAAY,CAAC,EAC3B,WAAW,EACX,cAAc,EACd,IAAa,EACb,UAAsB,EACtB,iBAAwB,EACxB,KAAW,EACX,MAAY,EACZ,QAAc,EACd,YAAmB,EACnB,UAAU,EACV,aAAkB,GACnB,EAAE,mBAAmB,GAAG,kBAAkB,CA0H1C"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useResizable - Headless UI Hook
|
|
3
|
+
*
|
|
4
|
+
* Fornece apenas: lógica, estado, processamento e API para componentes resizable
|
|
5
|
+
* NÃO fornece: markup, styles ou implementações pré-construídas
|
|
6
|
+
*
|
|
7
|
+
* Padrão Headless UI: você controla o markup e styles
|
|
8
|
+
*/
|
|
9
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
10
|
+
const MOBILE_BREAKPOINT = 768;
|
|
11
|
+
export function useResizable({ sidebarOpen, setSidebarOpen, side = "left", persistKey = "default", defaultSidebarPct = 0.28, minPx = 250, maxPct = 0.6, maxPxCap = 500, mobileDrawer = true, tinySizePx, snapThreshold = 50, }) {
|
|
12
|
+
const containerRef = useRef(null);
|
|
13
|
+
const sidebarPanelRef = useRef(null);
|
|
14
|
+
const [isMobile, setIsMobile] = useState(false);
|
|
15
|
+
const [sidebarSize, setSidebarSize] = useState(defaultSidebarPct * 100);
|
|
16
|
+
// Detectar mobile
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
const checkMobile = () => {
|
|
19
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
20
|
+
};
|
|
21
|
+
checkMobile();
|
|
22
|
+
window.addEventListener("resize", checkMobile);
|
|
23
|
+
return () => window.removeEventListener("resize", checkMobile);
|
|
24
|
+
}, []);
|
|
25
|
+
// Carregar tamanho persistido
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (typeof window === "undefined")
|
|
28
|
+
return;
|
|
29
|
+
const storageKey = `resizable-sidebar-${persistKey}`;
|
|
30
|
+
const saved = localStorage.getItem(storageKey);
|
|
31
|
+
if (saved) {
|
|
32
|
+
try {
|
|
33
|
+
const parsed = JSON.parse(saved);
|
|
34
|
+
if (typeof parsed.size === "number" && parsed.size > 0 && parsed.size < 100) {
|
|
35
|
+
setSidebarSize(parsed.size);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Ignorar erros de parsing
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}, [persistKey]);
|
|
43
|
+
// Salvar tamanho no localStorage
|
|
44
|
+
const saveSize = useCallback((size) => {
|
|
45
|
+
if (typeof window === "undefined")
|
|
46
|
+
return;
|
|
47
|
+
const storageKey = `resizable-sidebar-${persistKey}`;
|
|
48
|
+
localStorage.setItem(storageKey, JSON.stringify({ size, timestamp: Date.now() }));
|
|
49
|
+
}, [persistKey]);
|
|
50
|
+
// Calcular tamanhos
|
|
51
|
+
const minSize = useMemo(() => {
|
|
52
|
+
if (!containerRef.current)
|
|
53
|
+
return (minPx / 1920) * 100; // Assumir largura padrão
|
|
54
|
+
const containerWidth = containerRef.current.offsetWidth;
|
|
55
|
+
return (minPx / containerWidth) * 100;
|
|
56
|
+
}, [minPx]);
|
|
57
|
+
const maxSize = useMemo(() => {
|
|
58
|
+
if (!containerRef.current)
|
|
59
|
+
return maxPct * 100;
|
|
60
|
+
const containerWidth = containerRef.current.offsetWidth;
|
|
61
|
+
const maxPx = Math.min(maxPxCap, containerWidth * maxPct);
|
|
62
|
+
return (maxPx / containerWidth) * 100;
|
|
63
|
+
}, [maxPct, maxPxCap]);
|
|
64
|
+
// Handler para toggle do sidebar (double click)
|
|
65
|
+
const handleDoubleClick = useCallback(() => {
|
|
66
|
+
if (sidebarOpen) {
|
|
67
|
+
// Colapsar
|
|
68
|
+
sidebarPanelRef.current?.collapse();
|
|
69
|
+
setSidebarOpen(false);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
// Expandir
|
|
73
|
+
sidebarPanelRef.current?.expand();
|
|
74
|
+
setSidebarOpen(true);
|
|
75
|
+
}
|
|
76
|
+
}, [sidebarOpen, setSidebarOpen]);
|
|
77
|
+
// Handler para mudanças de layout
|
|
78
|
+
const handleLayout = useCallback((sizes) => {
|
|
79
|
+
if (sizes.length > 0) {
|
|
80
|
+
const newSize = side === "left" ? sizes[0] : sizes[sizes.length - 1];
|
|
81
|
+
setSidebarSize(newSize);
|
|
82
|
+
saveSize(newSize);
|
|
83
|
+
}
|
|
84
|
+
}, [side, saveSize]);
|
|
85
|
+
// Handler para fim do resize (snap automático)
|
|
86
|
+
const handleResizeEnd = useCallback(() => {
|
|
87
|
+
if (!tinySizePx || !containerRef.current)
|
|
88
|
+
return;
|
|
89
|
+
const containerWidth = containerRef.current.offsetWidth;
|
|
90
|
+
const currentSizePx = (sidebarSize / 100) * containerWidth;
|
|
91
|
+
const tinySizePercent = (tinySizePx / containerWidth) * 100;
|
|
92
|
+
// Verificar se está próximo do tamanho tiny
|
|
93
|
+
if (Math.abs(currentSizePx - tinySizePx) <= snapThreshold &&
|
|
94
|
+
currentSizePx < tinySizePx + snapThreshold) {
|
|
95
|
+
// Snap para tiny
|
|
96
|
+
const targetSize = tinySizePercent;
|
|
97
|
+
setSidebarSize(targetSize);
|
|
98
|
+
saveSize(targetSize);
|
|
99
|
+
sidebarPanelRef.current?.resize(targetSize);
|
|
100
|
+
}
|
|
101
|
+
}, [sidebarSize, tinySizePx, snapThreshold, saveSize]);
|
|
102
|
+
const shouldUseMobileDrawer = mobileDrawer && isMobile;
|
|
103
|
+
const autoSaveId = `resizable-${persistKey}`;
|
|
104
|
+
return {
|
|
105
|
+
handleDoubleClick,
|
|
106
|
+
shouldUseMobileDrawer,
|
|
107
|
+
containerRef,
|
|
108
|
+
autoSaveId,
|
|
109
|
+
handleLayout,
|
|
110
|
+
sidebarPanelRef: sidebarPanelRef,
|
|
111
|
+
sidebarSize,
|
|
112
|
+
minSize,
|
|
113
|
+
maxSize,
|
|
114
|
+
handleResizeEnd,
|
|
115
|
+
};
|
|
116
|
+
}
|