diff --git a/README.md b/README.md index f40b927..c81292b 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,7 @@ external keyboard). For instance, for `alt+b` it will return `Alt + B` on Windows/Linux or `⌥ B` on Mac. -If you're using overrides, pass the same override config both to `hotkeyKeyUX()` +If you’re using overrides, pass the same override config both to `hotkeyKeyUX()` and `getHotKeyHint()` for accurate hints: ```js @@ -431,3 +431,26 @@ startKeyUX(window, [ hiddenKeyUX() ]) ``` + + +### Mac Compatibility Mode + +It’s common to use the Meta (or ) modifier for hotkeys +on Mac, while Window and Linux usually favor the Ctrl key. To provide +familiar experience on all platforms, enable the Mac compatibility transform: + +```js +import { + hotkeyMacCompat, + hotkeyKeyUX, + startKeyUX, + getHotKeyHint +} from 'keyux' + +const macCompat = hotkeyMacCompat(); +startKeyUX(window, [hotkeyKeyUX([macCompat])]) +getHotKeyHint(window, 'ctrl+b', [macCompat]) +``` + +Hotkeys pressed with the Meta modifier will work as if the Ctrl +modifier was pressed. diff --git a/compat.js b/compat.js new file mode 100644 index 0000000..c3de248 --- /dev/null +++ b/compat.js @@ -0,0 +1,16 @@ +function maybeApplyCompat(code, window, from, to) { + if ( + window.navigator.platform.indexOf('Mac') === 0 && + !code.includes('meta+ctrl') + ) { + return code.replace(from, to) + } + return code +} + +export function hotkeyMacCompat() { + return [ + (code, window) => maybeApplyCompat(code, window, 'meta', 'ctrl'), + (code, window) => maybeApplyCompat(code, window, 'ctrl', 'meta') + ] +} diff --git a/index.d.ts b/index.d.ts index 81dd3a2..db312f2 100644 --- a/index.d.ts +++ b/index.d.ts @@ -186,3 +186,9 @@ export function getHotKeyHint( * ``` */ export function hotkeyOverrides(overrides: HotkeyOverride): Transformer + +/** + * Provides a transformer for Mac compatibility mode that can be used + * with `hotkeyKeyUX()` and `getHotKeyHint()`. + */ +export function hotkeyMacCompat(): Transformer diff --git a/index.js b/index.js index c4219d2..4e7596f 100644 --- a/index.js +++ b/index.js @@ -4,6 +4,7 @@ export * from './hidden.js' export * from './press.js' export * from './jump.js' export * from './overrides.js' +export * from './compat.js' export function startKeyUX(window, plugins) { let unbinds = plugins.map(plugin => plugin(window)) diff --git a/package.json b/package.json index bbfa172..0c3f849 100644 --- a/package.json +++ b/package.json @@ -83,9 +83,9 @@ { "name": "All modules", "import": { - "./index.js": "{ startKeyUX, hotkeyKeyUX, pressKeyUX, focusGroupKeyUX, jumpKeyUX, hiddenKeyUX, likelyWithKeyboard, getHotKeyHint, hotkeyOverrides }" + "./index.js": "{ startKeyUX, hotkeyKeyUX, pressKeyUX, focusGroupKeyUX, jumpKeyUX, hiddenKeyUX, likelyWithKeyboard, getHotKeyHint, hotkeyOverrides, hotkeyMacCompat }" }, - "limit": "1996 B" + "limit": "2059 B" } ], "clean-publish": { diff --git a/test/compat.test.ts b/test/compat.test.ts new file mode 100644 index 0000000..08d7742 --- /dev/null +++ b/test/compat.test.ts @@ -0,0 +1,30 @@ +import { JSDOM } from 'jsdom' +import { equal } from 'node:assert' +import { test } from 'node:test' + +import { hotkeyMacCompat } from '../compat.js' +import type { MinimalWindow } from '../index.js' + +const MAC_WINDOW = { + navigator: { + platform: 'Mac', + userAgent: 'Mac' + } +} as MinimalWindow + +const [tranformForward, transformReverse] = hotkeyMacCompat() + +test('applies hotkey compatibility for Mac platform', () => { + equal(tranformForward('meta+shift+b', MAC_WINDOW), 'ctrl+shift+b') + equal(tranformForward('meta+ctrl+shift+b', MAC_WINDOW), 'meta+ctrl+shift+b') +}) + +test('applies hint compatibility for Mac platform', () => { + equal(transformReverse('ctrl+shift+b', MAC_WINDOW), 'meta+shift+b') + equal(transformReverse('meta+ctrl+shift+b', MAC_WINDOW), 'meta+ctrl+shift+b') +}) + +test('does nothing for non-Mac platform', () => { + equal(tranformForward('meta+shift+b', new JSDOM().window), 'meta+shift+b') + equal(transformReverse('ctrl+shift+b', new JSDOM().window), 'ctrl+shift+b') +}) diff --git a/test/demo/index.tsx b/test/demo/index.tsx index 328c735..b9edccf 100644 --- a/test/demo/index.tsx +++ b/test/demo/index.tsx @@ -7,6 +7,7 @@ import { getHotKeyHint, hiddenKeyUX, hotkeyKeyUX, + hotkeyMacCompat, hotkeyOverrides, jumpKeyUX, likelyWithKeyboard, @@ -15,10 +16,11 @@ import { } from '../../index.js' let overrides: HotkeyOverride = {} -let overridesTransformer = hotkeyOverrides(overrides); +let overridesTransformer = hotkeyOverrides(overrides) +let macCompatTransformer = hotkeyMacCompat() startKeyUX(window, [ - hotkeyKeyUX([overridesTransformer]), + hotkeyKeyUX([macCompatTransformer, overridesTransformer]), focusGroupKeyUX(), pressKeyUX('is-pressed'), jumpKeyUX(), @@ -27,7 +29,12 @@ startKeyUX(window, [ const HotKeyHint: FC<{ hotkey: string }> = ({ hotkey }) => { return likelyWithKeyboard(window) ? ( - {getHotKeyHint(window, hotkey, [overridesTransformer])} + + {getHotKeyHint(window, hotkey, [ + overridesTransformer, + macCompatTransformer + ])} + ) : null } @@ -343,7 +350,7 @@ const Tabs: FC = () => { const Toolbar: FC = () => { return ( <> -
+
@@ -351,7 +358,7 @@ const Toolbar: FC = () => {