sanity
Version:
Sanity is a real-time content infrastructure with a scalable, hosted backend featuring a Graph Oriented Query Language (GROQ), asset pipelines and fast edge caches
361 lines (360 loc) • 15 kB
JavaScript
import { jsx, jsxs } from "react/jsx-runtime";
import { c } from "react/compiler-runtime";
import { Card, Text, Box, Flex, Stack, TextInput, useTheme, rem } from "@sanity/ui";
import { useVirtualizer } from "@tanstack/react-virtual";
import { isValid } from "date-fns/isValid";
import get from "lodash-es/get.js";
import { useState, useContext, useMemo, Fragment } from "react";
import { Button, TooltipDelayGroupProvider } from "./index.js";
import "react-i18next";
import { TableContext } from "sanity/_singletons";
import { ArrowUpIcon } from "@sanity/icons/ArrowUp";
import { SearchIcon } from "@sanity/icons/Search";
import { motion } from "motion/react";
import { useTranslation } from "./index2.js";
const emptyCellStyle = {
textAlign: "center",
height: "100%",
display: "flex",
alignItems: "center",
justifyContent: "center"
}, emptyRowStyle = {
justifyContent: "center",
alignItems: "center",
height: "100%"
}, TableEmptyState = (t0) => {
const $ = c(10), {
emptyState,
colSpan
} = t0;
if (typeof emptyState == "string") {
let t12;
$[0] !== emptyState ? (t12 = /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, children: emptyState }), $[0] = emptyState, $[1] = t12) : t12 = $[1];
let t22;
return $[2] !== colSpan || $[3] !== t12 ? (t22 = /* @__PURE__ */ jsx(Card, { borderBottom: !0, display: "flex", padding: 4, as: "tr", style: emptyRowStyle, children: /* @__PURE__ */ jsx("td", { colSpan, style: emptyCellStyle, children: t12 }) }), $[2] = colSpan, $[3] = t12, $[4] = t22) : t22 = $[4], t22;
}
const EmptyStateComponent = emptyState;
let t1;
$[5] !== EmptyStateComponent ? (t1 = /* @__PURE__ */ jsx(EmptyStateComponent, {}), $[5] = EmptyStateComponent, $[6] = t1) : t1 = $[6];
let t2;
return $[7] !== colSpan || $[8] !== t1 ? (t2 = /* @__PURE__ */ jsx(Card, { borderBottom: !0, display: "flex", padding: 4, as: "tr", style: emptyRowStyle, children: /* @__PURE__ */ jsx("td", { colSpan, style: emptyCellStyle, children: t1 }) }), $[7] = colSpan, $[8] = t1, $[9] = t2) : t2 = $[9], t2;
}, TableProvider = (t0) => {
const $ = c(7), {
children,
defaultSort
} = t0, [searchTerm, setSearchTerm] = useState(null), [sort, setSort] = useState(defaultSort || null);
let t1;
$[0] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (t1 = (newColumn) => {
setSort((s) => s?.column === newColumn ? {
...s,
direction: s.direction === "asc" ? "desc" : "asc"
} : {
column: String(newColumn),
direction: "desc"
});
}, $[0] = t1) : t1 = $[0];
const setSortColumn = t1;
let t2;
$[1] !== searchTerm || $[2] !== sort ? (t2 = {
searchTerm,
setSearchTerm,
sort,
setSortColumn
}, $[1] = searchTerm, $[2] = sort, $[3] = t2) : t2 = $[3];
const contextValue = t2;
let t3;
return $[4] !== children || $[5] !== contextValue ? (t3 = /* @__PURE__ */ jsx(TableContext.Provider, { value: contextValue, children }), $[4] = children, $[5] = contextValue, $[6] = t3) : t3 = $[6], t3;
}, useTableContext = () => {
const context = useContext(TableContext);
if (!context)
throw new Error("useTableContext must be used within a TableProvider");
return context;
}, MotionIcon = motion.create(ArrowUpIcon), BasicHeader = (t0) => {
const $ = c(2), {
text
} = t0;
let t1;
return $[0] !== text ? (t1 = /* @__PURE__ */ jsx(Box, { padding: 2, children: /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, weight: "medium", children: text }) }), $[0] = text, $[1] = t1) : t1 = $[1], t1;
}, SortHeaderButton = (t0) => {
const $ = c(12), {
header,
text
} = t0, {
sort,
setSortColumn
} = useTableContext();
sort?.direction;
const t1 = sort?.direction === "asc" ? 0 : 180;
let t2;
$[0] !== t1 ? (t2 = {
rotate: t1
}, $[0] = t1, $[1] = t2) : t2 = $[1];
let t3;
$[2] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (t3 = {
duration: 0.25,
ease: "easeInOut"
}, $[2] = t3) : t3 = $[2];
let t4;
$[3] !== t2 ? (t4 = /* @__PURE__ */ jsx(MotionIcon, { initial: !1, animate: t2, transition: t3 }), $[3] = t2, $[4] = t4) : t4 = $[4];
const sortIcon = t4, t5 = header.sorting && sort?.column === header.id ? sortIcon : void 0;
let t6;
$[5] !== header.id || $[6] !== setSortColumn ? (t6 = () => setSortColumn(String(header.id)), $[5] = header.id, $[6] = setSortColumn, $[7] = t6) : t6 = $[7];
let t7;
return $[8] !== t5 || $[9] !== t6 || $[10] !== text ? (t7 = /* @__PURE__ */ jsx(Button, { iconRight: t5, onClick: t6, mode: "bleed", size: "default", text }), $[8] = t5, $[9] = t6, $[10] = text, $[11] = t7) : t7 = $[11], t7;
}, TableHeaderSearch = (t0) => {
const $ = c(16), {
headerProps,
searchDisabled,
placeholder
} = t0, {
t
} = useTranslation(), {
setSearchTerm,
searchTerm
} = useTableContext();
let t1;
$[0] !== placeholder || $[1] !== t ? (t1 = placeholder || t("search.placeholder"), $[0] = placeholder, $[1] = t, $[2] = t1) : t1 = $[2];
const t2 = searchTerm || "";
let t3, t4;
$[3] !== setSearchTerm ? (t3 = (event) => setSearchTerm(event.currentTarget.value), t4 = () => setSearchTerm(""), $[3] = setSearchTerm, $[4] = t3, $[5] = t4) : (t3 = $[4], t4 = $[5]);
const t5 = !!searchTerm;
let t6;
$[6] !== searchDisabled || $[7] !== t1 || $[8] !== t2 || $[9] !== t3 || $[10] !== t4 || $[11] !== t5 ? (t6 = /* @__PURE__ */ jsx(TextInput, { border: !1, fontSize: 1, icon: SearchIcon, placeholder: t1, radius: 3, value: t2, disabled: searchDisabled, onChange: t3, onClear: t4, clearButton: t5 }), $[6] = searchDisabled, $[7] = t1, $[8] = t2, $[9] = t3, $[10] = t4, $[11] = t5, $[12] = t6) : t6 = $[12];
let t7;
return $[13] !== headerProps || $[14] !== t6 ? (t7 = /* @__PURE__ */ jsx(Stack, { ...headerProps, flex: 1, paddingY: 2, paddingRight: 3, sizing: "border", children: t6 }), $[13] = headerProps, $[14] = t6, $[15] = t7) : t7 = $[15], t7;
}, STICKY_HEADER_STYLE = {
position: "sticky",
top: 0,
zIndex: 1
}, TableHeader = (t0) => {
const $ = c(8), {
headers,
searchDisabled
} = t0;
let t1;
$[0] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (t1 = {
paddingInline: `max(
calc((100% - var(--maxInlineSize)) / 2),
var(--paddingInline)
)`
}, $[0] = t1) : t1 = $[0];
let t2;
if ($[1] !== headers || $[2] !== searchDisabled) {
let t32;
$[4] !== searchDisabled ? (t32 = (t4) => {
const {
header: Header,
style,
width,
id,
sorting
} = t4;
return !!Header && /* @__PURE__ */ jsx(Header, { headerProps: {
as: "th",
id: String(id),
style: {
...style,
width: width || void 0
}
}, header: {
id,
sorting
}, searchDisabled }, String(id));
}, $[4] = searchDisabled, $[5] = t32) : t32 = $[5], t2 = headers.map(t32), $[1] = headers, $[2] = searchDisabled, $[3] = t2;
} else
t2 = $[3];
let t3;
return $[6] !== t2 ? (t3 = /* @__PURE__ */ jsx(Card, { as: "thead", borderBottom: !0, style: STICKY_HEADER_STYLE, children: /* @__PURE__ */ jsx(Flex, { as: "tr", style: t1, children: t2 }) }), $[6] = t2, $[7] = t3) : t3 = $[7], t3;
}, Headers = {
SortHeaderButton,
TableHeaderSearch,
BasicHeader
}, emptyTableStyle = {
width: "100%",
height: "100%",
display: "grid",
gridTemplateRows: "auto 1fr"
}, defaultTableStyle = {
width: "100%"
}, TableLayout = (t0) => {
const $ = c(11), {
isEmptyState,
header,
content,
contentHeight
} = t0;
let t1;
$[0] !== contentHeight || $[1] !== isEmptyState ? (t1 = isEmptyState ? {
display: "block",
height: "100%",
position: "relative",
overflow: "hidden"
} : {
display: "block",
height: contentHeight,
position: "relative"
}, $[0] = contentHeight, $[1] = isEmptyState, $[2] = t1) : t1 = $[2];
const tbodyStyle = t1;
let t2;
$[3] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (t2 = {
height: "100%"
}, $[3] = t2) : t2 = $[3];
const t3 = isEmptyState ? emptyTableStyle : defaultTableStyle;
let t4;
$[4] !== content || $[5] !== tbodyStyle ? (t4 = /* @__PURE__ */ jsx("tbody", { style: tbodyStyle, children: content }), $[4] = content, $[5] = tbodyStyle, $[6] = t4) : t4 = $[6];
let t5;
return $[7] !== header || $[8] !== t3 || $[9] !== t4 ? (t5 = /* @__PURE__ */ jsx("div", { style: t2, children: /* @__PURE__ */ jsxs("table", { style: t3, children: [
header,
t4
] }) }), $[7] = header, $[8] = t3, $[9] = t4, $[10] = t5) : t5 = $[10], t5;
}, ITEM_HEIGHT = 59, LOADING_ROW_COUNT = 3, TableInner = ({
columnDefs,
data,
emptyState,
searchFilter,
rowId,
rowActions,
loading = !1,
rowProps = () => ({}),
scrollContainerRef,
hideTableInlinePadding = !1
}) => {
const {
searchTerm,
sort
} = useTableContext(), filteredData = useMemo(() => {
const filteredResult = searchFilter ? searchFilter(data, searchTerm || "") : data;
if (!sort) return filteredResult;
const sortColumn = columnDefs.find((column) => column.id === sort.column);
return [...filteredResult].sort((a, b) => {
let order;
const [aValue, bValue] = [a, b].map((sortValue) => sortColumn?.sortTransform?.(sortValue, sort.direction) ?? get(sortValue, sort.column));
if (typeof aValue == "string" && typeof bValue == "string" && !isValid(aValue) && !isValid(bValue))
order = aValue.toLowerCase().localeCompare(bValue.toLowerCase());
else {
const parseDate = (datum) => sortColumn?.sortTransform && typeof datum == "number" ? datum : typeof datum == "string" ? Date.parse(datum) : 0, [aDate, bDate] = [aValue, bValue].map(parseDate);
order = aDate - bDate;
}
return sort.direction === "asc" ? order : -order;
});
}, [columnDefs, data, searchFilter, searchTerm, sort]), rowVirtualizer = useVirtualizer({
count: filteredData.length,
getScrollElement: () => scrollContainerRef,
estimateSize: () => ITEM_HEIGHT,
overscan: 5
}), rowActionColumnDef = useMemo(() => ({
id: "actions",
sorting: !1,
width: 50,
header: ({
headerProps: {
id
}
}) => /* @__PURE__ */ jsx(Flex, { as: "th", id, paddingY: 3, paddingX: 3, sizing: "border", style: {
width: "50px"
}, children: /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, weight: "medium", children: "\xA0" }) }),
cell: ({
datum: datum_0,
cellProps: {
id: id_0
}
}) => /* @__PURE__ */ jsx(Flex, { as: "td", id: id_0, align: "center", flex: "none", padding: 3, style: {
width: "25px"
}, children: !datum_0.isLoading && rowActions?.({
datum: datum_0
}) || /* @__PURE__ */ jsx(Box, { style: {
width: "25px"
} }) })
}), [rowActions]), amalgamatedColumnDefs = useMemo(() => (rowActions ? [...columnDefs, rowActionColumnDef] : columnDefs).filter((column_0) => !column_0.hidden), [columnDefs, rowActionColumnDef, rowActions]), tableMinWidth = useMemo(() => amalgamatedColumnDefs.reduce((sum, col) => sum + (col.width || 200), 0), [amalgamatedColumnDefs]), renderRow = useMemo(() => function(datum_1) {
const cardRowProps = rowProps(datum_1), cardKey = loading ? `skeleton-${datum_1.index}` : String(get(datum_1, rowId));
return /* @__PURE__ */ jsx(Card, { "data-testid": loading ? "table-row-skeleton" : "table-row", borderBottom: !0, display: "flex", "data-index": datum_1.index, as: "tr", style: {
height: `${datum_1.virtualRow.size}px`,
position: "absolute",
top: 0,
left: 0,
right: 0,
transform: `translateY(${datum_1.virtualRow.start}px)`,
paddingInline: `max(
calc((100% - var(--maxInlineSize)) / 2),
var(--paddingInline)
)`
}, ...cardRowProps, children: amalgamatedColumnDefs.map(({
cell: Cell,
style,
width,
id: id_1,
sorting = !1
}) => /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(Cell, { datum: {
...datum_1,
isLoading: loading
}, cellProps: {
as: "td",
id: String(id_1),
style: {
...style,
width: width || void 0
}
}, sorting }) }, String(id_1))) }, cardKey);
}, [amalgamatedColumnDefs, loading, rowId, rowProps]), emptyContent = useMemo(() => /* @__PURE__ */ jsx(TableEmptyState, { emptyState, colSpan: amalgamatedColumnDefs.length }), [amalgamatedColumnDefs.length, emptyState]), headers = useMemo(() => amalgamatedColumnDefs.map(({
cell,
sortTransform,
...header
}) => ({
...header,
id: String(header.id)
})), [amalgamatedColumnDefs]), theme = useTheme(), maxInlineSize = !hideTableInlinePadding && theme.sanity.v2?.container[3] || 0, renderLoadingRows = (rowRenderer) => Array.from({
length: LOADING_ROW_COUNT
}).map((_el, index) => {
const cardKey_0 = `skeleton-${index}`, virtualRow = {
index,
start: index * ITEM_HEIGHT,
size: ITEM_HEIGHT,
lane: 0,
key: cardKey_0,
end: index * ITEM_HEIGHT + ITEM_HEIGHT
};
return rowRenderer({
_id: cardKey_0,
isLoading: !0,
virtualRow,
index,
isFirst: index === 0,
isLast: index === LOADING_ROW_COUNT - 1
});
}), tableContent = () => loading ? renderLoadingRows(renderRow) : filteredData.length === 0 ? emptyContent : rowVirtualizer.getVirtualItems().map((virtualRow_0, index_0) => {
const datum_2 = filteredData[virtualRow_0.index];
return renderRow({
...datum_2,
virtualRow: virtualRow_0,
index: index_0,
isFirst: virtualRow_0.index === 0,
isLast: virtualRow_0.index === filteredData.length - 1
});
});
return /* @__PURE__ */ jsx("div", { style: {
height: "100%"
}, children: /* @__PURE__ */ jsx("div", { style: {
width: "100%",
minWidth: `${tableMinWidth}px`,
height: "100%",
position: "relative",
"--maxInlineSize": rem(maxInlineSize),
"--paddingInline": rem(theme.sanity.v2?.space[3] ?? 0)
}, children: /* @__PURE__ */ jsx(TableLayout, { isEmptyState: filteredData.length === 0 && !loading, header: /* @__PURE__ */ jsx(TableHeader, { headers, searchDisabled: loading || !searchTerm && !data.length }), content: tableContent(), contentHeight: `${rowVirtualizer.getTotalSize()}px` }) }) });
}, Table = (t0) => {
const $ = c(8);
let defaultSort, props;
$[0] !== t0 ? ({
defaultSort,
...props
} = t0, $[0] = t0, $[1] = defaultSort, $[2] = props) : (defaultSort = $[1], props = $[2]);
let t1;
$[3] !== props ? (t1 = /* @__PURE__ */ jsx(TableInner, { ...props }), $[3] = props, $[4] = t1) : t1 = $[4];
let t2;
return $[5] !== defaultSort || $[6] !== t1 ? (t2 = /* @__PURE__ */ jsx(TooltipDelayGroupProvider, { children: /* @__PURE__ */ jsx(TableProvider, { defaultSort, children: t1 }) }), $[5] = defaultSort, $[6] = t1, $[7] = t2) : t2 = $[7], t2;
};
export {
Headers,
Table
};
//# sourceMappingURL=Table.js.map