@inklu/keys 1.2.3 → 1.4.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.
package/README.md CHANGED
@@ -15,16 +15,16 @@ A command is an addressable action. It has an id, title, and a handler.
15
15
  import { createCommands, seq } from "@inklu/keys";
16
16
 
17
17
  export const commands = createCommands({
18
- "palette.open": {
19
- title: "Open command palette",
20
- keys: "Mod+K",
21
- run: () => setPaletteOpen(true),
22
- },
23
- "nav.inbox": {
24
- title: "Go to inbox",
25
- keys: seq("G", "I"), // press G, then I
26
- run: () => navigate("/inbox"),
27
- },
18
+ "palette.open": {
19
+ title: "Open command palette",
20
+ keys: "Mod+K",
21
+ run: () => setPaletteOpen(true),
22
+ },
23
+ "nav.inbox": {
24
+ title: "Go to inbox",
25
+ keys: seq("G", "I"), // press G, then I
26
+ run: () => navigate("/inbox"),
27
+ },
28
28
  });
29
29
  ```
30
30
 
@@ -37,24 +37,26 @@ import { useCommands, useMountCommands, useShortcut } from "@inklu/keys/react";
37
37
  import { commands } from "./commands";
38
38
 
39
39
  function App() {
40
- // Starts listening in an effect
41
- useMountCommands(commands);
42
- return <ShortcutButton />;
40
+ // Starts listening in an effect
41
+ useMountCommands(commands);
42
+ return <ShortcutButton />;
43
43
  }
44
44
 
45
45
  function ShortcutButton() {
46
- // Get live shortcut state
47
- const shortcut = useShortcut(commands, "palette.open");
48
-
49
- return (
50
- <button
51
- onClick={() => commands.run("palette.open")}
52
- aria-keyshortcuts={shortcut.aria || undefined}
53
- >
54
- Open Palette
55
- {shortcut.tokens[0]?.map((token, i) => <kbd key={i}>{token}</kbd>)}
56
- </button>
57
- );
46
+ // Get live shortcut state
47
+ const shortcut = useShortcut(commands, "palette.open");
48
+
49
+ return (
50
+ <button
51
+ onClick={() => commands.run("palette.open")}
52
+ aria-keyshortcuts={shortcut.aria || undefined}
53
+ >
54
+ Open Palette
55
+ {shortcut.tokens[0]?.map((token, i) => (
56
+ <kbd key={i}>{token}</kbd>
57
+ ))}
58
+ </button>
59
+ );
58
60
  }
59
61
  ```
60
62
 
@@ -66,10 +68,10 @@ Use scopes to isolate commands when modals or dialogs are open.
66
68
  import { useScope } from "@inklu/keys/react";
67
69
 
68
70
  function Dialog({ isOpen }) {
69
- // When exclusive is true, commands outside this scope are silenced
70
- useScope(commands, "dialog", isOpen, { exclusive: true });
71
+ // When exclusive is true, commands outside this scope are silenced
72
+ useScope(commands, "dialog", isOpen, { exclusive: true });
71
73
 
72
- return isOpen ? <div className="dialog">...</div> : null;
74
+ return isOpen ? <div className="dialog">...</div> : null;
73
75
  }
74
76
  ```
75
77
 
@@ -82,27 +84,27 @@ Exactly one command runs per keypress. The winner is:
82
84
  1. The command in a named scope, over a global one. `"*"` counts as global here — it means "survives barriers", not "belongs to a region of the UI".
83
85
  2. Failing that, the one registered later. Registration order tracks mount order, so the most recently opened surface claims the key.
84
86
 
85
- A winner whose `when()` currently returns `false` steps aside rather than swallowing the keypress. This is how `Escape` closes the dialog when one is open and the panel otherwise, without making the dialog `exclusive`. Two commands sharing a chord *in the same scope* can never separate, so that case warns in development.
87
+ A winner whose `when()` currently returns `false` steps aside rather than swallowing the keypress. This is how `Escape` closes the dialog when one is open and the panel otherwise, without making the dialog `exclusive`. Two commands sharing a chord _in the same scope_ can never separate, so that case warns in development.
86
88
 
87
89
  ## 4. Rebinding
88
90
 
89
91
  Overrides are layered over defaults.
90
92
 
91
93
  ```ts
