@mui/x-data-grid-pro
Version:
The Pro plan edition of the MUI X Data Grid components.
177 lines (172 loc) • 8.05 kB
JavaScript
;
'use client';
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.MultiSelectChipsRoot = exports.GridMultiSelectChips = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
var React = _interopRequireWildcard(require("react"));
var _clsx = _interopRequireDefault(require("clsx"));
var _styles = require("@mui/material/styles");
var _useForkRef = _interopRequireDefault(require("@mui/utils/useForkRef"));
var _useEnhancedEffect = _interopRequireDefault(require("@mui/utils/useEnhancedEffect"));
var _xDataGrid = require("@mui/x-data-grid");
var _internals = require("@mui/x-data-grid/internals");
var _multiSelectCellUtils = require("../../utils/multiSelectCellUtils");
var _useGridPrivateApiContext = require("../../hooks/utils/useGridPrivateApiContext");
var _jsxRuntime = require("react/jsx-runtime");
const _excluded = ["values", "field", "columnWidth", "optionByValue", "getOptionLabel", "autoWrap", "classes", "slotProps"];
const MultiSelectChipsRoot = exports.MultiSelectChipsRoot = (0, _styles.styled)('div', {
name: 'MuiDataGrid',
slot: 'MultiSelectChips',
shouldForwardProp: prop => prop !== 'ownerState'
})({
display: 'flex',
alignItems: 'center',
width: '100%',
height: '100%',
gap: 4,
overflow: 'hidden',
position: 'relative'
});
const Chip = (0, _styles.styled)(_internals.NotRendered, {
name: 'MuiDataGrid',
slot: 'MultiSelectChip'
})({
[`&.${_xDataGrid.gridClasses['multiSelectCellChip--hidden']}`]: {
display: 'none'
}
});
// Delay before revealing all chips on resize start, so a quick double-click (autosize) — which
// toggles the resizing state in short bursts — doesn't flash every chip.
const RESIZE_REVEAL_DELAY_MS = 150;
function GridMultiSelectChipsImpl(props, ref) {
const {
values,
field,
columnWidth,
optionByValue,
getOptionLabel,
autoWrap,
classes,
slotProps
} = props,
other = (0, _objectWithoutPropertiesLoose2.default)(props, _excluded);
const rootProps = (0, _xDataGrid.useGridRootProps)();
const privateApiRef = (0, _useGridPrivateApiContext.useGridPrivateApiContext)();
const ownerState = rootProps;
const containerRef = React.useRef(null);
const handleRef = (0, _useForkRef.default)(containerRef, ref);
const chipsRef = React.useRef(new Map());
const chipWidthsRef = React.useRef(new Map());
const [measuredCount, setMeasuredCount] = React.useState(0);
const [containerWidth, setContainerWidth] = React.useState(null);
const subscribeMetrics = React.useCallback(notify => {
const cache = privateApiRef.current.caches.multiSelect;
if (!cache) {
return () => {};
}
return cache.subscribeOverflowMetrics(notify);
}, [privateApiRef]);
const getMetricsSnapshot = React.useCallback(() => privateApiRef.current.caches.multiSelect?.getOverflowMetrics() ?? null, [privateApiRef]);
const overflowMetrics = (0, _internals.useSyncExternalStore)(subscribeMetrics, getMetricsSnapshot, getMetricsSnapshot);
const arrayKey = React.useMemo(() => values.join('\0'), [values]);
const [prevArrayKey, setPrevArrayKey] = React.useState(arrayKey);
if (!autoWrap && prevArrayKey !== arrayKey) {
setPrevArrayKey(arrayKey);
chipWidthsRef.current.clear();
setMeasuredCount(0);
setContainerWidth(null);
}
// Re-measure on committed column width changes (incl. when a resize finishes); we don't
// track live drag, matching how other cells reflow only once the resize is committed.
(0, _useEnhancedEffect.default)(() => {
if (autoWrap || !containerRef.current) {
return;
}
setContainerWidth(containerRef.current.getBoundingClientRect().width);
}, [columnWidth, autoWrap]);
// Measure chip and container widths after render. `getBoundingClientRect` is sub-pixel,
// which keeps the chip-fit math aligned with the browser's actual layout.
(0, _useEnhancedEffect.default)(() => {
if (autoWrap) {
return;
}
if (containerWidth === null && containerRef.current) {
setContainerWidth(containerRef.current.getBoundingClientRect().width);
}
let newMeasurements = 0;
chipsRef.current.forEach((chipEl, index) => {
if (chipEl && !chipWidthsRef.current.has(index)) {
chipWidthsRef.current.set(index, chipEl.getBoundingClientRect().width);
newMeasurements += 1;
}
});
if (newMeasurements > 0) {
setMeasuredCount(chipWidthsRef.current.size);
}
}, [containerWidth, autoWrap]);
const overflowWidths = overflowMetrics?.overflowChipWidths ?? _multiSelectCellUtils.DEFAULT_OVERFLOW_CHIP_WIDTHS;
const gap = overflowMetrics?.gap ?? _multiSelectCellUtils.DEFAULT_GAP;
// While this column is being drag-resized, render every chip and let the cell clip them.
// The `+N` overflow is recomputed once the resize is committed (see the `columnWidth` effect).
const isResizingThisColumn = (0, _xDataGrid.useGridSelector)(privateApiRef, _xDataGrid.gridResizingColumnFieldSelector) === field;
// Debounce the reveal so a quick double-click to autosize doesn't flash all chips.
const revealTimeout = (0, _internals.useTimeout)();
const [revealWhileResizing, setRevealWhileResizing] = React.useState(false);
React.useEffect(() => {
if (!isResizingThisColumn) {
revealTimeout.clear();
setRevealWhileResizing(false);
return;
}
revealTimeout.start(RESIZE_REVEAL_DELAY_MS, () => setRevealWhileResizing(true));
}, [isResizingThisColumn, revealTimeout]);
const visibleCount = React.useMemo(() => {
if (autoWrap || revealWhileResizing || values.length === 0) {
return values.length;
}
if (containerWidth === null || containerWidth === 0 || measuredCount < values.length) {
return values.length;
}
return (0, _multiSelectCellUtils.calculateVisibleCount)(values.length, containerWidth, chipWidthsRef.current, overflowWidths, gap);
}, [values.length, measuredCount, containerWidth, autoWrap, revealWhileResizing, overflowWidths, gap]);
const hiddenCount = values.length - visibleCount;
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(MultiSelectChipsRoot, (0, _extends2.default)({
ref: handleRef,
ownerState: ownerState
}, other, slotProps?.root, {
className: (0, _clsx.default)(classes?.root, other?.className, slotProps?.root?.className),
children: [values.map((v, index) => {
const option = optionByValue.get(v) ?? v;
const chipProps = typeof slotProps?.chip === 'function' ? slotProps.chip(option, index) : slotProps?.chip;
return /*#__PURE__*/(0, _jsxRuntime.jsx)(Chip, (0, _extends2.default)({
as: rootProps.slots.baseChip,
ownerState: ownerState,
ref: el => {
if (el) {
chipsRef.current.set(index, el);
} else {
chipsRef.current.delete(index);
}
},
label: getOptionLabel(option),
size: "small",
variant: "outlined"
}, chipProps, {
className: (0, _clsx.default)(classes?.chip, chipProps?.className, index >= visibleCount && [_xDataGrid.gridClasses['multiSelectCellChip--hidden'], classes?.chipHidden])
}), index);
}), hiddenCount > 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)(rootProps.slots.baseChip, (0, _extends2.default)({
label: `+${hiddenCount}`,
size: "small",
variant: "outlined"
}, slotProps?.overflow, {
className: (0, _clsx.default)(classes?.overflow, slotProps?.overflow?.className)
}))]
}));
}
const GridMultiSelectChips = exports.GridMultiSelectChips = /*#__PURE__*/React.forwardRef(GridMultiSelectChipsImpl);
if (process.env.NODE_ENV !== "production") GridMultiSelectChips.displayName = "GridMultiSelectChips";