@cardenelabs/dragon 0.35.1 → 0.36.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.
- package/README.md +41 -3
- package/dist/cli.cjs +597 -375
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +597 -375
- package/dist/cli.js.map +1 -1
- package/dist/export.cjs +104 -37
- package/dist/export.cjs.map +1 -1
- package/dist/export.d.cts +1 -1
- package/dist/export.d.ts +1 -1
- package/dist/export.js +104 -37
- package/dist/export.js.map +1 -1
- package/dist/index.cjs +833 -526
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -15
- package/dist/index.d.ts +21 -15
- package/dist/index.js +833 -526
- package/dist/index.js.map +1 -1
- package/dist/player.global.js +2 -2
- package/dist/{schema-BBWfniwH.d.cts → schema-9VLameDG.d.cts} +15 -3
- package/dist/{schema-BBWfniwH.d.ts → schema-9VLameDG.d.ts} +15 -3
- package/package.json +3 -2
- package/src/cli.ts +13 -14
- package/src/figure-text.ts +1 -1
- package/src/index.ts +4 -4
- package/src/look/values.ts +16 -4
- package/src/messages.ts +158 -80
- package/src/parser.ts +402 -245
- package/src/player.ts +80 -9
- package/src/printer.ts +90 -60
- package/src/render/parts.ts +28 -8
- package/src/render/svg.ts +128 -33
- package/src/schema.ts +1 -1
- package/src/tokenize.ts +11 -8
- package/src/view.ts +5 -2
- package/src/words.ts +39 -65
package/dist/export.cjs
CHANGED
|
@@ -288,8 +288,16 @@ var LOOK = {
|
|
|
288
288
|
stroke: { hair: 1, edge: 1.7, edgeOn: 2.25, arrow: 1.5, flow: 1.3, halo: 7, on: 1.75, glyph: 2, lifeline: 1.2, envelope: 1.5, badgeRing: 1.5 },
|
|
289
289
|
shadow: { near: 0.8, far: 4, nearY: 1, farY: 3 },
|
|
290
290
|
mini: { w: 168, pad: 8, title: 14, inset: 12, radius: 10 },
|
|
291
|
-
/**
|
|
292
|
-
|
|
291
|
+
/**
|
|
292
|
+
* 寄って追う見せ方の窓の高さの、幅に対する割合と下限。
|
|
293
|
+
* `fitMinH` は見える高さに収める時 (#3047) の窓の高さの下限で、これより低い枠では収めずに枠の中で送る。
|
|
294
|
+
* `narrow` は縦長の全体図を出す枠の幅の下限で、これより狭い枠 (携帯の幅) では全体図を出さずに窓へ幅を渡す (#3055)。
|
|
295
|
+
* `badgeRoom` は番号の丸が窓から外れる段で窓を寄せ直す時に、丸の周りに空ける幅 (#3046)。
|
|
296
|
+
* `headRoom` は時系列図の図の頭の箱の下端から、窓に線を見せ始める所までの幅 (#3118)。
|
|
297
|
+
* `head` は時系列図の窓の上端に貼る頭の列の頭の箱で、アイコンを外した名前と下の字の 2 段 (#3120)。
|
|
298
|
+
* `pad` は頭の列の上下の余白、`h` は箱の高さ、`nameY` と `subY` は箱の上端から名前と下の字の基準線まで
|
|
299
|
+
*/
|
|
300
|
+
follow: { aspect: 0.75, minH: 320, fitMinH: 160, ease: 0.6, narrow: 440, badgeRoom: 8, headRoom: 10, head: { pad: 8, h: 40, nameY: 17, subY: 31 } },
|
|
293
301
|
/** 色を混ぜる割合 (%) */
|
|
294
302
|
mix: { icon: 14, regionIcon: 16, regionIconEdge: 34, cap: 12, capEdge: 42, badgePast: 14, badgePastEdge: 70, mini: 62, miniBand: 16, miniBandEdge: 36, view: 6 },
|
|
295
303
|
/** 字の並びの基準線を、置きたい高さの真ん中からどれだけ下げるか */
|
|
@@ -3052,20 +3060,31 @@ function band(region) {
|
|
|
3052
3060
|
const mark = region.icon && ICONS[region.icon] ? `<rect class="dg-bi" x="${r1(x)}" y="${r1(y)}" width="${icon}" height="${icon}" rx="${iconRadius}"/>${glyph(region.icon, x + icon / 2, y + icon / 2, iconScale)}` : "";
|
|
3053
3061
|
return `<g style="${cs(region.color)}"><rect class="dg-band" x="${r1(region.x + 0.5)}" y="${r1(region.y + 0.5)}" width="${r1(region.w - 1)}" height="${r1(region.h - 1)}" rx="${radius}"/>${mark}${lines}${note}</g>`;
|
|
3054
3062
|
}
|
|
3055
|
-
function
|
|
3056
|
-
const { m, sh } = ctx;
|
|
3057
|
-
const { radius, icon, iconRadius, iconScale, iconY, nameY, subY } = LOOK.box;
|
|
3063
|
+
function subLines(box, m, changes, y) {
|
|
3058
3064
|
const seq = [[0, box.sub ?? "", "dg-ss"], ...changes];
|
|
3059
|
-
|
|
3065
|
+
return seq.map(([t, text2, cls], k) => {
|
|
3060
3066
|
const next = seq[k + 1]?.[0];
|
|
3061
3067
|
const anim = k === 0 ? next === void 0 ? "" : m.until(next - MOTION.untilFade) : next === void 0 ? m.rise(t) : m.rise(t, next - MOTION.untilFade);
|
|
3062
3068
|
if (text2 === "") return "";
|
|
3063
|
-
return `<g${anim ? ` class="dg-a" style="${anim}"` : ""}><text class="${cls}" x="${r1(box.cx)}" y="${r1(
|
|
3069
|
+
return `<g${anim ? ` class="dg-a" style="${anim}"` : ""}><text class="${cls}" x="${r1(box.cx)}" y="${r1(y)}" text-anchor="middle">${esc(text2)}</text></g>`;
|
|
3064
3070
|
}).join("");
|
|
3071
|
+
}
|
|
3072
|
+
function cardFrame(box, ctx, act, y, h) {
|
|
3073
|
+
const rect = (cls, extra = "") => `<rect class="${cls}" x="${r1(box.x)}" y="${r1(y)}" width="${r1(box.w)}" height="${h}" rx="${LOOK.box.radius}"${extra}/>`;
|
|
3074
|
+
return `${act ? `<g class="dg-a" style="${act}">${rect("dg-halo")}</g>` : ""}${rect("dg-st", ` ${ctx.sh}`)}${act ? `<g class="dg-a" style="${act}">${rect("dg-on")}</g>` : ""}`;
|
|
3075
|
+
}
|
|
3076
|
+
function card(box, ctx, on, changes) {
|
|
3077
|
+
const { icon, iconRadius, iconScale, iconY, nameY, subY } = LOOK.box;
|
|
3078
|
+
const subs = subLines(box, ctx.m, changes, box.cy + subY);
|
|
3065
3079
|
const act = on.length > 0 ? activeKf(ctx, on) : void 0;
|
|
3066
|
-
const rect = (cls, extra = "") => `<rect class="${cls}" x="${r1(box.x)}" y="${r1(box.y)}" width="${r1(box.w)}" height="${box.h}" rx="${radius}"${extra}/>`;
|
|
3067
3080
|
const mark = box.icon && ICONS[box.icon] ? `<rect class="dg-ic" x="${r1(box.cx - icon / 2)}" y="${r1(box.cy + iconY - icon / 2)}" width="${icon}" height="${icon}" rx="${iconRadius}"/>${glyph(box.icon, box.cx, box.cy + iconY, iconScale)}` : "";
|
|
3068
|
-
return `<g style="${cs(box.color)}">${
|
|
3081
|
+
return `<g style="${cs(box.color)}">${cardFrame(box, ctx, act, box.y, box.h)}${mark}<text class="dg-sn" x="${r1(box.cx)}" y="${r1(box.cy + nameY)}" text-anchor="middle">${esc(box.name)}</text>${subs}</g>`;
|
|
3082
|
+
}
|
|
3083
|
+
function headCard(box, ctx, on, changes) {
|
|
3084
|
+
const { pad: pad2, h, nameY, subY } = LOOK.follow.head;
|
|
3085
|
+
const subs = subLines(box, ctx.m, changes, pad2 + subY);
|
|
3086
|
+
const act = on.length > 0 ? activeKf(ctx, on) : void 0;
|
|
3087
|
+
return `<g style="${cs(box.color)}">${cardFrame(box, ctx, act, pad2, h)}<text class="dg-sn" x="${r1(box.cx)}" y="${r1(pad2 + nameY)}" text-anchor="middle">${esc(box.name)}</text>${subs}</g>`;
|
|
3069
3088
|
}
|
|
3070
3089
|
function lifeline(x, y1, y2) {
|
|
3071
3090
|
return `<line class="dg-ll" x1="${r1(x)}" y1="${r1(y1)}" x2="${r1(x)}" y2="${r1(y2)}"/>`;
|
|
@@ -3358,6 +3377,7 @@ var PART_CSS = [
|
|
|
3358
3377
|
`.dg-tg text{${font(TYPE.tag)};fill:var(--on-c)}`,
|
|
3359
3378
|
".dg-vp-bg{fill:var(--bg)}",
|
|
3360
3379
|
".dg-vp-frame{fill:none;stroke:var(--hair)}",
|
|
3380
|
+
".dg-hd-bg{fill:var(--bg)}",
|
|
3361
3381
|
".dg-mm-bg{fill:var(--surf);stroke:var(--hair)}",
|
|
3362
3382
|
`.dg-mm-t{${font(TYPE.miniTitle)};fill:var(--mute)}`,
|
|
3363
3383
|
".dg-mm-world{fill:var(--sunk);stroke:var(--hair)}",
|
|
@@ -3471,13 +3491,34 @@ function drawSvg(diagram, layout, timeline, palette, theme, follow) {
|
|
|
3471
3491
|
const content = Object.values(L).map((parts) => parts.join("")).join("");
|
|
3472
3492
|
const { near, far, nearY, farY } = LOOK.shadow;
|
|
3473
3493
|
const shadow = `<filter id="dg-sh-${id}" x="-20%" y="-30%" width="140%" height="180%"><feDropShadow dx="0" dy="${nearY}" stdDeviation="${near}" style="flood-color:var(--sh);flood-opacity:var(--shA)"/><feDropShadow dx="0" dy="${farY}" stdDeviation="${far}" style="flood-color:var(--sh);flood-opacity:var(--shB)"/></filter>`;
|
|
3474
|
-
const
|
|
3494
|
+
const heads = follow && layout.kind === "sequence" ? layout.boxes.map((box) => headCard(box, ctx, on.get(box.id) ?? [], subs.get(box.id) ?? [])).join("") : "";
|
|
3495
|
+
const view = follow ? followView(layout, timeline, diagram, m, id, content, follow, heads) : { body: `<rect class="dg-bg" width="${layout.width}" height="${layout.height}" rx="${LOOK.region.radius}"/>${content}`, w: layout.width, h: layout.height };
|
|
3475
3496
|
const css = `.dg-${id}{${FONT_VARS};--T:${timeline.total}s;${paletteVars(palette, theme)}}${PART_CSS}${m.frames.join("")}`;
|
|
3476
3497
|
return `<svg xmlns="http://www.w3.org/2000/svg" class="dg dg-${id}" viewBox="0 0 ${Math.ceil(view.w)} ${Math.ceil(view.h)}" width="${Math.ceil(view.w)}" height="${Math.ceil(view.h)}" role="img" aria-label="${esc(diagram.title)}" data-dragon="figure" data-view="${follow ? "follow" : "fixed"}"><style>${css}</style><defs>${shadow}</defs>${view.body}</svg>`;
|
|
3477
3498
|
}
|
|
3499
|
+
function union(rects) {
|
|
3500
|
+
const x = Math.min(...rects.map((r) => r.x));
|
|
3501
|
+
const y = Math.min(...rects.map((r) => r.y));
|
|
3502
|
+
return { x, y, w: Math.max(...rects.map((r) => r.x + r.w)) - x, h: Math.max(...rects.map((r) => r.y + r.h)) - y };
|
|
3503
|
+
}
|
|
3478
3504
|
function focusOf(layout, diagram, step) {
|
|
3505
|
+
const rects = focusParts(layout, diagram, step);
|
|
3506
|
+
return rects.length === 0 ? void 0 : union(rects);
|
|
3507
|
+
}
|
|
3508
|
+
function badgeFocus(badge2, parts, vw, vh) {
|
|
3509
|
+
const room = LOOK.badge.r + LOOK.follow.badgeRoom;
|
|
3510
|
+
const { x: bx, y: by } = badge2;
|
|
3511
|
+
const away = (p) => Math.hypot(Math.max(0, p.x - bx, bx - p.x - p.w), Math.max(0, p.y - by, by - p.y - p.h));
|
|
3512
|
+
let held = { x: bx - room, y: by - room, w: room * 2, h: room * 2 };
|
|
3513
|
+
for (const p of [...parts].sort((a, b) => away(a) - away(b))) {
|
|
3514
|
+
const next = union([held, p]);
|
|
3515
|
+
if (next.w <= vw && next.h <= vh) held = next;
|
|
3516
|
+
}
|
|
3517
|
+
return held;
|
|
3518
|
+
}
|
|
3519
|
+
function focusParts(layout, diagram, step) {
|
|
3479
3520
|
const rects = [];
|
|
3480
|
-
for (const e of layout.edges.filter((
|
|
3521
|
+
for (const e of layout.edges.filter((x) => x.step === step)) {
|
|
3481
3522
|
const xs = e.points.map((p) => p[0]);
|
|
3482
3523
|
const ys = e.points.map((p) => p[1]);
|
|
3483
3524
|
rects.push({ x: Math.min(...xs), y: Math.min(...ys), w: Math.max(...xs) - Math.min(...xs), h: Math.max(...ys) - Math.min(...ys) });
|
|
@@ -3490,24 +3531,44 @@ function focusOf(layout, diagram, step) {
|
|
|
3490
3531
|
if (box && (layout.kind === "architecture" || event.type === "swap")) rects.push(box);
|
|
3491
3532
|
}
|
|
3492
3533
|
}
|
|
3493
|
-
|
|
3494
|
-
const x = Math.min(...rects.map((r) => r.x));
|
|
3495
|
-
const y = Math.min(...rects.map((r) => r.y));
|
|
3496
|
-
return { x, y, w: Math.max(...rects.map((r) => r.x + r.w)) - x, h: Math.max(...rects.map((r) => r.y + r.h)) - y };
|
|
3534
|
+
return rects;
|
|
3497
3535
|
}
|
|
3498
|
-
function followView(layout, timeline, diagram, m, id, content, follow) {
|
|
3536
|
+
function followView(layout, timeline, diagram, m, id, content, follow, heads) {
|
|
3499
3537
|
const F = LOOK.follow;
|
|
3500
3538
|
const M = LOOK.mini;
|
|
3501
|
-
const
|
|
3502
|
-
const
|
|
3539
|
+
const frameWidth = Math.max(1, follow.width);
|
|
3540
|
+
const full = Math.min(layout.width, frameWidth);
|
|
3541
|
+
const title = FIGURE_TEXT[follow.lang].overview;
|
|
3542
|
+
const sized = (vh2) => {
|
|
3543
|
+
const mw2 = Math.min(M.w, full * 0.4, vh2 * 0.4 / layout.height * layout.width);
|
|
3544
|
+
const k2 = mw2 / layout.width;
|
|
3545
|
+
const mh2 = layout.height * k2;
|
|
3546
|
+
const bw2 = Math.max(mw2, Math.ceil(textWidth(title, TYPE.miniTitle)));
|
|
3547
|
+
return { vh: vh2, mw: mw2, k: k2, mh: mh2, bw: bw2, bgW: bw2 + M.pad * 2, bgH: mh2 + M.pad * 2 + M.title, beside: mh2 > mw2 };
|
|
3548
|
+
};
|
|
3549
|
+
const natural = sized(Math.min(layout.height, Math.max(F.minH, full * F.aspect)));
|
|
3550
|
+
const bare = natural.beside && frameWidth < F.narrow;
|
|
3551
|
+
const room = follow.height === void 0 ? Number.POSITIVE_INFINITY : natural.beside ? follow.height : follow.height - natural.bgH - M.inset;
|
|
3552
|
+
const { vh, mw, k, mh, bw, bgW, bgH, beside } = room < natural.vh ? sized(Math.max(F.fitMinH, room)) : { ...natural, vh: Number.isFinite(room) ? Math.min(layout.height, room) : natural.vh };
|
|
3553
|
+
const vw = beside && !bare ? Math.min(layout.width, frameWidth - bgW - M.inset) : full;
|
|
3503
3554
|
const clampX = (x) => Math.min(layout.width - vw / 2, Math.max(vw / 2, x));
|
|
3504
|
-
const
|
|
3555
|
+
const top = heads === "" ? 0 : Math.max(...layout.boxes.map((b) => b.y + b.h)) + F.headRoom;
|
|
3556
|
+
const strip2 = heads === "" ? 0 : F.head.pad * 2 + F.head.h;
|
|
3557
|
+
const below = vh - strip2;
|
|
3558
|
+
const clampY = (y) => Math.min(layout.height - below / 2, Math.max(top + below / 2, y));
|
|
3559
|
+
const r = LOOK.badge.r;
|
|
3505
3560
|
let prev = [layout.width / 2, layout.height / 2];
|
|
3506
|
-
const
|
|
3561
|
+
const middles = timeline.steps.map((_, s) => {
|
|
3507
3562
|
const f = focusOf(layout, diagram, s);
|
|
3508
3563
|
prev = f ? [f.x + f.w / 2, f.y + f.h / 2] : prev;
|
|
3564
|
+
const at2 = [clampX(prev[0]), clampY(prev[1])];
|
|
3565
|
+
const b = layout.badges.find((x) => x.step === s);
|
|
3566
|
+
if (!b || Math.abs(b.x - at2[0]) <= vw / 2 - r && Math.abs(b.y - at2[1]) <= below / 2 - r) return at2;
|
|
3567
|
+
const near = badgeFocus(b, focusParts(layout, diagram, s), vw, below);
|
|
3568
|
+
prev = [near.x + near.w / 2, near.y + near.h / 2];
|
|
3509
3569
|
return [clampX(prev[0]), clampY(prev[1])];
|
|
3510
3570
|
});
|
|
3571
|
+
const centers = middles.map(([x, y]) => [x, y - strip2 / 2]);
|
|
3511
3572
|
const c0 = centers[0];
|
|
3512
3573
|
const cam = [
|
|
3513
3574
|
[0, c0[0], c0[1]],
|
|
@@ -3522,22 +3583,26 @@ function followView(layout, timeline, diagram, m, id, content, follow) {
|
|
|
3522
3583
|
const cl = centers[centers.length - 1];
|
|
3523
3584
|
cam.push([timeline.last, cl[0], cl[1], 1, EASE.inOut], [timeline.total, c0[0], c0[1]]);
|
|
3524
3585
|
const camKf = m.move(cam.map(([t, cx, cy, s, e]) => [t, vw / 2 - cx, vh / 2 - cy, s, e]));
|
|
3525
|
-
const
|
|
3526
|
-
const
|
|
3527
|
-
const
|
|
3528
|
-
const title = FIGURE_TEXT[follow.lang].overview;
|
|
3529
|
-
const bw = Math.max(mw, Math.ceil(textWidth(title, TYPE.miniTitle)));
|
|
3530
|
-
const bx = vw - bw - M.inset - M.pad;
|
|
3586
|
+
const bgX = beside ? vw + M.inset : vw - bgW - M.inset;
|
|
3587
|
+
const bgY = beside ? 0 : vh + M.inset;
|
|
3588
|
+
const bx = bgX + M.pad;
|
|
3531
3589
|
const mx = bx + (bw - mw) / 2;
|
|
3532
|
-
const my =
|
|
3533
|
-
const
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3590
|
+
const my = bgY + M.pad + M.title;
|
|
3591
|
+
const overview = () => {
|
|
3592
|
+
const shapes = [
|
|
3593
|
+
...layout.regions.map((r3) => `<rect class="dg-mm-band" style="${cs(r3.color)}" x="${mx + r3.x * k}" y="${my + r3.y * k}" width="${r3.w * k}" height="${r3.h * k}" rx="3"/>`),
|
|
3594
|
+
...layout.boxes.map((b) => `<rect class="dg-mm-card" style="${cs(b.color)}" x="${mx + b.x * k}" y="${my + b.y * k}" width="${b.w * k}" height="${b.h * k}" rx="1.5"/>`)
|
|
3595
|
+
].join("");
|
|
3596
|
+
const vp = m.move(cam.map(([t, cx, cy, , e]) => [t, mx + (cx - vw / 2) * k, my + (cy - vh / 2) * k, 1, e]));
|
|
3597
|
+
return {
|
|
3598
|
+
clip: `<clipPath id="dg-mm-${id}"><rect x="${mx}" y="${my}" width="${mw}" height="${mh}" rx="4"/></clipPath>`,
|
|
3599
|
+
body: `<rect class="dg-mm-bg" x="${bgX}" y="${bgY}" width="${bgW}" height="${bgH}" rx="${M.radius}"/><text class="dg-mm-t" x="${bx}" y="${my - M.pad + 2}">${title}</text><g clip-path="url(#dg-mm-${id})"><rect class="dg-mm-world" x="${mx}" y="${my}" width="${mw}" height="${mh}"/>${shapes}<rect class="dg-mm-vp dg-a"${strip2 === 0 ? "" : ` y="${strip2 * k}"`} width="${vw * k}" height="${(vh - strip2) * k}" rx="2" style="${vp}"/></g>`
|
|
3600
|
+
};
|
|
3601
|
+
};
|
|
3602
|
+
const mini = bare ? { clip: "", body: "" } : overview();
|
|
3603
|
+
const head = strip2 === 0 ? "" : `<g class="dg-hd"><rect class="dg-hd-bg" width="${vw}" height="${strip2}"/><line class="dg-sep" x1="0" y1="${strip2}" x2="${vw}" y2="${strip2}"/><g class="dg-a" style="${m.move(cam.map(([t, cx, , s, e]) => [t, vw / 2 - cx, 0, s, e]))}">${heads}</g></g>`;
|
|
3604
|
+
const body = `<defs><clipPath id="dg-vp-${id}"><rect width="${vw}" height="${vh}" rx="${LOOK.region.radius}"/></clipPath>${mini.clip}</defs><g clip-path="url(#dg-vp-${id})"><rect class="dg-vp-bg" width="${vw}" height="${vh}"/><g class="dg-a" style="${camKf}">${content}</g>${head}</g><rect class="dg-vp-frame" x="0.5" y="0.5" width="${vw - 1}" height="${vh - 1}" rx="${LOOK.region.radius}"/>${mini.body}`;
|
|
3605
|
+
return { body, w: beside && !bare ? vw + M.inset + bgW : full, h: beside ? vh : bgY + bgH };
|
|
3541
3606
|
}
|
|
3542
3607
|
function renderDiagram(input, options = {}) {
|
|
3543
3608
|
const lang = options.lang ?? "ja";
|
|
@@ -3561,8 +3626,10 @@ function renderDiagram(input, options = {}) {
|
|
|
3561
3626
|
}
|
|
3562
3627
|
|
|
3563
3628
|
// src/view.ts
|
|
3564
|
-
function chooseView(rendered, frameWidth) {
|
|
3565
|
-
const
|
|
3629
|
+
function chooseView(rendered, frameWidth, frameHeight) {
|
|
3630
|
+
const byWidth = Math.max(0, frameWidth) / rendered.layout.width;
|
|
3631
|
+
const scale = byWidth ;
|
|
3632
|
+
const textPx = scale * TYPE.boxName.size;
|
|
3566
3633
|
if (rendered.view) return { mode: rendered.view, textPx };
|
|
3567
3634
|
return { mode: textPx >= READABLE_PX ? "fixed" : "follow", textPx };
|
|
3568
3635
|
}
|