@tanstack/hotkeys-devtools 1.0.0 → 1.1.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/HotkeysContextProvider.js +1 -2
- package/dist/_registrations.js +1 -2
- package/dist/components/ActionButtons.js +2 -3
- package/dist/components/DetailsPanel.js +16 -3
- package/dist/components/HeldKeysTopbar.js +5 -3
- package/dist/components/HotkeyList.js +13 -3
- package/dist/components/Shell.js +5 -4
- package/dist/components/index.js +1 -2
- package/dist/core.d.ts +3 -6
- package/dist/core.js +1 -2
- package/dist/index.d.ts +2 -4
- package/dist/index.js +1 -2
- package/dist/sequence-progress.js +1 -2
- package/dist/styles/tokens.js +1 -2
- package/dist/styles/use-styles.js +5 -4
- package/package.json +11 -11
- package/dist/HotkeysContextProvider.js.map +0 -1
- package/dist/_registrations.js.map +0 -1
- package/dist/components/ActionButtons.js.map +0 -1
- package/dist/components/DetailsPanel.js.map +0 -1
- package/dist/components/HeldKeysTopbar.js.map +0 -1
- package/dist/components/HotkeyList.js.map +0 -1
- package/dist/components/Shell.js.map +0 -1
- package/dist/components/index.js.map +0 -1
- package/dist/core.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/sequence-progress.js.map +0 -1
- package/dist/styles/tokens.js.map +0 -1
- package/dist/styles/use-styles.js.map +0 -1
- package/src/HotkeysContextProvider.tsx +0 -130
- package/src/_registrations.ts +0 -59
- package/src/components/ActionButtons.tsx +0 -38
- package/src/components/DetailsPanel.tsx +0 -685
- package/src/components/HeldKeysTopbar.tsx +0 -46
- package/src/components/HotkeyList.tsx +0 -473
- package/src/components/Shell.tsx +0 -171
- package/src/components/index.tsx +0 -19
- package/src/core.tsx +0 -11
- package/src/index.ts +0 -11
- package/src/production.ts +0 -5
- package/src/sequence-progress.ts +0 -29
- package/src/styles/tokens.ts +0 -305
- package/src/styles/use-styles.ts +0 -687
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { For, Show } from 'solid-js'
|
|
2
|
-
import { detectPlatform, formatForDisplay } from '@tanstack/hotkeys'
|
|
3
|
-
import { useStyles } from '../styles/use-styles'
|
|
4
|
-
import { useHotkeysDevtoolsState } from '../HotkeysContextProvider'
|
|
5
|
-
import type { RegisterableHotkey } from '@tanstack/hotkeys'
|
|
6
|
-
|
|
7
|
-
export function HeldKeysBar() {
|
|
8
|
-
const styles = useStyles()
|
|
9
|
-
const state = useHotkeysDevtoolsState()
|
|
10
|
-
const platform = detectPlatform()
|
|
11
|
-
|
|
12
|
-
return (
|
|
13
|
-
<div class={styles().heldKeysBar}>
|
|
14
|
-
<span class={styles().heldKeysBarHeader}>Held</span>
|
|
15
|
-
<div class={styles().heldKeysBarList}>
|
|
16
|
-
<Show
|
|
17
|
-
when={state.heldKeys().length > 0}
|
|
18
|
-
fallback={<span class={styles().noKeysHeld}>--</span>}
|
|
19
|
-
>
|
|
20
|
-
<For each={state.heldKeys()}>
|
|
21
|
-
{(key) => {
|
|
22
|
-
const code = () => state.heldCodes()[key]
|
|
23
|
-
const label = () =>
|
|
24
|
-
formatForDisplay(key as RegisterableHotkey, {
|
|
25
|
-
platform,
|
|
26
|
-
useSymbols: true,
|
|
27
|
-
})
|
|
28
|
-
const codeLabel = () => {
|
|
29
|
-
const c = code()
|
|
30
|
-
return c || undefined
|
|
31
|
-
}
|
|
32
|
-
return (
|
|
33
|
-
<span class={styles().keyCap}>
|
|
34
|
-
<span>{label()}</span>
|
|
35
|
-
<Show when={codeLabel() && codeLabel() !== key}>
|
|
36
|
-
<span class={styles().keyCapCode}>{codeLabel()}</span>
|
|
37
|
-
</Show>
|
|
38
|
-
</span>
|
|
39
|
-
)
|
|
40
|
-
}}
|
|
41
|
-
</For>
|
|
42
|
-
</Show>
|
|
43
|
-
</div>
|
|
44
|
-
</div>
|
|
45
|
-
)
|
|
46
|
-
}
|
|
@@ -1,473 +0,0 @@
|
|
|
1
|
-
import { For, Show, createEffect, createMemo, createSignal, on } from 'solid-js'
|
|
2
|
-
import clsx from 'clsx'
|
|
3
|
-
import { matchSorter } from 'match-sorter'
|
|
4
|
-
import { formatForDisplay } from '@tanstack/hotkeys'
|
|
5
|
-
import { useStyles } from '../styles/use-styles'
|
|
6
|
-
import { useHotkeysDevtoolsState } from '../HotkeysContextProvider'
|
|
7
|
-
import { effectiveSequenceMatchedSteps } from '../sequence-progress'
|
|
8
|
-
import {
|
|
9
|
-
formatRegistration,
|
|
10
|
-
getBindingKind,
|
|
11
|
-
useRegistrationConflicts,
|
|
12
|
-
} from '../_registrations'
|
|
13
|
-
import type { SequenceRegistrationView } from '@tanstack/hotkeys'
|
|
14
|
-
|
|
15
|
-
type HotkeyListProps = {
|
|
16
|
-
selectedId: () => string | null
|
|
17
|
-
setSelectedId: (id: string | null) => void
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function getTargetLabel(target: HTMLElement | Document | Window): string {
|
|
21
|
-
if (typeof document !== 'undefined' && target === document) {
|
|
22
|
-
return 'document'
|
|
23
|
-
}
|
|
24
|
-
if (typeof window !== 'undefined' && target === window) {
|
|
25
|
-
return 'window'
|
|
26
|
-
}
|
|
27
|
-
if (target instanceof HTMLElement) {
|
|
28
|
-
return target.tagName.toLowerCase()
|
|
29
|
-
}
|
|
30
|
-
return 'element'
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function getTargetTooltip(target: HTMLElement | Document | Window): string {
|
|
34
|
-
if (typeof document !== 'undefined' && target === document) {
|
|
35
|
-
return 'Listening on document'
|
|
36
|
-
}
|
|
37
|
-
if (typeof window !== 'undefined' && target === window) {
|
|
38
|
-
return 'Listening on window'
|
|
39
|
-
}
|
|
40
|
-
if (target instanceof HTMLElement) {
|
|
41
|
-
const tag = target.tagName.toLowerCase()
|
|
42
|
-
const parts: Array<string> = [tag]
|
|
43
|
-
if (target.id) {
|
|
44
|
-
parts.push(`id="${target.id}"`)
|
|
45
|
-
}
|
|
46
|
-
if (target.className) {
|
|
47
|
-
const classes = target.className.split(/\s+/).filter(Boolean).join(', ')
|
|
48
|
-
parts.push(`class="${classes}"`)
|
|
49
|
-
}
|
|
50
|
-
// Collect data- attributes
|
|
51
|
-
const dataAttrs = Array.from(target.attributes)
|
|
52
|
-
.filter((attr) => attr.name.startsWith('data-'))
|
|
53
|
-
.map((attr) => `${attr.name}="${attr.value}"`)
|
|
54
|
-
if (dataAttrs.length > 0) {
|
|
55
|
-
parts.push(...dataAttrs)
|
|
56
|
-
}
|
|
57
|
-
return `Listening on ${parts.join(' ')}`
|
|
58
|
-
}
|
|
59
|
-
return 'Listening on element'
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function buildRowTooltip(meta?: {
|
|
63
|
-
name?: string
|
|
64
|
-
description?: string
|
|
65
|
-
group?: string
|
|
66
|
-
}): string | undefined {
|
|
67
|
-
if (!meta) return undefined
|
|
68
|
-
const parts: Array<string> = []
|
|
69
|
-
if (meta.group) parts.push(meta.group)
|
|
70
|
-
if (meta.name) parts.push(meta.name)
|
|
71
|
-
if (meta.description) parts.push(meta.description)
|
|
72
|
-
return parts.length > 0 ? parts.join(' — ') : undefined
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function SequenceListRow(props: {
|
|
76
|
-
reg: SequenceRegistrationView
|
|
77
|
-
getSequences: () => Array<SequenceRegistrationView>
|
|
78
|
-
sequenceProgressNow: () => number
|
|
79
|
-
selectedId: () => string | null
|
|
80
|
-
setSelectedId: (id: string | null) => void
|
|
81
|
-
}) {
|
|
82
|
-
const styles = useStyles()
|
|
83
|
-
|
|
84
|
-
const sequenceRegistrations = () => props.getSequences()
|
|
85
|
-
|
|
86
|
-
const conflicts = useRegistrationConflicts(() => props.reg)
|
|
87
|
-
const targetConflicts = () => conflicts().overlapping
|
|
88
|
-
const scopeConflicts = () => conflicts().separate
|
|
89
|
-
const hasTargetConflict = () => targetConflicts().length > 0
|
|
90
|
-
const hasScopeConflict = () => scopeConflicts().length > 0
|
|
91
|
-
const targetConflictBadge = () => ({
|
|
92
|
-
style: 'badgeConflict' as const,
|
|
93
|
-
label: '!',
|
|
94
|
-
tooltip: `Potential overlap: ${targetConflicts().length} other bindings on overlapping targets`,
|
|
95
|
-
})
|
|
96
|
-
const scopeConflictTooltip = () =>
|
|
97
|
-
`Info: ${scopeConflicts().length} related bindings on separate targets`
|
|
98
|
-
|
|
99
|
-
const enabled = () => props.reg.options.enabled !== false
|
|
100
|
-
|
|
101
|
-
const liveSequenceReg = createMemo(
|
|
102
|
-
() =>
|
|
103
|
-
sequenceRegistrations().find((r) => r.id === props.reg.id) ?? props.reg,
|
|
104
|
-
)
|
|
105
|
-
|
|
106
|
-
const triggerCount = () =>
|
|
107
|
-
sequenceRegistrations().find((r) => r.id === props.reg.id)?.triggerCount ??
|
|
108
|
-
props.reg.triggerCount
|
|
109
|
-
|
|
110
|
-
const matchedSteps = createMemo(() =>
|
|
111
|
-
effectiveSequenceMatchedSteps(
|
|
112
|
-
liveSequenceReg(),
|
|
113
|
-
props.sequenceProgressNow(),
|
|
114
|
-
),
|
|
115
|
-
)
|
|
116
|
-
|
|
117
|
-
const [prevCount, setPrevCount] = createSignal(props.reg.triggerCount)
|
|
118
|
-
const [pulsing, setPulsing] = createSignal(false)
|
|
119
|
-
|
|
120
|
-
createEffect(
|
|
121
|
-
on(triggerCount, (current) => {
|
|
122
|
-
if (current > prevCount()) {
|
|
123
|
-
setPulsing(true)
|
|
124
|
-
setTimeout(() => setPulsing(false), 600)
|
|
125
|
-
}
|
|
126
|
-
setPrevCount(current)
|
|
127
|
-
}),
|
|
128
|
-
)
|
|
129
|
-
|
|
130
|
-
const metaName = () => props.reg.options.meta?.name
|
|
131
|
-
const rowTooltip = () => buildRowTooltip(props.reg.options.meta)
|
|
132
|
-
|
|
133
|
-
return (
|
|
134
|
-
<div
|
|
135
|
-
class={clsx(
|
|
136
|
-
styles().hotkeyRow,
|
|
137
|
-
props.selectedId() === props.reg.id && styles().hotkeyRowSelected,
|
|
138
|
-
pulsing() && styles().hotkeyRowTriggered,
|
|
139
|
-
rowTooltip() && styles().tooltip,
|
|
140
|
-
)}
|
|
141
|
-
onClick={() => props.setSelectedId(props.reg.id)}
|
|
142
|
-
>
|
|
143
|
-
<Show when={rowTooltip()}>
|
|
144
|
-
<span class={styles().rowTooltipText} data-tooltip>
|
|
145
|
-
{rowTooltip()}
|
|
146
|
-
</span>
|
|
147
|
-
</Show>
|
|
148
|
-
<span class={styles().hotkeyLabel}>
|
|
149
|
-
<span class={styles().hotkeyLabelKeys}>
|
|
150
|
-
<For each={liveSequenceReg().sequence}>
|
|
151
|
-
{(step, i) => (
|
|
152
|
-
<span>
|
|
153
|
-
<Show when={i() > 0}> </Show>
|
|
154
|
-
<span
|
|
155
|
-
class={
|
|
156
|
-
i() < matchedSteps()
|
|
157
|
-
? styles().sequenceStepMatched
|
|
158
|
-
: undefined
|
|
159
|
-
}
|
|
160
|
-
>
|
|
161
|
-
{formatForDisplay(step, {
|
|
162
|
-
platform: props.reg.options.platform,
|
|
163
|
-
})}
|
|
164
|
-
</span>
|
|
165
|
-
</span>
|
|
166
|
-
)}
|
|
167
|
-
</For>
|
|
168
|
-
</span>
|
|
169
|
-
<Show when={metaName()}>
|
|
170
|
-
<span class={styles().hotkeyLabelName}>{metaName()}</span>
|
|
171
|
-
</Show>
|
|
172
|
-
</span>
|
|
173
|
-
<Show when={triggerCount() > 0}>
|
|
174
|
-
<span class={styles().triggerCount}>x{triggerCount()}</span>
|
|
175
|
-
</Show>
|
|
176
|
-
<div class={styles().hotkeyBadges}>
|
|
177
|
-
<span
|
|
178
|
-
class={clsx(styles().badge, styles().badgeTarget)}
|
|
179
|
-
data-binding-kind
|
|
180
|
-
>
|
|
181
|
-
{getBindingKind(props.reg)}
|
|
182
|
-
</span>
|
|
183
|
-
{hasTargetConflict() && (
|
|
184
|
-
<span
|
|
185
|
-
class={clsx(
|
|
186
|
-
styles().badge,
|
|
187
|
-
styles()[targetConflictBadge().style],
|
|
188
|
-
styles().tooltip,
|
|
189
|
-
)}
|
|
190
|
-
>
|
|
191
|
-
{targetConflictBadge().label}
|
|
192
|
-
<span class={styles().tooltipText} data-tooltip>
|
|
193
|
-
{targetConflictBadge().tooltip}
|
|
194
|
-
</span>
|
|
195
|
-
</span>
|
|
196
|
-
)}
|
|
197
|
-
{hasScopeConflict() && (
|
|
198
|
-
<span
|
|
199
|
-
class={clsx(styles().badge, styles().badgeInfo, styles().tooltip)}
|
|
200
|
-
>
|
|
201
|
-
i
|
|
202
|
-
<span class={styles().tooltipText} data-tooltip>
|
|
203
|
-
{scopeConflictTooltip()}
|
|
204
|
-
</span>
|
|
205
|
-
</span>
|
|
206
|
-
)}
|
|
207
|
-
<span
|
|
208
|
-
class={clsx(
|
|
209
|
-
styles().badge,
|
|
210
|
-
enabled() ? styles().badgeEnabled : styles().badgeDisabled,
|
|
211
|
-
styles().tooltip,
|
|
212
|
-
)}
|
|
213
|
-
>
|
|
214
|
-
{enabled() ? 'on' : 'off'}
|
|
215
|
-
<span class={styles().tooltipText} data-tooltip>
|
|
216
|
-
{enabled() ? 'Sequence is enabled' : 'Sequence is disabled'}
|
|
217
|
-
</span>
|
|
218
|
-
</span>
|
|
219
|
-
<span
|
|
220
|
-
class={clsx(
|
|
221
|
-
styles().badge,
|
|
222
|
-
(props.reg.options.eventType ?? 'keydown') === 'keydown'
|
|
223
|
-
? styles().badgeKeydown
|
|
224
|
-
: styles().badgeKeyup,
|
|
225
|
-
styles().tooltip,
|
|
226
|
-
)}
|
|
227
|
-
>
|
|
228
|
-
{props.reg.options.eventType ?? 'keydown'}
|
|
229
|
-
<span class={styles().tooltipText} data-tooltip>
|
|
230
|
-
Fires on {props.reg.options.eventType ?? 'keydown'} event
|
|
231
|
-
</span>
|
|
232
|
-
</span>
|
|
233
|
-
<span
|
|
234
|
-
class={clsx(styles().badge, styles().badgeTarget, styles().tooltip)}
|
|
235
|
-
>
|
|
236
|
-
{getTargetLabel(props.reg.target)}
|
|
237
|
-
<span class={styles().tooltipText} data-tooltip>
|
|
238
|
-
{getTargetTooltip(props.reg.target)}
|
|
239
|
-
</span>
|
|
240
|
-
</span>
|
|
241
|
-
</div>
|
|
242
|
-
</div>
|
|
243
|
-
)
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
export function HotkeyList(props: HotkeyListProps) {
|
|
247
|
-
const styles = useStyles()
|
|
248
|
-
const state = useHotkeysDevtoolsState()
|
|
249
|
-
|
|
250
|
-
const [searchQuery, setSearchQuery] = createSignal('')
|
|
251
|
-
|
|
252
|
-
const registrations = createMemo(() => state.registrations())
|
|
253
|
-
const sequenceRegistrations = createMemo(() => state.sequenceRegistrations())
|
|
254
|
-
|
|
255
|
-
const filteredRegistrations = createMemo(() => {
|
|
256
|
-
const query = searchQuery().trim()
|
|
257
|
-
if (!query) return registrations()
|
|
258
|
-
return matchSorter(registrations(), query, {
|
|
259
|
-
keys: [
|
|
260
|
-
(r) => formatRegistration(r),
|
|
261
|
-
'hotkey',
|
|
262
|
-
'options.meta.name',
|
|
263
|
-
'options.meta.description',
|
|
264
|
-
'options.meta.group',
|
|
265
|
-
],
|
|
266
|
-
})
|
|
267
|
-
})
|
|
268
|
-
|
|
269
|
-
const filteredSequenceRegistrations = createMemo(() => {
|
|
270
|
-
const query = searchQuery().trim()
|
|
271
|
-
if (!query) return sequenceRegistrations()
|
|
272
|
-
return matchSorter(sequenceRegistrations(), query, {
|
|
273
|
-
keys: [
|
|
274
|
-
(r) => formatRegistration(r),
|
|
275
|
-
(r) => r.sequence.join(' '),
|
|
276
|
-
'options.meta.name',
|
|
277
|
-
'options.meta.description',
|
|
278
|
-
'options.meta.group',
|
|
279
|
-
],
|
|
280
|
-
})
|
|
281
|
-
})
|
|
282
|
-
|
|
283
|
-
return (
|
|
284
|
-
<>
|
|
285
|
-
<div class={styles().searchContainer}>
|
|
286
|
-
<input
|
|
287
|
-
type="text"
|
|
288
|
-
class={styles().searchInput}
|
|
289
|
-
placeholder="Search hotkeys..."
|
|
290
|
-
value={searchQuery()}
|
|
291
|
-
onInput={(e) => setSearchQuery(e.currentTarget.value)}
|
|
292
|
-
/>
|
|
293
|
-
<Show when={searchQuery()}>
|
|
294
|
-
<button
|
|
295
|
-
class={styles().searchClear}
|
|
296
|
-
onClick={() => setSearchQuery('')}
|
|
297
|
-
>
|
|
298
|
-
×
|
|
299
|
-
</button>
|
|
300
|
-
</Show>
|
|
301
|
-
</div>
|
|
302
|
-
|
|
303
|
-
<div class={styles().panelHeader}>
|
|
304
|
-
Hotkeys ({filteredRegistrations().length})
|
|
305
|
-
</div>
|
|
306
|
-
<div class={styles().hotkeyList}>
|
|
307
|
-
<For each={filteredRegistrations()}>
|
|
308
|
-
{(reg) => {
|
|
309
|
-
const conflicts = useRegistrationConflicts(() => reg)
|
|
310
|
-
const targetConflicts = () => conflicts().overlapping
|
|
311
|
-
const scopeConflicts = () => conflicts().separate
|
|
312
|
-
const hasTargetConflict = () => targetConflicts().length > 0
|
|
313
|
-
const hasScopeConflict = () => scopeConflicts().length > 0
|
|
314
|
-
const targetConflictBadge = () => ({
|
|
315
|
-
style: 'badgeConflict' as const,
|
|
316
|
-
label: '!',
|
|
317
|
-
tooltip: `Potential overlap: ${targetConflicts().length} other bindings on overlapping targets`,
|
|
318
|
-
})
|
|
319
|
-
const scopeConflictTooltip = () =>
|
|
320
|
-
`Info: ${scopeConflicts().length} related bindings on separate targets`
|
|
321
|
-
|
|
322
|
-
const enabled = () => reg.options.enabled !== false
|
|
323
|
-
|
|
324
|
-
// Look up trigger count reactively from the registrations list
|
|
325
|
-
// (reg is a stable object ref; the list re-derives on store change)
|
|
326
|
-
const triggerCount = () =>
|
|
327
|
-
registrations().find((r) => r.id === reg.id)?.triggerCount ??
|
|
328
|
-
reg.triggerCount
|
|
329
|
-
|
|
330
|
-
// Track trigger count changes for pulse animation
|
|
331
|
-
const [prevCount, setPrevCount] = createSignal(reg.triggerCount)
|
|
332
|
-
const [pulsing, setPulsing] = createSignal(false)
|
|
333
|
-
|
|
334
|
-
createEffect(
|
|
335
|
-
on(triggerCount, (current) => {
|
|
336
|
-
if (current > prevCount()) {
|
|
337
|
-
setPulsing(true)
|
|
338
|
-
setTimeout(() => setPulsing(false), 600)
|
|
339
|
-
}
|
|
340
|
-
setPrevCount(current)
|
|
341
|
-
}),
|
|
342
|
-
)
|
|
343
|
-
|
|
344
|
-
const metaName = () => reg.options.meta?.name
|
|
345
|
-
const rowTooltip = () => buildRowTooltip(reg.options.meta)
|
|
346
|
-
|
|
347
|
-
return (
|
|
348
|
-
<div
|
|
349
|
-
class={clsx(
|
|
350
|
-
styles().hotkeyRow,
|
|
351
|
-
props.selectedId() === reg.id && styles().hotkeyRowSelected,
|
|
352
|
-
pulsing() && styles().hotkeyRowTriggered,
|
|
353
|
-
rowTooltip() && styles().tooltip,
|
|
354
|
-
)}
|
|
355
|
-
onClick={() => props.setSelectedId(reg.id)}
|
|
356
|
-
>
|
|
357
|
-
<Show when={rowTooltip()}>
|
|
358
|
-
<span class={styles().rowTooltipText} data-tooltip>
|
|
359
|
-
{rowTooltip()}
|
|
360
|
-
</span>
|
|
361
|
-
</Show>
|
|
362
|
-
<span class={styles().hotkeyLabel}>
|
|
363
|
-
<span class={styles().hotkeyLabelKeys}>
|
|
364
|
-
{formatRegistration(reg)}
|
|
365
|
-
</span>
|
|
366
|
-
<Show when={metaName()}>
|
|
367
|
-
<span class={styles().hotkeyLabelName}>{metaName()}</span>
|
|
368
|
-
</Show>
|
|
369
|
-
</span>
|
|
370
|
-
<Show when={triggerCount() > 0}>
|
|
371
|
-
<span class={styles().triggerCount}>x{triggerCount()}</span>
|
|
372
|
-
</Show>
|
|
373
|
-
<div class={styles().hotkeyBadges}>
|
|
374
|
-
<span
|
|
375
|
-
class={clsx(styles().badge, styles().badgeTarget)}
|
|
376
|
-
data-binding-kind
|
|
377
|
-
>
|
|
378
|
-
{getBindingKind(reg)}
|
|
379
|
-
</span>
|
|
380
|
-
{hasTargetConflict() && (
|
|
381
|
-
<span
|
|
382
|
-
class={clsx(
|
|
383
|
-
styles().badge,
|
|
384
|
-
styles()[targetConflictBadge().style],
|
|
385
|
-
styles().tooltip,
|
|
386
|
-
)}
|
|
387
|
-
>
|
|
388
|
-
{targetConflictBadge().label}
|
|
389
|
-
<span class={styles().tooltipText} data-tooltip>
|
|
390
|
-
{targetConflictBadge().tooltip}
|
|
391
|
-
</span>
|
|
392
|
-
</span>
|
|
393
|
-
)}
|
|
394
|
-
{hasScopeConflict() && (
|
|
395
|
-
<span
|
|
396
|
-
class={clsx(
|
|
397
|
-
styles().badge,
|
|
398
|
-
styles().badgeInfo,
|
|
399
|
-
styles().tooltip,
|
|
400
|
-
)}
|
|
401
|
-
>
|
|
402
|
-
i
|
|
403
|
-
<span class={styles().tooltipText} data-tooltip>
|
|
404
|
-
{scopeConflictTooltip()}
|
|
405
|
-
</span>
|
|
406
|
-
</span>
|
|
407
|
-
)}
|
|
408
|
-
<span
|
|
409
|
-
class={clsx(
|
|
410
|
-
styles().badge,
|
|
411
|
-
enabled()
|
|
412
|
-
? styles().badgeEnabled
|
|
413
|
-
: styles().badgeDisabled,
|
|
414
|
-
styles().tooltip,
|
|
415
|
-
)}
|
|
416
|
-
>
|
|
417
|
-
{enabled() ? 'on' : 'off'}
|
|
418
|
-
<span class={styles().tooltipText} data-tooltip>
|
|
419
|
-
{enabled() ? 'Hotkey is enabled' : 'Hotkey is disabled'}
|
|
420
|
-
</span>
|
|
421
|
-
</span>
|
|
422
|
-
<span
|
|
423
|
-
class={clsx(
|
|
424
|
-
styles().badge,
|
|
425
|
-
(reg.options.eventType ?? 'keydown') === 'keydown'
|
|
426
|
-
? styles().badgeKeydown
|
|
427
|
-
: styles().badgeKeyup,
|
|
428
|
-
styles().tooltip,
|
|
429
|
-
)}
|
|
430
|
-
>
|
|
431
|
-
{reg.options.eventType ?? 'keydown'}
|
|
432
|
-
<span class={styles().tooltipText} data-tooltip>
|
|
433
|
-
Fires on {reg.options.eventType ?? 'keydown'} event
|
|
434
|
-
</span>
|
|
435
|
-
</span>
|
|
436
|
-
<span
|
|
437
|
-
class={clsx(
|
|
438
|
-
styles().badge,
|
|
439
|
-
styles().badgeTarget,
|
|
440
|
-
styles().tooltip,
|
|
441
|
-
)}
|
|
442
|
-
>
|
|
443
|
-
{getTargetLabel(reg.target)}
|
|
444
|
-
<span class={styles().tooltipText} data-tooltip>
|
|
445
|
-
{getTargetTooltip(reg.target)}
|
|
446
|
-
</span>
|
|
447
|
-
</span>
|
|
448
|
-
</div>
|
|
449
|
-
</div>
|
|
450
|
-
)
|
|
451
|
-
}}
|
|
452
|
-
</For>
|
|
453
|
-
</div>
|
|
454
|
-
|
|
455
|
-
<div class={styles().panelHeader}>
|
|
456
|
-
Sequences ({filteredSequenceRegistrations().length})
|
|
457
|
-
</div>
|
|
458
|
-
<div class={styles().hotkeyList}>
|
|
459
|
-
<For each={filteredSequenceRegistrations()}>
|
|
460
|
-
{(reg) => (
|
|
461
|
-
<SequenceListRow
|
|
462
|
-
reg={reg}
|
|
463
|
-
getSequences={sequenceRegistrations}
|
|
464
|
-
sequenceProgressNow={state.sequenceProgressNow}
|
|
465
|
-
selectedId={props.selectedId}
|
|
466
|
-
setSelectedId={props.setSelectedId}
|
|
467
|
-
/>
|
|
468
|
-
)}
|
|
469
|
-
</For>
|
|
470
|
-
</div>
|
|
471
|
-
</>
|
|
472
|
-
)
|
|
473
|
-
}
|
package/src/components/Shell.tsx
DELETED
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createEffect,
|
|
3
|
-
createMemo,
|
|
4
|
-
createSignal,
|
|
5
|
-
onCleanup,
|
|
6
|
-
onMount,
|
|
7
|
-
} from 'solid-js'
|
|
8
|
-
import { Header, HeaderLogo, MainPanel } from '@tanstack/devtools-ui'
|
|
9
|
-
import { useStyles } from '../styles/use-styles'
|
|
10
|
-
import { useHotkeysDevtoolsState } from '../HotkeysContextProvider'
|
|
11
|
-
import { HeldKeysBar } from './HeldKeysTopbar'
|
|
12
|
-
import { HotkeyList } from './HotkeyList'
|
|
13
|
-
import { DetailsPanel } from './DetailsPanel'
|
|
14
|
-
|
|
15
|
-
function readResizeObserverBlockSize(entry: ResizeObserverEntry): number {
|
|
16
|
-
const [box] = entry.borderBoxSize
|
|
17
|
-
if (box !== undefined) return box.blockSize
|
|
18
|
-
return entry.contentRect.height
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/** TanStack devtools plugin pane; percentage heights break without this. */
|
|
22
|
-
function resolvePluginHost(el: HTMLElement): HTMLElement | null {
|
|
23
|
-
const found = el.closest('[id^="plugin-container-"]')
|
|
24
|
-
if (found instanceof HTMLElement) return found
|
|
25
|
-
let n: HTMLElement | null = el
|
|
26
|
-
for (let i = 0; i < 3 && n; i++) {
|
|
27
|
-
n = n.parentElement
|
|
28
|
-
}
|
|
29
|
-
return n
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function Shell() {
|
|
33
|
-
const styles = useStyles()
|
|
34
|
-
const state = useHotkeysDevtoolsState()
|
|
35
|
-
const [selectedId, setSelectedId] = createSignal<string | null>(null)
|
|
36
|
-
const [leftPanelWidth, setLeftPanelWidth] = createSignal(300)
|
|
37
|
-
const [isDragging, setIsDragging] = createSignal(false)
|
|
38
|
-
const [shellRootEl, setShellRootEl] = createSignal<HTMLElement | null>(null)
|
|
39
|
-
const [slotHeightPx, setSlotHeightPx] = createSignal<number | undefined>(
|
|
40
|
-
undefined,
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
const selectedRegistration = createMemo(() => {
|
|
44
|
-
const id = selectedId()
|
|
45
|
-
if (!id) return null
|
|
46
|
-
const hotkey = state.registrations().find((r) => r.id === id)
|
|
47
|
-
if (hotkey) return hotkey
|
|
48
|
-
const sequence = state.sequenceRegistrations().find((r) => r.id === id)
|
|
49
|
-
return sequence ?? null
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
let dragStartX = 0
|
|
53
|
-
let dragStartWidth = 0
|
|
54
|
-
|
|
55
|
-
const handleMouseDown = (e: MouseEvent) => {
|
|
56
|
-
e.preventDefault()
|
|
57
|
-
e.stopPropagation()
|
|
58
|
-
setIsDragging(true)
|
|
59
|
-
document.body.style.cursor = 'col-resize'
|
|
60
|
-
document.body.style.userSelect = 'none'
|
|
61
|
-
dragStartX = e.clientX
|
|
62
|
-
dragStartWidth = leftPanelWidth()
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const handleMouseMove = (e: MouseEvent) => {
|
|
66
|
-
if (!isDragging()) return
|
|
67
|
-
|
|
68
|
-
e.preventDefault()
|
|
69
|
-
const deltaX = e.clientX - dragStartX
|
|
70
|
-
const newWidth = Math.max(150, Math.min(800, dragStartWidth + deltaX))
|
|
71
|
-
setLeftPanelWidth(newWidth)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const handleMouseUp = () => {
|
|
75
|
-
setIsDragging(false)
|
|
76
|
-
document.body.style.cursor = ''
|
|
77
|
-
document.body.style.userSelect = ''
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
onMount(() => {
|
|
81
|
-
document.addEventListener('mousemove', handleMouseMove)
|
|
82
|
-
document.addEventListener('mouseup', handleMouseUp)
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
onCleanup(() => {
|
|
86
|
-
document.removeEventListener('mousemove', handleMouseMove)
|
|
87
|
-
document.removeEventListener('mouseup', handleMouseUp)
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
createEffect(() => {
|
|
91
|
-
const el = shellRootEl()
|
|
92
|
-
if (!el || typeof ResizeObserver === 'undefined') return
|
|
93
|
-
const pluginHost = resolvePluginHost(el)
|
|
94
|
-
if (!pluginHost) return
|
|
95
|
-
|
|
96
|
-
const applyHeight = (entry?: ResizeObserverEntry) => {
|
|
97
|
-
const clientH = pluginHost.clientHeight
|
|
98
|
-
const fromObserver =
|
|
99
|
-
entry !== undefined ? readResizeObserverBlockSize(entry) : 0
|
|
100
|
-
const h = clientH > 0 ? clientH : fromObserver
|
|
101
|
-
if (h > 0) setSlotHeightPx(Math.round(h))
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
applyHeight()
|
|
105
|
-
const ro = new ResizeObserver((entries) => {
|
|
106
|
-
applyHeight(entries[0])
|
|
107
|
-
})
|
|
108
|
-
ro.observe(pluginHost)
|
|
109
|
-
onCleanup(() => ro.disconnect())
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
return (
|
|
113
|
-
<div
|
|
114
|
-
ref={(el) => setShellRootEl(el)}
|
|
115
|
-
class={styles().shellRoot}
|
|
116
|
-
style={{
|
|
117
|
-
...(slotHeightPx() !== undefined
|
|
118
|
-
? {
|
|
119
|
-
height: `${slotHeightPx()}px`,
|
|
120
|
-
'max-height': `${slotHeightPx()}px`,
|
|
121
|
-
}
|
|
122
|
-
: {}),
|
|
123
|
-
}}
|
|
124
|
-
>
|
|
125
|
-
<MainPanel class={styles().mainPanelShell}>
|
|
126
|
-
<Header>
|
|
127
|
-
<HeaderLogo
|
|
128
|
-
flavor={{
|
|
129
|
-
light: 'oklch(51.4% 0.222 16.935)',
|
|
130
|
-
dark: 'oklch(58.6% 0.253 17.585)',
|
|
131
|
-
}}
|
|
132
|
-
>
|
|
133
|
-
TanStack Hotkeys
|
|
134
|
-
</HeaderLogo>
|
|
135
|
-
</Header>
|
|
136
|
-
|
|
137
|
-
<div class={styles().mainContainer}>
|
|
138
|
-
<HeldKeysBar />
|
|
139
|
-
|
|
140
|
-
<div class={styles().panelsContainer}>
|
|
141
|
-
<div
|
|
142
|
-
class={styles().leftPanel}
|
|
143
|
-
style={{
|
|
144
|
-
width: `${leftPanelWidth()}px`,
|
|
145
|
-
'min-width': '150px',
|
|
146
|
-
'max-width': '800px',
|
|
147
|
-
}}
|
|
148
|
-
>
|
|
149
|
-
<div class={styles().leftPanelScroll}>
|
|
150
|
-
<HotkeyList
|
|
151
|
-
selectedId={selectedId}
|
|
152
|
-
setSelectedId={setSelectedId}
|
|
153
|
-
/>
|
|
154
|
-
</div>
|
|
155
|
-
</div>
|
|
156
|
-
|
|
157
|
-
<div
|
|
158
|
-
class={`${styles().dragHandle} ${isDragging() ? 'dragging' : ''}`}
|
|
159
|
-
onMouseDown={handleMouseDown}
|
|
160
|
-
/>
|
|
161
|
-
|
|
162
|
-
<div class={styles().rightPanel} style={{ flex: 1 }}>
|
|
163
|
-
<div class={styles().panelHeader}>Details</div>
|
|
164
|
-
<DetailsPanel selectedRegistration={selectedRegistration} />
|
|
165
|
-
</div>
|
|
166
|
-
</div>
|
|
167
|
-
</div>
|
|
168
|
-
</MainPanel>
|
|
169
|
-
</div>
|
|
170
|
-
)
|
|
171
|
-
}
|