feat: canvas UX fixes — scroll, fullscreen, InfoTip tooltips, answer stub system #80

Merged
chihlasm merged 28 commits from feature/tree-editor-canvas into main 2026-02-18 17:52:08 +00:00
Showing only changes of commit 566306e4a6 - Show all commits

View File

@@ -53,6 +53,13 @@ def validate_tree_structure(tree_structure: dict[str, Any]) -> tuple[bool, list[
if "children" in tree_structure:
_validate_children(tree_structure["children"], "root.children", errors)
# Block publish if any answer placeholder nodes remain
if _has_answer_nodes(tree_structure):
errors.append({
"field": "tree_structure",
"message": "Answer placeholders must be resolved to a node type before publishing."
})
return len(errors) == 0, errors
@@ -89,6 +96,10 @@ def _validate_node(node: dict[str, Any], path: str, errors: list[dict[str, str]]
"message": "Solution nodes must have a non-empty solution"
})
elif node_type == "answer":
# Answer nodes are draft-only placeholders — no structural validation needed
pass
else:
errors.append({
"field": f"{path}.type",
@@ -115,6 +126,16 @@ def _validate_children(children: list[dict[str, Any]], path: str, errors: list[d
_validate_children(child["children"], f"{child_path}.children", errors)
def _has_answer_nodes(node: dict[str, Any]) -> bool:
"""Recursively check if any node in the tree has type 'answer'."""
if node.get("type") == "answer":
return True
for child in node.get("children", []):
if _has_answer_nodes(child):
return True
return False
# --- Procedural Tree Validation ---
VALID_STEP_TYPES = {"procedure_step", "procedure_end", "section_header"}