Skip to content

@codefly-dev/ui: Markdown emits source offsets and resolves links, and a generic Board — items 8 and 9 of #1001 #1010

Closed

Description

@antoinetoussaint-byte

Items 8 and 9 of #1001, which #1005 (items 1–7) does not deliver. Both came from the owner's live run of the consuming proposals solution (3 Oct 2026), and the solution carries stopgaps for each, labelled STOPGAP and naming #1001: solutions/proposals/services/fe-remote/src/markdown.tsx and solutions/proposals/services/fe-remote/src/Board.tsx. Those are the reference implementations; this issue replaces them with kit components.

8. Markdown emits source offsets, and takes a link resolver

@codefly-dev/ui/content Markdown renders with no source positions, so an annotation layer cannot map a selection back to the bytes of the version it was read from. The solution wrote a 155-line offset-aware renderer to do it.

  • Markdown takes the source and emits data-source-start / data-source-end on every block and inline run.
  • Where Markdown rewrote the text (emphasis, links, list bullets, code fences), the run also carries data-source-exact="false". Plain runs are byte-exact.
  • The offset contract is the annotations module's annotations-ui/src/anchors/source-map.ts; match it rather than inventing one.
  • A link in a corpus is often repository-relative (../decisions/x.md#why), and the kit cannot know where that goes. Markdown takes resolveLink?: (href: string) => { href: string; external: boolean }, and the consumer decides. In the reference, a page of the corpus opens in place, anything else opens in the repository at the commit the bytes were read at, and absolute URLs are untouched. Without a resolver, today's behaviour holds (http/https/mailto only, rel="noopener noreferrer").
  • The untrusted-content rules in the kit README still hold: no raw HTML, no innerHTML, and a resolved href passes the same scheme check.

9. Board

The solution wrote its own 71-line board.

  • Columns grouped by a field, with cards in them.
  • Drag a card to another column; onMove(item, column) lets the consumer confirm or refuse the move. The board never commits a move by itself.
  • Search, a count per column, and empty-column text.
  • Generic: no notion of status or proposal, and keyboard-operable as well as draggable. The kit already carries @dnd-kit for SortableGrid.

Constraint from #1001's thread

The host compiles no stylesheet for a solution remote: globals.css @sources only codefly-ui and saas-ui. These two are kit components, so their utilities are compiled. But they will be rendered from remotes, so keep arbitrary-value utilities out of them: structure inline, colour and type from the tokens. The kit README now says this (#1005).

Done when

  • Each has tests beside the existing ones and a story.
  • ui-inventory.json, the raw-type baseline and the README are updated.
  • preview.css is regenerated, and the kit version is bumped.
  • The two stopgaps in the solution can be deleted.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions