UNPKG

@mui/x-data-grid-premium

Version:

The Premium plan edition of the MUI X Data Grid Components.

345 lines (344 loc) 11.1 kB
'use client'; import _extends from "@babel/runtime/helpers/esm/extends"; import * as React from 'react'; import { styled } from '@mui/material/styles'; import { getDataGridUtilityClass, gridClasses, GridMenu, useGridSelector } from '@mui/x-data-grid-pro'; import composeClasses from '@mui/utils/composeClasses'; import { GridColumnSortButton, NotRendered, vars } from '@mui/x-data-grid-pro/internals'; import useId from '@mui/utils/useId'; import { useGridRootProps } from "../../hooks/utils/useGridRootProps.js"; import { getAggregationFunctionLabel, getAvailableAggregationFunctions } from "../../hooks/features/aggregation/gridAggregationUtils.js"; import { GridPivotPanelFieldMenu } from "./GridPivotPanelFieldMenu.js"; import { useGridApiContext } from "../../hooks/utils/useGridApiContext.js"; import { gridPivotInitialColumnsSelector } from "../../hooks/features/pivoting/gridPivotingSelectors.js"; import { useGridPrivateApiContext } from "../../hooks/utils/useGridPrivateApiContext.js"; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; const useUtilityClasses = ownerState => { const { classes, modelKey } = ownerState; const sorted = modelKey === 'columns' && ownerState.modelValue.sort; const slots = { root: ['pivotPanelField', sorted && 'pivotPanelField--sorted'], name: ['pivotPanelFieldName'], actionContainer: ['pivotPanelFieldActionContainer'], dragIcon: ['pivotPanelFieldDragIcon'], checkbox: ['pivotPanelFieldCheckbox'] }; return composeClasses(slots, getDataGridUtilityClass, classes); }; const GridPivotPanelFieldRoot = styled('div', { name: 'MuiDataGrid', slot: 'PivotPanelField', overridesResolver: (props, styles) => [{ [`&.${gridClasses['pivotPanelField--sorted']}`]: styles['pivotPanelField--sorted'] }, styles.pivotPanelField] })({ flexShrink: 0, position: 'relative', padding: vars.spacing(0, 1, 0, 2), height: 32, display: 'flex', alignItems: 'center', gap: vars.spacing(0.5), borderWidth: 0, borderTopWidth: 2, borderBottomWidth: 2, borderStyle: 'solid', borderColor: 'transparent', margin: '-1px 0', // collapse vertical borders cursor: 'grab', variants: [{ props: { dropPosition: 'top' }, style: { borderTopColor: vars.colors.interactive.selected } }, { props: { dropPosition: 'bottom' }, style: { borderBottomColor: vars.colors.interactive.selected } }, { props: { section: null }, style: { borderTopColor: 'transparent', borderBottomColor: 'transparent' } }], '&:hover': { backgroundColor: vars.colors.interactive.hover } }); const GridPivotPanelFieldName = styled('span', { name: 'MuiDataGrid', slot: 'PivotPanelFieldName' })({ flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }); const GridPivotPanelFieldActionContainer = styled('div', { name: 'MuiDataGrid', slot: 'PivotPanelFieldActionContainer' })({ display: 'flex', alignItems: 'center' }); const GridPivotPanelFieldDragIcon = styled('div', { name: 'MuiDataGrid', slot: 'PivotPanelFieldDragIcon' })({ position: 'absolute', left: -1, width: 16, display: 'flex', justifyContent: 'center', color: vars.colors.foreground.base, opacity: 0, '[draggable="true"]:hover > &': { opacity: 0.3 } }); const GridPivotPanelFieldCheckbox = styled(NotRendered, { name: 'MuiDataGrid', slot: 'PivotPanelFieldCheckbox' })({ flex: 1, position: 'relative', margin: vars.spacing(0, 0, 0, -1), cursor: 'grab' }); function AggregationSelect({ aggFunc, field }) { const rootProps = useGridRootProps(); const [aggregationMenuOpen, setAggregationMenuOpen] = React.useState(false); const aggregationMenuTriggerRef = React.useRef(null); const aggregationMenuTriggerId = useId(); const aggregationMenuId = useId(); const apiRef = useGridApiContext(); const initialColumns = useGridSelector(apiRef, gridPivotInitialColumnsSelector); const colDef = initialColumns.get(field); const availableAggregationFunctions = React.useMemo(() => getAvailableAggregationFunctions({ aggregationFunctions: rootProps.aggregationFunctions, colDef, isDataSource: !!rootProps.dataSource }), [colDef, rootProps.aggregationFunctions, rootProps.dataSource]); const handleClick = func => { apiRef.current.setPivotModel(prev => { return _extends({}, prev, { values: prev.values.map(col => { if (col.field === field) { return _extends({}, col, { aggFunc: func }); } return col; }) }); }); setAggregationMenuOpen(false); }; return availableAggregationFunctions.length > 0 ? /*#__PURE__*/_jsxs(React.Fragment, { children: [/*#__PURE__*/_jsx(rootProps.slots.baseChip, { label: getAggregationFunctionLabel({ apiRef, aggregationRule: { aggregationFunctionName: aggFunc, aggregationFunction: rootProps.aggregationFunctions[aggFunc] } }), size: "small", variant: "outlined", ref: aggregationMenuTriggerRef, id: aggregationMenuTriggerId, "aria-haspopup": "true", "aria-controls": aggregationMenuOpen ? aggregationMenuId : undefined, "aria-expanded": aggregationMenuOpen ? 'true' : undefined, onClick: () => setAggregationMenuOpen(!aggregationMenuOpen) }), /*#__PURE__*/_jsx(GridMenu, { open: aggregationMenuOpen, onClose: () => setAggregationMenuOpen(false), target: aggregationMenuTriggerRef.current, position: "bottom-start", children: /*#__PURE__*/_jsx(rootProps.slots.baseMenuList, _extends({ id: aggregationMenuId, "aria-labelledby": aggregationMenuTriggerId, autoFocusItem: true }, rootProps.slotProps?.baseMenuList, { children: availableAggregationFunctions.map(func => /*#__PURE__*/_jsx(rootProps.slots.baseMenuItem, _extends({ selected: aggFunc === func, onClick: () => handleClick(func) }, rootProps.slotProps?.baseMenuItem, { children: getAggregationFunctionLabel({ apiRef, aggregationRule: { aggregationFunctionName: func, aggregationFunction: rootProps.aggregationFunctions[func] } }) }), func)) })) })] }) : null; } function GridPivotPanelField(props) { const { children, field, onDragStart, onDragEnd } = props; const rootProps = useGridRootProps(); const [dropPosition, setDropPosition] = React.useState(null); const section = props.modelKey; const ownerState = _extends({}, props, { classes: rootProps.classes, dropPosition, section }); const classes = useUtilityClasses(ownerState); const apiRef = useGridPrivateApiContext(); const handleDragStart = React.useCallback(event => { const data = { field, modelKey: section }; event.dataTransfer.setData('text/plain', JSON.stringify(data)); event.dataTransfer.dropEffect = 'move'; onDragStart(section); }, [field, onDragStart, section]); const getDropPosition = React.useCallback(event => { const rect = event.target.getBoundingClientRect(); const y = event.clientY - rect.top; if (y < rect.height / 2) { return 'top'; } return 'bottom'; }, []); const handleDragOver = React.useCallback(event => { if (!event.currentTarget.contains(event.relatedTarget)) { setDropPosition(getDropPosition(event)); } }, [getDropPosition]); const handleDragLeave = React.useCallback(event => { if (!event.currentTarget.contains(event.relatedTarget)) { setDropPosition(null); } }, []); const handleDrop = React.useCallback(event => { setDropPosition(null); if (!event.currentTarget.contains(event.relatedTarget)) { event.preventDefault(); const position = getDropPosition(event); const { field: droppedField, modelKey: originSection } = JSON.parse(event.dataTransfer.getData('text/plain')); apiRef.current.updatePivotModel({ field: droppedField, targetField: field, targetFieldPosition: position, originSection, targetSection: section }); } }, [getDropPosition, apiRef, field, section]); const handleSort = () => { const currentSort = section === 'columns' ? props.modelValue.sort : null; let newValue; if (currentSort === 'asc') { newValue = 'desc'; } else if (currentSort === 'desc') { newValue = undefined; } else { newValue = 'asc'; } apiRef.current.setPivotModel(prev => { return _extends({}, prev, { columns: prev.columns.map(col => { if (col.field === field) { return _extends({}, col, { sort: newValue }); } return col; }) }); }); }; const handleVisibilityChange = event => { if (section) { apiRef.current.setPivotModel(prev => { return _extends({}, prev, { [section]: prev[section].map(col => { if (col.field === field) { return _extends({}, col, { hidden: !event.target.checked }); } return col; }) }); }); } }; const hideable = section !== null; return /*#__PURE__*/_jsxs(GridPivotPanelFieldRoot, { ownerState: ownerState, className: classes.root, onDragOver: handleDragOver, onDragLeave: handleDragLeave, onDrop: handleDrop, onDragStart: handleDragStart, onDragEnd: onDragEnd, draggable: "true", children: [/*#__PURE__*/_jsx(GridPivotPanelFieldDragIcon, { ownerState: ownerState, className: classes.dragIcon, children: /*#__PURE__*/_jsx(rootProps.slots.columnReorderIcon, { fontSize: "small" }) }), hideable ? /*#__PURE__*/_jsx(GridPivotPanelFieldCheckbox, _extends({ ownerState: ownerState, className: classes.checkbox, as: rootProps.slots.baseCheckbox, size: "small", density: "compact" }, rootProps.slotProps?.baseCheckbox, { checked: !props.modelValue.hidden || false, onChange: handleVisibilityChange, label: children })) : /*#__PURE__*/_jsx(GridPivotPanelFieldName, { ownerState: ownerState, className: classes.name, children: children }), /*#__PURE__*/_jsxs(GridPivotPanelFieldActionContainer, { ownerState: ownerState, className: classes.actionContainer, children: [section === 'columns' && /*#__PURE__*/_jsx(GridColumnSortButton, { field: field, direction: props.modelValue.sort, sortingOrder: rootProps.sortingOrder, onClick: handleSort }), section === 'values' && /*#__PURE__*/_jsx(AggregationSelect, { aggFunc: props.modelValue.aggFunc, field: field }), /*#__PURE__*/_jsx(GridPivotPanelFieldMenu, { field: field, modelKey: section })] })] }); } export { GridPivotPanelField };