@tanstack/hotkeys-devtools 0.7.4 → 0.8.1
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/dist/components/DetailsPanel.js +294 -200
- package/dist/components/DetailsPanel.js.map +1 -1
- package/dist/components/HotkeyList.js +225 -118
- package/dist/components/HotkeyList.js.map +1 -1
- package/dist/styles/use-styles.js +88 -1
- package/dist/styles/use-styles.js.map +1 -1
- package/package.json +3 -2
- package/src/components/DetailsPanel.tsx +78 -0
- package/src/components/HotkeyList.tsx +108 -20
- package/src/styles/use-styles.ts +88 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { For, Show, createEffect, createMemo, createSignal, on } from 'solid-js'
|
|
2
2
|
import clsx from 'clsx'
|
|
3
|
+
import { matchSorter } from 'match-sorter'
|
|
3
4
|
import { formatForDisplay } from '@tanstack/hotkeys'
|
|
4
5
|
import { useStyles } from '../styles/use-styles'
|
|
5
6
|
import { useHotkeysDevtoolsState } from '../HotkeysContextProvider'
|
|
@@ -113,6 +114,17 @@ function findSequenceScopeConflicts(
|
|
|
113
114
|
)
|
|
114
115
|
}
|
|
115
116
|
|
|
117
|
+
function buildRowTooltip(meta?: {
|
|
118
|
+
name?: string
|
|
119
|
+
description?: string
|
|
120
|
+
}): string | undefined {
|
|
121
|
+
if (!meta) return undefined
|
|
122
|
+
const parts: Array<string> = []
|
|
123
|
+
if (meta.name) parts.push(meta.name)
|
|
124
|
+
if (meta.description) parts.push(meta.description)
|
|
125
|
+
return parts.length > 0 ? parts.join(' — ') : undefined
|
|
126
|
+
}
|
|
127
|
+
|
|
116
128
|
function SequenceListRow(props: {
|
|
117
129
|
reg: SequenceRegistrationView
|
|
118
130
|
getSequences: () => Array<SequenceRegistrationView>
|
|
@@ -195,32 +207,46 @@ function SequenceListRow(props: {
|
|
|
195
207
|
}),
|
|
196
208
|
)
|
|
197
209
|
|
|
210
|
+
const metaName = () => props.reg.options.meta?.name
|
|
211
|
+
const rowTooltip = () => buildRowTooltip(props.reg.options.meta)
|
|
212
|
+
|
|
198
213
|
return (
|
|
199
214
|
<div
|
|
200
215
|
class={clsx(
|
|
201
216
|
styles().hotkeyRow,
|
|
202
217
|
props.selectedId() === props.reg.id && styles().hotkeyRowSelected,
|
|
203
218
|
pulsing() && styles().hotkeyRowTriggered,
|
|
219
|
+
rowTooltip() && styles().tooltip,
|
|
204
220
|
)}
|
|
205
221
|
onClick={() => props.setSelectedId(props.reg.id)}
|
|
206
222
|
>
|
|
223
|
+
<Show when={rowTooltip()}>
|
|
224
|
+
<span class={styles().rowTooltipText} data-tooltip>
|
|
225
|
+
{rowTooltip()}
|
|
226
|
+
</span>
|
|
227
|
+
</Show>
|
|
207
228
|
<span class={styles().hotkeyLabel}>
|
|
208
|
-
<
|
|
209
|
-
{(
|
|
210
|
-
|
|
211
|
-
<
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
229
|
+
<span class={styles().hotkeyLabelKeys}>
|
|
230
|
+
<For each={liveSequenceReg().sequence}>
|
|
231
|
+
{(step, i) => (
|
|
232
|
+
<span>
|
|
233
|
+
<Show when={i() > 0}> </Show>
|
|
234
|
+
<span
|
|
235
|
+
class={
|
|
236
|
+
i() < matchedSteps()
|
|
237
|
+
? styles().sequenceStepMatched
|
|
238
|
+
: undefined
|
|
239
|
+
}
|
|
240
|
+
>
|
|
241
|
+
{formatForDisplay(step)}
|
|
242
|
+
</span>
|
|
220
243
|
</span>
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
</
|
|
244
|
+
)}
|
|
245
|
+
</For>
|
|
246
|
+
</span>
|
|
247
|
+
<Show when={metaName()}>
|
|
248
|
+
<span class={styles().hotkeyLabelName}>{metaName()}</span>
|
|
249
|
+
</Show>
|
|
224
250
|
</span>
|
|
225
251
|
<Show when={triggerCount() > 0}>
|
|
226
252
|
<span class={styles().triggerCount}>x{triggerCount()}</span>
|
|
@@ -293,14 +319,62 @@ export function HotkeyList(props: HotkeyListProps) {
|
|
|
293
319
|
const styles = useStyles()
|
|
294
320
|
const state = useHotkeysDevtoolsState()
|
|
295
321
|
|
|
322
|
+
const [searchQuery, setSearchQuery] = createSignal('')
|
|
323
|
+
|
|
296
324
|
const registrations = createMemo(() => state.registrations())
|
|
297
325
|
const sequenceRegistrations = createMemo(() => state.sequenceRegistrations())
|
|
298
326
|
|
|
327
|
+
const filteredRegistrations = createMemo(() => {
|
|
328
|
+
const query = searchQuery().trim()
|
|
329
|
+
if (!query) return registrations()
|
|
330
|
+
return matchSorter(registrations(), query, {
|
|
331
|
+
keys: [
|
|
332
|
+
(r) => formatForDisplay(r.hotkey),
|
|
333
|
+
'hotkey',
|
|
334
|
+
'options.meta.name',
|
|
335
|
+
'options.meta.description',
|
|
336
|
+
],
|
|
337
|
+
})
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
const filteredSequenceRegistrations = createMemo(() => {
|
|
341
|
+
const query = searchQuery().trim()
|
|
342
|
+
if (!query) return sequenceRegistrations()
|
|
343
|
+
return matchSorter(sequenceRegistrations(), query, {
|
|
344
|
+
keys: [
|
|
345
|
+
(r) => r.sequence.map((s) => formatForDisplay(s)).join(' '),
|
|
346
|
+
(r) => r.sequence.join(' '),
|
|
347
|
+
'options.meta.name',
|
|
348
|
+
'options.meta.description',
|
|
349
|
+
],
|
|
350
|
+
})
|
|
351
|
+
})
|
|
352
|
+
|
|
299
353
|
return (
|
|
300
354
|
<>
|
|
301
|
-
<div class={styles().
|
|
355
|
+
<div class={styles().searchContainer}>
|
|
356
|
+
<input
|
|
357
|
+
type="text"
|
|
358
|
+
class={styles().searchInput}
|
|
359
|
+
placeholder="Search hotkeys..."
|
|
360
|
+
value={searchQuery()}
|
|
361
|
+
onInput={(e) => setSearchQuery(e.currentTarget.value)}
|
|
362
|
+
/>
|
|
363
|
+
<Show when={searchQuery()}>
|
|
364
|
+
<button
|
|
365
|
+
class={styles().searchClear}
|
|
366
|
+
onClick={() => setSearchQuery('')}
|
|
367
|
+
>
|
|
368
|
+
×
|
|
369
|
+
</button>
|
|
370
|
+
</Show>
|
|
371
|
+
</div>
|
|
372
|
+
|
|
373
|
+
<div class={styles().panelHeader}>
|
|
374
|
+
Hotkeys ({filteredRegistrations().length})
|
|
375
|
+
</div>
|
|
302
376
|
<div class={styles().hotkeyList}>
|
|
303
|
-
<For each={
|
|
377
|
+
<For each={filteredRegistrations()}>
|
|
304
378
|
{(reg) => {
|
|
305
379
|
const targetConflicts = () =>
|
|
306
380
|
findTargetConflicts(reg, registrations())
|
|
@@ -365,17 +439,31 @@ export function HotkeyList(props: HotkeyListProps) {
|
|
|
365
439
|
}),
|
|
366
440
|
)
|
|
367
441
|
|
|
442
|
+
const metaName = () => reg.options.meta?.name
|
|
443
|
+
const rowTooltip = () => buildRowTooltip(reg.options.meta)
|
|
444
|
+
|
|
368
445
|
return (
|
|
369
446
|
<div
|
|
370
447
|
class={clsx(
|
|
371
448
|
styles().hotkeyRow,
|
|
372
449
|
props.selectedId() === reg.id && styles().hotkeyRowSelected,
|
|
373
450
|
pulsing() && styles().hotkeyRowTriggered,
|
|
451
|
+
rowTooltip() && styles().tooltip,
|
|
374
452
|
)}
|
|
375
453
|
onClick={() => props.setSelectedId(reg.id)}
|
|
376
454
|
>
|
|
455
|
+
<Show when={rowTooltip()}>
|
|
456
|
+
<span class={styles().rowTooltipText} data-tooltip>
|
|
457
|
+
{rowTooltip()}
|
|
458
|
+
</span>
|
|
459
|
+
</Show>
|
|
377
460
|
<span class={styles().hotkeyLabel}>
|
|
378
|
-
{
|
|
461
|
+
<span class={styles().hotkeyLabelKeys}>
|
|
462
|
+
{formatForDisplay(reg.hotkey)}
|
|
463
|
+
</span>
|
|
464
|
+
<Show when={metaName()}>
|
|
465
|
+
<span class={styles().hotkeyLabelName}>{metaName()}</span>
|
|
466
|
+
</Show>
|
|
379
467
|
</span>
|
|
380
468
|
<Show when={triggerCount() > 0}>
|
|
381
469
|
<span class={styles().triggerCount}>x{triggerCount()}</span>
|
|
@@ -457,10 +545,10 @@ export function HotkeyList(props: HotkeyListProps) {
|
|
|
457
545
|
</div>
|
|
458
546
|
|
|
459
547
|
<div class={styles().panelHeader}>
|
|
460
|
-
Sequences ({
|
|
548
|
+
Sequences ({filteredSequenceRegistrations().length})
|
|
461
549
|
</div>
|
|
462
550
|
<div class={styles().hotkeyList}>
|
|
463
|
-
<For each={
|
|
551
|
+
<For each={filteredSequenceRegistrations()}>
|
|
464
552
|
{(reg) => (
|
|
465
553
|
<SequenceListRow
|
|
466
554
|
reg={reg}
|
package/src/styles/use-styles.ts
CHANGED
|
@@ -173,6 +173,55 @@ const stylesFactory = (theme: 'light' | 'dark') => {
|
|
|
173
173
|
min-width: 0;
|
|
174
174
|
overflow: hidden;
|
|
175
175
|
`,
|
|
176
|
+
searchContainer: css`
|
|
177
|
+
position: relative;
|
|
178
|
+
padding: ${size[2]};
|
|
179
|
+
padding-bottom: 0;
|
|
180
|
+
flex-shrink: 0;
|
|
181
|
+
`,
|
|
182
|
+
searchInput: css`
|
|
183
|
+
width: 100%;
|
|
184
|
+
padding: ${size[1.5]} ${size[2]};
|
|
185
|
+
padding-right: ${size[7]};
|
|
186
|
+
font-size: ${fontSize.xs};
|
|
187
|
+
font-family: ${fontFamily.sans};
|
|
188
|
+
color: ${t(colors.gray[900], colors.gray[100])};
|
|
189
|
+
background: ${t(colors.gray[200], colors.darkGray[700])};
|
|
190
|
+
border: 1px solid ${t(colors.gray[300], colors.darkGray[600])};
|
|
191
|
+
border-radius: ${border.radius.md};
|
|
192
|
+
outline: none;
|
|
193
|
+
box-sizing: border-box;
|
|
194
|
+
|
|
195
|
+
&::placeholder {
|
|
196
|
+
color: ${t(colors.gray[500], colors.gray[500])};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
&:focus {
|
|
200
|
+
border-color: ${t(colors.blue[500], colors.blue[400])};
|
|
201
|
+
box-shadow: 0 0 0 1px
|
|
202
|
+
${t(colors.blue[500] + alpha[30], colors.blue[400] + alpha[30])};
|
|
203
|
+
}
|
|
204
|
+
`,
|
|
205
|
+
searchClear: css`
|
|
206
|
+
position: absolute;
|
|
207
|
+
right: ${size[3]};
|
|
208
|
+
top: 50%;
|
|
209
|
+
transform: translateY(-50%);
|
|
210
|
+
background: none;
|
|
211
|
+
border: none;
|
|
212
|
+
color: ${t(colors.gray[500], colors.gray[400])};
|
|
213
|
+
font-size: ${fontSize.md};
|
|
214
|
+
cursor: pointer;
|
|
215
|
+
padding: ${size[1]};
|
|
216
|
+
line-height: 1;
|
|
217
|
+
display: flex;
|
|
218
|
+
align-items: center;
|
|
219
|
+
justify-content: center;
|
|
220
|
+
|
|
221
|
+
&:hover {
|
|
222
|
+
color: ${t(colors.gray[700], colors.gray[200])};
|
|
223
|
+
}
|
|
224
|
+
`,
|
|
176
225
|
panelHeader: css`
|
|
177
226
|
font-size: ${fontSize.md};
|
|
178
227
|
font-weight: ${font.weight.bold};
|
|
@@ -225,13 +274,28 @@ const stylesFactory = (theme: 'light' | 'dark') => {
|
|
|
225
274
|
}
|
|
226
275
|
`,
|
|
227
276
|
hotkeyLabel: css`
|
|
228
|
-
font-family: ${fontFamily.mono};
|
|
229
277
|
font-size: ${fontSize.xs};
|
|
230
278
|
color: ${t(colors.gray[900], colors.gray[100])};
|
|
231
279
|
flex: 1;
|
|
232
280
|
overflow: hidden;
|
|
233
281
|
text-overflow: ellipsis;
|
|
234
282
|
white-space: nowrap;
|
|
283
|
+
display: flex;
|
|
284
|
+
align-items: center;
|
|
285
|
+
gap: ${size[1.5]};
|
|
286
|
+
min-width: 0;
|
|
287
|
+
`,
|
|
288
|
+
hotkeyLabelKeys: css`
|
|
289
|
+
font-family: ${fontFamily.mono};
|
|
290
|
+
flex-shrink: 0;
|
|
291
|
+
`,
|
|
292
|
+
hotkeyLabelName: css`
|
|
293
|
+
font-family: ${fontFamily.sans};
|
|
294
|
+
color: ${t(colors.gray[500], colors.gray[400])};
|
|
295
|
+
overflow: hidden;
|
|
296
|
+
text-overflow: ellipsis;
|
|
297
|
+
white-space: nowrap;
|
|
298
|
+
min-width: 0;
|
|
235
299
|
`,
|
|
236
300
|
sequenceStepMatched: css`
|
|
237
301
|
font-weight: ${font.weight.bold};
|
|
@@ -580,6 +644,29 @@ const stylesFactory = (theme: 'light' | 'dark') => {
|
|
|
580
644
|
z-index: ${tokens.zIndices.tooltip};
|
|
581
645
|
margin-top: ${size[1]};
|
|
582
646
|
`,
|
|
647
|
+
rowTooltipText: css`
|
|
648
|
+
position: absolute;
|
|
649
|
+
bottom: 100%;
|
|
650
|
+
left: ${size[2]};
|
|
651
|
+
padding: ${size[1]} ${size[1.5]};
|
|
652
|
+
background: ${t(colors.gray[800], colors.darkGray[500])};
|
|
653
|
+
color: ${t(colors.white, colors.gray[100])};
|
|
654
|
+
font-size: ${fontSize['2xs']};
|
|
655
|
+
font-family: ${fontFamily.sans};
|
|
656
|
+
border-radius: ${border.radius.sm};
|
|
657
|
+
white-space: nowrap;
|
|
658
|
+
pointer-events: none;
|
|
659
|
+
opacity: 0;
|
|
660
|
+
visibility: hidden;
|
|
661
|
+
transition:
|
|
662
|
+
opacity 0.15s,
|
|
663
|
+
visibility 0.15s;
|
|
664
|
+
z-index: ${tokens.zIndices.tooltip};
|
|
665
|
+
margin-bottom: ${size[1]};
|
|
666
|
+
max-width: 300px;
|
|
667
|
+
overflow: hidden;
|
|
668
|
+
text-overflow: ellipsis;
|
|
669
|
+
`,
|
|
583
670
|
triggerCount: css`
|
|
584
671
|
font-family: ${fontFamily.mono};
|
|
585
672
|
font-size: ${fontSize['2xs']};
|