analytica-frontend-lib 1.2.7 → 1.2.8

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.
@@ -1,8 +1,47 @@
1
1
  import * as react from 'react';
2
- import { HTMLAttributes, TdHTMLAttributes } from 'react';
2
+ import { HTMLAttributes, ThHTMLAttributes, TdHTMLAttributes } from 'react';
3
3
 
4
4
  type TableVariant = 'default' | 'borderless';
5
5
  type TableRowState = 'default' | 'selected' | 'invalid' | 'disabled';
6
+ type SortDirection = 'asc' | 'desc' | null;
7
+ interface UseTableSortOptions {
8
+ /** Se true, sincroniza o estado de ordenação com os parâmetros da URL */
9
+ syncWithUrl?: boolean;
10
+ }
11
+ /**
12
+ * Hook para gerenciar ordenação de dados da tabela
13
+ *
14
+ * @param data - Array de dados a serem ordenados
15
+ * @param options - Opções de configuração do hook
16
+ * @returns Objeto com dados ordenados, coluna/direção atual e função de sort
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * const activities = [
21
+ * { id: 1, name: 'Task A', date: '2024-01-01' },
22
+ * { id: 2, name: 'Task B', date: '2024-01-02' },
23
+ * ];
24
+ *
25
+ * // Sem sincronização com URL
26
+ * const { sortedData, sortColumn, sortDirection, handleSort } = useTableSort(activities);
27
+ *
28
+ * // Com sincronização com URL
29
+ * const { sortedData, sortColumn, sortDirection, handleSort } = useTableSort(activities, { syncWithUrl: true });
30
+ *
31
+ * <TableHead
32
+ * sortDirection={sortColumn === 'name' ? sortDirection : null}
33
+ * onSort={() => handleSort('name')}
34
+ * >
35
+ * Name
36
+ * </TableHead>
37
+ * ```
38
+ */
39
+ declare function useTableSort<T extends Record<string, unknown>>(data: T[], options?: UseTableSortOptions): {
40
+ sortedData: T[];
41
+ sortColumn: string | null;
42
+ sortDirection: SortDirection;
43
+ handleSort: (column: string) => void;
44
+ };
6
45
  interface TableProps extends HTMLAttributes<HTMLTableElement> {
7
46
  variant?: TableVariant;
8
47
  }
