@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.
Files changed (43) hide show
  1. package/dist/HotkeysContextProvider.js +1 -2
  2. package/dist/_registrations.js +1 -2
  3. package/dist/components/ActionButtons.js +2 -3
  4. package/dist/components/DetailsPanel.js +16 -3
  5. package/dist/components/HeldKeysTopbar.js +5 -3
  6. package/dist/components/HotkeyList.js +13 -3
  7. package/dist/components/Shell.js +5 -4
  8. package/dist/components/index.js +1 -2
  9. package/dist/core.d.ts +3 -6
  10. package/dist/core.js +1 -2
  11. package/dist/index.d.ts +2 -4
  12. package/dist/index.js +1 -2
  13. package/dist/sequence-progress.js +1 -2
  14. package/dist/styles/tokens.js +1 -2
  15. package/dist/styles/use-styles.js +5 -4
  16. package/package.json +11 -11
  17. package/dist/HotkeysContextProvider.js.map +0 -1
  18. package/dist/_registrations.js.map +0 -1
  19. package/dist/components/ActionButtons.js.map +0 -1
  20. package/dist/components/DetailsPanel.js.map +0 -1
  21. package/dist/components/HeldKeysTopbar.js.map +0 -1
  22. package/dist/components/HotkeyList.js.map +0 -1
  23. package/dist/components/Shell.js.map +0 -1
  24. package/dist/components/index.js.map +0 -1
  25. package/dist/core.js.map +0 -1
  26. package/dist/index.js.map +0 -1
  27. package/dist/sequence-progress.js.map +0 -1
  28. package/dist/styles/tokens.js.map +0 -1
  29. package/dist/styles/use-styles.js.map +0 -1
  30. package/src/HotkeysContextProvider.tsx +0 -130
  31. package/src/_registrations.ts +0 -59
  32. package/src/components/ActionButtons.tsx +0 -38
  33. package/src/components/DetailsPanel.tsx +0 -685
  34. package/src/components/HeldKeysTopbar.tsx +0 -46
  35. package/src/components/HotkeyList.tsx +0 -473
  36. package/src/components/Shell.tsx +0 -171
  37. package/src/components/index.tsx +0 -19
  38. package/src/core.tsx +0 -11
  39. package/src/index.ts +0 -11
  40. package/src/production.ts +0 -5
  41. package/src/sequence-progress.ts +0 -29
  42. package/src/styles/tokens.ts +0 -305
  43. 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
- &times;
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
- }
@@ -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
- }