@tanstack/octane-hotkeys 0.9.2 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,14 @@
1
1
  import { UseHotkeyCommonOptions } from "./useHotkey.js";
2
- import { AppHotkeys, AppHotkeysStore, CustomHotkeys, HotkeyChordRecorderOptions, HotkeySequenceRecorderOptions } from "@tanstack/hotkeys";
2
+ import { AppHotkeys, AppHotkeysStore, CustomHotkeys, HotkeyChordRecorderOptions, HotkeyPlatform, HotkeySequenceRecorderOptions } from "@tanstack/hotkeys";
3
3
  import { HotkeysProviderScopeProps } from "@tanstack/hotkeys/adapter";
4
4
  //#region src/HotkeysProvider.d.ts
5
5
  export interface DefaultHotkeysOptions {
6
+ /**
7
+ * The user's platform, for labels from `useFormatForDisplay`, hotkeys, and
8
+ * recorders. Defaults to detection. When server rendering, set it from the
9
+ * request with `detectPlatform(userAgent)`.
10
+ */
11
+ platform?: HotkeyPlatform;
6
12
  /**
7
13
  * Defaults for every hotkey registered by `useHotkey` and `useHotkeys`.
8
14
  * `requireReset` applies to chords and `timeout` applies to sequences.
package/dist/index.d.ts CHANGED
@@ -5,10 +5,11 @@ import { useHeldKeys } from "./useHeldKeys.js";
5
5
  import { useHeldKeyCodes } from "./useHeldKeyCodes.js";
6
6
  import { useKeyHold } from "./useKeyHold.js";
7
7
  import { useHotkeyHint } from "./useHotkeyHint.js";
8
+ import { useFormatForDisplay } from "./useFormatForDisplay.js";
8
9
  import { HotkeyRegistrationsResult, OctaneHotkeyRecorder, UseCustomHotkeysResult } from "./types.js";
9
10
  import { useHotkeyRegistrations } from "./useHotkeyRegistrations.js";
10
11
  import { useHotkeyScopesState } from "./useHotkeyScopesState.js";
11
12
  import { useHotkeyRecorder } from "./useHotkeyRecorder.js";
12
13
  import { useAppHotkeyList, useAppHotkeys, useCustomHotkeys } from "./useAppHotkeys.js";
13
14
  export * from "@tanstack/hotkeys";
14
- export { type DefaultHotkeysOptions, HotkeyRegistrationsResult, HotkeysProvider, type HotkeysProviderOptions, type HotkeysProviderProps, OctaneHotkeyRecorder, UseAppHotkeyOptions, UseCustomHotkeysResult, UseHotkeyChordOptions, UseHotkeyCommonOptions, UseHotkeyDefinition, UseHotkeyOptions, UseHotkeyOptionsFor, UseHotkeySequenceOptions, UseHotkeyTarget, useAppHotkeyList, useAppHotkeys, useCustomHotkeys, useDefaultHotkeysOptions, useHeldKeyCodes, useHeldKeys, useHotkey, useHotkeyHint, useHotkeyRecorder, useHotkeyRegistrations, useHotkeyScopesState, useHotkeys, useHotkeysContext, useKeyHold };
15
+ export { type DefaultHotkeysOptions, HotkeyRegistrationsResult, HotkeysProvider, type HotkeysProviderOptions, type HotkeysProviderProps, OctaneHotkeyRecorder, UseAppHotkeyOptions, UseCustomHotkeysResult, UseHotkeyChordOptions, UseHotkeyCommonOptions, UseHotkeyDefinition, UseHotkeyOptions, UseHotkeyOptionsFor, UseHotkeySequenceOptions, UseHotkeyTarget, useAppHotkeyList, useAppHotkeys, useCustomHotkeys, useDefaultHotkeysOptions, useFormatForDisplay, useHeldKeyCodes, useHeldKeys, useHotkey, useHotkeyHint, useHotkeyRecorder, useHotkeyRegistrations, useHotkeyScopesState, useHotkeys, useHotkeysContext, useKeyHold };
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ import { useHeldKeys } from "./useHeldKeys.js";
5
5
  import { useHeldKeyCodes } from "./useHeldKeyCodes.js";
6
6
  import { useKeyHold } from "./useKeyHold.js";
7
7
  import { useHotkeyHint } from "./useHotkeyHint.js";
8
+ import { useFormatForDisplay } from "./useFormatForDisplay.js";
8
9
  import { useHotkeyRegistrations } from "./useHotkeyRegistrations.js";
9
10
  import { useHotkeyScopesState } from "./useHotkeyScopesState.js";
10
11
  import { useHotkeyRecorder } from "./useHotkeyRecorder.js";
@@ -12,4 +13,4 @@ import { useAppHotkeyList, useAppHotkeys, useCustomHotkeys } from "./useAppHotke
12
13
 
13
14
  export * from "@tanstack/hotkeys"
14
15
 
15
- export { HotkeysProvider, useAppHotkeyList, useAppHotkeys, useCustomHotkeys, useDefaultHotkeysOptions, useHeldKeyCodes, useHeldKeys, useHotkey, useHotkeyHint, useHotkeyRecorder, useHotkeyRegistrations, useHotkeyScopesState, useHotkeys, useHotkeysContext, useKeyHold };
16
+ export { HotkeysProvider, useAppHotkeyList, useAppHotkeys, useCustomHotkeys, useDefaultHotkeysOptions, useFormatForDisplay, useHeldKeyCodes, useHeldKeys, useHotkey, useHotkeyHint, useHotkeyRecorder, useHotkeyRegistrations, useHotkeyScopesState, useHotkeys, useHotkeysContext, useKeyHold };
@@ -0,0 +1,26 @@
1
+ import { formatForDisplay } from "@tanstack/hotkeys";
2
+ //#region src/useFormatForDisplay.d.ts
3
+ /**
4
+ * Returns `formatForDisplay` with the platform from `HotkeysProvider`, or the
5
+ * detected platform without one. A `platform` passed to the returned function
6
+ * wins. Without a provider platform, server rendering and hydration use
7
+ * 'linux', then the client re-renders with the detected platform.
8
+ *
9
+ * Call the hook once at the top of the component; the returned function can
10
+ * be called anywhere, such as in a loop or a condition. Server-rendered apps
11
+ * should set the provider's `defaultOptions.platform` from the request with
12
+ * `detectPlatform(userAgent)`, so the server HTML matches the user's platform.
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * function SaveButton() @{
17
+ * const format = useFormatForDisplay()
18
+ *
19
+ * <button>
20
+ * Save <kbd>{format('Mod+S')}</kbd>
21
+ * </button>
22
+ * }
23
+ * ```
24
+ */
25
+ export declare function useFormatForDisplay(): typeof formatForDisplay;
26
+ //#endregion
@@ -0,0 +1,19 @@
1
+ import { subSlot } from "./internal.js";
2
+ import { useDefaultHotkeysOptions } from "./HotkeysProvider.js";
3
+ import { detectPlatform, formatForDisplay } from "@tanstack/hotkeys";
4
+ import { useCallback, useSyncExternalStore } from "octane";
5
+ import { getServerPlatformSnapshot } from "@tanstack/hotkeys/adapter";
6
+
7
+ //#region src/useFormatForDisplay.ts
8
+ const subscribe = () => () => {};
9
+ function useFormatForDisplay(slot) {
10
+ const provided = useDefaultHotkeysOptions().platform;
11
+ const platform = useSyncExternalStore(subscribe, () => provided ?? detectPlatform(), () => provided ?? getServerPlatformSnapshot(), subSlot(slot, "platform"));
12
+ return useCallback((hotkey, options) => formatForDisplay(hotkey, {
13
+ ...options,
14
+ platform: options?.platform ?? platform
15
+ }), [platform], subSlot(slot, "format"));
16
+ }
17
+
18
+ //#endregion
19
+ export { useFormatForDisplay };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/octane-hotkeys",
3
- "version": "0.9.2",
3
+ "version": "0.10.0",
4
4
  "description": "Octane adapter for TanStack Hotkeys",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -35,7 +35,7 @@
35
35
  "skills"
36
36
  ],
