T-8ZHI-md-ui-overlays-bubble-link-table
State: closed/done · Impact: high · Complexity: medium
The engine now reports what sits under the cursor and where it is on screen, but no chrome floats there: no format strip on a selection, no link editor, no table menu, and the slash tooltip is unstyled in the layer. This task adds the three selection-anchored overlays and the slash tooltip theme.
| Location | Role today |
|---|---|
packages/ts/ui/app/components/DContextMenu.vue | The overlay position math; T-6OI8-ui-extract-anchored-position-and-chords lifts it into useAnchoredPosition |
packages/ts/ui/app/utils/dSemantics.ts#surfaceClasses | Overlay surface classes (surfaceClasses('overlay')) |
packages/ts/ui/app/components/DMenuRow.vue | Row primitive for the link search results |
packages/ts/ui/app/components/DInput.vue | Input primitive for the link target and alias fields |
packages/ts/ui/app/components/DCommandPalette.vue | The keyboard-navigation idiom the link search follows |
solutions/determined/experiences/notes/app/assets/notes.css | Host-side .cm-tooltip-autocomplete rules the layer stylesheet supersedes |
The anchors ref and link helpers come from T-MNRO-md-engine-anchors; the slash source,
renderIcon hook and --obsmd-chrome-* tooltip variables from
T-N58P-md-engine-slash-and-heading-completion; the layer and MdSurface from
T-A0HT-md-ui-layer-skeleton.
Proposed
Section titled “Proposed”| Piece | Design |
|---|---|
MdBubbleMenu | Floating format strip shown while anchors.selection is non-null (non-empty selection outside code). Teleport to="body", surfaceClasses('overlay'), positioned from anchors.rects.selection by useAnchoredPosition — not UPopover, because a CodeMirror selection has no anchor element. Buttons are the format group commands with aria-pressed from states. It never takes focus: mousedown.prevent on every button, no focusable children |
MdLinkPopover | Shown for anchors.link: target and alias DInput size="xs" fields, open and remove DIconButtons. Editing the target searches provider.searchNotes rendered as DMenuRows with the DCommandPalette keyboard idiom; apply calls setLinkAt(view, range, { kind, target, alias }), remove calls removeLinkAt |
MdTableMenu | Strip above anchors.table: row/column insert and delete plus an alignment group, each button running its table.* catalogue id |
| Slash tooltip theme | markdown-ui.css gains its slash/autocomplete section: .cm-tooltip-autocomplete, section labels, matched text and detail chips in --d-* tokens; MdSurface passes the mdIcons renderIcon factory to the engine’s icon hook so options carry Tailwind-scanned Lucide classes |
MdSurface mounts the three overlays over its editor modes and feeds them the anchors ref.
Approach
Section titled “Approach”- Write
packages/ts/markdown-ui/tests/mdOverlays.test.tsfirst (happy-dom, stubbedanchorsref): bubble appears for a selection anchor, disappears fornull; clicking a bubble button leavesdocument.activeElementunchanged and callsrunwith the command id; link popover fields prefill fromanchors.link; apply callssetLinkAtwith the anchor’s range; table menu renders one button per id and dispatches it. - Implement
MdBubbleMenu.vueoveruseAnchoredPositionwith a zero-size-rect fallback whencoordsAtPosyields nothing. - Implement
MdLinkPopover.vue(search debounce, keyboard selection, apply/remove) andMdTableMenu.vue(ids:table.row.insert-above,table.row.insert-below,table.col.insert-left,table.col.insert-right,table.row.delete,table.col.delete,table.align.left,table.align.center,table.align.right). - Mount the overlays in
MdSurface; passrenderIconto the engine options. - Add the slash/autocomplete section to
markdown-ui.css; stories for the three components; anoverlaysplayground page. 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/MdBubbleMenu.vue | new | Selection-anchored format strip |
packages/ts/markdown-ui/app/components/MdBubbleMenu.stories.ts | new | Story |
packages/ts/markdown-ui/app/components/MdLinkPopover.vue | new | Link edit/open/remove with note search |
packages/ts/markdown-ui/app/components/MdLinkPopover.stories.ts | new | Story |
packages/ts/markdown-ui/app/components/MdTableMenu.vue | new | Table row/column/alignment strip |
packages/ts/markdown-ui/app/components/MdTableMenu.stories.ts | new | Story |
packages/ts/markdown-ui/app/components/MdSurface.vue | new | Created by T-A0HT-md-ui-layer-skeleton; mounts the overlays, passes renderIcon |
packages/ts/markdown-ui/app/assets/css/markdown-ui.css | new | Created by T-A0HT-md-ui-layer-skeleton; gains the slash tooltip section |
packages/ts/markdown-ui/tests/mdOverlays.test.ts | new | Overlay behavior tests |
packages/ts/markdown-ui/playground/app/pages/overlays.vue | new | The three overlays over a fixture note |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1:
moon run markdown-ui:check markdown-ui:testpasses with the overlay suite. - AC-2: the bubble renders only while the stubbed
anchors.selectionis non-null, and clicking any bubble button leavesdocument.activeElementunchanged. - AC-3: applying the link popover calls
setLinkAtwith exactly theanchors.linkrange and the edited target/alias; remove callsremoveLinkAtwith the same range. - AC-4: editing the target renders
provider.searchNotesresults as menu rows and arrow-key plus Enter selection fills the target field. - AC-5:
MdTableMenurenders one control per id in the Approach step 3 list and dispatches that id on click. - AC-6: the slash tooltip section of
markdown-ui.cssreferences only--d-*tokens (just ci-guardspasses) and.cm-tooltip-autocompleterules exist in the layer stylesheet. - AC-7:
bun run storybook:buildsucceeds with stories for the three components.
Out of scope
Section titled “Out of scope”- The engine slash source, icon hook and
--obsmd-chrome-*variables (T-N58P-md-engine-slash-and-heading-completion ships them). - The
table.*command implementations (T-UYTR-md-engine-tables). - Overlay e2e coverage (T-I630-md-ui-playground-e2e-perf).
- Hover previews (T-RJVA-md-ui-find-outline-hover-lifts).
Dependencies
Section titled “Dependencies”- T-MNRO-md-engine-anchors for
anchors,setLinkAt,removeLinkAt; T-N58P-md-engine-slash-and-heading-completion for the tooltip variables andrenderIcon. - T-A0HT-md-ui-layer-skeleton for the layer and
MdSurface; T-6OI8-ui-extract-anchored-position-and-chords foruseAnchoredPosition; T-UYTR-md-engine-tables for thetable.*ids the menu runs; T-98EU-md-ui-toolbar-insert-frontmatter for themdIconsmap. - S-0010 / D-DLNG: overlay colors are
--d-*tokens; the guard ring enforces it.
Discovery context
Section titled “Discovery context”Member of milestone M-931L; chrome step C6 of decision D-K3EM-markdown-editor-chrome-and-plugin-environment.
Depends on
Section titled “Depends on”T-MNRO-md-engine-anchors, T-N58P-md-engine-slash-and-heading-completion