Skip to content

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.

LocationRole today
packages/ts/ui/app/components/DContextMenu.vueThe overlay position math; T-6OI8-ui-extract-anchored-position-and-chords lifts it into useAnchoredPosition
packages/ts/ui/app/utils/dSemantics.ts#surfaceClassesOverlay surface classes (surfaceClasses('overlay'))
packages/ts/ui/app/components/DMenuRow.vueRow primitive for the link search results
packages/ts/ui/app/components/DInput.vueInput primitive for the link target and alias fields
packages/ts/ui/app/components/DCommandPalette.vueThe keyboard-navigation idiom the link search follows
solutions/determined/experiences/notes/app/assets/notes.cssHost-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.

PieceDesign
MdBubbleMenuFloating 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
MdLinkPopoverShown 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
MdTableMenuStrip above anchors.table: row/column insert and delete plus an alignment group, each button running its table.* catalogue id
Slash tooltip thememarkdown-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.

  1. Write packages/ts/markdown-ui/tests/mdOverlays.test.ts first (happy-dom, stubbed anchors ref): bubble appears for a selection anchor, disappears for null; clicking a bubble button leaves document.activeElement unchanged and calls run with the command id; link popover fields prefill from anchors.link; apply calls setLinkAt with the anchor’s range; table menu renders one button per id and dispatches it.
  2. Implement MdBubbleMenu.vue over useAnchoredPosition with a zero-size-rect fallback when coordsAtPos yields nothing.
  3. Implement MdLinkPopover.vue (search debounce, keyboard selection, apply/remove) and MdTableMenu.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).
  4. Mount the overlays in MdSurface; pass renderIcon to the engine options.
  5. Add the slash/autocomplete section to markdown-ui.css; stories for the three components; an overlays playground page.
  6. moon run markdown-ui:check markdown-ui:test; bun run storybook:build; just ci-guards.
LocationKindChange
packages/ts/markdown-ui/app/components/MdBubbleMenu.vuenewSelection-anchored format strip
packages/ts/markdown-ui/app/components/MdBubbleMenu.stories.tsnewStory
packages/ts/markdown-ui/app/components/MdLinkPopover.vuenewLink edit/open/remove with note search
packages/ts/markdown-ui/app/components/MdLinkPopover.stories.tsnewStory
packages/ts/markdown-ui/app/components/MdTableMenu.vuenewTable row/column/alignment strip
packages/ts/markdown-ui/app/components/MdTableMenu.stories.tsnewStory
packages/ts/markdown-ui/app/components/MdSurface.vuenewCreated by T-A0HT-md-ui-layer-skeleton; mounts the overlays, passes renderIcon
packages/ts/markdown-ui/app/assets/css/markdown-ui.cssnewCreated by T-A0HT-md-ui-layer-skeleton; gains the slash tooltip section
packages/ts/markdown-ui/tests/mdOverlays.test.tsnewOverlay behavior tests
packages/ts/markdown-ui/playground/app/pages/overlays.vuenewThe three overlays over a fixture note
  • AC-1: moon run markdown-ui:check markdown-ui:test passes with the overlay suite.
  • AC-2: the bubble renders only while the stubbed anchors.selection is non-null, and clicking any bubble button leaves document.activeElement unchanged.
  • AC-3: applying the link popover calls setLinkAt with exactly the anchors.link range and the edited target/alias; remove calls removeLinkAt with the same range.
  • AC-4: editing the target renders provider.searchNotes results as menu rows and arrow-key plus Enter selection fills the target field.
  • AC-5: MdTableMenu renders 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.css references only --d-* tokens (just ci-guards passes) and .cm-tooltip-autocomplete rules exist in the layer stylesheet.
  • AC-7: bun run storybook:build succeeds with stories for the three components.

Member of milestone M-931L; chrome step C6 of decision D-K3EM-markdown-editor-chrome-and-plugin-environment.

T-MNRO-md-engine-anchors, T-N58P-md-engine-slash-and-heading-completion


← Back to Tasks