92
- commands.keymap.set("palette.open", "Mod+P"); // remap
94
+ commands.keymap.set("palette.open", "Mod+P"); // remap
93
95
  commands.keymap.add("palette.open", "Control+P"); // an additional key
94
- commands.keymap.set("palette.open", null); // unbind
95
- commands.keymap.reset("palette.open"); // reset to default
96
+ commands.keymap.set("palette.open", null); // unbind
97
+ commands.keymap.reset("palette.open"); // reset to default
96
98
  ```
97
99
 
98
100
  To rebind a command you did not define — one a package shipped — pass `bindings` when creating the registry. An unknown id is a compile error, and `reset` returns here rather than to the definition's `keys`:
99
101
 
100
102
  ```ts
101
103
  createCommands(commands, {
102
- bindings: {
103
- "palette.open": "Mod+P", // replace the shipped default
104
- "doc.publish": null, // ship it unbound
105
- },
104
+ bindings: {
105
+ "palette.open": "Mod+P", // replace the shipped default
106
+ "doc.publish": null, // ship it unbound
107
+ },
106
108
  });
107
109
  ```
108
110
 
@@ -113,9 +115,7 @@ In React, use the `useRebind` hook for a capture flow:
113
115
  ```tsx
114
116
  const rebind = useRebind(commands, "palette.open");
115
117
 
