react-super-mermaid 0.3.1 â 0.4.2
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.
- package/README.md +6 -5
- package/dist/index.cjs +390 -58
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +45 -11
- package/dist/index.d.ts +45 -11
- package/dist/index.js +389 -59
- package/dist/index.js.map +1 -1
- package/llms.txt +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -166,7 +166,7 @@ gitGraph
|
|
|
166
166
|
- đ **In-diagram search** â highlight + pan to matches (`/` or `Ctrl/Cmd+F`).
|
|
167
167
|
- đī¸ **Pan & zoom** â fit, actual size, keyboard `+ - 0 1 w` (via `svg-pan-zoom`).
|
|
168
168
|
- âļ **Fullscreen modal** â open the diagram in a viewport-filling, RWD-friendly popup (`f` / `Esc`); body scroll locked, auto re-fit.
|
|
169
|
-
- âĻ **Background
|
|
169
|
+
- âĻ **Background picker** â a swatch popover to set the canvas **surface** (preset colors + a custom color well) and an independent **pattern** (none / dots / grid lines, cycle with `b`). Surface + pattern combine freely and carry through to exports.
|
|
170
170
|
- đ¤ **Export** â SVG and high-res PNG/JPEG/WebP (1Ã/2Ã/4Ã, optional transparent background).
|
|
171
171
|
- đĒļ **Lightweight & decoupled** â `mermaid`, `svg-pan-zoom`, `react` are **optional peer deps**, never bundled. No Tailwind, no app coupling.
|
|
172
172
|
- đ **Load external mermaid** â inject an instance, dynamic-import the peer, or pull from a CDN. Your bundle doesn't carry mermaid.
|
|
@@ -248,8 +248,9 @@ Resolution order is **injected â peer import â CDN**, memoized so mermaid lo
|
|
|
248
248
|
| `panZoom` | `boolean` | `true` | |
|
|
249
249
|
| `search` | `boolean` | `true` | toolbar search |
|
|
250
250
|
| `exportable` | `boolean` | `true` | toolbar SVG/PNG export |
|
|
251
|
-
| `background` | `boolean` | `true` |
|
|
252
|
-
| `
|
|
251
|
+
| `background` | `boolean` | `true` | show the background picker (surface swatches + custom color + pattern toggle) |
|
|
252
|
+
| `pattern` | `'none' \| 'dots' \| 'grid'` | `'dots'` | initial / controlled overlay pattern |
|
|
253
|
+
| `solidColor` | `string \| null` | `null` (transparent) | initial / controlled canvas surface color (hex); `null` follows the page |
|
|
253
254
|
| `fullscreen` | `boolean` | `true` | toolbar fullscreen button â opens a viewport-filling modal (RWD) |
|
|
254
255
|
| `onFullscreenChange` | `(fullscreen: boolean) => void` | â | fired on enter / exit fullscreen |
|
|
255
256
|
| `keyboard` | `boolean` | `true` | shortcuts when the viewer is focused |
|
|
@@ -281,7 +282,7 @@ await ref.current?.downloadPng('diagram.png', { scale: 4 });
|
|
|
281
282
|
const svgString = ref.current?.exportSvg();
|
|
282
283
|
```
|
|
283
284
|
|
|
284
|
-
Handle: `zoomIn / zoomOut / fit / reset / actualSize / getZoomPercent / search / next / prev / clearSearch / exportSvg / exportPng / downloadSvg / downloadPng / getSvg / enterFullscreen / exitFullscreen / toggleFullscreen / isFullscreen /
|
|
285
|
+
Handle: `zoomIn / zoomOut / fit / reset / actualSize / getZoomPercent / search / next / prev / clearSearch / exportSvg / exportPng / downloadSvg / downloadPng / getSvg / enterFullscreen / exitFullscreen / toggleFullscreen / isFullscreen / setPattern / cyclePattern / getPattern / setSolidColor / getSolidColor`.
|
|
285
286
|
|
|
286
287
|
## Themes & the sketch font
|
|
287
288
|
|
|
@@ -307,7 +308,7 @@ Styles are injected automatically (`injectStyles` default `true`) â no CSS imp
|
|
|
307
308
|
|
|
308
309
|
## Keyboard shortcuts
|
|
309
310
|
|
|
310
|
-
Focus the viewer, then: `/` or `Ctrl/Cmd+F` search ¡ `+`/`-` zoom ¡ `0` fit ¡ `1` actual size ¡ `w` fit width ¡ `f` toggle fullscreen ¡ `b` cycle background ¡ `Esc` close search / exit fullscreen.
|
|
311
|
+
Focus the viewer, then: `/` or `Ctrl/Cmd+F` search ¡ `+`/`-` zoom ¡ `0` fit ¡ `1` actual size ¡ `w` fit width ¡ `f` toggle fullscreen ¡ `b` cycle background pattern (none / dots / grid) ¡ `Esc` close search / exit fullscreen.
|
|
311
312
|
|
|
312
313
|
## Next.js / SSR
|
|
313
314
|
|
package/dist/index.cjs
CHANGED
|
@@ -107,8 +107,13 @@ var RSM_CSS = `
|
|
|
107
107
|
--rsm-accent: #2563eb;
|
|
108
108
|
--rsm-hover: #f3f4f6;
|
|
109
109
|
--rsm-surface: #ffffff;
|
|
110
|
+
/* --rsm-paper = \u756B\u5E03\u5E95\u8272,\u5C0D\u9F4A VS Code \u64F4\u5145\u5957\u4EF6\u7684 editor-background(\u4EAE)\u3002 */
|
|
111
|
+
--rsm-paper: #ffffff;
|
|
110
112
|
--rsm-canvas-bg: transparent;
|
|
111
|
-
|
|
113
|
+
/* \u9EDE\u9663\u683C\u7DDA:\u5C0D\u9F4A VS Code \u7684 color-mix(foreground 9%) \u516C\u5F0F\u3002 */
|
|
114
|
+
--rsm-grid-dot: color-mix(in srgb, var(--rsm-fg) 9%, transparent);
|
|
115
|
+
/* \u7DB2\u683C\u7DDA:\u6BD4\u7DB2\u9EDE\u518D\u6DE1\u4E00\u9EDE,\u907F\u514D\u7DDA\u689D\u6436\u904E\u5716\u8868\u3002 */
|
|
116
|
+
--rsm-grid-line: color-mix(in srgb, var(--rsm-fg) 7%, transparent);
|
|
112
117
|
--rsm-radius: 8px;
|
|
113
118
|
display: flex;
|
|
114
119
|
flex-direction: column;
|
|
@@ -170,6 +175,14 @@ var RSM_CSS = `
|
|
|
170
175
|
}
|
|
171
176
|
.rsm-btn:disabled { opacity: 0.6; cursor: default; }
|
|
172
177
|
|
|
178
|
+
/* \u5DE5\u5177\u5217\u63A7\u5236\u9805\u9AD8\u5EA6\u4E00\u81F4(\u6A23\u5F0F\u4E0B\u62C9 / \u4E00\u822C\u9215 / \u7E2E\u653E\u7FA4 / \u80CC\u666F\u9215),\u907F\u514D\u9AD8\u4F4E\u4E0D\u9F4A\u3002 */
|
|
179
|
+
.rsm-toolbar .rsm-btn,
|
|
180
|
+
.rsm-toolbar .rsm-select,
|
|
181
|
+
.rsm-toolbar .rsm-zoom { min-height: 30px; }
|
|
182
|
+
.rsm-toolbar .rsm-btn,
|
|
183
|
+
.rsm-toolbar .rsm-select { align-items: center; }
|
|
184
|
+
.rsm-toolbar .rsm-zoom > button { display: inline-flex; align-items: center; justify-content: center; }
|
|
185
|
+
|
|
173
186
|
.rsm-zoom {
|
|
174
187
|
display: inline-flex;
|
|
175
188
|
align-items: stretch;
|
|
@@ -215,7 +228,8 @@ var RSM_CSS = `
|
|
|
215
228
|
flex: 1 1 auto;
|
|
216
229
|
min-height: 0;
|
|
217
230
|
overflow: hidden;
|
|
218
|
-
|
|
231
|
+
/* \u5E95\u8272\u7531 --rsm-canvas-bg \u63A7\u5236(\u9810\u8A2D\u900F\u660E,\u8DDF\u96A8\u9801\u9762);\u5716\u6A23\u758A\u5728\u5176\u4E0A(background-image)\u3002 */
|
|
232
|
+
background-color: var(--rsm-canvas-bg, transparent);
|
|
219
233
|
}
|
|
220
234
|
.rsm-stage { width: 100%; height: 100%; }
|
|
221
235
|
.rsm-root svg { cursor: grab; user-select: none; }
|
|
@@ -240,23 +254,172 @@ var RSM_CSS = `
|
|
|
240
254
|
.rsm-root .rsm-hit { filter: drop-shadow(0 0 5px #f59e0b) drop-shadow(0 0 1.5px #f59e0b); }
|
|
241
255
|
|
|
242
256
|
.rsm-root.rsm-dark {
|
|
243
|
-
|
|
244
|
-
--rsm-
|
|
245
|
-
--rsm-
|
|
246
|
-
--rsm-
|
|
247
|
-
--rsm-
|
|
248
|
-
--rsm-
|
|
249
|
-
--rsm-
|
|
257
|
+
/* \u6697\u8272\u9762\u677F\u5C0D\u9F4A VS Code Dark+ / Dark Modern \u7684\u4E2D\u6027\u7070(\u975E\u85CD\u8ABF)\u3002 */
|
|
258
|
+
--rsm-border: #3c3c3c;
|
|
259
|
+
--rsm-fg: #cccccc;
|
|
260
|
+
--rsm-muted: #9d9d9d;
|
|
261
|
+
--rsm-accent: #3794ff;
|
|
262
|
+
--rsm-hover: #2a2d2e;
|
|
263
|
+
--rsm-surface: #252526;
|
|
264
|
+
/* \u756B\u5E03\u5E95\u8272 = VS Code editor-background(\u6697);grid-dot \u7531 --rsm-fg 9% \u81EA\u52D5\u63A8\u5C0E\u3002 */
|
|
265
|
+
--rsm-paper: #1e1e1e;
|
|
250
266
|
}
|
|
251
267
|
|
|
252
|
-
/* \u2500\u2500 \u80CC\u666F
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
268
|
+
/* \u2500\u2500 \u80CC\u666F \u2500\u2500 \u5E95\u8272 + \u758A\u52A0\u5716\u6A23,\u5169\u8005\u7368\u7ACB\u3002
|
|
269
|
+
* \u5E95\u8272:--rsm-canvas-bg(\u7531\u8272\u7968 / \u81EA\u8A02\u8272 inline \u8986\u5BEB;\u672A\u8A2D = \u900F\u660E\u8DDF\u96A8\u9801\u9762)\u3002
|
|
270
|
+
* \u5716\u6A23:.rsm-pattern-dots(\u7DB2\u9EDE) / .rsm-pattern-grid(\u7DB2\u683C\u7DDA),\u758A\u5728\u5E95\u8272\u4E4B\u4E0A\u3002 */
|
|
271
|
+
.rsm-root.rsm-pattern-dots .rsm-canvas {
|
|
256
272
|
background-image: radial-gradient(var(--rsm-grid-dot) 1px, transparent 1px);
|
|
257
273
|
background-size: 18px 18px;
|
|
258
274
|
background-position: -9px -9px;
|
|
259
275
|
}
|
|
276
|
+
.rsm-root.rsm-pattern-grid .rsm-canvas {
|
|
277
|
+
background-image:
|
|
278
|
+
linear-gradient(to right, var(--rsm-grid-line) 1px, transparent 1px),
|
|
279
|
+
linear-gradient(to bottom, var(--rsm-grid-line) 1px, transparent 1px);
|
|
280
|
+
background-size: 22px 22px;
|
|
281
|
+
background-position: -1px -1px;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/* \u2500\u2500 \u80CC\u666F\u9078\u64C7\u5668(toolbar \u5167\u7684\u8272\u4E95\u6309\u9215 + \u5F48\u51FA\u9762\u677F)\u2500\u2500 */
|
|
285
|
+
.rsm-bg { position: relative; display: inline-flex; }
|
|
286
|
+
|
|
287
|
+
/* \u89F8\u767C\u9215\u5DE6\u5074\u7684\u300C\u8272\u4E95\u300D:\u53CD\u6620\u76EE\u524D\u5E95\u8272;\u900F\u660E / \u9810\u8A2D\u6642\u756B\u4E00\u9053\u659C\u7DDA\u8868\u793A\u300C\u4E0D\u8986\u5BEB\u300D\u3002 */
|
|
288
|
+
.rsm-bg-well {
|
|
289
|
+
width: 16px;
|
|
290
|
+
height: 16px;
|
|
291
|
+
border-radius: 4px;
|
|
292
|
+
border: 1px solid color-mix(in srgb, var(--rsm-fg) 28%, transparent);
|
|
293
|
+
background-color: var(--rsm-well-color, transparent);
|
|
294
|
+
}
|
|
295
|
+
.rsm-bg-well[data-empty="true"] {
|
|
296
|
+
background-color: var(--rsm-surface);
|
|
297
|
+
background-image: linear-gradient(
|
|
298
|
+
to top right,
|
|
299
|
+
transparent calc(50% - 1px),
|
|
300
|
+
#ef4444 calc(50% - 1px),
|
|
301
|
+
#ef4444 calc(50% + 1px),
|
|
302
|
+
transparent calc(50% + 1px)
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/* \u5F48\u51FA\u9762\u677F:\u5361\u7247\u5F0F\u3001\u8F15\u9670\u5F71\u3001\u6DE1\u5165\u3002 */
|
|
307
|
+
.rsm-bg-pop {
|
|
308
|
+
position: absolute;
|
|
309
|
+
top: calc(100% + 8px);
|
|
310
|
+
left: 0;
|
|
311
|
+
z-index: 50;
|
|
312
|
+
display: flex;
|
|
313
|
+
flex-direction: column;
|
|
314
|
+
gap: 12px;
|
|
315
|
+
padding: 12px;
|
|
316
|
+
min-width: 260px;
|
|
317
|
+
border: 1px solid var(--rsm-border);
|
|
318
|
+
border-radius: 12px;
|
|
319
|
+
background: var(--rsm-surface);
|
|
320
|
+
color: var(--rsm-fg);
|
|
321
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.16), 0 2px 6px rgba(0, 0, 0, 0.08);
|
|
322
|
+
animation: rsm-pop-in 0.13s ease-out;
|
|
323
|
+
}
|
|
324
|
+
@keyframes rsm-pop-in {
|
|
325
|
+
from { opacity: 0; transform: translateY(-5px); }
|
|
326
|
+
to { opacity: 1; transform: none; }
|
|
327
|
+
}
|
|
328
|
+
.rsm-bg-section { display: flex; flex-direction: column; gap: 8px; }
|
|
329
|
+
.rsm-bg-section-label {
|
|
330
|
+
font-size: 11px;
|
|
331
|
+
font-weight: 600;
|
|
332
|
+
letter-spacing: 0.03em;
|
|
333
|
+
color: var(--rsm-muted);
|
|
334
|
+
}
|
|
335
|
+
.rsm-bg-swatches { display: flex; flex-wrap: wrap; gap: 8px; }
|
|
336
|
+
|
|
337
|
+
/* \u8272\u7968:\u5713\u89D2\u5C0F\u65B9\u584A;\u9078\u4E2D\u52A0\u540C\u8272\u5916\u74B0\u3002 */
|
|
338
|
+
.rsm-swatch {
|
|
339
|
+
position: relative;
|
|
340
|
+
width: 26px;
|
|
341
|
+
height: 26px;
|
|
342
|
+
padding: 0;
|
|
343
|
+
border: 1px solid color-mix(in srgb, var(--rsm-fg) 16%, transparent);
|
|
344
|
+
border-radius: 7px;
|
|
345
|
+
cursor: pointer;
|
|
346
|
+
transition: transform 0.1s ease, box-shadow 0.1s ease;
|
|
347
|
+
}
|
|
348
|
+
.rsm-swatch:hover { transform: scale(1.12); }
|
|
349
|
+
.rsm-swatch:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--rsm-accent); }
|
|
350
|
+
.rsm-swatch.rsm-selected { outline: 2px solid var(--rsm-accent); outline-offset: 2px; }
|
|
351
|
+
.rsm-swatch[data-empty="true"] {
|
|
352
|
+
background-color: var(--rsm-surface);
|
|
353
|
+
background-image: linear-gradient(
|
|
354
|
+
to top right,
|
|
355
|
+
transparent calc(50% - 1px),
|
|
356
|
+
#ef4444 calc(50% - 1px),
|
|
357
|
+
#ef4444 calc(50% + 1px),
|
|
358
|
+
transparent calc(50% + 1px)
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/* \u81EA\u8A02\u8272\u7968:\u8986\u4E00\u500B\u96B1\u5F62\u7684\u539F\u751F color input,\u672A\u9078\u6642\u986F\u793A \u{1F3A8}\u3002 */
|
|
363
|
+
.rsm-swatch-custom {
|
|
364
|
+
display: inline-flex;
|
|
365
|
+
align-items: center;
|
|
366
|
+
justify-content: center;
|
|
367
|
+
overflow: hidden;
|
|
368
|
+
background:
|
|
369
|
+
conic-gradient(from 180deg, #f87171, #fbbf24, #34d399, #60a5fa, #a78bfa, #f87171);
|
|
370
|
+
}
|
|
371
|
+
.rsm-swatch-custom.rsm-has-color { background: none; }
|
|
372
|
+
.rsm-swatch-custom input[type="color"] {
|
|
373
|
+
position: absolute;
|
|
374
|
+
inset: 0;
|
|
375
|
+
width: 100%;
|
|
376
|
+
height: 100%;
|
|
377
|
+
margin: 0;
|
|
378
|
+
padding: 0;
|
|
379
|
+
border: 0;
|
|
380
|
+
opacity: 0;
|
|
381
|
+
cursor: pointer;
|
|
382
|
+
}
|
|
383
|
+
.rsm-swatch-custom-icon {
|
|
384
|
+
font-size: 12px;
|
|
385
|
+
line-height: 1;
|
|
386
|
+
pointer-events: none;
|
|
387
|
+
filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.35));
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/* \u5716\u6A23\u5207\u63DB:\u5206\u6BB5\u5F0F\u6309\u9215(\u7121 / \u7DB2\u9EDE / \u7DB2\u683C)\u3002 */
|
|
391
|
+
.rsm-seg {
|
|
392
|
+
display: inline-flex;
|
|
393
|
+
align-self: flex-start;
|
|
394
|
+
border: 1px solid var(--rsm-border);
|
|
395
|
+
border-radius: 8px;
|
|
396
|
+
overflow: hidden;
|
|
397
|
+
}
|
|
398
|
+
.rsm-seg > button {
|
|
399
|
+
flex: 1 1 0;
|
|
400
|
+
min-width: 58px;
|
|
401
|
+
display: inline-flex;
|
|
402
|
+
align-items: center;
|
|
403
|
+
justify-content: center;
|
|
404
|
+
gap: 5px;
|
|
405
|
+
border: 0;
|
|
406
|
+
background: var(--rsm-surface);
|
|
407
|
+
color: var(--rsm-fg);
|
|
408
|
+
padding: 6px 11px;
|
|
409
|
+
font-size: 12px;
|
|
410
|
+
line-height: 1.3;
|
|
411
|
+
white-space: nowrap;
|
|
412
|
+
cursor: pointer;
|
|
413
|
+
transition: background 0.1s ease, color 0.1s ease;
|
|
414
|
+
}
|
|
415
|
+
.rsm-seg > button + button { border-left: 1px solid var(--rsm-border); }
|
|
416
|
+
.rsm-seg > button:hover { background: var(--rsm-hover); }
|
|
417
|
+
.rsm-seg > button[aria-pressed="true"] {
|
|
418
|
+
background: color-mix(in srgb, var(--rsm-accent) 14%, transparent);
|
|
419
|
+
color: var(--rsm-accent);
|
|
420
|
+
font-weight: 600;
|
|
421
|
+
}
|
|
422
|
+
.rsm-seg-glyph { font-size: 13px; line-height: 1; }
|
|
260
423
|
|
|
261
424
|
/* \u2500\u2500 \u5168\u87A2\u5E55\u8DF3\u7A97 \u2500\u2500 position:fixed \u8986\u84CB\u6574\u500B\u8996\u7A97,RWD \u53CB\u5584\u3002 */
|
|
262
425
|
.rsm-root.rsm-fullscreen {
|
|
@@ -338,7 +501,11 @@ function ensureStyles() {
|
|
|
338
501
|
if (typeof document === "undefined") {
|
|
339
502
|
return;
|
|
340
503
|
}
|
|
341
|
-
|
|
504
|
+
const existing = document.getElementById(RSM_STYLE_ID);
|
|
505
|
+
if (existing) {
|
|
506
|
+
if (existing.textContent !== RSM_CSS) {
|
|
507
|
+
existing.textContent = RSM_CSS;
|
|
508
|
+
}
|
|
342
509
|
return;
|
|
343
510
|
}
|
|
344
511
|
const style = document.createElement("style");
|
|
@@ -1449,7 +1616,7 @@ async function rasterizeToBlob(prepared, opts = {}) {
|
|
|
1449
1616
|
throw new Error("\u53D6\u4E0D\u5230 Canvas 2D context\u3002");
|
|
1450
1617
|
}
|
|
1451
1618
|
if (!transparent || mime === "image/jpeg") {
|
|
1452
|
-
ctx.fillStyle = opts.background ?? (opts.dark ? "#
|
|
1619
|
+
ctx.fillStyle = opts.background ?? (opts.dark ? "#1e1e1e" : "#ffffff");
|
|
1453
1620
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
1454
1621
|
}
|
|
1455
1622
|
ctx.scale(scale, scale);
|
|
@@ -1690,11 +1857,19 @@ function useMermaidViewer(opts) {
|
|
|
1690
1857
|
getSvg
|
|
1691
1858
|
};
|
|
1692
1859
|
}
|
|
1693
|
-
var
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
}
|
|
1860
|
+
var BACKGROUND_PRESETS = [
|
|
1861
|
+
{ value: null, label: "\u9810\u8A2D / \u900F\u660E" },
|
|
1862
|
+
{ value: "#FFFFFF", label: "\u767D" },
|
|
1863
|
+
{ value: "#F3F4F6", label: "\u6DFA\u7070" },
|
|
1864
|
+
{ value: "#EFF6FF", label: "\u6DFA\u85CD" },
|
|
1865
|
+
{ value: "#FEFCE8", label: "\u6DFA\u9EC3" },
|
|
1866
|
+
{ value: "#FDF2F8", label: "\u6DFA\u73AB\u7470" }
|
|
1867
|
+
];
|
|
1868
|
+
var PATTERN_OPTIONS = [
|
|
1869
|
+
{ value: "none", glyph: "\u25A2", label: "\u7121" },
|
|
1870
|
+
{ value: "dots", glyph: "\u283F", label: "\u7DB2\u9EDE" },
|
|
1871
|
+
{ value: "grid", glyph: "\u229E", label: "\u7DB2\u683C" }
|
|
1872
|
+
];
|
|
1698
1873
|
var DEFAULT_THEME_OPTIONS = [
|
|
1699
1874
|
{ value: "colorful", label: "Colorful" },
|
|
1700
1875
|
{ value: "sketch", label: "Excalidraw" },
|
|
@@ -1704,6 +1879,126 @@ var DEFAULT_THEME_OPTIONS = [
|
|
|
1704
1879
|
{ value: "neutral", label: "Neutral" },
|
|
1705
1880
|
{ value: "forest", label: "Forest" }
|
|
1706
1881
|
];
|
|
1882
|
+
var HEX6 = /^#[0-9a-fA-F]{6}$/;
|
|
1883
|
+
function isSameColor(a, b) {
|
|
1884
|
+
if (a === null || b === null) {
|
|
1885
|
+
return a === b;
|
|
1886
|
+
}
|
|
1887
|
+
return a.toLowerCase() === b.toLowerCase();
|
|
1888
|
+
}
|
|
1889
|
+
function BackgroundPicker(props) {
|
|
1890
|
+
const [open, setOpen] = react.useState(false);
|
|
1891
|
+
const rootRef = react.useRef(null);
|
|
1892
|
+
react.useEffect(() => {
|
|
1893
|
+
if (!open) {
|
|
1894
|
+
return void 0;
|
|
1895
|
+
}
|
|
1896
|
+
const onDocPointer = (e) => {
|
|
1897
|
+
if (rootRef.current && !rootRef.current.contains(e.target)) {
|
|
1898
|
+
setOpen(false);
|
|
1899
|
+
}
|
|
1900
|
+
};
|
|
1901
|
+
const onKey = (e) => {
|
|
1902
|
+
if (e.key === "Escape") {
|
|
1903
|
+
setOpen(false);
|
|
1904
|
+
}
|
|
1905
|
+
};
|
|
1906
|
+
document.addEventListener("mousedown", onDocPointer);
|
|
1907
|
+
document.addEventListener("keydown", onKey);
|
|
1908
|
+
return () => {
|
|
1909
|
+
document.removeEventListener("mousedown", onDocPointer);
|
|
1910
|
+
document.removeEventListener("keydown", onKey);
|
|
1911
|
+
};
|
|
1912
|
+
}, [open]);
|
|
1913
|
+
const isPreset = BACKGROUND_PRESETS.some((p) => isSameColor(p.value, props.surface));
|
|
1914
|
+
const customActive = props.surface !== null && !isPreset;
|
|
1915
|
+
const customInputValue = props.surface && HEX6.test(props.surface) ? props.surface : "#1e293b";
|
|
1916
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rsm-bg", ref: rootRef, children: [
|
|
1917
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1918
|
+
"button",
|
|
1919
|
+
{
|
|
1920
|
+
type: "button",
|
|
1921
|
+
className: "rsm-btn rsm-bg-trigger",
|
|
1922
|
+
"aria-expanded": open,
|
|
1923
|
+
"aria-haspopup": "dialog",
|
|
1924
|
+
onClick: () => setOpen((o) => !o),
|
|
1925
|
+
title: "\u756B\u5E03\u80CC\u666F\uFF08\u5E95\u8272 + \u7DB2\u9EDE / \u7DB2\u683C\uFF0CB\uFF09",
|
|
1926
|
+
children: [
|
|
1927
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1928
|
+
"span",
|
|
1929
|
+
{
|
|
1930
|
+
className: "rsm-bg-well",
|
|
1931
|
+
"data-empty": props.surface === null ? "true" : void 0,
|
|
1932
|
+
style: props.surface ? { ["--rsm-well-color"]: props.surface } : void 0
|
|
1933
|
+
}
|
|
1934
|
+
),
|
|
1935
|
+
"\u80CC\u666F"
|
|
1936
|
+
]
|
|
1937
|
+
}
|
|
1938
|
+
),
|
|
1939
|
+
open ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rsm-bg-pop", role: "dialog", "aria-label": "\u756B\u5E03\u80CC\u666F\u8A2D\u5B9A", children: [
|
|
1940
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rsm-bg-section", children: [
|
|
1941
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rsm-bg-section-label", children: "\u5E95\u8272" }),
|
|
1942
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rsm-bg-swatches", children: [
|
|
1943
|
+
BACKGROUND_PRESETS.map((preset) => {
|
|
1944
|
+
const selected = isSameColor(preset.value, props.surface);
|
|
1945
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1946
|
+
"button",
|
|
1947
|
+
{
|
|
1948
|
+
type: "button",
|
|
1949
|
+
className: `rsm-swatch${selected ? " rsm-selected" : ""}`,
|
|
1950
|
+
"data-empty": preset.value === null ? "true" : void 0,
|
|
1951
|
+
style: preset.value ? { backgroundColor: preset.value } : void 0,
|
|
1952
|
+
title: preset.label,
|
|
1953
|
+
"aria-label": `\u5E95\u8272\uFF1A${preset.label}`,
|
|
1954
|
+
"aria-pressed": selected,
|
|
1955
|
+
onClick: () => props.onSurfaceChange(preset.value)
|
|
1956
|
+
},
|
|
1957
|
+
preset.label
|
|
1958
|
+
);
|
|
1959
|
+
}),
|
|
1960
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1961
|
+
"span",
|
|
1962
|
+
{
|
|
1963
|
+
className: `rsm-swatch rsm-swatch-custom${customActive ? " rsm-has-color rsm-selected" : ""}`,
|
|
1964
|
+
style: customActive ? { backgroundColor: props.surface } : void 0,
|
|
1965
|
+
title: "\u81EA\u8A02\u984F\u8272",
|
|
1966
|
+
children: [
|
|
1967
|
+
!customActive ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rsm-swatch-custom-icon", children: "\u{1F3A8}" }) : null,
|
|
1968
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1969
|
+
"input",
|
|
1970
|
+
{
|
|
1971
|
+
type: "color",
|
|
1972
|
+
value: customInputValue,
|
|
1973
|
+
"aria-label": "\u81EA\u8A02\u5E95\u8272",
|
|
1974
|
+
onChange: (e) => props.onSurfaceChange(e.target.value)
|
|
1975
|
+
}
|
|
1976
|
+
)
|
|
1977
|
+
]
|
|
1978
|
+
}
|
|
1979
|
+
)
|
|
1980
|
+
] })
|
|
1981
|
+
] }),
|
|
1982
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rsm-bg-section", children: [
|
|
1983
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rsm-bg-section-label", children: "\u5716\u6A23" }),
|
|
1984
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rsm-seg", role: "group", "aria-label": "\u80CC\u666F\u5716\u6A23", children: PATTERN_OPTIONS.map((opt) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1985
|
+
"button",
|
|
1986
|
+
{
|
|
1987
|
+
type: "button",
|
|
1988
|
+
"aria-pressed": props.pattern === opt.value,
|
|
1989
|
+
title: opt.label,
|
|
1990
|
+
onClick: () => props.onPatternChange(opt.value),
|
|
1991
|
+
children: [
|
|
1992
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "rsm-seg-glyph", "aria-hidden": "true", children: opt.glyph }),
|
|
1993
|
+
opt.label
|
|
1994
|
+
]
|
|
1995
|
+
},
|
|
1996
|
+
opt.value
|
|
1997
|
+
)) })
|
|
1998
|
+
] })
|
|
1999
|
+
] }) : null
|
|
2000
|
+
] });
|
|
2001
|
+
}
|
|
1707
2002
|
function Toolbar(props) {
|
|
1708
2003
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rsm-toolbar", children: [
|
|
1709
2004
|
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "rsm-label", children: [
|
|
@@ -1718,18 +2013,13 @@ function Toolbar(props) {
|
|
|
1718
2013
|
}
|
|
1719
2014
|
)
|
|
1720
2015
|
] }),
|
|
1721
|
-
props.backgroundEnabled ? /* @__PURE__ */ jsxRuntime.
|
|
1722
|
-
|
|
2016
|
+
props.backgroundEnabled ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2017
|
+
BackgroundPicker,
|
|
1723
2018
|
{
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
children: [
|
|
1729
|
-
BACKGROUND_LABELS[props.background].icon,
|
|
1730
|
-
" \u80CC\u666F\uFF1A",
|
|
1731
|
-
BACKGROUND_LABELS[props.background].label
|
|
1732
|
-
]
|
|
2019
|
+
surface: props.surface,
|
|
2020
|
+
onSurfaceChange: props.onSurfaceChange,
|
|
2021
|
+
pattern: props.pattern,
|
|
2022
|
+
onPatternChange: props.onPatternChange
|
|
1733
2023
|
}
|
|
1734
2024
|
) : null,
|
|
1735
2025
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rsm-toolbar-spacer" }),
|
|
@@ -1799,7 +2089,24 @@ function Toolbar(props) {
|
|
|
1799
2089
|
) : null
|
|
1800
2090
|
] });
|
|
1801
2091
|
}
|
|
1802
|
-
var
|
|
2092
|
+
var PATTERN_CYCLE = ["none", "dots", "grid"];
|
|
2093
|
+
function defaultSolidColor(dark) {
|
|
2094
|
+
return dark ? "#1e1e1e" : "#ffffff";
|
|
2095
|
+
}
|
|
2096
|
+
function patternInk(surface, dark) {
|
|
2097
|
+
const m = surface ? /^#([0-9a-fA-F]{6})$/.exec(surface) : null;
|
|
2098
|
+
let lightCanvas;
|
|
2099
|
+
if (m) {
|
|
2100
|
+
const r = parseInt(m[1].slice(0, 2), 16);
|
|
2101
|
+
const g = parseInt(m[1].slice(2, 4), 16);
|
|
2102
|
+
const b = parseInt(m[1].slice(4, 6), 16);
|
|
2103
|
+
lightCanvas = (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255 > 0.5;
|
|
2104
|
+
} else {
|
|
2105
|
+
lightCanvas = !dark;
|
|
2106
|
+
}
|
|
2107
|
+
const ink = lightCanvas ? "15, 23, 42" : "226, 232, 240";
|
|
2108
|
+
return { dot: `rgba(${ink}, 0.34)`, line: `rgba(${ink}, 0.2)` };
|
|
2109
|
+
}
|
|
1803
2110
|
function usePrefersDark(explicit) {
|
|
1804
2111
|
const [autoDark, setAutoDark] = react.useState(false);
|
|
1805
2112
|
react.useEffect(() => {
|
|
@@ -1849,14 +2156,18 @@ var MermaidViewer = react.forwardRef(
|
|
|
1849
2156
|
const [query, setQuery] = react.useState("");
|
|
1850
2157
|
const [matchInfo, setMatchInfo] = react.useState({ current: 0, total: 0 });
|
|
1851
2158
|
const [exporting, setExporting] = react.useState(false);
|
|
1852
|
-
const [
|
|
1853
|
-
|
|
1854
|
-
|
|
2159
|
+
const [pattern, setPatternState] = react.useState(props.pattern ?? "dots");
|
|
2160
|
+
react.useEffect(() => {
|
|
2161
|
+
if (props.pattern) {
|
|
2162
|
+
setPatternState(props.pattern);
|
|
2163
|
+
}
|
|
2164
|
+
}, [props.pattern]);
|
|
2165
|
+
const [solidColor, setSolidColorState] = react.useState(props.solidColor ?? null);
|
|
1855
2166
|
react.useEffect(() => {
|
|
1856
|
-
if (props.
|
|
1857
|
-
|
|
2167
|
+
if (props.solidColor !== void 0) {
|
|
2168
|
+
setSolidColorState(props.solidColor);
|
|
1858
2169
|
}
|
|
1859
|
-
}, [props.
|
|
2170
|
+
}, [props.solidColor]);
|
|
1860
2171
|
const [isFullscreen, setIsFullscreen] = react.useState(false);
|
|
1861
2172
|
const rootRef = react.useRef(null);
|
|
1862
2173
|
const searchInputRef = react.useRef(null);
|
|
@@ -1913,21 +2224,27 @@ var MermaidViewer = react.forwardRef(
|
|
|
1913
2224
|
const exportPng = react.useCallback(async () => {
|
|
1914
2225
|
setExporting(true);
|
|
1915
2226
|
try {
|
|
1916
|
-
|
|
2227
|
+
const paper = solidColor ?? defaultSolidColor(dark);
|
|
2228
|
+
const transparent = solidColor === null && pattern === "none";
|
|
2229
|
+
const bgOpt = transparent ? { transparent: true } : { background: paper };
|
|
2230
|
+
await vm.downloadPng("diagram.png", { scale: 2, ...bgOpt });
|
|
1917
2231
|
} catch (e) {
|
|
1918
2232
|
onError?.(e instanceof Error ? e : new Error(String(e)));
|
|
1919
2233
|
} finally {
|
|
1920
2234
|
setExporting(false);
|
|
1921
2235
|
}
|
|
1922
|
-
}, [vm, onError]);
|
|
1923
|
-
const
|
|
1924
|
-
|
|
1925
|
-
const i =
|
|
1926
|
-
return
|
|
2236
|
+
}, [vm, onError, pattern, solidColor, dark]);
|
|
2237
|
+
const cyclePattern = react.useCallback(() => {
|
|
2238
|
+
setPatternState((prev) => {
|
|
2239
|
+
const i = PATTERN_CYCLE.indexOf(prev);
|
|
2240
|
+
return PATTERN_CYCLE[(i + 1) % PATTERN_CYCLE.length];
|
|
1927
2241
|
});
|
|
1928
2242
|
}, []);
|
|
1929
|
-
const
|
|
1930
|
-
|
|
2243
|
+
const setPattern = react.useCallback((next) => {
|
|
2244
|
+
setPatternState(next);
|
|
2245
|
+
}, []);
|
|
2246
|
+
const setSolidColor = react.useCallback((color) => {
|
|
2247
|
+
setSolidColorState(color);
|
|
1931
2248
|
}, []);
|
|
1932
2249
|
const enterFullscreen = react.useCallback(() => {
|
|
1933
2250
|
setIsFullscreen((prev) => {
|
|
@@ -2047,7 +2364,7 @@ var MermaidViewer = react.forwardRef(
|
|
|
2047
2364
|
toggleFullscreen();
|
|
2048
2365
|
} else if (backgroundEnabled && (e.key === "b" || e.key === "B")) {
|
|
2049
2366
|
e.preventDefault();
|
|
2050
|
-
|
|
2367
|
+
cyclePattern();
|
|
2051
2368
|
}
|
|
2052
2369
|
};
|
|
2053
2370
|
root.addEventListener("keydown", onKey);
|
|
@@ -2061,7 +2378,7 @@ var MermaidViewer = react.forwardRef(
|
|
|
2061
2378
|
isFullscreen,
|
|
2062
2379
|
exitFullscreen,
|
|
2063
2380
|
toggleFullscreen,
|
|
2064
|
-
|
|
2381
|
+
cyclePattern,
|
|
2065
2382
|
fullscreenEnabled,
|
|
2066
2383
|
backgroundEnabled
|
|
2067
2384
|
]);
|
|
@@ -2087,9 +2404,11 @@ var MermaidViewer = react.forwardRef(
|
|
|
2087
2404
|
exitFullscreen,
|
|
2088
2405
|
toggleFullscreen,
|
|
2089
2406
|
isFullscreen: () => isFullscreen,
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2407
|
+
setPattern,
|
|
2408
|
+
cyclePattern,
|
|
2409
|
+
getPattern: () => pattern,
|
|
2410
|
+
setSolidColor,
|
|
2411
|
+
getSolidColor: () => solidColor
|
|
2093
2412
|
}),
|
|
2094
2413
|
[
|
|
2095
2414
|
vm,
|
|
@@ -2097,9 +2416,11 @@ var MermaidViewer = react.forwardRef(
|
|
|
2097
2416
|
exitFullscreen,
|
|
2098
2417
|
toggleFullscreen,
|
|
2099
2418
|
isFullscreen,
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2419
|
+
setPattern,
|
|
2420
|
+
cyclePattern,
|
|
2421
|
+
pattern,
|
|
2422
|
+
setSolidColor,
|
|
2423
|
+
solidColor
|
|
2103
2424
|
]
|
|
2104
2425
|
);
|
|
2105
2426
|
let countText = "";
|
|
@@ -2111,16 +2432,23 @@ var MermaidViewer = react.forwardRef(
|
|
|
2111
2432
|
const rootClassName = [
|
|
2112
2433
|
"rsm-root",
|
|
2113
2434
|
dark ? "rsm-dark" : "",
|
|
2114
|
-
`rsm-
|
|
2435
|
+
`rsm-pattern-${pattern}`,
|
|
2115
2436
|
isFullscreen ? "rsm-fullscreen" : "",
|
|
2116
2437
|
className ?? ""
|
|
2117
2438
|
].filter(Boolean).join(" ");
|
|
2439
|
+
const ink = patternInk(solidColor, dark);
|
|
2440
|
+
const rootStyle = {
|
|
2441
|
+
...style ?? {},
|
|
2442
|
+
["--rsm-grid-dot"]: ink.dot,
|
|
2443
|
+
["--rsm-grid-line"]: ink.line,
|
|
2444
|
+
...solidColor ? { ["--rsm-canvas-bg"]: solidColor } : {}
|
|
2445
|
+
};
|
|
2118
2446
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2119
2447
|
"div",
|
|
2120
2448
|
{
|
|
2121
2449
|
ref: rootRef,
|
|
2122
2450
|
className: rootClassName,
|
|
2123
|
-
style,
|
|
2451
|
+
style: rootStyle,
|
|
2124
2452
|
tabIndex: keyboard ? 0 : void 0,
|
|
2125
2453
|
children: [
|
|
2126
2454
|
toolbar ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2142,8 +2470,10 @@ var MermaidViewer = react.forwardRef(
|
|
|
2142
2470
|
onExportSvg: exportSvg,
|
|
2143
2471
|
onExportPng: exportPng,
|
|
2144
2472
|
backgroundEnabled,
|
|
2145
|
-
|
|
2146
|
-
|
|
2473
|
+
surface: solidColor,
|
|
2474
|
+
onSurfaceChange: setSolidColor,
|
|
2475
|
+
pattern,
|
|
2476
|
+
onPatternChange: setPattern,
|
|
2147
2477
|
fullscreenEnabled,
|
|
2148
2478
|
fullscreen: isFullscreen,
|
|
2149
2479
|
onToggleFullscreen: toggleFullscreen
|
|
@@ -2210,10 +2540,12 @@ var MermaidDiagram = react.forwardRef(
|
|
|
2210
2540
|
}
|
|
2211
2541
|
);
|
|
2212
2542
|
|
|
2543
|
+
exports.BACKGROUND_PRESETS = BACKGROUND_PRESETS;
|
|
2213
2544
|
exports.DEFAULT_THEME_OPTIONS = DEFAULT_THEME_OPTIONS;
|
|
2214
2545
|
exports.DEFAULT_VIRGIL_FONT_URL = DEFAULT_VIRGIL_FONT_URL;
|
|
2215
2546
|
exports.MermaidDiagram = MermaidDiagram;
|
|
2216
2547
|
exports.MermaidViewer = MermaidViewer;
|
|
2548
|
+
exports.PATTERN_OPTIONS = PATTERN_OPTIONS;
|
|
2217
2549
|
exports.SKETCH_FONT = SKETCH_FONT;
|
|
2218
2550
|
exports.Toolbar = Toolbar;
|
|
2219
2551
|
exports.boostLegibility = boostLegibility;
|