mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Introduce modifier for ctrl or command based on platform in use
Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
parent
0622b8ddaa
commit
926e7e2eb7
@ -6,6 +6,7 @@ import {
|
|||||||
KeyboardShortcut,
|
KeyboardShortcut,
|
||||||
keyboardShortcutInjectionToken,
|
keyboardShortcutInjectionToken,
|
||||||
} from "./keyboard-shortcut-injection-token";
|
} from "./keyboard-shortcut-injection-token";
|
||||||
|
import platformInjectable from "./platform.injectable";
|
||||||
|
|
||||||
export type InvokeShortcut = (event: KeyboardEvent) => void;
|
export type InvokeShortcut = (event: KeyboardEvent) => void;
|
||||||
|
|
||||||
@ -28,36 +29,58 @@ const toShortcutsWithMatchingScope = (shortcut: KeyboardShortcut) => {
|
|||||||
|
|
||||||
const toBindingWithDefaults = (binding: Binding) =>
|
const toBindingWithDefaults = (binding: Binding) =>
|
||||||
isString(binding)
|
isString(binding)
|
||||||
? { code: binding, shift: false, ctrl: false, altOrOption: false, meta: false }
|
? {
|
||||||
: { ctrl: false, shift: false, altOrOption: false, meta: false, ...binding };
|
code: binding,
|
||||||
|
shift: false,
|
||||||
|
ctrl: false,
|
||||||
|
altOrOption: false,
|
||||||
|
meta: false,
|
||||||
|
ctrlOrCommand: false,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
ctrl: false,
|
||||||
|
shift: false,
|
||||||
|
altOrOption: false,
|
||||||
|
meta: false,
|
||||||
|
ctrlOrCommand: false,
|
||||||
|
...binding,
|
||||||
|
};
|
||||||
|
|
||||||
const toShortcutsWithMatchingBinding = (event: KeyboardEvent) => (shortcut: KeyboardShortcut) => {
|
const toShortcutsWithMatchingBinding =
|
||||||
const binding = toBindingWithDefaults(shortcut.binding);
|
(event: KeyboardEvent, platform: string) => (shortcut: KeyboardShortcut) => {
|
||||||
|
const binding = toBindingWithDefaults(shortcut.binding);
|
||||||
|
|
||||||
const shiftModifierMatches = binding.shift === event.shiftKey;
|
const shiftModifierMatches = binding.shift === event.shiftKey;
|
||||||
const ctrlModifierMatches = binding.ctrl === event.ctrlKey;
|
const altModifierMatches = binding.altOrOption === event.altKey;
|
||||||
const altModifierMatches = binding.altOrOption === event.altKey;
|
|
||||||
const metaModifierMatches = binding.meta === event.metaKey;
|
|
||||||
|
|
||||||
return (
|
const isMac = platform === "darwin";
|
||||||
event.code === binding.code &&
|
|
||||||
shiftModifierMatches &&
|
const ctrlModifierMatches =
|
||||||
ctrlModifierMatches &&
|
binding.ctrl === event.ctrlKey || (!isMac && binding.ctrlOrCommand === event.ctrlKey);
|
||||||
altModifierMatches &&
|
|
||||||
metaModifierMatches
|
const metaModifierMatches =
|
||||||
);
|
binding.meta === event.metaKey || (isMac && binding.ctrlOrCommand === event.metaKey);
|
||||||
};
|
|
||||||
|
return (
|
||||||
|
event.code === binding.code &&
|
||||||
|
shiftModifierMatches &&
|
||||||
|
ctrlModifierMatches &&
|
||||||
|
altModifierMatches &&
|
||||||
|
metaModifierMatches
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const invokeShortcutInjectable = getInjectable({
|
const invokeShortcutInjectable = getInjectable({
|
||||||
id: "invoke-shortcut",
|
id: "invoke-shortcut",
|
||||||
|
|
||||||
instantiate: (di): InvokeShortcut => {
|
instantiate: (di): InvokeShortcut => {
|
||||||
const getShortcuts = () => di.injectMany(keyboardShortcutInjectionToken);
|
const getShortcuts = () => di.injectMany(keyboardShortcutInjectionToken);
|
||||||
|
const platform = di.inject(platformInjectable);
|
||||||
|
|
||||||
return (event) => {
|
return (event) => {
|
||||||
const shortcutsToInvoke = pipeline(
|
const shortcutsToInvoke = pipeline(
|
||||||
getShortcuts(),
|
getShortcuts(),
|
||||||
filter(toShortcutsWithMatchingBinding(event)),
|
filter(toShortcutsWithMatchingBinding(event, platform)),
|
||||||
filter(toShortcutsWithMatchingScope),
|
filter(toShortcutsWithMatchingScope),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,14 @@ import { getInjectionToken } from "@ogre-tools/injectable";
|
|||||||
|
|
||||||
export type Binding =
|
export type Binding =
|
||||||
| string
|
| string
|
||||||
| { code: string; shift?: boolean; ctrl?: boolean; altOrOption?: boolean; meta?: boolean };
|
| {
|
||||||
|
code: string;
|
||||||
|
shift?: boolean;
|
||||||
|
ctrl?: boolean;
|
||||||
|
altOrOption?: boolean;
|
||||||
|
meta?: boolean;
|
||||||
|
ctrlOrCommand?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export type KeyboardShortcut = {
|
export type KeyboardShortcut = {
|
||||||
binding: Binding;
|
binding: Binding;
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import { Discover, discoverFor } from "@k8slens/react-testing-library-discovery"
|
|||||||
import { startApplicationInjectionToken } from "@k8slens/application";
|
import { startApplicationInjectionToken } from "@k8slens/application";
|
||||||
import { renderInjectionToken } from "@k8slens/react-application";
|
import { renderInjectionToken } from "@k8slens/react-application";
|
||||||
import { reactApplicationChildrenInjectionToken } from "@k8slens/react-application";
|
import { reactApplicationChildrenInjectionToken } from "@k8slens/react-application";
|
||||||
|
import platformInjectable from "./platform.injectable";
|
||||||
|
|
||||||
describe("keyboard-shortcuts", () => {
|
describe("keyboard-shortcuts", () => {
|
||||||
let di: DiContainer;
|
let di: DiContainer;
|
||||||
@ -203,6 +204,8 @@ describe("keyboard-shortcuts", () => {
|
|||||||
].forEach(({ binding, keyboard, scenario, shouldCallCallback }) => {
|
].forEach(({ binding, keyboard, scenario, shouldCallCallback }) => {
|
||||||
// eslint-disable-next-line jest/valid-title
|
// eslint-disable-next-line jest/valid-title
|
||||||
it(scenario, () => {
|
it(scenario, () => {
|
||||||
|
const invokeMock = jest.fn();
|
||||||
|
|
||||||
const shortcutInjectable = getInjectable({
|
const shortcutInjectable = getInjectable({
|
||||||
id: "shortcut",
|
id: "shortcut",
|
||||||
|
|
||||||
@ -230,4 +233,121 @@ describe("keyboard-shortcuts", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("given in mac and keyboard shortcut with modifier for ctrl or command", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
di.override(platformInjectable, () => "darwin");
|
||||||
|
|
||||||
|
invokeMock = jest.fn();
|
||||||
|
|
||||||
|
const shortcutInjectable = getInjectable({
|
||||||
|
id: "shortcut",
|
||||||
|
|
||||||
|
instantiate: () => ({
|
||||||
|
binding: { code: "KeyK", ctrlOrCommand: true },
|
||||||
|
invoke: invokeMock,
|
||||||
|
}),
|
||||||
|
|
||||||
|
injectionToken: keyboardShortcutInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
di.register(shortcutInjectable);
|
||||||
|
});
|
||||||
|
|
||||||
|
const startApplication = di.inject(startApplicationInjectionToken);
|
||||||
|
|
||||||
|
await startApplication();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("when pressing the keyboard shortcut with command, calls the callback", () => {
|
||||||
|
userEvent.keyboard("{Meta>}[KeyK]");
|
||||||
|
|
||||||
|
expect(invokeMock).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("when pressing the keyboard shortcut with ctrl, does not call the callback", () => {
|
||||||
|
userEvent.keyboard("{Control>}[KeyK]");
|
||||||
|
|
||||||
|
expect(invokeMock).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("given in windows and keyboard shortcut with modifier for ctrl or command", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
di.override(platformInjectable, () => "win32");
|
||||||
|
|
||||||
|
invokeMock = jest.fn();
|
||||||
|
|
||||||
|
const shortcutInjectable = getInjectable({
|
||||||
|
id: "shortcut",
|
||||||
|
|
||||||
|
instantiate: () => ({
|
||||||
|
binding: { code: "KeyK", ctrlOrCommand: true },
|
||||||
|
invoke: invokeMock,
|
||||||
|
}),
|
||||||
|
|
||||||
|
injectionToken: keyboardShortcutInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
di.register(shortcutInjectable);
|
||||||
|
});
|
||||||
|
|
||||||
|
const startApplication = di.inject(startApplicationInjectionToken);
|
||||||
|
|
||||||
|
await startApplication();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("when pressing the keyboard shortcut with windows, does not call the callback", () => {
|
||||||
|
userEvent.keyboard("{Meta>}[KeyK]");
|
||||||
|
|
||||||
|
expect(invokeMock).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("when pressing the keyboard shortcut with ctrl, calls the callback", () => {
|
||||||
|
userEvent.keyboard("{Control>}[KeyK]");
|
||||||
|
|
||||||
|
expect(invokeMock).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("given in any other platform and keyboard shortcut with modifier for ctrl or command", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
di.override(platformInjectable, () => "some-other-platform");
|
||||||
|
|
||||||
|
invokeMock = jest.fn();
|
||||||
|
|
||||||
|
const shortcutInjectable = getInjectable({
|
||||||
|
id: "shortcut",
|
||||||
|
|
||||||
|
instantiate: () => ({
|
||||||
|
binding: { code: "KeyK", ctrlOrCommand: true },
|
||||||
|
invoke: invokeMock,
|
||||||
|
}),
|
||||||
|
|
||||||
|
injectionToken: keyboardShortcutInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
di.register(shortcutInjectable);
|
||||||
|
});
|
||||||
|
|
||||||
|
const startApplication = di.inject(startApplicationInjectionToken);
|
||||||
|
|
||||||
|
await startApplication();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("when pressing the keyboard shortcut with meta, does not call the callback", () => {
|
||||||
|
userEvent.keyboard("{Meta>}[KeyK]");
|
||||||
|
|
||||||
|
expect(invokeMock).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("when pressing the keyboard shortcut with ctrl, calls the callback", () => {
|
||||||
|
userEvent.keyboard("{Control>}[KeyK]");
|
||||||
|
|
||||||
|
expect(invokeMock).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -0,0 +1,11 @@
|
|||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
|
||||||
|
export const allPlatforms = ["win32", "darwin", "linux"] as const;
|
||||||
|
|
||||||
|
const platformInjectable = getInjectable({
|
||||||
|
id: "platform",
|
||||||
|
instantiate: () => process.platform as (typeof allPlatforms)[number],
|
||||||
|
causesSideEffects: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default platformInjectable;
|
||||||
Loading…
Reference in New Issue
Block a user