116
- <button onClick={rebind.start}>
117
- {rebind.recording ? "Press keys…" : rebind.display}
118
- </button>;
118
+ <button onClick={rebind.start}>{rebind.recording ? "Press keys…" : rebind.display}</button>;
119
119
  ```
120
120
 
121
121
  ## API Summary
@@ -12,6 +12,10 @@ type Binding = Chord | SequenceBinding;
12
12
  type BindingInput = Binding | ReadonlyArray<Binding>;
13
13
  /** JSON-serializable form of a binding. */
14
14
  type SerializedBinding = string | Array<string>;
15
+ /** An arbitrary JSON-compatible value, e.g. from `JSON.parse` or persisted storage. */
16
+ type Json = string | number | boolean | null | ReadonlyArray<Json> | {
17
+ readonly [key: string]: Json;
18
+ };
15
19
  /** Trigger source for a command. */
16
20
  type CommandSource = "keyboard" | "api" | "dom";
17
21
  /** Context passed to a command's `run` handler. */
@@ -138,7 +142,7 @@ interface CommandKeymap<Id extends string = string> {
138
142
  /** Exports user overrides as JSON-serializable data. */
139
143
  export(): SerializedKeymap;
140
144
  /** Imports user overrides, replacing current overrides and saving to storage. */
141
- import(data: unknown): void;
145
+ import(data: Json): void;
142
146
  }
143
147
  //#endregion
144
148
  //#region src/registry.d.ts
@@ -182,7 +186,7 @@ interface CommandsOptions<Id extends string = string> {
182
186
  */
183
187
  onRun?: (context: CommandContext) => void;
184
188
  /** Error handler called when a command execution fails. Defaults to `console.error`. */
185
- onError?: (error: unknown, context: CommandContext) => void;
189
+ onError?: (error: Error, context: CommandContext) => void;
186
190
  }
187
191
  /** Options passed when manually running a command. */
188
192
  interface RunOptions {
@@ -1,2 +1,2 @@
1
- import { n as observe, t as ObserveOptions } from "./attributes-DbxlLdrb.js";
1
+ import { n as observe, t as ObserveOptions } from "./attributes-O6bXNKT9.js";
2
2
  export { ObserveOptions, observe };
@@ -5,7 +5,7 @@ const KEYS_ATTRIBUTE = "data-command-keys";
5
5
  * Wires a commands registry to DOM data attributes. Returns a cleanup function.
6
6
  */
7
7
  function observe(registry, options = {}) {
8
- if (typeof document === "undefined") return () => {};
8
+ if (!("document" in globalThis)) return () => {};
9
9
  const root = options.root ?? document;
10
10
  const onClick = (event) => {
11
11
  const target = event.target;
@@ -45,7 +45,7 @@ function observe(registry, options = {}) {
45
45
  paintWithin(root);
46
46
  });
47
47
  let observer;
48
- if (typeof MutationObserver !== "undefined") {
48
+ if ("MutationObserver" in globalThis) {
49
49
  observer = new MutationObserver((mutations) => {
50
50
  for (const mutation of mutations) {
51
51
  if (mutation.type === "attributes" && mutation.target instanceof Element) {
@@ -1,4 +1,4 @@
1
- import { M as SequenceBinding, T as Conflict, a as Commands, b as Chord, v as Binding } from "./attributes-DbxlLdrb.js";
1
+ import { M as SequenceBinding, T as Conflict, a as Commands, b as Chord, v as Binding } from "./attributes-O6bXNKT9.js";
2
2
  import { Hotkey } from "@tanstack/hotkeys";
3
3
  //#region src/bindings.d.ts
4
4
  /**
@@ -37,7 +37,7 @@ interface RebindState<Id extends string = string> {
37
37
  interface RebindOptions<Id extends string = string> {
38
38
  /** Capture mode. Defaults to `"chord"`. */
39
39
  mode?: RebindMode;
40
- /** Whether to apply the recorded binding to the keymap. Defaults to `true`. */
40
+ /** Whether to write the recorded (or cleared) binding into the keymap. Defaults to `true`. */
41
41
  apply?: boolean;
42
42
  /** Whether to append rather than replace existing bindings. Defaults to `false`. */
43
43
  add?: boolean;
@@ -51,7 +51,7 @@ interface RebindOptions<Id extends string = string> {
51
51
  onRecord?: (binding: Binding, conflicts: ReadonlyArray<Conflict<Id>>) => void;
52
52
  /** Callback fired when recording is cancelled. */
53
53
  onCancel?: () => void;
54
- /** Callback fired when bindings are cleared. */
54
+ /** Callback fired when Backspace or Delete clears the binding while recording. */
55
55
  onClear?: () => void;
56
56
  }
57
57
  /** Controller instance for managing a rebinding session. */
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import { A as Platform, C as CommandDefinition, D as HotkeySequence, E as Hotkey, M as SequenceBinding, N as SerializedBinding, O as KeymapPersistence, S as CommandContext, T as Conflict, _ as formatBinding, a as Commands, b as Chord, c as PendingSequence, d as createCommands, f as CommandKeymap, g as bindingTokens, h as ariaKeyShortcuts, i as CommandId, j as ScopeOptions, k as KeymapStorage, l as RunBlockReason, m as DisplayOptions, n as observe, o as CommandsOptions, p as SerializedKeymap, r as CommandHandle, s as ConflictOptions, t as ObserveOptions, u as RunOptions, v as Binding, w as CommandSource, x as Command, y as BindingInput } from "./attributes-DbxlLdrb.js";
2
- import { a as Rebinder, c as seq, i as RebindState, l as validateBinding, n as RebindMode, o as createRebinder, r as RebindOptions, s as BindingValidation, t as ALWAYS_SCOPE } from "./index-D4UoKAQU.js";
1
+ import { A as Platform, C as CommandDefinition, D as HotkeySequence, E as Hotkey, M as SequenceBinding, N as SerializedBinding, O as KeymapPersistence, S as CommandContext, T as Conflict, _ as formatBinding, a as Commands, b as Chord, c as PendingSequence, d as createCommands, f as CommandKeymap, g as bindingTokens, h as ariaKeyShortcuts, i as CommandId, j as ScopeOptions, k as KeymapStorage, l as RunBlockReason, m as DisplayOptions, n as observe, o as CommandsOptions, p as SerializedKeymap, r as CommandHandle, s as ConflictOptions, t as ObserveOptions, u as RunOptions, v as Binding, w as CommandSource, x as Command, y as BindingInput } from "./attributes-O6bXNKT9.js";
2
+ import { a as Rebinder, c as seq, i as RebindState, l as validateBinding, n as RebindMode, o as createRebinder, r as RebindOptions, s as BindingValidation, t as ALWAYS_SCOPE } from "./index-B5iiRwCy.js";
3
3
  export { ALWAYS_SCOPE, type Binding, type BindingInput, type BindingValidation, type Chord, type Command, type CommandContext, type CommandDefinition, type CommandHandle, type CommandId, type CommandKeymap, type CommandSource, type Commands, type CommandsOptions, type Conflict, type ConflictOptions, type DisplayOptions, type Hotkey, type HotkeySequence, type KeymapPersistence, type KeymapStorage, type ObserveOptions, type PendingSequence, type Platform, type RebindMode, type RebindOptions, type RebindState, type Rebinder, type RunBlockReason, type RunOptions, type ScopeOptions, type SequenceBinding, type SerializedBinding, type SerializedKeymap, ariaKeyShortcuts, bindingTokens, createCommands, createRebinder, formatBinding, observe, seq, validateBinding };
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  import { observe } from "./attributes.js";
2
- import { a as bindingTokens, c as seq, i as ariaKeyShortcuts, n as ALWAYS_SCOPE, o as formatBinding, r as createRebinder, t as createCommands, u as validateBinding } from "./src-DyFUgmho.js";
2
+ import { a as bindingTokens, c as seq, i as ariaKeyShortcuts, n as ALWAYS_SCOPE, o as formatBinding, r as createRebinder, t as createCommands, u as validateBinding } from "./src-DWmUPZSL.js";
3
3
  export { ALWAYS_SCOPE, ariaKeyShortcuts, bindingTokens, createCommands, createRebinder, formatBinding, observe, seq, validateBinding };
package/dist/react.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { A as Platform, C as CommandDefinition, D as HotkeySequence, E as Hotkey, M as SequenceBinding, N as SerializedBinding, O as KeymapPersistence, S as CommandContext, T as Conflict, _ as formatBinding, a as Commands, b as Chord, c as PendingSequence, d as createCommands, f as CommandKeymap, g as bindingTokens, h as ariaKeyShortcuts, i as CommandId, j as ScopeOptions, k as KeymapStorage, l as RunBlockReason, m as DisplayOptions, n as observe, o as CommandsOptions, p as SerializedKeymap, r as CommandHandle, s as ConflictOptions, t as ObserveOptions, u as RunOptions, v as Binding, w as CommandSource, x as Command, y as BindingInput } from "./attributes-DbxlLdrb.js";
2
- import { a as Rebinder, c as seq, i as RebindState, l as validateBinding, n as RebindMode, o as createRebinder, r as RebindOptions, s as BindingValidation, t as ALWAYS_SCOPE } from "./index-D4UoKAQU.js";
1
+ import { A as Platform, C as CommandDefinition, D as HotkeySequence, E as Hotkey, M as SequenceBinding, N as SerializedBinding, O as KeymapPersistence, S as CommandContext, T as Conflict, _ as formatBinding, a as Commands, b as Chord, c as PendingSequence, d as createCommands, f as CommandKeymap, g as bindingTokens, h as ariaKeyShortcuts, i as CommandId, j as ScopeOptions, k as KeymapStorage, l as RunBlockReason, m as DisplayOptions, n as observe, o as CommandsOptions, p as SerializedKeymap, r as CommandHandle, s as ConflictOptions, t as ObserveOptions, u as RunOptions, v as Binding, w as CommandSource, x as Command, y as BindingInput } from "./attributes-O6bXNKT9.js";
2
+ import { a as Rebinder, c as seq, i as RebindState, l as validateBinding, n as RebindMode, o as createRebinder, r as RebindOptions, s as BindingValidation, t as ALWAYS_SCOPE } from "./index-B5iiRwCy.js";
3
3
  //#region src/react/hooks.d.ts
4
4
  /**
5
5
  * Mounts a commands registry for the lifecycle of the component.
package/dist/react.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { observe } from "./attributes.js";
3
- import { a as bindingTokens, c as seq, i as ariaKeyShortcuts, l as toBindings, n as ALWAYS_SCOPE, o as formatBinding, r as createRebinder, s as bindingSignature, t as createCommands, u as validateBinding } from "./src-DyFUgmho.js";
3
+ import { a as bindingTokens, c as seq, i as ariaKeyShortcuts, l as toBindings, n as ALWAYS_SCOPE, o as formatBinding, r as createRebinder, s as bindingSignature, t as createCommands, u as validateBinding } from "./src-DWmUPZSL.js";
4
4
  import { getKeyStateTracker } from "@tanstack/hotkeys";
5
5
  import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
6
6
  //#region src/react/hooks.ts
@@ -1,6 +1,10 @@
1
1
  import { HotkeyRecorder, HotkeySequenceRecorder, detectPlatform, formatForDisplay, getHotkeyManager, getSequenceManager, normalizeHotkey, validateHotkey } from "@tanstack/hotkeys";
2
2
  //#region src/bindings.ts
3
3
  /** Comparing, validating and serializing hotkey bindings. */
4
+ /** Type guard narrowing a JSON value to a string. */
5
+ function isJsonString(value) {
6
+ return typeof value === "string";
7
+ }
4
8
  /**
5
9
  * Creates a sequence binding from ordered hotkey steps.
6
10
  *
@@ -50,7 +54,7 @@ function serializeBinding(binding) {
50
54
  }
51
55
  /** Deserializes a stored value into a valid binding, or `null` if invalid. */
52
56
  function deserializeBinding(value) {
53
- if (typeof value === "string") {
57
+ if (isJsonString(value)) {
54
58
  const trimmed = value.trim();
55
59
  return trimmed && isBindingValid(trimmed) ? trimmed : null;
56
60
  }
@@ -188,6 +192,7 @@ function createRebinder(registry, id, options = {}) {
188
192
  };
189
193
  const cleared = () => {
190
194
  releaseScope();
195
+ if (options.apply !== false) registry.keymap.set(id, null);
191
196
  notify({
192
197
  recording: false,
193
198
  binding: null,
@@ -208,7 +213,9 @@ function createRebinder(registry, id, options = {}) {
208
213
  onClear: cleared
209
214
  }) : new HotkeyRecorder({
210
215
  ignoreInputs: options.ignoreInputs ?? true,
211
- onRecord: (hotkey) => record(hotkey),
216
+ onRecord: (hotkey) => {
217
+ if (hotkey) record(hotkey);
218
+ },
212
219
  onCancel: cancelled,
213
220
  onClear: cleared
214
221
  });
@@ -396,6 +403,10 @@ var Binder = class {
396
403
  //#region src/keymap.ts
397
404
  /** Keymap managing default bindings and user overrides. */
398
405
  const DEFAULT_STORAGE_KEY = "inklu.keys";
406
+ /** Type guard narrowing a JSON value to a plain object (excludes arrays and `null`). */
407
+ function isJsonObject(value) {
408
+ return typeof value === "object" && value !== null && !Array.isArray(value);
409
+ }
399
410
  var Keymap = class {
400
411
  #defaults = /* @__PURE__ */ new Map();
401
412
  #overrides = /* @__PURE__ */ new Map();
@@ -445,9 +456,7 @@ var Keymap = class {
445
456
  }
446
457
  /** Exports user overrides as a serialized keymap object. */
447
458
  export() {
448
- const data = {};
449
- for (const [id, bindings] of this.#overrides) data[id] = bindings.map(serializeBinding);
450
- return data;
459
+ return Object.fromEntries(Array.from(this.#overrides, ([id, bindings]) => [id, bindings.map(serializeBinding)]));
451
460
  }
452
461
  /** Imports serialized user overrides and saves to storage. */
453
462
  import(data) {
@@ -462,8 +471,10 @@ var Keymap = class {
462
471
  const raw = storage.getItem(this.#storageKey());
463
472
  if (!raw) return;
464
473
  this.#read(JSON.parse(raw));
465
- for (const listener of this.#listeners) listener();
466
- } catch {}
474
+ } catch {
475
+ return;
476
+ }
477
+ for (const listener of this.#listeners) listener();
467
478
  }
468
479
  /** Subscribes to keymap changes. Returns an unsubscribe function. */
469
480
  subscribe(listener) {
@@ -473,7 +484,7 @@ var Keymap = class {
473
484
  };
474
485
  }
475
486
  #read(data) {
476
- if (typeof data !== "object" || data === null) return;
487
+ if (!isJsonObject(data)) return;
477
488
  this.#overrides.clear();
478
489
  for (const [id, value] of Object.entries(data)) {
479
490
  if (!Array.isArray(value)) continue;
@@ -638,7 +649,7 @@ var CommandRegistry = class {
638
649
  try {
639
650
  return definition.when() === false ? "guarded" : null;
640
651
  } catch (error) {
641
- this.#reportError(error, {
652
+ this.#reportError(toError(error), {
642
653
  id,
643
654
  source: "api",
644
655
  commands: this
@@ -660,9 +671,14 @@ var CommandRegistry = class {
660
671
  if (this.#mounts > 0) this.#binder.sync(id);
661
672
  this.#invalidate();
662
673
  this.#auditAdded(id);
674
+ let disposed = false;
663
675
  return {
664
- run: (options) => this.run(id, options),
665
- dispose: () => this.#pop(id, entry)
676
+ run: (options) => !disposed && this.run(id, options),
677
+ dispose: () => {
678
+ if (disposed) return;
679
+ disposed = true;
680
+ this.#pop(id, entry);
681
+ }
666
682
  };
667
683
  }
668
684
  remove(loose) {
@@ -898,13 +914,13 @@ var CommandRegistry = class {
898
914
  if (this.#options.onRun) try {
899
915
  this.#options.onRun(full);
900
916
  } catch (error) {
901
- this.#reportError(error, full);
917
+ this.#reportError(toError(error), full);
902
918
  }
903
919
  try {
904
920
  const result = definition.run(full);
905
- if (result instanceof Promise) result.catch((error) => this.#reportError(error, full));
921
+ if (result instanceof Promise) result.catch((cause) => this.#reportError(toError(cause), full));
906
922
  } catch (error) {
907
- this.#reportError(error, full);
923
+ this.#reportError(toError(error), full);
908
924
  }
909
925
  }
910
926
  #reportError(error, context) {
@@ -1014,7 +1030,11 @@ var CommandRegistry = class {
1014
1030
  }
1015
1031
  };
1016
1032
  function describeBinding(binding) {
1017
- return typeof binding === "string" ? `"${binding}"` : `"${binding.sequence.join(" ")}"`;
1033
+ return isSequence(binding) ? `"${binding.sequence.join(" ")}"` : `"${binding}"`;
1034
+ }
1035
+ /** Normalizes an arbitrary thrown value into a real `Error` at the catch boundary. */
1036
+ function toError(cause) {
1037
+ return cause instanceof Error ? cause : new Error(String(cause));
1018
1038
  }
1019
1039
  function isDevelopment() {
1020
1040
  const environment = globalThis.process?.env?.NODE_ENV;
package/package.json CHANGED
@@ -1,22 +1,37 @@
1
1
  {
2
2
  "name": "@inklu/keys",
3
- "version": "1.2.3",
3
+ "version": "1.4.0",
4
4
  "description": "A command system for the web — typed commands, portable keybindings, scopes, sequences, conflict detection, rebinding, and platform-aware display.",
5
5
  "keywords": [
6
- "keyboard",
7
- "shortcuts",
8
- "hotkeys",
9
- "keybindings",
6
+ "accessibility",
10
7
  "command-palette",
11
8
  "commands",
9
+ "hotkeys",
10
+ "keybindings",
11
+ "keyboard",
12
+ "react",
12
13
  "scopes",
13
14
  "sequences",
14
- "accessibility",
15
- "react"
15
+ "shortcuts"
16
16
  ],
17
+ "homepage": "https://github.com/nkurunziza-saddy/inklu#readme",
18
+ "bugs": {
19
+ "url": "https://github.com/nkurunziza-saddy/inklu/issues"
20
+ },
17
21
  "license": "MIT",
18
22
  "author": "nkurunziza-saddy",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/nkurunziza-saddy/inklu.git",
26
+ "directory": "packages/keys"
27
+ },
28
+ "files": [
29
+ "dist",
30
+ "README.md",
31
+ "LICENSE"
32
+ ],
19
33
  "type": "module",
34
+ "sideEffects": false,
20
35
  "main": "./dist/index.js",
21
36
  "module": "./dist/index.js",
22
37
  "types": "./dist/index.d.ts",
@@ -38,61 +53,47 @@
38
53
  },
39
54
  "./package.json": "./package.json"
40
55
  },
41
- "sideEffects": false,
42
- "files": [
43
- "dist",
44
- "README.md",
45
- "LICENSE"
46
- ],
47
- "engines": {
48
- "node": ">=18"
56
+ "publishConfig": {
57
+ "access": "public"
49
58
  },
50
59
  "dependencies": {
51
60
  "@tanstack/hotkeys": "0.8.0"
52
61
  },
53
- "peerDependencies": {
54
- "react": "^18.0.0 || ^19.0.0"
55
- },
56
- "peerDependenciesMeta": {
57
- "react": {
58
- "optional": true
59
- }
60
- },
61
62
  "devDependencies": {
63
+ "@inklu/tsconfig": "1.0.0",
62
64
  "@testing-library/react": "^16.3.2",
63
65
  "@types/react": "^19",
64
- "@vitest/coverage-v8": "^4.1.10",
66
+ "@vitest/coverage-v8": "4.1.11",
65
67
  "jsdom": "^29.1.1",
66
68
  "react": "19.2.8",
67
69
  "react-dom": "19.2.8",
68
- "tsdown": "^0.22.14",
69
70
  "typescript": "^5.8.2",
70
- "vitest": "^4.1.10",
71
- "@inklu/tsconfig": "1.0.0"
71
+ "vite": "npm:@voidzero-dev/vite-plus-core@0.3.0",
72
+ "vite-plus": "0.3.0",
73
+ "vitest": "4.1.11"
72
74
  },
73
- "repository": {
74
- "type": "git",
75
- "url": "git+https://github.com/nkurunziza-saddy/inklu.git",
76
- "directory": "packages/keys"
75
+ "peerDependencies": {
76
+ "react": "^18.0.0 || ^19.0.0"
77
77
  },
78
- "homepage": "https://github.com/nkurunziza-saddy/inklu#readme",
79
- "bugs": {
80
- "url": "https://github.com/nkurunziza-saddy/inklu/issues"
78
+ "peerDependenciesMeta": {
79
+ "react": {
80
+ "optional": true
81
+ }
81
82
  },
82
- "publishConfig": {
83
- "access": "public"
83
+ "engines": {
84
+ "node": ">=18"
84
85
  },
85
86
  "scripts": {
86
- "build": "tsdown",
87
+ "build": "vp pack",
87
88
  "lint:exports": "publint",
88
- "dev": "tsdown --watch",
89
- "lint": "biome lint",
90
- "check": "biome check",
91
- "format": "biome format --write",
89
+ "dev": "vp pack --watch",
90
+ "lint": "vp lint",
91
+ "check": "vp check",
92
+ "format": "vp fmt --write",
92
93
  "check-types": "tsc --noEmit",
93
94
  "typecheck": "tsc --noEmit",
94
- "test": "vitest run",
95
- "test:watch": "vitest",
96
- "test:coverage": "vitest run --coverage"
95
+ "test": "vp test run",
96
+ "test:watch": "vp test",
97
+ "test:coverage": "vp test run --coverage"
97
98
  }
98
99
  }