UNPKG

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
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