@zenuml/core 3.47.8 → 3.48.0

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.
Files changed (204) hide show
  1. package/dist/cloud-icons-eHuugVSv.js.map +1 -0
  2. package/dist/zenuml.esm.mjs +2153 -2156
  3. package/dist/zenuml.esm.mjs.map +1 -0
  4. package/dist/zenuml.js +82 -82
  5. package/dist/zenuml.js.map +1 -0
  6. package/package.json +11 -1
  7. package/src/cli/zenuml.ts +1164 -0
  8. package/.agents/skills/babysit-pr/SKILL.md +0 -223
  9. package/.agents/skills/babysit-pr/agents/openai.yaml +0 -7
  10. package/.agents/skills/dia-scoring/SKILL.md +0 -139
  11. package/.agents/skills/dia-scoring/agents/openai.yaml +0 -7
  12. package/.agents/skills/dia-scoring/references/selectors-and-keys.md +0 -253
  13. package/.agents/skills/land-pr/SKILL.md +0 -120
  14. package/.agents/skills/propagate-core-release/SKILL.md +0 -205
  15. package/.agents/skills/propagate-core-release/agents/openai.yaml +0 -7
  16. package/.agents/skills/propagate-core-release/references/downstreams.md +0 -42
  17. package/.agents/skills/ship-branch/SKILL.md +0 -105
  18. package/.agents/skills/submit-branch/SKILL.md +0 -76
  19. package/.agents/skills/validate-branch/SKILL.md +0 -72
  20. package/.claude/commands/README.md +0 -162
  21. package/.claude/commands/analyze.md +0 -101
  22. package/.claude/commands/clarify.md +0 -158
  23. package/.claude/commands/code-review.md +0 -322
  24. package/.claude/commands/constitution.md +0 -73
  25. package/.claude/commands/create-docs.md +0 -309
  26. package/.claude/commands/full-context.md +0 -121
  27. package/.claude/commands/gemini-consult.md +0 -164
  28. package/.claude/commands/handoff.md +0 -146
  29. package/.claude/commands/implement.md +0 -56
  30. package/.claude/commands/plan.md +0 -43
  31. package/.claude/commands/refactor.md +0 -188
  32. package/.claude/commands/specify.md +0 -21
  33. package/.claude/commands/tasks.md +0 -62
  34. package/.claude/commands/update-docs.md +0 -314
  35. package/.claude/hooks/README.md +0 -270
  36. package/.claude/hooks/config/sensitive-patterns.json +0 -86
  37. package/.claude/hooks/gemini-context-injector.sh +0 -129
  38. package/.claude/hooks/mcp-security-scan.sh +0 -147
  39. package/.claude/hooks/notify.sh +0 -103
  40. package/.claude/hooks/setup/hook-setup.md +0 -96
  41. package/.claude/hooks/setup/settings.json.template +0 -63
  42. package/.claude/hooks/sounds/complete.wav +0 -0
  43. package/.claude/hooks/sounds/input-needed.wav +0 -0
  44. package/.claude/hooks/subagent-context-injector.sh +0 -65
  45. package/.claude/skills/babysit-pr/SKILL.md +0 -223
  46. package/.claude/skills/babysit-pr/agents/openai.yaml +0 -7
  47. package/.claude/skills/dia-scoring/SKILL.md +0 -139
  48. package/.claude/skills/dia-scoring/agents/openai.yaml +0 -7
  49. package/.claude/skills/dia-scoring/references/selectors-and-keys.md +0 -253
  50. package/.claude/skills/emoji-eval/SKILL.md +0 -187
  51. package/.claude/skills/land-pr/SKILL.md +0 -120
  52. package/.claude/skills/propagate-core-release/SKILL.md +0 -205
  53. package/.claude/skills/propagate-core-release/agents/openai.yaml +0 -7
  54. package/.claude/skills/propagate-core-release/references/downstreams.md +0 -42
  55. package/.claude/skills/ship-branch/SKILL.md +0 -105
  56. package/.claude/skills/submit-branch/SKILL.md +0 -76
  57. package/.claude/skills/validate-branch/SKILL.md +0 -72
  58. package/.claude/skills/zenuml-ux-research/SKILL.md +0 -183
  59. package/.claude/skills/zenuml-ux-research/references/assertion-catalog.md +0 -261
  60. package/.claude/skills/zenuml-ux-research/references/best-practices-overview.md +0 -56
  61. package/.claude/skills/zenuml-ux-research/references/report-template.md +0 -89
  62. package/.claude/skills/zenuml-ux-research/references/scenarios/edit-message-label.md +0 -37
  63. package/.claude/skills/zenuml-ux-research/references/scenarios/insert-message.md +0 -36
  64. package/.claude/skills/zenuml-ux-research/references/scenarios/insert-participant.md +0 -31
  65. package/.claude/skills/zenuml-ux-research/references/scenarios/rename-participant.md +0 -33
  66. package/.claude/skills/zenuml-ux-research/references/scenarios/undo-insert.md +0 -35
  67. package/.devcontainer/devcontainer.json +0 -21
  68. package/.dockerignore +0 -19
  69. package/.eslintrc.js +0 -39
  70. package/.git-blame-ignore-revs +0 -6
  71. package/.kiro/hooks/README.md +0 -38
  72. package/.kiro/hooks/session-sound-notification.js +0 -44
  73. package/.kiro/hooks/session-sound-notification.json +0 -23
  74. package/.mcp.json.example +0 -17
  75. package/.nvmrc +0 -1
  76. package/.prettierignore +0 -4
  77. package/.prettierrc +0 -1
  78. package/.specify/memory/constitution.md +0 -33
  79. package/.specify/scripts/bash/check-prerequisites.sh +0 -166
  80. package/.specify/scripts/bash/common.sh +0 -113
  81. package/.specify/scripts/bash/create-new-feature.sh +0 -97
  82. package/.specify/scripts/bash/setup-plan.sh +0 -60
  83. package/.specify/scripts/bash/update-agent-context.sh +0 -728
  84. package/.specify/templates/agent-file-template.md +0 -23
  85. package/.specify/templates/plan-template.md +0 -219
  86. package/.specify/templates/spec-template.md +0 -116
  87. package/.specify/templates/tasks-template.md +0 -127
  88. package/.storybook/main.ts +0 -25
  89. package/.storybook/preview.ts +0 -29
  90. package/.watchmanconfig +0 -3
  91. package/AGENTS.md +0 -26
  92. package/CLAUDE.md +0 -124
  93. package/DEPLOYMENT.md +0 -62
  94. package/Dockerfile +0 -36
  95. package/IMPLEMENTATION_PLAN.md +0 -163
  96. package/Integration/vanilla-js/index.html +0 -42
  97. package/MCP-ASSISTANT-RULES.md +0 -85
  98. package/README_CN.md +0 -15
  99. package/TUTORIAL.md +0 -116
  100. package/antlr/antlr-4.11.1-complete.jar +0 -0
  101. package/bun.lock +0 -1544
  102. package/bunfig.toml +0 -52
  103. package/docs/UNICODE_SUPPORT.md +0 -179
  104. package/docs/ai-context/deployment-infrastructure.md +0 -21
  105. package/docs/ai-context/docs-overview.md +0 -89
  106. package/docs/ai-context/handoff.md +0 -174
  107. package/docs/ai-context/project-structure.md +0 -160
  108. package/docs/ai-context/system-integration.md +0 -21
  109. package/docs/asciidoc/contributor.adoc +0 -54
  110. package/docs/asciidoc/create-my-own-theme.adoc +0 -149
  111. package/docs/asciidoc/images/creation-component.png +0 -0
  112. package/docs/asciidoc/images/creation-rtl.png +0 -0
  113. package/docs/asciidoc/images/message-arrow-rtl.png +0 -0
  114. package/docs/asciidoc/images/occurrence.png +0 -0
  115. package/docs/asciidoc/images/return-message-conflict.png +0 -0
  116. package/docs/asciidoc/images/shift-up-half-the-height.png +0 -0
  117. package/docs/asciidoc/images/three-layer-info-arch.png +0 -0
  118. package/docs/asciidoc/images/vertical-alignment.svg +0 -1
  119. package/docs/asciidoc/images/vertically-aligning.png +0 -0
  120. package/docs/asciidoc/index.adoc +0 -277
  121. package/docs/asciidoc/theme-debug-web-app.png +0 -0
  122. package/docs/asciidoc/tutorial.adoc +0 -22
  123. package/docs/asciidoc/user-css.png +0 -0
  124. package/docs/async-vs-sync-parser-rules.md +0 -81
  125. package/docs/divider-parser-allow-spaces.md +0 -38
  126. package/docs/highlighting-messages.md +0 -52
  127. package/docs/images/editor-sample.png +0 -0
  128. package/docs/inherited-vs-provided-from.md +0 -64
  129. package/docs/parser/Assignment.md +0 -8
  130. package/docs/parser/PARSER_IMPROVEMENTS_CC.md +0 -425
  131. package/docs/parser/grammar_review_gemini.md +0 -116
  132. package/docs/participants-function.md +0 -25
  133. package/docs/responsive-participant-margin.md +0 -52
  134. package/docs/starter.md +0 -9
  135. package/docs/superpowers/plans/2026-03-27-e2e-test-reorg.md +0 -698
  136. package/docs/superpowers/plans/2026-03-30-emoji-support.md +0 -1220
  137. package/docs/superpowers/plans/2026-03-30-self-correcting-scoring.md +0 -206
  138. package/docs/superpowers/plans/2026-04-15-keyboard-editing-on-diagram.md +0 -1992
  139. package/docs/superpowers/plans/2026-04-15-zenuml-ux-research-skill.md +0 -1452
  140. package/docs/ux-research/.gitkeep +0 -0
  141. package/docs/ux-research/2026-04-15-rename-participant.md +0 -156
  142. package/docs/ux-research/2026-04-18-insert-participant.md +0 -151
  143. package/docs/width-translate-and-offsets.md +0 -62
  144. package/docs/xss.md +0 -59
  145. package/e2e/data/compare-cases.js +0 -1090
  146. package/e2e/data/diff-algorithm.js +0 -199
  147. package/e2e/fixtures/create-message.html +0 -26
  148. package/e2e/fixtures/editable-label.html +0 -35
  149. package/e2e/fixtures/editable-span.html +0 -122
  150. package/e2e/fixtures/empty-diagram.html +0 -23
  151. package/e2e/fixtures/fixture.html +0 -31
  152. package/e2e/fixtures/insert-participant.html +0 -23
  153. package/e2e/fixtures/reorder-cross-fragment.html +0 -31
  154. package/e2e/fixtures/reorder-fragment.html +0 -29
  155. package/e2e/fixtures/reorder-message.html +0 -27
  156. package/e2e/fixtures/svg-test.html +0 -21
  157. package/e2e/fixtures/type-switch.html +0 -29
  158. package/e2e/tools/canonical-history.html +0 -908
  159. package/e2e/tools/compare-case.html +0 -371
  160. package/e2e/tools/compare.html +0 -35
  161. package/e2e/tools/native-diff-ext/background.js +0 -60
  162. package/e2e/tools/native-diff-ext/bridge.js +0 -26
  163. package/e2e/tools/native-diff-ext/content.js +0 -194
  164. package/e2e/tools/svg-preview.html +0 -56
  165. package/embed.html +0 -193
  166. package/eslint.config.mjs +0 -35
  167. package/firebase-debug.log +0 -108
  168. package/iframe-container-demo/diagram.html +0 -124
  169. package/iframe-container-demo/host.html +0 -817
  170. package/index.html +0 -771
  171. package/mermaid-zenuml-async-spa-auth.png +0 -0
  172. package/mermaid-zenuml-async-spa-auth.snapshot.md +0 -96
  173. package/newsletter/unicode-support-announcement.md +0 -134
  174. package/playground/creation.html +0 -53
  175. package/playground/message.html +0 -63
  176. package/playwright.config.ts +0 -40
  177. package/renderer.html +0 -366
  178. package/scripts/analyze-compare-case/collect-data.mjs +0 -1134
  179. package/scripts/analyze-compare-case/config.mjs +0 -102
  180. package/scripts/analyze-compare-case/geometry.mjs +0 -101
  181. package/scripts/analyze-compare-case/native-diff.mjs +0 -224
  182. package/scripts/analyze-compare-case/output.mjs +0 -74
  183. package/scripts/analyze-compare-case/panel-diff.mjs +0 -114
  184. package/scripts/analyze-compare-case/report.mjs +0 -162
  185. package/scripts/analyze-compare-case/residual-scopes.mjs +0 -347
  186. package/scripts/analyze-compare-case/scoring.mjs +0 -829
  187. package/scripts/analyze-compare-case.mjs +0 -149
  188. package/scripts/bump-version.js +0 -117
  189. package/scripts/snapshot-dual.js +0 -173
  190. package/scripts/update-snapshots.js +0 -70
  191. package/skills/dia-scoring/SKILL.md +0 -129
  192. package/skills/dia-scoring/agents/openai.yaml +0 -7
  193. package/skills/dia-scoring/references/selectors-and-keys.md +0 -253
  194. package/tailwind.config.js +0 -126
  195. package/test-compression.html +0 -274
  196. package/test-mermaid-zenuml.html +0 -57
  197. package/test-setup.ts +0 -124
  198. package/test-url-params.html +0 -192
  199. package/tsconfig.app.json +0 -31
  200. package/tsconfig.node.json +0 -24
  201. package/tsconfig.test.json +0 -9
  202. package/vite.config.lib.ts +0 -93
  203. package/vite.config.ts +0 -84
  204. package/wrangler.toml +0 -18
