Skip to content

Commit 679bfbe

Browse files
aldergclaude
andcommitted
Add an SVG appearance setting for .drawio.svg files [#217]
The xmlsvg export request sent no theme, so draw.io picked one from the dark mode of the editor: auto (light-dark() colors) in a dark editor, light otherwise. A saved .drawio.svg thus depended on the VS Code theme of whoever saved it last, although the extension meant to always save light SVGs. The new hediet.vscode-drawio.svgAppearance setting (light, auto, dark; default light) is now sent as the theme of every svg export: .drawio.svg saves, Export To... and Convert..., and editable image links saved from the inline Markdown editor. With the default, files saved in a dark editor are light again; auto gives SVGs that adapt to the color scheme of the page that shows them. PNG exports are unchanged, draw.io always renders them light. Fixes #217 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 90f1538 commit 679bfbe

8 files changed

Lines changed: 89 additions & 7 deletions

File tree

‎README.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@ Add this to your VS Code `settings.json` file if you want to associate it with `
9090

9191
You won't be able to edit arbitrary SVG files though - only those that have been created with Draw.io or this extension!
9292

93+
## Light and Dark `.drawio.svg` Files
94+
95+
By default, `.drawio.svg` files are saved with light colors, whatever theme the editor uses.
96+
Set `hediet.vscode-drawio.svgAppearance` to `auto` to make them adapt to the color scheme of the page that shows them, for example a README on GitHub in dark mode, or to `dark` to always save them with dark colors.
97+
The setting applies the next time a diagram is saved. Add it to the workspace settings so that everyone on a team saves the same file.
98+
9399
## Inline Diagrams in VS Code's Markdown Editor (Experimental, Insiders only)
94100

95101
VS Code Insiders ships an experimental WYSIWYG Markdown editor (`View: Reopen Editor With... > Markdown Editor`).

‎package.json‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,23 @@
286286
"description": "When enabled, no ForeignObjects are used in the svg.",
287287
"order": 40
288288
},
289+
"hediet.vscode-drawio.svgAppearance": {
290+
"type": "string",
291+
"default": "light",
292+
"enum": [
293+
"light",
294+
"auto",
295+
"dark"
296+
],
297+
"enumDescriptions": [
298+
"The SVG always uses light colors.",
299+
"The SVG adapts to the light or dark color scheme of the page that shows it.",
300+
"The SVG always uses dark colors."
301+
],
302+
"title": "SVG Appearance",
303+
"description": "The appearance of `.drawio.svg` files and SVG exports. It does not depend on the theme of the editor.",
304+
"order": 45
305+
},
289306
"hediet.vscode-drawio.zoomFactor": {
290307
"type": "number",
291308
"default": 1.2,

‎src/Config.ts‎

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@ import {
1010
window,
1111
workspace,
1212
} from "vscode";
13-
import { Style, ColorScheme, DrawioLibraryData } from "./DrawioClient";
13+
import {
14+
Style,
15+
ColorScheme,
16+
DrawioExportTheme,
17+
DrawioLibraryData,
18+
} from "./DrawioClient";
1419
import { BufferImpl } from "./utils/buffer";
1520
import { SimpleTemplate } from "./utils/SimpleTemplate";
1621
import {
@@ -338,6 +343,28 @@ export class DiagramConfig {
338343

339344
//#endregion
340345

346+
//#region SVG Appearance
347+
348+
private readonly _svgAppearance = new VsCodeSetting(
349+
`${extensionId}.svgAppearance`,
350+
{
351+
scope: this.uri,
352+
serializer: serializerWithDefault<DrawioExportTheme>("light"),
353+
}
354+
);
355+
356+
/**
357+
* The theme of .drawio.svg files and svg exports. Without it, draw.io
358+
* picks one from the dark mode of the editor, so the saved file would
359+
* depend on the VS Code theme of whoever saved it last.
360+
*/
361+
@computed
362+
public get svgAppearance(): DrawioExportTheme {
363+
return this._svgAppearance.get();
364+
}
365+
366+
//#endregion
367+
341368
//#region Preset Colors
342369

343370
private readonly _presetColors = new VsCodeSetting(

‎src/DrawioClient/DrawioClient.ts‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { EventEmitter } from "@hediet/std/events";
22
import { Disposable } from "@hediet/std/disposable";
3-
import { DrawioConfig, DrawioEvent, DrawioAction } from "./DrawioTypes";
3+
import {
4+
DrawioConfig,
5+
DrawioEvent,
6+
DrawioAction,
7+
DrawioExportTheme,
8+
} from "./DrawioTypes";
49
import { BufferImpl } from "../utils/buffer";
510

611
/**
@@ -35,7 +40,8 @@ export class DrawioClient<
3540
constructor(
3641
private readonly messageStream: MessageStream,
3742
private readonly getConfig: () => Promise<DrawioConfig>,
38-
public readonly reloadWebview: () => void
43+
public readonly reloadWebview: () => void,
44+
private readonly getSvgTheme: () => DrawioExportTheme
3945
) {
4046
this.dispose.track(
4147
messageStream.registerMessageHandler((msg) =>
@@ -280,6 +286,7 @@ export class DrawioClient<
280286
const response = await this.sendActionWaitForResponse({
281287
action: "export",
282288
format: "xmlsvg",
289+
theme: this.getSvgTheme(),
283290
});
284291
if (response.event !== "export") {
285292
throw new Error("Unexpected response");

‎src/DrawioClient/DrawioClientFactory.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,8 @@ export class DrawioClientFactory {
135135
runInAction("Force reload", () => {
136136
reloadId.id++;
137137
});
138-
}
138+
},
139+
() => config.svgAppearance
139140
);
140141

141142
drawioClient.onUnknownMessage.sub(({ message }) => {

‎src/DrawioClient/DrawioTypes.ts‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ export type DrawioAction =
4747
format: DrawioFormat;
4848
// Exports the visible page instead of the first page (png)
4949
currentPage?: boolean;
50+
// Colors of the svg (xmlsvg); draw.io ignores it for png
51+
theme?: DrawioExportTheme;
5052
}
5153
| {
5254
action: "configure";
@@ -268,3 +270,9 @@ export interface DrawioResource {
268270
}
269271

270272
export type DrawioFormat = "html" | "xmlpng" | "png" | "xml" | "xmlsvg";
273+
274+
/**
275+
* The colors of an svg export: "auto" adapts to the color scheme of the page
276+
* that shows the svg (light-dark() colors).
277+
*/
278+
export type DrawioExportTheme = "auto" | "light" | "dark";

‎src/inline-editor/extension.ts‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2237,6 +2237,12 @@ class MarkdownEditorProvider implements vscode.CustomTextEditorProvider {
22372237
type: "setDiagramPadding",
22382238
padding: diagramPadding,
22392239
});
2240+
webviewPanel.webview.postMessage({
2241+
type: "setSvgAppearance",
2242+
appearance: vscode.workspace
2243+
.getConfiguration(DRAWIO_CONFIG_SECTION, document.uri)
2244+
.get<string>("svgAppearance", "light"),
2245+
});
22402246
sendContent();
22412247
{
22422248
const uriKey = document.uri.toString();

‎src/inline-editor/webview/inlinePreview.html‎

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,12 @@
709709
return /\.drawio\.png(?:[?#]|$)/i.test(target || '') ? 'xmlpng' : 'xmlsvg';
710710
}
711711

712+
// Export request for saving an editable image link. theme sets the colors
713+
// of the svg (hediet.vscode-drawio.svgAppearance); draw.io ignores it for png.
714+
function linkExportRequest(target) {
715+
return JSON.stringify({ action: 'export', format: linkExportFormat(target), theme: svgAppearance });
716+
}
717+
712718
// Forward intercepted VS Code shortcuts from draw.io iframes.
713719
// This is a dedicated listener that doesn't depend on iframe source
714720
// matching, because VS Code's webview iframe nesting can make
@@ -807,6 +813,7 @@
807813
var isDark = document.body.classList.contains('vscode-dark');
808814
var minimalUI = true;
809815
var diagramPadding = 28;
816+
var svgAppearance = 'light'; // colors of saved .drawio.svg links; set via setSvgAppearance
810817

811818
var imageBaseUri = '';
812819
var diagramBlocks = [];
@@ -2051,6 +2058,9 @@
20512058
case 'setDiagramPadding':
20522059
diagramPadding = msg.padding;
20532060
break;
2061+
case 'setSvgAppearance':
2062+
svgAppearance = msg.appearance;
2063+
break;
20542064
case 'sourceConverted':
20552065
handleSourceConverted(msg);
20562066
break;
@@ -2401,7 +2411,7 @@
24012411
if (overlayState.linkTarget) {
24022412
overlayState._pendingLinkSave = true;
24032413
state._linkSaveQuietUntil = Date.now() + 2000;
2404-
overlayFrame.contentWindow.postMessage(JSON.stringify({ action: 'export', format: linkExportFormat(overlayState.linkTarget) }), '*');
2414+
overlayFrame.contentWindow.postMessage(linkExportRequest(overlayState.linkTarget), '*');
24052415
}
24062416
else {
24072417
vscode.postMessage({
@@ -3423,7 +3433,7 @@
34233433
if (linkSec && linkSec.linkTarget) {
34243434
if (state.iframe && state.initialized) {
34253435
state._pendingLinkSave = true;
3426-
state.iframe.contentWindow.postMessage(JSON.stringify({ action: 'export', format: linkExportFormat(linkSec.linkTarget) }), '*');
3436+
state.iframe.contentWindow.postMessage(linkExportRequest(linkSec.linkTarget), '*');
34273437
}
34283438
return;
34293439
}
@@ -3441,7 +3451,7 @@
34413451
if (overlayState.active && overlayState.dirty) {
34423452
if (overlayState.linkTarget) {
34433453
overlayState._pendingLinkSave = true;
3444-
overlayFrame.contentWindow.postMessage(JSON.stringify({ action: 'export', format: linkExportFormat(overlayState.linkTarget) }), '*');
3454+
overlayFrame.contentWindow.postMessage(linkExportRequest(overlayState.linkTarget), '*');
34453455
}
34463456
else {
34473457
vscode.postMessage({

0 commit comments

Comments
 (0)