Rich text / foldkit-mixins-richtext

Sixty seconds: the mark toolbar

ts
import { Style } from 'foldkit-mixins'
import { MarkToolbarSlots, markToolbar } from 'foldkit-mixins-richtext'

const Toolbar = markToolbar<Message>().pipe(
  Style.attach(Style.forSlots(MarkToolbarSlots)({ button: Style.class('mark-button') })),
)

// In a view:
Toolbar(
  {
    state: { document, selection, storedMarks },
    toggled: mark => edited(Message.ToggledMark({ mark })),
  },
  h,
)

state is what the editor projects; toggled turns a mark into the caller's Message; marks defaults to the three foldkit-richtext ships. The Style.attach line is the point of the package: the buttons are a slot, and the application styled them without the view knowing. Each button renders with its mark as the slot item's id, so a Behavior can single one out. The view owns each button's click and pressed state, so neither is in a slot's contract, and a mixin cannot take them over.

SlotCapabilityRenders
rootContainerthe toolbar's wrapper
toolbarCollectionthe row of buttons
buttonInteractiveone mark's button, per mark

A floating toolbar is this one inside an element carrying foldkit-richtext-dom/toolbar's selectionAnchor, as that package's README shows.