UNPKG

analytica-frontend-lib

Version:

Repositório público dos componentes utilizados nas plataformas da Analytica Ensino

1 lines 30.4 kB
{"version":3,"sources":["../src/components/Table/Table.tsx"],"sourcesContent":["import React, {\n forwardRef,\n HTMLAttributes,\n TdHTMLAttributes,\n ThHTMLAttributes,\n useCallback,\n useState,\n useMemo,\n useEffect,\n useRef,\n Children,\n isValidElement,\n ReactNode,\n} from 'react';\nimport { cn } from '../../utils/utils';\nimport { ArrowUpIcon } from '@phosphor-icons/react/dist/csr/ArrowUp';\nimport { ArrowDownIcon } from '@phosphor-icons/react/dist/csr/ArrowDown';\nimport NoSearchResult from '../NoSearchResult/NoSearchResult';\nimport EmptyState from '../EmptyState/EmptyState';\nimport { SkeletonTable } from '../Skeleton/Skeleton';\nimport type {\n EmptyStateConfig,\n LoadingStateConfig,\n NoSearchResultConfig,\n} from '../TableProvider/TableProvider';\n\ntype TableVariant = 'default' | 'borderless';\ntype TableRowState = 'default' | 'selected' | 'invalid' | 'disabled';\nexport type SortDirection = 'asc' | 'desc' | null;\n\nexport type SortMode = 'client' | 'server';\n\nexport interface SortState {\n sortBy: string;\n sortOrder: 'asc' | 'desc';\n}\n\nexport interface UseTableSortOptions {\n /** Se true, sincroniza o estado de ordenação com os parâmetros da URL */\n syncWithUrl?: boolean;\n /**\n * `'client'` (padrão) ordena o array recebido no próprio navegador.\n * `'server'` mantém a ordem dos dados como vieram — a ordenação é\n * responsabilidade da API — e apenas rastreia a coluna/direção para\n * emiti-las nos parâmetros da tabela.\n */\n mode?: SortMode;\n /**\n * Prefixo das chaves na URL (`vendas_sortBy` em vez de `sortBy`). Necessário\n * quando mais de uma tabela compartilha a mesma URL, senão elas leem o estado\n * de ordenação uma da outra.\n */\n urlKeyPrefix?: string;\n /**\n * Colunas aceitas. Um `sortBy` vindo da URL que não esteja nesta lista é\n * descartado — uma URL colada não pode injetar uma coluna inexistente.\n */\n allowedColumns?: string[];\n /** Ordenação inicial quando a URL não traz nenhuma. */\n defaultSort?: SortState;\n /** Chamado a cada mudança de ordenação (o TableProvider usa para voltar à página 1). */\n onSortChange?: () => void;\n}\n\n/** Nomes das chaves de URL, opcionalmente prefixadas por tabela. */\nconst getUrlKeys = (prefix?: string) => ({\n sortBy: prefix ? `${prefix}_sortBy` : 'sortBy',\n sortOrder: prefix ? `${prefix}_sortOrder` : 'sortOrder',\n /** Contrato antigo (`sort=ASC`), ainda lido para não quebrar links salvos. */\n legacySort: prefix ? `${prefix}_sort` : 'sort',\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 {\n syncWithUrl = false,\n mode = 'client',\n urlKeyPrefix,\n allowedColumns,\n defaultSort,\n onSortChange,\n } = options;\n\n const urlKeys = useMemo(() => getUrlKeys(urlKeyPrefix), [urlKeyPrefix]);\n\n // Read through refs so the popstate listener doesn't resubscribe on every\n // render just because these arrived as new array/function identities.\n const allowedColumnsRef = useRef(allowedColumns);\n allowedColumnsRef.current = allowedColumns;\n const onSortChangeRef = useRef(onSortChange);\n onSortChangeRef.current = onSortChange;\n const defaultSortRef = useRef(defaultSort);\n defaultSortRef.current = defaultSort;\n\n const readFromUrl = useCallback((): {\n column: string | null;\n direction: SortDirection;\n } => {\n const fallback = defaultSortRef.current\n ? {\n column: defaultSortRef.current.sortBy,\n direction: defaultSortRef.current.sortOrder as SortDirection,\n }\n : { column: null, direction: null };\n\n if (!syncWithUrl || globalThis.window === undefined) {\n return fallback;\n }\n\n const params = new URLSearchParams(globalThis.location.search);\n const column = params.get(urlKeys.sortBy);\n if (!column) return fallback;\n\n // Current contract: sortOrder=asc|desc. Legacy: sort=ASC|DESC.\n const rawOrder =\n params.get(urlKeys.sortOrder) ?? params.get(urlKeys.legacySort);\n const direction = rawOrder?.toLowerCase();\n if (direction !== 'asc' && direction !== 'desc') return fallback;\n\n const allowed = allowedColumnsRef.current;\n if (allowed && !allowed.includes(column)) return fallback;\n\n return { column, direction };\n }, [syncWithUrl, urlKeys]);\n\n const [initialState] = useState(readFromUrl);\n const [sortColumn, setSortColumn] = useState<string | null>(\n initialState.column\n );\n const [sortDirection, setSortDirection] = useState<SortDirection>(\n initialState.direction\n );\n\n // Only ever remove the sort params this instance actually wrote. Without this\n // guard a table that never sorted would wipe the sort params of whatever else\n // shares the URL, just by mounting.\n const hasWrittenUrlRef = useRef(false);\n\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(urlKeys.sortBy, sortColumn);\n params.set(urlKeys.sortOrder, sortDirection);\n params.delete(urlKeys.legacySort);\n hasWrittenUrlRef.current = true;\n } else if (hasWrittenUrlRef.current) {\n params.delete(urlKeys.sortBy);\n params.delete(urlKeys.sortOrder);\n params.delete(urlKeys.legacySort);\n } else {\n return;\n }\n\n globalThis.history.replaceState({}, '', url.toString());\n }, [sortColumn, sortDirection, syncWithUrl, urlKeys]);\n\n // Back/forward has to bring the table's sort along with the URL.\n useEffect(() => {\n if (!syncWithUrl || globalThis.window === undefined) return;\n\n const handlePopState = () => {\n const next = readFromUrl();\n setSortColumn(next.column);\n setSortDirection(next.direction);\n };\n\n globalThis.addEventListener('popstate', handlePopState);\n return () => globalThis.removeEventListener('popstate', handlePopState);\n }, [syncWithUrl, readFromUrl]);\n\n /** Cycles asc → desc → unsorted. */\n const handleSort = (column: string) => {\n if (sortColumn === column && sortDirection === 'asc') {\n setSortDirection('desc');\n } else if (sortColumn === column && sortDirection === 'desc') {\n setSortColumn(null);\n setSortDirection(null);\n } else {\n setSortColumn(column);\n setSortDirection('asc');\n }\n\n onSortChangeRef.current?.();\n };\n\n const sortedData = useMemo(() => {\n // In server mode the rows already arrive ordered. Re-sorting them here would\n // shuffle the current page by whatever the cell happens to render — e.g.\n // comparing \"2h 05min\" as a string.\n if (mode === 'server' || !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, mode]);\n\n return { sortedData, sortColumn, sortDirection, handleSort };\n}\n\ninterface TableProps extends HTMLAttributes<HTMLTableElement> {\n variant?: TableVariant;\n\n /** Show loading state (controlled by TableProvider) */\n showLoading?: boolean;\n /** Loading state configuration */\n loadingState?: LoadingStateConfig;\n\n /** Show no search result state (controlled by TableProvider) */\n showNoSearchResult?: boolean;\n /** No search result state configuration */\n noSearchResultState?: NoSearchResultConfig;\n\n /** Show empty state (controlled by TableProvider) */\n showEmpty?: boolean;\n /** Empty state configuration */\n emptyState?: EmptyStateConfig;\n}\n\ninterface TableRowProps extends HTMLAttributes<HTMLTableRowElement> {\n state?: TableRowState;\n}\n\n/**\n * Renders the table header and caption from children\n */\nconst renderHeaderElements = (children: ReactNode) => {\n return Children.map(children, (child) => {\n if (\n isValidElement(child) &&\n (child.type === TableCaption || child.type === TableHeader)\n ) {\n return child;\n }\n return null;\n });\n};\n\n/**\n * Gets no search result content based on configuration\n */\nconst getNoSearchResultContent = (\n config: NoSearchResultConfig,\n defaultTitle: string,\n defaultDescription: string\n) => {\n if (config.component) {\n return config.component;\n }\n\n if (config.image) {\n return (\n <NoSearchResult\n image={config.image}\n title={config.title || defaultTitle}\n description={config.description || defaultDescription}\n />\n );\n }\n\n return (\n <div className=\"text-center\">\n <p className=\"text-text-600 text-lg font-semibold mb-2\">\n {config.title || defaultTitle}\n </p>\n <p className=\"text-text-500 text-sm\">\n {config.description || defaultDescription}\n </p>\n </div>\n );\n};\n\n/**\n * Gets empty state content based on configuration\n */\nconst getEmptyStateContent = (\n config: EmptyStateConfig | undefined,\n defaultTitle: string,\n defaultDescription: string\n) => {\n if (config?.component) {\n return config.component;\n }\n\n return (\n <EmptyState\n image={config?.image}\n title={config?.title || defaultTitle}\n description={config?.description || defaultDescription}\n buttonText={config?.buttonText}\n buttonIcon={config?.buttonIcon}\n onButtonClick={config?.onButtonClick}\n buttonVariant={config?.buttonVariant}\n buttonAction={config?.buttonAction}\n />\n );\n};\n\n/**\n * Renders table wrapper with header and state content\n */\nconst renderTableWrapper = (\n variant: TableVariant,\n tableRef: React.Ref<HTMLTableElement>,\n className: string | undefined,\n children: ReactNode,\n stateContent: ReactNode,\n tableProps: HTMLAttributes<HTMLTableElement>\n) => {\n return (\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={tableRef}\n className={cn(\n 'analytica-table w-full caption-bottom text-sm border-separate border-spacing-0',\n className\n )}\n {...tableProps}\n >\n {renderHeaderElements(children)}\n </table>\n <div className=\"py-8 flex justify-center\">{stateContent}</div>\n </div>\n );\n};\n\nconst Table = forwardRef<HTMLTableElement, TableProps>(\n (\n {\n variant = 'default',\n className,\n children,\n showLoading = false,\n loadingState,\n showNoSearchResult = false,\n noSearchResultState,\n showEmpty = false,\n emptyState,\n ...props\n },\n ref\n ) => {\n // Default configurations\n const defaultNoSearchResultState: NoSearchResultConfig = {\n title: 'Nenhum resultado encontrado',\n description:\n 'Não encontramos nenhum resultado com esse nome. Tente revisar a busca ou usar outra palavra-chave.',\n };\n\n const defaultEmptyState: EmptyStateConfig = {\n title: 'Nenhum dado disponível',\n description: 'Não há dados para exibir no momento.',\n };\n\n const finalNoSearchResultState =\n noSearchResultState || defaultNoSearchResultState;\n const finalEmptyState = emptyState || defaultEmptyState;\n\n // Render Loading State FIRST (highest priority)\n if (showLoading) {\n const loadingContent = loadingState?.component || (\n <SkeletonTable rows={5} columns={4} showHeader={false} />\n );\n return renderTableWrapper(\n variant,\n ref,\n className,\n children,\n loadingContent,\n props\n );\n }\n\n // Render NoSearchResult outside table\n if (showNoSearchResult) {\n const noSearchContent = getNoSearchResultContent(\n finalNoSearchResultState,\n defaultNoSearchResultState.title || '',\n defaultNoSearchResultState.description || ''\n );\n return renderTableWrapper(\n variant,\n ref,\n className,\n children,\n noSearchContent,\n props\n );\n }\n\n // Render Empty State outside table (same pattern as NoSearchResult)\n if (showEmpty) {\n const emptyContent = getEmptyStateContent(\n finalEmptyState,\n defaultEmptyState.title || 'Nenhum dado disponível',\n defaultEmptyState.description || 'Não há dados para exibir no momento.'\n );\n return renderTableWrapper(\n variant,\n ref,\n className,\n children,\n emptyContent,\n props\n );\n }\n\n return (\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 variant === 'default' && 'analytica-table',\n variant === 'default' && 'border-separate border-spacing-0',\n 'w-full caption-bottom text-sm',\n className\n )}\n {...props}\n >\n {/* Render fallback caption only if no TableCaption provided */}\n {!Children.toArray(children).some(\n (child) => isValidElement(child) && child.type === TableCaption\n ) && <caption className=\"sr-only\">My Table</caption>}\n {children}\n </table>\n </div>\n );\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, variant = 'default', ...props }, ref) => (\n <tbody\n ref={ref}\n className={cn(\n '[&_tr:last-child]:border-border-200',\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 border-border-200',\n defaultBorderless: 'border-b border-border-200',\n borderless: '',\n },\n selected: {\n default: 'border-b-2 border-indicator-primary',\n defaultBorderless: 'border-b border-indicator-primary',\n borderless: 'bg-indicator-primary/10',\n },\n invalid: {\n default: 'border-b-2 border-indicator-error',\n defaultBorderless: 'border-b 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 defaultBorderless:\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 | 'defaultBorderless';\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 state === 'disabled' || !clickable ? '' : '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 /**\n * Enable sorting on this column (default: false).\n *\n * This used to default to `true`, which made every header look clickable —\n * including the ones whose `onSort` did nothing.\n */\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 * Rendered at the right of the label — the column's filter menu trigger.\n * When present, only the label toggles sorting (instead of the whole cell),\n * so the two click targets don't fight over the same pixels.\n */\n filterSlot?: ReactNode;\n}\n\nconst TableHead = forwardRef<HTMLTableCellElement, TableHeadProps>(\n (\n {\n className,\n sortable = false,\n sortDirection = null,\n onSort,\n filterSlot,\n children,\n ...props\n },\n ref\n ) => {\n const handleClick = () => {\n if (sortable && onSort) {\n onSort();\n }\n };\n\n const ariaSort = (() => {\n if (!sortable) return undefined;\n if (sortDirection === 'asc') return 'ascending' as const;\n if (sortDirection === 'desc') return 'descending' as const;\n return 'none' as const;\n })();\n\n // An arrow — distinct from the caret that opens a column's filter menu, so\n // the two never read as the same affordance. Only the column actually being\n // sorted shows it.\n const sortArrow = sortable && sortDirection && (\n <span className=\"flex shrink-0\">\n {sortDirection === 'asc' ? (\n <ArrowUpIcon size={16} className=\"text-text-800\" />\n ) : (\n <ArrowDownIcon size={16} className=\"text-text-800\" />\n )}\n </span>\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 aria-sort={ariaSort}\n {...props}\n >\n <div className=\"flex items-center gap-2\">\n {/*\n * Sorting always lives on a real <button>, never on the <th> itself:\n * a click handler on the cell is unreachable by keyboard, and giving\n * the cell a role/tabindex would break the table semantics that\n * aria-sort relies on. `flex-1` keeps the click target spanning the\n * cell, so pointer users lose nothing.\n */}\n {sortable ? (\n <button\n type=\"button\"\n onClick={handleClick}\n className={cn(\n 'flex items-center gap-2 text-left cursor-pointer select-none hover:opacity-80',\n // Span the cell so pointer users keep a full-width target — but\n // not when a filter caret follows, or it would be shoved to the\n // far edge of the column instead of sitting next to the label.\n !filterSlot && 'flex-1'\n )}\n >\n {children}\n {sortArrow}\n </button>\n ) : (\n children\n )}\n {filterSlot}\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 as TablePagination } from './TablePagination';\nexport type { TablePaginationProps } from './TablePagination';\n\nexport default Table;\nexport {\n TableHeader,\n TableBody,\n TableFooter,\n TableHead,\n TableRow,\n TableCell,\n TableCaption,\n};\n"],"mappings":"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","names":[]}