@mui/x-data-grid
Version:
The community edition of the data grid component (MUI X).
304 lines (250 loc) • 10.7 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.renderActionsCell = exports.GridActionsCell = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
var React = _interopRequireWildcard(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _IconButton = _interopRequireDefault(require("@mui/material/IconButton"));
var _MenuList = _interopRequireDefault(require("@mui/material/MenuList"));
var _utils = require("@mui/material/utils");
var _gridClasses = require("../../constants/gridClasses");
var _GridMenu = require("../menu/GridMenu");
var _useGridRootProps = require("../../hooks/utils/useGridRootProps");
var _useGridApiContext = require("../../hooks/utils/useGridApiContext");
var _jsxRuntime = require("react/jsx-runtime");
const _excluded = ["colDef", "id", "api", "hasFocus", "isEditable", "field", "value", "formattedValue", "row", "rowNode", "cellMode", "getValue", "tabIndex", "position", "focusElementRef"];
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
const hasActions = colDef => typeof colDef.getActions === 'function';
const GridActionsCell = props => {
const {
colDef,
id,
hasFocus,
tabIndex,
position = 'bottom-end',
focusElementRef
} = props,
other = (0, _objectWithoutPropertiesLoose2.default)(props, _excluded);
const [focusedButtonIndex, setFocusedButtonIndex] = React.useState(-1);
const [open, setOpen] = React.useState(false);
const apiRef = (0, _useGridApiContext.useGridApiContext)();
const rootRef = React.useRef(null);
const buttonRef = React.useRef(null);
const ignoreCallToFocus = React.useRef(false);
const touchRippleRefs = React.useRef({});
const menuId = (0, _utils.unstable_useId)();
const buttonId = (0, _utils.unstable_useId)();
const rootProps = (0, _useGridRootProps.useGridRootProps)();
React.useLayoutEffect(() => {
if (!hasFocus) {
Object.entries(touchRippleRefs.current).forEach(([index, ref]) => {
ref == null ? void 0 : ref.stop({}, () => {
delete touchRippleRefs.current[index];
});
});
}
}, [hasFocus]);
React.useEffect(() => {
if (focusedButtonIndex < 0 || !rootRef.current) {
return;
}
if (focusedButtonIndex >= rootRef.current.children.length) {
return;
}
const child = rootRef.current.children[focusedButtonIndex];
child.focus();
}, [focusedButtonIndex]);
React.useEffect(() => {
if (!hasFocus) {
setFocusedButtonIndex(-1);
ignoreCallToFocus.current = false;
}
}, [hasFocus]);
React.useImperativeHandle(focusElementRef, () => ({
focus() {
// If ignoreCallToFocus is true, then one of the buttons was clicked and the focus is already set
if (!ignoreCallToFocus.current) {
setFocusedButtonIndex(0);
}
}
}), []);
if (!hasActions(colDef)) {
throw new Error('MUI: Missing the `getActions` property in the `GridColDef`.');
}
const options = colDef.getActions(apiRef.current.getRowParams(id));
const iconButtons = options.filter(option => !option.props.showInMenu);
const menuButtons = options.filter(option => option.props.showInMenu);
const numberOfButtons = iconButtons.length + (menuButtons.length ? 1 : 0);
React.useEffect(() => {
if (focusedButtonIndex >= numberOfButtons) {
setFocusedButtonIndex(numberOfButtons - 1);
}
}, [focusedButtonIndex, numberOfButtons]);
const showMenu = () => {
setOpen(true);
setFocusedButtonIndex(numberOfButtons - 1);
ignoreCallToFocus.current = true;
};
const hideMenu = () => {
setOpen(false);
};
const handleTouchRippleRef = index => instance => {
touchRippleRefs.current[index] = instance;
};
const handleButtonClick = (index, onClick) => event => {
setFocusedButtonIndex(index);
ignoreCallToFocus.current = true;
if (onClick) {
onClick(event);
}
};
const handleRootKeyDown = event => {
if (numberOfButtons <= 1) {
return;
}
let newIndex = focusedButtonIndex;
if (event.key === 'ArrowRight') {
newIndex += 1;
} else if (event.key === 'ArrowLeft') {
newIndex -= 1;
}
if (newIndex < 0 || newIndex >= numberOfButtons) {
return; // We're already in the first or last item = do nothing and let the grid listen the event
}
if (newIndex !== focusedButtonIndex) {
event.preventDefault(); // Prevent scrolling
event.stopPropagation(); // Don't stop propagation for other keys, e.g. ArrowUp
setFocusedButtonIndex(newIndex);
}
};
const handleListKeyDown = event => {
if (event.key === 'Tab') {
event.preventDefault();
}
if (['Tab', 'Enter', 'Escape'].includes(event.key)) {
hideMenu();
}
};
return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", (0, _extends2.default)({
role: "menu",
ref: rootRef,
tabIndex: -1,
className: _gridClasses.gridClasses.actionsCell,
onKeyDown: handleRootKeyDown
}, other, {
children: [iconButtons.map((button, index) => /*#__PURE__*/React.cloneElement(button, {
key: index,
touchRippleRef: handleTouchRippleRef(index),
onClick: handleButtonClick(index, button.props.onClick),
tabIndex: focusedButtonIndex === index ? tabIndex : -1
})), menuButtons.length > 0 && buttonId && /*#__PURE__*/(0, _jsxRuntime.jsx)(_IconButton.default, {
ref: buttonRef,
id: buttonId,
"aria-label": apiRef.current.getLocaleText('actionsCellMore'),
"aria-controls": menuId,
"aria-expanded": open ? 'true' : undefined,
"aria-haspopup": "true",
role: "menuitem",
size: "small",
onClick: showMenu,
touchRippleRef: handleTouchRippleRef(buttonId),
tabIndex: focusedButtonIndex === iconButtons.length ? tabIndex : -1,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(rootProps.components.MoreActionsIcon, {
fontSize: "small"
})
}), menuButtons.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_GridMenu.GridMenu, {
onClickAway: hideMenu,
onClick: hideMenu,
open: open,
target: buttonRef.current,
position: position,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_MenuList.default, {
id: menuId,
className: _gridClasses.gridClasses.menuList,
onKeyDown: handleListKeyDown,
"aria-labelledby": buttonId,
variant: "menu",
autoFocusItem: true,
children: menuButtons.map((button, index) => /*#__PURE__*/React.cloneElement(button, {
key: index
}))
})
})]
}));
};
exports.GridActionsCell = GridActionsCell;
process.env.NODE_ENV !== "production" ? GridActionsCell.propTypes = {
// ----------------------------- Warning --------------------------------
// | These PropTypes are generated from the TypeScript type definitions |
// | To update them edit the TypeScript types and run "yarn proptypes" |
// ----------------------------------------------------------------------
/**
* GridApi that let you manipulate the grid.
* @deprecated Use the `apiRef` returned by `useGridApiContext` or `useGridApiRef` (only available in `@mui/x-data-grid-pro`)
*/
api: _propTypes.default.any.isRequired,
/**
* The mode of the cell.
*/
cellMode: _propTypes.default.oneOf(['edit', 'view']).isRequired,
/**
* The column of the row that the current cell belongs to.
*/
colDef: _propTypes.default.object.isRequired,
/**
* The column field of the cell that triggered the event.
*/
field: _propTypes.default.string.isRequired,
/**
* A ref allowing to set imperative focus.
* It can be passed to the element that should receive focus.
* @ignore - do not document.
*/
focusElementRef: _propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.shape({
current: _propTypes.default.shape({
focus: _propTypes.default.func.isRequired
})
})]),
formattedValue: _propTypes.default.any,
/**
* Get the cell value of a row and field.
* @param {GridRowId} id The row id.
* @param {string} field The field.
* @returns {any} The cell value.
* @deprecated Use `params.row` to directly access the fields you want instead.
*/
getValue: _propTypes.default.func.isRequired,
/**
* If true, the cell is the active element.
*/
hasFocus: _propTypes.default.bool.isRequired,
/**
* The grid row id.
*/
id: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]).isRequired,
/**
* If true, the cell is editable.
*/
isEditable: _propTypes.default.bool,
position: _propTypes.default.oneOf(['bottom-end', 'bottom-start', 'bottom', 'left-end', 'left-start', 'left', 'right-end', 'right-start', 'right', 'top-end', 'top-start', 'top']),
/**
* The row model of the row that the current cell belongs to.
*/
row: _propTypes.default.object.isRequired,
/**
* The node of the row that the current cell belongs to.
*/
rowNode: _propTypes.default.object.isRequired,
/**
* the tabIndex value.
*/
tabIndex: _propTypes.default.oneOf([-1, 0]).isRequired,
value: _propTypes.default.any
} : void 0;
const renderActionsCell = params => /*#__PURE__*/(0, _jsxRuntime.jsx)(GridActionsCell, (0, _extends2.default)({}, params));
exports.renderActionsCell = renderActionsCell;