Skip to content

Fix DrawIO CLI docs, refactor context menu, correct XML generation#2593

Merged
davydkov merged 4 commits intomainfrom
copilot/update-cli-docs-drawio-export
Feb 11, 2026
Merged

Fix DrawIO CLI docs, refactor context menu, correct XML generation#2593
davydkov merged 4 commits intomainfrom
copilot/update-cli-docs-drawio-export

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 11, 2026

Description

Three DrawIO-related fixes:

1. CLI Documentation

File: apps/docs/src/content/docs/tooling/cli.mdx

Changed --output, -o--outdir, -o to match handler implementation.

2. Context Menu Refactoring

Files: apps/playground/src/components/drawio/*

Extracted duplicated import/export logic from DrawioContextMenu and DrawioContextMenuProvider:

  • useDrawioActions hook: encapsulates fileInputRef, file import (FileReader → parseDrawioToLikeC4 → workspace.addFile), and export (generateDrawio → Blob download)
  • DrawioContextMenuView component: presentational Mantine Menu rendering (props: opened, onClose, menuPosition, onImport, onExport, canExport)

Both components now reuse these abstractions instead of duplicating ~80 lines of logic.

3. XML Generation Structure

File: packages/generators/src/drawio/generate-drawio.ts

Fixed mxUserObject placement in generated XML:

<!-- Before: inline within opening tag -->
<mxCell ...>${userData}
  <mxGeometry ... />
</mxCell>

<!-- After: proper child element before mxGeometry -->
<mxCell ...>
  ${userData}<mxGeometry ... />
</mxCell>

Improved description/technology handling by using flattenMarkdownOrString from @likec4/core/types and isEmptyish from remeda for cleaner type handling and better support for both plain strings and MarkdownOrString objects.

This aligns with the parser's expectations and ensures roundtrip compatibility (generate → parse → generate preserves description/technology metadata).

Checklist

  • I've thoroughly read the latest contribution guidelines.
  • I've rebased my branch onto main before creating this PR.
  • My commit messages follow conventional spec
  • I've added tests to cover my changes (if applicable).
  • I've verified that all new and existing tests have passed locally for mobile, tablet, and desktop screen sizes.
  • My change requires documentation updates.
  • I've updated the documentation accordingly.

💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Feb 11, 2026

⚠️ No Changeset found

Latest commit: 9428ec0

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copilot AI changed the title [WIP] Update CLI docs for DrawIO export flag Fix DrawIO CLI docs, refactor context menu, correct XML generation Feb 11, 2026
Copilot AI requested a review from davydkov February 11, 2026 10:24
@davydkov
Copy link
Copy Markdown
Member

@sraphaz Can you review this?

Comment on lines 153 to 155
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot fix lint issue by using flattenMarkdownOrString from @likec4/core/types, and isEmptyish from remeda

Something like

Suggested change
const description = node.description && flattenMarkdownOrString(node.description)
const desc = isEmptyish(description) ? '' : escapeXml(description)```

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 9428ec0 - now using flattenMarkdownOrString from @likec4/core/types and isEmptyish from remeda for cleaner description/technology handling.

Copy link
Copy Markdown
Collaborator

@sraphaz sraphaz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review: PR #2593 — Fix DrawIO CLI docs, refactor context menu, correct XML generation

Review by @sraphaz (as requested by @davydkov).


Summary

This PR applies three sets of changes: CLI documentation fix, DrawIO context menu refactor, and XML generation adjustments. The direction is correct; there is one issue that will break the playground typecheck and a few minor suggestions.


What looks good

1. CLI docs (cli.mdx)

  • --output, -o--outdir, -o is correct and matches the handler in packages/likec4/src/cli/export/drawio/handler.ts.

2. Context menu refactor

  • Extracting logic into useDrawioActions and the presentational DrawioContextMenuView reduces duplication and keeps the components easier to maintain.
  • Using triggerImport in the DRAWIO_IMPORT_EVENT / DRAWIO_EXPORT_EVENT listeners in the Provider is consistent.
  • DrawioContextMenuView with explicit props (opened, onClose, menuPosition, onImport, onExport, canExport) keeps the UI testable and reusable.

3. XML (generate-drawio.ts)

  • Placing mxUserObject after <mxGeometry /> inside each vertex mxCell is correct and aligns with what draw.io expects.
  • Using flattenMarkdownOrString and isEmptyish for description/technology improves typing and roundtrip behavior.

Issue that breaks typecheck

openMenu in the context menu is typed only with React.MouseEvent.

In DrawioContextMenuProvider.tsx (and in the DrawioContextMenuApi type):

openMenu: (event: React.MouseEvent) => void

But LikeC4Diagram expects (in packages/diagram/src/LikeC4Diagram.props.ts):

export type OnCanvasContextMenu = (event: ReactMouseEvent | MouseEvent) => void

So the callback may receive either React.MouseEvent or DOM MouseEvent. The code that calls onCanvasContextMenu (e.g. ReactFlow) can pass the native event.

Effect: when passing openMenu to onCanvasContextMenu in $viewId.tsx, the playground typecheck fails with:

error TS2322: Type '(event: MouseEvent<Element, MouseEvent>) => void' is not assignable to type 'OnCanvasContextMenu'.
  Types of parameters 'event' and 'event' are incompatible.
  Type 'MouseEvent | React.MouseEvent<...>' is not assignable to type 'MouseEvent<Element, MouseEvent>'.

Suggested fix: accept the union in the type and in the handler:

  • In DrawioContextMenuProvider.tsx: in DrawioContextMenuApi, use
    openMenu: (event: React.MouseEvent | MouseEvent) => void
  • In the hook that implements openMenu (in useDrawioActions or wherever openMenu is defined): use the signature
    (event: React.MouseEvent | MouseEvent) => void
    and keep using event.preventDefault(), event.clientX, event.clientY (they exist on both types).
  • In DrawioContextMenu.tsx, in the render prop children, type the argument the same way:
    (onCanvasContextMenu: (event: React.MouseEvent | MouseEvent) => void) => React.ReactNode

That makes the handler compatible with OnCanvasContextMenu and the playground typecheck will pass.


Minor suggestions

  1. Changeset
    The bot already noted there is no changeset. Since this PR touches docs, playground, and generators, adding a changeset (e.g. patch for @likec4/docs-astro, @likec4/playground, @likec4/generators) makes sense if you intend to version these changes.

  2. handleImportFile typing
    In useDrawioActions.ts, handleImportFile is typed as (e: React.ChangeEvent). For clarity and alignment with <input type="file">, consider:
    (e: React.ChangeEvent<HTMLInputElement>).

  3. Naming
    Current names (useDrawioActions, DrawioContextMenuView) are clear. An alternative used elsewhere is useDrawioContextMenuActions + DrawioContextMenuDropdown; either is fine as long as the rest of the drawio code is consistent.


Post-fix checklist

  • Update openMenu type to (event: React.MouseEvent | MouseEvent) => void (API + hook + render prop).
  • Run pnpm turbo run typecheck --filter='@likec4/playground' and ensure it passes.
  • (Optional) Add a changeset; (optional) type handleImportFile as React.ChangeEvent<HTMLInputElement>.

After that, this PR looks ready to merge from my side (assuming tests and the rest of typecheck are already green).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants