obsidian-dev-utils 96.5.4 → 96.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/integration-test-plugin/main.js +335 -142
  3. package/dist/lib/cjs/__merged.cjs +6 -1
  4. package/dist/lib/cjs/__merged.d.cts +1 -0
  5. package/dist/lib/cjs/generated-during-build.cjs +2 -2
  6. package/dist/lib/cjs/obsidian/css-class.cjs +7 -1
  7. package/dist/lib/cjs/obsidian/css-class.d.cts +27 -0
  8. package/dist/lib/cjs/obsidian/modals/index.cjs +4 -1
  9. package/dist/lib/cjs/obsidian/modals/index.d.cts +1 -0
  10. package/dist/lib/cjs/obsidian/modals/modal-command-builder.cjs +460 -0
  11. package/dist/lib/cjs/obsidian/modals/modal-command-builder.d.cts +281 -0
  12. package/dist/lib/cjs/obsidian/modals/prompt.cjs +7 -1
  13. package/dist/lib/cjs/obsidian/modals/prompt.d.cts +15 -0
  14. package/dist/lib/cjs/obsidian/modals/suggest-modal-command-builder.cjs +3 -137
  15. package/dist/lib/cjs/obsidian/modals/suggest-modal-command-builder.d.cts +23 -159
  16. package/dist/lib/esm/__merged.d.mts +1 -0
  17. package/dist/lib/esm/__merged.mjs +7 -1
  18. package/dist/lib/esm/generated-during-build.mjs +2 -2
  19. package/dist/lib/esm/obsidian/css-class.d.mts +27 -0
  20. package/dist/lib/esm/obsidian/css-class.mjs +7 -1
  21. package/dist/lib/esm/obsidian/modals/index.d.mts +1 -0
  22. package/dist/lib/esm/obsidian/modals/index.mjs +3 -1
  23. package/dist/lib/esm/obsidian/modals/modal-command-builder.d.mts +281 -0
  24. package/dist/lib/esm/obsidian/modals/modal-command-builder.mjs +357 -0
  25. package/dist/lib/esm/obsidian/modals/prompt.d.mts +15 -0
  26. package/dist/lib/esm/obsidian/modals/prompt.mjs +7 -1
  27. package/dist/lib/esm/obsidian/modals/suggest-modal-command-builder.d.mts +23 -159
  28. package/dist/lib/esm/obsidian/modals/suggest-modal-command-builder.mjs +3 -140
  29. package/dist/styles.css +44 -1
  30. package/obsidian/modals/modal-command-builder/package.json +6 -0
  31. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 96.6.0
4
+
5
+ - feat(modals): let the command builder drive any modal, and prompt() take one
6
+
3
7
  ## 96.5.4
4
8
 
5
9
  - fix(templates): call parseVersionArguments, and type-check templates so a rename cannot ship broken
