Bare setTimeout/activeWindow.requestAnimationFrame calls should
resolve via window explicitly for popout-window compatibility - if a
command is added from a floating window, the timer needs to run
against that window rather than whatever window happens to be
"active". Affects macro DELAY actions, the page-header button
refresh, and a couple of confetti-timed link opens.
Applies one consistent rule across main.ts and every command manager
(leftRibbon/pageHeader/statusBar/titleBar/explorer/menu):
- Inside an already-async handler (onClick, onclick, event listeners),
await the addCommand/removeCommand/reorder/removeMenu call so
settings are actually saved before the handler resolves, matching
the style already used by the adjacent Change Icon/Rename handlers
in the same files.
- In genuinely fire-and-forget contexts (executeStartupMacros,
forEach over settings on construction), mark the call with `void`
instead, since making the caller async there isn't warranted and
the existing concurrent-fire behavior is intentional.
- Drop `async` from a few addEventListener("transitionend", ...)
callbacks that never awaited anything - the async was doing nothing
but triggering the misused-promises warning.
- executeMacro's COMMAND/LOOP actions no longer await
executeCommandById, since it's synchronous (returns void, not a
Promise) - the await was already a no-op.
- Reject with Error objects instead of plain strings in the three
awaitSelection() modals (addCommand/chooseIcon/chooseCustomName),
since nothing reads the specific string value of these rejections.
No sequencing that previously happened is removed; this only adds
missing awaits/void or removes awaits/async that were already inert.
Worth exercising the affected menus (status bar, title bar, page
header, explorer, left ribbon, right-click "Add/Change Icon/Rename/
Delete") to confirm they still save and update correctly.
- Add explicit `(): void` return types to several useEffect cleanup
callbacks (settingTabComponent, ColorPicker, AdvancedToolbarSettings,
mobileModifyComponent).
- Widen Mode's literal union with `(string & {})` instead of a bare
string constituent, preserving autocomplete without the redundant
type warning.
- Drop an unnecessary `as ItemView` cast in pageHeaderManager now that
the preceding instanceof guard already narrows the type.
- Switch eslint.config.mts from the deprecated tseslint.config() to
eslint's own defineConfig().
Type-level only, no runtime behavior change.
- Remove unused imports (getIconIds, setIcon, exp, arrayMoveMutable, etc.)
- Add missing explicit return types on functions and arrow functions
- Add public accessibility modifier to PageHeaderManager.buttons
- Fix mixed spaces/tabs in constants.ts and commandComponent.tsx
- Wrap case block declaration in MacroBuilder.tsx to fix no-case-declarations
- Add eslint-disable comments for false-positive no-unused-vars on
function type annotation parameter names and TypeScript enum members
- Remove dead forceUpdate reference in MacroBuilder.tsx (was referencing
this in a function component)
Reduces from 64 errors + 2 warnings to 0 errors + 2 warnings (the remaining
warnings are intentional non-null assertions).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Fix memory leaks and cleanup issues
- Remove buttons when plugin is unloaded
- Each time a .registerX() method is called, it adds another closure to the plugin
and keeps it there until the plugin is unloaded. Calling it multiple times for
the same thing uses memory unnecessarily
- It's not necesaray to registerDomEvent for events registered on HTML that the
plugin itself will remove from the page when it unloads, and doing so for each
button each time leaks the memory.
* Always init header buttons, even w/title bar off
Some plugins and themes show the tab title bar even when it's
turned off in settings. Also, not initializing means if you
turn the titlebar on in settings, you'd have to restart Obsidian
to get the buttons showing.
* Only add buttons when needed
Buttons only need to be added when the layout changes (either due
to a new tab or a file being loaded into a tab). Using the
layout-change event instead of file-open handles both of these
cases.
* Use core API to create buttons; update all on add
Using addAction() and setActiveLeaf() ensures consistency
with any future HTML changes, cuts down on duplicate code.
(It also gets rid of the issue where right-clicking a button
could also trigger it.)
* Track added buttons, support multi-window
The old button removal code only worked in the window active as of
the time of removal; by tracking all added buttons, they can now
be removed in all open windows. HTML queries are also avoided,
since the added buttons are always known.
* Add an "adder" button to every pane
This keeps the title/breadcrumbs from jumping around as
you change panes (see issue #25).
* Performance improvements
- Use requestAnimationFrame to minimize flicker
- Don't bother processing views that have already had buttons added,
unless it's a full refresh.
* No need to restart to toggle adder button
* Ensure all added buttons are on the left
Since plugins and Obsidian can add view actions at any time,
using `order` lets us ensure Commander-supplied buttons are
always first in the list.
* Render buttons in same order as shown in settings