@diagrammo/dgmo 0.8.14 → 0.8.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,7 +4,7 @@ Diagrammo uses named colors throughout. There are two ways colors appear in diag
4
4
 
5
5
  ## Named Colors
6
6
 
7
- Nine color names are available everywhere colors are accepted:
7
+ Eleven color names are available everywhere colors are accepted:
8
8
 
9
9
  <table>
10
10
  <tr><th>Name</th><th>Swatch (Nord)</th></tr>
@@ -17,67 +17,71 @@ Nine color names are available everywhere colors are accepted:
17
17
  <tr><td><code>teal</code></td><td><span style="display:inline-block;width:20px;height:20px;background:#8fbcbb;border-radius:3px;vertical-align:middle"></span></td></tr>
18
18
  <tr><td><code>cyan</code></td><td><span style="display:inline-block;width:20px;height:20px;background:#88c0d0;border-radius:3px;vertical-align:middle"></span></td></tr>
19
19
  <tr><td><code>gray</code></td><td><span style="display:inline-block;width:20px;height:20px;background:#4c566a;border-radius:3px;vertical-align:middle"></span></td></tr>
20
+ <tr><td><code>black</code></td><td><span style="display:inline-block;width:20px;height:20px;background:#2e3440;border-radius:3px;vertical-align:middle"></span></td></tr>
21
+ <tr><td><code>white</code></td><td><span style="display:inline-block;width:20px;height:20px;background:#e5e9f0;border-radius:3px;vertical-align:middle;border:1px solid #d8dee9"></span></td></tr>
20
22
  </table>
21
23
 
