2023-05-19 23:14:55 +02:00
|
|
|
import React from "@modules/react";
|
2022-10-03 05:08:10 +02:00
|
|
|
|
2023-08-29 05:47:20 +02:00
|
|
|
import Button from "../../base/button";
|
2023-05-20 00:37:21 +02:00
|
|
|
import Keyboard from "@ui/icons/keyboard";
|
|
|
|
import Close from "@ui/icons/close";
|
2022-10-03 05:08:10 +02:00
|
|
|
|
2023-03-07 01:17:28 +01:00
|
|
|
const {useState, useCallback, useEffect} = React;
|
2022-10-03 05:08:10 +02:00
|
|
|
|
|
|
|
|
2023-03-07 01:17:28 +01:00
|
|
|
export default function Keybind({value: initialValue, onChange, max = 2, clearable = true}) {
|
|
|
|
const [state, setState] = useState({value: initialValue, isRecording: false, accum: []});
|
2022-10-03 05:08:10 +02:00
|
|
|
|
2023-03-07 01:17:28 +01:00
|
|
|
useEffect(() => {
|
2023-03-22 17:23:40 +01:00
|
|
|
window.addEventListener("keydown", keyHandler, true);
|
|
|
|
return () => window.removeEventListener("keydown", keyHandler, true);
|
2023-03-07 01:17:28 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
const keyHandler = useCallback((event) => {
|
|
|
|
if (!state.isRecording) return;
|
2022-10-03 05:08:10 +02:00
|
|
|
event.stopImmediatePropagation();
|
|
|
|
event.stopPropagation();
|
|
|
|
event.preventDefault();
|
2023-03-07 01:17:28 +01:00
|
|
|
if (event.repeat || state.accum.includes(event.key)) return;
|
2022-10-03 05:08:10 +02:00
|
|
|
|
2023-03-07 01:17:28 +01:00
|
|
|
state.accum.push(event.key);
|
|
|
|
if (state.accum.length == max) {
|
|
|
|
if (onChange) onChange(state.accum);
|
|
|
|
setState({value: state.accum.slice(0), isRecording: false, accum: []});
|
2022-10-03 05:08:10 +02:00
|
|
|
}
|
2023-03-20 03:23:11 +01:00
|
|
|
}, [state, max, onChange]);
|
2022-10-03 05:08:10 +02:00
|
|
|
|
2023-03-07 01:17:28 +01:00
|
|
|
const clearKeybind = useCallback((event) => {
|
2022-10-03 05:08:10 +02:00
|
|
|
event.stopPropagation();
|
|
|
|
event.preventDefault();
|
2023-03-07 01:17:28 +01:00
|
|
|
if (onChange) onChange([]);
|
2023-03-22 17:23:40 +01:00
|
|
|
setState({...state, isRecording: false, value: [], accum: []});
|
2023-03-20 03:23:11 +01:00
|
|
|
}, [onChange, state]);
|
|
|
|
|
|
|
|
const onClick = useCallback((e) => {
|
|
|
|
if (e.target?.className?.includes?.("bd-keybind-clear") || e.target?.closest(".bd-button")?.className?.includes("bd-keybind-clear")) return clearKeybind(e);
|
|
|
|
setState({...state, isRecording: !state.isRecording});
|
|
|
|
}, [state, clearKeybind]);
|
2023-03-07 01:17:28 +01:00
|
|
|
|
|
|
|
|
|
|
|
const displayValue = state.isRecording ? "Recording..." : !state.value.length ? "N/A" : state.value.join(" + ");
|
|
|
|
return <div className={"bd-keybind-wrap" + (state.isRecording ? " recording" : "")} onClick={onClick}>
|
|
|
|
<input readOnly={true} type="text" className="bd-keybind-input" value={displayValue} />
|
|
|
|
<div className="bd-keybind-controls">
|
2023-08-29 05:47:20 +02:00
|
|
|
<Button size={Button.Sizes.ICON} look={Button.Looks.FILLED} color={state.isRecording ? Button.Colors.RED : Button.Colors.BRAND} className="bd-keybind-record" onClick={onClick}><Keyboard size="24px" /></Button>
|
|
|
|
{clearable && <Button size={Button.Sizes.ICON} look={Button.Looks.BLANK} onClick={clearKeybind} className="bd-keybind-clear"><Close size="24px" /></Button>}
|
2023-03-07 01:17:28 +01:00
|
|
|
</div>
|
|
|
|
</div>;
|
2022-10-03 05:08:10 +02:00
|
|
|
}
|