@caddis/cli 0.4.48 → 0.4.50
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/bundles/antigravity-plugin/plugin.json +1 -1
- package/bundles/antigravity-plugin/skills/flow-studio/SKILL.md +2 -2
- package/bundles/antigravity-plugin/skills/flow-studio/model.schema.json +4 -1
- package/bundles/antigravity-plugin/skills/flow-studio/react/FlowStudioView.test.tsx +18 -1
- package/bundles/antigravity-plugin/skills/flow-studio/react/FlowStudioView.tsx +6 -1
- package/bundles/antigravity-plugin/skills/flow-studio/react/README.md +1 -1
- package/bundles/antigravity-plugin/skills/flow-studio/references/design-language.md +5 -5
- package/bundles/antigravity-plugin/skills/flow-studio/references/model-schema.md +16 -0
- package/bundles/antigravity-plugin/skills/flow-studio/scripts/lib/styles.test.mjs +13 -4
- package/bundles/antigravity-plugin/skills/flow-studio/src/bars.test.ts +90 -0
- package/bundles/antigravity-plugin/skills/flow-studio/src/bars.ts +53 -0
- package/bundles/antigravity-plugin/skills/flow-studio/src/ctx.ts +3 -0
- package/bundles/antigravity-plugin/skills/flow-studio/src/engine.ts +8 -3
- package/bundles/antigravity-plugin/skills/flow-studio/src/layout.test.ts +17 -0
- package/bundles/antigravity-plugin/skills/flow-studio/src/layout.ts +2 -1
- package/bundles/antigravity-plugin/skills/flow-studio/src/model.ts +11 -0
- package/bundles/antigravity-plugin/skills/flow-studio/src/playbackui.ts +1 -1
- package/bundles/antigravity-plugin/skills/flow-studio/src/render.ts +4 -2
- package/bundles/antigravity-plugin/skills/flow-studio/src/styles.css +6 -1
- package/bundles/antigravity-plugin/skills/flow-studio/templates/engine.html +64 -7
- package/bundles/antigravity-plugin/skills/flow-studio/templates/flow-studio.css +6 -1
- package/bundles/antigravity-plugin/skills/flow-studio/templates/flow-studio.lib.mjs +58 -6
- package/bundles/antigravity-plugin/skills/flow-studio/templates/shell-body.html +1 -1
- package/bundles/codex/.codex/skills/frontend/flow-studio/SKILL.md +2 -2
- package/bundles/codex/.codex/skills/frontend/flow-studio/model.schema.json +4 -1
- package/bundles/codex/.codex/skills/frontend/flow-studio/react/FlowStudioView.test.tsx +18 -1
- package/bundles/codex/.codex/skills/frontend/flow-studio/react/FlowStudioView.tsx +6 -1
- package/bundles/codex/.codex/skills/frontend/flow-studio/react/README.md +1 -1
- package/bundles/codex/.codex/skills/frontend/flow-studio/references/design-language.md +5 -5
- package/bundles/codex/.codex/skills/frontend/flow-studio/references/model-schema.md +16 -0
- package/bundles/codex/.codex/skills/frontend/flow-studio/scripts/lib/styles.test.mjs +13 -4
- package/bundles/codex/.codex/skills/frontend/flow-studio/src/bars.test.ts +90 -0
- package/bundles/codex/.codex/skills/frontend/flow-studio/src/bars.ts +53 -0
- package/bundles/codex/.codex/skills/frontend/flow-studio/src/ctx.ts +3 -0
- package/bundles/codex/.codex/skills/frontend/flow-studio/src/engine.ts +8 -3
- package/bundles/codex/.codex/skills/frontend/flow-studio/src/layout.test.ts +17 -0
- package/bundles/codex/.codex/skills/frontend/flow-studio/src/layout.ts +2 -1
- package/bundles/codex/.codex/skills/frontend/flow-studio/src/model.ts +11 -0
- package/bundles/codex/.codex/skills/frontend/flow-studio/src/playbackui.ts +1 -1
- package/bundles/codex/.codex/skills/frontend/flow-studio/src/render.ts +4 -2
- package/bundles/codex/.codex/skills/frontend/flow-studio/src/styles.css +6 -1
- package/bundles/codex/.codex/skills/frontend/flow-studio/templates/engine.html +64 -7
- package/bundles/codex/.codex/skills/frontend/flow-studio/templates/flow-studio.css +6 -1
- package/bundles/codex/.codex/skills/frontend/flow-studio/templates/flow-studio.lib.mjs +58 -6
- package/bundles/codex/.codex/skills/frontend/flow-studio/templates/shell-body.html +1 -1
- package/bundles/manifest.json +2 -2
- package/package.json +1 -1
|
@@ -69,6 +69,8 @@ function validateModel(input) {
|
|
|
69
69
|
const metric = n.metrics;
|
|
70
70
|
const invalidSeries = metric?.series !== void 0 && (!Array.isArray(metric.series) || metric.series.length > 60 || metric.series.some((v) => !Number.isFinite(v)));
|
|
71
71
|
if (metric !== void 0 && (!metric || !Number.isFinite(metric.value) || metric.max != null && !Number.isFinite(metric.max) || invalidSeries)) add("error", "metric-invalid", w, "Metrics need finite values and at most 60 finite series points.");
|
|
72
|
+
const badBars = n.bars !== void 0 && (!Array.isArray(n.bars) || n.bars.length > 120 || n.bars.some((b) => !b || typeof b.key !== "string" || b.value !== null && (typeof b.value !== "number" || !Number.isFinite(b.value) || b.value < 0)));
|
|
73
|
+
if (badBars) add("error", "bars-invalid", w, "Bars need a list of at most 120 items, each with a string key and a finite, non-negative value or null.");
|
|
72
74
|
if (n.sla !== void 0 && (!Number.isFinite(n.sla) || n.sla <= 0)) add("error", "sla-invalid", w, "SLA must be a positive finite number of seconds.");
|
|
73
75
|
}
|
|
74
76
|
for (const n of nodes) {
|
|
@@ -749,6 +751,7 @@ function on(ctx, target, type, fn, opts) {
|
|
|
749
751
|
|
|
750
752
|
// src/layout.ts
|
|
751
753
|
var DEFAULTS = { pitch: 62, top: 64, gap: 34, padX: 24, visible: () => true };
|
|
754
|
+
var BARS_EXTRA = 26;
|
|
752
755
|
var LANE_PAD_TOP = 38;
|
|
753
756
|
var LANE_PAD_BOTTOM = 14;
|
|
754
757
|
function computeGeometry(m, opt = {}) {
|
|
@@ -762,7 +765,7 @@ function computeGeometry(m, opt = {}) {
|
|
|
762
765
|
const world = { w: Math.max(1, x - o.gap + o.padX), h: 1 };
|
|
763
766
|
const nodes = {};
|
|
764
767
|
for (const n of m.nodes) {
|
|
765
|
-
const h = NODE_HEIGHT[n.kind] ?? 54;
|
|
768
|
+
const h = (NODE_HEIGHT[n.kind] ?? 54) + (n.bars?.length ? BARS_EXTRA : 0);
|
|
766
769
|
if (m.layout === "free") {
|
|
767
770
|
nodes[n.id] = { id: n.id, x: n.x ?? 0, y: n.y ?? 0, w: n.w ?? 190, h: n.h ?? h };
|
|
768
771
|
continue;
|
|
@@ -884,6 +887,47 @@ function sparkline(metric, width = 56, height = 12) {
|
|
|
884
887
|
return `<svg class="spark" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" aria-hidden="true"><polyline points="${points}"/></svg>`;
|
|
885
888
|
}
|
|
886
889
|
|
|
890
|
+
// src/bars.ts
|
|
891
|
+
var BAR_UNIT = 4;
|
|
892
|
+
function barsHtml(bars, height = 22) {
|
|
893
|
+
if (!bars || bars.length === 0) return "";
|
|
894
|
+
const width = bars.length * BAR_UNIT;
|
|
895
|
+
const max = Math.max(1, ...bars.map((b) => b.value ?? 0));
|
|
896
|
+
const lastWithData = bars.map((b) => b.value !== null).lastIndexOf(true);
|
|
897
|
+
const rects = bars.map((b, i) => {
|
|
898
|
+
const x = i * BAR_UNIT;
|
|
899
|
+
const w = BAR_UNIT - 1;
|
|
900
|
+
const label = esc(b.label ?? (b.value === null ? `${b.key}: no data` : `${b.key}: ${b.value}`));
|
|
901
|
+
if (b.value === null) {
|
|
902
|
+
return `<rect class="miss" data-key="${esc(b.key)}" x="${x}" y="${height - 4}" width="${w}" height="4"><title>${label}</title></rect>`;
|
|
903
|
+
}
|
|
904
|
+
const h = Math.max(1, b.value / max * (height - 5));
|
|
905
|
+
const cls = b.kind === "low" ? "low" : i === lastWithData ? "last" : "";
|
|
906
|
+
return `<rect${cls ? ` class="${cls}"` : ""} data-key="${esc(b.key)}" x="${x}" y="${height - h}" width="${w}" height="${h}"><title>${label}</title></rect>`;
|
|
907
|
+
});
|
|
908
|
+
const first = esc(bars[0].key), last = esc(bars[bars.length - 1].key);
|
|
909
|
+
return `<svg class="bars" viewBox="0 0 ${width} ${height}" preserveAspectRatio="none" role="img" aria-label="Bars, ${first} to ${last}">${rects.join("")}</svg>`;
|
|
910
|
+
}
|
|
911
|
+
function markKey(root, key) {
|
|
912
|
+
for (const r of Array.from(root.querySelectorAll("rect[data-key]"))) {
|
|
913
|
+
if (key !== null && r.getAttribute("data-key") === key) r.setAttribute("data-hl", "true");
|
|
914
|
+
else r.removeAttribute("data-hl");
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
function installBars(ctx) {
|
|
918
|
+
const set = (key) => {
|
|
919
|
+
if (ctx.hoverKey === key) return;
|
|
920
|
+
ctx.hoverKey = key;
|
|
921
|
+
markKey(ctx.els.world, key);
|
|
922
|
+
ctx.onHoverKey?.(key);
|
|
923
|
+
};
|
|
924
|
+
on(ctx, ctx.els.world, "mouseover", (e) => {
|
|
925
|
+
const bar = e.target?.closest?.("rect[data-key]");
|
|
926
|
+
set(bar ? bar.getAttribute("data-key") : null);
|
|
927
|
+
});
|
|
928
|
+
on(ctx, ctx.els.world, "mouseleave", () => set(null));
|
|
929
|
+
}
|
|
930
|
+
|
|
887
931
|
// src/render.ts
|
|
888
932
|
function loopRoute(ctx, fromId, toId, from, to, channel) {
|
|
889
933
|
const detourFor = (end, other) => {
|
|
@@ -920,7 +964,7 @@ function nodeHtml(ctx, n) {
|
|
|
920
964
|
const arrow = n.kind === "chip" ? '<span aria-hidden="true">\u2191 </span>' : "";
|
|
921
965
|
const lead = showWord ? `<b class="ev st-${cssId(sid)}">${esc(word)}</b> \xB7 ` : "";
|
|
922
966
|
const fold = n.kind === "group" && n.contains?.length ? `<span class="fold">\u25B8 ${n.contains.length}</span>` : "";
|
|
923
|
-
return `<div class="t"><span class="newdot" title="Added in this view"></span><span class="name">${arrow}${esc(n.title)}</span>${fold}${badge}</div><div class="s${spark ? " has-spark" : ""}" title="${esc(sub)}">${lead}${esc(sub)}</div>${spark}${bar}${improved}${upgrade}`;
|
|
967
|
+
return `<div class="t"><span class="newdot" title="Added in this view"></span><span class="name">${arrow}${esc(n.title)}</span>${fold}${badge}</div><div class="s${spark ? " has-spark" : ""}" title="${esc(sub)}">${lead}${esc(sub)}</div>${spark}${barsHtml(n.bars)}${bar}${improved}${upgrade}`;
|
|
924
968
|
}
|
|
925
969
|
function build(ctx) {
|
|
926
970
|
const { model, els } = ctx;
|
|
@@ -955,7 +999,7 @@ function build(ctx) {
|
|
|
955
999
|
for (const n of model.nodes) {
|
|
956
1000
|
const p = ctx.geom.nodes[n.id];
|
|
957
1001
|
if (!p) continue;
|
|
958
|
-
const d = el("div", "node" + (n.kind === "chip" ? " ref" : "") + ((n.colSpan ?? 1) > 1 ? " wide" : ""));
|
|
1002
|
+
const d = el("div", "node" + (n.kind === "chip" ? " ref" : "") + ((n.colSpan ?? 1) > 1 ? " wide" : "") + (n.bars?.length ? " has-bars" : ""));
|
|
959
1003
|
d.id = "n_" + n.id;
|
|
960
1004
|
d.tabIndex = 0;
|
|
961
1005
|
d.setAttribute("role", "button");
|
|
@@ -1090,6 +1134,7 @@ function paint(ctx, fromSwitch = false) {
|
|
|
1090
1134
|
d.style.height = r.h + "px";
|
|
1091
1135
|
}
|
|
1092
1136
|
}
|
|
1137
|
+
markKey(ctx.els.world, ctx.hoverKey);
|
|
1093
1138
|
ctx.fn.buildChrome();
|
|
1094
1139
|
ctx.fn.trace(ctx.selected);
|
|
1095
1140
|
ctx.fn.renderInspector();
|
|
@@ -1983,7 +2028,7 @@ function install7(ctx) {
|
|
|
1983
2028
|
let t = 0, idx = -1, playing = false, frame = 0, timer = 0, stamp = 0, choicesKey = "";
|
|
1984
2029
|
let markedEdges = [];
|
|
1985
2030
|
let markedNodes = [];
|
|
1986
|
-
const token = sv("circle", { id: "token", class: "token", r: "
|
|
2031
|
+
const token = sv("circle", { id: "token", class: "token", r: "4" });
|
|
1987
2032
|
e.layer.appendChild(token);
|
|
1988
2033
|
const pathOf = (link) => ctx.edgeEls[ctx.links.findIndex((l) => l.id === link)];
|
|
1989
2034
|
const nodeOf = (id) => ctx.nodeEls.get(id);
|
|
@@ -2310,6 +2355,8 @@ function mount(root, model, opts = {}) {
|
|
|
2310
2355
|
root,
|
|
2311
2356
|
els,
|
|
2312
2357
|
onSelect: opts.onSelect,
|
|
2358
|
+
onHoverKey: opts.onHoverKey,
|
|
2359
|
+
hoverKey: null,
|
|
2313
2360
|
notes: opts.notes && opts.notes.length ? opts.notes : model.notes ?? [],
|
|
2314
2361
|
nodes: new Map(model.nodes.map((n) => [n.id, n])),
|
|
2315
2362
|
links: model.links,
|
|
@@ -2352,6 +2399,7 @@ function mount(root, model, opts = {}) {
|
|
|
2352
2399
|
style.textContent = stateCss(model.states);
|
|
2353
2400
|
install(ctx);
|
|
2354
2401
|
install2(ctx);
|
|
2402
|
+
installBars(ctx);
|
|
2355
2403
|
install3(ctx);
|
|
2356
2404
|
install4(ctx);
|
|
2357
2405
|
install5(ctx);
|
|
@@ -2398,6 +2446,10 @@ function mount(root, model, opts = {}) {
|
|
|
2398
2446
|
ctx.fn.fit(animate);
|
|
2399
2447
|
},
|
|
2400
2448
|
select: (id) => ctx.fn.select(id),
|
|
2449
|
+
highlightKey: (key) => {
|
|
2450
|
+
ctx.hoverKey = key;
|
|
2451
|
+
markKey(ctx.els.world, key);
|
|
2452
|
+
},
|
|
2401
2453
|
selected: () => ctx.selected,
|
|
2402
2454
|
mode: () => ctx.mode,
|
|
2403
2455
|
setMode: (id) => ctx.fn.setMode(id),
|
|
@@ -2423,7 +2475,7 @@ function mount(root, model, opts = {}) {
|
|
|
2423
2475
|
const changes = diffModels(ctx.model, prepared);
|
|
2424
2476
|
const saved = { view: { ...ctx.view }, mode: ctx.mode, selected: ctx.selected, inspectorOpen: els.inspector.classList.contains("open"), query: ctx.query, hops: ctx.hops, filter: ctx.filter, collapsed: new Set(ctx.collapsed), knownGroups: new Set(ctx.model.nodes.filter((n) => n.kind === "group").map((n) => n.id)), playback: playback.playback() };
|
|
2425
2477
|
api.destroy();
|
|
2426
|
-
const replacement = mount(root, prepared, { notes: opts.notes, onSelect: opts.onSelect, restore: saved });
|
|
2478
|
+
const replacement = mount(root, prepared, { notes: opts.notes, onSelect: opts.onSelect, onHoverKey: opts.onHoverKey, restore: saved });
|
|
2427
2479
|
notifySelection(saved.selected, replacement.selected(), opts.onSelect);
|
|
2428
2480
|
Object.assign(api, replacement);
|
|
2429
2481
|
window.FlowStudio = api;
|
|
@@ -2448,7 +2500,7 @@ function mount(root, model, opts = {}) {
|
|
|
2448
2500
|
}
|
|
2449
2501
|
|
|
2450
2502
|
// src/lib.ts
|
|
2451
|
-
var SHELL_BODY_HTML = "<header class=\"top\">\r\n <span class=\"brand\"><i></i>flow-studio</span>\r\n <span class=\"spacer\"></span>\r\n <button id=\"notesBtn\" type=\"button\" aria-pressed=\"false\">Implementation notes (N)</button>\r\n <button id=\"theme\" type=\"button\" aria-label=\"Toggle light and dark\">☀ / ☾</button>\r\n</header>\r\n<main>\r\n <div class=\"titlerow\"><h1 id=\"title\"></h1><span class=\"readline\" id=\"readat\"></span></div>\r\n <p class=\"help\" id=\"help\"></p>\r\n <div id=\"banner\" role=\"alert\" hidden></div>\r\n\r\n <section class=\"summary\"><div class=\"layerstrip\" id=\"layerstrip\" aria-label=\"Completeness by column\"></div><div class=\"tiles\" id=\"kpis\" aria-label=\"Summary\"></div></section>\r\n\r\n <div class=\"toolbar\">\r\n <div class=\"seggrp\" role=\"tablist\" aria-label=\"View\" id=\"modeSwitch\"></div>\r\n <input id=\"q\" type=\"search\" placeholder=\"Find a group or member… ( / )\" aria-label=\"Find a group or member\">\r\n <select id=\"hops\" aria-label=\"Search radius\"><option value=\"0\">This group</option><option value=\"1\">+1 hop</option><option value=\"2\">+2 hops</option><option value=\"3\">+3 hops</option></select>\r\n <span id=\"matchinfo\" class=\"note\" style=\"margin:0\"></span>\r\n </div>\r\n\r\n <div class=\"workspace\" id=\"workspace\">\r\n <section class=\"canvaswrap\">\r\n <div id=\"viewport\" tabindex=\"0\" role=\"application\" aria-label=\"Flow canvas. Scroll to zoom, drag to pan. Keys: V select, H hand, plus and minus zoom, 0 fit, 1 actual size, F zoom to selection, arrows pan.\">\r\n <div id=\"world\"><svg id=\"edges\" aria-hidden=\"true\"><defs><marker id=\"arr\" viewBox=\"0 0 8 8\" refX=\"7\" refY=\"4\" markerWidth=\"
|
|
2503
|
+
var SHELL_BODY_HTML = "<header class=\"top\">\r\n <span class=\"brand\"><i></i>flow-studio</span>\r\n <span class=\"spacer\"></span>\r\n <button id=\"notesBtn\" type=\"button\" aria-pressed=\"false\">Implementation notes (N)</button>\r\n <button id=\"theme\" type=\"button\" aria-label=\"Toggle light and dark\">☀ / ☾</button>\r\n</header>\r\n<main>\r\n <div class=\"titlerow\"><h1 id=\"title\"></h1><span class=\"readline\" id=\"readat\"></span></div>\r\n <p class=\"help\" id=\"help\"></p>\r\n <div id=\"banner\" role=\"alert\" hidden></div>\r\n\r\n <section class=\"summary\"><div class=\"layerstrip\" id=\"layerstrip\" aria-label=\"Completeness by column\"></div><div class=\"tiles\" id=\"kpis\" aria-label=\"Summary\"></div></section>\r\n\r\n <div class=\"toolbar\">\r\n <div class=\"seggrp\" role=\"tablist\" aria-label=\"View\" id=\"modeSwitch\"></div>\r\n <input id=\"q\" type=\"search\" placeholder=\"Find a group or member… ( / )\" aria-label=\"Find a group or member\">\r\n <select id=\"hops\" aria-label=\"Search radius\"><option value=\"0\">This group</option><option value=\"1\">+1 hop</option><option value=\"2\">+2 hops</option><option value=\"3\">+3 hops</option></select>\r\n <span id=\"matchinfo\" class=\"note\" style=\"margin:0\"></span>\r\n </div>\r\n\r\n <div class=\"workspace\" id=\"workspace\">\r\n <section class=\"canvaswrap\">\r\n <div id=\"viewport\" tabindex=\"0\" role=\"application\" aria-label=\"Flow canvas. Scroll to zoom, drag to pan. Keys: V select, H hand, plus and minus zoom, 0 fit, 1 actual size, F zoom to selection, arrows pan.\">\r\n <div id=\"world\"><svg id=\"edges\" aria-hidden=\"true\"><defs><marker id=\"arr\" viewBox=\"0 0 8 8\" refX=\"7\" refY=\"4\" markerWidth=\"6\" markerHeight=\"6\" markerUnits=\"userSpaceOnUse\" orient=\"auto\"><path d=\"M0 0 L8 4 L0 8 z\" fill=\"context-stroke\"/></marker></defs><g id=\"edgeLayer\"></g></svg></div>\r\n <div id=\"cols\" aria-hidden=\"true\"></div>\r\n <div id=\"tools\" role=\"toolbar\" aria-label=\"Canvas controls\" aria-orientation=\"vertical\"></div>\r\n <div id=\"zoomLabel\" aria-hidden=\"true\">100%</div>\r\n </div>\r\n <div id=\"playbar\" hidden aria-label=\"Scenario playback\">\r\n <select id=\"pbScenario\" aria-label=\"Scenario\"></select>\r\n <button id=\"pbPlay\" type=\"button\" aria-label=\"Play\">▶</button>\r\n <button id=\"pbStep\" type=\"button\" aria-label=\"Step\">Step</button>\r\n <button id=\"pbReset\" type=\"button\" aria-label=\"Reset\">Reset</button>\r\n <select id=\"pbSpeed\" aria-label=\"Speed\"><option value=\"0.5\">0.5x</option><option value=\"1\" selected>1x</option><option value=\"2\">2x</option></select>\r\n <input id=\"pbScrub\" type=\"range\" min=\"0\" max=\"1000\" value=\"0\" aria-label=\"Playback position\" aria-valuetext=\"Step 1 of 1\">\r\n <span id=\"pbCaption\"></span><span id=\"pbCounter\"></span><span id=\"pbChoices\"></span>\r\n </div>\r\n <div class=\"keyline\" id=\"legend\" aria-label=\"Legend\"></div>\r\n <aside class=\"insp\" id=\"inspector\" aria-label=\"Inspector\" aria-hidden=\"true\"></aside>\r\n </section>\r\n </div>\r\n <div id=\"live\" class=\"sr\" role=\"status\" aria-live=\"polite\"></div>\r\n\r\n <div class=\"ledger\" id=\"ledger\"></div>\r\n <details class=\"tableview\"><summary>Table view</summary><table class=\"sources\" id=\"tbl\"></table></details>\r\n <details class=\"spec\" id=\"spec\"><summary>Model reference (for the person or agent who builds this)</summary><div id=\"specbody\"></div></details>\r\n</main>\r\n<footer id=\"footer\"></footer>\r\n<aside id=\"drawer\" aria-label=\"Implementation notes\"><h2>Implementation notes</h2><p class=\"note\">Numbered markers on the page match these cards. Hover a card to find its place; click a marker to jump to its card.</p><div id=\"notelist\"></div></aside>\r\n\r\n";
|
|
2452
2504
|
export {
|
|
2453
2505
|
K_MAX,
|
|
2454
2506
|
K_MIN,
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
<div class="workspace" id="workspace">
|
|
22
22
|
<section class="canvaswrap">
|
|
23
23
|
<div id="viewport" tabindex="0" role="application" aria-label="Flow canvas. Scroll to zoom, drag to pan. Keys: V select, H hand, plus and minus zoom, 0 fit, 1 actual size, F zoom to selection, arrows pan.">
|
|
24
|
-
<div id="world"><svg id="edges" aria-hidden="true"><defs><marker id="arr" viewBox="0 0 8 8" refX="7" refY="4" markerWidth="
|
|
24
|
+
<div id="world"><svg id="edges" aria-hidden="true"><defs><marker id="arr" viewBox="0 0 8 8" refX="7" refY="4" markerWidth="6" markerHeight="6" markerUnits="userSpaceOnUse" orient="auto"><path d="M0 0 L8 4 L0 8 z" fill="context-stroke"/></marker></defs><g id="edgeLayer"></g></svg></div>
|
|
25
25
|
<div id="cols" aria-hidden="true"></div>
|
|
26
26
|
<div id="tools" role="toolbar" aria-label="Canvas controls" aria-orientation="vertical"></div>
|
|
27
27
|
<div id="zoomLabel" aria-hidden="true">100%</div>
|
package/bundles/manifest.json
CHANGED
package/package.json
CHANGED