mirror of
https://github.com/DayuanJiang/next-ai-draw-io.git
synced 2026-09-01 17:10:24 +08:00
feat(diagram-engine): open shape vocabulary — catalog + pass-through, structured style merge
The expressiveness gap traced to vocabulary: draw.io has hundreds of shapes, the declarative layer allowed six. Opening it, with the failure modes from design review handled: - shapes.ts: a ~20-entry curated catalog (full style fragment incl. the matching perimeter — required or edges connect to the bounding box; a text-scale factor verified in the real editor — the same sentence overflows a 1.0x rhombus and fits a 1.5x one; labelOutside+glyph for umlActor-style figures). Any other token passes through verbatim: draw.io degrades unknown shapes to rectangles safely (verified). Injection-capable tokens (;/=) are rejected outright. - Pass-through emits a WARNING with a nearest-catalog hint (bounded edit distance), so a typo'd 'cyclinder' is a one-turn fix instead of a silently rectangular node forever. set_shape/set_role/set_group operations make the fix possible without remove+re-add (which would drop links). - mergeStyle(): style fragments merge per-key (later wins, bare shape classes displace each other) instead of string concatenation. This is what makes shape and theme composable by rule — shape owns geometry keys, theme owns colour/type keys, and an overlap resolves by order instead of emitting contradictory duplicates. - dai_shape marker carries the declared token through the round trip: appearance-based reverse mapping cannot distinguish aliases (diamond vs decision) or a rotated queue from a cylinder. - dai_auto marker separates engine-measured size from user-fixed size: parsed boxes no longer freeze the first layout's numbers, so changing a label re-measures. Pinned nodes keep everything, as before. - draw_graph's closed shape enum opened to match (first instance of the schema-drift problem the review predicted). 14 new tests: merge ownership, injection rejection, near-match hints, alias-preserving round trip, re-measure on label change, mxgraph.* tokens staying boxes with role/group intact. 556 unit tests green; acceptance diagram (person/hexagon/cylinder/queue/cloud/decision/callout) verified in the real editor.
This commit is contained in:
@@ -64,6 +64,18 @@ export const MARKER = {
|
||||
role: "dai_role",
|
||||
/** The node's semantic zone, whose hue ramp colours it. */
|
||||
group: "dai_group",
|
||||
/**
|
||||
* The declared shape token, verbatim. Appearance-based reverse mapping is ambiguous
|
||||
* (aliases, rotated variants, styles with no unique shape= token), so the round trip
|
||||
* carries the declaration itself.
|
||||
*/
|
||||
shape: "dai_shape",
|
||||
/**
|
||||
* Marks a node's size as engine-computed rather than user-fixed. Without it, the
|
||||
* w/h read back from the canvas would freeze the first layout's measurement: change
|
||||
* the label and the box would keep the old size instead of re-measuring.
|
||||
*/
|
||||
auto: "dai_auto",
|
||||
/** Share of the parent's leftover flow-axis space — flex-grow. */
|
||||
grow: "dai_grow",
|
||||
/** Cross-axis position within the parent: "start" | "center" | "end". */
|
||||
@@ -388,6 +400,21 @@ export function stampGroup(style: string, group: string): string {
|
||||
return append(style, MARKER.group, encodeURIComponent(group))
|
||||
}
|
||||
|
||||
/** Stamp the declared shape token, so the round trip carries the declaration itself. */
|
||||
export function stampShape(style: string, shape: string): string {
|
||||
return append(style, MARKER.shape, encodeURIComponent(shape))
|
||||
}
|
||||
|
||||
/** Mark a node's size as engine-computed, so a re-layout re-measures it. */
|
||||
export function stampAuto(style: string): string {
|
||||
return append(style, MARKER.auto, 1)
|
||||
}
|
||||
|
||||
/** Was this node's size computed by the engine (vs fixed by the user or the model)? */
|
||||
export function isAutoSized(style: string): boolean {
|
||||
return readMarker(style, MARKER.auto) === "1"
|
||||
}
|
||||
|
||||
type FlexAlign = "start" | "center" | "end" | "stretch"
|
||||
|
||||
/** Stamp the flex fields a node carries, so a round-trip preserves them. */
|
||||
|
||||
Reference in New Issue
Block a user