SuggestModal select w/ modifier key

Suggest modals will often have instructions for different ways of selecting a suggestion (e.g. Enter does one thing, Shift+Enter does another, etc.). However, in my very basic implementation of a SuggestModal, holding down a key like Cmd, Shift, etc. while hitting Enter actually never fires either selectSuggestion nor chooseSuggestion. Is this expected behavior?

Here’s the implementation for those interested:

import { App, Notice } from "obsidian";
import { SuggestModal } from "./SuggestModal";
import { MyPlugin } from "~/plugin";

type SubtitledItem = {
  title: string;
  subtitle: string;
};

type SubtitledSelectorModalOptions = {
  initialValue?: string;
  suggestionsGetter: (query: string) => SubtitledItem[];
  actions?: Array<{
    id: string;
    command: string;
    purpose: string;
  }>;
  placeholder?: string;
};

export class SubtitledSelectorModal extends SuggestModal<SubtitledItem> {
  options: SubtitledItem[];
  initialValue: NonNullable<SubtitledSelectorModalOptions["initialValue"]>;
  suggestionsGetter: SubtitledSelectorModalOptions["suggestionsGetter"];

  constructor(
    app: App,
    plugin: MyPlugin,
    {
      initialValue = "",
      suggestionsGetter,
      placeholder = "",
      actions = [],
    }: SubtitledSelectorModalOptions
  ) {
    super(app, plugin);
    this.initialValue = initialValue;

    this.setPlaceholder(placeholder);
    this.setInstructions(actions);

    this.options = [];
    this.suggestionsGetter = suggestionsGetter;
  }

  onOpen() {
    super.onOpen();

    if (this.initialValue) {
      this.inputEl.value = this.initialValue;
      this.inputEl.focus();
      this.inputEl.dispatchEvent(new InputEvent("input"));
    }
  }

  // Render each suggestion item with title and subtitle
  renderSuggestion(item: SubtitledItem, el: HTMLElement) {
    const titleEl = el.createEl("div", {
      text: item.title,
      cls: "suggestion-title",
    });
    const subtitleEl = el.createEl("small", {
      text: item.subtitle,
      cls: "suggestion-subtitle",
    });

    // Optional: Add styling for better visibility
    titleEl.style.fontWeight = "bold";
    subtitleEl.style.color = "var(--color-base-40)";
  }

  // Return filtered options based on query
  getSuggestions(query: string): SubtitledItem[] {
    return this.suggestionsGetter(query);
  }

  onChooseSuggestion(item: SubtitledItem) {
    // ! this will never fire if you're holding down a modifier key
    console.log("onChooseSuggestion", item);
  }
}

Yes, it’s expected. You need to register keymap event handlers to the modal’s scope.

For example, the quick swticher modal has something like this in its constructor (you can see it in app.js):

    this.setInstructions([{
        command: "↑↓",
        purpose: h1.instructionNavigate()
    }, {
        command: "↵",
        purpose: h1.instructionOpen()
    }, {
        command: Platform.isMacOS ? "⌘ ↵" : "ctrl ↵",
        purpose: h1.instructionOpenInNewTab()
    }, {
        command: Platform.isMacOS ? "⌘ ⌥ ↵" : "ctrl alt ↵",
        purpose: h1.instructionOpenToTheRight()
    }, {
        command: "shift ↵",
        purpose: h1.instructionCreate()
    }, {
        command: "esc",
        purpose: h1.instructionDismiss()
    }]);
    return this.scope.register(["Shift"], "Enter", (function (e) {
        this.selectSuggestion(null, e);
        return false;
    }
    ));
    this.scope.register(["Mod", "Shift"], "Enter", (function (e) {
        this.selectSuggestion(null, e)
        return false;
    }
    ));
    this.scope.register(null, "Enter", (function (e) {
        this.selectActiveSuggestion(e)
        return false;
    }
    ))
1 Like

What is app.js? Where do I find it? The code you sent looks chopped up, I suppose app.js is where I find the full version, but where is it

Open Developer tool > Source tab > app.js

1 Like