@@ -7403,6 +7403,7 @@ var init_css_class = __esm({
7403
7403
  CssClass3["DateTimeComponent"] = "datetime-component";
7404
7404
  CssClass3["EmailComponent"] = "email-component";
7405
7405
  CssClass3["FileComponent"] = "file-component";
7406
+ CssClass3["IsActive"] = "is-active";
7406
7407
  CssClass3["IsPlaceholder"] = "is-placeholder";
7407
7408
  CssClass3["LibraryName"] = "obsidian-dev-utils";
7408
7409
  CssClass3["MarkdownRendered"] = "markdown-rendered";
@@ -7411,6 +7412,9 @@ var init_css_class = __esm({
7411
7412
  CssClass3["MinimizedModalBar"] = "minimized-modal-bar";
7412
7413
  CssClass3["MinimizedModalBarAttention"] = "minimized-modal-bar-attention";
7413
7414
  CssClass3["MinimizedModalBarTitle"] = "minimized-modal-bar-title";
7415
+ CssClass3["ModalCommand"] = "modal-command";
7416
+ CssClass3["ModalCommandHotkey"] = "modal-command-hotkey";
7417
+ CssClass3["ModalCommands"] = "modal-commands";
7414
7418
  CssClass3["ModalHeaderButton"] = "modal-header-button";
7415
7419
  CssClass3["MonthComponent"] = "month-component";
7416
7420
  CssClass3["MultipleDropdownComponent"] = "multiple-dropdown-component";
@@ -7428,6 +7432,8 @@ var init_css_class = __esm({
7428
7432
  CssClass3["PluginSettingsTab"] = "plugin-settings-tab";
7429
7433
  CssClass3["PluginSuggestionBanner"] = "plugin-suggestion-banner";
7430
7434
  CssClass3["Popover"] = "popover";
7435
+ CssClass3["PromptInstruction"] = "prompt-instruction";
7436
+ CssClass3["PromptInstructions"] = "prompt-instructions";
7431
7437
  CssClass3["PromptModal"] = "prompt-modal";
7432
7438
  CssClass3["RestoreButton"] = "restore-button";
7433
7439
  CssClass3["SelectItemModal"] = "select-item-modal";
@@ -12704,6 +12710,8 @@ __export(merged_exports, {
12704
12710
  MinimizableModal: () => MinimizableModal,
12705
12711
  MissingPathTreatment: () => MissingPathTreatment,
12706
12712
  ModalBase: () => ModalBase,
12713
+ ModalCommandBuilder: () => ModalCommandBuilder,
12714
+ ModalCommandsRenderMode: () => ModalCommandsRenderMode,
12707
12715
  MonkeyAroundComponent: () => MonkeyAroundComponent,
12708
12716
  MonthComponent: () => MonthComponent,
12709
12717
  MultipleDisposeBehavior: () => MultipleDisposeBehavior,
@@ -36152,6 +36160,319 @@ function suppressWhilePeekLocked($event) {
36152
36160
  blockEvent($event);
36153
36161
  }
36154
36162
 
36163
+ // src/obsidian/modals/modal-command-builder.ts
36164
+ var modal_command_builder_exports = {};
36165
+ __export(modal_command_builder_exports, {
36166
+ ModalCommandBuilder: () => ModalCommandBuilder,
36167
+ ModalCommandsRenderMode: () => ModalCommandsRenderMode
36168
+ });
36169
+ var import_obsidian134 = require("obsidian");
36170
+ init_css_class();
36171
+ init_plugin_context();
36172
+ var KEYS_MAP = /* @__PURE__ */ new Map([
36173
+ ["Enter", "\u21B5"],
36174
+ ["UpDown", "\u2191\u2193"]
36175
+ ]);
36176
+ var ModalCommandsRenderMode = /* @__PURE__ */ ((ModalCommandsRenderMode2) => {
36177
+ ModalCommandsRenderMode2["Buttons"] = "buttons";
36178
+ ModalCommandsRenderMode2["Instructions"] = "instructions";
36179
+ return ModalCommandsRenderMode2;
36180
+ })(ModalCommandsRenderMode || {});
36181
+ var NOOP_MODAL_COMMANDS = {
36182
+ refresh: () => {
36183
+ }
36184
+ };
36185
+ var ModalCommandBuilder = class {
36186
+ entries = [];
36187
+ /**
36188
+ * Adds an interactive checkbox to the control strip, bound to a modifier+key shortcut that toggles it.
36189
+ *
36190
+ * @param command - The checkbox command to add.
36191
+ * @returns The builder instance for chaining.
36192
+ */
36193
+ addCheckbox(command) {
36194
+ this.entries.push({
36195
+ checkIsAvailable: command.checkIsAvailable ?? null,
36196
+ commandText: this.buildCommandText(command),
36197
+ initButton: (buttonEl, scope) => {
36198
+ const checkboxEl = createEl("input", { type: "checkbox" });
36199
+ initCheckbox(checkboxEl, scope);
36200
+ buttonEl.addEventListener("click", () => {
36201
+ toggleCheckbox(checkboxEl);
36202
+ });
36203
+ return {
36204
+ checkIsOn: () => checkboxEl.checked,
36205
+ setDisabled: (isDisabled) => {
36206
+ checkboxEl.disabled = isDisabled;
36207
+ buttonEl.disabled = isDisabled;
36208
+ }
36209
+ };
36210
+ },
36211
+ initInstruction: (purposeEl, scope) => initCheckbox(purposeEl.createEl("input", { type: "checkbox" }), scope),
36212
+ isDropDown: false,
36213
+ purpose: command.purpose,
36214
+ registerScope: null
36215
+ });
36216
+ return this;
36217
+ function initCheckbox(checkboxEl, scope) {
36218
+ command.onInit(checkboxEl);
36219
+ checkboxEl.addEventListener("change", () => {
36220
+ command.onChange(checkboxEl.checked);
36221
+ });
36222
+ scope.register(command.modifiers ?? [], command.key, () => {
36223
+ toggleCheckbox(checkboxEl);
36224
+ });
36225
+ return {
36226
+ setDisabled: (isDisabled) => {
36227
+ checkboxEl.disabled = isDisabled;
36228
+ }
36229
+ };
36230
+ }
36231
+ }
36232
+ /**
36233
+ * Adds a dropdown to the control strip, bound to a modifier+key shortcut that cycles through its
36234
+ * options.
36235
+ *
36236
+ * @param command - The dropdown command to add.
36237
+ * @returns The builder instance for chaining.
36238
+ */
36239
+ addDropDown(command) {
36240
+ this.entries.push({
36241
+ checkIsAvailable: command.checkIsAvailable ?? null,
36242
+ commandText: this.buildCommandText(command),
36243
+ initButton: null,
36244
+ initInstruction: (purposeEl, scope) => {
36245
+ purposeEl.appendText(" ");
36246
+ const dropdownComponent = new import_obsidian134.DropdownComponent(purposeEl);
36247
+ command.onInit(dropdownComponent);
36248
+ dropdownComponent.onChange((value) => {
36249
+ command.onChange(value);
36250
+ });
36251
+ scope.register(command.modifiers ?? [], command.key, () => {
36252
+ if (dropdownComponent.disabled) {
36253
+ return;
36254
+ }
36255
+ const selectEl = dropdownComponent.selectEl;
36256
+ selectEl.selectedIndex = (selectEl.selectedIndex + 1) % selectEl.options.length;
36257
+ selectEl.trigger("change");
36258
+ });
36259
+ return {
36260
+ setDisabled: (isDisabled) => {
36261
+ dropdownComponent.setDisabled(isDisabled);
36262
+ }
36263
+ };
36264
+ },
36265
+ isDropDown: true,
36266
+ purpose: command.purpose,
36267
+ registerScope: null
36268
+ });
36269
+ return this;
36270
+ }
36271
+ /**
36272
+ * Adds a keyboard command to the control strip. When {@link KeyboardCommand.onKey} is provided, its
36273
+ * handler is registered with the modal scope; otherwise the command is a hint only.
36274
+ *
36275
+ * @param command - The keyboard command to add.
36276
+ * @returns The builder instance for chaining.
36277
+ */
36278
+ addKeyboardCommand(command) {
36279
+ const checkIsOn = command.checkIsOn ?? (() => false);
36280
+ const onActivate = command.onActivate ?? null;
36281
+ const onKey = command.onKey?.bind(command) ?? null;
36282
+ this.entries.push({
36283
+ checkIsAvailable: command.checkIsAvailable ?? null,
36284
+ commandText: this.buildCommandText(command),
36285
+ initButton: onActivate ? (buttonEl) => {
36286
+ buttonEl.addEventListener("click", ($event) => {
36287
+ onActivate($event);
36288
+ });
36289
+ return {
36290
+ checkIsOn,
36291
+ setDisabled: (isDisabled) => {
36292
+ buttonEl.disabled = isDisabled;
36293
+ }
36294
+ };
36295
+ } : null,
36296
+ initInstruction: null,
36297
+ isDropDown: false,
36298
+ purpose: command.purpose,
36299
+ registerScope: onKey ? (scope) => {
36300
+ scope.register(command.modifiers ?? [], command.key, onKey);
36301
+ } : null
36302
+ });
36303
+ return this;
36304
+ }
36305
+ /**
36306
+ * Applies the accumulated commands to a modal. Always registers the essential navigation/action key
36307
+ * handlers; only renders the control strip and registers the option-toggle shortcuts when
36308
+ * {@link ModalCommandBuilderBuildOptions.shouldShowInstructions} is `true`.
36309
+ *
36310
+ * @param target - The modal, or the bare element + scope, to apply the commands to.
36311
+ * @param options - The build options.
36312
+ * @returns A handle whose {@link ModalCommands.refresh} re-states every rendered control.
36313
+ */
36314
+ build(target, options = {}) {
36315
+ const {
36316
+ renderMode = "instructions" /* Instructions */,
36317
+ shouldShowInstructions = true
36318
+ } = options;
36319
+ const scope = target.scope;
36320
+ for (const entry of this.entries) {
36321
+ entry.registerScope?.(scope);
36322
+ }
36323
+ if (!shouldShowInstructions) {
36324
+ return NOOP_MODAL_COMMANDS;
36325
+ }
36326
+ const refreshers = renderMode === "buttons" /* Buttons */ ? this.renderButtons(target, scope) : this.renderInstructions(target, scope);
36327
+ const modalCommands = {
36328
+ refresh: () => {
36329
+ for (const refreshControl of refreshers) {
36330
+ refreshControl();
36331
+ }
36332
+ }
36333
+ };
36334
+ modalCommands.refresh();
36335
+ return modalCommands;
36336
+ }
36337
+ buildCommandText(command) {
36338
+ let commandText = KEYS_MAP.get(command.key) ?? command.key;
36339
+ for (const modifier of command.modifiers ?? []) {
36340
+ commandText = `${this.getModifierString(modifier)} ${commandText}`;
36341
+ }
36342
+ return commandText;
36343
+ }
36344
+ getModifierString(modifier) {
36345
+ switch (modifier) {
36346
+ case "Alt": {
36347
+ return "alt";
36348
+ }
36349
+ case "Ctrl": {
36350
+ return "ctrl";
36351
+ }
36352
+ case "Meta": {
36353
+ return import_obsidian134.Platform.isMacOS ? "cmd" : "win";
36354
+ }
36355
+ case "Mod": {
36356
+ return import_obsidian134.Platform.isMacOS ? "cmd" : "ctrl";
36357
+ }
36358
+ case "Shift": {
36359
+ return "shift";
36360
+ }
36361
+ default: {
36362
+ return modifier;
36363
+ }
36364
+ }
36365
+ }
36366
+ /**
36367
+ * Resolves the element a self-created strip is appended to.
36368
+ *
36369
+ * A {@link Modal} carries both `modalEl` and a `containerEl` that is the OUTER `.modal-container`, so
36370
+ * `modalEl` has to win — otherwise the strip lands outside the modal frame. Discriminated with `in`
36371
+ * rather than a property read, because tests hand `build` a `strictProxy` mock whose `get` trap throws
36372
+ * on unmocked members.
36373
+ *
36374
+ * @param target - The build target.
36375
+ * @returns The element to append the strip to.
36376
+ */
36377
+ getStripContainerEl(target) {
36378
+ return "modalEl" in target ? target.modalEl : target.containerEl;
36379
+ }
36380
+ renderButtons(target, scope) {
36381
+ const stripEl = this.getStripContainerEl(target).createDiv();
36382
+ addPluginCssClasses(stripEl, "modal-commands" /* ModalCommands */);
36383
+ const refreshers = [];
36384
+ for (const entry of this.entries) {
36385
+ if (entry.isDropDown) {
36386
+ throw new Error(`Cannot render dropdown command "${entry.purpose}" as a button: a control that cycles has no button form.`);
36387
+ }
36388
+ if (!entry.initButton) {
36389
+ continue;
36390
+ }
36391
+ const buttonEl = stripEl.createEl("button", { type: "button" });
36392
+ addPluginCssClasses(buttonEl, "modal-command" /* ModalCommand */);
36393
+ buttonEl.createSpan({ text: entry.purpose });
36394
+ if (!import_obsidian134.Platform.isMobile) {
36395
+ const hotkeyEl = buttonEl.createSpan({ text: entry.commandText });
36396
+ addPluginCssClasses(hotkeyEl, "modal-command-hotkey" /* ModalCommandHotkey */);
36397
+ }
36398
+ buttonEl.addEventListener("mousedown", ($event) => {
36399
+ $event.preventDefault();
36400
+ });
36401
+ const buttonControl = entry.initButton(buttonEl, scope);
36402
+ const checkIsAvailable = entry.checkIsAvailable;
36403
+ refreshers.push(() => {
36404
+ if (checkIsAvailable) {
36405
+ buttonControl.setDisabled(!checkIsAvailable());
36406
+ }
36407
+ const isOn = buttonControl.checkIsOn();
36408
+ buttonEl.toggleClass("is-active" /* IsActive */, isOn);
36409
+ buttonEl.setAttribute("aria-pressed", String(isOn));
36410
+ });
36411
+ }
36412
+ return refreshers;
36413
+ }
36414
+ renderInstructions(target, scope) {
36415
+ const instructions = this.entries.map((entry) => ({
36416
+ command: entry.commandText,
36417
+ entry,
36418
+ purpose: entry.purpose
36419
+ }));
36420
+ const purposeEls = "setInstructions" in target ? this.renderNativeInstructions(target, instructions) : this.renderOwnInstructions(this.getStripContainerEl(target), instructions);
36421
+ const refreshers = [];
36422
+ for (const [index2, instruction] of instructions.entries()) {
36423
+ const purposeEl = purposeEls[index2];
36424
+ if (!purposeEl) {
36425
+ continue;
36426
+ }
36427
+ const instructionControl = instruction.entry.initInstruction?.(purposeEl, scope);
36428
+ const checkIsAvailable = instruction.entry.checkIsAvailable;
36429
+ if (instructionControl && checkIsAvailable) {
36430
+ refreshers.push(() => {
36431
+ instructionControl.setDisabled(!checkIsAvailable());
36432
+ });
36433
+ }
36434
+ }
36435
+ return refreshers;
36436
+ }
36437
+ /**
36438
+ * Renders through Obsidian's own instruction bar, the way every {@link SuggestModal} consumer has always
36439
+ * had it.
36440
+ *
36441
+ * @param modal - The suggest modal.
36442
+ * @param instructions - The instructions to render.
36443
+ * @returns The purpose element of each rendered instruction.
36444
+ */
36445
+ renderNativeInstructions(modal, instructions) {
36446
+ modal.setInstructions(instructions);
36447
+ return [...modal.instructionsEl.findAll(".prompt-instruction > span:nth-child(2)")];
36448
+ }
36449
+ /**
36450
+ * Renders an instruction bar of the builder's own, for a host that has none.
36451
+ *
36452
+ * The markup mirrors what `setInstructions` produces, so Obsidian's own styling applies unchanged.
36453
+ *
36454
+ * @param containerEl - The element to append the bar to.
36455
+ * @param instructions - The instructions to render.
36456
+ * @returns The purpose element of each rendered instruction.
36457
+ */
36458
+ renderOwnInstructions(containerEl, instructions) {
36459
+ const instructionsEl = containerEl.createDiv("prompt-instructions" /* PromptInstructions */);
36460
+ addPluginCssClasses(instructionsEl, "modal-commands" /* ModalCommands */);
36461
+ return instructions.map((instruction) => {
36462
+ const instructionEl = instructionsEl.createDiv("prompt-instruction" /* PromptInstruction */);
36463
+ instructionEl.createSpan({ text: instruction.command });
36464
+ return instructionEl.createSpan({ text: instruction.purpose });
36465
+ });
36466
+ }
36467
+ };
36468
+ function toggleCheckbox(checkboxEl) {
36469
+ if (checkboxEl.disabled) {
36470
+ return;
36471
+ }
36472
+ checkboxEl.checked = !checkboxEl.checked;
36473
+ checkboxEl.trigger("change");
36474
+ }
36475
+
36155
36476
  // src/__merged.ts
36156
36477
  init_modal();
36157
36478
 
@@ -36160,14 +36481,17 @@ var prompt_exports = {};
36160
36481
  __export(prompt_exports, {
36161
36482
  prompt: () => prompt
36162
36483
  });
36163
- var import_obsidian134 = require("obsidian");
36484
+ var import_obsidian135 = require("obsidian");
36164
36485
  init_async();
36165
36486
  init_function();
36487
+ init_object_utils();
36166
36488
  init_css_class();
36167
36489
  init_i18n();
36168
36490
  init_modal();
36169
36491
  var PromptModal = class extends ModalBase {
36170
36492
  cancelButtonText;
36493
+ commandBuilder;
36494
+ commandsRenderMode;
36171
36495
  isOkClicked = false;
36172
36496
  isTouched = false;
36173
36497
  okButtonText;
@@ -36179,6 +36503,8 @@ var PromptModal = class extends ModalBase {
36179
36503
  super(params);
36180
36504
  this.addCssClasses("prompt-modal" /* PromptModal */);
36181
36505
  this.cancelButtonText = params.cancelButtonText ?? t2(($) => $.obsidianDevUtils.buttons.cancel);
36506
+ this.commandBuilder = params.commandBuilder ?? null;
36507
+ this.commandsRenderMode = params.commandsRenderMode;
36182
36508
  this.okButtonText = params.okButtonText ?? t2(($) => $.obsidianDevUtils.buttons.ok);
36183
36509
  this.placeholder = params.placeholder ?? "";
36184
36510
  this.title = params.title ?? "";
@@ -36190,7 +36516,7 @@ var PromptModal = class extends ModalBase {
36190
36516
  }
36191
36517
  onOpen() {
36192
36518
  this.titleEl.setText(this.title);
36193
- const textComponent = new import_obsidian134.TextComponent(this.contentEl);
36519
+ const textComponent = new import_obsidian135.TextComponent(this.contentEl);
36194
36520
  const inputEl = textComponent.inputEl;
36195
36521
  inputEl.setAttribute("spellcheck", String(isSpellcheckEnabled(this.app)));
36196
36522
  const validate = async (shouldReport) => {
@@ -36225,17 +36551,18 @@ var PromptModal = class extends ModalBase {
36225
36551
  inputEl.addEventListener("input", convertAsyncToSync(handleInput));
36226
36552
  inputEl.addEventListener("focus", convertAsyncToSync(handleFocus));
36227
36553
  invokeAsyncSafely(() => validate(false));
36228
- const okButton = new import_obsidian134.ButtonComponent(this.contentEl);
36554
+ const okButton = new import_obsidian135.ButtonComponent(this.contentEl);
36229
36555
  okButton.setButtonText(this.okButtonText);
36230
36556
  okButton.setCta();
36231
36557
  okButton.onClick((event) => {
36232
36558
  this.handleOk(event, textComponent);
36233
36559
  });
36234
36560
  okButton.setClass("ok-button" /* OkButton */);
36235
- const cancelButton = new import_obsidian134.ButtonComponent(this.contentEl);
36561
+ const cancelButton = new import_obsidian135.ButtonComponent(this.contentEl);
36236
36562
  cancelButton.setButtonText(this.cancelButtonText);
36237
36563
  cancelButton.onClick(this.close.bind(this));
36238
36564
  cancelButton.setClass("cancel-button" /* CancelButton */);
36565
+ this.commandBuilder?.build(this, normalizeOptionalProperties({ renderMode: this.commandsRenderMode }));
36239
36566
  }
36240
36567
  handleOk(event, textComponent) {
36241
36568
  event.preventDefault();
@@ -36266,11 +36593,11 @@ var select_item_exports = {};
36266
36593
  __export(select_item_exports, {
36267
36594
  selectItem: () => selectItem
36268
36595
  });
36269
- var import_obsidian135 = require("obsidian");
36596
+ var import_obsidian136 = require("obsidian");
36270
36597
  init_css_class();
36271
36598
  init_plugin_context();
36272
36599
  init_modal();
36273
- var ItemSelectModal = class extends import_obsidian135.FuzzySuggestModal {
36600
+ var ItemSelectModal = class extends import_obsidian136.FuzzySuggestModal {
36274
36601
  isSelected = false;
36275
36602
  items;
36276
36603
  itemTextFunction;
@@ -36322,142 +36649,7 @@ var suggest_modal_command_builder_exports = {};
36322
36649
  __export(suggest_modal_command_builder_exports, {
36323
36650
  SuggestModalCommandBuilder: () => SuggestModalCommandBuilder
36324
36651
  });
36325
- var import_obsidian136 = require("obsidian");
36326
- var KEYS_MAP = /* @__PURE__ */ new Map([
36327
- ["Enter", "\u21B5"],
36328
- ["UpDown", "\u2191\u2193"]
36329
- ]);
36330
- var SuggestModalCommandBuilder = class {
36331
- instructions = [];
36332
- /**
36333
- * Adds an interactive checkbox to the instruction bar, bound to a modifier+key shortcut that toggles
36334
- * it.
36335
- *
36336
- * @param command - The checkbox command to add.
36337
- * @returns The builder instance for chaining.
36338
- */
36339
- addCheckbox(command) {
36340
- this.instructions.push({
36341
- command: this.buildCommand(command),
36342
- init: (purposeEl, scope) => {
36343
- const checkboxEl = purposeEl.createEl("input", { type: "checkbox" });
36344
- command.onInit(checkboxEl);
36345
- checkboxEl.addEventListener("change", () => {
36346
- command.onChange(checkboxEl.checked);
36347
- });
36348
- scope.register(command.modifiers ?? [], command.key, () => {
36349
- if (checkboxEl.disabled) {
36350
- return;
36351
- }
36352
- checkboxEl.checked = !checkboxEl.checked;
36353
- checkboxEl.trigger("change");
36354
- });
36355
- },
36356
- purpose: command.purpose
36357
- });
36358
- return this;
36359
- }
36360
- /**
36361
- * Adds a dropdown to the instruction bar, bound to a modifier+key shortcut that cycles through its
36362
- * options.
36363
- *
36364
- * @param command - The dropdown command to add.
36365
- * @returns The builder instance for chaining.
36366
- */
36367
- addDropDown(command) {
36368
- this.instructions.push({
36369
- command: this.buildCommand(command),
36370
- init: (purposeEl, scope) => {
36371
- purposeEl.appendText(" ");
36372
- const dropdownComponent = new import_obsidian136.DropdownComponent(purposeEl);
36373
- command.onInit(dropdownComponent);
36374
- dropdownComponent.onChange((value) => {
36375
- command.onChange(value);
36376
- });
36377
- scope.register(command.modifiers ?? [], command.key, () => {
36378
- if (dropdownComponent.disabled) {
36379
- return;
36380
- }
36381
- const selectEl = dropdownComponent.selectEl;
36382
- selectEl.selectedIndex = (selectEl.selectedIndex + 1) % selectEl.options.length;
36383
- selectEl.trigger("change");
36384
- });
36385
- },
36386
- purpose: command.purpose
36387
- });
36388
- return this;
36389
- }
36390
- /**
36391
- * Adds a keyboard command to the instruction bar. When {@link KeyboardCommand.onKey} is provided, its
36392
- * handler is registered with the modal scope; otherwise the command is a hint only.
36393
- *
36394
- * @param command - The keyboard command to add.
36395
- * @returns The builder instance for chaining.
36396
- */
36397
- addKeyboardCommand(command) {
36398
- this.instructions.push({
36399
- command: this.buildCommand(command),
36400
- purpose: command.purpose,
36401
- registerScope: (scope) => {
36402
- if (command.onKey) {
36403
- scope.register(command.modifiers ?? [], command.key, command.onKey.bind(command));
36404
- }
36405
- }
36406
- });
36407
- return this;
36408
- }
36409
- /**
36410
- * Applies the accumulated commands to a modal. Always registers the essential navigation/action key
36411
- * handlers; only renders the instruction UI and registers the option-toggle shortcuts when
36412
- * {@link SuggestModalCommandBuilderBuildOptions.shouldShowInstructions} is `true`.
36413
- *
36414
- * @param modal - The modal to apply the commands to.
36415
- * @param options - The build options.
36416
- */
36417
- build(modal, options = {}) {
36418
- const { shouldShowInstructions = true } = options;
36419
- for (const instruction of this.instructions) {
36420
- instruction.registerScope?.(modal.scope);
36421
- }
36422
- if (!shouldShowInstructions) {
36423
- return;
36424
- }
36425
- modal.setInstructions(this.instructions);
36426
- const purposeEls = [...modal.instructionsEl.findAll(".prompt-instruction > span:nth-child(2)")];
36427
- for (const [index2, purposeEl] of purposeEls.entries()) {
36428
- this.instructions[index2]?.init?.(purposeEl, modal.scope);
36429
- }
36430
- }
36431
- buildCommand(entry) {
36432
- let command = KEYS_MAP.get(entry.key) ?? entry.key;
36433
- for (const modifier of entry.modifiers ?? []) {
36434
- command = `${this.getModifierString(modifier)} ${command}`;
36435
- }
36436
- return command;
36437
- }
36438
- getModifierString(modifier) {
36439
- switch (modifier) {
36440
- case "Alt": {
36441
- return "alt";
36442
- }
36443
- case "Ctrl": {
36444
- return "ctrl";
36445
- }
36446
- case "Meta": {
36447
- return import_obsidian136.Platform.isMacOS ? "cmd" : "win";
36448
- }
36449
- case "Mod": {
36450
- return import_obsidian136.Platform.isMacOS ? "cmd" : "ctrl";
36451
- }
36452
- case "Shift": {
36453
- return "shift";
36454
- }
36455
- default: {
36456
- return modifier;
36457
- }
36458
- }
36459
- }
36460
- };
36652
+ var SuggestModalCommandBuilder = ModalCommandBuilder;
36461
36653
 
36462
36654
  // src/obsidian/note-priority.ts
36463
36655
  var note_priority_exports = {};
@@ -41207,6 +41399,7 @@ __export(modals_exports, {
41207
41399
  confirm: () => confirm_exports,
41208
41400
  "minimizable-modal": () => minimizable_modal_exports,
41209
41401
  modal: () => modal_exports,
41402
+ "modal-command-builder": () => modal_command_builder_exports,
41210
41403
  prompt: () => prompt_exports,
41211
41404
  "select-item": () => select_item_exports,
41212
41405
  "select-option": () => select_option_exports,