authorgravatar for 88523594+RakshithBhat03@users.noreply.github.comRakshith Bhat <88523594+RakshithBhat03@users.noreply.github.com> 2026-09-02 09:44:32+05:30
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-02 00:14:32-04:00
loga1a2bb1cd9f000f53fbeae752ed5c38f152eadf2
treeb9d4d6292e09c7257c5dcf0dfa9d66db99022b9a
parente9db39ce05c706122bb747fd5e7e70e1aac78935
signature Signed by PGP key B5690EEEBB952194

fix(web): label keybinding condition removal actions (#8664)


3 files changed, 68 insertions(+), 30 deletions(-)

apps/web/src/components/settings/KeybindingsSettings.logic.test.ts+14
......@@ -12,6 +12,7 @@ import {
1212 shortcutToKeybindingInput,
1313 unknownWhenVariables,
1414 whenAstToExpression,
15 whenNodeRemoveLabel,
1516} from "./KeybindingsSettings.logic";
1617
1718describe("KeybindingsSettings.logic", () => {
......@@ -120,6 +121,19 @@ describe("KeybindingsSettings.logic", () => {
120121 });
121122 });
122123
124 it("describes the scope of each visual expression removal", () => {
125 const condition = { type: "identifier", name: "terminalFocus" } as const;
126 const negatedCondition = { type: "not", node: condition } as const;
127 const group = { type: "and", left: condition, right: negatedCondition } as const;
128 const negatedGroup = { type: "not", node: group } as const;
129
130 expect(whenNodeRemoveLabel(group, 0)).toBe("Clear all conditions");
131 expect(whenNodeRemoveLabel(condition, 1)).toBe("Remove condition");
132 expect(whenNodeRemoveLabel(negatedCondition, 1)).toBe("Remove condition");
133 expect(whenNodeRemoveLabel(group, 1)).toBe("Remove group and its conditions");
134 expect(whenNodeRemoveLabel(negatedGroup, 1)).toBe("Remove group and its conditions");
135 });
136
123137 it("formats static and project script command labels", () => {
124138 expect(commandLabel("commandPalette.toggle")).toBe("Command Palette: Toggle");
125139 expect(commandLabel("themeEditor.toggle")).toBe("Theme Editor: Toggle");
apps/web/src/components/settings/KeybindingsSettings.logic.ts+8
......@@ -68,6 +68,14 @@ export function whenAstToExpression(node: KeybindingWhenNode | undefined): strin
6868 }
6969}
7070
71export function whenNodeRemoveLabel(node: KeybindingWhenNode, depth: number): string {
72 if (depth === 0) return "Clear all conditions";
73 if (node.type === "identifier" || (node.type === "not" && node.node.type === "identifier")) {
74 return "Remove condition";
75 }
76 return "Remove group and its conditions";
77}
78
7179function wrapWhenExpression(node: KeybindingWhenNode): string {
7280 if (node.type === "identifier" || node.type === "not") return whenAstToExpression(node);
7381 return `(${whenAstToExpression(node)})`;
apps/web/src/components/settings/KeybindingsSettings.tsx+46-30
......@@ -67,6 +67,7 @@ import {
6767 type WhenVariableOption,
6868 unknownWhenVariables,
6969 whenAstToExpression,
70 whenNodeRemoveLabel,
7071} from "./KeybindingsSettings.logic";
7172import { SettingsPageContainer, SettingsRow, SettingsSection } from "./settingsLayout";
7273import { searchableSetting } from "./settingsSearch";
......@@ -349,6 +350,37 @@ function WhenVariableSelect({
349350 );
350351}
351352
353function WhenExpressionRemoveButton({
354 label,
355 className,
356 onRemove,
357}: {
358 label: string;
359 className?: string | undefined;
360 onRemove: () => void;
361}) {
362 return (
363 <Tooltip>
364 <TooltipTrigger
365 delay={200}
366 render={
367 <Button
368 type="button"
369 variant="ghost"
370 size="icon-sm"
371 className={cn("size-7", className)}
372 aria-label={label}
373 onClick={onRemove}
374 />
375 }
376 >
377 <MinusIcon aria-hidden className="size-3.5" />
378 </TooltipTrigger>
379 <TooltipPopup side="top">{label}</TooltipPopup>
380 </Tooltip>
381 );
382}
383
352384function WhenExpressionNodeEditor({
353385 node,
354386 variables,
......@@ -388,16 +420,10 @@ function WhenExpressionNodeEditor({
388420 onChange={(value) => onChange(setConditionIdentifier(node, value))}
389421 />
390422 {onRemove ? (
391 <Button
392 type="button"
393 variant="ghost"
394 size="icon-sm"
395 className="size-7"
396 aria-label="Remove condition"
397 onClick={onRemove}
398 >
399 <MinusIcon className="size-3.5" />
400 </Button>
423 <WhenExpressionRemoveButton
424 label={whenNodeRemoveLabel(node, depth)}
425 onRemove={onRemove}
426 />
401427 ) : null}
402428 </div>
403429 );
......@@ -423,16 +449,11 @@ function WhenExpressionNodeEditor({
423449 Not
424450 </Toggle>
425451 {onRemove ? (
426 <Button
427 type="button"
428 variant="ghost"
429 size="icon-sm"
430 className="ml-auto size-7"
431 aria-label="Remove negated group"
432 onClick={onRemove}
433 >
434 <MinusIcon className="size-3.5" />
435 </Button>
452 <WhenExpressionRemoveButton
453 label={whenNodeRemoveLabel(node, depth)}
454 className="ml-auto"
455 onRemove={onRemove}
456 />
436457 ) : null}
437458 </div>
438459 <div className="relative pl-4">
......@@ -546,16 +567,11 @@ function WhenExpressionNodeEditor({
546567 Group
547568 </Button>
548569 {onRemove ? (
549 <Button
550 type="button"
551 variant="ghost"
552 size="icon-sm"
553 className="ml-auto size-7"
554 aria-label="Remove group"
555 onClick={onRemove}
556 >
557 <MinusIcon className="size-3.5" />
558 </Button>
570 <WhenExpressionRemoveButton
571 label={whenNodeRemoveLabel(node, depth)}
572 className="ml-auto"
573 onRemove={onRemove}
574 />
559575 ) : null}
560576 </div>
561577 <div className="space-y-2">