mirror of
https://github.com/DayuanJiang/next-ai-draw-io.git
synced 2026-09-02 01:20:23 +08:00
feat(diagram-engine): flex knobs (grow/align/pad) + inline rich-text labels
The expressiveness gap between engine output and hand-written XML came down to two missing capabilities, both generic: - Block layout inside a box: nested containers already existed, but there was no way to split space by weight, pin a child to an edge, or tighten padding. Added grow (flex-grow over the parent's leftover flow-axis space, TeX's glue), align (start/center/end/stretch on the cross axis) and pad (per-group interior padding). All three round-trip via dai_grow/dai_align/ dai_pad markers. - Inline rich text: labels already render HTML (html=1 on every style, esc() entities decode back), but the measure pass counted markup as text. The visibleText() strip makes autoBoxSize measure what draw.io draws: <br> is a line, other inline tags are invisible. Graphviz (HTML-like table labels), D2 (grid containers + markdown-in-shape) and TeX (box+glue) converged on exactly this design: nested boxes for block structure, proportional glue, a small inline set for text — never full HTML. Prompts teach the composition with a comparison-card recipe; verified by rebuilding the CoT poster end to end in the real editor.
This commit is contained in:
@@ -25,6 +25,7 @@ import {
|
||||
isInvisible,
|
||||
stampCell,
|
||||
stampContainer,
|
||||
stampFlex,
|
||||
stampGroup,
|
||||
stampLane,
|
||||
stampLeaf,
|
||||
@@ -35,7 +36,7 @@ import {
|
||||
stampSequence,
|
||||
} from "./markers"
|
||||
import { type RoutedEdge, routeEdges } from "./route"
|
||||
import { hueOf, NEUTRAL, type Role, themedStyle } from "./theme"
|
||||
import { hueOf, NEUTRAL, themedStyle } from "./theme"
|
||||
import {
|
||||
type BoxShape,
|
||||
type DiagramNode,
|
||||
@@ -58,6 +59,14 @@ export function esc(s: string): string {
|
||||
.replace(/'/g, "'")
|
||||
}
|
||||
|
||||
// NOTE ON RICH TEXT: a label may carry inline HTML — <b>, <i>, <font color>, <br>,
|
||||
// <span> — and needs no special handling here. `esc()` writes it into the value
|
||||
// attribute as entities, the XML parser decodes them back, and because every style
|
||||
// carries `html=1` draw.io renders the tags. That is exactly how hand-written rich
|
||||
// labels have always worked; the editor sanitises HTML labels itself. The one place
|
||||
// tags DO need handling is the measure pass (layout.ts autoBoxSize), which must not
|
||||
// count markup as text.
|
||||
|
||||
/** Resolve a catalog name to a style. Injected so the engine does not own the catalog. */
|
||||
export type StyleResolver = (
|
||||
name: string,
|
||||
@@ -177,6 +186,7 @@ function styleFor(
|
||||
let stamped = stampLeaf(base, "box")
|
||||
if (n.role && n.role !== "body") stamped = stampRole(stamped, n.role)
|
||||
if (n.group) stamped = stampGroup(stamped, n.group)
|
||||
stamped = stampFlex(stamped, { grow: n.grow, align: n.align })
|
||||
return n.cell ? stampCell(stamped, n.cell) : stamped
|
||||
}
|
||||
|
||||
@@ -218,6 +228,8 @@ function styleFor(
|
||||
}
|
||||
if (groupRole && groupRole !== "body") base = stampRole(base, groupRole)
|
||||
if (zone) base = stampGroup(base, zone)
|
||||
if (n.kind === "group")
|
||||
base = stampFlex(base, { grow: n.grow, align: n.align, pad: n.pad })
|
||||
return stampContainer(base, {
|
||||
kind: n.kind,
|
||||
dir: n.kind === "grid" ? "grid" : n.dir,
|
||||
|
||||
Reference in New Issue
Block a user