package/index.html DELETED
@@ -1,771 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <!-- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> -->
8
- <!-- <link
9
- rel="preload stylesheet"
10
- as="style"
11
- href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap"
12
- /> -->
13
- <style id="zenumlstyle">
14
- /* Custom styles for the diagram */
15
- </style>
16
- <link
17
- rel="stylesheet"
18
- href="/vendor/highlightjs/github-dark.min.css"
19
- />
20
- <script src="/vendor/codemirror/codemirror.min.js"></script>
21
- <link
22
- rel="stylesheet"
23
- href="/vendor/codemirror/codemirror.min.css"
24
- />
25
- <link
26
- rel="stylesheet"
27
- href="/vendor/codemirror/material-darker.min.css"
28
- />
29
- <title>ZenUML Dev Workbench</title>
30
- <style>
31
- :root {
32
- --bg: #0f172a;
33
- --bg-alt: #111827;
34
- --panel: #ffffff;
35
- --panel-alt: #f8fafc;
36
- --panel-muted: #eef2f7;
37
- --ink: #0f172a;
38
- --muted: #526072;
39
- --line: #d7deea;
40
- --line-strong: #c4cedd;
41
- --accent: #0f766e;
42
- --accent-strong: #115e59;
43
- --danger: #991b1b;
44
- --shadow: 0 18px 48px rgba(15, 23, 42, 0.14);
45
- --radius-lg: 14px;
46
- --radius-md: 10px;
47
- --editor-width: 420px;
48
- }
49
-
50
- * {
51
- box-sizing: border-box;
52
- }
53
-
54
- html,
55
- body {
56
- margin: 0;
57
- min-height: 100%;
58
- }
59
-
60
- body {
61
- font-family:
62
- "SF Pro Text",
63
- "Segoe UI",
64
- system-ui,
65
- sans-serif;
66
- color: var(--ink);
67
- background: linear-gradient(180deg, var(--bg) 0%, var(--bg-alt) 100%);
68
- }
69
-
70
- a {
71
- color: inherit;
72
- }
73
-
74
- code,
75
- .CodeMirror,
76
- .tool-chip,
77
- .tool-button,
78
- .tool-link,
79
- .stats-text,
80
- .toolbar-label {
81
- font-family:
82
- "IBM Plex Mono",
83
- "SFMono-Regular",
84
- "Menlo",
85
- "Monaco",
86
- "Consolas",
87
- monospace;
88
- }
89
-
90
- .app-shell {
91
- min-height: 100vh;
92
- display: grid;
93
- grid-template-rows: auto 1fr;
94
- gap: 12px;
95
- padding: 14px;
96
- }
97
-
98
- .toolbar {
99
- display: grid;
100
- grid-template-columns: minmax(0, 1fr) auto;
101
- align-items: center;
102
- gap: 16px;
103
- padding: 12px 14px;
104
- border: 1px solid rgba(255, 255, 255, 0.08);
105
- border-radius: var(--radius-lg);
106
- background: rgba(15, 23, 42, 0.9);
107
- color: #e5edf8;
108
- box-shadow: var(--shadow);
109
- }
110
-
111
- .toolbar-title {
112
- display: flex;
113
- flex-wrap: wrap;
114
- align-items: baseline;
115
- gap: 12px;
116
- }
117
-
118
- .toolbar-title strong {
119
- font-size: 15px;
120
- font-weight: 700;
121
- letter-spacing: 0.01em;
122
- }
123
-
124
- .toolbar-title span {
125
- color: #9fb1c7;
126
- font-size: 12px;
127
- }
128
-
129
- .toolbar-actions {
130
- display: flex;
131
- align-items: center;
132
- justify-content: flex-end;
133
- flex-wrap: wrap;
134
- gap: 8px;
135
- }
136
-
137
- .toolbar-label {
138
- color: #9fb1c7;
139
- font-size: 11px;
140
- letter-spacing: 0.08em;
141
- text-transform: uppercase;
142
- }
143
-
144
- .workspace {
145
- min-height: 0;
146
- display: grid;
147
- grid-template-columns: minmax(280px, var(--editor-width)) 10px minmax(320px, 1fr) minmax(320px, 1fr);
148
- gap: 12px;
149
- align-items: stretch;
150
- }
151
-
152
- .panel {
153
- display: flex;
154
- flex-direction: column;
155
- min-height: 0;
156
- min-width: 0;
157
- overflow: hidden;
158
- border-radius: var(--radius-lg);
159
- border: 1px solid var(--line);
160
- background: var(--panel);
161
- box-shadow: var(--shadow);
162
- }
163
-
164
- .workspace-resizer {
165
- position: relative;
166
- min-height: 0;
167
- border-radius: 999px;
168
- background: rgba(148, 163, 184, 0.28);
169
- cursor: col-resize;
170
- touch-action: none;
171
- }
172
-
173
- .workspace-resizer::before {
174
- content: "";
175
- position: absolute;
176
- inset: 0;
177
- margin: auto;
178
- width: 4px;
179
- height: 56px;
180
- border-radius: 999px;
181
- background: rgba(15, 118, 110, 0.22);
182
- }
183
-
184
- .workspace-resizer:hover,
185
- .workspace.is-resizing .workspace-resizer {
186
- background: rgba(15, 118, 110, 0.2);
187
- }
188
-
189
- .workspace.is-resizing {
190
- user-select: none;
191
- }
192
-
193
- .panel-header {
194
- display: flex;
195
- align-items: center;
196
- justify-content: space-between;
197
- gap: 14px;
198
- padding: 12px 14px;
199
- border-bottom: 1px solid var(--line);
200
- background: var(--panel-alt);
201
- }
202
-
203
- .panel-title {
204
- display: flex;
205
- flex-direction: column;
206
- gap: 4px;
207
- }
208
-
209
- .panel-title h2,
210
- .panel-title h3 {
211
- margin: 0;
212
- font-size: 14px;
213
- letter-spacing: 0.01em;
214
- }
215
-
216
- .panel-title p {
217
- margin: 0;
218
- color: var(--muted);
219
- font-size: 12px;
220
- line-height: 1.3;
221
- }
222
-
223
- .panel-actions {
224
- display: flex;
225
- align-items: center;
226
- flex-wrap: wrap;
227
- justify-content: flex-end;
228
- gap: 8px;
229
- }
230
-
231
- .tool-button,
232
- .tool-chip,
233
- .tool-link {
234
- display: inline-flex;
235
- align-items: center;
236
- justify-content: center;
237
- appearance: none;
238
- border: 1px solid var(--line);
239
- border-radius: 8px;
240
- padding: 8px 10px;
241
- background: #fff;
242
- color: var(--ink);
243
- cursor: pointer;
244
- text-decoration: none;
245
- transition:
246
- border-color 160ms ease,
247
- background 160ms ease;
248
- font-size: 11px;
249
- letter-spacing: 0.03em;
250
- white-space: nowrap;
251
- }
252
-
253
- .tool-button:hover,
254
- .tool-chip:hover,
255
- .tool-link:hover {
256
- border-color: var(--line-strong);
257
- background: var(--panel-muted);
258
- }
259
-
260
- .toolbar .tool-chip,
261
- .toolbar .tool-link {
262
- background: rgba(15, 23, 42, 0.55);
263
- border-color: rgba(159, 177, 199, 0.25);
264
- color: #e5edf8;
265
- }
266
-
267
- .toolbar .tool-chip:hover,
268
- .toolbar .tool-link:hover {
269
- background: rgba(30, 41, 59, 0.95);
270
- border-color: rgba(191, 209, 230, 0.4);
271
- }
272
-
273
- .tool-chip.is-active {
274
- background: var(--accent);
275
- border-color: var(--accent-strong);
276
- color: #f8fffe;
277
- }
278
-
279
- .tool-button.primary {
280
- background: var(--accent);
281
- border-color: var(--accent-strong);
282
- color: #f8fffe;
283
- }
284
-
285
- .panel-body {
286
- flex: 1;
287
- min-height: 0;
288
- }
289
-
290
- .editor-body {
291
- background: #1d1d1b;
292
- }
293
-
294
- .CodeMirror {
295
- font-size: 14px;
296
- height: 100%;
297
- overflow: hidden;
298
- }
299
-
300
- .CodeMirror-scroll {
301
- padding: 1rem;
302
- }
303
-
304
- .zenuml .CodeMirror .CodeMirror-cursor {
305
- border-color: #fff;
306
- border-left-width: 2px;
307
- }
308
-
309
- .preview-surface {
310
- height: 100%;
311
- overflow: auto;
312
- padding: 12px;
313
- background: var(--panel-muted);
314
- }
315
-
316
- .html-surface {
317
- position: relative;
318
- }
319
-
320
- .preview-stage {
321
- min-height: 100%;
322
- padding: 10px;
323
- border-radius: var(--radius-md);
324
- border: 1px solid var(--line);
325
- background: #fff;
326
- }
327
-
328
- .preview-stage pre {
329
- margin: 0;
330
- }
331
-
332
- .preview-stage svg {
333
- display: block;
334
- }
335
-
336
- .svg-stage {
337
- display: block;
338
- }
339
-
340
- #svg-container {
341
- width: max-content;
342
- margin: 0 auto;
343
- min-width: 100%;
344
- min-height: 100%;
345
- display: grid;
346
- place-items: center;
347
- }
348
-
349
- #svg-container svg {
350
- display: block;
351
- box-shadow: 0 10px 28px rgba(15, 23, 42, 0.08);
352
- }
353
-
354
- .stats-text {
355
- color: #9fb1c7;
356
- font-size: 11px;
357
- }
358
-
359
- .svg-error {
360
- display: grid;
361
- place-items: center;
362
- min-height: 240px;
363
- padding: 20px;
364
- border-radius: var(--radius-md);
365
- border: 1px dashed #d4b4b4;
366
- color: var(--danger);
367
- background: #fff7f7;
368
- text-align: center;
369
- line-height: 1.6;
370
- }
371
-
372
- .workspace.mode-svg,
373
- .workspace.mode-dom {
374
- grid-template-columns: minmax(280px, var(--editor-width)) 10px minmax(720px, 1fr);
375
- }
376
-
377
- .workspace.mode-svg .html-panel,
378
- .workspace.mode-dom .svg-panel {
379
- display: none;
380
- }
381
-
382
- @media (max-width: 1440px) {
383
- .workspace,
384
- .workspace.mode-svg,
385
- .workspace.mode-dom {
386
- grid-template-columns: minmax(280px, var(--editor-width)) 10px minmax(320px, 1fr);
387
- }
388
-
389
- .workspace.mode-split .svg-panel {
390
- grid-column: 3;
391
- }
392
- }
393
-
394
- @media (max-width: 1024px) {
395
- .app-shell {
396
- padding: 10px;
397
- }
398
-
399
- .toolbar {
400
- grid-template-columns: 1fr;
401
- align-items: start;
402
- }
403
-
404
- .workspace,
405
- .workspace.mode-svg,
406
- .workspace.mode-dom {
407
- grid-template-columns: 1fr;
408
- }
409
-
410
- .workspace-resizer {
411
- display: none;
412
- }
413
-
414
- .workspace.mode-split .svg-panel {
415
- grid-column: auto;
416
- }
417
-
418
- .panel {
419
- min-height: 360px;
420
- }
421
- }
422
- </style>
423
- <script src="/vendor/tailwindcss/tailwindcss.js"></script>
424
- </head>
425
- <body>
426
- <div class="app-shell">
427
- <header class="toolbar">
428
- <div class="toolbar-title">
429
- <strong>ZenUML Dev Workbench</strong>
430
- <span>default to native SVG, switch to DOM or split only when needed</span>
431
- </div>
432
- <div class="toolbar-actions">
433
- <span class="toolbar-label">View</span>
434
- <button id="view-svg" class="tool-chip">SVG</button>
435
- <button id="view-dom" class="tool-chip">DOM</button>
436
- <button id="view-split" class="tool-chip">Split</button>
437
- <span class="toolbar-label">Editing</span>
438
- <button class="tool-chip" data-flag="enableParticipantInsertion" title="Toggle ParticipantInsertControls (+ between participants)">+ Participant</button>
439
- <button class="tool-chip" data-flag="enableMessageInsertion" title="Toggle Occurrence drag-to-create + GapHandleZone message handles">+ Message</button>
440
- <button class="tool-chip" data-flag="enableDividerInsertion" title="Toggle GapHandleZone divider button">+ Divider</button>
441
- <button class="tool-chip" data-flag="enableParticipantStyleEditing" title="Toggle ParticipantStylePanel (color/type)">Style Participant</button>
442
- <button id="width-provider-toggle" class="tool-chip"></button>
443
- <span id="svg-stats" class="stats-text">SVG: waiting</span>
444
- <a class="tool-link" href="/e2e/tools/compare.html" target="_blank" rel="noreferrer">
445
- Compare Cases
446
- </a>
447
- <a class="tool-link" href="/e2e/tools/svg-preview.html" target="_blank" rel="noreferrer">
448
- SVG Only
449
- </a>
450
- </div>
451
- </header>
452
-
453
- <main class="workspace mode-svg" id="workspace">
454
- <article class="panel editor-panel">
455
- <div class="panel-header">
456
- <div class="panel-title">
457
- <h2>Editor</h2>
458
- <p>Persisted in <code>localStorage</code>.</p>
459
- </div>
460
- <div class="panel-actions">
461
- <button onclick="loadExample('basic')" class="tool-button">Basic</button>
462
- <button onclick="loadExample('advanced')" class="tool-button">Advanced</button>
463
- <button onclick="clearEditor()" class="tool-button">Clear</button>
464
- <button onclick="exportDiagram()" class="tool-button primary">Export PNG</button>
465
- </div>
466
- </div>
467
- <div class="panel-body editor-body">
468
- <textarea id="text" style="display: none"></textarea>
469
- </div>
470
- </article>
471
-
472
- <div
473
- id="editor-resizer"
474
- class="workspace-resizer"
475
- role="separator"
476
- aria-orientation="vertical"
477
- aria-label="Resize editor"
478
- ></div>
479
-
480
- <article class="panel html-panel">
481
- <div class="panel-header">
482
- <div class="panel-title">
483
- <h3>DOM preview</h3>
484
- <p><code>window.zenUml.render()</code> output.</p>
485
- </div>
486
- </div>
487
- <div class="panel-body preview-surface html-surface">
488
- <div class="preview-stage">
489
- <pre class="zenuml"></pre>
490
- </div>
491
- </div>
492
- </article>
493
-
494
- <article class="panel svg-panel">
495
- <div class="panel-header">
496
- <div class="panel-title">
497
- <h3>Native SVG preview</h3>
498
- <p><code>renderToSvg()</code> output.</p>
499
- </div>
500
- </div>
501
- <div class="panel-body preview-surface svg-surface">
502
- <div class="preview-stage svg-stage">
503
- <div id="svg-container"></div>
504
- </div>
505
- </div>
506
- </article>
507
- </main>
508
- </div>
509
-
510
- <script type="module">
511
- import { waitUntil, debounce } from "./src/utils.ts";
512
- import { createConfig } from "./src/config.ts";
513
- import { toPng } from "html-to-image";
514
- import { renderToSvg } from "./src/svg/renderToSvg.ts";
515
-
516
- const editor = CodeMirror.fromTextArea(document.getElementById("text"), {
517
- lineNumbers: true,
518
- singleCursorHeightPerLine: false,
519
- theme: "material-darker",
520
- mode: "text/plain",
521
- autofocus: true,
522
- });
523
-
524
- const svgContainer = document.getElementById("svg-container");
525
- const svgStats = document.getElementById("svg-stats");
526
- const workspace = document.getElementById("workspace");
527
- const editorResizer = document.getElementById("editor-resizer");
528
- const viewButtons = {
529
- svg: document.getElementById("view-svg"),
530
- dom: document.getElementById("view-dom"),
531
- split: document.getElementById("view-split"),
532
- };
533
- const minEditorWidth = 280;
534
-
535
- function clampEditorWidth(nextWidth) {
536
- const maxEditorWidth = Math.max(minEditorWidth, Math.floor(window.innerWidth * 0.72));
537
- return Math.min(Math.max(nextWidth, minEditorWidth), maxEditorWidth);
538
- }
539
-
540
- function setEditorWidth(nextWidth) {
541
- const clampedWidth = clampEditorWidth(nextWidth);
542
- document.documentElement.style.setProperty("--editor-width", `${clampedWidth}px`);
543
- localStorage.setItem("zenuml-workbench-editor-width", String(clampedWidth));
544
- }
545
-
546
- function setViewMode(mode) {
547
- const validMode = ["svg", "dom", "split"].includes(mode) ? mode : "svg";
548
- workspace.classList.remove("mode-svg", "mode-dom", "mode-split");
549
- workspace.classList.add(`mode-${validMode}`);
550
-
551
- Object.entries(viewButtons).forEach(([key, button]) => {
552
- button.classList.toggle("is-active", key === validMode);
553
- });
554
-
555
- localStorage.setItem("zenuml-workbench-view", validMode);
556
- }
557
-
558
- const FLAG_KEYS = [
559
- "enableParticipantInsertion",
560
- "enableMessageInsertion",
561
- "enableDividerInsertion",
562
- "enableParticipantStyleEditing",
563
- ];
564
- const FLAG_STORAGE_PREFIX = "zenuml-workbench-flag-";
565
-
566
- function readFlag(key) {
567
- const stored = localStorage.getItem(FLAG_STORAGE_PREFIX + key);
568
- // Default ON in the workbench so dev experience matches main.tsx.
569
- return stored === null ? true : stored === "true";
570
- }
571
-
572
- function writeFlag(key, value) {
573
- localStorage.setItem(FLAG_STORAGE_PREFIX + key, String(value));
574
- }
575
-
576
- function readFlags() {
577
- return Object.fromEntries(FLAG_KEYS.map((k) => [k, readFlag(k)]));
578
- }
579
-
580
- function syncFlagButtons() {
581
- document.querySelectorAll("[data-flag]").forEach((btn) => {
582
- btn.classList.toggle("is-active", readFlag(btn.dataset.flag));
583
- });
584
- }
585
-
586
- const updateHtmlPreview = debounce((content) => {
587
- const config = createConfig({
588
- ...readFlags(),
589
- onContentChange: (code) => editor.setValue(code),
590
- });
591
-
592
- window.zenUml.render(content, config).then((r) => {
593
- window.parentLogger
594
- .child({ name: "index.html" })
595
- .debug("render resolved", r);
596
- });
597
- }, 400);
598
-
599
- document.querySelectorAll("[data-flag]").forEach((btn) => {
600
- btn.addEventListener("click", () => {
601
- const key = btn.dataset.flag;
602
- writeFlag(key, !readFlag(key));
603
- syncFlagButtons();
604
- updateHtmlPreview(editor.getValue());
605
- });
606
- });
607
- syncFlagButtons();
608
-
609
- const updateSvgPreview = debounce((content) => {
610
- try {
611
- const t0 = performance.now();
612
- const result = renderToSvg(content);
613
- const dt = (performance.now() - t0).toFixed(1);
614
-
615
- if (!result.svg || result.width === 0 || result.height === 0) {
616
- svgContainer.innerHTML = `
617
- <div class="svg-error">
618
- Native SVG output is empty for the current input.
619
- </div>
620
- `;
621
- svgStats.textContent = "SVG: empty";
622
- return;
623
- }
624
-
625
- svgContainer.innerHTML = result.svg;
626
- svgStats.textContent = `SVG ${result.width}x${result.height} | ${dt}ms`;
627
- } catch (error) {
628
- console.error("Failed to render native SVG preview:", error);
629
- svgContainer.innerHTML = `
630
- <div class="svg-error">
631
- Native SVG preview failed. Check the console for details.
632
- </div>
633
- `;
634
- svgStats.textContent = "SVG: error";
635
- }
636
- }, 180);
637
-
638
- Object.entries(viewButtons).forEach(([mode, button]) => {
639
- button.addEventListener("click", () => setViewMode(mode));
640
- });
641
-
642
- editorResizer.addEventListener("pointerdown", (event) => {
643
- if (window.innerWidth <= 1024) {
644
- return;
645
- }
646
-
647
- event.preventDefault();
648
- workspace.classList.add("is-resizing");
649
- editorResizer.setPointerCapture(event.pointerId);
650
-
651
- const onPointerMove = (moveEvent) => {
652
- setEditorWidth(moveEvent.clientX - workspace.getBoundingClientRect().left);
653
- };
654
-
655
- const stopResize = () => {
656
- workspace.classList.remove("is-resizing");
657
- editorResizer.removeEventListener("pointermove", onPointerMove);
658
- editorResizer.removeEventListener("pointerup", stopResize);
659
- editorResizer.removeEventListener("pointercancel", stopResize);
660
- };
661
-
662
- editorResizer.addEventListener("pointermove", onPointerMove);
663
- editorResizer.addEventListener("pointerup", stopResize);
664
- editorResizer.addEventListener("pointercancel", stopResize);
665
- });
666
-
667
- window.addEventListener("resize", () => {
668
- const savedWidth = Number(localStorage.getItem("zenuml-workbench-editor-width"));
669
- if (savedWidth) {
670
- setEditorWidth(savedWidth);
671
- }
672
- });
673
-
674
- editor.on("change", function (cm) {
675
- const content = cm.getValue();
676
- updateSvgPreview(content);
677
-
678
- waitUntil(
679
- () => window.zenUml,
680
- () => {
681
- updateHtmlPreview(content);
682
- // Save to localStorage
683
- localStorage.setItem("zenuml-cm-code", content);
684
- },
685
- );
686
- });
687
-
688
- // Example data
689
- const examples = {
690
- basic: `Alice -> Bob: Hello Bob!
691
- Bob -> Alice: Hello Alice!`,
692
- advanced: `title Online Shopping
693
- participant Customer
694
- participant WebApp
695
- participant PaymentService
696
- participant Database
697
-
698
- Customer -> WebApp: Browse products
699
- WebApp -> Database: Query products
700
- Database --> WebApp: Return products
701
- WebApp --> Customer: Display products
702
-
703
- Customer -> WebApp: Add to cart
704
- WebApp -> Database: Update cart
705
- Database --> WebApp: Cart updated
706
- WebApp --> Customer: Show cart
707
-
708
- Customer -> WebApp: Checkout
709
- WebApp -> PaymentService: Process payment
710
- PaymentService --> WebApp: Payment confirmed
711
- WebApp -> Database: Create order
712
- Database --> WebApp: Order created
713
- WebApp --> Customer: Order confirmation`,
714
- };
715
-
716
- // Global functions
717
- window.loadExample = function (type) {
718
- editor.setValue(examples[type] || examples.basic);
719
- };
720
-
721
- window.clearEditor = function () {
722
- editor.setValue("");
723
- };
724
-
725
- window.exportDiagram = async function () {
726
- const element = document.querySelector(".zenuml");
727
- if (element) {
728
- try {
729
- const dataUrl = await toPng(element);
730
- const link = document.createElement("a");
731
- link.download = "sequence-diagram.png";
732
- link.href = dataUrl;
733
- link.click();
734
- } catch (error) {
735
- console.error("Failed to export diagram:", error);
736
- }
737
- }
738
- };
739
-
740
- // Load saved code from localStorage or default example
741
- const savedCode = localStorage.getItem("zenuml-cm-code");
742
- if (savedCode) {
743
- editor.setValue(savedCode);
744
- } else {
745
- editor.setValue(examples.basic);
746
- }
747
-
748
- const savedEditorWidth = Number(localStorage.getItem("zenuml-workbench-editor-width"));
749
- if (savedEditorWidth) {
750
- setEditorWidth(savedEditorWidth);
751
- }
752
-
753
- setViewMode(localStorage.getItem("zenuml-workbench-view") || "svg");
754
- </script>
755
- <script type="module">
756
- const params = new URLSearchParams(location.search);
757
- const wp = params.get("WIDTH_PROVIDER") || import.meta.env.VITE_WIDTH_PROVIDER || "browser";
758
- const toggle = document.getElementById("width-provider-toggle");
759
- const isCanvas = wp === "canvas";
760
- toggle.textContent = "WIDTH: " + wp;
761
- toggle.classList.toggle("is-active", isCanvas);
762
- toggle.title = "Click to switch to " + (isCanvas ? "browser" : "canvas");
763
- toggle.addEventListener("click", () => {
764
- const next = isCanvas ? "browser" : "canvas";
765
- params.set("WIDTH_PROVIDER", next);
766
- location.search = params.toString();
767
- });
768
- </script>
769
- <script type="module" src="/src/main.tsx"></script>
770
- </body>
771
- </html>