@@ -21,10 +60,19 @@ interface TableFooterProps extends HTMLAttributes<HTMLTableSectionElement> {
21
60
  declare const TableFooter: react.ForwardRefExoticComponent<TableFooterProps & react.RefAttributes<HTMLTableSectionElement>>;
22
61
  interface TableRowPropsExtended extends TableRowProps {
23
62
  variant?: TableVariant;
63
+ clickable?: boolean;
24
64
  }
25
65
  declare const TableRow: react.ForwardRefExoticComponent<TableRowPropsExtended & react.RefAttributes<HTMLTableRowElement>>;
26
- declare const TableHead: react.ForwardRefExoticComponent<TdHTMLAttributes<HTMLTableCellElement> & react.RefAttributes<HTMLTableCellElement>>;
66
+ interface TableHeadProps extends ThHTMLAttributes<HTMLTableCellElement> {
67
+ /** Enable sorting on this column (default: true) */
68
+ sortable?: boolean;
69
+ /** Current sort direction for this column */
70
+ sortDirection?: SortDirection;
71
+ /** Callback when column header is clicked */
72
+ onSort?: () => void;
73
+ }
74
+ declare const TableHead: react.ForwardRefExoticComponent<TableHeadProps & react.RefAttributes<HTMLTableCellElement>>;
27
75
  declare const TableCell: react.ForwardRefExoticComponent<TdHTMLAttributes<HTMLTableCellElement> & react.RefAttributes<HTMLTableCellElement>>;
28
76
  declare const TableCaption: react.ForwardRefExoticComponent<HTMLAttributes<HTMLTableCaptionElement> & react.RefAttributes<HTMLTableCaptionElement>>;
29
77
 
30
- export { TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Table as default };
78
+ export { type SortDirection, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Table as default, useTableSort };
@@ -1,8 +1,47 @@
1
1
  import * as react from 'react';
2
- import { HTMLAttributes, TdHTMLAttributes } from 'react';
2
+ import { HTMLAttributes, ThHTMLAttributes, TdHTMLAttributes } from 'react';
3
3
 
4
4
  type TableVariant = 'default' | 'borderless';
5
5
  type TableRowState = 'default' | 'selected' | 'invalid' | 'disabled';
6
+ type SortDirection = 'asc' | 'desc' | null;
7
+ interface UseTableSortOptions {
8
+ /** Se true, sincroniza o estado de ordenação com os parâmetros da URL */
9
+ syncWithUrl?: boolean;
10
+ }
11
+ /**
12
+ * Hook para gerenciar ordenação de dados da tabela
13
+ *
14
+ * @param data - Array de dados a serem ordenados
15
+ * @param options - Opções de configuração do hook
16
+ * @returns Objeto com dados ordenados, coluna/direção atual e função de sort
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * const activities = [
21
+ * { id: 1, name: 'Task A', date: '2024-01-01' },
22
+ * { id: 2, name: 'Task B', date: '2024-01-02' },
23
+ * ];
24
+ *
25
+ * // Sem sincronização com URL
26
+ * const { sortedData, sortColumn, sortDirection, handleSort } = useTableSort(activities);
27
+ *
28
+ * // Com sincronização com URL
29
+ * const { sortedData, sortColumn, sortDirection, handleSort } = useTableSort(activities, { syncWithUrl: true });
30
+ *
31
+ * <TableHead
32
+ * sortDirection={sortColumn === 'name' ? sortDirection : null}
33
+ * onSort={() => handleSort('name')}
34
+ * >
35
+ * Name
36
+ * </TableHead>
37
+ * ```
38
+ */
39
+ declare function useTableSort<T extends Record<string, unknown>>(data: T[], options?: UseTableSortOptions): {
40
+ sortedData: T[];
41
+ sortColumn: string | null;
42
+ sortDirection: SortDirection;
43
+ handleSort: (column: string) => void;
44
+ };
6
45
  interface TableProps extends HTMLAttributes<HTMLTableElement> {
7
46
  variant?: TableVariant;
8
47
  }
@@ -21,10 +60,19 @@ interface TableFooterProps extends HTMLAttributes<HTMLTableSectionElement> {
21
60
  declare const TableFooter: react.ForwardRefExoticComponent<TableFooterProps & react.RefAttributes<HTMLTableSectionElement>>;
22
61
  interface TableRowPropsExtended extends TableRowProps {
23
62
  variant?: TableVariant;
63
+ clickable?: boolean;
24
64
  }
25
65
  declare const TableRow: react.ForwardRefExoticComponent<TableRowPropsExtended & react.RefAttributes<HTMLTableRowElement>>;
26
- declare const TableHead: react.ForwardRefExoticComponent<TdHTMLAttributes<HTMLTableCellElement> & react.RefAttributes<HTMLTableCellElement>>;
66
+ interface TableHeadProps extends ThHTMLAttributes<HTMLTableCellElement> {
67
+ /** Enable sorting on this column (default: true) */
68
+ sortable?: boolean;
69
+ /** Current sort direction for this column */
70
+ sortDirection?: SortDirection;
71
+ /** Callback when column header is clicked */
72
+ onSort?: () => void;
73
+ }
74
+ declare const TableHead: react.ForwardRefExoticComponent<TableHeadProps & react.RefAttributes<HTMLTableCellElement>>;
27
75
  declare const TableCell: react.ForwardRefExoticComponent<TdHTMLAttributes<HTMLTableCellElement> & react.RefAttributes<HTMLTableCellElement>>;
28
76
  declare const TableCaption: react.ForwardRefExoticComponent<HTMLAttributes<HTMLTableCaptionElement> & react.RefAttributes<HTMLTableCaptionElement>>;
29
77
 
30
- export { TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Table as default };
78
+ export { type SortDirection, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Table as default, useTableSort };
@@ -27,7 +27,8 @@ __export(Table_exports, {
27
27
  TableHead: () => TableHead,
28
28
  TableHeader: () => TableHeader,
29
29
  TableRow: () => TableRow,
30
- default: () => Table_default
30
+ default: () => Table_default,
31
+ useTableSort: () => useTableSort
31
32
  });
32
33
  module.exports = __toCommonJS(Table_exports);
33
34
  var import_react = require("react");
@@ -40,20 +41,93 @@ function cn(...inputs) {
40
41
  }
41
42
 
42
43
  // src/components/Table/Table.tsx
44
+ var import_phosphor_react = require("phosphor-react");
43
45
  var import_jsx_runtime = require("react/jsx-runtime");
46
+ function useTableSort(data, options = {}) {
47
+ const { syncWithUrl = false } = options;
48
+ const getInitialState = () => {
49
+ if (!syncWithUrl || globalThis.window === void 0) {
50
+ return { column: null, direction: null };
51
+ }
52
+ const params = new URLSearchParams(globalThis.location.search);
53
+ const sortBy = params.get("sortBy");
54
+ const sort = params.get("sort");
55
+ if (sortBy && sort && (sort === "ASC" || sort === "DESC")) {
56
+ return {
57
+ column: sortBy,
58
+ direction: sort.toLowerCase()
59
+ };
60
+ }
61
+ return { column: null, direction: null };
62
+ };
63
+ const initialState = getInitialState();
64
+ const [sortColumn, setSortColumn] = (0, import_react.useState)(
65
+ initialState.column
66
+ );
67
+ const [sortDirection, setSortDirection] = (0, import_react.useState)(
68
+ initialState.direction
69
+ );
70
+ (0, import_react.useEffect)(() => {
71
+ if (!syncWithUrl || globalThis.window === void 0) return;
72
+ const url = new URL(globalThis.location.href);
73
+ const params = url.searchParams;
74
+ if (sortColumn && sortDirection) {
75
+ params.set("sortBy", sortColumn);
76
+ params.set("sort", sortDirection.toUpperCase());
77
+ } else {
78
+ params.delete("sortBy");
79
+ params.delete("sort");
80
+ }
81
+ globalThis.history.replaceState({}, "", url.toString());
82
+ }, [sortColumn, sortDirection, syncWithUrl]);
83
+ const handleSort = (column) => {
84
+ if (sortColumn === column) {
85
+ if (sortDirection === "asc") {
86
+ setSortDirection("desc");
87
+ } else if (sortDirection === "desc") {
88
+ setSortColumn(null);
89
+ setSortDirection(null);
90
+ }
91
+ } else {
92
+ setSortColumn(column);
93
+ setSortDirection("asc");
94
+ }
95
+ };
96
+ const sortedData = (0, import_react.useMemo)(() => {
97
+ if (!sortColumn || !sortDirection) {
98
+ return data;
99
+ }
100
+ return [...data].sort((a, b) => {
101
+ const aValue = a[sortColumn];
102
+ const bValue = b[sortColumn];
103
+ if (typeof aValue === "string" && typeof bValue === "string") {
104
+ const comparison = aValue.localeCompare(bValue);
105
+ return sortDirection === "asc" ? comparison : -comparison;
106
+ }
107
+ if (typeof aValue === "number" && typeof bValue === "number") {
108
+ return sortDirection === "asc" ? aValue - bValue : bValue - aValue;
109
+ }
110
+ return 0;
111
+ });
112
+ }, [data, sortColumn, sortDirection]);
113
+ return { sortedData, sortColumn, sortDirection, handleSort };
114
+ }
44
115
  var Table = (0, import_react.forwardRef)(
45
116
  ({ variant = "default", className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
46
117
  "div",
47
118
  {
48
119
  className: cn(
49
- "relative w-full overflow-hidden",
120
+ "relative w-full overflow-x-auto",
50
121
  variant === "default" && "border border-border-200 rounded-xl"
51
122
  ),
52
123
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
53
124
  "table",
54
125
  {
55
126
  ref,
56
- className: cn("w-full caption-bottom text-sm", className),
127
+ className: cn(
128
+ "analytica-table w-full caption-bottom text-sm border-separate border-spacing-0",
129
+ className
130
+ ),
57
131
  ...props,
58
132
  children: [
59
133
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("caption", { className: "sr-only", children: "My Table" }),
@@ -75,15 +149,11 @@ var TableHeader = (0, import_react.forwardRef)(({ className, ...props }, ref) =>
75
149
  ));
76
150
  TableHeader.displayName = "TableHeader";
77
151
  var TableBody = (0, import_react.forwardRef)(
78
- ({ variant = "default", className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
152
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
79
153
  "tbody",
80
154
  {
81
155
  ref,
82
- className: cn(
83
- "[&_tr:last-child]:border-0",
84
- variant === "default" && "border-t border-border-200",
85
- className
86
- ),
156
+ className: cn("[&_tr:last-child]:border-border-200", className),
87
157
  ...props
88
158
  }
89
159
  )
@@ -106,7 +176,7 @@ var TableFooter = (0, import_react.forwardRef)(
106
176
  TableFooter.displayName = "TableFooter";
107
177
  var VARIANT_STATES_ROW = {
108
178
  default: {
109
- default: "border-b border-border-200",
179
+ default: "border border-border-200",
110
180
  borderless: ""
111
181
  },
112
182
  selected: {
@@ -123,7 +193,13 @@ var VARIANT_STATES_ROW = {
123
193
  }
124
194
  };
125
195
  var TableRow = (0, import_react.forwardRef)(
126
- ({ variant = "default", state = "default", className, ...props }, ref) => {
196
+ ({
197
+ variant = "default",
198
+ state = "default",
199
+ clickable = false,
200
+ className,
201
+ ...props
202
+ }, ref) => {
127
203
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
128
204
  "tr",
129
205
  {
@@ -131,6 +207,7 @@ var TableRow = (0, import_react.forwardRef)(
131
207
  className: cn(
132
208
  "transition-colors",
133
209
  state !== "disabled" ? "hover:bg-muted/50" : "",
210
+ clickable && state !== "disabled" ? "cursor-pointer" : "",
134
211
  VARIANT_STATES_ROW[state][variant],
135
212
  className
136
213
  ),
@@ -141,24 +218,49 @@ var TableRow = (0, import_react.forwardRef)(
141
218
  }
142
219
  );
143
220
  TableRow.displayName = "TableRow";
144
- var TableHead = (0, import_react.forwardRef)(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
145
- "th",
146
- {
147
- ref,
148
- className: cn(
149
- "h-10 px-6 py-3.5 bg-muted/50 text-left align-middle font-bold text-text-800 [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
150
- className
151
- ),
221
+ var TableHead = (0, import_react.forwardRef)(
222
+ ({
223
+ className,
224
+ sortable = true,
225
+ sortDirection = null,
226
+ onSort,
227
+ children,
152
228
  ...props
229
+ }, ref) => {
230
+ const handleClick = () => {
231
+ if (sortable && onSort) {
232
+ onSort();
233
+ }
234
+ };
235
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
236
+ "th",
237
+ {
238
+ ref,
239
+ className: cn(
240
+ "h-10 px-6 py-3.5 text-left align-middle font-bold text-base text-text-800 tracking-[0.2px] leading-none [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px] whitespace-nowrap",
241
+ sortable && "cursor-pointer select-none hover:bg-muted/30",
242
+ className
243
+ ),
244
+ onClick: handleClick,
245
+ ...props,
246
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2", children: [
247
+ children,
248
+ sortable && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col", children: [
249
+ sortDirection === "asc" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_phosphor_react.CaretUp, { size: 16, weight: "fill", className: "text-text-800" }),
250
+ sortDirection === "desc" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_phosphor_react.CaretDown, { size: 16, weight: "fill", className: "text-text-800" })
251
+ ] })
252
+ ] })
253
+ }
254
+ );
153
255
  }
154
- ));
256
+ );
155
257
  TableHead.displayName = "TableHead";
156
258
  var TableCell = (0, import_react.forwardRef)(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
157
259
  "td",
158
260
  {
159
261
  ref,
160
262
  className: cn(
161
- "p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px] text-md text-text-800 px-6 py-3.5",
263
+ "p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px] text-base font-normal text-text-800 leading-[150%] tracking-normal px-6 py-3.5 whitespace-nowrap",
162
264
  className
163
265
  ),
164
266
  ...props
@@ -186,6 +288,7 @@ var Table_default = Table;
186
288
  TableFooter,
187
289
  TableHead,
188
290
  TableHeader,
189
- TableRow
291
+ TableRow,
292
+ useTableSort
190
293
  });
191
294
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/Table/Table.tsx","../../src/utils/utils.ts"],"sourcesContent":["import { forwardRef, HTMLAttributes, TdHTMLAttributes } from 'react';\nimport { cn } from '../../utils/utils';\n\ntype TableVariant = 'default' | 'borderless';\ntype TableRowState = 'default' | 'selected' | 'invalid' | 'disabled';\n\ninterface TableProps extends HTMLAttributes<HTMLTableElement> {\n variant?: TableVariant;\n}\n\ninterface TableRowProps extends HTMLAttributes<HTMLTableRowElement> {\n state?: TableRowState;\n}\n\nconst Table = forwardRef<HTMLTableElement, TableProps>(\n ({ variant = 'default', className, children, ...props }, ref) => (\n <div\n className={cn(\n 'relative w-full overflow-hidden',\n variant === 'default' && 'border border-border-200 rounded-xl'\n )}\n >\n <table\n ref={ref}\n className={cn('w-full caption-bottom text-sm', className)}\n {...props}\n >\n {/* Fix Sonnar */}\n <caption className=\"sr-only\">My Table</caption>\n {children}\n </table>\n </div>\n )\n);\n\nTable.displayName = 'Table';\n\nconst TableHeader = forwardRef<\n HTMLTableSectionElement,\n HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <thead\n ref={ref}\n className={cn('[&_tr:first-child]:border-0', className)}\n {...props}\n />\n));\nTableHeader.displayName = 'TableHeader';\n\ninterface TableBodyProps extends HTMLAttributes<HTMLTableSectionElement> {\n variant?: TableVariant;\n}\n\nconst TableBody = forwardRef<HTMLTableSectionElement, TableBodyProps>(\n ({ variant = 'default', className, ...props }, ref) => (\n <tbody\n ref={ref}\n className={cn(\n '[&_tr:last-child]:border-0',\n variant === 'default' && 'border-t border-border-200',\n className\n )}\n {...props}\n />\n )\n);\nTableBody.displayName = 'TableBody';\n\ninterface TableFooterProps extends HTMLAttributes<HTMLTableSectionElement> {\n variant?: TableVariant;\n}\n\nconst TableFooter = forwardRef<HTMLTableSectionElement, TableFooterProps>(\n ({ variant = 'default', className, ...props }, ref) => (\n <tfoot\n ref={ref}\n className={cn(\n 'bg-background-50 font-medium [&>tr]:last:border-b-0 px-6 py-3.5',\n variant === 'default' && 'border-t border-border-200',\n className\n )}\n {...props}\n />\n )\n);\nTableFooter.displayName = 'TableFooter';\n\nconst VARIANT_STATES_ROW = {\n default: {\n default: 'border-b border-border-200',\n borderless: '',\n },\n selected: {\n default: 'border-b-2 border-indicator-primary',\n borderless: 'bg-indicator-primary/10',\n },\n invalid: {\n default: 'border-b-2 border-indicator-error',\n borderless: 'bg-indicator-error/10',\n },\n disabled: {\n default:\n 'border-b border-border-100 bg-background-50 opacity-50 cursor-not-allowed',\n borderless: 'bg-background-50 opacity-50 cursor-not-allowed',\n },\n} as const;\n\ninterface TableRowPropsExtended extends TableRowProps {\n variant?: TableVariant;\n}\n\nconst TableRow = forwardRef<HTMLTableRowElement, TableRowPropsExtended>(\n ({ variant = 'default', state = 'default', className, ...props }, ref) => {\n return (\n <tr\n ref={ref}\n className={cn(\n 'transition-colors',\n state !== 'disabled' ? 'hover:bg-muted/50' : '',\n VARIANT_STATES_ROW[state][variant],\n className\n )}\n aria-disabled={state === 'disabled'}\n {...props}\n />\n );\n }\n);\nTableRow.displayName = 'TableRow';\n\nconst TableHead = forwardRef<\n HTMLTableCellElement,\n TdHTMLAttributes<HTMLTableCellElement>\n>(({ className, ...props }, ref) => (\n <th\n ref={ref}\n className={cn(\n 'h-10 px-6 py-3.5 bg-muted/50 text-left align-middle font-bold text-text-800 [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]',\n className\n )}\n {...props}\n />\n));\nTableHead.displayName = 'TableHead';\n\nconst TableCell = forwardRef<\n HTMLTableCellElement,\n TdHTMLAttributes<HTMLTableCellElement>\n>(({ className, ...props }, ref) => (\n <td\n ref={ref}\n className={cn(\n 'p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px] text-md text-text-800 px-6 py-3.5',\n className\n )}\n {...props}\n />\n));\nTableCell.displayName = 'TableCell';\n\nconst TableCaption = forwardRef<\n HTMLTableCaptionElement,\n HTMLAttributes<HTMLTableCaptionElement>\n>(({ className, ...props }, ref) => (\n <caption\n ref={ref}\n className={cn(\n 'border-t border-border-200 text-sm text-text-800 px-6 py-3.5',\n className\n )}\n {...props}\n />\n));\nTableCaption.displayName = 'TableCaption';\n\nexport default Table;\nexport {\n TableHeader,\n TableBody,\n TableFooter,\n TableHead,\n TableRow,\n TableCell,\n TableCaption,\n};\n","import { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport { syncDropdownState } from './dropdown';\n\n/**\n * Retorna a cor hexadecimal com opacidade 0.3 (4d) se não estiver em dark mode.\n * Se estiver em dark mode, retorna a cor original.\n *\n * @param hexColor - Cor hexadecimal (ex: \"#0066b8\" ou \"0066b8\")\n * @param isDark - booleano indicando se está em dark mode\n * @returns string - cor hexadecimal com opacidade se necessário\n */\nexport function getSubjectColorWithOpacity(\n hexColor: string | undefined,\n isDark: boolean\n): string | undefined {\n if (!hexColor) return undefined;\n // Remove o '#' se existir\n let color = hexColor.replace(/^#/, '').toLowerCase();\n\n if (isDark) {\n // Se está em dark mode, sempre remove opacidade se existir\n if (color.length === 8) {\n color = color.slice(0, 6);\n }\n return `#${color}`;\n } else {\n // Se não está em dark mode (light mode)\n let resultColor: string;\n if (color.length === 6) {\n // Adiciona opacidade 0.3 (4D) para cores de 6 dígitos\n resultColor = `#${color}4d`;\n } else if (color.length === 8) {\n // Já tem opacidade, retorna como está\n resultColor = `#${color}`;\n } else {\n // Para outros tamanhos (3, 4, 5 dígitos), retorna como está\n resultColor = `#${color}`;\n }\n return resultColor;\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/Table/Table.tsx","../../src/utils/utils.ts"],"sourcesContent":["import {\n forwardRef,\n HTMLAttributes,\n TdHTMLAttributes,\n ThHTMLAttributes,\n useState,\n useMemo,\n useEffect,\n} from 'react';\nimport { cn } from '../../utils/utils';\nimport { CaretUp, CaretDown } from 'phosphor-react';\n\ntype TableVariant = 'default' | 'borderless';\ntype TableRowState = 'default' | 'selected' | 'invalid' | 'disabled';\nexport type SortDirection = 'asc' | 'desc' | null;\n\ninterface UseTableSortOptions {\n /** Se true, sincroniza o estado de ordenação com os parâmetros da URL */\n syncWithUrl?: boolean;\n}\n\n/**\n * Hook para gerenciar ordenação de dados da tabela\n *\n * @param data - Array de dados a serem ordenados\n * @param options - Opções de configuração do hook\n * @returns Objeto com dados ordenados, coluna/direção atual e função de sort\n *\n * @example\n * ```tsx\n * const activities = [\n * { id: 1, name: 'Task A', date: '2024-01-01' },\n * { id: 2, name: 'Task B', date: '2024-01-02' },\n * ];\n *\n * // Sem sincronização com URL\n * const { sortedData, sortColumn, sortDirection, handleSort } = useTableSort(activities);\n *\n * // Com sincronização com URL\n * const { sortedData, sortColumn, sortDirection, handleSort } = useTableSort(activities, { syncWithUrl: true });\n *\n * <TableHead\n * sortDirection={sortColumn === 'name' ? sortDirection : null}\n * onSort={() => handleSort('name')}\n * >\n * Name\n * </TableHead>\n * ```\n */\nexport function useTableSort<T extends Record<string, unknown>>(\n data: T[],\n options: UseTableSortOptions = {}\n) {\n const { syncWithUrl = false } = options;\n\n // Inicializar estado a partir da URL se syncWithUrl estiver habilitado\n const getInitialState = () => {\n if (!syncWithUrl || globalThis.window === undefined) {\n return { column: null, direction: null };\n }\n\n const params = new URLSearchParams(globalThis.location.search);\n const sortBy = params.get('sortBy');\n const sort = params.get('sort');\n\n if (sortBy && sort && (sort === 'ASC' || sort === 'DESC')) {\n return {\n column: sortBy,\n direction: sort.toLowerCase() as SortDirection,\n };\n }\n\n return { column: null, direction: null };\n };\n\n const initialState = getInitialState();\n const [sortColumn, setSortColumn] = useState<string | null>(\n initialState.column\n );\n const [sortDirection, setSortDirection] = useState<SortDirection>(\n initialState.direction\n );\n\n // Atualizar URL quando o estado de ordenação mudar\n useEffect(() => {\n if (!syncWithUrl || globalThis.window === undefined) return;\n\n const url = new URL(globalThis.location.href);\n const params = url.searchParams;\n\n if (sortColumn && sortDirection) {\n params.set('sortBy', sortColumn);\n params.set('sort', sortDirection.toUpperCase());\n } else {\n params.delete('sortBy');\n params.delete('sort');\n }\n\n // Atualizar URL sem recarregar a página\n globalThis.history.replaceState({}, '', url.toString());\n }, [sortColumn, sortDirection, syncWithUrl]);\n\n const handleSort = (column: string) => {\n if (sortColumn === column) {\n if (sortDirection === 'asc') {\n setSortDirection('desc');\n } else if (sortDirection === 'desc') {\n setSortColumn(null);\n setSortDirection(null);\n }\n } else {\n setSortColumn(column);\n setSortDirection('asc');\n }\n };\n\n const sortedData = useMemo(() => {\n if (!sortColumn || !sortDirection) {\n return data;\n }\n\n return [...data].sort((a, b) => {\n const aValue = a[sortColumn as keyof T];\n const bValue = b[sortColumn as keyof T];\n\n if (typeof aValue === 'string' && typeof bValue === 'string') {\n const comparison = aValue.localeCompare(bValue);\n return sortDirection === 'asc' ? comparison : -comparison;\n }\n\n if (typeof aValue === 'number' && typeof bValue === 'number') {\n return sortDirection === 'asc' ? aValue - bValue : bValue - aValue;\n }\n\n return 0;\n });\n }, [data, sortColumn, sortDirection]);\n\n return { sortedData, sortColumn, sortDirection, handleSort };\n}\n\ninterface TableProps extends HTMLAttributes<HTMLTableElement> {\n variant?: TableVariant;\n}\n\ninterface TableRowProps extends HTMLAttributes<HTMLTableRowElement> {\n state?: TableRowState;\n}\n\nconst Table = forwardRef<HTMLTableElement, TableProps>(\n ({ variant = 'default', className, children, ...props }, ref) => (\n <div\n className={cn(\n 'relative w-full overflow-x-auto',\n variant === 'default' && 'border border-border-200 rounded-xl'\n )}\n >\n <table\n ref={ref}\n className={cn(\n 'analytica-table w-full caption-bottom text-sm border-separate border-spacing-0',\n className\n )}\n {...props}\n >\n {/* Fix Sonnar */}\n <caption className=\"sr-only\">My Table</caption>\n {children}\n </table>\n </div>\n )\n);\n\nTable.displayName = 'Table';\n\nconst TableHeader = forwardRef<\n HTMLTableSectionElement,\n HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <thead\n ref={ref}\n className={cn('[&_tr:first-child]:border-0', className)}\n {...props}\n />\n));\nTableHeader.displayName = 'TableHeader';\n\ninterface TableBodyProps extends HTMLAttributes<HTMLTableSectionElement> {\n variant?: TableVariant;\n}\n\nconst TableBody = forwardRef<HTMLTableSectionElement, TableBodyProps>(\n ({ className, ...props }, ref) => (\n <tbody\n ref={ref}\n className={cn('[&_tr:last-child]:border-border-200', className)}\n {...props}\n />\n )\n);\nTableBody.displayName = 'TableBody';\n\ninterface TableFooterProps extends HTMLAttributes<HTMLTableSectionElement> {\n variant?: TableVariant;\n}\n\nconst TableFooter = forwardRef<HTMLTableSectionElement, TableFooterProps>(\n ({ variant = 'default', className, ...props }, ref) => (\n <tfoot\n ref={ref}\n className={cn(\n 'bg-background-50 font-medium [&>tr]:last:border-b-0 px-6 py-3.5',\n variant === 'default' && 'border-t border-border-200',\n className\n )}\n {...props}\n />\n )\n);\nTableFooter.displayName = 'TableFooter';\n\nconst VARIANT_STATES_ROW = {\n default: {\n default: 'border border-border-200',\n borderless: '',\n },\n selected: {\n default: 'border-b-2 border-indicator-primary',\n borderless: 'bg-indicator-primary/10',\n },\n invalid: {\n default: 'border-b-2 border-indicator-error',\n borderless: 'bg-indicator-error/10',\n },\n disabled: {\n default:\n 'border-b border-border-100 bg-background-50 opacity-50 cursor-not-allowed',\n borderless: 'bg-background-50 opacity-50 cursor-not-allowed',\n },\n} as const;\n\ninterface TableRowPropsExtended extends TableRowProps {\n variant?: TableVariant;\n clickable?: boolean;\n}\n\nconst TableRow = forwardRef<HTMLTableRowElement, TableRowPropsExtended>(\n (\n {\n variant = 'default',\n state = 'default',\n clickable = false,\n className,\n ...props\n },\n ref\n ) => {\n return (\n <tr\n ref={ref}\n className={cn(\n 'transition-colors',\n state !== 'disabled' ? 'hover:bg-muted/50' : '',\n clickable && state !== 'disabled' ? 'cursor-pointer' : '',\n VARIANT_STATES_ROW[state][variant],\n className\n )}\n aria-disabled={state === 'disabled'}\n {...props}\n />\n );\n }\n);\nTableRow.displayName = 'TableRow';\n\ninterface TableHeadProps extends ThHTMLAttributes<HTMLTableCellElement> {\n /** Enable sorting on this column (default: true) */\n sortable?: boolean;\n /** Current sort direction for this column */\n sortDirection?: SortDirection;\n /** Callback when column header is clicked */\n onSort?: () => void;\n}\n\nconst TableHead = forwardRef<HTMLTableCellElement, TableHeadProps>(\n (\n {\n className,\n sortable = true,\n sortDirection = null,\n onSort,\n children,\n ...props\n },\n ref\n ) => {\n const handleClick = () => {\n if (sortable && onSort) {\n onSort();\n }\n };\n\n return (\n <th\n ref={ref}\n className={cn(\n 'h-10 px-6 py-3.5 text-left align-middle font-bold text-base text-text-800 tracking-[0.2px] leading-none [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px] whitespace-nowrap',\n sortable && 'cursor-pointer select-none hover:bg-muted/30',\n className\n )}\n onClick={handleClick}\n {...props}\n >\n <div className=\"flex items-center gap-2\">\n {children}\n {sortable && (\n <div className=\"flex flex-col\">\n {sortDirection === 'asc' && (\n <CaretUp size={16} weight=\"fill\" className=\"text-text-800\" />\n )}\n {sortDirection === 'desc' && (\n <CaretDown size={16} weight=\"fill\" className=\"text-text-800\" />\n )}\n </div>\n )}\n </div>\n </th>\n );\n }\n);\nTableHead.displayName = 'TableHead';\n\nconst TableCell = forwardRef<\n HTMLTableCellElement,\n TdHTMLAttributes<HTMLTableCellElement>\n>(({ className, ...props }, ref) => (\n <td\n ref={ref}\n className={cn(\n 'p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px] text-base font-normal text-text-800 leading-[150%] tracking-normal px-6 py-3.5 whitespace-nowrap',\n className\n )}\n {...props}\n />\n));\nTableCell.displayName = 'TableCell';\n\nconst TableCaption = forwardRef<\n HTMLTableCaptionElement,\n HTMLAttributes<HTMLTableCaptionElement>\n>(({ className, ...props }, ref) => (\n <caption\n ref={ref}\n className={cn(\n 'border-t border-border-200 text-sm text-text-800 px-6 py-3.5',\n className\n )}\n {...props}\n />\n));\nTableCaption.displayName = 'TableCaption';\n\nexport default Table;\nexport {\n TableHeader,\n TableBody,\n TableFooter,\n TableHead,\n TableRow,\n TableCell,\n TableCaption,\n};\n","import { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport { syncDropdownState } from './dropdown';\n\n/**\n * Retorna a cor hexadecimal com opacidade 0.3 (4d) se não estiver em dark mode.\n * Se estiver em dark mode, retorna a cor original.\n *\n * @param hexColor - Cor hexadecimal (ex: \"#0066b8\" ou \"0066b8\")\n * @param isDark - booleano indicando se está em dark mode\n * @returns string - cor hexadecimal com opacidade se necessário\n */\nexport function getSubjectColorWithOpacity(\n hexColor: string | undefined,\n isDark: boolean\n): string | undefined {\n if (!hexColor) return undefined;\n // Remove o '#' se existir\n let color = hexColor.replace(/^#/, '').toLowerCase();\n\n if (isDark) {\n // Se está em dark mode, sempre remove opacidade se existir\n if (color.length === 8) {\n color = color.slice(0, 6);\n }\n return `#${color}`;\n } else {\n // Se não está em dark mode (light mode)\n let resultColor: string;\n if (color.length === 6) {\n // Adiciona opacidade 0.3 (4D) para cores de 6 dígitos\n resultColor = `#${color}4d`;\n } else if (color.length === 8) {\n // Já tem opacidade, retorna como está\n resultColor = `#${color}`;\n } else {\n // Para outros tamanhos (3, 4, 5 dígitos), retorna como está\n resultColor = `#${color}`;\n }\n return resultColor;\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,5 +1,10 @@
1
1
  // src/components/Table/Table.tsx
2
- import { forwardRef } from "react";
2
+ import {
3
+ forwardRef,
4
+ useState,
5
+ useMemo,
6
+ useEffect
7
+ } from "react";
3
8
 
4
9
  // src/utils/utils.ts
5
10
  import { clsx } from "clsx";
@@ -9,20 +14,93 @@ function cn(...inputs) {
9
14
  }
10
15
 
11
16
  // src/components/Table/Table.tsx
17
+ import { CaretUp, CaretDown } from "phosphor-react";
12
18
  import { jsx, jsxs } from "react/jsx-runtime";
19
+ function useTableSort(data, options = {}) {
20
+ const { syncWithUrl = false } = options;
21
+ const getInitialState = () => {
22
+ if (!syncWithUrl || globalThis.window === void 0) {
23
+ return { column: null, direction: null };
24
+ }
25
+ const params = new URLSearchParams(globalThis.location.search);
26
+ const sortBy = params.get("sortBy");
27
+ const sort = params.get("sort");
28
+ if (sortBy && sort && (sort === "ASC" || sort === "DESC")) {
29
+ return {
30
+ column: sortBy,
31
+ direction: sort.toLowerCase()
32
+ };
33
+ }
34
+ return { column: null, direction: null };
35
+ };
36
+ const initialState = getInitialState();
37
+ const [sortColumn, setSortColumn] = useState(
38
+ initialState.column
39
+ );
40
+ const [sortDirection, setSortDirection] = useState(
41
+ initialState.direction
42
+ );
43
+ useEffect(() => {
44
+ if (!syncWithUrl || globalThis.window === void 0) return;
45
+ const url = new URL(globalThis.location.href);
46
+ const params = url.searchParams;
47
+ if (sortColumn && sortDirection) {
48
+ params.set("sortBy", sortColumn);
49
+ params.set("sort", sortDirection.toUpperCase());
50
+ } else {
51
+ params.delete("sortBy");
52
+ params.delete("sort");
53
+ }
54
+ globalThis.history.replaceState({}, "", url.toString());
55
+ }, [sortColumn, sortDirection, syncWithUrl]);
56
+ const handleSort = (column) => {
57
+ if (sortColumn === column) {
58
+ if (sortDirection === "asc") {
59
+ setSortDirection("desc");
60
+ } else if (sortDirection === "desc") {
61
+ setSortColumn(null);
62
+ setSortDirection(null);
63
+ }
64
+ } else {
65
+ setSortColumn(column);
66
+ setSortDirection("asc");
67
+ }
68
+ };
69
+ const sortedData = useMemo(() => {
70
+ if (!sortColumn || !sortDirection) {
71
+ return data;
72
+ }
73
+ return [...data].sort((a, b) => {
74
+ const aValue = a[sortColumn];
75
+ const bValue = b[sortColumn];
76
+ if (typeof aValue === "string" && typeof bValue === "string") {
77
+ const comparison = aValue.localeCompare(bValue);
78
+ return sortDirection === "asc" ? comparison : -comparison;
79
+ }
80
+ if (typeof aValue === "number" && typeof bValue === "number") {
81
+ return sortDirection === "asc" ? aValue - bValue : bValue - aValue;
82
+ }
83
+ return 0;
84
+ });
85
+ }, [data, sortColumn, sortDirection]);
86
+ return { sortedData, sortColumn, sortDirection, handleSort };
87
+ }
13
88
  var Table = forwardRef(
14
89
  ({ variant = "default", className, children, ...props }, ref) => /* @__PURE__ */ jsx(
15
90
  "div",
16
91
  {
17
92
  className: cn(
18
- "relative w-full overflow-hidden",
93
+ "relative w-full overflow-x-auto",
19
94
  variant === "default" && "border border-border-200 rounded-xl"
20
95
  ),
21
96
  children: /* @__PURE__ */ jsxs(
22
97
  "table",
23
98
  {
24
99
  ref,
25
- className: cn("w-full caption-bottom text-sm", className),
100
+ className: cn(
101
+ "analytica-table w-full caption-bottom text-sm border-separate border-spacing-0",
102
+ className
103
+ ),
26
104
  ...props,
27
105
  children: [
28
106
  /* @__PURE__ */ jsx("caption", { className: "sr-only", children: "My Table" }),
@@ -44,15 +122,11 @@ var TableHeader = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ j
44
122
  ));
45
123
  TableHeader.displayName = "TableHeader";
46
124
  var TableBody = forwardRef(
47
- ({ variant = "default", className, ...props }, ref) => /* @__PURE__ */ jsx(
125
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
48
126
  "tbody",
49
127
  {
50
128
  ref,
51
- className: cn(
52
- "[&_tr:last-child]:border-0",
53
- variant === "default" && "border-t border-border-200",
54
- className
55
- ),
129
+ className: cn("[&_tr:last-child]:border-border-200", className),
56
130
  ...props
57
131
  }
58
132
  )
@@ -75,7 +149,7 @@ var TableFooter = forwardRef(
75
149
  TableFooter.displayName = "TableFooter";
76
150
  var VARIANT_STATES_ROW = {
77
151
  default: {
78
- default: "border-b border-border-200",
152
+ default: "border border-border-200",
79
153
  borderless: ""
80
154
  },
81
155
  selected: {
@@ -92,7 +166,13 @@ var VARIANT_STATES_ROW = {
92
166
  }
93
167
  };
94
168
  var TableRow = forwardRef(
95
- ({ variant = "default", state = "default", className, ...props }, ref) => {
169
+ ({
170
+ variant = "default",
171
+ state = "default",
172
+ clickable = false,
173
+ className,
174
+ ...props
175
+ }, ref) => {
96
176
  return /* @__PURE__ */ jsx(
97
177
  "tr",
98
178
  {
@@ -100,6 +180,7 @@ var TableRow = forwardRef(
100
180
  className: cn(
101
181
  "transition-colors",
102
182
  state !== "disabled" ? "hover:bg-muted/50" : "",
183
+ clickable && state !== "disabled" ? "cursor-pointer" : "",
103
184
  VARIANT_STATES_ROW[state][variant],
104
185
  className
105
186
  ),
@@ -110,24 +191,49 @@ var TableRow = forwardRef(
110
191
  }
111
192
  );
112
193
  TableRow.displayName = "TableRow";
113
- var TableHead = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
114
- "th",
115
- {
116
- ref,
117
- className: cn(
118
- "h-10 px-6 py-3.5 bg-muted/50 text-left align-middle font-bold text-text-800 [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
119
- className
120
- ),
194
+ var TableHead = forwardRef(
195
+ ({
196
+ className,
197
+ sortable = true,
198
+ sortDirection = null,
199
+ onSort,
200
+ children,
121
201
  ...props
202
+ }, ref) => {
203
+ const handleClick = () => {
204
+ if (sortable && onSort) {
205
+ onSort();
206
+ }
207
+ };
208
+ return /* @__PURE__ */ jsx(
209
+ "th",
210
+ {
211
+ ref,
212
+ className: cn(
213
+ "h-10 px-6 py-3.5 text-left align-middle font-bold text-base text-text-800 tracking-[0.2px] leading-none [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px] whitespace-nowrap",
214
+ sortable && "cursor-pointer select-none hover:bg-muted/30",
215
+ className
216
+ ),
217
+ onClick: handleClick,
218
+ ...props,
219
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
220
+ children,
221
+ sortable && /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
222
+ sortDirection === "asc" && /* @__PURE__ */ jsx(CaretUp, { size: 16, weight: "fill", className: "text-text-800" }),
223
+ sortDirection === "desc" && /* @__PURE__ */ jsx(CaretDown, { size: 16, weight: "fill", className: "text-text-800" })
224
+ ] })
225
+ ] })
226
+ }
227
+ );
122
228
  }
123
- ));
229
+ );
124
230
  TableHead.displayName = "TableHead";
125
231
  var TableCell = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
126
232
  "td",
127
233
  {
128
234
  ref,
129
235
  className: cn(
130
- "p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px] text-md text-text-800 px-6 py-3.5",
236
+ "p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px] text-base font-normal text-text-800 leading-[150%] tracking-normal px-6 py-3.5 whitespace-nowrap",
131
237
  className
132
238
  ),
133
239
  ...props
@@ -155,6 +261,7 @@ export {
155
261
  TableHead,
156
262
  TableHeader,
157
263
  TableRow,
158
- Table_default as default
264
+ Table_default as default,
265
+ useTableSort
159
266
  };
160
267
  //# sourceMappingURL=index.mjs.map