@grafana/ui
Version:
Grafana Components Library
1 lines • 10.2 kB
Source Map (JSON)
{"version":3,"file":"KeyboardPlugin.mjs","sources":["../../../../../src/components/uPlot/plugins/KeyboardPlugin.tsx"],"sourcesContent":["import { clamp } from 'lodash';\nimport { useLayoutEffect } from 'react';\nimport uPlot from 'uplot';\n\nimport { UPlotConfigBuilder } from '../config/UPlotConfigBuilder';\n\ninterface KeyboardPluginProps {\n config: UPlotConfigBuilder; // onkeypress, onkeyup, onkeydown (triggered by vizlayout handlers)\n}\n\nconst PIXELS_PER_MS = 0.1 as const;\nconst SHIFT_MULTIPLIER = 2 as const;\nconst KNOWN_KEYS = new Set(['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown', 'Shift', ' ']);\n\nconst initHook = (u: uPlot) => {\n let parentWithFocus: HTMLElement | null = u.root;\n let pressedKeys = new Set<string>();\n let dragStartX: number | null = null;\n let keysLastHandledAt: number | null = null;\n\n if (!parentWithFocus) {\n return;\n }\n // Make Graph area focusable. Setting this in Viz* components will make focus available on panels that do not yet have keyboard support\n parentWithFocus.tabIndex = 0;\n\n const moveCursor = (dx: number, dy: number) => {\n const { cursor } = u;\n if (cursor.left === undefined || cursor.top === undefined) {\n return;\n }\n\n const { width, height } = u.over.style;\n const [maxX, maxY] = [Math.floor(parseFloat(width)), Math.floor(parseFloat(height))];\n\n u.setCursor({\n left: clamp(cursor.left + dx, 0, maxX),\n top: clamp(cursor.top + dy, 0, maxY),\n });\n };\n\n const handlePressedKeys = (time: number) => {\n const nothingPressed = pressedKeys.size === 0;\n if (nothingPressed || !u) {\n keysLastHandledAt = null;\n return;\n }\n\n const dt = time - (keysLastHandledAt ?? time);\n const dx = dt * PIXELS_PER_MS;\n let horValue = 0;\n let vertValue = 0;\n\n if (pressedKeys.has('ArrowUp')) {\n vertValue -= dx;\n }\n if (pressedKeys.has('ArrowDown')) {\n vertValue += dx;\n }\n if (pressedKeys.has('ArrowLeft')) {\n horValue -= dx;\n }\n if (pressedKeys.has('ArrowRight')) {\n horValue += dx;\n }\n if (pressedKeys.has('Shift')) {\n horValue *= SHIFT_MULTIPLIER;\n vertValue *= SHIFT_MULTIPLIER;\n }\n\n moveCursor(horValue, vertValue);\n\n const { cursor } = u;\n if (pressedKeys.has(' ') && cursor) {\n const drawHeight = Number(u.over.style.height.slice(0, -2));\n\n u.setSelect(\n {\n left: cursor.left! < dragStartX! ? cursor.left! : dragStartX!,\n top: 0,\n width: Math.abs(cursor.left! - (dragStartX ?? cursor.left!)),\n height: drawHeight,\n },\n false\n );\n }\n\n keysLastHandledAt = time;\n window.requestAnimationFrame(handlePressedKeys);\n };\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Tab') {\n // Hide the cursor if the user tabs away\n u.setCursor({ left: -5, top: -5 });\n return;\n }\n\n if (!KNOWN_KEYS.has(e.key)) {\n return;\n }\n\n e.preventDefault();\n e.stopPropagation();\n\n const newKey = !pressedKeys.has(e.key);\n if (newKey) {\n const initiateAnimationLoop = pressedKeys.size === 0;\n pressedKeys.add(e.key);\n\n dragStartX = e.key === ' ' && dragStartX === null ? u.cursor.left! : dragStartX;\n\n if (initiateAnimationLoop) {\n window.requestAnimationFrame(handlePressedKeys);\n }\n }\n };\n\n const onKeyUp = (e: KeyboardEvent) => {\n if (!KNOWN_KEYS.has(e.key)) {\n return;\n }\n\n pressedKeys.delete(e.key);\n\n if (e.key === ' ') {\n e.preventDefault();\n e.stopPropagation();\n\n // We do this so setSelect hooks get fired, zooming the plot\n u.setSelect(u.select);\n dragStartX = null;\n }\n };\n\n const onFocus = () => {\n // We only want to initialize the cursor if the user is using keyboard controls\n if (!parentWithFocus?.matches(':focus-visible')) {\n return;\n }\n\n // Is there a more idiomatic way to do this?\n const drawWidth = parseFloat(u.over.style.width);\n const drawHeight = parseFloat(u.over.style.height);\n u.setCursor({ left: drawWidth / 2, top: drawHeight / 2 });\n };\n\n const onBlur = () => {\n keysLastHandledAt = null;\n dragStartX = null;\n pressedKeys.clear();\n u.setSelect({ left: 0, top: 0, width: 0, height: 0 }, false);\n };\n\n parentWithFocus.addEventListener('keydown', onKeyDown);\n parentWithFocus.addEventListener('keyup', onKeyUp);\n parentWithFocus.addEventListener('focus', onFocus);\n parentWithFocus.addEventListener('blur', onBlur);\n\n const onDestroy = () => {\n parentWithFocus?.removeEventListener('keydown', onKeyDown);\n parentWithFocus?.removeEventListener('keyup', onKeyUp);\n parentWithFocus?.removeEventListener('focus', onFocus);\n parentWithFocus?.removeEventListener('blur', onBlur);\n parentWithFocus = null;\n };\n\n (u.hooks.destroy ??= []).push(onDestroy);\n};\n\n/**\n * @alpha\n */\nexport const KeyboardPlugin = ({ config }: KeyboardPluginProps) => {\n useLayoutEffect(() => config.addHook('init', initHook), [config]);\n\n return null;\n};\n"],"names":[],"mappings":"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"}