@tanstack/hotkeys-devtools 1.3.5 → 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.
@@ -2,6 +2,7 @@ import { effectiveSequenceMatchedSteps } from "../sequence-progress.js";
2
2
  import { useHotkeysDevtoolsState } from "../HotkeysContextProvider.js";
3
3
  import { useStyles } from "../styles/use-styles.js";
4
4
  import { formatRegistration, getBindingKind, useRegistrationConflicts } from "../_registrations.js";
5
+ import { groupByScope, scopeStatusDescriptions } from "../_scopes.js";
5
6
  import { className, createComponent, delegateEvents, effect, insert, memo, template } from "solid-js/web";
6
7
  import { For, Show, createEffect, createMemo, createSignal, on } from "solid-js";
7
8
  import { formatForDisplay } from "@tanstack/hotkeys";
@@ -15,16 +16,17 @@ var _tmpl$3 = /*#__PURE__*/ template(`<span>`);
15
16
  var _tmpl$4 = /*#__PURE__*/ template(`<span>x`);
16
17
  var _tmpl$5 = /*#__PURE__*/ template(`<span>seq`);
17
18
  var _tmpl$6 = /*#__PURE__*/ template(`<span>custom<span data-tooltip>The user changed this app hotkey from its default`);
18
- var _tmpl$7 = /*#__PURE__*/ template(`<div><span><span></span></span><div><span data-binding-kind></span><span><span data-tooltip></span></span><span><span data-tooltip>Fires on <!> event</span></span><span><span data-tooltip>`);
19
+ var _tmpl$7 = /*#__PURE__*/ template(`<div><span data-row-label><span></span></span><div><span data-binding-kind></span><span><span data-tooltip></span></span><span><span data-tooltip>Fires on <!> event</span></span><span><span data-tooltip>`);
19
20
  var _tmpl$8 = /*#__PURE__*/ template(`<span><span data-tooltip>`);
20
21
  var _tmpl$9 = /*#__PURE__*/ template(`<span>i<span data-tooltip>`);
21
22
  var _tmpl$0 = /*#__PURE__*/ template(`<span>custom`);
22
- var _tmpl$1 = /*#__PURE__*/ template(`<div><span><span></span><span></span></span><div><span><span data-tooltip>`);
23
+ var _tmpl$1 = /*#__PURE__*/ template(`<div><span data-row-label><span></span><span></span></span><div><span><span data-tooltip>`);
23
24
  var _tmpl$10 = /*#__PURE__*/ template(`<button>&times;`);
24
25
  var _tmpl$11 = /*#__PURE__*/ template(`<div><input type=text placeholder="Search hotkeys...">`);
25
26
  var _tmpl$12 = /*#__PURE__*/ template(`<div>Hotkeys (<!>)`);
26
27
  var _tmpl$13 = /*#__PURE__*/ template(`<div>`);
27
28
  var _tmpl$14 = /*#__PURE__*/ template(`<div>Declared, not registered (<!>)`);
29
+ var _tmpl$15 = /*#__PURE__*/ template(`<div><div><span><span> scope</span></span><span></span><span><span data-tooltip>`);
28
30
  function getTargetLabel(target) {
29
31
  if (typeof document !== "undefined" && target === document) return "document";
30
32
  if (typeof window !== "undefined" && target === window) return "window";
@@ -95,9 +97,9 @@ function RegistrationRow(props) {
95
97
  const targetConflictBadge = () => ({
96
98
  style: "badgeConflict",
97
99
  label: "!",
98
- tooltip: `Potential overlap: ${targetConflicts().length} other bindings on overlapping targets`
100
+ tooltip: `Potential overlap: ${targetConflicts().length} other bindings in the same scope on overlapping targets`
99
101
  });
100
- const scopeConflictTooltip = () => `Info: ${scopeConflicts().length} related bindings on separate targets`;
102
+ const scopeConflictTooltip = () => `Info: ${scopeConflicts().length} related bindings in other scopes or on separate targets`;
101
103
  const enabled = () => props.reg.options.enabled !== false;
102
104
  const liveReg = createMemo(() => state.registrations().find((r) => r.id === props.reg.id) ?? props.reg);
103
105
  const triggerCount = () => liveReg().triggerCount;
@@ -274,6 +276,17 @@ function AppHotkeyRow(props) {
274
276
  return () => _c$3() ? formatForDisplay(hotkey(), { sequenceSeparator: " → " }) : "Unassigned";
275
277
  })());
