@etsoo/materialui
Version:
TypeScript Material-UI Implementation
161 lines (160 loc) • 5.79 kB
JavaScript
import { jsx as _jsx } from "react/jsx-runtime";
import { css } from "@emotion/css";
import { ScrollerList } from "@etsoo/react";
import { Utils } from "@etsoo/shared";
import React from "react";
import { MUGlobal } from "./MUGlobal";
import { useTheme } from "@mui/material/styles";
// Scroll bar size
const scrollbarSize = 16;
// Selected class name
const selectedClassName = "ScrollerListEx-Selected";
const createGridStyle = (alternatingColors, selectedColor) => {
return css({
"& .ScrollerListEx-Selected": {
backgroundColor: selectedColor
},
"& .ScrollerListEx-Row0:not(.ScrollerListEx-Selected)": {
backgroundColor: alternatingColors[0]
},
"& .ScrollerListEx-Row1:not(.ScrollerListEx-Selected)": {
backgroundColor: alternatingColors[1]
},
"@media (min-width: 800px)": {
"::-webkit-scrollbar": {
width: scrollbarSize,
height: scrollbarSize,
backgroundColor: "#f6f6f6"
},
"::-webkit-scrollbar-thumb": {
backgroundColor: "rgba(0,0,0,0.4)",
borderRadius: "2px"
},
"::-webkit-scrollbar-track-piece:start": {
background: "transparent"
},
"::-webkit-scrollbar-track-piece:end": {
background: "transparent"
}
}
});
};
// Default margin
// horizon: null means full horizontal margin, -1 means all half, >=0 means left/right
const defaultMargin = (margin, horizon) => {
const half = MUGlobal.half(margin);
if (horizon == null) {
const half = MUGlobal.half(margin);
return {
marginLeft: margin,
marginRight: margin,
marginTop: half,
marginBottom: half
};
}
if ((typeof horizon === "number" && horizon >= 0) ||
(typeof horizon === "string" && /^-?\d+/.test(horizon))) {
return {
marginLeft: horizon,
marginRight: horizon,
marginTop: half,
marginBottom: half
};
}
return {
marginLeft: half,
marginRight: half,
marginTop: half,
marginBottom: half
};
};
// Default itemRenderer
function defaultItemRenderer({ index, innerItemRenderer, data, onMouseDown, selected, style, itemHeight, onClick, onDoubleClick, space, margins }) {
// Child
const child = innerItemRenderer({
index,
data,
style,
selected,
itemHeight,
space,
margins
});
let rowClass = `ScrollerListEx-Row${index % 2}`;
if (selected)
rowClass += ` ${selectedClassName}`;
// Layout
return (_jsx("div", { className: rowClass, style: style, onMouseDown: (event) => onMouseDown(event.currentTarget, data), onClick: (event) => onClick && onClick(event, data), onDoubleClick: (event) => onDoubleClick && onDoubleClick(event, data), children: child }));
}
/**
* Extended ScrollerList
* @param props Props
* @returns Component
*/
export function ScrollerListEx(props) {
// Selected item ref
const selectedItem = React.useRef();
const onMouseDown = (div, data) => {
// Destruct
const [selectedDiv, selectedData] = selectedItem.current ?? [];
if (selectedData != null && selectedData[idField] === data[idField])
return;
selectedDiv?.classList.remove(selectedClassName);
div.classList.add(selectedClassName);
selectedItem.current = [div, data];
if (onSelectChange)
onSelectChange([data]);
};
const isSelected = (data) => {
const [_, selectedData] = selectedItem.current ?? [];
const selected = selectedData && data && selectedData[idField] === data[idField]
? true
: false;
return selected;
};
// Destruct
const { alternatingColors = [undefined, undefined], className, idField = "id", innerItemRenderer, itemSize, itemRenderer = (itemProps) => {
const [itemHeight, space, margins] = calculateItemSize(itemProps.index);
return defaultItemRenderer({
itemHeight,
innerItemRenderer,
onMouseDown,
onClick,
onDoubleClick,
space,
margins,
selected: isSelected(itemProps.data),
...itemProps
});
}, onClick, onDoubleClick, onSelectChange, selectedColor = "#edf4fb", ...rest } = props;
// Theme
const theme = useTheme();
// Cache calculation
const itemSizeResult = React.useMemo(() => {
if (typeof itemSize === "function")
return undefined;
const [size, spaces, h] = itemSize;
if (typeof spaces === "number")
return [size, spaces, defaultMargin(MUGlobal.pagePaddings, undefined)];
return [size, MUGlobal.getSpace(spaces, theme), defaultMargin(spaces, h)];
}, [itemSize]);
// Calculate size
const calculateItemSize = (index) => {
// Callback function
if (typeof itemSize === "function") {
const result = itemSize(index);
if (result.length == 2)
return [...result, defaultMargin(MUGlobal.pagePaddings)];
return result;
}
// Calculation
return itemSizeResult;
};
// Local item size
const itemSizeLocal = (index) => {
const [size, space] = calculateItemSize(index);
return size + space;
};
// Layout
return (_jsx(ScrollerList, { className: Utils.mergeClasses("ScrollerListEx-Body", className, createGridStyle(alternatingColors, selectedColor)), idField: idField, itemRenderer: itemRenderer, itemSize: itemSizeLocal, ...rest }));
}