Commit graph

148 commits

Author SHA1 Message Date
Gary Ritchie
8c6e0eaa2d
Update devDependencies and adapt to eslint-plugin-obsidianmd 0.4.1 (#56)
* Update devDependencies and adapt to eslint-plugin-obsidianmd 0.4.1

* Bump minAppVersion to 1.13.0 and drop deprecated API usage

* Remove dead ESLint config obsoleted by obsidianmd 0.4.1
2026-07-19 17:32:55 -06:00
Gary Ritchie
300f33321a
npm audit fix 2026-07-19 14:16:58 -06:00
Gary Ritchie
27a80cc07c
Fix timer leak on redraw in page-navigation settings example (#55) 2026-05-29 20:09:31 -06:00
Gary Ritchie
184b14d524
Fix behavioral bugs in settings skill examples (#54)
- page-navigation: timer callback re-ran display() each tick, leaking a
  new interval per tick while hide() cleared only the most recent one.
  Create the interval once and update the element from the callback.
- nested-settings: shallow Object.assign in loadSettings dropped sibling
  defaults for partial stored objects and let a null section break
  predicates. Merge each nested object explicitly.
- migration-simple: validate trimmed before testing but the framework
  persists the raw value, silently changing stored data. Validate the
  raw value and document that validate cannot normalize.
2026-05-29 19:54:37 -06:00
Gary Ritchie
26c7dc8a60
add skill for migrating obsidian settings 2026-05-29 19:44:03 -06:00
Gary Ritchie
f5e9a17561
1.0.10 2026-05-29 19:30:32 -06:00
Gary Ritchie
62790c8ab8
Update npm dependencies to latest; adapt to TS 6 and Obsidian 1.13 typings (#53)
- Bump @types/node, esbuild, jiti, obsidian, typescript (6.0),
  and typescript-eslint to latest
- Hold @eslint/js at 9.x: eslint-plugin-obsidianmd peer-pins ^9.30.1
- tsconfig: drop unused baseUrl and switch moduleResolution to bundler
  (both deprecated as errors in TS 6.0)
- main.ts: declare settings to refine Plugin.settings (new in 1.13.0)
- settings.ts: add override to display(); centralise the still-supported
  imperative re-render behind rerender() with one deprecation suppression
- Keep setWarning() over setDestructive() to avoid raising minAppVersion
  from 1.8.7 to 1.13.0
2026-05-29 19:25:35 -06:00
Gary Ritchie
6030335ddb
Revise manual installation section in README
Updated installation instructions for clarity.
2026-05-12 19:35:50 -06:00
Gary Ritchie
b7aee75aff
1.0.9 2026-05-12 18:52:16 -06:00
Gary Ritchie
9e2e0cc30d
Attest release artifacts with build provenance (#52)
Add actions/attest-build-provenance step to the release workflow so
main.js and styles.css are signed via Sigstore and verifiable with
`gh attestation verify`. Grants the job id-token: write and
attestations: write to support OIDC token minting and recording.
2026-05-12 18:15:55 -06:00
Gary Ritchie
7a5cfd22c3
Address Obsidian plugin review feedback (#51)
* Use createSpan helper for file path element

* Use createSpan helper for selection conflict warning

* Use createSpan helper for checkbox-type warning

* Use createSpan helper for selection conflict warning (initial render)

* Use createSpan helper for checkbox-type warning (initial render)

* Upgrade eslint-plugin-obsidianmd to 0.3.0

Apply prefer-window-timers fix for popout window compatibility.
2026-05-12 18:10:25 -06:00
Gary Ritchie
5e0d50b7bc
1.0.8 2026-04-22 20:21:15 -06:00
Gary Ritchie
eaf24746b3
Move delete button to the select/deselect row (#50)
* Move "Delete selected" button to select/deselect row

Addresses #48: the warning-red delete button next to the lighter-red
"Update properties" CTA drew the eye toward delete and made update
look inactive. Move delete to the Select all / Deselect all row,
left-justified, with the same styling as the sibling buttons.

* Let selection row span full modal width

The "Delete selected" button was only pushed left within the right
half of the row. Hide the empty .setting-item-info on this row so the
control area spans the modal, letting margin-right: auto put Delete at
the left edge while Select all / Deselect all stay on the right.
2026-04-22 20:17:33 -06:00
Gary Ritchie
4d53ba0e27
Upgrade eslint-plugin-obsidianmd to 0.2.4 (#49)
* Upgrade eslint-plugin-obsidianmd to 0.2.4

Pick up new rules: prefer-active-doc, prefer-active-window-timers,
no-unsupported-api, prefer-instanceof, editor-drop-paste,
rule-custom-message, plus the bundled no-unsanitized plugin.

Fix new lint errors:
- Use activeDocument/activeWindow instead of document/window in the
  modal and settings (popout compatibility).
- Use activeWindow.setTimeout/clearTimeout for the status bar debouncer.
- Bump minAppVersion to 1.8.7. Notice.messageEl (1.8.7) and
  FileManager.trashFile (1.6.6) were already in use, so the previous
  1.4.10 floor was incorrect.

Config tweaks:
- Scope a local override to turn off the preset's type-aware
  obsidianmd rules on package.json: the 0.2.4 preset spreads them
  globally and they crash on the JSON parser.
- Keep reportUnusedDisableDirectives and require-await overrides
  (the preset still does not set them).
- Switch from the deprecated tseslint.config() to ESLint core's
  defineConfig(). Drop the now-redundant globals dep (the preset
  sets browser/obsidian globals itself).

* Pin debounce timers to owning window, not activeWindow

activeWindow resolves at call time, so a timer scheduled in one
window could be cleared against a different window (no-op) if the
user moved focus between schedule and cancel. The stale callback
would still fire and clobber a newer pending timer id.

Capture the owning window via the element's `.win` accessor and use
the same reference for both setTimeout and clearTimeout — status
bar in main.ts, selection-property blur debouncer in settings.ts.

* Pin modal DOM to owning document; bump version to 1.0.8

activeDocument follows focus, so modal code that used it to check
active element or create inputs could target the wrong window when
focus moved between pop-outs. Switch to the owning document of the
relevant element (checkbox.ownerDocument, setting.controlEl.ownerDocument).

Bump plugin version to 1.0.8 and record versions["1.0.8"] = "1.8.7".
Keeping the minAppVersion change under version 1.0.7 would have left
the packaged manifest (1.8.7) disagreeing with the community index
(versions.json mapping 1.0.7 → 1.4.10).

* Revert premature version bump to 1.0.8

Roll package/manifest/versions metadata back to 1.0.7; the version
bump belongs in a separate release commit via `npm version patch`,
not in this branch. minAppVersion stays at 1.8.7 because the code
on this branch uses APIs that require it.
2026-04-22 20:04:30 -06:00
Gary Ritchie
d149c98d37
1.0.7 2026-04-12 11:59:23 -06:00
Gary Ritchie
8d087efcf0
Add bottom padding to new value region in bulk edit modal (#47) 2026-04-12 11:57:23 -06:00
Gary Ritchie
a930563d59
Address Obsidian review lint findings (#46)
* Address Obsidian review lint findings

Replace `any` casts with typed App extensions for the undocumented
`app.setting` and `app.metadataTypeManager` APIs, remove sentence-case
disables by rephrasing the empty-state link and fallback Notice, and
drop `async` from `toggleSelection` (which never awaited).

Tighten local ESLint config to catch similar issues going forward:
enable `reportUnusedDisableDirectives` and re-enable
`@typescript-eslint/require-await` (the obsidianmd preset disables it).

* Fix stale eslint.config.js references in ESLint config

The config referenced eslint.config.js (from before the rename to .mts)
in both allowDefaultProject and globalIgnores — dead entries since that
file doesn't exist. The real eslint.config.mts was neither allowlisted
for projectService nor explicitly ignored, relying on the obsidianmd
preset's files patterns happening to exclude .mts. An upgrade adding
.mts to that pattern would have made lint fail on the config itself.

Explicitly ignore eslint.config.mts (matching the treatment of the
other build config files) and drop the dead allowDefaultProject entry.
2026-04-12 11:51:34 -06:00
Gary Ritchie
fdd32c79a6
1.0.6 2026-04-12 09:22:28 -06:00
Gary Ritchie
938d3a25c5
Show ribbon icon inline in README (#45)
Add the Lucide list-checks icon (the plugin's ribbon icon) inline
in the Usage section, with light/dark theme variants via <picture>.
2026-04-12 09:17:11 -06:00
Gary Ritchie
353372c921
Add metadata cache warning after large bulk operations (#44)
* Add metadata cache warning modal for large bulk operations

When a bulk operation modifies more than 75 notes, show a modal
explaining that Obsidian's metadata cache may take several minutes
to re-index. Includes a "Don't show again" toggle persisted via a
new showLargeOperationWarning setting, re-enableable from the
settings tab. Covers bulk update, bulk delete, deselect all, and
remove selection property entry points.

Also simplifies deselectAll and removeSelectionProperty signatures
to take the plugin instance, deriving app and selectionProperty
from it.

* Pass captured selectionProperty through to doRemove

Restore the original data flow where selectionProperty is captured
once at command start and threaded through, rather than re-read
from plugin.settings inside doRemove. The signature simplification
in the prior commit introduced a subtle re-read that could
mismatch if the setting changed between confirmation and execution.

* Remove cache warning from file deletion, lower threshold to 25

File deletion reconciles in the metadata cache much faster than
property edits (entry removal vs YAML re-parse), so the warning
would be misleading. Also lower LARGE_OPERATION_THRESHOLD from 75
to 25.

* Document scale expectations and cache warning in README

* Avoid hardcoding threshold number in README
2026-04-12 09:09:44 -06:00
Gary Ritchie
66b30f2241
Parallelize withProgress actions with bounded worker pool (#43)
* Run withProgress actions through a bounded worker pool

Replace the strict sequential for-loop with a worker pool (concurrency
8) so bulk operations like "Deselect all notes" and the bulk edit
modal's update/delete actions run their per-file processFrontMatter or
trashFile calls in parallel. Progress text updates on completion so the
displayed count is monotonic.

Same public signature; callers are unchanged.

* Run delete sequentially to preserve cancel semantics

Parallel delete meant clicking Cancel could still trash up to 7 more
notes before withProgress returned. Metadata writes are cheap enough
that the regression is invisible, but trashFile runs long enough that
a panicked Cancel should stop promptly.

Add an optional concurrency parameter to withProgress (default 8) and
pass 1 at the delete call site. Other callers are unchanged.
2026-04-11 15:41:47 -06:00
Gary Ritchie
3800a5f79d
Use "notes" instead of "files" in user-visible text (#41)
* Refine manifest description to use 'notes' per Obsidian style guide

* Replace user-visible "files" with "notes" per Obsidian style guide

Updates command names, UI labels, notices, confirmation messages,
settings descriptions, and README copy. Internal identifiers and
Obsidian UI names (File menu, file explorer, Settings → Files and
links → Deleted files) left unchanged.
2026-04-11 11:24:25 -06:00
Gary Ritchie
e66c0eeea1
1.0.5 2026-04-04 15:20:18 -06:00
Gary Ritchie
31c2145cd5
improve README accuracy re: file deleting 2026-04-04 15:19:34 -06:00
Gary Ritchie
25edc49cb2
update README with details on delete functionality 2026-04-04 15:15:08 -06:00
Gary Ritchie
9d52c6c6b6
Add delete action to bulk edit dialog (#40)
* Add delete action to bulk edit dialog

Adds a "Delete selected files" button alongside "Update properties"
in the bulk edit dialog, routing through app.fileManager.trashFile()
so the user's Obsidian trash preference is honored. The heading is
renamed to "Bulk edit selected files" to reflect the expanded scope.

The no-properties-configured branch no longer returns early so the
Delete button remains available when only a selection is present but
no editable properties are configured.

ConfirmModal gains optional confirmText and confirmStyle so the
delete confirmation can show a red "Delete" button rather than the
default CTA "Continue". doDelete() re-reads getCheckedFiles() after
awaiting pendingSaves to avoid confirming on a stale positive count
that resolves to zero.

* Allow duplicates when merging multitext properties

The merge save path deduplicated new values against the existing
list for every array type, but the UI only enforces dedup for tags
and aliases — multitext pills can intentionally repeat (e.g. a
shopping list with "eggs" twice). The save path silently dropped
those duplicates.

Gate the dedup step on the same DEDUP_TYPES set the UI uses, and
append newValues as-is for multitext. The tags/aliases path is
unchanged.

* Treat null list-property values as empty, not non-list

A frontmatter key like "items:" with no value parses as null, which
hit the non-list fallback and marked the file as skipped. That made
merge impossible against bare or explicitly-null list properties.

Group null with undefined in the current-value conversion: merge
starts from an empty list and appends, delete short-circuits since
there is nothing to remove.
2026-04-04 15:12:21 -06:00
Gary Ritchie
6a6d8cb50a
Warn when selection property is not a Checkbox type (#39)
Show a warning in settings when the selection property has a
known non-checkbox type (e.g. Text, Number). The warning appears
both on initial display and when the value changes. If the type
cannot be determined, no warning is shown.
2026-04-04 12:53:11 -06:00
Gary Ritchie
0e8d99c9ca
Link empty-state message to plugin settings (#38)
* Link "plugin settings" text to open settings tab in empty-state message

When no properties are configured, the modal now shows "plugin settings"
as a clickable link that closes the modal and navigates directly to the
plugin's settings tab.

* Guard undocumented settings API with feature detection

Check that setting.open and setting.openTabById are functions before
calling them. Falls back to a Notice with manual navigation instructions
if the internal API is absent.

* Add focus-visible indicator for links in the modal
2026-04-04 12:31:42 -06:00
Gary Ritchie
95f45ceb31
Make file list rows clickable and fix keyboard focus (#37)
* Make file path labels clickable in bulk edit modal

Use a <label> element instead of a <div> for file rows so clicking
the file path text toggles the checkbox, not just clicking the
checkbox itself.

* Restore checkbox focus after toggle save completes

Disabling the checkbox during save causes the browser to remove focus,
so spacebar stops working until the user tabs away and back. Refocus
the checkbox after re-enabling it.

* Guard checkbox refocus to avoid stealing focus from other controls

Only restore focus to the checkbox after save if the user hasn't
tabbed to another control in the meantime. Checks that activeElement
is still document.body (where it lands after disable) before refocusing.
2026-04-04 11:17:36 -06:00
Gary Ritchie
61cc61d12b
Fix type dropdown auto-selecting Text for unknown properties (#36)
* Fix type dropdown resetting to first option for unknown properties

The "Choose type…" placeholder <option> was disabled, which prevented
setValue("") from selecting it programmatically. When auto-detect
returned null for a novel property name, the browser fell through to
the first enabled option instead of staying on the placeholder.

* Skip type auto-detect for property names not in the vault

metadataTypeManager.getPropertyInfo() returns {widget: "text"} as a
default for unknown names, causing the type dropdown to silently
pre-fill "Text" for novel properties. Guard with a vault property
name check so the dropdown stays on "Choose type…" instead.
2026-04-04 10:48:43 -06:00
Gary Ritchie
c97c4816fe
Block selection property from conflicting with configured properties (#35)
* Block selection property from conflicting with configured properties

Prevent setting the selection property to a value already in the
properties edit list. Validation fires on blur and suggestion selection
(not on every keystroke) to avoid false notices while typing through
a conflicting prefix. Also adds a warning in settings when a
pre-existing conflict is detected on disk.

* Stop persisting intermediate keystrokes for selection property

Move from onChange-based saving to commit-on-blur/suggestion-selection.
This prevents intermediate prefixes from being persisted, so reverting
on conflict always restores the original value. The blur handler is
deferred via setTimeout(0) so a suggestion click can cancel it and
avoid a double-commit race. The on-disk conflict warning now updates
inline after a successful save instead of requiring a full re-render.

* Fix initialization crash and async overwrite race

Move initial warning render outside the addSearch callback so
selectionSetting is fully initialized before descEl is accessed.
The inline updateWarning() still handles dynamic updates after saves.

Restore stale-write guard: capture the draft input value before
awaiting the save, only reset the input if it still matches when
the save completes.
2026-04-04 10:31:27 -06:00
Gary Ritchie
579637e58c
1.0.4 2026-04-03 19:59:42 -06:00
Gary Ritchie
de7abe1851
Fix selection property not saving when chosen from suggestion dropdown (#34)
AbstractInputSuggest.setValue() sets the input's .value property directly
without firing an input event, so SearchComponent.onChange() never
executes when a suggestion is clicked. Wire up onSuggestionSelected to
explicitly invoke the save logic after a suggestion is selected.
2026-04-03 19:57:05 -06:00
Gary Ritchie
ef7d43b2ff
Document merge, replace, and delete actions for multi-value properties (#33) 2026-04-03 15:07:14 -06:00
Gary Ritchie
131af3a9b8
1.0.3 2026-04-03 14:27:57 -06:00
Gary Ritchie
ea07e78912
Add /release-notes skill for generating user-facing release notes (#32)
* Add /release-notes project command

Generates user-facing release notes from merged PRs since the last
GitHub release, categorized into New Features, Enhancements, Bug Fixes,
and Other. Output is saved to the Notes inbox as a timestamped markdown
file for manual review before publishing.

* Use tag commit date instead of release publishedAt for PR cutoff

Draft releases can be published well after the tag is created, which
would cause PRs merged in between to be missed. Deriving the cutoff
from the tag's commit date avoids this gap.

* Move release-notes from command to skill format

Skills support frontmatter (invoke: user for manual-only triggering)
and a directory for supporting files. The /release-notes slash command
works the same way.

* Use committer date instead of author date for tag cutoff

Author date (%aI) can be stale if the tagged commit was rebased or
cherry-picked. Committer date (%cI) reflects when the commit was
actually created on the branch.
2026-04-03 14:23:55 -06:00
Gary Ritchie
94f2ddf29e
Add merge, replace, and delete actions for array properties (#31)
* Add merge, replace, and delete actions for array properties (#31)

For tags, aliases, and multitext properties, users can now choose an
action when bulk editing: merge (add to existing values), replace
(overwrite all values), or delete (remove specified values). The action
defaults to merge each time the dialog opens.

Merge deduplicates against existing values and within the incoming
batch using case-sensitive comparison. Files with non-array stored
values are skipped to preserve data. Delete on a missing property is
a no-op. Replace shows a confirmation warning before proceeding.

* Normalize scalar string values to array for merge and delete

Frontmatter commonly stores single tags/aliases values as a scalar
string rather than a one-element array. Normalize these to [string]
before applying merge/delete instead of skipping. Only skip truly
incompatible types (numbers, booleans, objects).
2026-04-03 12:07:22 -06:00
Gary Ritchie
f51ab93188
Update README: friendly type names, reorder sections, fix wording (#30)
* Update README: move Setup before Usage, use friendly type names

Setup is a prerequisite for using the plugin so it belongs first.
Property types now use the same friendly names shown in the settings
UI (e.g. "Date & time" instead of "datetime", "List" instead of
"multitext").

* Clean up README wording

Usage step 1 now references the configured selection property instead
of re-introducing it. Fix typo in Manual Installation callout.
2026-04-03 10:17:01 -06:00
Gary Ritchie
6b204483c0
Show friendly names in property type dropdown and list (#29)
* Show friendly display names in property type dropdown (#29)

Map internal property type strings to user-friendly labels
matching Obsidian Bases (e.g. "datetime" → "Date & time",
"multitext" → "List") and sort alphabetically.

* Show friendly type label in property list description
2026-04-03 10:00:28 -06:00
Gary Ritchie
227440c5ff
Filter configured properties from name suggestions (#28)
* Exclude already-configured properties from name suggestions (#28)

The property name autocomplete in settings now filters out properties
that are already in the configured list, preventing duplicate selection.

* Exclude selection property from add-property suggestions

The selection property is already filtered out of the bulk-edit modal,
so allowing it to be added to the properties list is a confusing no-op.
Exclude it from autocomplete suggestions and reject it in the add-button
validation with a clear message.
2026-04-03 09:49:08 -06:00
Gary Ritchie
7e44237185
Serialize settings saves with copy-on-write semantics (#27)
* Fix release workflow tag filter and serialize all settings saves

The release workflow tag filter used regex syntax ([0-9]+) but GitHub
Actions expects glob patterns, so it would never match semver tags.
Replace with *.*.*; the manifest/tag equality check remains as strict
validation.

Move the settings save queue from BulkPropertiesSettingTab into the
plugin so all callers (settings tab, bulk-edit modal) share a single
serialized write path, preventing concurrent saves from overwriting
each other.

* Revert release workflow tag filter change

The original [0-9]+.[0-9]+.[0-9]+ pattern is correct. GitHub Actions
filter patterns support + as "one or more of the preceding character",
unlike standard globs. The review finding was based on the incorrect
assumption that + is literal in this context.

* Use copy-on-write semantics for serialized settings saves

updateSetting() on the plugin builds a candidate snapshot and only
assigns it to this.settings after saveData() succeeds. On failure,
in-memory settings remain unchanged, preventing a later unrelated
save from persisting a value that was reported as failed.

Both the settings tab and bulk-edit modal now use this single method
instead of mutating settings before saving.
2026-04-03 09:13:41 -06:00
Gary Ritchie
a7eacdace0
Add autocomplete suggestions for pill inputs (#26)
* Add autocomplete suggestions for tags/multitext pill inputs

Show a completion dropdown with known vault values when entering
tags, aliases, or multitext property values in the bulk edit modal.
Uses AbstractInputSuggest attached to the pill input element.

Suggestions are collected from frontmatter across all vault files,
filtered to exclude already-added pills, and normalized consistently
with tag input (leading # stripped for matching).

* Fix focusout committing partial text when clicking a suggestion

When the user clicks a suggestion in the dropdown, the pill container's
focusout handler fires before selectSuggestion, which would commit the
partially typed query as an unintended pill. Defer the focusout commit
via requestAnimationFrame so selectSuggestion can set a flag and clear
the input first.

* Scope focusout suppression to mouse-triggered suggestions only

Keyboard selections are captured by the suggest's Scope before
focusout fires, so the didSelect flag is only needed for mouse
clicks. Setting it unconditionally left the flag armed after
keyboard selections, which could discard the next legitimate
blur commit.

* Pre-normalize tag values in suggestion list to strip # prefix

Known values for tags are now normalized (leading # removed) before
being passed to the suggest, so the dropdown never shows # prefixes.
Deduplicates after normalization in case both #foo and foo exist.

* Re-sort tag suggestions after normalization

Stripping # prefixes can break the original alphabetical order
from getPropertyValues(). Re-sort after normalize and dedup.

* Fix suggestion selection not adding pill

The selectSuggestion override replaced the base class implementation
that invokes the onSelect callback, so addPill was never called.
Use a direct callback property (onValueSelected) called from within
selectSuggestion, matching the PropertyNameSuggest pattern.
2026-04-03 08:52:51 -06:00
Gary Ritchie
a0d7b6d93b
Fix toggle keyboard and screen reader accessibility (#25)
* Fix keyboard and screen reader accessibility for deselect toggle

The toggle in the bulk edit modal ignored Space key when focused via
Tab because Obsidian's ToggleComponent label element doesn't forward
keyboard events. Add a keydown handler for Space and an aria-label so
screen readers announce the checkbox purpose.

* Remove double tab stop and associate label with checkbox input

Remove tabindex from the outer label element so only the native
checkbox input receives focus. Move aria-label onto the input so
screen readers announce "Deselect when finished" for the checkbox.
The native input handles Space key natively, so the custom keydown
handler is no longer needed.

* Fix toggle focus ring size and inverted screen reader state

The native checkbox is smaller than the visual toggle and its checked
state is inverted from the visual state. Fix by keeping focus on the
outer toggleEl (which already has tabindex=0 and the correct visual
size), hiding the native input from tab order and accessibility tree,
and using role=switch with aria-checked that tracks the actual toggle
value. Space key handler on toggleEl triggers the toggle.

* Extract toggle a11y helper and apply to all toggles

Move the toggle accessibility fix (role=switch, aria-checked,
aria-label, Space key handler, hidden native input) into a shared
makeToggleAccessible helper. Apply to all three toggles: the modal
deselect toggle and both settings tab toggles.

* Fix toggle keyboard behavior: Space on keyup, Enter on keydown

Space now prevents default on keydown (to avoid scrolling) but only
toggles on keyup, matching native checkbox behavior. Enter toggles on
keydown. Both ignore repeated key events via e.repeat check.

* Always prevent default for Space keydown to avoid scroll on hold

Move the repeat guard so Space preventDefault runs unconditionally on
keydown (preventing page scroll even when held), while Enter's repeat
guard remains inline to block repeated toggles.
2026-04-03 08:04:54 -06:00
Gary Ritchie
4d5e49550c
Update dev dependencies (#24)
- @types/node: ^16.11.6 → ^25.5.0
- esbuild: 0.25.5 → 0.27.5
- globals: 14.0.0 → 17.4.0
- obsidian: 1.10.3 → 1.12.3
- tslib: 2.4.0 → 2.8.1
- typescript-eslint: 8.35.1 → 8.58.0
- @eslint/js: 9.30.1 → 9.39.4
- Pin typescript to 5.8.3 (eslint-plugin-obsidianmd requires <5.9.0)
2026-04-03 07:06:01 -06:00
Gary Ritchie
480c5d9c04
Fix silent discard of invalid pill input (#23)
* Prevent silent discard of invalid pill input during bulk edit

addPill now returns a boolean so callers know whether input was
accepted.  Invalid text is preserved in the input field on Enter,
paste, and blur instead of being silently dropped.  The Update
button is disabled while uncommitted text remains, and doUpdate
guards against proceeding with stale input.

Fixes review #99.

* Fix duplicate pill on Enter for multitext properties

Clear pillInput.value before calling addPill in keydown, paste,
and focusout handlers.  renderPills() moves the input element via
appendChild, which fires a focusout event; if the input still held
text, the focusout handler would call addPill a second time.  Now
the input is cleared first and restored only if addPill rejects.
2026-04-01 20:23:02 -06:00
Gary Ritchie
f7e28e5e2c
Replace comma-separated textarea with pill-style input for multi-value properties (#22)
* Replace comma-separated textarea with pill-style input for tags

Use Obsidian's native .multi-select-pill CSS classes for tags,
aliases, and multitext property types. Pills are added via Enter,
comma, or paste and removed via × button or Backspace. Dedup
applies to tags/aliases only; multitext allows duplicates. IME
composition is respected to avoid breaking CJK input.

* Add x icon to pill remove button via setIcon

* Fix paste merging and blur commit behavior for pill input

Paste now merges clipboard text with existing input value at the
cursor position before splitting on commas. The trailing segment
after the last comma stays in the input for further editing.

Blur only commits pending text when focus leaves the pill container
entirely, not when clicking a remove button inside it.

* Move pending-text commit to container focusout

Replace the input-level blur handler with a container-level focusout
listener that commits pending text only when focus leaves the pill
container entirely. This covers the keyboard path where focus moves
from a remove button to outside the container.

* Strip border from pill remove button and reduce pill size

* Add hover and focus-visible styles to pill remove button

* Use span with role=button for pill remove to match Obsidian's DOM

Obsidian's native multi-select pills use a span for the remove
control, not a button element. The button element picks up
Obsidian's base button styling (visible border) that can't be
easily overridden. Switching to a span with role="button" and
tabindex="0" matches the native DOM while preserving keyboard
accessibility via an explicit keydown handler.

* Match native button behavior: activate Space on keyup, not keydown

* Validate tag names against Obsidian's naming rules

Reject tags containing spaces, invalid characters, or only digits.
Strip leading # from user input. Show a Notice with the specific
reason when a tag is rejected. Validation applies only to the tags
property type, not aliases or multitext.

* Show notice when bare # is entered as a tag name

* Restore focus to pill input after adding or removing a pill

* Only refocus pill input from keyboard and paste, not blur commits

* Fix duplicate pill on multitext by clearing input before addPill

renderPills() detaches and reattaches the input element, which can
fire a focusout event mid-operation. The focusout handler would then
see the still-populated input and commit the same value again. For
tags/aliases this was masked by dedup, but multitext allows
duplicates so the double-add was visible. Fix by capturing and
clearing the input value before calling addPill.
2026-04-01 19:55:02 -06:00
Gary Ritchie
2a9a76fc3b
1.0.2 2026-03-29 11:51:03 -06:00
Gary Ritchie
040ff069e7
Update README.md
Clarify the manual installation instructions and mention use of BRAT plugin.
2026-03-29 11:48:53 -06:00
Gary Ritchie
c411cdda32
Merge pull request #20 from gtritchie/fix-review-findings
Fix write race, add deselect confirmation, debounce status bar
2026-03-29 11:41:23 -06:00
Gary Ritchie
964369c64a
Fix write serialization race, add deselect-all confirmation, debounce status bar
- Route bulkSetSelection writes through pendingSaves map and add per-file
  cleanup in finally blocks so settled entries don't accumulate
- Add confirmation dialog before "Deselect all files" command, consistent
  with the existing confirmation on "Remove selection property"
- Debounce status bar updates triggered by metadata-change and file-delete
  events (500ms) to avoid redundant full-vault scans during bulk operations
2026-03-29 11:34:08 -06:00