276
278
  insert(_el$31, () => props.item.appHotkey.meta?.name ?? props.item.appHotkey.id);
279
+ insert(_el$32, createComponent(Show, {
280
+ get when() {
281
+ return props.item.appHotkey.scope;
282
+ },
283
+ children: (scope) => (() => {
284
+ var _el$36 = _tmpl$3();
285
+ insert(_el$36, scope);
286
+ effect(() => className(_el$36, clsx(styles().badge, styles().badgeTarget)));
287
+ return _el$36;
288
+ })()
289
+ }), _el$34);
277
290
  insert(_el$32, createComponent(Show, {
278
291
  get when() {
279
292
  return props.item.isCustom;
@@ -325,9 +338,11 @@ function HotkeyList(props) {
325
338
  (r) => typeof r.hotkey === "string" ? r.hotkey : r.hotkey.join(" "),
326
339
  "options.meta.name",
327
340
  "options.meta.description",
328
- "options.meta.group"
341
+ "options.meta.group",
342
+ "options.scope"
329
343
  ] });
330
344
  });
345
+ const scopeGroups = createMemo(() => groupByScope(filteredRegistrations(), state.scopes()));
331
346
  const filteredAppHotkeys = createMemo(() => {
332
347
  const unregistered = state.appHotkeys().filter((item) => item.registrations.length === 0);
333
348
  const query = searchQuery().trim();
@@ -336,65 +351,98 @@ function HotkeyList(props) {
336
351
  "appHotkey.id",
337
352
  "appHotkey.meta.name",
338
353
  "appHotkey.meta.description",
339
- "appHotkey.meta.group"
354
+ "appHotkey.meta.group",
355
+ "appHotkey.scope"
340
356
  ] });
341
357
  });
