analytica-frontend-lib
Version:
Repositório público dos componentes utilizados nas plataformas da Analytica Ensino
484 lines (456 loc) • 18 kB
JavaScript
;Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
var _chunkJL5R5KTYjs = require('./chunk-JL5R5KTY.js');
var _chunkNEDUOGWUjs = require('./chunk-NEDUOGWU.js');
var _chunkEKKSTC6Qjs = require('./chunk-EKKSTC6Q.js');
var _chunkTN3AYOMVjs = require('./chunk-TN3AYOMV.js');
// src/components/Table/Table.tsx
var _react = require('react');
var _ArrowUp = require('@phosphor-icons/react/dist/csr/ArrowUp');
var _ArrowDown = require('@phosphor-icons/react/dist/csr/ArrowDown');
var _jsxruntime = require('react/jsx-runtime');
var getUrlKeys = (prefix) => ({
sortBy: prefix ? `${prefix}_sortBy` : "sortBy",
sortOrder: prefix ? `${prefix}_sortOrder` : "sortOrder",
/** Contrato antigo (`sort=ASC`), ainda lido para não quebrar links salvos. */
legacySort: prefix ? `${prefix}_sort` : "sort"
});
function useTableSort(data, options = {}) {
const {
syncWithUrl = false,
mode = "client",
urlKeyPrefix,
allowedColumns,
defaultSort,
onSortChange
} = options;
const urlKeys = _react.useMemo.call(void 0, () => getUrlKeys(urlKeyPrefix), [urlKeyPrefix]);
const allowedColumnsRef = _react.useRef.call(void 0, allowedColumns);
allowedColumnsRef.current = allowedColumns;
const onSortChangeRef = _react.useRef.call(void 0, onSortChange);
onSortChangeRef.current = onSortChange;
const defaultSortRef = _react.useRef.call(void 0, defaultSort);
defaultSortRef.current = defaultSort;
const readFromUrl = _react.useCallback.call(void 0, () => {
const fallback = defaultSortRef.current ? {
column: defaultSortRef.current.sortBy,
direction: defaultSortRef.current.sortOrder
} : { column: null, direction: null };
if (!syncWithUrl || globalThis.window === void 0) {
return fallback;
}
const params = new URLSearchParams(globalThis.location.search);
const column = params.get(urlKeys.sortBy);
if (!column) return fallback;
const rawOrder = _nullishCoalesce(params.get(urlKeys.sortOrder), () => ( params.get(urlKeys.legacySort)));
const direction = _optionalChain([rawOrder, 'optionalAccess', _ => _.toLowerCase, 'call', _2 => _2()]);
if (direction !== "asc" && direction !== "desc") return fallback;
const allowed = allowedColumnsRef.current;
if (allowed && !allowed.includes(column)) return fallback;
return { column, direction };
}, [syncWithUrl, urlKeys]);
const [initialState] = _react.useState.call(void 0, readFromUrl);
const [sortColumn, setSortColumn] = _react.useState.call(void 0,
initialState.column
);
const [sortDirection, setSortDirection] = _react.useState.call(void 0,
initialState.direction
);
const hasWrittenUrlRef = _react.useRef.call(void 0, false);
_react.useEffect.call(void 0, () => {
if (!syncWithUrl || globalThis.window === void 0) return;
const url = new URL(globalThis.location.href);
const params = url.searchParams;
if (sortColumn && sortDirection) {
params.set(urlKeys.sortBy, sortColumn);
params.set(urlKeys.sortOrder, sortDirection);
params.delete(urlKeys.legacySort);
hasWrittenUrlRef.current = true;
} else if (hasWrittenUrlRef.current) {
params.delete(urlKeys.sortBy);
params.delete(urlKeys.sortOrder);
params.delete(urlKeys.legacySort);
} else {
return;
}
globalThis.history.replaceState({}, "", url.toString());
}, [sortColumn, sortDirection, syncWithUrl, urlKeys]);
_react.useEffect.call(void 0, () => {
if (!syncWithUrl || globalThis.window === void 0) return;
const handlePopState = () => {
const next = readFromUrl();
setSortColumn(next.column);
setSortDirection(next.direction);
};
globalThis.addEventListener("popstate", handlePopState);
return () => globalThis.removeEventListener("popstate", handlePopState);
}, [syncWithUrl, readFromUrl]);
const handleSort = (column) => {
if (sortColumn === column && sortDirection === "asc") {
setSortDirection("desc");
} else if (sortColumn === column && sortDirection === "desc") {
setSortColumn(null);
setSortDirection(null);
} else {
setSortColumn(column);
setSortDirection("asc");
}
_optionalChain([onSortChangeRef, 'access', _3 => _3.current, 'optionalCall', _4 => _4()]);
};
const sortedData = _react.useMemo.call(void 0, () => {
if (mode === "server" || !sortColumn || !sortDirection) {
return data;
}
return [...data].sort((a, b) => {
const aValue = a[sortColumn];
const bValue = b[sortColumn];
if (typeof aValue === "string" && typeof bValue === "string") {
const comparison = aValue.localeCompare(bValue);
return sortDirection === "asc" ? comparison : -comparison;
}
if (typeof aValue === "number" && typeof bValue === "number") {
return sortDirection === "asc" ? aValue - bValue : bValue - aValue;
}
return 0;
});
}, [data, sortColumn, sortDirection, mode]);
return { sortedData, sortColumn, sortDirection, handleSort };
}
var renderHeaderElements = (children) => {
return _react.Children.map(children, (child) => {
if (_react.isValidElement.call(void 0, child) && (child.type === TableCaption || child.type === TableHeader)) {
return child;
}
return null;
});
};
var getNoSearchResultContent = (config, defaultTitle, defaultDescription) => {
if (config.component) {
return config.component;
}
if (config.image) {
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
_chunkEKKSTC6Qjs.NoSearchResult_default,
{
image: config.image,
title: config.title || defaultTitle,
description: config.description || defaultDescription
}
);
}
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "text-center", children: [
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-text-600 text-lg font-semibold mb-2", children: config.title || defaultTitle }),
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-text-500 text-sm", children: config.description || defaultDescription })
] });
};
var getEmptyStateContent = (config, defaultTitle, defaultDescription) => {
if (_optionalChain([config, 'optionalAccess', _5 => _5.component])) {
return config.component;
}
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
_chunkJL5R5KTYjs.EmptyState_default,
{
image: _optionalChain([config, 'optionalAccess', _6 => _6.image]),
title: _optionalChain([config, 'optionalAccess', _7 => _7.title]) || defaultTitle,
description: _optionalChain([config, 'optionalAccess', _8 => _8.description]) || defaultDescription,
buttonText: _optionalChain([config, 'optionalAccess', _9 => _9.buttonText]),
buttonIcon: _optionalChain([config, 'optionalAccess', _10 => _10.buttonIcon]),
onButtonClick: _optionalChain([config, 'optionalAccess', _11 => _11.onButtonClick]),
buttonVariant: _optionalChain([config, 'optionalAccess', _12 => _12.buttonVariant]),
buttonAction: _optionalChain([config, 'optionalAccess', _13 => _13.buttonAction])
}
);
};
var renderTableWrapper = (variant, tableRef, className, children, stateContent, tableProps) => {
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
"div",
{
className: _chunkTN3AYOMVjs.cn.call(void 0,
"relative w-full overflow-x-auto",
variant === "default" && "border border-border-200 rounded-xl"
),
children: [
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
"table",
{
ref: tableRef,
className: _chunkTN3AYOMVjs.cn.call(void 0,
"analytica-table w-full caption-bottom text-sm border-separate border-spacing-0",
className
),
...tableProps,
children: renderHeaderElements(children)
}
),
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "py-8 flex justify-center", children: stateContent })
]
}
);
};
var Table = _react.forwardRef.call(void 0,
({
variant = "default",
className,
children,
showLoading = false,
loadingState,
showNoSearchResult = false,
noSearchResultState,
showEmpty = false,
emptyState,
...props
}, ref) => {
const defaultNoSearchResultState = {
title: "Nenhum resultado encontrado",
description: "N\xE3o encontramos nenhum resultado com esse nome. Tente revisar a busca ou usar outra palavra-chave."
};
const defaultEmptyState = {
title: "Nenhum dado dispon\xEDvel",
description: "N\xE3o h\xE1 dados para exibir no momento."
};
const finalNoSearchResultState = noSearchResultState || defaultNoSearchResultState;
const finalEmptyState = emptyState || defaultEmptyState;
if (showLoading) {
const loadingContent = _optionalChain([loadingState, 'optionalAccess', _14 => _14.component]) || /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkNEDUOGWUjs.SkeletonTable, { rows: 5, columns: 4, showHeader: false });
return renderTableWrapper(
variant,
ref,
className,
children,
loadingContent,
props
);
}
if (showNoSearchResult) {
const noSearchContent = getNoSearchResultContent(
finalNoSearchResultState,
defaultNoSearchResultState.title || "",
defaultNoSearchResultState.description || ""
);
return renderTableWrapper(
variant,
ref,
className,
children,
noSearchContent,
props
);
}
if (showEmpty) {
const emptyContent = getEmptyStateContent(
finalEmptyState,
defaultEmptyState.title || "Nenhum dado dispon\xEDvel",
defaultEmptyState.description || "N\xE3o h\xE1 dados para exibir no momento."
);
return renderTableWrapper(
variant,
ref,
className,
children,
emptyContent,
props
);
}
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
"div",
{
className: _chunkTN3AYOMVjs.cn.call(void 0,
"relative w-full overflow-x-auto",
variant === "default" && "border border-border-200 rounded-xl"
),
children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
"table",
{
ref,
className: _chunkTN3AYOMVjs.cn.call(void 0,
variant === "default" && "analytica-table",
variant === "default" && "border-separate border-spacing-0",
"w-full caption-bottom text-sm",
className
),
...props,
children: [
!_react.Children.toArray(children).some(
(child) => _react.isValidElement.call(void 0, child) && child.type === TableCaption
) && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "caption", { className: "sr-only", children: "My Table" }),
children
]
}
)
}
);
}
);
Table.displayName = "Table";
var TableHeader = _react.forwardRef.call(void 0, ({ className, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
"thead",
{
ref,
className: _chunkTN3AYOMVjs.cn.call(void 0, "[&_tr:first-child]:border-0", className),
...props
}
));
TableHeader.displayName = "TableHeader";
var TableBody = _react.forwardRef.call(void 0,
({ className, variant = "default", ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
"tbody",
{
ref,
className: _chunkTN3AYOMVjs.cn.call(void 0,
"[&_tr:last-child]:border-border-200",
variant === "default" && "border-t border-border-200",
className
),
...props
}
)
);
TableBody.displayName = "TableBody";
var TableFooter = _react.forwardRef.call(void 0,
({ variant = "default", className, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
"tfoot",
{
ref,
className: _chunkTN3AYOMVjs.cn.call(void 0,
"bg-background-50 font-medium [&>tr]:last:border-b-0 px-6 py-3.5",
variant === "default" && "border-t border-border-200",
className
),
...props
}
)
);
TableFooter.displayName = "TableFooter";
var VARIANT_STATES_ROW = {
default: {
default: "border border-border-200",
defaultBorderless: "border-b border-border-200",
borderless: ""
},
selected: {
default: "border-b-2 border-indicator-primary",
defaultBorderless: "border-b border-indicator-primary",
borderless: "bg-indicator-primary/10"
},
invalid: {
default: "border-b-2 border-indicator-error",
defaultBorderless: "border-b border-indicator-error",
borderless: "bg-indicator-error/10"
},
disabled: {
default: "border-b border-border-100 bg-background-50 opacity-50 cursor-not-allowed",
defaultBorderless: "border-b border-border-100 bg-background-50 opacity-50 cursor-not-allowed",
borderless: "bg-background-50 opacity-50 cursor-not-allowed"
}
};
var TableRow = _react.forwardRef.call(void 0,
({
variant = "default",
state = "default",
clickable = false,
className,
...props
}, ref) => {
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
"tr",
{
ref,
className: _chunkTN3AYOMVjs.cn.call(void 0,
"transition-colors",
state === "disabled" ? "" : "hover:bg-muted/50",
state === "disabled" || !clickable ? "" : "cursor-pointer",
VARIANT_STATES_ROW[state][variant],
className
),
"aria-disabled": state === "disabled",
...props
}
);
}
);
TableRow.displayName = "TableRow";
var TableHead = _react.forwardRef.call(void 0,
({
className,
sortable = false,
sortDirection = null,
onSort,
filterSlot,
children,
...props
}, ref) => {
const handleClick = () => {
if (sortable && onSort) {
onSort();
}
};
const ariaSort = (() => {
if (!sortable) return void 0;
if (sortDirection === "asc") return "ascending";
if (sortDirection === "desc") return "descending";
return "none";
})();
const sortArrow = sortable && sortDirection && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "flex shrink-0", children: sortDirection === "asc" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _ArrowUp.ArrowUpIcon, { size: 16, className: "text-text-800" }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _ArrowDown.ArrowDownIcon, { size: 16, className: "text-text-800" }) });
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
"th",
{
ref,
className: _chunkTN3AYOMVjs.cn.call(void 0,
"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",
sortable && "cursor-pointer select-none hover:bg-muted/30",
className
),
"aria-sort": ariaSort,
...props,
children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-2", children: [
sortable ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
"button",
{
type: "button",
onClick: handleClick,
className: _chunkTN3AYOMVjs.cn.call(void 0,
"flex items-center gap-2 text-left cursor-pointer select-none hover:opacity-80",
// Span the cell so pointer users keep a full-width target — but
// not when a filter caret follows, or it would be shoved to the
// far edge of the column instead of sitting next to the label.
!filterSlot && "flex-1"
),
children: [
children,
sortArrow
]
}
) : children,
filterSlot
] })
}
);
}
);
TableHead.displayName = "TableHead";
var TableCell = _react.forwardRef.call(void 0, ({ className, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
"td",
{
ref,
className: _chunkTN3AYOMVjs.cn.call(void 0,
"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",
className
),
...props
}
));
TableCell.displayName = "TableCell";
var TableCaption = _react.forwardRef.call(void 0, ({ className, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
"caption",
{
ref,
className: _chunkTN3AYOMVjs.cn.call(void 0,
"border-t border-border-200 text-sm text-text-800 px-6 py-3.5",
className
),
...props
}
));
TableCaption.displayName = "TableCaption";
var Table_default = Table;
exports.useTableSort = useTableSort; exports.TableHeader = TableHeader; exports.TableBody = TableBody; exports.TableFooter = TableFooter; exports.TableRow = TableRow; exports.TableHead = TableHead; exports.TableCell = TableCell; exports.TableCaption = TableCaption; exports.Table_default = Table_default;
//# sourceMappingURL=chunk-LWUL5WRW.js.map