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
@@ -0,0 +1,281 @@
1
+ /// <reference path="../../library.d.mts" />
2
+ /**
3
+ * @file
4
+ *
5
+ * A builder for a modal's control strip.
6
+ *
7
+ * {@link ModalCommandBuilder} assembles the strip of controls shown at the bottom of a modal:
8
+ * keyboard-command hints ({@link ModalCommandBuilder.addKeyboardCommand}), interactive checkboxes bound to
9
+ * a modifier+key shortcut ({@link ModalCommandBuilder.addCheckbox}), and dropdowns bound to a modifier+key
10
+ * shortcut ({@link ModalCommandBuilder.addDropDown}). Chain the `add*` calls, then apply everything to a
11
+ * modal with {@link ModalCommandBuilder.build}:
12
+ *
13
+ * ```ts
14
+ * new ModalCommandBuilder()
15
+ * .addKeyboardCommand({ key: 'Enter', modifiers: ['Mod'], onKey, purpose: 'to create' })
16
+ * .addCheckbox({ key: '1', modifiers: ['Alt'], onChange, onInit, purpose: 'Fix footnotes' })
17
+ * .build(modal);
18
+ * ```
19
+ *
20
+ * The strip is described by two independent axes:
21
+ *
22
+ * - **Where it is hosted.** A {@link SuggestModal} in {@link ModalCommandsRenderMode.Instructions} mode
23
+ * keeps Obsidian's own instruction bar (`setInstructions` + `instructionsEl`). Every other target — a
24
+ * plain {@link Modal}, or a bare {@link ModalCommandsHost} of an element plus a `Scope` — gets a strip
25
+ * element the builder creates itself.
26
+ * - **How each control looks.** {@link ModalCommandsRenderMode.Instructions} renders the purpose text with
27
+ * an inline checkbox or dropdown; {@link ModalCommandsRenderMode.Buttons} renders one clickable button
28
+ * per control, carrying its pressed and disabled state.
29
+ *
30
+ * The axes are independent because a button strip inside a {@link SuggestModal} is a real combination.
31
+ *
32
+ * {@link ModalCommandBuilder.build} always registers the essential navigation/action key handlers, but
33
+ * only renders the control UI and registers the option-toggle shortcuts when
34
+ * {@link ModalCommandBuilderBuildOptions.shouldShowInstructions} is `true` (the default).
35
+ */
36
+ import type { KeymapContext, Modal, Modifier, Scope, SuggestModal } from 'obsidian';
37
+ import { DropdownComponent } from 'obsidian';
38
+ /**
39
+ * The way {@link ModalCommandBuilder.build} renders each control.
40
+ */
41
+ export declare enum ModalCommandsRenderMode {
42
+ /**
43
+ * One clickable button per control, carrying its pressed (`aria-pressed`) and disabled state.
44
+ *
45
+ * Only controls reachable by pointer are rendered — checkboxes, and keyboard commands that supply
46
+ * {@link KeyboardCommand.onActivate}. A hint-only or keyboard-only command still registers its handler
47
+ * but renders no button, because a button nobody can press is worse than no button. A dropdown throws:
48
+ * a control that CYCLES has no button form.
49
+ */
50
+ Buttons = "buttons",
51
+ /**
52
+ * Obsidian's instruction-bar look: the shortcut, then the purpose text with an inline checkbox or
53
+ * dropdown.
54
+ */
55
+ Instructions = "instructions"
56
+ }
57
+ /**
58
+ * A checkbox command shown in a modal's control strip and bound to a modifier+key shortcut that toggles
59
+ * it.
60
+ */
61
+ export interface CheckboxCommand extends CommandBase {
62
+ /**
63
+ * Called when the checkbox value changes.
64
+ *
65
+ * @param isChecked - The new checked state.
66
+ */
67
+ onChange(isChecked: boolean): void;
68
+ /**
69
+ * Called once with the created checkbox element, to initialize its state.
70
+ *
71
+ * In {@link ModalCommandsRenderMode.Buttons} mode the element is created but never appended — the
72
+ * button is a view of it — so the same initialization code serves both render modes.
73
+ *
74
+ * @param checkboxEl - The created checkbox element.
75
+ */
76
+ onInit(checkboxEl: HTMLInputElement): void;
77
+ }
78
+ /**
79
+ * The members every command shares.
80
+ */
81
+ export interface CommandBase {
82
+ /**
83
+ * Whether the control can be used right now. When it returns `false` the control is rendered
84
+ * **disabled rather than removed**, so the strip does not reflow under the pointer as modes change —
85
+ * which on a phone means a mis-tap.
86
+ *
87
+ * Re-read by {@link ModalCommands.refresh}. When omitted, the builder never touches the control's
88
+ * disabled state, leaving whatever {@link CheckboxCommand.onInit} / {@link DropDownCommand.onInit} set.
89
+ *
90
+ * @returns Whether the control can be used right now.
91
+ */
92
+ checkIsAvailable?(this: void): boolean;
93
+ /**
94
+ * The key that activates the command.
95
+ */
96
+ key: string;
97
+ /**
98
+ * The modifiers combined with {@link CommandBase.key}. When omitted, no modifiers are required.
99
+ */
100
+ modifiers?: Modifier[];
101
+ /**
102
+ * The human-readable description shown next to the control.
103
+ */
104
+ purpose: string;
105
+ }
106
+ /**
107
+ * A dropdown command shown in a modal's control strip and bound to a modifier+key shortcut that cycles
108
+ * through its options.
109
+ *
110
+ * Supported in {@link ModalCommandsRenderMode.Instructions} mode only.
111
+ */
112
+ export interface DropDownCommand extends CommandBase {
113
+ /**
114
+ * Called when the dropdown value changes.
115
+ *
116
+ * @param value - The newly selected value.
117
+ */
118
+ onChange(value: string): void;
119
+ /**
120
+ * Called once with the created dropdown component, to initialize its options and state.
121
+ *
122
+ * @param dropdownComponent - The created dropdown component.
123
+ */
124
+ onInit(dropdownComponent: DropdownComponent): void;
125
+ }
126
+ /**
127
+ * A keyboard command shown in a modal's control strip and optionally bound to a modifier+key handler.
128
+ */
129
+ export interface KeyboardCommand extends CommandBase {
130
+ /**
131
+ * Whether the command reads as ON. Supply it for a toggle whose state lives outside the strip; omit it
132
+ * for an action, which does something and is done. A {@link CheckboxCommand} needs no equivalent — its
133
+ * checkbox element is the state.
134
+ *
135
+ * Re-read by {@link ModalCommands.refresh}.
136
+ *
137
+ * @returns Whether the command reads as ON.
138
+ */
139
+ checkIsOn?(this: void): boolean;
140
+ /**
141
+ * The pointer route into the same handler the shortcut runs. Required for the command to render a
142
+ * button in {@link ModalCommandsRenderMode.Buttons} mode — on a phone there is no modifier key to
143
+ * press, so this is the only way in.
144
+ *
145
+ * @param $event - The click event, so a command that picks something has one to hand on.
146
+ */
147
+ onActivate?(this: void, $event: MouseEvent): void;
148
+ /**
149
+ * The handler invoked when the shortcut is pressed. When omitted, the command is a hint only and no
150
+ * scope handler is registered.
151
+ *
152
+ * @param $event - The keyboard event.
153
+ * @param context - The keymap context.
154
+ * @returns `false` to prevent Obsidian's default handling, or `void`/`true` otherwise.
155
+ */
156
+ onKey?($event: KeyboardEvent, context: KeymapContext): boolean;
157
+ }
158
+ /**
159
+ * Options for {@link ModalCommandBuilder.build}.
160
+ */
161
+ export interface ModalCommandBuilderBuildOptions {
162
+ /**
163
+ * The way each control is rendered.
164
+ *
165
+ * @default {@link ModalCommandsRenderMode.Instructions}
166
+ */
167
+ readonly renderMode?: ModalCommandsRenderMode;
168
+ /**
169
+ * Whether to render the control strip (checkboxes, dropdowns, keyboard hints) and register the
170
+ * option-toggle keyboard shortcuts. When `false`, no control UI is shown and the option-toggle
171
+ * shortcuts are not registered; only the essential navigation key handlers remain active.
172
+ *
173
+ * @default `true`
174
+ */
175
+ readonly shouldShowInstructions?: boolean;
176
+ }
177
+ /**
178
+ * The handle returned by {@link ModalCommandBuilder.build}.
179
+ */
180
+ export interface ModalCommands {
181
+ /**
182
+ * Brings every rendered control's disabled and pressed state up to date, by re-reading
183
+ * {@link CommandBase.checkIsAvailable} and {@link KeyboardCommand.checkIsOn}.
184
+ *
185
+ * The strip is built once and only re-stated afterwards, because rebuilding it would replace an element
186
+ * the pointer may be about to click.
187
+ */
188
+ refresh(): void;
189
+ }
190
+ /**
191
+ * A bare host for a control strip: the element to render into, plus the scope to register shortcuts with.
192
+ */
193
+ export interface ModalCommandsHost {
194
+ /**
195
+ * The element the control strip is appended to.
196
+ */
197
+ readonly containerEl: HTMLElement;
198
+ /**
199
+ * The scope the shortcuts are registered with.
200
+ */
201
+ readonly scope: Scope;
202
+ }
203
+ /**
204
+ * Every target {@link ModalCommandBuilder.build} accepts.
205
+ */
206
+ export type ModalCommandsTarget = Modal | ModalCommandsHost | SuggestModal<unknown>;
207
+ /**
208
+ * Builds a modal's control strip from keyboard commands, interactive checkboxes, and dropdowns, then
209
+ * applies them to a modal via {@link ModalCommandBuilder.build}.
210
+ */
211
+ export declare class ModalCommandBuilder {
212
+ private readonly entries;
213
+ /**
214
+ * Adds an interactive checkbox to the control strip, bound to a modifier+key shortcut that toggles it.
215
+ *
216
+ * @param command - The checkbox command to add.
217
+ * @returns The builder instance for chaining.
218
+ */
219
+ addCheckbox(command: CheckboxCommand): this;
220
+ /**
221
+ * Adds a dropdown to the control strip, bound to a modifier+key shortcut that cycles through its
222
+ * options.
223
+ *
224
+ * @param command - The dropdown command to add.
225
+ * @returns The builder instance for chaining.
226
+ */
227
+ addDropDown(command: DropDownCommand): this;
228
+ /**
229
+ * Adds a keyboard command to the control strip. When {@link KeyboardCommand.onKey} is provided, its
230
+ * handler is registered with the modal scope; otherwise the command is a hint only.
231
+ *
232
+ * @param command - The keyboard command to add.
233
+ * @returns The builder instance for chaining.
234
+ */
235
+ addKeyboardCommand(command: KeyboardCommand): this;
236
+ /**
237
+ * Applies the accumulated commands to a modal. Always registers the essential navigation/action key
238
+ * handlers; only renders the control strip and registers the option-toggle shortcuts when
239
+ * {@link ModalCommandBuilderBuildOptions.shouldShowInstructions} is `true`.
240
+ *
241
+ * @param target - The modal, or the bare element + scope, to apply the commands to.
242
+ * @param options - The build options.
243
+ * @returns A handle whose {@link ModalCommands.refresh} re-states every rendered control.
244
+ */
245
+ build(target: ModalCommandsTarget, options?: ModalCommandBuilderBuildOptions): ModalCommands;
246
+ private buildCommandText;
247
+ private getModifierString;
248
+ /**
249
+ * Resolves the element a self-created strip is appended to.
250
+ *
251
+ * A {@link Modal} carries both `modalEl` and a `containerEl` that is the OUTER `.modal-container`, so
252
+ * `modalEl` has to win — otherwise the strip lands outside the modal frame. Discriminated with `in`
253
+ * rather than a property read, because tests hand `build` a `strictProxy` mock whose `get` trap throws
254
+ * on unmocked members.
255
+ *
256
+ * @param target - The build target.
257
+ * @returns The element to append the strip to.
258
+ */
259
+ private getStripContainerEl;
260
+ private renderButtons;
261
+ private renderInstructions;
262
+ /**
263
+ * Renders through Obsidian's own instruction bar, the way every {@link SuggestModal} consumer has always
264
+ * had it.
265
+ *
266
+ * @param modal - The suggest modal.
267
+ * @param instructions - The instructions to render.
268
+ * @returns The purpose element of each rendered instruction.
269
+ */
270
+ private renderNativeInstructions;
271
+ /**
272
+ * Renders an instruction bar of the builder's own, for a host that has none.
273
+ *
274
+ * The markup mirrors what `setInstructions` produces, so Obsidian's own styling applies unchanged.
275
+ *
276
+ * @param containerEl - The element to append the bar to.
277
+ * @param instructions - The instructions to render.
278
+ * @returns The purpose element of each rendered instruction.
279
+ */
280
+ private renderOwnInstructions;
281
+ }