342
358
  return [
343
359
  (() => {
344
- var _el$36 = _tmpl$11(), _el$37 = _el$36.firstChild;
345
- _el$37.$$input = (e) => setSearchQuery(e.currentTarget.value);
346
- insert(_el$36, createComponent(Show, {
360
+ var _el$37 = _tmpl$11(), _el$38 = _el$37.firstChild;
361
+ _el$38.$$input = (e) => setSearchQuery(e.currentTarget.value);
362
+ insert(_el$37, createComponent(Show, {
347
363
  get when() {
348
364
  return searchQuery();
349
365
  },
350
366
  get children() {
351
- var _el$38 = _tmpl$10();
352
- _el$38.$$click = () => setSearchQuery("");
353
- effect(() => className(_el$38, styles().searchClear));
354
- return _el$38;
367
+ var _el$39 = _tmpl$10();
368
+ _el$39.$$click = () => setSearchQuery("");
369
+ effect(() => className(_el$39, styles().searchClear));
370
+ return _el$39;
355
371
  }
356
372
  }), null);
357
373
  effect((_p$) => {
358
374
  var _v$23 = styles().searchContainer, _v$24 = styles().searchInput;
359
- _v$23 !== _p$.e && className(_el$36, _p$.e = _v$23);
360
- _v$24 !== _p$.t && className(_el$37, _p$.t = _v$24);
375
+ _v$23 !== _p$.e && className(_el$37, _p$.e = _v$23);
376
+ _v$24 !== _p$.t && className(_el$38, _p$.t = _v$24);
361
377
  return _p$;
362
378
  }, {
363
379
  e: void 0,
364
380
  t: void 0
365
381
  });
366
- effect(() => _el$37.value = searchQuery());
367
- return _el$36;
382
+ effect(() => _el$38.value = searchQuery());
383
+ return _el$37;
368
384
  })(),
369
385
  (() => {
370
- var _el$39 = _tmpl$12(), _el$42 = _el$39.firstChild.nextSibling;
371
- _el$42.nextSibling;
372
- insert(_el$39, () => filteredRegistrations().length, _el$42);
373
- effect(() => className(_el$39, styles().panelHeader));
374
- return _el$39;
386
+ var _el$40 = _tmpl$12(), _el$43 = _el$40.firstChild.nextSibling;
387
+ _el$43.nextSibling;
388
+ insert(_el$40, () => filteredRegistrations().length, _el$43);
389
+ effect(() => className(_el$40, styles().panelHeader));
390
+ return _el$40;
375
391
  })(),
376
392
  (() => {
377
- var _el$43 = _tmpl$13();
378
- insert(_el$43, createComponent(For, {
393
+ var _el$44 = _tmpl$13();
394
+ insert(_el$44, createComponent(For, {
379
395
  get each() {
380
- return filteredRegistrations();
396
+ return scopeGroups();
381
397
  },
382
- children: (reg) => createComponent(RegistrationRow, {
383
- reg,
384
- appHotkey: () => reg.options.appHotkeyId === void 0 ? void 0 : appHotkeyById().get(reg.options.appHotkeyId),
385
- get sequenceProgressNow() {
386
- return state.sequenceProgressNow;
387
- },
388
- get selectedId() {
389
- return props.selectedId;
390
- },
391
- get setSelectedId() {
392
- return props.setSelectedId;
393
- }
394
- })
398
+ children: (group) => (() => {
399
+ var _el$50 = _tmpl$15(), _el$51 = _el$50.firstChild, _el$52 = _el$51.firstChild, _el$53 = _el$52.firstChild, _el$54 = _el$52.nextSibling, _el$55 = _el$54.nextSibling, _el$56 = _el$55.firstChild;
400
+ insert(_el$52, () => group.scope, _el$53);
401
+ insert(_el$54, () => group.registrations.length);
402
+ insert(_el$55, () => group.status, _el$56);
403
+ insert(_el$56, () => scopeStatusDescriptions[group.status]);
404
+ insert(_el$50, createComponent(For, {
405
+ get each() {
406
+ return group.registrations;
407
+ },
408
+ children: (reg) => createComponent(RegistrationRow, {
409
+ reg,
410
+ appHotkey: () => reg.options.appHotkeyId === void 0 ? void 0 : appHotkeyById().get(reg.options.appHotkeyId),
411
+ get sequenceProgressNow() {
412
+ return state.sequenceProgressNow;
413
+ },
414
+ get selectedId() {
415
+ return props.selectedId;
416
+ },
417
+ get setSelectedId() {
418
+ return props.setSelectedId;
419
+ }
420
+ })
421
+ }), null);
422
+ effect((_p$) => {
423
+ var _v$25 = clsx(styles().scopeGroup, (group.status === "suspended" || group.status === "inactive") && styles().scopeGroupDimmed), _v$26 = styles().scopeHeader, _v$27 = styles().scopeName, _v$28 = styles().scopeNameSuffix, _v$29 = styles().scopeCount, _v$30 = clsx(styles().badge, styles().tooltip, group.status === "exclusive" ? styles().badgeExclusive : group.status === "allowed" ? styles().badgeInfo : group.status === "active" ? styles().badgeEnabled : group.status === "suspended" ? styles().badgeSuspended : styles().badgeDisabled), _v$31 = styles().tooltipText;
424
+ _v$25 !== _p$.e && className(_el$50, _p$.e = _v$25);
425
+ _v$26 !== _p$.t && className(_el$51, _p$.t = _v$26);
426
+ _v$27 !== _p$.a && className(_el$52, _p$.a = _v$27);
427
+ _v$28 !== _p$.o && className(_el$53, _p$.o = _v$28);
428
+ _v$29 !== _p$.i && className(_el$54, _p$.i = _v$29);
429
+ _v$30 !== _p$.n && className(_el$55, _p$.n = _v$30);
430
+ _v$31 !== _p$.s && className(_el$56, _p$.s = _v$31);
431
+ return _p$;
432
+ }, {
433
+ e: void 0,
434
+ t: void 0,
435
+ a: void 0,
436
+ o: void 0,
437
+ i: void 0,
438
+ n: void 0,
439
+ s: void 0
440
+ });
441
+ return _el$50;
442
+ })()
395
443
  }));
396
- effect(() => className(_el$43, styles().hotkeyList));
397
- return _el$43;
444
+ effect(() => className(_el$44, styles().hotkeyList));
445
+ return _el$44;
398
446
  })(),
399
447
  createComponent(Show, {
400
448
  get when() {
@@ -402,14 +450,14 @@ function HotkeyList(props) {
402
450
  },
403
451
  get children() {
404
452
  return [(() => {
405
- var _el$44 = _tmpl$14(), _el$47 = _el$44.firstChild.nextSibling;
406
- _el$47.nextSibling;
407
- insert(_el$44, () => filteredAppHotkeys().length, _el$47);
408
- effect(() => className(_el$44, styles().panelHeader));
409
- return _el$44;
453
+ var _el$45 = _tmpl$14(), _el$48 = _el$45.firstChild.nextSibling;
454
+ _el$48.nextSibling;
455
+ insert(_el$45, () => filteredAppHotkeys().length, _el$48);
456
+ effect(() => className(_el$45, styles().panelHeader));
457
+ return _el$45;
410
458
  })(), (() => {
411
- var _el$48 = _tmpl$13();
412
- insert(_el$48, createComponent(For, {
459
+ var _el$49 = _tmpl$13();
460
+ insert(_el$49, createComponent(For, {
413
461
  get each() {
414
462
  return filteredAppHotkeys();
415
463
  },
@@ -423,8 +471,8 @@ function HotkeyList(props) {
423
471
  }
424
472
  })
425
473
  }));
426
- effect(() => className(_el$48, styles().hotkeyList));
427
- return _el$48;
474
+ effect(() => className(_el$49, styles().hotkeyList));
475
+ return _el$49;
428
476
  })()];
429
477
  }
430
478
  })
@@ -27,7 +27,7 @@ function Shell() {
27
27
  const styles = useStyles();
28
28
  const state = useHotkeysDevtoolsState();
29
29
  const [selectedId, setSelectedId] = createSignal(null);
30
- const [leftPanelWidth, setLeftPanelWidth] = createSignal(300);
30
+ const [leftPanelWidth, setLeftPanelWidth] = createSignal(440);
31
31
  const [isDragging, setIsDragging] = createSignal(false);
32
32
  const [shellRootEl, setShellRootEl] = createSignal(null);
33
33
  const [slotHeightPx, setSlotHeightPx] = createSignal(void 0);
@@ -160,6 +160,7 @@ const stylesFactory = (theme) => {
160
160
  leftPanelScroll: css`
161
161
  flex: 1;
162
162
  min-height: 0;
163
+ overflow-x: hidden;
163
164
  overflow-y: auto;
164
165
  `,
165
166
  rightPanel: css`
@@ -237,6 +238,40 @@ const stylesFactory = (theme) => {
237
238
  `,
238
239
  hotkeyList: css`
239
240
  padding: ${size[1]};
241
+ `,
242
+ scopeGroup: css`
243
+ margin-bottom: ${size[2]};
244
+ `,
245
+ scopeGroupDimmed: css`
246
+ & [data-row-label] {
247
+ opacity: 0.55;
248
+ }
249
+ `,
250
+ scopeHeader: css`
251
+ display: flex;
252
+ align-items: center;
253
+ gap: ${size[1.5]};
254
+ padding: ${size[1]} ${size[1]} ${size[1.5]};
255
+ position: sticky;
256
+ top: 0;
257
+ z-index: 3;
258
+ background: ${t(colors.gray[100], colors.darkGray[800])};
259
+ `,
260
+ scopeName: css`
261
+ font-family: ${fontFamily.mono};
262
+ font-size: ${fontSize.sm};
263
+ font-weight: ${font.weight.bold};
264
+ color: ${t(colors.gray[800], colors.gray[200])};
265
+ `,
266
+ scopeNameSuffix: css`
267
+ font-family: ${fontFamily.sans};
268
+ font-weight: ${font.weight.normal};
269
+ color: ${t(colors.gray[500], colors.gray[400])};
270
+ `,
271
+ scopeCount: css`
272
+ font-size: ${fontSize.xs};
273
+ color: ${t(colors.gray[500], colors.gray[400])};
274
+ margin-right: auto;
240
275
  `,
241
276
  hotkeyRow: css`
242
277
  display: flex;
@@ -249,14 +284,19 @@ const stylesFactory = (theme) => {
249
284
  cursor: pointer;
250
285
  transition: all 0.2s ease;
251
286
  border: 1px solid transparent;
287
+ position: relative;
252
288
 
253
289
  &:hover {
254
290
  background: ${t(colors.gray[300], colors.darkGray[600])};
255
291
  border-color: ${t(colors.gray[400], colors.darkGray[500])};
292
+ /* Lift the row so its tooltips render above the rows after it. */
293
+ z-index: 2;
256
294
  }
257
295
  `,
258
296
  hotkeyRowInactive: css`
259
- opacity: 0.65;
297
+ & > [data-row-label] {
298
+ opacity: 0.65;
299
+ }
260
300
  border-style: dashed;
261
301
  border-color: ${t(colors.gray[400], colors.darkGray[500])};
262
302
  `,
@@ -360,6 +400,14 @@ const stylesFactory = (theme) => {
360
400
  badgeAllow: css`
361
401
  color: ${t(colors.gray[600], colors.gray[400])};
362
402
  background: ${t(colors.gray[200], colors.darkGray[600])};
403
+ `,
404
+ badgeExclusive: css`
405
+ color: ${t(colors.purple[700], colors.purple[400])};
406
+ background: ${t(colors.purple[100], colors.purple[900] + alpha[30])};
407
+ `,
408
+ badgeSuspended: css`
409
+ color: ${t(colors.yellow[700], colors.yellow[400])};
410
+ background: ${t(colors.yellow[100], colors.yellow[900] + alpha[30])};
363
411
  `,
364
412
  badgeInfo: css`
365
413
  color: ${t(colors.blue[700], colors.blue[400])};
@@ -635,15 +683,16 @@ const stylesFactory = (theme) => {
635
683
  tooltip: css`
636
684
  position: relative;
637
685
  &:hover > [data-tooltip] {
686
+ display: block;
638
687
  opacity: 1;
639
688
  visibility: visible;
640
689
  }
641
690
  `,
642
691
  tooltipText: css`
692
+ display: none;
643
693
  position: absolute;
644
694
  top: 100%;
645
- left: 50%;
646
- transform: translateX(-50%);
695
+ right: 0;
647
696
  padding: ${size[1]} ${size[1.5]};
648
697
  background: ${t(colors.gray[800], colors.darkGray[500])};
649
698
  color: ${t(colors.white, colors.gray[100])};
@@ -660,6 +709,7 @@ const stylesFactory = (theme) => {
660
709
  margin-top: ${size[1]};
661
710
  `,
662
711
  rowTooltipText: css`
712
+ display: none;
663
713
  position: absolute;
664
714
  bottom: 100%;
665
715
  left: ${size[2]};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/hotkeys-devtools",
3
- "version": "1.3.5",
3
+ "version": "1.4.0",
4
4
  "description": "Devtools for TanStack Hotkeys",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -36,7 +36,7 @@
36
36
  "dist"
37
37
  ],
38
38
  "peerDependencies": {
39
- "@tanstack/hotkeys": "0.15.0"
39
+ "@tanstack/hotkeys": "0.16.0"
40
40
  },
41
41
  "dependencies": {
42
42
  "@tanstack/devtools-ui": "^0.7.1",