UNPKG

react-admin-kit

Version:

A react based UI components for admin system

536 lines (509 loc) 25.9 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = exports.TableColumnTypeBaseComponent = exports.TableColumnSelfTypeComponent = exports.TableColumnOriginTypeComponent = exports.TableAlertOptionTypeComponent = exports.MyProTableSelfTypeComponent = exports.MyProTableOriginTypeComponent = exports.InnerRefTypeComponent = exports.FORM_TYPE_LOCALE = exports.EnableDeleteTypeComponent = void 0; var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof")); var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2")); var _regeneratorRuntime2 = _interopRequireDefault(require("@babel/runtime/helpers/regeneratorRuntime")); var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties")); var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _proTable = _interopRequireDefault(require("@ant-design/pro-table")); var _immer = _interopRequireDefault(require("immer")); var _styledComponents = _interopRequireWildcard(require("styled-components")); var _ModalForm = _interopRequireDefault(require("../ModalForm")); var _react = require("react"); var _context2 = require("../SettingProvider/context"); var _omit = _interopRequireDefault(require("omit.js")); var _utils = require("../utils"); var _antd = require("antd"); var _LinkButton = _interopRequireDefault(require("../LinkButton")); var _utils2 = require("./utils"); var _jsxRuntime = require("react/jsx-runtime"); var _excluded = ["rowKey", "name", "onOpen", "defaultHideInSearch", "rakLocale", "noPadding", "options", "rowSelection", "delFunction", "delPermission", "delConfirmType", "delPopconfirmProps", "delModalConfirmProps", "delSuccessProps", "optionColumnSpaceProps", "tableAlertOptionRender", "tableAlertOption", "modalFormProps"], _excluded2 = ["title"]; var FORM_TYPE_LOCALE = exports.FORM_TYPE_LOCALE = { new: 'formTypeNew', edit: 'formTypeEdit', read: 'formTypeRead' }; var TableWrapper = _styledComponents.default.div.withConfig({ shouldForwardProp: function shouldForwardProp(prop) { return !['noPadding'].includes(prop); } }).withConfig({ displayName: "TableWrapper", componentId: "react-admin-kit__sc-1774qxd-0" })(["& .ant-pro-table-alert-container{font-size:14px;}", ""], function (props) { return props.noPadding && (0, _styledComponents.css)(["& .ant-pro-card-body{padding-inline:unset;}"]); }); var ProTable = function ProTable(props) { var _globalLocale$delSucc; var _message$useMessage = _antd.message.useMessage(), _message$useMessage2 = (0, _slicedToArray2.default)(_message$useMessage, 2), messageApi = _message$useMessage2[0], contextHolder = _message$useMessage2[1]; var _Modal$useModal = _antd.Modal.useModal(), _Modal$useModal2 = (0, _slicedToArray2.default)(_Modal$useModal, 2), modal = _Modal$useModal2[0], modalContextHolder = _Modal$useModal2[1]; // ------- state --------- var _useState = (0, _react.useState)('new'), _useState2 = (0, _slicedToArray2.default)(_useState, 2), formType = _useState2[0], setFormType = _useState2[1]; var _useState3 = (0, _react.useState)(false), _useState4 = (0, _slicedToArray2.default)(_useState3, 2), delLoading = _useState4[0], setDelLoading = _useState4[1]; var _useState5 = (0, _react.useState)([]), _useState6 = (0, _slicedToArray2.default)(_useState5, 2), selectedRowKeys = _useState6[0], setSelectedRowKeys = _useState6[1]; var _useState7 = (0, _react.useState)([]), _useState8 = (0, _slicedToArray2.default)(_useState7, 2), selectedRows = _useState8[0], setSelectedRows = _useState8[1]; // ------- ref ----------- var actionRef = (0, _react.useRef)(); var targetId = (0, _react.useRef)(); // 全局默认设置 var globalLocale = (0, _react.useContext)(_context2.LocaleContext); var setting = (0, _react.useContext)(_context2.ProTableContext) || {}; var safeProps = (0, _omit.default)(props, ['request', 'columns', 'formColumns', 'onFinish', 'innerRef', 'actionRef']); var mergedProps = (0, _utils.myMergeOptions)(setting, safeProps || {}, // 默认值放在这里,能合并对象类属性 { toolbar: {}, rakLocale: globalLocale, delSuccessProps: { content: (_globalLocale$delSucc = globalLocale.delSuccessContent) !== null && _globalLocale$delSucc !== void 0 ? _globalLocale$delSucc : '删除成功', type: 'success' }, delPopconfirmProps: {}, delModalConfirmProps: {}, optionColumnSpaceProps: { size: 'small' }, tableAlertOption: { enableDelete: true, spaceProps: { size: 'middle' }, delPopconfirmProps: { okButtonProps: { loading: delLoading } }, delModalConfirmProps: { okButtonProps: { loading: delLoading } } } }); var propsActionRef = props.actionRef, propsInnerRef = props.innerRef, columns = props.columns, formColumns = props.formColumns, request = props.request, onFinish = props.onFinish; var _mergedProps$rowKey = mergedProps.rowKey, rowKey = _mergedProps$rowKey === void 0 ? 'id' : _mergedProps$rowKey, name = mergedProps.name, onOpen = mergedProps.onOpen, _mergedProps$defaultH = mergedProps.defaultHideInSearch, defaultHideInSearch = _mergedProps$defaultH === void 0 ? false : _mergedProps$defaultH, rakLocale = mergedProps.rakLocale, _mergedProps$noPaddin = mergedProps.noPadding, noPadding = _mergedProps$noPaddin === void 0 ? false : _mergedProps$noPaddin, _mergedProps$options = mergedProps.options, options = _mergedProps$options === void 0 ? false : _mergedProps$options, rowSelection = mergedProps.rowSelection, delFunction = mergedProps.delFunction, delPermission = mergedProps.delPermission, _mergedProps$delConfi = mergedProps.delConfirmType, delConfirmType = _mergedProps$delConfi === void 0 ? 'popconfirm' : _mergedProps$delConfi, delPopconfirmProps = mergedProps.delPopconfirmProps, delModalConfirmProps = mergedProps.delModalConfirmProps, delSuccessProps = mergedProps.delSuccessProps, optionColumnSpaceProps = mergedProps.optionColumnSpaceProps, tableAlertOptionRender = mergedProps.tableAlertOptionRender, tableAlertOption = mergedProps.tableAlertOption, _mergedProps$modalFor = mergedProps.modalFormProps, modalFormProps = _mergedProps$modalFor === void 0 ? {} : _mergedProps$modalFor, restTableProps = (0, _objectWithoutProperties2.default)(mergedProps, _excluded); var hasDelPermission = delPermission ? delPermission() : true; var getHeaderTitle = function getHeaderTitle() { var toolbar = mergedProps.toolbar; var _ref = toolbar, title = _ref.title; if (title) return title; if (name) return "".concat(name).concat(rakLocale.tableTitleAfter); return false; }; var getModalTitle = function getModalTitle() { var _mergedProps$name = mergedProps.name, name = _mergedProps$name === void 0 ? '' : _mergedProps$name; var localeKey = FORM_TYPE_LOCALE[formType]; var formTypeStr = rakLocale[localeKey]; return "".concat(formTypeStr).concat(name) || ''; }; var _modalFormProps$title = modalFormProps.title, title = _modalFormProps$title === void 0 ? getModalTitle() : _modalFormProps$title, modalFormRestProps = (0, _objectWithoutProperties2.default)(modalFormProps, _excluded2); // 这是传给 ModalForm 组件的, 所以类型是 ModalForm 的 innerRef 类型 var innerRef = (0, _react.useRef)(); (0, _react.useImperativeHandle)(propsInnerRef, function () { return innerRef.current; }, []); var getActionRef = function getActionRef() { // @ts-ignore return propsActionRef || actionRef; }; var patchRequest = function patchRequest() { if (request) { return function (params, sort, filter) { return new Promise(function (resolve, reject) { request(params, sort, filter).then(function (res) { if (innerRef.current) { innerRef.current.total = res.total; innerRef.current.dataSource = res.data; innerRef.current.params = params; } resolve(res); }).catch(function (err) { return reject(err); }); }); }; } }; var selfOnOpen = /*#__PURE__*/function () { var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/(0, _regeneratorRuntime2.default)().mark(function _callee(formType, formRef, formData) { return (0, _regeneratorRuntime2.default)().wrap(function _callee$(_context) { while (1) switch (_context.prev = _context.next) { case 0: setFormType(formType); if (!onOpen) { _context.next = 4; break; } _context.next = 4; return onOpen(formType, formRef, formData); case 4: case "end": return _context.stop(); } }, _callee); })); return function selfOnOpen(_x, _x2, _x3) { return _ref2.apply(this, arguments); }; }(); var getRecordKey = function getRecordKey(record) { return typeof rowKey === 'function' ? rowKey(record) : record[rowKey]; }; // 分受控和非受控 var getRowSelection = function getRowSelection() { // 如果属性上没有提供 selectedRowKeys 就转成内部受控 if (rowSelection && !rowSelection.selectedRowKeys) { return (0, _objectSpread2.default)((0, _objectSpread2.default)({}, rowSelection), {}, { selectedRowKeys: selectedRowKeys, onChange: function onChange(keys, selectedRows) { setSelectedRowKeys(keys); setSelectedRows(selectedRows); } }); } return rowSelection; }; var handleDelete = function handleDelete(selectedIds, record, callback) { setDelLoading(true); targetId.current = getRecordKey(record); Promise.resolve(delFunction(selectedIds, record)).then(function () { var _getActionRef$current; if (delSuccessProps) { messageApi.open((0, _objectSpread2.default)((0, _objectSpread2.default)({}, delSuccessProps), {}, { content: delSuccessProps.content // 这么做仅仅是为了消除 ts 告警提示 })); } if (callback) callback(); // bugfix: 如果在多选选中后, 点的行上的删除, 而不是点的批量删除, 删除后要去除掉selectedKeys if (getRecordKey(record) && rowSelection) { var ids = (selectedIds || []).filter(function (id) { return id !== getRecordKey(record); }); if (rowSelection.selectedRowKeys) { // @ts-ignore onChange 应有三个参数 if (rowSelection.onChange) rowSelection.onChange(ids); } else { setSelectedRowKeys(ids); } } (_getActionRef$current = getActionRef().current) === null || _getActionRef$current === void 0 || _getActionRef$current.reload(); }).finally(function () { setDelLoading(false); }); }; var getDelDom = function getDelDom(_ref3) { var popconfirmProps = _ref3.popconfirmProps, modalFuncProps = _ref3.modalFuncProps, disabled = _ref3.disabled, danger = _ref3.danger, loading = _ref3.loading, btnText = _ref3.btnText; if (delConfirmType === 'popconfirm') { return /*#__PURE__*/(0, _react.createElement)(_antd.Popconfirm, (0, _objectSpread2.default)((0, _objectSpread2.default)({}, popconfirmProps), {}, { key: "del-dom" }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_LinkButton.default, { disabled: disabled, onClick: function onClick(e) { return e.stopPropagation(); }, loading: loading, danger: danger, children: btnText })); } else { return /*#__PURE__*/(0, _jsxRuntime.jsx)(_LinkButton.default, { disabled: disabled, onClick: function onClick(e) { e.stopPropagation(); modal.confirm(modalFuncProps); }, loading: loading, danger: danger, children: btnText }, "del-dom"); } }; var getTableAlertOptionRender = function getTableAlertOptionRender(option) { var _rakLocale$alertDelPo, _rakLocale$alertDelMo; var delDom = null; var _ref4 = tableAlertOption, enableDelete = _ref4.enableDelete, delPopconfirmProps = _ref4.delPopconfirmProps, delModalConfirmProps = _ref4.delModalConfirmProps, spaceProps = _ref4.spaceProps; var alertEnableDelete = typeof enableDelete === 'function' ? enableDelete(option.selectedRowKeys, option.selectedRows) : enableDelete; var _ref5 = (0, _typeof2.default)(alertEnableDelete) === 'object' ? alertEnableDelete : {}, _ref5$disabled = _ref5.disabled, disabled = _ref5$disabled === void 0 ? false : _ref5$disabled, _ref5$danger = _ref5.danger, danger = _ref5$danger === void 0 ? false : _ref5$danger, _ref5$btnText = _ref5.btnText, btnText = _ref5$btnText === void 0 ? rakLocale === null || rakLocale === void 0 ? void 0 : rakLocale.alertDelBtnText : _ref5$btnText; // 处理 popconfirm title 默认值 var popconfirmTitle = typeof delPopconfirmProps.title === 'function' ? delPopconfirmProps.title(option.selectedRowKeys, option.selectedRows) : delPopconfirmProps.title || (rakLocale === null || rakLocale === void 0 || (_rakLocale$alertDelPo = rakLocale.alertDelPopconfirmTitle) === null || _rakLocale$alertDelPo === void 0 ? void 0 : _rakLocale$alertDelPo.call(rakLocale, option.selectedRowKeys)); // 处理 popconfirm description 默认值 var popconfirmDescription = typeof delPopconfirmProps.description === 'function' ? delPopconfirmProps.description(option.selectedRowKeys, option.selectedRows) : delPopconfirmProps.description; // 处理 modal title 默认值 var modalConfirmTitle = typeof delModalConfirmProps.title === 'function' ? delModalConfirmProps.title(option.selectedRowKeys, option.selectedRows) : delModalConfirmProps.title || (rakLocale === null || rakLocale === void 0 ? void 0 : rakLocale.alertDelModalConfirmTitle); // 处理 modal content 默认值 var modalConfirmContent = typeof delModalConfirmProps.content === 'function' ? delModalConfirmProps.content(option.selectedRowKeys, option.selectedRows) : delModalConfirmProps.content || (rakLocale === null || rakLocale === void 0 || (_rakLocale$alertDelMo = rakLocale.alertDelModalConfirmContent) === null || _rakLocale$alertDelMo === void 0 ? void 0 : _rakLocale$alertDelMo.call(rakLocale, option.selectedRowKeys)); if (delFunction && hasDelPermission && alertEnableDelete) { delDom = getDelDom({ disabled: disabled, danger: danger, btnText: btnText, loading: delLoading, popconfirmProps: (0, _objectSpread2.default)((0, _objectSpread2.default)({}, delPopconfirmProps), {}, { onConfirm: function onConfirm() { var _delPopconfirmProps$o; handleDelete(option.selectedRowKeys, {}, option.onCleanSelected); delPopconfirmProps === null || delPopconfirmProps === void 0 || (_delPopconfirmProps$o = delPopconfirmProps.onConfirm) === null || _delPopconfirmProps$o === void 0 || _delPopconfirmProps$o.call(delPopconfirmProps); }, title: popconfirmTitle, description: popconfirmDescription }), modalFuncProps: (0, _objectSpread2.default)((0, _objectSpread2.default)({}, delModalConfirmProps), {}, { title: modalConfirmTitle, content: modalConfirmContent, onOk: function onOk() { var _delModalConfirmProps; handleDelete(option.selectedRowKeys, {}, option.onCleanSelected); delModalConfirmProps === null || delModalConfirmProps === void 0 || (_delModalConfirmProps = delModalConfirmProps.onOk) === null || _delModalConfirmProps === void 0 || _delModalConfirmProps.call(delModalConfirmProps); } }) }); } var cancelDom = /*#__PURE__*/(0, _jsxRuntime.jsx)(_LinkButton.default, { onClick: option.onCleanSelected, children: option.intl.getMessage('alert.clear', '清空') }); var defaultDom = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_antd.Space, (0, _objectSpread2.default)((0, _objectSpread2.default)({}, spaceProps), {}, { children: [delDom, cancelDom] })); return tableAlertOptionRender ? tableAlertOptionRender(option, { delDom: delDom, cancelDom: cancelDom }) : defaultDom; }; /** * 增加 render 函数 * 1. 给 option 列增加 innerRef * 2. option 列的 renderDom 包裹 Space 组件 * 3. 加入删除节点 */ var patchRender = function patchRender(columns, _ref6) { var innerRef = _ref6.innerRef, spaceProps = _ref6.spaceProps; return (0, _immer.default)(columns, function (cols) { cols.forEach(function (col) { var render = col.render, _col$enableDelete = col.enableDelete, enableDelete = _col$enableDelete === void 0 ? false : _col$enableDelete; // 给 valueType 为 option 列的 render 增加 ref 参数 if (col.valueType === 'option' && render) { col.render = function (text, record, index, action) { var renderDom = render(text, record, index, action, innerRef); // 增加删除节点 var enableDeleteResult = typeof enableDelete === 'function' ? enableDelete(record, index) : enableDelete; if (delFunction && hasDelPermission && enableDeleteResult && Array.isArray(renderDom)) { var _ref7 = (0, _typeof2.default)(enableDeleteResult) === 'object' ? enableDeleteResult : {}, _ref7$disabled = _ref7.disabled, disabled = _ref7$disabled === void 0 ? false : _ref7$disabled, _ref7$danger = _ref7.danger, danger = _ref7$danger === void 0 ? false : _ref7$danger, _ref7$btnText = _ref7.btnText, btnText = _ref7$btnText === void 0 ? rakLocale === null || rakLocale === void 0 ? void 0 : rakLocale.delBtnText : _ref7$btnText, _ref7$btnIndex = _ref7.btnIndex, btnIndex = _ref7$btnIndex === void 0 ? renderDom.length : _ref7$btnIndex; // 处理 popconfirm title 默认值 var popconfirmTitle = typeof delPopconfirmProps.title === 'function' ? delPopconfirmProps.title(record, index) : delPopconfirmProps.title || (rakLocale === null || rakLocale === void 0 ? void 0 : rakLocale.delPopconfirmTitle); // 处理 popconfirm description 默认值 var popconfirmDescription = typeof delPopconfirmProps.description === 'function' ? delPopconfirmProps.description(record, index) : delPopconfirmProps.description; // 处理 modal title 默认值 var modalConfirmTitle = typeof delModalConfirmProps.title === 'function' ? delModalConfirmProps.title(record, index) : delModalConfirmProps.title || (rakLocale === null || rakLocale === void 0 ? void 0 : rakLocale.delModalConfirmTitle); // 处理 modal content 默认值 var modalConfirmContent = typeof delModalConfirmProps.content === 'function' ? delModalConfirmProps.content(record, index) : delModalConfirmProps.content || (rakLocale === null || rakLocale === void 0 ? void 0 : rakLocale.delModalConfirmContent); var delDom = getDelDom({ disabled: disabled, danger: danger, btnText: btnText, loading: delLoading && getRecordKey(record) === targetId.current, popconfirmProps: (0, _objectSpread2.default)((0, _objectSpread2.default)({}, delPopconfirmProps), {}, { onConfirm: function onConfirm() { var _delPopconfirmProps$o2; handleDelete([getRecordKey(record)], record); delPopconfirmProps === null || delPopconfirmProps === void 0 || (_delPopconfirmProps$o2 = delPopconfirmProps.onConfirm) === null || _delPopconfirmProps$o2 === void 0 || _delPopconfirmProps$o2.call(delPopconfirmProps); }, title: popconfirmTitle, description: popconfirmDescription }), modalFuncProps: (0, _objectSpread2.default)((0, _objectSpread2.default)({}, delModalConfirmProps), {}, { title: modalConfirmTitle, content: modalConfirmContent, onOk: function onOk() { var _delModalConfirmProps2; handleDelete([getRecordKey(record)], record); delModalConfirmProps === null || delModalConfirmProps === void 0 || (_delModalConfirmProps2 = delModalConfirmProps.onOk) === null || _delModalConfirmProps2 === void 0 || _delModalConfirmProps2.call(delModalConfirmProps); } }) }); renderDom.splice(btnIndex, 0, delDom); } //数组的话外面包一个 Space 组件 return Array.isArray(renderDom) ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_antd.Space, (0, _objectSpread2.default)((0, _objectSpread2.default)({}, spaceProps), {}, { children: renderDom })) : renderDom; }; } }); }); }; (0, _react.useEffect)(function () { if (innerRef.current) { var exportColumns = (0, _utils2.getAreaFields)(columns, 'export'); // 多语言 var defaultFilename = "".concat(name).concat(rakLocale === null || rakLocale === void 0 ? void 0 : rakLocale.tableTitleAfter) || (rakLocale === null || rakLocale === void 0 ? void 0 : rakLocale.exportFilename); innerRef.current.export = function (rows, ExcelJS) { var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; return (0, _utils2.exportTable)(exportColumns, rows, ExcelJS, (0, _objectSpread2.default)((0, _objectSpread2.default)({}, options), {}, { filename: options.filename || defaultFilename })); }; } }, [columns, name]); (0, _react.useEffect)(function () { var tableReload = function tableReload() { var _getActionRef$current2; (_getActionRef$current2 = getActionRef().current) === null || _getActionRef$current2 === void 0 || _getActionRef$current2.reload(); }; /** 注册一个事件用于 reload 表格; 这对于一些已缓存的页面比较有用, 在其它页面可以控制刷新表格 */ document.addEventListener('@proTableReload', tableReload); return function () { document.removeEventListener('@proTableReload', tableReload); }; }, []); return /*#__PURE__*/(0, _jsxRuntime.jsxs)(TableWrapper, { noPadding: noPadding, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_proTable.default, (0, _objectSpread2.default)({ rowKey: rowKey, headerTitle: getHeaderTitle(), actionRef: getActionRef(), columns: patchRender((0, _utils2.getAreaFields)(columns, 'search', { defaultHideInSearch: defaultHideInSearch }).concat((0, _utils2.getAreaFields)(columns, 'table')), { innerRef: innerRef, spaceProps: optionColumnSpaceProps }), request: patchRequest(), rowSelection: getRowSelection(), tableAlertOptionRender: tableAlertOptionRender === false ? false : getTableAlertOptionRender, options: options }, restTableProps)), /*#__PURE__*/(0, _jsxRuntime.jsx)(_ModalForm.default, (0, _objectSpread2.default)({ title: title, innerRef: innerRef //@ts-ignore render 方法在 table 和 form 上的使用方法稍有不同,使用时需注意,最好两端分开用 render , columns: (0, _utils2.getAreaFields)(formColumns || columns, 'form'), onOpen: selfOnOpen, onFinish: onFinish }, modalFormRestProps)), contextHolder, modalContextHolder] }); }; var _default = exports.default = ProTable; // 用于生成api文档 /* istanbul ignore next */ var MyProTableSelfTypeComponent = exports.MyProTableSelfTypeComponent = function MyProTableSelfTypeComponent() { return null; }; // 用于生成api文档 /* istanbul ignore next */ var MyProTableOriginTypeComponent = exports.MyProTableOriginTypeComponent = function MyProTableOriginTypeComponent() { return null; }; // 用于生成api文档 /* istanbul ignore next */ var InnerRefTypeComponent = exports.InnerRefTypeComponent = function InnerRefTypeComponent() { return null; }; // 用于生成api文档 /* istanbul ignore next */ var TableAlertOptionTypeComponent = exports.TableAlertOptionTypeComponent = function TableAlertOptionTypeComponent() { return null; }; // 用于生成api文档 /* istanbul ignore next */ var TableColumnTypeBaseComponent = exports.TableColumnTypeBaseComponent = function TableColumnTypeBaseComponent() { return null; }; // 用于生成api文档 /* istanbul ignore next */ var TableColumnSelfTypeComponent = exports.TableColumnSelfTypeComponent = function TableColumnSelfTypeComponent() { return null; }; // 用于生成api文档 /* istanbul ignore next */ var TableColumnOriginTypeComponent = exports.TableColumnOriginTypeComponent = function TableColumnOriginTypeComponent() { return null; }; // 用于生成api文档 /* istanbul ignore next */ var EnableDeleteTypeComponent = exports.EnableDeleteTypeComponent = function EnableDeleteTypeComponent() { return null; };