hotkey-engine 0.0.0-stage → 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 HotkeyEngine contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,344 @@
1
- # Temporary Holding Version
1
+ # hotkey-engine
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ hotkey-engine یک موتور میانبر کیبورد برای React 18+ و Next.js 13+ است. API بدون رابط کاربری، دکمهٔ شناور و پنجرهٔ آماده برای مدیریت میانبرها را در یک پکیج ارائه می‌کند. کاربر می‌تواند میانبرها را ویرایش، غیرفعال یا به پیش‌فرض بازنشانی کند و انتخاب او در مرورگر ذخیره می‌شود.
4
+
5
+ ## امکانات
6
+
7
+ - میانبرهای فیزیکی و مستقل از زبان کیبورد؛ تغییر زبان کیبورد، Ctrl + K را تغییر نمی‌دهد.
8
+ - نگاشت mod به ⌘ Command در macOS و Ctrl در Windows/Linux.
9
+ - Scopeهای اولویت‌دار، جلوگیری از تداخل و تشخیص میانبرهای رزرو مرورگر/سیستم‌عامل.
10
+ - جلوگیری از اجرا داخل input، textarea و contenteditable، مگر با اجازهٔ صریح هر Action.
11
+ - ذخیره‌سازی نسخه‌دار در localStorage و سازگاری با SSR.
12
+ - پنجرهٔ قابل دسترس: focus trap، بازگردانی focus، Escape و roleهای مناسب.
13
+ - رابط آماده با تم light، dark و system، به‌همراه انگلیسی/LTR و فارسی/RTL.
14
+ - CSS مستقل و قابل شخصی‌سازی، بدون وابستگی UI خارجی.
15
+
16
+ ## نصب
17
+
18
+ ~~~bash
19
+ npm install hotkey-engine
20
+ ~~~
21
+
22
+ CSS را یک‌بار، پس از CSS پایهٔ پروژه، import کنید:
23
+
24
+ ~~~tsx
25
+ import "hotkey-engine/styles.css";
26
+ ~~~
27
+
28
+ ## شروع سریع در React
29
+
30
+ ~~~tsx
31
+ import {
32
+ HotkeyProvider,
33
+ HotkeySettingsTrigger,
34
+ type HotkeyAction,
35
+ } from "hotkey-engine";
36
+ import "hotkey-engine/styles.css";
37
+
38
+ const actions: HotkeyAction[] = [
39
+ {
40
+ id: "site-search",
41
+ label: "Open site search",
42
+ defaultShortcut: "mod+k",
43
+ editable: true,
44
+ onTrigger: () => document.getElementById("site-search")?.focus(),
45
+ },
46
+ {
47
+ id: "save-draft",
48
+ label: "Save draft",
49
+ defaultShortcut: "mod+s",
50
+ editable: true,
51
+ preventDefault: true,
52
+ onTrigger: () => saveDraft(),
53
+ },
54
+ ];
55
+
56
+ export function App() {
57
+ return (
58
+ <HotkeyProvider actions={actions}>
59
+ <input id="site-search" placeholder="Search" />
60
+ <HotkeySettingsTrigger>Keyboard shortcuts</HotkeySettingsTrigger>
61
+ </HotkeyProvider>
62
+ );
63
+ }
64
+ ~~~
65
+
66
+ دکمهٔ شناور تنظیمات به‌صورت پیش‌فرض پایینِ چپ صفحه است. HotkeySettingsTrigger اختیاری است و برای متصل‌کردن دکمه یا منوی اختصاصی شما به پنجرهٔ تنظیمات استفاده می‌شود.
67
+
68
+ ## استفاده در Next.js 13+ (App Router)
69
+
70
+ Provider را در یک Client Component بگذارید. پکیج هنگام SSR به window یا localStorage دسترسی ندارد.
71
+
72
+ ~~~tsx
73
+ // app/shortcut-provider.tsx
74
+ "use client";
75
+
76
+ import { HotkeyProvider, type HotkeyAction } from "hotkey-engine";
77
+
78
+ const actions: HotkeyAction[] = [
79
+ {
80
+ id: "search",
81
+ label: "Open search",
82
+ defaultShortcut: "mod+k",
83
+ editable: true,
84
+ onTrigger: () => console.log("open search"),
85
+ },
86
+ ];
87
+
88
+ export function ShortcutProvider({ children }: { children: React.ReactNode }) {
89
+ return <HotkeyProvider actions={actions}>{children}</HotkeyProvider>;
90
+ }
91
+ ~~~
92
+
93
+ ~~~tsx
94
+ // app/layout.tsx
95
+ import "hotkey-engine/styles.css";
96
+ import { ShortcutProvider } from "./shortcut-provider";
97
+
98
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
99
+ return (
100
+ <html lang="en">
101
+ <body><ShortcutProvider>{children}</ShortcutProvider></body>
102
+ </html>
103
+ );
104
+ }
105
+ ~~~
106
+
107
+ ## تعریف Action
108
+
109
+ ~~~ts
110
+ type HotkeyAction = {
111
+ id: string;
112
+ label: string;
113
+ defaultShortcut: string;
114
+ onTrigger: (event: KeyboardEvent) => void;
115
+ editable?: boolean;
116
+ scope?: string;
117
+ allowInEditable?: boolean;
118
+ preventDefault?: boolean;
119
+ };
120
+ ~~~
121
+
122
+ | فیلد | توضیح |
123
+ | --- | --- |
124
+ | id | شناسهٔ یکتا و پایدار. |
125
+ | label | نام Action در پنجرهٔ تنظیمات. |
126
+ | defaultShortcut | مانند mod+k، ctrl+shift+n یا alt+arrowleft. |
127
+ | onTrigger | تابع اجراشونده پس از تطابق میانبر. |
128
+ | editable | اگر false باشد، کاربر نمی‌تواند آن را ویرایش یا غیرفعال کند. |
129
+ | scope | نام Scope؛ اگر مشخص نشود global است. |
130
+ | allowInEditable | اجازهٔ اجرا هنگام تمرکز روی input، textarea یا contenteditable. پیش‌فرض: false. |
131
+ | preventDefault | پیش از اجرا event.preventDefault() را فراخوانی می‌کند. |
132
+
133
+ کلیدهای پشتیبانی‌شده: حروف، اعداد، F1 تا F12، enter، escape، space، tab، backspace، delete، arrowup، arrowdown، arrowleft، arrowright و slash. Modifierها: ctrl، alt، shift، meta و mod.
134
+
135
+ ## باز و بسته کردن پنجره
136
+
137
+ ~~~tsx
138
+ import { useHotkeySettings } from "hotkey-engine";
139
+
140
+ function ShortcutMenuItem() {
141
+ const { openSettings, closeSettings, open } = useHotkeySettings();
142
+
143
+ return (
144
+ <>
145
+ <button onClick={openSettings}>Manage shortcuts</button>
146
+ {open && <button onClick={closeSettings}>Close settings</button>}
147
+ </>
148
+ );
149
+ }
150
+ ~~~
151
+
152
+ useHotkeySettings() باید زیر HotkeyProvider استفاده شود.
153
+
154
+ ## Scope و اولویت
155
+
156
+ میانبرهای Scope فعال از global اولویت بیشتری دارند. اگر چند Scope فعال باشند، آخرین Scope فعال‌شده اول بررسی می‌شود.
157
+
158
+ ~~~tsx
159
+ import { useHotkeyScope } from "hotkey-engine";
160
+
161
+ function Editor() {
162
+ useHotkeyScope("editor");
163
+ return <textarea />;
164
+ }
165
+
166
+ const actions = [
167
+ { id: "global-save", label: "Save", defaultShortcut: "mod+s", onTrigger: saveSite },
168
+ { id: "editor-save", label: "Save editor", defaultShortcut: "mod+s", scope: "editor", onTrigger: saveEditor },
169
+ ];
170
+ ~~~
171
+
172
+ دو Action با یک میانبر در Scopeهای هم‌پوشان قابل ذخیره نیستند و پنجره، تداخل را به کاربر اعلام می‌کند.
173
+
174
+ ## میانبرهای رزرو مرورگر و سیستم‌عامل
175
+
176
+ به‌صورت پیش‌فرض، کاربر نمی‌تواند Ctrl/Cmd + K، L، R، W، T، N، P یا Alt + F4 را در Recorder ثبت کند؛ این‌ها معمولاً به مرورگر یا سیستم‌عامل تعلق دارند. پیام خطا کنار همان Action نشان داده می‌شود و میانبر قبلی حفظ می‌شود.
177
+
178
+ اگر توسعه‌دهنده آگاهانه بخواهد این امکان را بدهد:
179
+
180
+ ~~~tsx
181
+ <HotkeyProvider actions={actions} allowReservedShortcuts>
182
+ <App />
183
+ </HotkeyProvider>
184
+ ~~~
185
+
186
+ در این حالت، پکیج برای میانبر رزروشده preventDefault() اجرا می‌کند تا سایت بیشترین اولویت ممکن را داشته باشد. با این حال، مرورگر یا سیستم‌عامل ممکن است همچنان فرمان را کنترل کند؛ override آن در وب تضمین‌پذیر نیست.
187
+
188
+ ## تم
189
+
190
+ ~~~tsx
191
+ <HotkeyProvider actions={actions} theme="dark">
192
+ <App />
193
+ </HotkeyProvider>
194
+ ~~~
195
+
196
+ | مقدار | رفتار |
197
+ | --- | --- |
198
+ | light | رابط روشن. |
199
+ | dark | رابط تیره. |
200
+ | system | پیش‌فرض؛ براساس prefers-color-scheme. |
201
+
202
+ تم فقط UI پکیج را تغییر می‌دهد و تم سایت شما را دست‌کاری نمی‌کند.
203
+
204
+ ## زبان و RTL
205
+
206
+ انگلیسی/LTR پیش‌فرض است. برای فارسی، locale="fa" بگذارید؛ پنجره RTL می‌شود و فونت Vazir داخلی برای متن فارسی استفاده می‌شود.
207
+
208
+ ~~~tsx
209
+ <HotkeyProvider actions={actions} locale="fa">
210
+ <App />
211
+ </HotkeyProvider>
212
+ ~~~
213
+
214
+ برای تغییر زبان در زمان اجرا:
215
+
216
+ ~~~tsx
217
+ import { useHotkeyLocale } from "hotkey-engine";
218
+
219
+ function LanguageSwitch() {
220
+ const { locale, setLocale } = useHotkeyLocale();
221
+ return (
222
+ <button onClick={() => setLocale(locale === "en" ? "fa" : "en")}>
223
+ {locale === "en" ? "فارسی" : "English"}
224
+ </button>
225
+ );
226
+ }
227
+ ~~~
228
+
229
+ برای تعیین جهت مستقل از زبان، از dir="rtl" یا dir="ltr" استفاده کنید.
230
+
231
+ ## دکمهٔ شناور
232
+
233
+ ~~~tsx
234
+ <HotkeyProvider
235
+ actions={actions}
236
+ showFloatingButton
237
+ position="bottom-right"
238
+ offset={{ x: 32, y: 24 }}
239
+ zIndex={2000}
240
+ >
241
+ <App />
242
+ </HotkeyProvider>
243
+ ~~~
244
+
245
+ - showFloatingButton: پیش‌فرض true.
246
+ - position: bottom-left (پیش‌فرض)، bottom-right، top-left یا top-right.
247
+ - offset: عدد یا { x, y } برحسب پیکسل.
248
+ - zIndex: پیش‌فرض 1000.
249
+
250
+ ## شخصی‌سازی UI
251
+
252
+ رابط پکیج قابل تغییر است. ابتدا CSS پکیج و سپس stylesheet پروژهٔ خود را import کنید تا overrideها اعمال شوند.
253
+
254
+ ~~~tsx
255
+ <HotkeyProvider actions={actions} className="my-product">
256
+ <HotkeySettingsTrigger className="my-shortcut-button">
257
+ Shortcuts
258
+ </HotkeySettingsTrigger>
259
+ <App />
260
+ </HotkeyProvider>
261
+ ~~~
262
+
263
+ className روی Provider، wrapper محتوای شما و className روی HotkeySettingsTrigger، Trigger اختصاصی شماست. پنجرهٔ تنظیمات با portal در document.body رندر می‌شود؛ پس برای استایل آن از selectorهای پکیج استفاده کنید، نه selector وابسته به .my-product.
264
+
265
+ ### مثال: رنگ و گردی اختصاصی
266
+
267
+ ~~~css
268
+ /* app.css — بعد از hotkey-engine/styles.css import شود */
269
+ .hotkey-dialog[data-hotkey-theme="light"] {
270
+ --hk-header: linear-gradient(110deg, #075985, #0f766e);
271
+ --hk-text: #17324d;
272
+ --hk-muted: #52718f;
273
+ --hk-line: rgba(15, 118, 110, .18);
274
+ --hk-control: rgba(255, 255, 255, .72);
275
+ --hk-control-hover: rgba(236, 253, 245, .9);
276
+ border-radius: 24px;
277
+ }
278
+
279
+ .hotkey-floating-trigger {
280
+ background: #0f766e;
281
+ color: #fff;
282
+ border-color: transparent;
283
+ border-radius: 14px;
284
+ }
285
+
286
+ .hotkey-action-edit,
287
+ .hotkey-action-disable,
288
+ .hotkey-action-reset {
289
+ border-radius: 8px;
290
+ }
291
+ ~~~
292
+
293
+ | selector | بخش |
294
+ | --- | --- |
295
+ | .hotkey-floating-trigger | دکمهٔ شناور |
296
+ | .hotkey-overlay | لایهٔ پشت پنجره |
297
+ | .hotkey-dialog | پنجرهٔ تنظیمات |
298
+ | .hotkey-glass-header | هدر |
299
+ | .hotkey-search-wrap، .hotkey-search | جست‌وجو |
300
+ | .hotkey-action-item | ردیف هر Action |
301
+ | .hotkey-action-edit، .hotkey-action-disable، .hotkey-action-reset | دکمه‌های Action |
302
+ | .hotkey-inline-feedback | خطای تداخل/رزرو |
303
+ | .hotkey-recorder | وضعیت ثبت میانبر |
304
+
305
+ متغیرهای اصلی CSS: --hk-header، --hk-panel، --hk-control، --hk-control-hover، --hk-text، --hk-muted و --hk-line. برای تم تیره، selector را به .hotkey-dialog[data-hotkey-theme="dark"] تغییر دهید.
306
+
307
+ ## ذخیره‌سازی و بازنشانی
308
+
309
+ تنظیمات کاربر پس از mount در localStorage با کلید نسخه‌دار hotkey-engine:v1 ذخیره می‌شوند. ویرایش‌ها بلافاصله اجرا و ذخیره می‌شوند. آیکن بازنشانی هدر، همهٔ میانبرها را فوراً به حالت پیش‌فرض برمی‌گرداند.
310
+
311
+ Storage Adapter عمومی، همگام‌سازی چنددستگاهی و میانبرهای چندمرحله‌ای در این نسخه وجود ندارند.
312
+
313
+ ## API Provider
314
+
315
+ | prop | پیش‌فرض | توضیح |
316
+ | --- | --- | --- |
317
+ | actions | — | آرایهٔ Actionها؛ الزامی. |
318
+ | showFloatingButton | true | نمایش دکمهٔ شناور. |
319
+ | position | bottom-left | محل دکمهٔ شناور. |
320
+ | offset | { x: 24, y: 24 } | فاصله از لبه‌ها. |
321
+ | zIndex | 1000 | z-index دکمه. |
322
+ | theme | system | light، dark یا system. |
323
+ | locale | en | en یا fa. |
324
+ | dir | طبق locale | ltr یا rtl. |
325
+ | className | — | کلاس wrapper فرزندان Provider. |
326
+ | allowReservedShortcuts | false | اجازهٔ ثبت میانبرهای رزرو. |
327
+
328
+ ## بررسی و توسعه
329
+
330
+ ~~~bash
331
+ npm test
332
+ npm run build
333
+ npm run storybook
334
+ ~~~
335
+
336
+ برای ساخت Storybook ایستا:
337
+
338
+ ~~~bash
339
+ npm run build-storybook
340
+ ~~~
341
+
342
+ ## License
343
+
344
+ [MIT](./LICENSE)
Binary file
Binary file