@ant-design/x
Version:
Craft AI-driven interfaces effortlessly
178 lines (170 loc) • 6.35 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _KeyCode = _interopRequireDefault(require("@rc-component/util/lib/KeyCode"));
var _react = require("react");
var _warning = _interopRequireDefault(require("../warning"));
var _useXComponentConfig = _interopRequireDefault(require("./use-x-component-config"));
const PrefixKeys = {
Alt: ['altKey', '⌥', 'Alt'],
Ctrl: ['ctrlKey', '⌃', 'Ctrl'],
Meta: ['metaKey', '⌘', 'Win'],
Shift: ['shiftKey', '⇧', 'Shift']
};
const NumberKeyCode = Array.from({
length: 9
}, (_, i) => _KeyCode.default.ONE + i);
const isAppleDevice = /(mac|iphone|ipod|ipad)/i.test(typeof navigator !== 'undefined' ? navigator?.platform : '');
// ======================== Shortcut Keys Icon ========================
const getShortcutKeysIcon = key => {
if (key === 'number') {
return key;
}
if (typeof key === 'string' && PrefixKeys?.[key]?.[isAppleDevice ? 1 : 2]) {
return PrefixKeys[key][isAppleDevice ? 1 : 2];
}
return Object.entries(_KeyCode.default || {})?.find(([_, v]) => v === key)?.[0] || '';
};
// ======================== Determine if the shortcut key has been hit, And return the corresponding data ========================
const getShortcutAction = (shortcutKey, event) => {
const copyShortcutKey = [...shortcutKey];
const keyCode = copyShortcutKey.pop();
const signKeys = copyShortcutKey;
const hitKey = signKeys.reduce((value, signKey) => {
if (!value) return value;
return event[PrefixKeys?.[signKey]?.[0]] || false;
}, keyCode === event.keyCode);
if (hitKey) return {
actionShortcutKey: shortcutKey,
actionKeyCodeNumber: NumberKeyCode.indexOf(event.keyCode) > -1 ? NumberKeyCode.indexOf(event.keyCode) : false,
actionKeyCode: event.keyCode,
timeStamp: event.timeStamp
};
return false;
};
// ======================== Get the decomposed shortcut keys ========================
const getDecomposedShortcutKeys = shortcutKeys => {
const copyShortcutKey = [...shortcutKeys];
const keyCode = copyShortcutKey.pop();
const prefixKeys = copyShortcutKey;
const keyCodeDict = keyCode === 'number' ? NumberKeyCode : [keyCode];
return {
keyCodeDict,
prefixKeys
};
};
// ======================== Use shortcut keys with the same configuration to waring ========================
const waringConfig = (flattenShortcutKeys, shortcutKey, component) => {
const sameShortcutKeys = !!flattenShortcutKeys.find(({
shortcutKey: oriShortcutKey
}) => oriShortcutKey.toString() === shortcutKey.toString());
(0, _warning.default)(!sameShortcutKeys, component, `Same shortcutKey ${shortcutKey.toString()}`);
};
// ======================== Flatten shortcut key data ========================
const getFlattenShortcutKeys = (component, contextShortcutKeys, componentShortcutKeys) => {
const mergeShortcutKeys = Object.assign({}, contextShortcutKeys || {}, componentShortcutKeys);
return Object.keys(mergeShortcutKeys).reduce(({
flattenShortcutKeys,
shortcutKeysInfo
}, subName) => {
const subShortcutKeys = mergeShortcutKeys[subName];
if (!Array.isArray(subShortcutKeys)) {
return {
flattenShortcutKeys,
shortcutKeysInfo
};
}
shortcutKeysInfo = {
...shortcutKeysInfo,
[subName]: {
shortcutKeys: subShortcutKeys,
shortcutKeysIcon: []
}
};
if (subShortcutKeys.every(item => Array.isArray(item))) {
subShortcutKeys.forEach((shortcutKey, index) => {
const shortcutKeyArr = shortcutKey;
waringConfig(flattenShortcutKeys, shortcutKeyArr, component);
flattenShortcutKeys.push({
name: subName,
shortcutKey: shortcutKeyArr,
index
});
shortcutKeysInfo[subName].shortcutKeysIcon.push(shortcutKeyArr?.map(key => getShortcutKeysIcon(key)));
});
} else {
const {
keyCodeDict,
prefixKeys
} = getDecomposedShortcutKeys(subShortcutKeys);
keyCodeDict.forEach(keyCode => {
waringConfig(flattenShortcutKeys, [...prefixKeys, keyCode], component);
flattenShortcutKeys.push({
name: subName,
shortcutKey: [...prefixKeys, keyCode]
});
});
shortcutKeysInfo[subName].shortcutKeysIcon = subShortcutKeys.map(key => getShortcutKeysIcon(key));
}
return {
flattenShortcutKeys,
shortcutKeysInfo
};
}, {
flattenShortcutKeys: [],
shortcutKeysInfo: {}
});
};
const useObservable = () => {
const observer = (0, _react.useRef)(undefined);
const subscribe = fn => {
observer.current = fn;
};
return [observer, subscribe];
};
// ================== Monitor shortcut key triggering ======================
const useShortcutKeys = (component, shortcutKeys) => {
const contextConfig = (0, _useXComponentConfig.default)(component);
const {
flattenShortcutKeys,
shortcutKeysInfo
} = getFlattenShortcutKeys(component, contextConfig.shortcutKeys, shortcutKeys);
const [shortcutAction, setShortcutAction] = (0, _react.useState)(null);
const [observer, subscribe] = useObservable();
const keyLockRef = (0, _react.useRef)(false);
const onKeydown = event => {
for (const shortcutKeyInfo of flattenShortcutKeys) {
const activeKeyInfo = getShortcutAction(shortcutKeyInfo.shortcutKey, event);
if (activeKeyInfo) {
const info = {
...activeKeyInfo,
name: shortcutKeyInfo.name,
index: shortcutKeyInfo?.index
};
if (keyLockRef.current) {
return;
}
keyLockRef.current = true;
setShortcutAction(info);
observer?.current?.(info);
}
}
};
const onKeyup = () => {
keyLockRef.current = false;
};
(0, _react.useEffect)(() => {
if (flattenShortcutKeys.length === 0) return;
document.addEventListener('keydown', onKeydown);
document.addEventListener('keyup', onKeyup);
return () => {
document.removeEventListener('keydown', onKeydown);
document.addEventListener('keyup', onKeyup);
};
}, [flattenShortcutKeys.length, observer]);
return [shortcutAction, shortcutKeysInfo, subscribe];
};
var _default = exports.default = useShortcutKeys;