@diagrammo/dgmo 0.8.19 → 0.8.21
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/dist/cli.cjs +92 -131
- package/dist/editor.cjs +13 -1
- package/dist/editor.cjs.map +1 -1
- package/dist/editor.js +13 -1
- package/dist/editor.js.map +1 -1
- package/dist/highlight.cjs +13 -1
- package/dist/highlight.cjs.map +1 -1
- package/dist/highlight.js +13 -1
- package/dist/highlight.js.map +1 -1
- package/dist/index.cjs +4524 -1511
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +427 -186
- package/dist/index.d.ts +427 -186
- package/dist/index.js +4526 -1503
- package/dist/index.js.map +1 -1
- package/docs/guide/chart-mindmap.md +198 -0
- package/docs/guide/chart-sequence.md +23 -1
- package/docs/guide/chart-wireframe.md +100 -0
- package/docs/guide/index.md +8 -0
- package/docs/language-reference.md +210 -2
- package/package.json +22 -9
- package/src/boxes-and-lines/collapse.ts +21 -3
- package/src/boxes-and-lines/layout.ts +51 -9
- package/src/boxes-and-lines/parser.ts +16 -4
- package/src/boxes-and-lines/renderer.ts +121 -23
- package/src/boxes-and-lines/types.ts +1 -0
- package/src/c4/parser.ts +8 -7
- package/src/class/parser.ts +6 -0
- package/src/cli.ts +1 -9
- package/src/completion.ts +26 -0
- package/src/d3.ts +169 -266
- package/src/dgmo-router.ts +103 -5
- package/src/diagnostics.ts +16 -6
- package/src/echarts.ts +43 -10
- package/src/editor/keywords.ts +12 -0
- package/src/er/parser.ts +22 -2
- package/src/gantt/renderer.ts +2 -2
- package/src/graph/flowchart-parser.ts +89 -52
- package/src/graph/layout.ts +73 -9
- package/src/graph/state-collapse.ts +78 -0
- package/src/graph/state-parser.ts +60 -35
- package/src/graph/state-renderer.ts +139 -34
- package/src/index.ts +41 -16
- package/src/infra/parser.ts +9 -2
- package/src/kanban/renderer.ts +305 -59
- package/src/mindmap/collapse.ts +88 -0
- package/src/mindmap/layout.ts +605 -0
- package/src/mindmap/parser.ts +379 -0
- package/src/mindmap/renderer.ts +543 -0
- package/src/mindmap/text-wrap.ts +207 -0
- package/src/mindmap/types.ts +55 -0
- package/src/palettes/color-utils.ts +4 -12
- package/src/palettes/index.ts +0 -4
- package/src/render.ts +31 -20
- package/src/sequence/parser.ts +7 -2
- package/src/sequence/renderer.ts +141 -21
- package/src/sharing.ts +2 -0
- package/src/sitemap/layout.ts +35 -12
- package/src/sitemap/renderer.ts +1 -6
- package/src/utils/arrows.ts +180 -11
- package/src/utils/d3-types.ts +4 -0
- package/src/utils/export-container.ts +3 -2
- package/src/utils/legend-constants.ts +0 -4
- package/src/utils/legend-d3.ts +1 -0
- package/src/utils/legend-layout.ts +2 -2
- package/src/utils/parsing.ts +2 -0
- package/src/utils/time-ticks.ts +213 -0
- package/src/wireframe/layout.ts +460 -0
- package/src/wireframe/parser.ts +956 -0
- package/src/wireframe/renderer.ts +1293 -0
- package/src/wireframe/types.ts +110 -0
- package/src/branding.ts +0 -67
- package/src/dgmo-mermaid.ts +0 -262
- package/src/palettes/mermaid-bridge.ts +0 -220
package/src/d3.ts
CHANGED
|
@@ -4,8 +4,9 @@ import * as d3Shape from 'd3-shape';
|
|
|
4
4
|
import * as d3Array from 'd3-array';
|
|
5
5
|
import cloud from 'd3-cloud';
|
|
6
6
|
import { FONT_FAMILY } from './fonts';
|
|
7
|
-
import { injectBranding } from './branding';
|
|
8
7
|
import { computeQuadrantPointLabels, type LabelRect } from './label-layout';
|
|
8
|
+
import { MONTH_ABBR, computeTimeTicks } from './utils/time-ticks';
|
|
9
|
+
import type { D3ExportDimensions } from './utils/d3-types';
|
|
9
10
|
|
|
10
11
|
// ============================================================
|
|
11
12
|
// Types
|
|
@@ -133,10 +134,7 @@ interface QuadrantLabels {
|
|
|
133
134
|
}
|
|
134
135
|
|
|
135
136
|
/** Optional explicit dimensions for CLI/export rendering (bypasses DOM layout). */
|
|
136
|
-
export
|
|
137
|
-
width?: number;
|
|
138
|
-
height?: number;
|
|
139
|
-
}
|
|
137
|
+
export type { D3ExportDimensions } from './utils/d3-types';
|
|
140
138
|
|
|
141
139
|
export interface ParsedVisualization {
|
|
142
140
|
type: VisualizationType | null;
|
|
@@ -331,34 +329,6 @@ export function parseTimelineDate(s: string): number {
|
|
|
331
329
|
);
|
|
332
330
|
}
|
|
333
331
|
|
|
334
|
-
/** Convert a fractional year number back to a Date (inverse of parseTimelineDate). */
|
|
335
|
-
function fractionalYearToDate(frac: number): Date {
|
|
336
|
-
const year = Math.floor(frac);
|
|
337
|
-
const remainder = frac - year;
|
|
338
|
-
// Inverse of: (month-1)/12 + (day-1)/365 + hour/8760 + minute/525600
|
|
339
|
-
const monthFrac = remainder * 12;
|
|
340
|
-
const month = Math.floor(monthFrac); // 0-based
|
|
341
|
-
const monthRemainder = remainder - month / 12;
|
|
342
|
-
const dayFrac = monthRemainder * 365; // fractional day-of-year offset
|
|
343
|
-
const day = Math.floor(dayFrac) + 1;
|
|
344
|
-
const dayRemainder = dayFrac - Math.floor(dayFrac);
|
|
345
|
-
const hourFrac = dayRemainder * 24;
|
|
346
|
-
const hour = Math.floor(hourFrac);
|
|
347
|
-
const minute = Math.round((hourFrac - hour) * 60);
|
|
348
|
-
return new Date(year, month, day, hour, minute);
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
/** Convert a Date to a fractional year number. */
|
|
352
|
-
function dateToFractionalYear(d: Date): number {
|
|
353
|
-
return (
|
|
354
|
-
d.getFullYear() +
|
|
355
|
-
d.getMonth() / 12 +
|
|
356
|
-
(d.getDate() - 1) / 365 +
|
|
357
|
-
d.getHours() / 8760 +
|
|
358
|
-
d.getMinutes() / 525600
|
|
359
|
-
);
|
|
360
|
-
}
|
|
361
|
-
|
|
362
332
|
/**
|
|
363
333
|
* Adds a duration to a date string and returns the resulting date string.
|
|
364
334
|
* Supports: d (days), w (weeks), m (months), y (years), h (hours), min (minutes)
|
|
@@ -2885,21 +2855,6 @@ function renderMarkers(
|
|
|
2885
2855
|
// Timeline Time Scale
|
|
2886
2856
|
// ============================================================
|
|
2887
2857
|
|
|
2888
|
-
const MONTH_ABBR = [
|
|
2889
|
-
'Jan',
|
|
2890
|
-
'Feb',
|
|
2891
|
-
'Mar',
|
|
2892
|
-
'Apr',
|
|
2893
|
-
'May',
|
|
2894
|
-
'Jun',
|
|
2895
|
-
'Jul',
|
|
2896
|
-
'Aug',
|
|
2897
|
-
'Sep',
|
|
2898
|
-
'Oct',
|
|
2899
|
-
'Nov',
|
|
2900
|
-
'Dec',
|
|
2901
|
-
];
|
|
2902
|
-
|
|
2903
2858
|
/**
|
|
2904
2859
|
* Converts a DSL date string (YYYY, YYYY-MM, YYYY-MM-DD, or YYYY-MM-DD HH:MM) to a human-readable label.
|
|
2905
2860
|
* '1718' → '1718'
|
|
@@ -2947,173 +2902,6 @@ function formatBoundaryLabel(dateStr: string, otherDateStr: string): string {
|
|
|
2947
2902
|
return formatDateLabel(dateStr);
|
|
2948
2903
|
}
|
|
2949
2904
|
|
|
2950
|
-
/**
|
|
2951
|
-
* Computes adaptive tick marks for a timeline scale.
|
|
2952
|
-
* - Multi-year spans → year ticks
|
|
2953
|
-
* - Within ~1 year → month ticks
|
|
2954
|
-
* - Within ~3 months → week ticks (1st, 8th, 15th, 22nd)
|
|
2955
|
-
*
|
|
2956
|
-
* Optional boundary parameters add ticks at exact data start/end:
|
|
2957
|
-
* - boundaryStart/boundaryEnd: numeric date values
|
|
2958
|
-
* - boundaryStartLabel/boundaryEndLabel: formatted labels for those dates
|
|
2959
|
-
*/
|
|
2960
|
-
export function computeTimeTicks(
|
|
2961
|
-
domainMin: number,
|
|
2962
|
-
domainMax: number,
|
|
2963
|
-
scale: d3Scale.ScaleLinear<number, number>,
|
|
2964
|
-
boundaryStart?: number,
|
|
2965
|
-
boundaryEnd?: number,
|
|
2966
|
-
boundaryStartLabel?: string,
|
|
2967
|
-
boundaryEndLabel?: string
|
|
2968
|
-
): { pos: number; label: string }[] {
|
|
2969
|
-
const minYear = Math.floor(domainMin);
|
|
2970
|
-
const maxYear = Math.floor(domainMax);
|
|
2971
|
-
const span = domainMax - domainMin;
|
|
2972
|
-
|
|
2973
|
-
let ticks: { pos: number; label: string }[] = [];
|
|
2974
|
-
|
|
2975
|
-
// Year ticks for multi-year spans (need at least 2 boundaries)
|
|
2976
|
-
const firstYear = Math.ceil(domainMin);
|
|
2977
|
-
const lastYear = Math.floor(domainMax);
|
|
2978
|
-
if (lastYear >= firstYear + 1) {
|
|
2979
|
-
// Decimate ticks for long spans so labels don't overlap
|
|
2980
|
-
const yearSpan = lastYear - firstYear;
|
|
2981
|
-
let step = 1;
|
|
2982
|
-
if (yearSpan > 80) step = 20;
|
|
2983
|
-
else if (yearSpan > 40) step = 10;
|
|
2984
|
-
else if (yearSpan > 20) step = 5;
|
|
2985
|
-
else if (yearSpan > 10) step = 2;
|
|
2986
|
-
|
|
2987
|
-
// Align to step boundary so ticks land on round years (1700, 1710, …)
|
|
2988
|
-
const alignedFirst = Math.ceil(firstYear / step) * step;
|
|
2989
|
-
for (let y = alignedFirst; y <= lastYear; y += step) {
|
|
2990
|
-
ticks.push({ pos: scale(y), label: String(y) });
|
|
2991
|
-
}
|
|
2992
|
-
} else if (span > 0.25) {
|
|
2993
|
-
// Month ticks for spans > ~3 months
|
|
2994
|
-
const crossesYear = maxYear > minYear;
|
|
2995
|
-
for (let y = minYear; y <= maxYear + 1; y++) {
|
|
2996
|
-
for (let m = 1; m <= 12; m++) {
|
|
2997
|
-
const val = y + (m - 1) / 12;
|
|
2998
|
-
if (val > domainMax) break;
|
|
2999
|
-
if (val >= domainMin) {
|
|
3000
|
-
ticks.push({
|
|
3001
|
-
pos: scale(val),
|
|
3002
|
-
label: crossesYear
|
|
3003
|
-
? `${MONTH_ABBR[m - 1]} '${String(y).slice(-2)}`
|
|
3004
|
-
: MONTH_ABBR[m - 1],
|
|
3005
|
-
});
|
|
3006
|
-
}
|
|
3007
|
-
}
|
|
3008
|
-
}
|
|
3009
|
-
} else if (span <= 0.000685) {
|
|
3010
|
-
// Minute ticks for spans ≤ ~6 hours
|
|
3011
|
-
// Adaptive step: >3h → 30min, >1h → 15min, >30min → 10min, else 5min
|
|
3012
|
-
let stepMin = 5;
|
|
3013
|
-
const spanHours = span * 8760;
|
|
3014
|
-
if (spanHours > 3) stepMin = 30;
|
|
3015
|
-
else if (spanHours > 1) stepMin = 15;
|
|
3016
|
-
else if (spanHours > 0.5) stepMin = 10;
|
|
3017
|
-
|
|
3018
|
-
// Iterate from the start hour boundary
|
|
3019
|
-
const startDate = fractionalYearToDate(domainMin);
|
|
3020
|
-
// Round down to nearest step boundary
|
|
3021
|
-
startDate.setMinutes(
|
|
3022
|
-
Math.floor(startDate.getMinutes() / stepMin) * stepMin,
|
|
3023
|
-
0,
|
|
3024
|
-
0
|
|
3025
|
-
);
|
|
3026
|
-
|
|
3027
|
-
while (true) {
|
|
3028
|
-
const val = dateToFractionalYear(startDate);
|
|
3029
|
-
if (val > domainMax) break;
|
|
3030
|
-
if (val >= domainMin) {
|
|
3031
|
-
const hh = String(startDate.getHours()).padStart(2, '0');
|
|
3032
|
-
const mm = String(startDate.getMinutes()).padStart(2, '0');
|
|
3033
|
-
ticks.push({ pos: scale(val), label: `${hh}:${mm}` });
|
|
3034
|
-
}
|
|
3035
|
-
startDate.setMinutes(startDate.getMinutes() + stepMin);
|
|
3036
|
-
}
|
|
3037
|
-
} else if (span <= 0.00822) {
|
|
3038
|
-
// Hour ticks for spans ≤ ~3 days
|
|
3039
|
-
// Adaptive step: >2d → 6h, >1d → 3h, >12h → 2h, else 1h
|
|
3040
|
-
let stepHour = 1;
|
|
3041
|
-
const spanHours = span * 8760;
|
|
3042
|
-
if (spanHours > 48) stepHour = 6;
|
|
3043
|
-
else if (spanHours > 24) stepHour = 3;
|
|
3044
|
-
else if (spanHours > 12) stepHour = 2;
|
|
3045
|
-
|
|
3046
|
-
// For single-day spans, just show HH:MM without the date prefix
|
|
3047
|
-
const singleDay = spanHours <= 24;
|
|
3048
|
-
|
|
3049
|
-
const startDate = fractionalYearToDate(domainMin);
|
|
3050
|
-
// Round down to nearest step boundary
|
|
3051
|
-
startDate.setHours(
|
|
3052
|
-
Math.floor(startDate.getHours() / stepHour) * stepHour,
|
|
3053
|
-
0,
|
|
3054
|
-
0,
|
|
3055
|
-
0
|
|
3056
|
-
);
|
|
3057
|
-
|
|
3058
|
-
while (true) {
|
|
3059
|
-
const val = dateToFractionalYear(startDate);
|
|
3060
|
-
if (val > domainMax) break;
|
|
3061
|
-
if (val >= domainMin) {
|
|
3062
|
-
const hh = String(startDate.getHours()).padStart(2, '0');
|
|
3063
|
-
const mm = String(startDate.getMinutes()).padStart(2, '0');
|
|
3064
|
-
if (singleDay) {
|
|
3065
|
-
ticks.push({ pos: scale(val), label: `${hh}:${mm}` });
|
|
3066
|
-
} else {
|
|
3067
|
-
const mon = MONTH_ABBR[startDate.getMonth()];
|
|
3068
|
-
const d = startDate.getDate();
|
|
3069
|
-
ticks.push({ pos: scale(val), label: `${mon} ${d} ${hh}:${mm}` });
|
|
3070
|
-
}
|
|
3071
|
-
}
|
|
3072
|
-
startDate.setHours(startDate.getHours() + stepHour);
|
|
3073
|
-
}
|
|
3074
|
-
} else {
|
|
3075
|
-
// Week ticks for spans ≤ ~3 months (1st, 8th, 15th, 22nd of each month)
|
|
3076
|
-
for (let y = minYear; y <= maxYear + 1; y++) {
|
|
3077
|
-
for (let m = 1; m <= 12; m++) {
|
|
3078
|
-
for (const d of [1, 8, 15, 22]) {
|
|
3079
|
-
const val = y + (m - 1) / 12 + (d - 1) / 365;
|
|
3080
|
-
if (val > domainMax) break;
|
|
3081
|
-
if (val >= domainMin) {
|
|
3082
|
-
ticks.push({
|
|
3083
|
-
pos: scale(val),
|
|
3084
|
-
label: `${MONTH_ABBR[m - 1]} ${d}`,
|
|
3085
|
-
});
|
|
3086
|
-
}
|
|
3087
|
-
}
|
|
3088
|
-
}
|
|
3089
|
-
}
|
|
3090
|
-
}
|
|
3091
|
-
|
|
3092
|
-
// Add boundary ticks at exact data start/end if provided
|
|
3093
|
-
// When a boundary tick collides with a standard tick, replace the standard tick
|
|
3094
|
-
const collisionThreshold = 40; // pixels
|
|
3095
|
-
|
|
3096
|
-
if (boundaryStart !== undefined && boundaryStartLabel) {
|
|
3097
|
-
const boundaryPos = scale(boundaryStart);
|
|
3098
|
-
// Remove any standard ticks that would collide with the start boundary
|
|
3099
|
-
ticks = ticks.filter(
|
|
3100
|
-
(t) => Math.abs(t.pos - boundaryPos) >= collisionThreshold
|
|
3101
|
-
);
|
|
3102
|
-
ticks.unshift({ pos: boundaryPos, label: boundaryStartLabel });
|
|
3103
|
-
}
|
|
3104
|
-
|
|
3105
|
-
if (boundaryEnd !== undefined && boundaryEndLabel) {
|
|
3106
|
-
const boundaryPos = scale(boundaryEnd);
|
|
3107
|
-
// Remove any standard ticks that would collide with the end boundary
|
|
3108
|
-
ticks = ticks.filter(
|
|
3109
|
-
(t) => Math.abs(t.pos - boundaryPos) >= collisionThreshold
|
|
3110
|
-
);
|
|
3111
|
-
ticks.push({ pos: boundaryPos, label: boundaryEndLabel });
|
|
3112
|
-
}
|
|
3113
|
-
|
|
3114
|
-
return ticks;
|
|
3115
|
-
}
|
|
3116
|
-
|
|
3117
2905
|
/**
|
|
3118
2906
|
* Renders adaptive tick marks along the time axis.
|
|
3119
2907
|
* Optional boundary parameters add ticks at exact data start/end.
|
|
@@ -6678,8 +6466,7 @@ function createExportContainer(width: number, height: number): HTMLDivElement {
|
|
|
6678
6466
|
function finalizeSvgExport(
|
|
6679
6467
|
container: HTMLDivElement,
|
|
6680
6468
|
theme: string,
|
|
6681
|
-
palette: PaletteColors
|
|
6682
|
-
options?: { branding?: boolean }
|
|
6469
|
+
palette: PaletteColors
|
|
6683
6470
|
): string {
|
|
6684
6471
|
const svgEl = container.querySelector('svg');
|
|
6685
6472
|
if (!svgEl) return '';
|
|
@@ -6694,10 +6481,6 @@ function finalizeSvgExport(
|
|
|
6694
6481
|
svgEl.querySelectorAll('[data-export-ignore]').forEach((el) => el.remove());
|
|
6695
6482
|
const svgHtml = svgEl.outerHTML;
|
|
6696
6483
|
document.body.removeChild(container);
|
|
6697
|
-
if (options?.branding !== false) {
|
|
6698
|
-
const brandColor = theme === 'transparent' ? '#888' : palette.textMuted;
|
|
6699
|
-
return injectBranding(svgHtml, brandColor);
|
|
6700
|
-
}
|
|
6701
6484
|
return svgHtml;
|
|
6702
6485
|
}
|
|
6703
6486
|
|
|
@@ -6709,14 +6492,8 @@ export async function renderForExport(
|
|
|
6709
6492
|
content: string,
|
|
6710
6493
|
theme: 'light' | 'dark' | 'transparent',
|
|
6711
6494
|
palette?: PaletteColors,
|
|
6712
|
-
|
|
6713
|
-
collapsedNodes?: Set<string>;
|
|
6714
|
-
activeTagGroup?: string | null;
|
|
6715
|
-
hiddenAttributes?: Set<string>;
|
|
6716
|
-
swimlaneTagGroup?: string | null;
|
|
6717
|
-
},
|
|
6495
|
+
viewState?: import('./sharing').CompactViewState,
|
|
6718
6496
|
options?: {
|
|
6719
|
-
branding?: boolean;
|
|
6720
6497
|
c4Level?: 'context' | 'containers' | 'components' | 'deployment';
|
|
6721
6498
|
c4System?: string;
|
|
6722
6499
|
c4Container?: string;
|
|
@@ -6739,14 +6516,14 @@ export async function renderForExport(
|
|
|
6739
6516
|
const orgParsed = parseOrg(content, effectivePalette);
|
|
6740
6517
|
if (orgParsed.error) return '';
|
|
6741
6518
|
|
|
6742
|
-
// Apply interactive collapse state when provided
|
|
6743
|
-
const collapsedNodes =
|
|
6519
|
+
// Apply interactive collapse state when provided (read from unified viewState)
|
|
6520
|
+
const collapsedNodes = viewState?.cg ? new Set(viewState.cg) : undefined;
|
|
6744
6521
|
const activeTagGroup = resolveActiveTagGroup(
|
|
6745
6522
|
orgParsed.tagGroups,
|
|
6746
6523
|
orgParsed.options['active-tag'],
|
|
6747
|
-
|
|
6524
|
+
viewState?.tag ?? options?.tagGroup
|
|
6748
6525
|
);
|
|
6749
|
-
const hiddenAttributes =
|
|
6526
|
+
const hiddenAttributes = viewState?.ha ? new Set(viewState.ha) : undefined;
|
|
6750
6527
|
|
|
6751
6528
|
const { parsed: effectiveParsed, hiddenCounts } =
|
|
6752
6529
|
collapsedNodes && collapsedNodes.size > 0
|
|
@@ -6778,7 +6555,7 @@ export async function renderForExport(
|
|
|
6778
6555
|
activeTagGroup,
|
|
6779
6556
|
hiddenAttributes
|
|
6780
6557
|
);
|
|
6781
|
-
return finalizeSvgExport(container, theme, effectivePalette
|
|
6558
|
+
return finalizeSvgExport(container, theme, effectivePalette);
|
|
6782
6559
|
}
|
|
6783
6560
|
|
|
6784
6561
|
if (detectedType === 'sitemap') {
|
|
@@ -6793,14 +6570,14 @@ export async function renderForExport(
|
|
|
6793
6570
|
const sitemapParsed = parseSitemap(content, effectivePalette);
|
|
6794
6571
|
if (sitemapParsed.error || sitemapParsed.roots.length === 0) return '';
|
|
6795
6572
|
|
|
6796
|
-
// Apply interactive collapse state when provided
|
|
6797
|
-
const collapsedNodes =
|
|
6573
|
+
// Apply interactive collapse state when provided (read from unified viewState)
|
|
6574
|
+
const collapsedNodes = viewState?.cg ? new Set(viewState.cg) : undefined;
|
|
6798
6575
|
const activeTagGroup = resolveActiveTagGroup(
|
|
6799
6576
|
sitemapParsed.tagGroups,
|
|
6800
6577
|
sitemapParsed.options['active-tag'],
|
|
6801
|
-
|
|
6578
|
+
viewState?.tag ?? options?.tagGroup
|
|
6802
6579
|
);
|
|
6803
|
-
const hiddenAttributes =
|
|
6580
|
+
const hiddenAttributes = viewState?.ha ? new Set(viewState.ha) : undefined;
|
|
6804
6581
|
|
|
6805
6582
|
const { parsed: effectiveParsed, hiddenCounts } =
|
|
6806
6583
|
collapsedNodes && collapsedNodes.size > 0
|
|
@@ -6832,7 +6609,7 @@ export async function renderForExport(
|
|
|
6832
6609
|
activeTagGroup,
|
|
6833
6610
|
hiddenAttributes
|
|
6834
6611
|
);
|
|
6835
|
-
return finalizeSvgExport(container, theme, effectivePalette
|
|
6612
|
+
return finalizeSvgExport(container, theme, effectivePalette);
|
|
6836
6613
|
}
|
|
6837
6614
|
|
|
6838
6615
|
if (detectedType === 'kanban') {
|
|
@@ -6853,10 +6630,14 @@ export async function renderForExport(
|
|
|
6853
6630
|
activeTagGroup: resolveActiveTagGroup(
|
|
6854
6631
|
kanbanParsed.tagGroups,
|
|
6855
6632
|
kanbanParsed.options['active-tag'],
|
|
6856
|
-
options?.tagGroup
|
|
6633
|
+
viewState?.tag ?? options?.tagGroup
|
|
6857
6634
|
),
|
|
6635
|
+
currentSwimlaneGroup: viewState?.swim ?? null,
|
|
6636
|
+
collapsedLanes: viewState?.cl ? new Set(viewState.cl) : undefined,
|
|
6637
|
+
collapsedColumns: viewState?.cc ? new Set(viewState.cc) : undefined,
|
|
6638
|
+
compactMeta: viewState?.cm,
|
|
6858
6639
|
});
|
|
6859
|
-
return finalizeSvgExport(container, theme, effectivePalette
|
|
6640
|
+
return finalizeSvgExport(container, theme, effectivePalette);
|
|
6860
6641
|
}
|
|
6861
6642
|
|
|
6862
6643
|
if (detectedType === 'class') {
|
|
@@ -6884,7 +6665,7 @@ export async function renderForExport(
|
|
|
6884
6665
|
undefined,
|
|
6885
6666
|
{ width: exportWidth, height: exportHeight }
|
|
6886
6667
|
);
|
|
6887
|
-
return finalizeSvgExport(container, theme, effectivePalette
|
|
6668
|
+
return finalizeSvgExport(container, theme, effectivePalette);
|
|
6888
6669
|
}
|
|
6889
6670
|
|
|
6890
6671
|
if (detectedType === 'er') {
|
|
@@ -6914,22 +6695,32 @@ export async function renderForExport(
|
|
|
6914
6695
|
resolveActiveTagGroup(
|
|
6915
6696
|
erParsed.tagGroups,
|
|
6916
6697
|
erParsed.options['active-tag'],
|
|
6917
|
-
options?.tagGroup
|
|
6918
|
-
)
|
|
6698
|
+
viewState?.tag ?? options?.tagGroup
|
|
6699
|
+
),
|
|
6700
|
+
viewState?.sem
|
|
6919
6701
|
);
|
|
6920
|
-
return finalizeSvgExport(container, theme, effectivePalette
|
|
6702
|
+
return finalizeSvgExport(container, theme, effectivePalette);
|
|
6921
6703
|
}
|
|
6922
6704
|
|
|
6923
6705
|
if (detectedType === 'boxes-and-lines') {
|
|
6924
6706
|
const { parseBoxesAndLines } = await import('./boxes-and-lines/parser');
|
|
6925
|
-
const { layoutBoxesAndLines } = await import('./boxes-and-lines/layout');
|
|
6926
|
-
const { renderBoxesAndLinesForExport } =
|
|
6927
|
-
await import('./boxes-and-lines/renderer');
|
|
6928
|
-
|
|
6929
6707
|
const effectivePalette = await resolveExportPalette(theme, palette);
|
|
6930
6708
|
const blParsed = parseBoxesAndLines(content);
|
|
6931
6709
|
if (blParsed.error || blParsed.nodes.length === 0) return '';
|
|
6932
6710
|
|
|
6711
|
+
// Convert viewState.htv (Record<string, string[]>) to Map<string, Set<string>>
|
|
6712
|
+
let blHiddenTagValues: Map<string, Set<string>> | undefined;
|
|
6713
|
+
if (viewState?.htv) {
|
|
6714
|
+
blHiddenTagValues = new Map();
|
|
6715
|
+
for (const [k, v] of Object.entries(viewState.htv)) {
|
|
6716
|
+
blHiddenTagValues.set(k, new Set(v));
|
|
6717
|
+
}
|
|
6718
|
+
}
|
|
6719
|
+
|
|
6720
|
+
const { layoutBoxesAndLines } = await import('./boxes-and-lines/layout');
|
|
6721
|
+
const { renderBoxesAndLinesForExport } =
|
|
6722
|
+
await import('./boxes-and-lines/renderer');
|
|
6723
|
+
|
|
6933
6724
|
const blLayout = layoutBoxesAndLines(blParsed);
|
|
6934
6725
|
const PADDING = 20;
|
|
6935
6726
|
const titleOffset = blParsed.title ? 40 : 0;
|
|
@@ -6945,10 +6736,104 @@ export async function renderForExport(
|
|
|
6945
6736
|
theme === 'dark',
|
|
6946
6737
|
{
|
|
6947
6738
|
exportDims: { width: exportWidth, height: exportHeight },
|
|
6948
|
-
activeTagGroup: options?.tagGroup,
|
|
6739
|
+
activeTagGroup: viewState?.tag ?? options?.tagGroup,
|
|
6740
|
+
hiddenTagValues: blHiddenTagValues,
|
|
6949
6741
|
}
|
|
6950
6742
|
);
|
|
6951
|
-
return finalizeSvgExport(container, theme, effectivePalette
|
|
6743
|
+
return finalizeSvgExport(container, theme, effectivePalette);
|
|
6744
|
+
}
|
|
6745
|
+
|
|
6746
|
+
if (detectedType === 'mindmap') {
|
|
6747
|
+
const { parseMindmap } = await import('./mindmap/parser');
|
|
6748
|
+
const { layoutMindmap } = await import('./mindmap/layout');
|
|
6749
|
+
const { collapseMindmapTree } = await import('./mindmap/collapse');
|
|
6750
|
+
const { renderMindmap } = await import('./mindmap/renderer');
|
|
6751
|
+
|
|
6752
|
+
const isDark = theme === 'dark';
|
|
6753
|
+
const effectivePalette = await resolveExportPalette(theme, palette);
|
|
6754
|
+
|
|
6755
|
+
const mmParsed = parseMindmap(content, effectivePalette);
|
|
6756
|
+
if (mmParsed.error) return '';
|
|
6757
|
+
|
|
6758
|
+
const collapsedNodes = viewState?.cg ? new Set(viewState.cg) : undefined;
|
|
6759
|
+
const activeTagGroup = resolveActiveTagGroup(
|
|
6760
|
+
mmParsed.tagGroups,
|
|
6761
|
+
mmParsed.options['active-tag'],
|
|
6762
|
+
viewState?.tag ?? options?.tagGroup
|
|
6763
|
+
);
|
|
6764
|
+
const hideDescriptions =
|
|
6765
|
+
mmParsed.options['hide-descriptions'] === 'true' ||
|
|
6766
|
+
viewState?.hd === true;
|
|
6767
|
+
|
|
6768
|
+
const { roots: effectiveRoots, hiddenCounts } =
|
|
6769
|
+
collapsedNodes && collapsedNodes.size > 0
|
|
6770
|
+
? collapseMindmapTree(mmParsed.roots, collapsedNodes)
|
|
6771
|
+
: { roots: mmParsed.roots, hiddenCounts: new Map<string, number>() };
|
|
6772
|
+
|
|
6773
|
+
const effectiveParsed = { ...mmParsed, roots: effectiveRoots };
|
|
6774
|
+
|
|
6775
|
+
const mmLayout = layoutMindmap(effectiveParsed, effectivePalette, {
|
|
6776
|
+
interactive: false,
|
|
6777
|
+
hiddenCounts: hiddenCounts.size > 0 ? hiddenCounts : undefined,
|
|
6778
|
+
activeTagGroup,
|
|
6779
|
+
hideDescriptions,
|
|
6780
|
+
});
|
|
6781
|
+
|
|
6782
|
+
const PADDING = 20;
|
|
6783
|
+
const titleOffset = effectiveParsed.title ? 30 : 0;
|
|
6784
|
+
const exportWidth = mmLayout.width + PADDING * 2;
|
|
6785
|
+
const exportHeight = mmLayout.height + PADDING * 2 + titleOffset;
|
|
6786
|
+
const container = createExportContainer(exportWidth, exportHeight);
|
|
6787
|
+
|
|
6788
|
+
const colorByDepth = viewState?.cbd === true;
|
|
6789
|
+
|
|
6790
|
+
renderMindmap(
|
|
6791
|
+
container,
|
|
6792
|
+
effectiveParsed,
|
|
6793
|
+
mmLayout,
|
|
6794
|
+
effectivePalette,
|
|
6795
|
+
isDark,
|
|
6796
|
+
undefined,
|
|
6797
|
+
{ width: exportWidth, height: exportHeight },
|
|
6798
|
+
undefined,
|
|
6799
|
+
hideDescriptions,
|
|
6800
|
+
colorByDepth ? null : activeTagGroup,
|
|
6801
|
+
colorByDepth ? { colorByDepth: true } : undefined
|
|
6802
|
+
);
|
|
6803
|
+
return finalizeSvgExport(container, theme, effectivePalette);
|
|
6804
|
+
}
|
|
6805
|
+
|
|
6806
|
+
if (detectedType === 'wireframe') {
|
|
6807
|
+
const { parseWireframe } = await import('./wireframe/parser');
|
|
6808
|
+
const { layoutWireframe } = await import('./wireframe/layout');
|
|
6809
|
+
const { renderWireframe } = await import('./wireframe/renderer');
|
|
6810
|
+
|
|
6811
|
+
const effectivePalette = await resolveExportPalette(theme, palette);
|
|
6812
|
+
const wireframeParsed = parseWireframe(content);
|
|
6813
|
+
if (
|
|
6814
|
+
wireframeParsed.error ||
|
|
6815
|
+
(wireframeParsed.roots.length === 0 &&
|
|
6816
|
+
wireframeParsed.modals.length === 0)
|
|
6817
|
+
)
|
|
6818
|
+
return '';
|
|
6819
|
+
|
|
6820
|
+
const wireframeLayout = layoutWireframe(wireframeParsed);
|
|
6821
|
+
|
|
6822
|
+
const exportWidth = wireframeLayout.width;
|
|
6823
|
+
const exportHeight = wireframeLayout.height;
|
|
6824
|
+
const container = createExportContainer(exportWidth, exportHeight);
|
|
6825
|
+
|
|
6826
|
+
renderWireframe(
|
|
6827
|
+
container,
|
|
6828
|
+
wireframeParsed,
|
|
6829
|
+
wireframeLayout,
|
|
6830
|
+
effectivePalette,
|
|
6831
|
+
theme === 'dark',
|
|
6832
|
+
undefined,
|
|
6833
|
+
{ width: exportWidth, height: exportHeight },
|
|
6834
|
+
theme
|
|
6835
|
+
);
|
|
6836
|
+
return finalizeSvgExport(container, theme, effectivePalette);
|
|
6952
6837
|
}
|
|
6953
6838
|
|
|
6954
6839
|
if (detectedType === 'c4') {
|
|
@@ -6966,10 +6851,18 @@ export async function renderForExport(
|
|
|
6966
6851
|
const c4Parsed = parseC4(content, effectivePalette);
|
|
6967
6852
|
if (c4Parsed.error || c4Parsed.elements.length === 0) return '';
|
|
6968
6853
|
|
|
6969
|
-
// Container/component-level rendering
|
|
6970
|
-
const c4Level =
|
|
6971
|
-
|
|
6972
|
-
|
|
6854
|
+
// Container/component-level rendering (viewState fallback for share links)
|
|
6855
|
+
const c4Level =
|
|
6856
|
+
options?.c4Level ??
|
|
6857
|
+
(viewState?.c4l as
|
|
6858
|
+
| 'context'
|
|
6859
|
+
| 'containers'
|
|
6860
|
+
| 'components'
|
|
6861
|
+
| 'deployment'
|
|
6862
|
+
| undefined) ??
|
|
6863
|
+
'context';
|
|
6864
|
+
const c4System = options?.c4System ?? viewState?.c4s;
|
|
6865
|
+
const c4Container = options?.c4Container ?? viewState?.c4c;
|
|
6973
6866
|
|
|
6974
6867
|
const c4Layout =
|
|
6975
6868
|
c4Level === 'deployment'
|
|
@@ -7006,10 +6899,10 @@ export async function renderForExport(
|
|
|
7006
6899
|
resolveActiveTagGroup(
|
|
7007
6900
|
c4Parsed.tagGroups,
|
|
7008
6901
|
c4Parsed.options['active-tag'],
|
|
7009
|
-
options?.tagGroup
|
|
6902
|
+
viewState?.tag ?? options?.tagGroup
|
|
7010
6903
|
)
|
|
7011
6904
|
);
|
|
7012
|
-
return finalizeSvgExport(container, theme, effectivePalette
|
|
6905
|
+
return finalizeSvgExport(container, theme, effectivePalette);
|
|
7013
6906
|
}
|
|
7014
6907
|
|
|
7015
6908
|
if (detectedType === 'flowchart') {
|
|
@@ -7033,7 +6926,7 @@ export async function renderForExport(
|
|
|
7033
6926
|
undefined,
|
|
7034
6927
|
{ width: EXPORT_WIDTH, height: EXPORT_HEIGHT }
|
|
7035
6928
|
);
|
|
7036
|
-
return finalizeSvgExport(container, theme, effectivePalette
|
|
6929
|
+
return finalizeSvgExport(container, theme, effectivePalette);
|
|
7037
6930
|
}
|
|
7038
6931
|
|
|
7039
6932
|
if (detectedType === 'infra') {
|
|
@@ -7052,7 +6945,7 @@ export async function renderForExport(
|
|
|
7052
6945
|
const activeTagGroup = resolveActiveTagGroup(
|
|
7053
6946
|
infraParsed.tagGroups,
|
|
7054
6947
|
infraParsed.options['active-tag'],
|
|
7055
|
-
options?.tagGroup
|
|
6948
|
+
viewState?.tag ?? options?.tagGroup
|
|
7056
6949
|
);
|
|
7057
6950
|
|
|
7058
6951
|
const titleOffset = infraParsed.title ? 40 : 0;
|
|
@@ -7078,7 +6971,8 @@ export async function renderForExport(
|
|
|
7078
6971
|
false,
|
|
7079
6972
|
null,
|
|
7080
6973
|
null,
|
|
7081
|
-
true
|
|
6974
|
+
true,
|
|
6975
|
+
viewState?.cg ? new Set(viewState.cg) : null
|
|
7082
6976
|
);
|
|
7083
6977
|
// Restore explicit pixel dimensions for resvg (renderer uses 100%/viewBox for app scaling)
|
|
7084
6978
|
const infraSvg = container.querySelector('svg');
|
|
@@ -7086,7 +6980,7 @@ export async function renderForExport(
|
|
|
7086
6980
|
infraSvg.setAttribute('width', String(exportWidth));
|
|
7087
6981
|
infraSvg.setAttribute('height', String(exportHeight));
|
|
7088
6982
|
}
|
|
7089
|
-
return finalizeSvgExport(container, theme, effectivePalette
|
|
6983
|
+
return finalizeSvgExport(container, theme, effectivePalette);
|
|
7090
6984
|
}
|
|
7091
6985
|
|
|
7092
6986
|
if (detectedType === 'gantt') {
|
|
@@ -7108,10 +7002,19 @@ export async function renderForExport(
|
|
|
7108
7002
|
resolved,
|
|
7109
7003
|
effectivePalette,
|
|
7110
7004
|
theme === 'dark',
|
|
7111
|
-
|
|
7005
|
+
{
|
|
7006
|
+
collapsedGroups: viewState?.cg ? new Set(viewState.cg) : undefined,
|
|
7007
|
+
currentSwimlaneGroup: viewState?.swim ?? undefined,
|
|
7008
|
+
collapsedLanes: viewState?.cl ? new Set(viewState.cl) : undefined,
|
|
7009
|
+
currentActiveGroup: resolveActiveTagGroup(
|
|
7010
|
+
resolved.tagGroups,
|
|
7011
|
+
resolved.options.activeTag ?? undefined,
|
|
7012
|
+
viewState?.tag ?? options?.tagGroup
|
|
7013
|
+
),
|
|
7014
|
+
},
|
|
7112
7015
|
{ width: EXPORT_W, height: EXPORT_H }
|
|
7113
7016
|
);
|
|
7114
|
-
return finalizeSvgExport(container, theme, effectivePalette
|
|
7017
|
+
return finalizeSvgExport(container, theme, effectivePalette);
|
|
7115
7018
|
}
|
|
7116
7019
|
|
|
7117
7020
|
if (detectedType === 'state') {
|
|
@@ -7135,7 +7038,7 @@ export async function renderForExport(
|
|
|
7135
7038
|
undefined,
|
|
7136
7039
|
{ width: EXPORT_WIDTH, height: EXPORT_HEIGHT }
|
|
7137
7040
|
);
|
|
7138
|
-
return finalizeSvgExport(container, theme, effectivePalette
|
|
7041
|
+
return finalizeSvgExport(container, theme, effectivePalette);
|
|
7139
7042
|
}
|
|
7140
7043
|
|
|
7141
7044
|
const parsed = parseVisualization(content, palette);
|
|
@@ -7209,9 +7112,9 @@ export async function renderForExport(
|
|
|
7209
7112
|
resolveActiveTagGroup(
|
|
7210
7113
|
parsed.timelineTagGroups,
|
|
7211
7114
|
undefined,
|
|
7212
|
-
|
|
7115
|
+
viewState?.tag ?? options?.tagGroup
|
|
7213
7116
|
),
|
|
7214
|
-
|
|
7117
|
+
viewState?.swim
|
|
7215
7118
|
);
|
|
7216
7119
|
} else if (parsed.type === 'venn') {
|
|
7217
7120
|
renderVenn(container, parsed, effectivePalette, isDark, undefined, dims);
|
|
@@ -7235,5 +7138,5 @@ export async function renderForExport(
|
|
|
7235
7138
|
);
|
|
7236
7139
|
}
|
|
7237
7140
|
|
|
7238
|
-
return finalizeSvgExport(container, theme, effectivePalette
|
|
7141
|
+
return finalizeSvgExport(container, theme, effectivePalette);
|
|
7239
7142
|
}
|