diff --git a/e2e/playwright/testing-segment-overlays.spec.ts b/e2e/playwright/testing-segment-overlays.spec.ts
index fa3876d7a..28b51733e 100644
--- a/e2e/playwright/testing-segment-overlays.spec.ts
+++ b/e2e/playwright/testing-segment-overlays.spec.ts
@@ -1445,7 +1445,7 @@ part001 = startSketchOn(XZ)
await page.getByTestId('overlay-menu').click()
await page.waitForTimeout(100)
- await page.getByText('Remove constraints').click()
+ await page.getByRole('button', { name: 'Remove constraints' }).click()
await editor.expectEditor.toContain(after, { shouldNormalise: true })
diff --git a/known-circular.txt b/known-circular.txt
index 45ea02e96..a6ea66441 100644
--- a/known-circular.txt
+++ b/known-circular.txt
@@ -3,11 +3,11 @@
> dpdm --no-warning --no-tree -T --skip-dynamic-imports=circular src/index.tsx
• Circular Dependencies
- 1) src/lang/std/sketch.ts -> src/lang/modifyAst.ts
- 2) src/lang/std/sketch.ts -> src/lang/modifyAst.ts -> src/lang/std/sketchcombos.ts
- 3) src/hooks/useModelingContext.ts -> src/components/ModelingMachineProvider.tsx -> src/components/Toolbar/setAngleLength.tsx -> src/components/SetAngleLengthModal.tsx -> src/lib/useCalculateKclExpression.ts
- 4) src/lib/singletons.ts -> src/editor/manager.ts -> src/lib/selections.ts
- 5) src/lib/singletons.ts -> src/editor/manager.ts -> src/lib/selections.ts
- 6) src/lib/singletons.ts -> src/lang/codeManager.ts
- 7) src/lib/singletons.ts -> src/clientSideScene/sceneEntities.ts -> src/clientSideScene/segments.ts -> src/components/Toolbar/angleLengthInfo.ts
- 8) src/lib/singletons.ts -> src/clientSideScene/sceneEntities.ts -> src/clientSideScene/segments.ts
+ 1) src/lib/singletons.ts -> src/editor/manager.ts -> src/lib/selections.ts
+ 2) src/lib/singletons.ts -> src/editor/manager.ts -> src/lib/selections.ts
+ 3) src/lib/singletons.ts -> src/lang/codeManager.ts
+ 4) src/lang/std/sketch.ts -> src/lang/modifyAst.ts
+ 5) src/lang/std/sketch.ts -> src/lang/modifyAst.ts -> src/lang/std/sketchcombos.ts
+ 6) src/lib/singletons.ts -> src/clientSideScene/sceneEntities.ts -> src/clientSideScene/segments.ts -> src/components/Toolbar/angleLengthInfo.ts
+ 7) src/lib/singletons.ts -> src/clientSideScene/sceneEntities.ts -> src/clientSideScene/segments.ts
+ 8) src/hooks/useModelingContext.ts -> src/components/ModelingMachineProvider.tsx -> src/components/Toolbar/setAngleLength.tsx -> src/components/SetAngleLengthModal.tsx -> src/lib/useCalculateKclExpression.ts
diff --git a/src/Toolbar.tsx b/src/Toolbar.tsx
index 589cb8391..424f89f56 100644
--- a/src/Toolbar.tsx
+++ b/src/Toolbar.tsx
@@ -25,8 +25,8 @@ import type {
ToolbarModeName,
} from '@src/lib/toolbar'
import { isToolbarItemResolvedDropdown, toolbarConfig } from '@src/lib/toolbar'
-import { isArray } from '@src/lib/utils'
import { commandBarActor } from '@src/lib/singletons'
+import { filterEscHotkey } from '@src/lib/hotkeyWrapper'
export function Toolbar({
className = '',
@@ -253,7 +253,8 @@ export function Toolbar({
!['available', 'experimental'].includes(
itemConfig.status
) ||
- itemConfig.disabled === true,
+ itemConfig.disabled === true ||
+ itemConfig.disableHotkey === true,
status: itemConfig.status,
}))}
>
@@ -410,6 +411,10 @@ const ToolbarItemTooltip = memo(function ToolbarItemContents({
contentClassName = '',
children,
}: ToolbarItemContentsProps) {
+ /**
+ * GOTCHA: `useHotkeys` can only register one hotkey listener per component.
+ * TODO: make a global hotkey registration system. make them editable.
+ */
useHotkeys(
itemConfig.hotkey || '',
() => {
@@ -469,7 +474,7 @@ const ToolbarItemTooltipShortContent = ({
{title}
{hotkey && (
- {displayHotkeys(hotkey)}
+ {filterEscHotkey(hotkey)}
)}
@@ -510,7 +515,7 @@ const ToolbarItemTooltipRichContent = ({
{shouldBeEnabled && itemConfig.hotkey ? (
- {displayHotkeys(itemConfig.hotkey)}
+ {filterEscHotkey(itemConfig.hotkey)}
) : itemConfig.status === 'kcl-only' ? (
<>
@@ -573,11 +578,6 @@ const ToolbarItemTooltipRichContent = ({
)
}
-// We don't want to display Esc hotkeys to avoid confusion in the Toolbar UI (eg. "EscR")
-function displayHotkeys(hotkey: string | string[]) {
- return (isArray(hotkey) ? hotkey : [hotkey]).filter((h) => h !== 'Esc')
-}
-
function isToolbarDropdown(
item: ToolbarItem | ToolbarDropdown
): item is ToolbarDropdown {
diff --git a/src/components/ActionButtonDropdown.tsx b/src/components/ActionButtonDropdown.tsx
index bb850f893..c3525cdfc 100644
--- a/src/components/ActionButtonDropdown.tsx
+++ b/src/components/ActionButtonDropdown.tsx
@@ -3,6 +3,8 @@ import { Popover } from '@headlessui/react'
import type { ActionButtonProps } from '@src/components/ActionButton'
import { CustomIcon } from '@src/components/CustomIcon'
import Tooltip from '@src/components/Tooltip'
+import { filterEscHotkey } from '@src/lib/hotkeyWrapper'
+import { useHotkeys } from 'react-hotkeys-hook'
type ActionButtonSplitProps = ActionButtonProps & { Element: 'button' } & {
name?: string
@@ -10,7 +12,7 @@ type ActionButtonSplitProps = ActionButtonProps & { Element: 'button' } & {
splitMenuItems: {
id: string
label: string
- shortcut?: string
+ hotkey?: string | string[]
onClick: () => void
disabled?: boolean
status?: 'available' | 'unavailable' | 'kcl-only' | 'experimental'
@@ -63,54 +65,18 @@ export function ActionButtonDropdown({