package doc
import (
"github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/extension"
east "github.com/yuin/goldmark/extension/ast"
"github.com/yuin/goldmark/renderer"
"github.com/yuin/goldmark/renderer/html"
"github.com/yuin/goldmark/util"
)
// tableRenderer wraps every GFM table in a horizontally scrollable box.
//
// A `<table>` will not shrink below its min-content width, and specs have
// tables whose cells are bare URLs — an unbreakable 70-character token each.
// Inside the page grid's `minmax(0,1fr)` column such a table simply overflows
// its cell and paints on top of the table-of-contents rail. The wrapper is a
// block box that does honour the column width, so the overflow becomes a scroll
// bar on the table instead of a collision with the rail.
//
// Two nested divs rather than one: the review UI hangs per-block affordances in
// the left gutter of every top-level child of .prose, and the scrolling box —
// their containing block — would clip an absolutely positioned handle. The
// outer div takes the block role, the inner one does the scrolling.
//
// Only the table element itself is overridden; rows, cells, and the alignment
// handling stay with goldmark's own renderer.
type tableRenderer struct{}
// tableRendererPriority beats the GFM table renderer's 500. goldmark registers
// node renderers from the lowest priority number last, so the last write to a
// node kind — and thus the winner — is the smaller number.
const tableRendererPriority = 100
func (tableRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
reg.Register(east.KindTable, renderTable)
}
func renderTable(w util.BufWriter, _ []byte, n ast.Node, entering bool) (ast.WalkStatus, error) {
if entering {
_, _ = w.WriteString(`<div class="table-block"><div class="table-scroll"><table`)
if n.Attributes() != nil {
html.RenderAttributes(w, n, extension.TableAttributeFilter)
}
_, _ = w.WriteString(">\n")
} else {
_, _ = w.WriteString("</table></div></div>\n")
}
return ast.WalkContinue, nil
}