Bump to 1.0.20: raise minAppVersion to 1.13.0, drop pre-1.13 fallbacks

1.0.19's deprecation fixes used SettingTab.update() and setDestructive(),
both @since 1.13.0 — the review's no-unsupported-api check rightly flags
calling them while minAppVersion declared 1.7.2, runtime guards
notwithstanding. The review effectively requires the 1.13 settings APIs
(it reports display()/setWarning() as deprecated), so the only consistent
state is a 1.13.0 floor.

With 1.13.0 guaranteed:
- settings.ts loses the entire imperative display()/renderImperative()
  fallback (~45 lines) — the tab renders declaratively only
- refresh() calls update() unconditionally
- setDestructive() is called directly, no typeof guard
- README compatibility table updated; versions.json maps 1.0.20 -> 1.13.0

No existing installed base is affected: the plugin is not yet listed in
the community directory.
This commit is contained in:
Daniel Anderson 2026-07-17 13:35:57 +10:00
parent 807b685d74
commit 3f51f3000f
6 changed files with 21 additions and 70 deletions

View file

@ -177,7 +177,7 @@ Visual Notes only reads and writes files inside your own vault — it makes no n
|---|---|
| Obsidian desktop (Mac, Windows, Linux) | ✅ Supported |
| Obsidian mobile (iOS, iPadOS) | ✅ Supported |
| Minimum Obsidian version | 1.7.2 |
| Minimum Obsidian version | 1.13.0 |
---

View file

@ -1,8 +1,8 @@
{
"id": "visual-notes",
"name": "Visual Notes",
"version": "1.0.19",
"minAppVersion": "1.7.2",
"version": "1.0.20",
"minAppVersion": "1.13.0",
"description": "A visual workspace built on the Canvas format: nestable freeform boards, icon tile grids, kanban boards, sticky notes, checklists, columns, drawing with pen and highlighter, labels, reactions, and more.",
"author": "Daniel Anderson",
"isDesktopOnly": false

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "visual-notes",
"version": "1.0.19",
"version": "1.0.20",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "visual-notes",
"version": "1.0.19",
"version": "1.0.20",
"license": "MIT",
"dependencies": {
"sortablejs": "^1.15.7"

View file

@ -1,6 +1,6 @@
{
"name": "visual-notes",
"version": "1.0.19",
"version": "1.0.20",
"description": "Visual Notes — a visual workspace for Obsidian",
"main": "main.js",
"scripts": {

View file

@ -27,13 +27,11 @@ class BoardPickerModal extends FuzzySuggestModal<TFile> {
// ── Settings tab ──────────────────────────────────────────────
//
// Each setting is built by a small `buildX(setting)` method that fills in
// an already-created Setting — shared verbatim between display() (the
// imperative fallback for Obsidian < 1.13, still called on those versions)
// and getSettingDefinitions() (the declarative form 1.13+ uses to render
// this tab and to index every setting's name/desc for its settings search).
// Keeping one body per setting means the two rendering paths can never
// drift out of sync with each other.
// Rendered declaratively via getSettingDefinitions() (Obsidian 1.13+, which
// is the plugin's minAppVersion) — the app renders each definition and
// indexes every setting's name/desc for its settings search. Each setting's
// controls are built by a small `buildX(setting)` method that fills in the
// Setting the app created for it.
export class VisualNotesSettingsTab extends PluginSettingTab {
plugin: VisualNotesPlugin;
@ -103,56 +101,11 @@ export class VisualNotesSettingsTab extends PluginSettingTab {
];
}
// ── Imperative fallback (Obsidian < 1.13) ───────────────────
override display(): void {
this.renderImperative();
}
// Re-render after a settings mutation that changes the tab's structure
// (reset buttons, board picker's Clear visibility, sticky palette).
// (reset buttons, board picker's Clear visibility, sticky palette):
// update() re-renders the tab from fresh definitions.
private refresh(): void {
// On 1.13+ the tab renders declaratively from getSettingDefinitions();
// update() re-renders it from fresh definitions. Older versions have no
// update() and rendered imperatively — re-render the same way.
if (typeof this.update === 'function') this.update();
else this.renderImperative();
}
private renderImperative(): void {
const { containerEl } = this;
containerEl.empty();
this.buildOpenOnStartup(new Setting(containerEl));
this.buildDefaultBoard(new Setting(containerEl));
new Setting(containerEl).setName('Freeform canvas').setHeading();
this.buildToolbarPosition(new Setting(containerEl));
this.buildDotColor(new Setting(containerEl));
this.buildDotSize(new Setting(containerEl));
this.buildCanvasBgColor(new Setting(containerEl));
this.buildCardDragAnimation(new Setting(containerEl));
this.buildCardDragAnimationIntensity(new Setting(containerEl));
this.buildSnapToGrid(new Setting(containerEl));
this.buildGridSize(new Setting(containerEl));
this.buildTrashZoneSize(new Setting(containerEl));
this.buildLargeKanbanItems(new Setting(containerEl));
this.buildBookmarkCacheDuration(new Setting(containerEl));
this.buildDefaultStickyColor(new Setting(containerEl));
this.buildCommentAuthorName(new Setting(containerEl));
new Setting(containerEl).setName('Assets').setHeading();
this.buildAutoSortAssets(new Setting(containerEl));
this.buildAutoRelinkOnOpen(new Setting(containerEl));
this.buildRelinkAllBoardsNow(new Setting(containerEl));
new Setting(containerEl).setName('Data').setHeading();
this.buildExportTilesJson(new Setting(containerEl));
this.buildImportDesc(new Setting(containerEl));
this.buildImportButton(new Setting(containerEl));
new Setting(containerEl).setName('Danger zone').setHeading();
this.buildResetAllTiles(new Setting(containerEl));
this.update();
}
// ── Per-setting builders ─────────────────────────────────────
@ -577,13 +530,10 @@ export class VisualNotesSettingsTab extends PluginSettingTab {
setting
.setName('Reset all tiles')
.setDesc('Permanently delete every tile and nested board. This cannot be undone.')
.addButton(btn => {
// setDestructive() is 1.13+; on older Obsidian apply the same
// styling class the deprecated setWarning() would have added.
if (typeof btn.setDestructive === 'function') btn.setDestructive();
else btn.buttonEl.addClass('mod-warning');
return btn
.addButton(btn =>
btn
.setButtonText('Reset everything')
.setDestructive()
.onClick(() => {
new ConfirmModal(
this.app,
@ -594,7 +544,7 @@ export class VisualNotesSettingsTab extends PluginSettingTab {
new Notice('All tiles deleted.');
})(); }
).open();
});
});
})
);
}
}

View file

@ -18,5 +18,6 @@
"1.0.16": "1.7.2",
"1.0.17": "1.7.2",
"1.0.18": "1.7.2",
"1.0.19": "1.7.2"
"1.0.19": "1.7.2",
"1.0.20": "1.13.0"
}