How to know if a dialog is closed with AltKey

Given a dialog of the form:

<dialog id="dlg">
  <form method="dialog">
    <sp-textfield type="text"></sp-textfield>
    <sp-button type="submit" id="formTestButton">Submit</sp-button>
  </form>
</dialog>

You can use this JS to respond to normal or alternate dismissal:

function decorateDialogWithAltKeySubmission(theDialog, {normal, alternate} = {}) {
  const theDialogForm = theDialog.querySelector("form");

  // if dialog has been decorated before, bail
  if (theDialog.dataset.decorated) return;

  // keep track of user's intent throughout key presses, clicks, and submits
  let theDialogReturnValue = normal;

  // detect if ALT is pressed
  function setDialogReturnValue(event) {
      if (event.altKey === undefined) return; // ignore events where this
                                              // isn't set so we don't
                                              // forget the user intent
      // pick the right return value based on altKey
      theDialogReturnValue = event.altKey ? alternate : normal;
  }

  // if user presses ENTER, we want a chance to see if ALT is pressed
  theDialogForm.addEventListener("keydown", event => {
    if (event.key !== "Enter") return; // bail if ENTER isn't pressed
    setDialogReturnValue(event);
  });

  // If the form is submitted, forward along our return value
  theDialogForm.addEventListener("submit", (event) => {
    event.preventDefault(); // prevent default blank (""_ return value
    theDialog.close(theDialogReturnValue);
  });

  // sp-buttons don't automatically act as submit buttons, so 
  // check for ALT here and close
  theDialogForm.querySelector("sp-button[type=submit]")
    .addEventListener("click", event => {
    setDialogReturnValue(event);
    theDialog.close(theDialogReturnValue);
  });

  // don't decorate the dialog again
  theDialog.dataset.decorated = "yes"; 
}

Then “decorate” the dialog with:

const theDialog = document.querySelector("#dlg");
decorateDialogWithAltKeySubmission(theDialog , {
  normal: "translate", // return if ALT is not pressed
  alternate: "duplicate" // return if ALT is pressed
});

Then when you show and get a response, you’ll get reasonCanceled (ESC or other dismissal), the “normal” response (translate) if ALT is not held, and the “alternate” response (duplicate) if ALT is held.

const response = await theDialog.uxpShowModal({
    title: "Title",
    size: { width: 480, height: 320 }
})

if (response === "reasonCanceled") return;
if (response === "translate") { /* do translate stuff */ }
if (response === "duplicate") { /* do duplicate stuff */ }

Some other observations:

  • <button> in PS doesn’t send UXP any modifiers. As such, altKey (et al) will all be false. Yes, I’d call it a bug, but the workaround is to use sp-button.
  • <sp-button>, however, is controlled by UXP and does send modifiers. altKey will contain the state of the Alt key (whatever that is for the OS in question)
  • ctrl+click has lots of funky behavior in Ps – on a <button>, submission will happen, but you won’t see ctrlKey === true (it’ll be false). On an <sp-button>, ctrl+click won’t submit or send a click event at all.
  • As such, your most reliable option is <sp-button> and avoid the ctrl key.
1 Like