Skip to content

refactor(core): explicit per-field operation variants + deprecate renderMarkdown - #27

Merged
LeslieOA merged 2 commits into
developfrom
refactor/explicit-update-variants
Oct 4, 2026
Merged

LeslieOA merged 2 commits into
developfrom
refactor/explicit-update-variants

Conversation

@LeslieOA

@LeslieOA LeslieOA commented May 23, 2026 •

Copy link
Copy Markdown
Member

Summary

Two changes to the public API.

1. Explicit per-field operations replace Partial<CanvasNode> (closes #5)

updateNodeContent(nodeId, Partial<CanvasNode>) has no clean Rust equivalent across JSI or wasm-bindgen. Six operations replace it:

  • updateNodeColor(nodeId, color)
  • updateTextNodeText(nodeId, text)
  • updateLinkNodeUrl(nodeId, url)
  • updateFileNode(nodeId, file, subpath)
  • updateGroupNodeLabel(nodeId, label)
  • updateGroupNodeBackground(nodeId, background, backgroundStyle)

Each Operation variant carries the new and the previous values, for invertOperation. Each is a no-op, with nothing recorded in the history, when the node is missing or of the wrong type. GroupBackgroundStyle is exported from the core types, and GroupNode uses it.

Breaking: updateNodeContent is gone. Nothing in this repo or in Workspace's apps calls it (desktop and mobile use CanvasView; Linux uses parseCanvas and the types).

2. renderMarkdown is deprecated (closes #26)

Nothing in src/renderer reads the prop: text nodes always draw through Skia. It is marked @deprecated, still accepted, and ignored, so nothing breaks. Workspace's desktop and mobile apps pass it today and can drop it.

The README gains a "Markdown in text nodes" section saying what draws and what doesn't. Checked by running parseToSegments: tables, images and nested list items are dropped, and task-list items draw as plain bullets.

Corrected in review

  • Added 11 tests for the six operations (apply, undo, redo, serialisation of a cleared field, no-ops, invertOperation round-trip). There were none.
  • The README section had claimed tables and task-list checkboxes are supported.
  • AGENTS.md still described renderMarkdown as a way to supply a markdown component.

Verification

  • npm test: 133 pass on this branch
  • npm run typecheck: clean
  • npm run lint: 0 errors

Closes #5, closes #26

🤖 Generated with Claude Code

…derMarkdown

Two API hygiene changes bundled.

1. Replace Partial<CanvasNode> with explicit operation variants (closes #5)
   The previous `updateNodeContent(nodeId, Partial<CanvasNode>)` shape was
   the last FFI-hostile item from the original audit — Partial<T> has no
   clean Rust equivalent and would have forced either a stringly-typed
   HashMap or a sparse-field struct across the JSI/wasm-bindgen boundary.

   Replaced with six per-field operation variants and matching CanvasState
   methods:
     - updateNodeColor(nodeId, color)
     - updateTextNodeText(nodeId, text)
     - updateLinkNodeUrl(nodeId, url)
     - updateFileNode(nodeId, file, subpath)
     - updateGroupNodeLabel(nodeId, label)
     - updateGroupNodeBackground(nodeId, background, backgroundStyle)

   Each Operation variant carries the new value(s) and the prev value(s) for
   invertOperation, which now has a case per variant. Apply paths verify
   node type before mutating (silent no-op on missing or mismatched type,
   consistent with removeNode's `if (!node) return` pattern).

   Exported `GroupBackgroundStyle = 'cover' | 'ratio' | 'repeat'` so
   consumers can type-narrow the backgroundStyle parameter without
   reaching into the GroupNode type.

   x / y / width / height stay in moveNode / resizeNode where they were
   before — they're not "content" updates.

   Breaking change: `updateNodeContent` is removed from the public API.
   No external consumers in this repo (grep confirmed). Workspace's
   canvas-ui has the same shape and will need the same migration when
   it next pulls from upstream.

2. Deprecate renderMarkdown (closes #26)
   The prop on CanvasView is vestigial — nothing in src/renderer consumes
   it because TextNodeContent returns null and all text-node bodies
   render through Skia's paragraphBuilder. The prop has been silently
   accepted-and-ignored for the entire life of the library.

   Marked @deprecated in both declaration sites (CanvasView.tsx,
   CanvasContext.tsx) with a JSDoc explaining the situation and pointing
   at the actual markdown-rendering pathway. README's "What's inside"
   section gains a "Markdown rendering" subsection enumerating what's
   actually supported (inline marks, blocks, GFM extensions) and what
   isn't (anything needing a React overlay).

   No behavioural change — the prop continues to be accepted. Removal
   is a separate decision for a future major version.

Verified

- npm test: 38/38 (tests reference state.history.canRedo which is unchanged)
- npm run typecheck: clean
- npm run lint: exit 0

Refs: #5, #26

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@LeslieOA
LeslieOA force-pushed the refactor/explicit-update-variants branch from 9642005 to 6455ce1 Compare October 4, 2026 20:09
Review of #27 before landing:

- The six per-field operations had no tests. Adds 11: each applies,
  undoes and redoes; a cleared field is absent from the serialised
  document; a missing node or wrong node type is a no-op with nothing
  to undo; invertOperation round-trips.
- The README's new markdown section claimed tables and task-list
  checkboxes are supported. Running parseToSegments shows tables,
  images and nested list items are dropped, and task items draw as
  plain bullets. The section now says what draws and what doesn't,
  names the parser (parseToSegments, not paragraphBuilder), and is
  scoped to the React Native renderer.
- AGENTS.md still said a host can supply a markdown component through
  renderMarkdown, which this PR deprecates as ignored.
- GroupBackgroundStyle duplicated GroupNode's union in operations.ts.
  It now lives in core/types.ts, and GroupNode uses it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@LeslieOA
LeslieOA merged commit 2e206be into develop Oct 4, 2026
1 check passed
@LeslieOA
LeslieOA deleted the refactor/explicit-update-variants branch October 4, 2026 21:20
LeslieOA added a commit that referenced this pull request Oct 4, 2026
CanvasView accepted renderMarkdown and put it in the canvas context, and nothing read it: text nodes have drawn through Skia since March. #27 marked it deprecated. Its only callers, Workspace's desktop and mobile apps, stopped passing it in workspace-sh/workspace#644.

BREAKING CHANGE: CanvasView no longer has a renderMarkdown prop, and the value from useCanvasContext no longer has a renderMarkdown field. A caller that still passes the prop fails typecheck; delete the prop, it had no effect.

The goal the prop was for, text nodes that match a markdown document, is #88.

Refs: #26, #88

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant