From aae405373008879490af064eae80dac281e7a3c2 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Thu, 25 Jan 2024 08:35:56 -0800 Subject: [PATCH 1/5] Focus->Zoom In --- .../SquiggleViewer/SquiggleValueMenu.tsx | 20 +++---- .../SquiggleViewer/ValueWithContextViewer.tsx | 26 ++++----- .../SquiggleViewer/ViewerProvider.tsx | 39 +++++++------ .../src/components/SquiggleViewer/index.tsx | 57 ++++++++++--------- .../{focusedSqValue.ts => zoomedInSqValue.ts} | 18 +++--- ...nfocusedSqValue.ts => zoomedOutSqValue.ts} | 11 +++- .../src/widgets/TableChartWidget.tsx | 6 +- 7 files changed, 96 insertions(+), 81 deletions(-) rename packages/components/src/components/SquiggleViewer/keyboardNav/{focusedSqValue.ts => zoomedInSqValue.ts} (71%) rename packages/components/src/components/SquiggleViewer/keyboardNav/{unfocusedSqValue.ts => zoomedOutSqValue.ts} (87%) diff --git a/packages/components/src/components/SquiggleViewer/SquiggleValueMenu.tsx b/packages/components/src/components/SquiggleViewer/SquiggleValueMenu.tsx index 8e06f1281f..e4266a27fd 100644 --- a/packages/components/src/components/SquiggleViewer/SquiggleValueMenu.tsx +++ b/packages/components/src/components/SquiggleViewer/SquiggleValueMenu.tsx @@ -18,19 +18,19 @@ import { valueToHeadingString } from "../../widgets/utils.js"; import { CollapsedIcon, ExpandedIcon } from "./icons.js"; import { getChildrenValues } from "./utils.js"; import { - useFocus, useHasLocalSettings, - useIsFocused, + useIsZoomedIn, useSetCollapsed, - useUnfocus, useViewerContext, + useZoomIn, + useZoomOut, } from "./ViewerProvider.js"; const FocusItem: FC<{ value: SqValueWithContext }> = ({ value }) => { const { path } = value.context; - const isFocused = useIsFocused(path); - const focus = useFocus(); - const unfocus = useUnfocus(); + const isFocused = useIsZoomedIn(path); + const zoomIn = useZoomIn(); + const zoomOut = useZoomOut(); if (path.isRoot()) { return null; } @@ -38,17 +38,17 @@ const FocusItem: FC<{ value: SqValueWithContext }> = ({ value }) => { if (isFocused) { return ( ); } else { return ( focus(path)} + onClick={() => zoomIn(path)} /> ); } diff --git a/packages/components/src/components/SquiggleViewer/ValueWithContextViewer.tsx b/packages/components/src/components/SquiggleViewer/ValueWithContextViewer.tsx index 20e4153798..79dd64bff2 100644 --- a/packages/components/src/components/SquiggleViewer/ValueWithContextViewer.tsx +++ b/packages/components/src/components/SquiggleViewer/ValueWithContextViewer.tsx @@ -12,8 +12,8 @@ import { MarkdownViewer } from "../../lib/MarkdownViewer.js"; import { SqValueWithContext } from "../../lib/utility.js"; import { ErrorBoundary } from "../ErrorBoundary.js"; import { CollapsedIcon, ExpandedIcon } from "./icons.js"; -import { useFocusedSqValueKeyEvent } from "./keyboardNav/focusedSqValue.js"; -import { useUnfocusedSqValueKeyEvent } from "./keyboardNav/unfocusedSqValue.js"; +import { useZoomedInSqValueKeyEvent } from "./keyboardNav/zoomedInSqValue.js"; +import { useZoomedOutSqValueKeyEvent } from "./keyboardNav/zoomedOutSqValue.js"; import { SquiggleValueChart } from "./SquiggleValueChart.js"; import { SquiggleValueMenu } from "./SquiggleValueMenu.js"; import { SquiggleValuePreview } from "./SquiggleValuePreview.js"; @@ -23,13 +23,13 @@ import { pathToShortName, } from "./utils.js"; import { - useFocus, useMergedSettings, useRegisterAsItemViewer, useScrollToEditorPath, useToggleCollapsed, useViewerContext, useViewerType, + useZoomIn, } from "./ViewerProvider.js"; const CommentIconForValue: FC<{ value: SqValueWithContext }> = ({ value }) => { @@ -148,16 +148,16 @@ export const ValueWithContextViewer: FC = ({ useRegisterAsItemViewer(path, handle); - const _focus = useFocus(); - const focus = () => enableFocus && _focus(path); - const focusedKeyEvent = useFocusedSqValueKeyEvent(path); - const unfocusedKeyEvent = useUnfocusedSqValueKeyEvent(path); + const zoomIn = useZoomIn(); + const focus = () => enableFocus && zoomIn(path); + const focusedKeyEvent = useZoomedInSqValueKeyEvent(path); + const unfocusedKeyEvent = useZoomedOutSqValueKeyEvent(path); const viewerType = useViewerType(); const scrollEditorToPath = useScrollToEditorPath(path); - const { itemStore, focused: _focused } = useViewerContext(); - const isFocused = _focused?.isEqual(path); + const { itemStore, zoomedInPath } = useViewerContext(); + const isZoomedIn = zoomedInPath?.isEqual(path); const itemState = itemStore.getStateOrInitialize(value); const isRoot = path.isRoot(); @@ -176,7 +176,7 @@ export const ValueWithContextViewer: FC = ({ const isOpen = !collapsible || !itemState.collapsed; useEffect(() => { - if (isFocused && !isRoot) { + if (isZoomedIn && !isRoot) { handle.focusOnHeader(); } }, []); @@ -267,7 +267,7 @@ export const ValueWithContextViewer: FC = ({ //Focus on the header on mount if focused useEffect(() => { - if (isFocused && !isRoot && headerRef && headerVisibility !== "hide") { + if (isZoomedIn && !isRoot && headerRef && headerVisibility !== "hide") { handle.focusOnHeader(); } }, []); @@ -281,7 +281,7 @@ export const ValueWithContextViewer: FC = ({ tabIndex={viewerType === "tooltip" ? undefined : 0} className={clsx( "flex justify-between group pr-0.5 hover:bg-stone-100 rounded-sm focus-visible:outline-none", - isFocused + isZoomedIn ? "focus:bg-indigo-50 mb-2 px-0.5 py-1" : "focus:bg-indigo-100" )} @@ -289,7 +289,7 @@ export const ValueWithContextViewer: FC = ({ scrollEditorToPath(); }} onKeyDown={(event) => { - isFocused ? focusedKeyEvent(event) : unfocusedKeyEvent(event); + isZoomedIn ? focusedKeyEvent(event) : unfocusedKeyEvent(event); }} >
diff --git a/packages/components/src/components/SquiggleViewer/ViewerProvider.tsx b/packages/components/src/components/SquiggleViewer/ViewerProvider.tsx index 2a86132dab..bc8d260603 100644 --- a/packages/components/src/components/SquiggleViewer/ViewerProvider.tsx +++ b/packages/components/src/components/SquiggleViewer/ViewerProvider.tsx @@ -173,8 +173,8 @@ type ViewerContextShape = { // Instead, we keep `localItemState` in local state and notify the global context via `setLocalItemState` to pass them down the component tree again if it got rebuilt from scratch. // See ./SquiggleViewer.tsx and ./ValueWithContextViewer.tsx for other implementation details on this. globalSettings: PlaygroundSettings; - focused: SqValuePath | undefined; - setFocused: (value: SqValuePath | undefined) => void; + zoomedInPath: SqValuePath | undefined; + setZoomedInPath: (value: SqValuePath | undefined) => void; editor?: CodeEditorHandle; itemStore: ItemStore; viewerType: ViewerType; @@ -186,8 +186,8 @@ type ViewerContextShape = { export const ViewerContext = createContext({ globalSettings: defaultPlaygroundSettings, - focused: undefined, - setFocused: () => undefined, + zoomedInPath: undefined, + setZoomedInPath: () => undefined, editor: undefined, itemStore: new ItemStore(), viewerType: "normal", @@ -283,23 +283,24 @@ export function useHasLocalSettings(path: SqValuePath) { ); } -export function useFocus() { - const { focused, setFocused } = useViewerContext(); +export function useZoomIn() { + const { zoomedInPath: zoomedInPath, setZoomedInPath: setZoomedInPath } = + useViewerContext(); return (path: SqValuePath) => { - if (focused?.isEqual(path)) { + if (zoomedInPath?.isEqual(path)) { return; // nothing to do } if (path.isRoot()) { - setFocused(undefined); // focusing on root nodes is not allowed + setZoomedInPath(undefined); // full screening on root nodes is not allowed } else { - setFocused(path); + setZoomedInPath(path); } }; } -export function useUnfocus() { - const { setFocused } = useViewerContext(); - return () => setFocused(undefined); +export function useZoomOut() { + const { setZoomedInPath: setZoomedInPath } = useViewerContext(); + return () => setZoomedInPath(undefined); } export function useScrollToEditorPath(path: SqValuePath) { @@ -316,9 +317,9 @@ export function useScrollToEditorPath(path: SqValuePath) { }; } -export function useIsFocused(path: SqValuePath) { - const { focused } = useViewerContext(); - return focused?.isEqual(path); +export function useIsZoomedIn(path: SqValuePath) { + const { zoomedInPath: zoomedInPath } = useViewerContext(); + return zoomedInPath?.isEqual(path); } export function useMergedSettings(path: SqValuePath) { @@ -367,7 +368,9 @@ export const InnerViewerProvider = forwardRef( unstablePlaygroundSettings ); - const [focused, setFocused] = useState(); + const [zoomedInPath, setZoomedInPathPath] = useState< + SqValuePath | undefined + >(); const globalSettings = useMemo(() => { return merge({}, defaultPlaygroundSettings, playgroundSettings); @@ -390,8 +393,8 @@ export const InnerViewerProvider = forwardRef( rootValue: _rootValue, globalSettings, editor, - focused, - setFocused, + zoomedInPath, + setZoomedInPath: setZoomedInPathPath, itemStore, viewerType, handle, diff --git a/packages/components/src/components/SquiggleViewer/index.tsx b/packages/components/src/components/SquiggleViewer/index.tsx index bc6e092419..479f67ee7b 100644 --- a/packages/components/src/components/SquiggleViewer/index.tsx +++ b/packages/components/src/components/SquiggleViewer/index.tsx @@ -10,13 +10,13 @@ import { useGetSubvalueByPath } from "./utils.js"; import { ValueViewer } from "./ValueViewer.js"; import { SquiggleViewerHandle, - useFocus, - useUnfocus, useViewerContext, + useZoomIn, + useZoomOut, ViewerProvider, } from "./ViewerProvider.js"; -const FocusedNavigationItem: FC<{ +const ZoomedInNavigationItem: FC<{ text: string; onClick: () => void; }> = ({ text, onClick }) => ( @@ -31,38 +31,38 @@ const FocusedNavigationItem: FC<{
); -const FocusedNavigation: FC<{ - focusedPath: SqValuePath; +const ZoomedInNavigation: FC<{ + zoomedInPath: SqValuePath; rootPath?: SqValuePath | undefined; -}> = ({ focusedPath, rootPath }) => { - const unfocus = useUnfocus(); - const focus = useFocus(); +}> = ({ zoomedInPath, rootPath }) => { + const zoomOut = useZoomOut(); + const zoomIn = useZoomIn(); - const isFocusedOnRootPath = rootPath && rootPath.isEqual(focusedPath); + const isZoomedInOnRootPath = rootPath && rootPath.isEqual(zoomedInPath); - if (isFocusedOnRootPath) { + if (isZoomedInOnRootPath) { return null; } - // If we're focused on the root path override, we need to adjust the focused path accordingly when presenting the navigation, so that it begins with the root path intead. This is a bit confusing. - const rootPathFocusedAdjustment = rootPath?.edges.length + // If we're zoomedIn on the root path override, we need to adjust the zoomedIn path accordingly when presenting the navigation, so that it begins with the root path intead. This is a bit confusing. + const rootPathZoomedInAdjustment = rootPath?.edges.length ? rootPath.edges.length - 1 : 0; return (
{!rootPath?.edges.length && ( - + )} - {focusedPath + {zoomedInPath .allPrefixPaths({ includeRoot: false }) - .slice(rootPathFocusedAdjustment, -1) + .slice(rootPathZoomedInAdjustment, -1) .map((path, i) => ( - focus(path)} - text={path.edges[i + rootPathFocusedAdjustment].toDisplayString()} + onClick={() => zoomIn(path)} + text={path.edges[i + rootPathZoomedInAdjustment].toDisplayString()} /> ))}
@@ -75,27 +75,30 @@ export type SquiggleViewerProps = { } & PartialPlaygroundSettings; const SquiggleViewerWithoutProvider: FC = ({ value }) => { - const { focused } = useViewerContext(); + const { zoomedInPath } = useViewerContext(); const getSubvalueByPath = useGetSubvalueByPath(); - let focusedItem: SqValue | undefined; - if (focused) { - focusedItem = getSubvalueByPath(value, focused); + let zoomedInItem: SqValue | undefined; + if (zoomedInPath) { + zoomedInItem = getSubvalueByPath(value, zoomedInPath); } - return focused ? ( + return zoomedInPath ? (
- - {focusedItem ? ( + + {zoomedInItem ? ( ) : ( - + )}
) : ( diff --git a/packages/components/src/components/SquiggleViewer/keyboardNav/focusedSqValue.ts b/packages/components/src/components/SquiggleViewer/keyboardNav/zoomedInSqValue.ts similarity index 71% rename from packages/components/src/components/SquiggleViewer/keyboardNav/focusedSqValue.ts rename to packages/components/src/components/SquiggleViewer/keyboardNav/zoomedInSqValue.ts index f0197e4c86..9f3ad279df 100644 --- a/packages/components/src/components/SquiggleViewer/keyboardNav/focusedSqValue.ts +++ b/packages/components/src/components/SquiggleViewer/keyboardNav/zoomedInSqValue.ts @@ -3,13 +3,17 @@ import { SqValuePath } from "@quri/squiggle-lang"; import { useViewerContext } from "../ViewerProvider.js"; import { focusSqValueHeader, keyboardEventHandler } from "./utils.js"; -export function useFocusedSqValueKeyEvent(selected: SqValuePath) { - const { setFocused, itemStore, findNode } = useViewerContext(); +export function useZoomedInSqValueKeyEvent(selected: SqValuePath) { + const { + setZoomedInPath: setZoomedInPath, + itemStore, + findNode, + } = useViewerContext(); function resetToRoot() { - setFocused(undefined); + setZoomedInPath(undefined); - // This timeout is a hack to make sure the header is focused after the reset + // This timeout is a hack to make sure the header is zoomedIn after the reset setTimeout(() => { focusSqValueHeader(selected, itemStore); }, 1); @@ -19,13 +23,13 @@ export function useFocusedSqValueKeyEvent(selected: SqValuePath) { ArrowDown: () => { const newPath = findNode(selected)?.nextSibling()?.node.path; if (newPath) { - setFocused(newPath); + setZoomedInPath(newPath); } }, ArrowUp: () => { const newPath = findNode(selected)?.prevSibling()?.node.path; if (newPath) { - setFocused(newPath); + setZoomedInPath(newPath); } }, ArrowLeft: () => { @@ -34,7 +38,7 @@ export function useFocusedSqValueKeyEvent(selected: SqValuePath) { if (newItem.isRoot()) { resetToRoot(); } else { - setFocused(newItem.node.path); + setZoomedInPath(newItem.node.path); } } }, diff --git a/packages/components/src/components/SquiggleViewer/keyboardNav/unfocusedSqValue.ts b/packages/components/src/components/SquiggleViewer/keyboardNav/zoomedOutSqValue.ts similarity index 87% rename from packages/components/src/components/SquiggleViewer/keyboardNav/unfocusedSqValue.ts rename to packages/components/src/components/SquiggleViewer/keyboardNav/zoomedOutSqValue.ts index a610986318..188f8f07b2 100644 --- a/packages/components/src/components/SquiggleViewer/keyboardNav/unfocusedSqValue.ts +++ b/packages/components/src/components/SquiggleViewer/keyboardNav/zoomedOutSqValue.ts @@ -3,8 +3,13 @@ import { SqValuePath } from "@quri/squiggle-lang"; import { toggleCollapsed, useViewerContext } from "../ViewerProvider.js"; import { focusSqValueHeader, keyboardEventHandler } from "./utils.js"; -export function useUnfocusedSqValueKeyEvent(selected: SqValuePath) { - const { setFocused, itemStore, editor, findNode } = useViewerContext(); +export function useZoomedOutSqValueKeyEvent(selected: SqValuePath) { + const { + setZoomedInPath: setZoomedInPath, + itemStore, + editor, + findNode, + } = useViewerContext(); return keyboardEventHandler({ ArrowDown: () => { @@ -37,7 +42,7 @@ export function useUnfocusedSqValueKeyEvent(selected: SqValuePath) { } }, Enter: () => { - setFocused(selected); + setZoomedInPath(selected); }, " ": () => { toggleCollapsed(itemStore, selected); diff --git a/packages/components/src/widgets/TableChartWidget.tsx b/packages/components/src/widgets/TableChartWidget.tsx index 1a6128a3e3..27a43a4c39 100644 --- a/packages/components/src/widgets/TableChartWidget.tsx +++ b/packages/components/src/widgets/TableChartWidget.tsx @@ -5,7 +5,7 @@ import { TableCellsIcon } from "@quri/ui"; import { PlaygroundSettings } from "../components/PlaygroundSettings.js"; import { SquiggleValueChart } from "../components/SquiggleViewer/SquiggleValueChart.js"; -import { useFocus } from "../components/SquiggleViewer/ViewerProvider.js"; +import { useZoomIn } from "../components/SquiggleViewer/ViewerProvider.js"; import { valueHasContext } from "../lib/utility.js"; import { widgetRegistry } from "./registry.js"; @@ -23,7 +23,7 @@ widgetRegistry.register("TableChart", { Chart: (valueWithContext, settings) => { const environment = valueWithContext.context.project.getEnvironment(); const value = valueWithContext.value; - const focus = useFocus(); + const zoomedIn = useZoomIn(); const rowsAndColumns = value.items(environment); const columnNames = value.columnNames; const hasColumnNames = columnNames.filter((name) => !!name).length > 0; @@ -92,7 +92,7 @@ widgetRegistry.register("TableChart", { if (event.key === "Enter" && item.ok) { event.preventDefault(); const path = item.value.context?.path; - path && focus(path); + path && zoomedIn(path); } }} className={clsx( From 25e76d452fe480cdd27f7153848558659a9f85a6 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Thu, 25 Jan 2024 10:18:57 -0800 Subject: [PATCH 2/5] Adds changeset --- .changeset/strong-balloons-rush.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/strong-balloons-rush.md diff --git a/.changeset/strong-balloons-rush.md b/.changeset/strong-balloons-rush.md new file mode 100644 index 0000000000..3a1618538a --- /dev/null +++ b/.changeset/strong-balloons-rush.md @@ -0,0 +1,6 @@ +--- +"@quri/squiggle-lang": patch +"@quri/squiggle-components": patch +--- + +Adds simple keyboard navigation for Viewer From 7d04a7b9c1cac80734e7109adffbeb9e13026937 Mon Sep 17 00:00:00 2001 From: Vyacheslav Matyukhin Date: Thu, 25 Jan 2024 13:52:06 -0600 Subject: [PATCH 3/5] refactor auto-focus zoomed in values --- .../SquiggleViewer/ValueWithContextViewer.tsx | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/packages/components/src/components/SquiggleViewer/ValueWithContextViewer.tsx b/packages/components/src/components/SquiggleViewer/ValueWithContextViewer.tsx index 79dd64bff2..d1ffcaf67d 100644 --- a/packages/components/src/components/SquiggleViewer/ValueWithContextViewer.tsx +++ b/packages/components/src/components/SquiggleViewer/ValueWithContextViewer.tsx @@ -2,7 +2,7 @@ import "../../widgets/index.js"; import { clsx } from "clsx"; -import { FC, PropsWithChildren, useEffect, useMemo, useRef } from "react"; +import { FC, PropsWithChildren, useCallback, useMemo, useRef } from "react"; import { SqValue } from "@quri/squiggle-lang"; import { CommentIcon, TextTooltip } from "@quri/ui"; @@ -129,10 +129,15 @@ export const ValueWithContextViewer: FC = ({ const { path } = value.context; const containerRef = useRef(null); - const headerRef = useRef(null); + const headerRef = useRef(null); const toggleCollapsed_ = useToggleCollapsed(); + // Identity must be stable for the sake of `setHeaderRef` callback + const focusOnHeader = useCallback(() => { + headerRef.current?.focus(); + }, []); + const handle: ValueWithContextViewerHandle = { scrollIntoView: () => { containerRef?.current?.scrollIntoView({ @@ -140,9 +145,7 @@ export const ValueWithContextViewer: FC = ({ }); }, forceUpdate: useForceUpdate(), - focusOnHeader: () => { - headerRef.current?.focus(); - }, + focusOnHeader, toggleCollapsed: () => toggleCollapsed_(path), }; @@ -175,12 +178,6 @@ export const ValueWithContextViewer: FC = ({ // In that case, the output would look broken (empty). const isOpen = !collapsible || !itemState.collapsed; - useEffect(() => { - if (isZoomedIn && !isRoot) { - handle.focusOnHeader(); - } - }, []); - const triangleToggle = () => { const Icon = itemState.collapsed ? CollapsedIcon : ExpandedIcon; const _hasExtraContentToShow = hasExtraContentToShow(value); @@ -265,19 +262,25 @@ export const ValueWithContextViewer: FC = ({ } }; - //Focus on the header on mount if focused - useEffect(() => { - if (isZoomedIn && !isRoot && headerRef && headerVisibility !== "hide") { - handle.focusOnHeader(); - } - }, []); + // Store the header reference for the future `focusOnHeader()` handle, and auto-focus zoomed in values on mount. + const setHeaderRef = useCallback( + (el: HTMLElement | null) => { + headerRef.current = el; + + // If `isZoomedIn` toggles from `false` to `true`, this callback identity will change and it will update the focus. + if (isZoomedIn) { + focusOnHeader(); + } + }, + [isZoomedIn, focusOnHeader] + ); return (
{headerVisibility !== "hide" && (
Date: Thu, 25 Jan 2024 13:53:27 -0600 Subject: [PATCH 4/5] no need for custom `key` --- .../src/components/SquiggleViewer/ValueViewer.tsx | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/packages/components/src/components/SquiggleViewer/ValueViewer.tsx b/packages/components/src/components/SquiggleViewer/ValueViewer.tsx index ab45b74f01..065f534b70 100644 --- a/packages/components/src/components/SquiggleViewer/ValueViewer.tsx +++ b/packages/components/src/components/SquiggleViewer/ValueViewer.tsx @@ -16,12 +16,5 @@ export const ValueViewer: React.FC = ({ value, ...rest }) => { return ; } - // The key ID is needed to make sure that when open a nested value as Focused, it will get focused. - return ( - - ); + return ; }; From da41d3e1d7600b20cc32f6c97538e8df740d0c05 Mon Sep 17 00:00:00 2001 From: Vyacheslav Matyukhin Date: Thu, 25 Jan 2024 14:12:58 -0600 Subject: [PATCH 5/5] move focusOnPath to ItemStore --- .../components/SquiggleViewer/ViewerProvider.tsx | 4 ++++ .../components/SquiggleViewer/keyboardNav/utils.ts | 8 -------- .../SquiggleViewer/keyboardNav/zoomedInSqValue.ts | 6 +++--- .../SquiggleViewer/keyboardNav/zoomedOutSqValue.ts | 14 ++++++-------- 4 files changed, 13 insertions(+), 19 deletions(-) diff --git a/packages/components/src/components/SquiggleViewer/ViewerProvider.tsx b/packages/components/src/components/SquiggleViewer/ViewerProvider.tsx index bc8d260603..70f8b22a74 100644 --- a/packages/components/src/components/SquiggleViewer/ViewerProvider.tsx +++ b/packages/components/src/components/SquiggleViewer/ViewerProvider.tsx @@ -166,6 +166,10 @@ export class ItemStore { scrollViewerToPath(path: SqValuePath) { this.handles[path.uid()]?.scrollIntoView(); } + + focusOnPath(path: SqValuePath) { + this.handles[path.uid()]?.focusOnHeader(); + } } type ViewerContextShape = { diff --git a/packages/components/src/components/SquiggleViewer/keyboardNav/utils.ts b/packages/components/src/components/SquiggleViewer/keyboardNav/utils.ts index 329bd50d40..279c3ffc62 100644 --- a/packages/components/src/components/SquiggleViewer/keyboardNav/utils.ts +++ b/packages/components/src/components/SquiggleViewer/keyboardNav/utils.ts @@ -1,11 +1,3 @@ -import { SqValuePath } from "@quri/squiggle-lang"; - -import { ItemStore } from "../ViewerProvider.js"; - -export const focusSqValueHeader = (path: SqValuePath, itemStore: ItemStore) => { - itemStore.handles[path.uid()]?.focusOnHeader(); -}; - // Returns boolean to indicate if the key was handled. The caller might want to do something else if it wasn't. export function keyboardEventHandler( handlers: Partial void>> diff --git a/packages/components/src/components/SquiggleViewer/keyboardNav/zoomedInSqValue.ts b/packages/components/src/components/SquiggleViewer/keyboardNav/zoomedInSqValue.ts index 9f3ad279df..1623e8e830 100644 --- a/packages/components/src/components/SquiggleViewer/keyboardNav/zoomedInSqValue.ts +++ b/packages/components/src/components/SquiggleViewer/keyboardNav/zoomedInSqValue.ts @@ -1,7 +1,7 @@ import { SqValuePath } from "@quri/squiggle-lang"; import { useViewerContext } from "../ViewerProvider.js"; -import { focusSqValueHeader, keyboardEventHandler } from "./utils.js"; +import { keyboardEventHandler } from "./utils.js"; export function useZoomedInSqValueKeyEvent(selected: SqValuePath) { const { @@ -15,7 +15,7 @@ export function useZoomedInSqValueKeyEvent(selected: SqValuePath) { // This timeout is a hack to make sure the header is zoomedIn after the reset setTimeout(() => { - focusSqValueHeader(selected, itemStore); + itemStore.focusOnPath(selected); }, 1); } @@ -45,7 +45,7 @@ export function useZoomedInSqValueKeyEvent(selected: SqValuePath) { ArrowRight: () => { const newItem = findNode(selected)?.children()[0]; if (newItem) { - focusSqValueHeader(newItem.node.path, itemStore); + itemStore.focusOnPath(newItem.node.path); } }, Enter: resetToRoot, diff --git a/packages/components/src/components/SquiggleViewer/keyboardNav/zoomedOutSqValue.ts b/packages/components/src/components/SquiggleViewer/keyboardNav/zoomedOutSqValue.ts index 188f8f07b2..f3b5c37cf2 100644 --- a/packages/components/src/components/SquiggleViewer/keyboardNav/zoomedOutSqValue.ts +++ b/packages/components/src/components/SquiggleViewer/keyboardNav/zoomedOutSqValue.ts @@ -1,7 +1,7 @@ import { SqValuePath } from "@quri/squiggle-lang"; import { toggleCollapsed, useViewerContext } from "../ViewerProvider.js"; -import { focusSqValueHeader, keyboardEventHandler } from "./utils.js"; +import { keyboardEventHandler } from "./utils.js"; export function useZoomedOutSqValueKeyEvent(selected: SqValuePath) { const { @@ -14,17 +14,15 @@ export function useZoomedOutSqValueKeyEvent(selected: SqValuePath) { return keyboardEventHandler({ ArrowDown: () => { const newPath = findNode(selected)?.next()?.node.path; - newPath && focusSqValueHeader(newPath, itemStore); + newPath && itemStore.focusOnPath(newPath); }, ArrowUp: () => { const newPath = findNode(selected)?.prev()?.node.path; - newPath && focusSqValueHeader(newPath, itemStore); + newPath && itemStore.focusOnPath(newPath); }, ArrowLeft: () => { const newItem = findNode(selected)?.parent(); - newItem && - !newItem.isRoot() && - focusSqValueHeader(newItem.node.path, itemStore); + newItem && !newItem.isRoot() && itemStore.focusOnPath(newItem.node.path); }, ArrowRight: () => { const newItem = findNode(selected)?.children().at(0); @@ -34,10 +32,10 @@ export function useZoomedOutSqValueKeyEvent(selected: SqValuePath) { if (isCollapsed) { toggleCollapsed(itemStore, selected); setTimeout(() => { - focusSqValueHeader(newItem.node.path, itemStore); + itemStore.focusOnPath(newItem.node.path); }, 1); } else { - focusSqValueHeader(newItem.node.path, itemStore); + itemStore.focusOnPath(newItem.node.path); } } },