37
37
  "dependencies": {
38
- "@tanstack/hotkeys": "0.22.1"
38
+ "@tanstack/hotkeys": "0.23.0"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@tsrx/oxc": "0.20.0",
@@ -55,6 +55,7 @@ export function Panel({ onSave }: { onSave: () => void }) @{
55
55
  | `<HotkeysProvider>` | Set default options, a scope (`exclusive` for dialogs), `enabled`, and app hotkeys for the components inside it. |
56
56
  | `useHotkeysContext()` | Read the nearest provider's merged defaults and enabled state, or `null` outside a provider. |
57
57
  | `useDefaultHotkeysOptions()` | Read the default options merged from every provider above. |
58
+ | `useFormatForDisplay()` | Get `formatForDisplay` with the provider's `platform` filled in. Use it for labels in server-rendered apps; call it at the top of the component. |
58
59
  | `useAppHotkeys()` | Get the declared app hotkeys with the user's custom hotkeys applied, to pass to the register API. |
59
60
  | `useAppHotkeyList()` | List every app hotkey with its status, including ones whose components aren't mounted, for a cheat sheet or settings screen. |
60
61
  | `useCustomHotkeys()` | Read, change, and reset the user's custom hotkeys, and check a new one for conflicts. |
@@ -77,6 +78,7 @@ No provider is required. Use Octane 0.12 or newer, with hooks in compiler-enable
77
78
  - **Hooks are tracked by call site.** Use `useHotkeys(items.map(...))` for lists, not `useHotkey` in a loop.
78
79
  - **Custom hooks in plain `.ts` and `.js` files need the compiler.** Calls from a `.ts` or `.js` file that the compiler skips share one slot per hook in each component, even across different custom hooks, so only the last `useHotkey` call works. The compiler handles a file that imports a value from `octane` or starts with `/** @jsxImportSource octane */`. A type-only import doesn't count. `.tsrx` and `.tsx` files are fine.
79
80
  - **Call the hooks directly.** A `useShortcut(keys: string)` wrapper has to cast strings to hotkeys, which turns off type checking and drops sequences, options, and app hotkeys.
81
+ - **Server-rendered labels need the user's platform.** On the server, `formatForDisplay` can't see the user's OS, so it renders Linux labels that differ after hydration for Mac and Windows users. Set the provider's `defaultOptions.platform` to `detectPlatform(userAgent)` from the request's `User-Agent` header, and format labels with `const format = useFormatForDisplay()` at the top of the component, then `format(hotkey)`. Keep plain `formatForDisplay` for labels that render only in the browser.
80
82
 
81
83
  When declaring app hotkeys, building a cheat sheet, or letting users rebind shortcuts, load `@tanstack/hotkeys#app-hotkeys` and read [app hotkeys in Octane](references/app-hotkeys.md).
82
84