Files
video-gen/video-gen-admin/node_modules/@rc-component/portal/es/useEscKeyDown.js
T
2026-05-25 17:08:18 +08:00

79 lines
2.0 KiB
JavaScript

import { useEvent } from '@rc-component/util';
import useId from "@rc-component/util/es/hooks/useId";
import { useEffect, useMemo } from 'react';
let stack = [];
const IME_LOCK_DURATION = 200;
let lastCompositionEndTime = 0;
// Export for testing
export const _test = process.env.NODE_ENV === 'test' ? () => ({
stack,
reset: () => {
// Not reset stack to ensure effect will clean up correctly
lastCompositionEndTime = 0;
}
}) : null;
// Global event handlers
const onGlobalKeyDown = event => {
if (event.key === 'Escape' && !event.isComposing) {
const now = Date.now();
if (now - lastCompositionEndTime < IME_LOCK_DURATION) {
return;
}
const len = stack.length;
for (let i = len - 1; i >= 0; i -= 1) {
stack[i].onEsc({
top: i === len - 1,
event
});
}
}
};
const onGlobalCompositionEnd = () => {
lastCompositionEndTime = Date.now();
};
function attachGlobalEventListeners() {
window.addEventListener('keydown', onGlobalKeyDown);
window.addEventListener('compositionend', onGlobalCompositionEnd);
}
function detachGlobalEventListeners() {
if (stack.length === 0) {
window.removeEventListener('keydown', onGlobalKeyDown);
window.removeEventListener('compositionend', onGlobalCompositionEnd);
}
}
export default function useEscKeyDown(open, onEsc) {
const id = useId();
const onEventEsc = useEvent(onEsc);
const ensure = () => {
if (!stack.find(item => item.id === id)) {
stack.push({
id,
onEsc: onEventEsc
});
}
};
const clear = () => {
stack = stack.filter(item => item.id !== id);
};
useMemo(() => {
if (open) {
ensure();
} else if (!open) {
clear();
}
}, [open]);
useEffect(() => {
if (open) {
ensure();
// Attach global event listeners
attachGlobalEventListeners();
return () => {
clear();
// Remove global event listeners if instances is empty
detachGlobalEventListeners();
};
}
}, [open]);
}