T-RJVA-md-ui-find-outline-hover-lifts
State: closed/done · Impact: high · Complexity: medium
Find, outline and hover preview exist only inside the notes product, bound to its stores and
notes-* test ids, so no other markdown surface can have them. This task lifts all three into
the markdown-ui layer as MdFindBar + useMarkdownFind, MdOutline and MdHoverPreview,
generalised over MarkdownProvider and the surface API.
| Location | Role today |
|---|---|
solutions/determined/experiences/notes/app/components/NotesFindBar.vue | Find bar UI with notes-find-* test ids |
solutions/determined/experiences/notes/app/composables/useNoteFind.ts#useNoteFind | Orchestrates DOM find in read mode and editor search in live/source |
solutions/determined/experiences/notes/app/utils/noteFind.ts | foldForFind, findMatches, collectFindText, findRange, rangeRect; the ::highlight plumbing |
solutions/determined/experiences/notes/app/utils/noteFind.test.ts | Unit suite that ports with the module |
solutions/determined/experiences/notes/app/components/NotesOutline.vue | Outline pane bound to notes state |
solutions/determined/experiences/notes/app/components/NotesHoverPreview.vue#anchorTo | Hover preview with its own position math |
packages/ts/obsidian-editor/src/search.ts | setNoteSearch, stepNoteSearch, clearNoteSearch, noteSearchStatus — the live/source path |
packages/ts/obsidian-editor/src/outline.ts#extractOutline | Outline extraction the edit modes use |
packages/ts/obsidian-md/src/slice.ts#sliceEmbed | Fragment slicing the hover preview renders |
The layer, MdSurface and MdViewer come from T-A0HT-md-ui-layer-skeleton;
useAnchoredPosition from T-6OI8-ui-extract-anchored-position-and-chords.
Proposed
Section titled “Proposed”| Piece | Design |
|---|---|
app/utils/mdFind.ts | noteFind.ts moved and renamed: same functions, highlight name md-find-match, MD_-prefixed constants |
useMarkdownFind | useNoteFind generalised over the surface: read mode → DOM path over the viewer root (::highlight(md-find-match) ranges); live/source → setNoteSearch / stepNoteSearch / clearNoteSearch with counts from noteSearchStatus; one API (query, open, count, index, next(), prev(), close()) across modes |
MdFindBar | NotesFindBar.vue generalised; every data-testid it carries today reappears with the md-find- prefix |
MdOutline | NotesOutline.vue generalised over MdOutlineEntry (the engine OutlineEntry); renders the surface’s outline, emits select with the entry, DEmptyState when empty |
MdHoverPreview | NotesHoverPreview.vue generalised: hovering a resolved wikilink in the viewer or editor DOM loads via provider.loadNote, slices with sliceEmbed, renders through MdViewer with { pre: undefined, table: undefined } component overrides, positioned by useAnchoredPosition |
MdSurface wires find: boolean, v-model:findOpen, the find-scroll emit, hoverPreview,
and exposes find on its API. markdown-ui.css gains the find-highlight and sticky-anchor
section. The notes originals stay in place until T-3DFJ-notes-adopts-markdown-ui rewires the
product and deletes them.
Approach
Section titled “Approach”- Port
noteFind.tsand its unit suite topackages/ts/markdown-ui/app/utils/mdFind.tsandpackages/ts/markdown-ui/tests/mdFind.test.ts; rename ids and constants; the suite passes unchanged in substance. - Write
packages/ts/markdown-ui/tests/useMarkdownFind.test.ts(happy-dom): in read mode a query sets highlight ranges under the namemd-find-matchandcountmatches the fixture; in live mode the composable callssetNoteSearchand mirrorsnoteSearchStatuscounts;next()wraps;close()clears both paths. - Implement
useMarkdownFind.tsandMdFindBar.vuewith stories. - Implement
MdOutline.vuewith its test (three-heading fixture renders three entries; click emitsselect; empty doc rendersDEmptyState) and story. - Implement
MdHoverPreview.vuewith its test (stubloadNote; hover over a resolved wikilink shows a preview containing the target’s rendered body; thepre/tableoverrides apply) and story. - Wire
MdSurface; add the stylesheet section; add afindplayground page exercising bar, outline and hover on one surface. moon run markdown-ui:check markdown-ui:test;bun run storybook:build;just ci-guards.
Files to touch
Section titled “Files to touch”| Location | Kind | Change |
|---|---|---|
packages/ts/markdown-ui/app/components/MdFindBar.vue | new | Generalised find bar, md-find-* ids |
packages/ts/markdown-ui/app/components/MdFindBar.stories.ts | new | Story |
packages/ts/markdown-ui/app/components/MdOutline.vue | new | Outline pane over MdOutlineEntry |
packages/ts/markdown-ui/app/components/MdOutline.stories.ts | new | Story |
packages/ts/markdown-ui/app/components/MdHoverPreview.vue | new | Hover preview over loadNote + sliceEmbed + MdViewer |
packages/ts/markdown-ui/app/components/MdHoverPreview.stories.ts | new | Story |
packages/ts/markdown-ui/app/composables/useMarkdownFind.ts | new | Mode-spanning find orchestration |
packages/ts/markdown-ui/app/utils/mdFind.ts | new | Ported find utilities |
packages/ts/markdown-ui/app/components/MdSurface.vue | new | Created by T-A0HT-md-ui-layer-skeleton; find and hover wiring |
packages/ts/markdown-ui/app/assets/css/markdown-ui.css | new | Created by T-A0HT-md-ui-layer-skeleton; find highlight and sticky anchor section |
packages/ts/markdown-ui/tests/mdFind.test.ts | new | Ported unit suite |
packages/ts/markdown-ui/tests/useMarkdownFind.test.ts | new | Mode-path tests |
packages/ts/markdown-ui/tests/mdOutline.test.ts | new | Outline tests |
packages/ts/markdown-ui/tests/mdHoverPreview.test.ts | new | Hover preview tests |
packages/ts/markdown-ui/playground/app/pages/find.vue | new | Bar, outline and hover on one surface |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1:
moon run markdown-ui:check markdown-ui:testpasses with the four new suites, and the portedmdFind.test.tscovers every casesolutions/determined/experiences/notes/app/utils/noteFind.test.tscovers today. - AC-2: every
data-testidvalue insolutions/determined/experiences/notes/app/components/NotesFindBar.vuereappears inMdFindBar.vuewithnotes-find-replaced bymd-find-. - AC-3: in read mode a query highlights under the CSS highlight name
md-find-match; in live mode the same query drivessetNoteSearchand the bar’s count equalsnoteSearchStatus’s. - AC-4:
MdOutlinerenders one entry per heading of the three-heading fixture and emitsselectwith the clicked entry; an empty document rendersDEmptyState. - AC-5: with a stub
loadNote, hovering a resolved wikilink renders a preview containing the target’s body, and fenced code inside the preview renders without the custom code-block component (the{ pre: undefined, table: undefined }overrides hold). - AC-6:
just ci-guardspasses andbun run storybook:buildsucceeds with the three new stories.
Out of scope
Section titled “Out of scope”- Rewiring notes onto these components and deleting
NotesFindBar.vue,NotesOutline.vue,NotesHoverPreview.vue,useNoteFind.ts,noteFind.ts(T-3DFJ-notes-adopts-markdown-ui). - Engine search internals;
setNoteSearchand friends are consumed as-is. - Find e2e coverage (T-I630-md-ui-playground-e2e-perf).
Dependencies
Section titled “Dependencies”- T-A0HT-md-ui-layer-skeleton for the layer,
MdSurface,MdViewerand the provider contract (loadNote). - T-6OI8-ui-extract-anchored-position-and-chords for
useAnchoredPosition. docs/PRINCIPLES.md: generalizing deletes the originals — executed by T-3DFJ-notes-adopts-markdown-ui so the product swap and the deletions land together.
Discovery context
Section titled “Discovery context”Member of milestone M-931L; the layer half of chrome step C3 of decision D-K3EM-markdown-editor-chrome-and-plugin-environment (the notes half is T-3DFJ-notes-adopts-markdown-ui).