24
+ `black` and `white` are theme-stable — each palette picks near-darkest / near-lightest values that stay distinct from the canvas.
25
+
22
26
  Swatches above use Nord values. The actual color rendered depends on your active color scheme — see [Color Schemes](#color-schemes) below.
23
27
 
24
28
  ---
25
29
 
26
30
  ## Color Schemes
27
31
 
28
- Diagrammo includes ten built-in color schemes. Change yours in **Settings**. The same nine color names resolve to different hex values in each scheme. Swatches show the first six colors (red → purple) for light / dark mode.
32
+ Diagrammo includes ten built-in color schemes. Change yours in **Settings**. The same eleven color names resolve to different hex values in each scheme. Swatches show all eleven colors (red → white) for light / dark mode.
29
33
 
30
34
  <table>
31
35
  <tr><th>Scheme</th><th style="text-align:center">Light</th><th style="text-align:center">Dark</th></tr>
32
36
  <tr>
33
37
  <td><strong>Bold</strong></td>
34
- <td><span style="display:inline-flex;gap:2px;background:#ffffff;padding:4px 6px;border-radius:4px;border:1px solid #cccccc"><span style="display:inline-block;width:14px;height:14px;background:#ff0000;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ff8000;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ffcc00;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#00cc00;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#0000ff;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#cc00cc;border-radius:2px"></span></span></td>
35
- <td><span style="display:inline-flex;gap:2px;background:#000000;padding:4px 6px;border-radius:4px;border:1px solid #333333"><span style="display:inline-block;width:14px;height:14px;background:#ff0000;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ff8000;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ffff00;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#00ff00;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#0066ff;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ff00ff;border-radius:2px"></span></span></td>
38
+ <td><span style="display:inline-flex;gap:2px;background:#ffffff;padding:4px 6px;border-radius:4px;border:1px solid #cccccc"><span style="display:inline-block;width:14px;height:14px;background:#ff0000;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ff8000;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ffcc00;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#00cc00;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#0000ff;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#cc00cc;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#009999;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#00bfff;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#666666;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#000000;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#f0f0f0;border-radius:2px"></span></span></td>
39
+ <td><span style="display:inline-flex;gap:2px;background:#000000;padding:4px 6px;border-radius:4px;border:1px solid #333333"><span style="display:inline-block;width:14px;height:14px;background:#ff0000;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ff8000;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ffff00;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#00ff00;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#0066ff;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ff00ff;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#00cccc;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#00ffff;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#999999;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#111111;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ffffff;border-radius:2px"></span></span></td>
36
40
  </tr>
37
41
  <tr>
38
42
  <td><strong>Catppuccin</strong></td>
39
- <td><span style="display:inline-flex;gap:2px;background:#eff1f5;padding:4px 6px;border-radius:4px;border:1px solid #ccd0da"><span style="display:inline-block;width:14px;height:14px;background:#d20f39;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#fe640b;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#df8e1d;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#40a02b;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#1e66f5;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#8839ef;border-radius:2px"></span></span></td>
40
- <td><span style="display:inline-flex;gap:2px;background:#1e1e2e;padding:4px 6px;border-radius:4px;border:1px solid #45475a"><span style="display:inline-block;width:14px;height:14px;background:#f38ba8;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#fab387;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#f9e2af;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#a6e3a1;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#89b4fa;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#cba6f7;border-radius:2px"></span></span></td>
43
+ <td><span style="display:inline-flex;gap:2px;background:#eff1f5;padding:4px 6px;border-radius:4px;border:1px solid #ccd0da"><span style="display:inline-block;width:14px;height:14px;background:#d20f39;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#fe640b;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#df8e1d;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#40a02b;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#1e66f5;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#8839ef;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#179299;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#04a5e5;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#9ca0b0;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#4c4f69;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#e6e9ef;border-radius:2px"></span></span></td>
44
+ <td><span style="display:inline-flex;gap:2px;background:#1e1e2e;padding:4px 6px;border-radius:4px;border:1px solid #45475a"><span style="display:inline-block;width:14px;height:14px;background:#f38ba8;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#fab387;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#f9e2af;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#a6e3a1;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#89b4fa;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#cba6f7;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#94e2d5;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#89dceb;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#a6adc8;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#313244;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#cdd6f4;border-radius:2px"></span></span></td>
41
45
  </tr>
42
46
  <tr>
43
47
  <td><strong>Dracula</strong></td>
44
- <td><span style="display:inline-flex;gap:2px;background:#f8f8f2;padding:4px 6px;border-radius:4px;border:1px solid #d8d8d2"><span style="display:inline-block;width:14px;height:14px;background:#ff5555;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ffb86c;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#f1fa8c;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#50fa7b;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#6272a4;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#bd93f9;border-radius:2px"></span></span></td>
45
- <td><span style="display:inline-flex;gap:2px;background:#282a36;padding:4px 6px;border-radius:4px;border:1px solid #6272a4"><span style="display:inline-block;width:14px;height:14px;background:#ff5555;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ffb86c;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#f1fa8c;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#50fa7b;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#6272a4;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#bd93f9;border-radius:2px"></span></span></td>
48
+ <td><span style="display:inline-flex;gap:2px;background:#f8f8f2;padding:4px 6px;border-radius:4px;border:1px solid #d8d8d2"><span style="display:inline-block;width:14px;height:14px;background:#ff5555;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ffb86c;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#f1fa8c;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#50fa7b;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#6272a4;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#bd93f9;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#8be9fd;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#8be9fd;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#6272a4;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#282a36;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#f0f0ec;border-radius:2px"></span></span></td>
49
+ <td><span style="display:inline-flex;gap:2px;background:#282a36;padding:4px 6px;border-radius:4px;border:1px solid #6272a4"><span style="display:inline-block;width:14px;height:14px;background:#ff5555;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ffb86c;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#f1fa8c;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#50fa7b;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#6272a4;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#bd93f9;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#8be9fd;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#8be9fd;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#6272a4;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#343746;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#f8f8f2;border-radius:2px"></span></span></td>
46
50
  </tr>
47
51
  <tr>
48
52
  <td><strong>Gruvbox</strong></td>
49
- <td><span style="display:inline-flex;gap:2px;background:#fbf1c7;padding:4px 6px;border-radius:4px;border:1px solid #d5c4a1"><span style="display:inline-block;width:14px;height:14px;background:#9d0006;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#af3a03;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#b57614;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#79740e;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#076678;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#8f3f71;border-radius:2px"></span></span></td>
50
- <td><span style="display:inline-flex;gap:2px;background:#282828;padding:4px 6px;border-radius:4px;border:1px solid #504945"><span style="display:inline-block;width:14px;height:14px;background:#fb4934;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#fe8019;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#fabd2f;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#b8bb26;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#83a598;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#d3869b;border-radius:2px"></span></span></td>
53
+ <td><span style="display:inline-flex;gap:2px;background:#fbf1c7;padding:4px 6px;border-radius:4px;border:1px solid #d5c4a1"><span style="display:inline-block;width:14px;height:14px;background:#9d0006;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#af3a03;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#b57614;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#79740e;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#076678;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#8f3f71;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#427b58;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#689d6a;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#7c6f64;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#3c3836;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ebdbb2;border-radius:2px"></span></span></td>
54
+ <td><span style="display:inline-flex;gap:2px;background:#282828;padding:4px 6px;border-radius:4px;border:1px solid #504945"><span style="display:inline-block;width:14px;height:14px;background:#fb4934;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#fe8019;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#fabd2f;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#b8bb26;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#83a598;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#d3869b;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#8ec07c;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#8ec07c;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#928374;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#3c3836;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ebdbb2;border-radius:2px"></span></span></td>
51
55
  </tr>
52
56
  <tr>
53
57
  <td><strong>Monokai</strong></td>
54
- <td><span style="display:inline-flex;gap:2px;background:#fafaf8;padding:4px 6px;border-radius:4px;border:1px solid #d4d3cc"><span style="display:inline-block;width:14px;height:14px;background:#f92672;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#fd971f;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#e6db74;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#a6e22e;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#5c7eab;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ae81ff;border-radius:2px"></span></span></td>
55
- <td><span style="display:inline-flex;gap:2px;background:#272822;padding:4px 6px;border-radius:4px;border:1px solid #49483e"><span style="display:inline-block;width:14px;height:14px;background:#f92672;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#fd971f;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#e6db74;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#a6e22e;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#5c7eab;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ae81ff;border-radius:2px"></span></span></td>
58
+ <td><span style="display:inline-flex;gap:2px;background:#fafaf8;padding:4px 6px;border-radius:4px;border:1px solid #d4d3cc"><span style="display:inline-block;width:14px;height:14px;background:#f92672;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#fd971f;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#e6db74;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#a6e22e;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#5c7eab;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ae81ff;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#66d9ef;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#66d9ef;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#75715e;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#272822;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#f0efe8;border-radius:2px"></span></span></td>
59
+ <td><span style="display:inline-flex;gap:2px;background:#272822;padding:4px 6px;border-radius:4px;border:1px solid #49483e"><span style="display:inline-block;width:14px;height:14px;background:#f92672;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#fd971f;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#e6db74;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#a6e22e;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#5c7eab;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ae81ff;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#66d9ef;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#66d9ef;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#75715e;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#2d2e27;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#f8f8f2;border-radius:2px"></span></span></td>
56
60
  </tr>
57
61
  <tr>
58
62
  <td><strong>Nord</strong></td>
59
- <td><span style="display:inline-flex;gap:2px;background:#eceff4;padding:4px 6px;border-radius:4px;border:1px solid #d8dee9"><span style="display:inline-block;width:14px;height:14px;background:#bf616a;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#d08770;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ebcb8b;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#a3be8c;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#5e81ac;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#b48ead;border-radius:2px"></span></span></td>
60
- <td><span style="display:inline-flex;gap:2px;background:#2e3440;padding:4px 6px;border-radius:4px;border:1px solid #4c566a"><span style="display:inline-block;width:14px;height:14px;background:#bf616a;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#d08770;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ebcb8b;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#a3be8c;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#5e81ac;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#b48ead;border-radius:2px"></span></span></td>
63
+ <td><span style="display:inline-flex;gap:2px;background:#eceff4;padding:4px 6px;border-radius:4px;border:1px solid #d8dee9"><span style="display:inline-block;width:14px;height:14px;background:#bf616a;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#d08770;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ebcb8b;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#a3be8c;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#5e81ac;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#b48ead;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#8fbcbb;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#88c0d0;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#4c566a;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#2e3440;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#e5e9f0;border-radius:2px"></span></span></td>
64
+ <td><span style="display:inline-flex;gap:2px;background:#2e3440;padding:4px 6px;border-radius:4px;border:1px solid #4c566a"><span style="display:inline-block;width:14px;height:14px;background:#bf616a;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#d08770;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ebcb8b;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#a3be8c;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#5e81ac;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#b48ead;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#8fbcbb;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#88c0d0;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#4c566a;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#3b4252;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#eceff4;border-radius:2px"></span></span></td>
61
65
  </tr>
62
66
  <tr>
63
67
  <td><strong>One Dark</strong></td>
64
- <td><span style="display:inline-flex;gap:2px;background:#fafafa;padding:4px 6px;border-radius:4px;border:1px solid #d0d0d0"><span style="display:inline-block;width:14px;height:14px;background:#e45649;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#c18401;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#c18401;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#50a14f;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#4078f2;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#a626a4;border-radius:2px"></span></span></td>
65
- <td><span style="display:inline-flex;gap:2px;background:#282c34;padding:4px 6px;border-radius:4px;border:1px solid #3e4451"><span style="display:inline-block;width:14px;height:14px;background:#e06c75;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#d19a66;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#e5c07b;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#98c379;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#61afef;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#c678dd;border-radius:2px"></span></span></td>
68
+ <td><span style="display:inline-flex;gap:2px;background:#fafafa;padding:4px 6px;border-radius:4px;border:1px solid #d0d0d0"><span style="display:inline-block;width:14px;height:14px;background:#e45649;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#c18401;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#c18401;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#50a14f;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#4078f2;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#a626a4;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#0184bc;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#0184bc;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#a0a1a7;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#383a42;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#f0f0f0;border-radius:2px"></span></span></td>
69
+ <td><span style="display:inline-flex;gap:2px;background:#282c34;padding:4px 6px;border-radius:4px;border:1px solid #3e4451"><span style="display:inline-block;width:14px;height:14px;background:#e06c75;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#d19a66;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#e5c07b;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#98c379;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#61afef;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#c678dd;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#56b6c2;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#56b6c2;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#abb2bf;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#21252b;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#abb2bf;border-radius:2px"></span></span></td>
66
70
  </tr>
67
71
  <tr>
68
72
  <td><strong>Rosé Pine</strong></td>
69
- <td><span style="display:inline-flex;gap:2px;background:#faf4ed;padding:4px 6px;border-radius:4px;border:1px solid #f2e9e1"><span style="display:inline-block;width:14px;height:14px;background:#b4637a;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#d7827e;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ea9d34;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#286983;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#56949f;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#907aa9;border-radius:2px"></span></span></td>
70
- <td><span style="display:inline-flex;gap:2px;background:#191724;padding:4px 6px;border-radius:4px;border:1px solid #26233a"><span style="display:inline-block;width:14px;height:14px;background:#eb6f92;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ea9a97;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#f6c177;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#3e8fb0;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#9ccfd8;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#c4a7e7;border-radius:2px"></span></span></td>
73
+ <td><span style="display:inline-flex;gap:2px;background:#faf4ed;padding:4px 6px;border-radius:4px;border:1px solid #f2e9e1"><span style="display:inline-block;width:14px;height:14px;background:#b4637a;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#d7827e;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ea9d34;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#286983;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#56949f;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#907aa9;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#56949f;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#56949f;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#9893a5;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#575279;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#fffaf3;border-radius:2px"></span></span></td>
74
+ <td><span style="display:inline-flex;gap:2px;background:#191724;padding:4px 6px;border-radius:4px;border:1px solid #26233a"><span style="display:inline-block;width:14px;height:14px;background:#eb6f92;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ea9a97;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#f6c177;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#3e8fb0;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#9ccfd8;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#c4a7e7;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#9ccfd8;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#9ccfd8;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#908caa;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#2a273f;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#e0def4;border-radius:2px"></span></span></td>
71
75
  </tr>
72
76
  <tr>
73
77
  <td><strong>Solarized</strong></td>
74
- <td><span style="display:inline-flex;gap:2px;background:#fdf6e3;padding:4px 6px;border-radius:4px;border:1px solid #eee8d5"><span style="display:inline-block;width:14px;height:14px;background:#dc322f;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#cb4b16;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#b58900;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#859900;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#268bd2;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#6c71c4;border-radius:2px"></span></span></td>
75
- <td><span style="display:inline-flex;gap:2px;background:#002b36;padding:4px 6px;border-radius:4px;border:1px solid #073642"><span style="display:inline-block;width:14px;height:14px;background:#dc322f;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#cb4b16;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#b58900;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#859900;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#268bd2;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#6c71c4;border-radius:2px"></span></span></td>
78
+ <td><span style="display:inline-flex;gap:2px;background:#fdf6e3;padding:4px 6px;border-radius:4px;border:1px solid #eee8d5"><span style="display:inline-block;width:14px;height:14px;background:#dc322f;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#cb4b16;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#b58900;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#859900;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#268bd2;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#6c71c4;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#2aa198;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#2aa198;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#93a1a1;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#657b83;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#eee8d5;border-radius:2px"></span></span></td>
79
+ <td><span style="display:inline-flex;gap:2px;background:#002b36;padding:4px 6px;border-radius:4px;border:1px solid #073642"><span style="display:inline-block;width:14px;height:14px;background:#dc322f;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#cb4b16;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#b58900;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#859900;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#268bd2;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#6c71c4;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#2aa198;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#2aa198;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#586e75;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#073642;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#839496;border-radius:2px"></span></span></td>
76
80
  </tr>
77
81
  <tr>
78
82
  <td><strong>Tokyo Night</strong></td>
79
- <td><span style="display:inline-flex;gap:2px;background:#d5d6db;padding:4px 6px;border-radius:4px;border:1px solid #9699a3"><span style="display:inline-block;width:14px;height:14px;background:#f52a65;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#b15c00;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#8c6c3e;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#587539;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#2e7de9;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#7847bd;border-radius:2px"></span></span></td>
80
- <td><span style="display:inline-flex;gap:2px;background:#1a1b26;padding:4px 6px;border-radius:4px;border:1px solid #3b4261"><span style="display:inline-block;width:14px;height:14px;background:#f7768e;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ff9e64;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#e0af68;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#9ece6a;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#7aa2f7;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#bb9af7;border-radius:2px"></span></span></td>
83
+ <td><span style="display:inline-flex;gap:2px;background:#d5d6db;padding:4px 6px;border-radius:4px;border:1px solid #9699a3"><span style="display:inline-block;width:14px;height:14px;background:#f52a65;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#b15c00;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#8c6c3e;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#587539;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#2e7de9;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#7847bd;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#118c74;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#007197;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#8990b3;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#1a1b26;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#d0d5e3;border-radius:2px"></span></span></td>
84
+ <td><span style="display:inline-flex;gap:2px;background:#1a1b26;padding:4px 6px;border-radius:4px;border:1px solid #3b4261"><span style="display:inline-block;width:14px;height:14px;background:#f7768e;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#ff9e64;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#e0af68;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#9ece6a;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#7aa2f7;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#bb9af7;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#1abc9c;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#7dcfff;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#565f89;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#292e42;border-radius:2px"></span><span style="display:inline-block;width:14px;height:14px;background:#c0caf5;border-radius:2px"></span></span></td>
81
85
  </tr>
82
86
  </table>
83
87
 
@@ -80,7 +80,9 @@ EntityName | key: value, key2: value2
80
80
  Label(colorName)
81
81
  ```
82
82
 
83
- - Named palette colors only (no hex codes)
83
+ - **Allowed color names (exactly these 10):** `red`, `orange`, `yellow`, `green`, `blue`, `purple`, `teal`, `cyan`, `lightblue`, `gray`
84
+ - Any other value — including hex codes (`#ff0000`), CSS keywords (`black`, `white`, `pink`), or typos — is a parse error and produces an inline diagnostic in the editor (with a "did you mean?" suggestion when close to a known name)
85
+ - The actual hex value rendered for each name comes from the active palette/theme; users cannot extend or override the allowed list
84
86
  - Appears at end of labels, node names, tag values, series names
85
87
  - Color is stripped from display text
86
88
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diagrammo/dgmo",
3
- "version": "0.8.14",
3
+ "version": "0.8.16",
4
4
  "description": "DGMO diagram markup language — parser, renderer, and color system",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/chart.ts CHANGED
@@ -59,7 +59,7 @@ export interface ParsedChart {
59
59
  // Colors
60
60
  // ============================================================
61
61
 
62
- import { resolveColor } from './colors';
62
+ import { resolveColorWithDiagnostic } from './colors';
63
63
  import type { PaletteColors } from './palettes';
64
64
  import { makeDgmoError, formatDgmoError, suggest } from './diagnostics';
65
65
  import {
@@ -215,7 +215,14 @@ export function parseChart(
215
215
  rawEras.push({
216
216
  start: eraMatch[1].trim(),
217
217
  afterArrow,
218
- color: eraMatch[3] ? resolveColor(eraMatch[3].trim(), palette) : null,
218
+ color: eraMatch[3]
219
+ ? (resolveColorWithDiagnostic(
220
+ eraMatch[3].trim(),
221
+ lineNumber,
222
+ result.diagnostics,
223
+ palette
224
+ ) ?? null)
225
+ : null,
219
226
  lineNumber,
220
227
  });
221
228
  }
@@ -278,12 +285,23 @@ export function parseChart(
278
285
  }
279
286
 
280
287
  if (firstToken === 'color') {
281
- result.color = resolveColor(value.trim(), palette) ?? undefined;
288
+ result.color = resolveColorWithDiagnostic(
289
+ value.trim(),
290
+ lineNumber,
291
+ result.diagnostics,
292
+ palette
293
+ );
282
294
  continue;
283
295
  }
284
296
 
285
297
  if (firstToken === 'series') {
286
- const parsed = parseSeriesNames(value, lines, i, palette);
298
+ const parsed = parseSeriesNames(
299
+ value,
300
+ lines,
301
+ i,
302
+ palette,
303
+ result.diagnostics
304
+ );
287
305
  i = parsed.newIndex;
288
306
  result.series = parsed.series;
289
307
  result.seriesLineNumber = lineNumber;
@@ -1,4 +1,4 @@
1
- import { resolveColor } from '../colors';
1
+ import { resolveColorWithDiagnostic } from '../colors';
2
2
  import type { PaletteColors } from '../palettes';
3
3
  import { makeDgmoError, formatDgmoError } from '../diagnostics';
4
4
  import {
@@ -302,7 +302,14 @@ export function parseClassDiagram(
302
302
  const bracketModifier = classDecl[5] as ClassModifier | undefined;
303
303
  const modifier = prefixModifier ?? bracketModifier;
304
304
  const colorName = classDecl[6]?.trim();
305
- const color = colorName ? resolveColor(colorName, palette) : undefined;
305
+ const color = colorName
306
+ ? resolveColorWithDiagnostic(
307
+ colorName,
308
+ lineNumber,
309
+ result.diagnostics,
310
+ palette
311
+ )
312
+ : undefined;
306
313
 
307
314
  const node = getOrCreateClass(name, lineNumber);
308
315
  if (modifier) node.modifier = modifier;
package/src/colors.ts CHANGED
@@ -36,33 +36,89 @@ export const colorNames: Record<string, string> = {
36
36
  purple: nord.nord15,
37
37
  teal: nord.nord7,
38
38
  cyan: nord.nord8,
39
- lightblue: nord.nord8,
40
39
  gray: nord.nord3,
40
+ black: nord.nord0,
41
+ white: nord.nord6,
41
42
  };
42
43
 
43
44
  /**
44
- * Resolves a color name to a valid CSS color.
45
- * When a palette is provided, named colors resolve against its color map first.
46
- * Hex codes are NOT supported use named colors only.
47
- * Unknown names are returned as-is.
45
+ * The canonical, closed set of color names accepted by the DGMO language.
46
+ * See `docs/dgmo-language-spec.md` §1.5. Users cannot extend this list
47
+ * palettes only provide the per-theme hex values for these names.
48
+ */
49
+ export const RECOGNIZED_COLOR_NAMES = Object.freeze([
50
+ 'red',
51
+ 'orange',
52
+ 'yellow',
53
+ 'green',
54
+ 'blue',
55
+ 'purple',
56
+ 'teal',
57
+ 'cyan',
58
+ 'gray',
59
+ 'black',
60
+ 'white',
61
+ ] as const);
62
+
63
+ /**
64
+ * Returns true iff `name` is one of the 11 recognized DGMO color names.
65
+ */
66
+ export function isRecognizedColorName(name: string): boolean {
67
+ return Object.prototype.hasOwnProperty.call(colorNames, name.toLowerCase());
68
+ }
69
+
70
+ /**
71
+ * Resolves a recognized color name to its hex value for the active palette
72
+ * (falling back to the built-in Nord defaults). Returns `null` for any
73
+ * unrecognized input — including hex codes, CSS keywords like `black`,
74
+ * and typos. Callers MUST treat `null` as a parse error and emit a
75
+ * diagnostic; do not silently fall back to the raw input.
48
76
  */
49
77
  export function resolveColor(
50
78
  color: string,
51
79
  palette?: { colors: Record<string, string> }
52
80
  ): string | null {
81
+ if (!color) return null;
53
82
  // Reject hex color codes — only named colors are supported
54
83
  if (color.startsWith('#')) return null;
55
84
 
56
85
  const lower = color.toLowerCase();
86
+ if (!isRecognizedColorName(lower)) return null;
57
87
 
58
88
  if (palette) {
59
89
  const named = palette.colors[lower];
60
90
  if (named) return named;
61
91
  }
92
+ return colorNames[lower];
93
+ }
94
+
95
+ import type { DgmoError } from './diagnostics';
96
+ import { makeDgmoError, suggest } from './diagnostics';
62
97
 
63
- if (colorNames[lower]) return colorNames[lower];
64
- // Unknown color name return as-is so callers can detect + warn
65
- return color;
98
+ /**
99
+ * Resolves a color name and pushes a warning diagnostic on failure.
100
+ * Returns the hex string for valid names, or `undefined` for unknown
101
+ * input (after pushing a diagnostic). Use this from parsers that have
102
+ * a diagnostics array and a line number in scope.
103
+ */
104
+ export function resolveColorWithDiagnostic(
105
+ color: string,
106
+ line: number,
107
+ diagnostics: DgmoError[],
108
+ palette?: { colors: Record<string, string> }
109
+ ): string | undefined {
110
+ const resolved = resolveColor(color, palette);
111
+ if (resolved !== null) return resolved;
112
+ const hint = suggest(color, RECOGNIZED_COLOR_NAMES as readonly string[]);
113
+ const suggestion = hint ? ` ${hint}` : '';
114
+ diagnostics.push(
115
+ makeDgmoError(
116
+ line,
117
+ `Unknown color "${color}". Allowed: ${RECOGNIZED_COLOR_NAMES.join(', ')}.${suggestion}`,
118
+ 'warning'
119
+ )
120
+ );
121
+ return undefined;
66
122
  }
67
123
 
68
124
  /** @deprecated Use getSeriesColors(palette) from '@/lib/palettes' instead. */
package/src/d3.ts CHANGED
@@ -177,7 +177,7 @@ export interface ParsedVisualization {
177
177
  // Color Imports
178
178
  // ============================================================
179
179
 
180
- import { resolveColor } from './colors';
180
+ import { resolveColorWithDiagnostic } from './colors';
181
181
  import type { PaletteColors } from './palettes';
182
182
  import { getSeriesColors } from './palettes';
183
183
  import { mix } from './palettes/color-utils';
@@ -609,14 +609,24 @@ export function parseVisualization(
609
609
  if (result.type === 'arc') {
610
610
  const name = groupMatch[1].trim();
611
611
  const color = groupMatch[2]
612
- ? resolveColor(groupMatch[2].trim(), palette)
612
+ ? (resolveColorWithDiagnostic(
613
+ groupMatch[2].trim(),
614
+ lineNumber,
615
+ result.diagnostics,
616
+ palette
617
+ ) ?? null)
613
618
  : null;
614
619
  result.arcNodeGroups.push({ name, nodes: [], color, lineNumber });
615
620
  currentArcGroup = name;
616
621
  } else if (result.type === 'timeline') {
617
622
  const name = groupMatch[1].trim();
618
623
  const color = groupMatch[2]
619
- ? resolveColor(groupMatch[2].trim(), palette)
624
+ ? (resolveColorWithDiagnostic(
625
+ groupMatch[2].trim(),
626
+ lineNumber,
627
+ result.diagnostics,
628
+ palette
629
+ ) ?? null)
620
630
  : null;
621
631
  result.timelineGroups.push({ name, color, lineNumber });
622
632
  currentTimelineGroup = name;
@@ -658,7 +668,12 @@ export function parseVisualization(
658
668
  const source = linkMatch[1].trim();
659
669
  const target = linkMatch[2].trim();
660
670
  const linkColor = linkMatch[3]
661
- ? resolveColor(linkMatch[3].trim(), palette)
671
+ ? (resolveColorWithDiagnostic(
672
+ linkMatch[3].trim(),
673
+ lineNumber,
674
+ result.diagnostics,
675
+ palette
676
+ ) ?? null)
662
677
  : null;
663
678
  result.links.push({
664
679
  source,
@@ -701,7 +716,12 @@ export function parseVisualization(
701
716
  endDate: eraEntryMatch[2],
702
717
  label: eraEntryMatch[3].trim(),
703
718
  color: colorAnnotation
704
- ? resolveColor(colorAnnotation, palette)
719
+ ? (resolveColorWithDiagnostic(
720
+ colorAnnotation,
721
+ lineNumber,
722
+ result.diagnostics,
723
+ palette
724
+ ) ?? null)
705
725
  : null,
706
726
  lineNumber,
707
727
  });
@@ -728,7 +748,12 @@ export function parseVisualization(
728
748
  date: markerEntryMatch[1],
729
749
  label: markerEntryMatch[2].trim(),
730
750
  color: colorAnnotation
731
- ? resolveColor(colorAnnotation, palette)
751
+ ? (resolveColorWithDiagnostic(
752
+ colorAnnotation,
753
+ lineNumber,
754
+ result.diagnostics,
755
+ palette
756
+ ) ?? null)
732
757
  : null,
733
758
  lineNumber,
734
759
  });
@@ -766,7 +791,12 @@ export function parseVisualization(
766
791
  endDate: eraMatch[2],
767
792
  label: eraMatch[3].trim(),
768
793
  color: colorAnnotation
769
- ? resolveColor(colorAnnotation, palette)
794
+ ? (resolveColorWithDiagnostic(
795
+ colorAnnotation,
796
+ lineNumber,
797
+ result.diagnostics,
798
+ palette
799
+ ) ?? null)
770
800
  : null,
771
801
  lineNumber,
772
802
  });
@@ -783,7 +813,12 @@ export function parseVisualization(
783
813
  date: markerMatch[1],
784
814
  label: markerMatch[2].trim(),
785
815
  color: colorAnnotation
786
- ? resolveColor(colorAnnotation, palette)
816
+ ? (resolveColorWithDiagnostic(
817
+ colorAnnotation,
818
+ lineNumber,
819
+ result.diagnostics,
820
+ palette
821
+ ) ?? null)
787
822
  : null,
788
823
  lineNumber,
789
824
  });
@@ -938,20 +973,13 @@ export function parseVisualization(
938
973
  const colorName = setDeclMatch[2]?.trim() ?? null;
939
974
  let color: string | null = null;
940
975
  if (colorName) {
941
- const resolved = resolveColor(colorName, palette);
942
- if (resolved === null) {
943
- warn(
944
- lineNumber,
945
- `Hex colors are not supported — use named colors (blue, red, green, etc.)`
946
- );
947
- } else if (resolved.startsWith('#')) {
948
- color = resolved;
949
- } else {
950
- warn(
976
+ color =
977
+ resolveColorWithDiagnostic(
978
+ colorName,
951
979
  lineNumber,
952
- `Unknown color "${colorName}" on set "${name}". Using auto-assigned color.`
953
- );
954
- }
980
+ result.diagnostics,
981
+ palette
982
+ ) ?? null;
955
983
  }
956
984
  const alias = setDeclMatch[3]?.trim() ?? null;
957
985
  result.vennSets.push({ name, alias, color, lineNumber });
@@ -1010,7 +1038,12 @@ export function parseVisualization(
1010
1038
  const labelColorMatch = labelPart.match(/^(.+?)\s*\(([^)]+)\)\s*$/);
1011
1039
  const text = labelColorMatch ? labelColorMatch[1].trim() : labelPart;
1012
1040
  const color = labelColorMatch
1013
- ? resolveColor(labelColorMatch[2].trim(), palette)
1041
+ ? (resolveColorWithDiagnostic(
1042
+ labelColorMatch[2].trim(),
1043
+ lineNumber,
1044
+ result.diagnostics,
1045
+ palette
1046
+ ) ?? null)
1014
1047
  : null;
1015
1048
  const label: QuadrantLabel = { text, color, lineNumber };
1016
1049
 
@@ -1232,7 +1265,12 @@ export function parseVisualization(
1232
1265
  const colorMatch = joinedLabel.match(/^(.+?)\(([^)]+)\)\s*$/);
1233
1266
  const labelPart = colorMatch ? colorMatch[1].trim() : joinedLabel;
1234
1267
  const colorPart = colorMatch
1235
- ? resolveColor(colorMatch[2].trim(), palette)
1268
+ ? (resolveColorWithDiagnostic(
1269
+ colorMatch[2].trim(),
1270
+ lineNumber,
1271
+ result.diagnostics,
1272
+ palette
1273
+ ) ?? null)
1236
1274
  : null;
1237
1275
 
1238
1276
  if (!labelPart) {
@@ -1333,7 +1371,12 @@ export function parseVisualization(
1333
1371
  // Data line: "Label: value1, value2" or "Label(color): value1, value2"
1334
1372
  const labelPart = colorMatch ? colorMatch[1].trim() : rawKey;
1335
1373
  const colorPart = colorMatch
1336
- ? resolveColor(colorMatch[2].trim(), palette)
1374
+ ? (resolveColorWithDiagnostic(
1375
+ colorMatch[2].trim(),
1376
+ lineNumber,
1377
+ result.diagnostics,
1378
+ palette
1379
+ ) ?? null)
1337
1380
  : null;
1338
1381
  const valuePart = line.substring(colonIndex + 1).trim();
1339
1382
  const values = valuePart.split(',').map((v) => v.trim());
@@ -6806,19 +6849,13 @@ export async function renderForExport(
6806
6849
  container.style.left = '-9999px';
6807
6850
  document.body.appendChild(container);
6808
6851
 
6809
- renderKanban(
6810
- container,
6811
- kanbanParsed,
6812
- effectivePalette,
6813
- theme === 'dark',
6814
- undefined,
6815
- undefined,
6816
- resolveActiveTagGroup(
6852
+ renderKanban(container, kanbanParsed, effectivePalette, theme === 'dark', {
6853
+ activeTagGroup: resolveActiveTagGroup(
6817
6854
  kanbanParsed.tagGroups,
6818
6855
  kanbanParsed.options['active-tag'],
6819
6856
  options?.tagGroup
6820
- )
6821
- );
6857
+ ),
6858
+ });
6822
6859
  return finalizeSvgExport(container, theme, effectivePalette, options);
6823
6860
  }
6824
6861
 
@@ -3,7 +3,7 @@
3
3
  // Parses dgmo quadrant syntax and generates valid Mermaid code.
4
4
  // ============================================================
5
5
 
6
- import { resolveColor } from './colors';
6
+ import { resolveColorWithDiagnostic } from './colors';
7
7
  import type { DgmoError } from './diagnostics';
8
8
  import { makeDgmoError, formatDgmoError } from './diagnostics';
9
9
 
@@ -127,7 +127,13 @@ export function parseQuadrant(content: string): ParsedQuadrant {
127
127
  if (labelMatch) {
128
128
  const label: QuadrantLabel = {
129
129
  text: labelMatch[1].trim(),
130
- color: labelMatch[2] ? resolveColor(labelMatch[2].trim()) : null,
130
+ color: labelMatch[2]
131
+ ? (resolveColorWithDiagnostic(
132
+ labelMatch[2].trim(),
133
+ lineNumber,
134
+ result.diagnostics
135
+ ) ?? null)
136
+ : null,
131
137
  lineNumber,
132
138
  };
133
139
  if (position === 'top-right') result.quadrants.topRight = label;