🚀. Socket Launch Week Day 3:Socket Firewall Now Blocks Malicious VS Code and Open VSX Extensions.Learn more
Sign In

@agent-format/renderer

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@agent-format/renderer - npm Package Compare versions

Comparing version
0.1.4
to
0.1.5
+307
-459
dist/index.cjs

@@ -26,4 +26,6 @@ "use strict";

downloadPrintableHtml: () => downloadPrintableHtml,
findVariantComponent: () => findVariantComponent,
openInViewer: () => openInViewer,
useHost: () => useHost
useHost: () => useHost,
usePlugins: () => usePlugins
});

@@ -421,5 +423,292 @@ module.exports = __toCommonJS(index_exports);

// src/sections/InheritanceDiagramSection.tsx
// src/sections/FamilyGraphSection.tsx
var import_react = require("react");
// src/plugins.ts
function findVariantComponent(plugins, sectionType, variant) {
if (!variant) return void 0;
for (const plugin of plugins) {
const component = plugin.variants?.[sectionType]?.[variant];
if (component) return component;
}
return void 0;
}
// src/sections/FamilyGraphSection.tsx
var import_jsx_runtime13 = require("react/jsx-runtime");
var MAX_GENERATIONS = 8;
var CARD_W = 220;
var CARD_H = 120;
var COL_GAP = 40;
var ROW_GAP = 80;
var MARGIN_X = 20;
var MARGIN_Y = 20;
function FamilyGraphSectionView({ section, setHeaderActions }) {
const plugins = usePlugins();
const variant = section.data?.variant;
const VariantComponent = findVariantComponent(plugins, "family-graph", variant);
if (VariantComponent) {
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(VariantComponent, { section, setHeaderActions });
}
if (section.type === "inheritance-diagram") {
const AliasComponent = findVariantComponent(plugins, "inheritance-diagram", variant);
if (AliasComponent) {
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(AliasComponent, { section, setHeaderActions });
}
}
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DefaultGenealogy, { section });
}
function DefaultGenealogy({ section }) {
const persons = section.data?.persons ?? [];
const rels = section.data?.relationships ?? [];
const focusedId = section.data?.focusedPersonId;
const layout = (0, import_react.useMemo)(() => computeLayout(persons, rels), [persons, rels]);
if (persons.length === 0) {
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "af-empty", children: "No persons in diagram." });
}
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "af-family-graph", style: { overflow: "auto" }, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
"svg",
{
xmlns: "http://www.w3.org/2000/svg",
width: layout.width,
height: layout.height,
viewBox: `0 0 ${layout.width} ${layout.height}`,
role: "img",
"aria-label": "Family graph",
children: [
layout.parentChildEdges.map((edge, i) => {
const p = cardById(layout, edge.parent);
const c = cardById(layout, edge.child);
if (!p || !c) return null;
const px = p.x + CARD_W / 2;
const py = p.y + CARD_H;
const cx = c.x + CARD_W / 2;
const cy = c.y;
const midY = (py + cy) / 2;
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
"polyline",
{
points: `${px},${py} ${px},${midY} ${cx},${midY} ${cx},${cy}`,
fill: "none",
stroke: "currentColor",
strokeWidth: "1.2",
opacity: "0.6"
},
`pc-${i}`
);
}),
layout.spouseEdges.map((edge, i) => {
const a = cardById(layout, edge.a);
const b = cardById(layout, edge.b);
if (!a || !b) return null;
const ay = a.y + CARD_H / 2;
const by = b.y + CARD_H / 2;
const ax = a.x + CARD_W;
const bx = b.x;
if (a.y !== b.y) {
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
"line",
{
x1: a.x + CARD_W / 2,
y1: ay,
x2: b.x + CARD_W / 2,
y2: by,
stroke: "currentColor",
strokeWidth: "1.2",
strokeDasharray: edge.dissolved ? "4 3" : void 0,
opacity: "0.6"
},
`sp-${i}`
);
}
const mid = (ay + by) / 2;
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("g", { children: [
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
"line",
{
x1: ax,
y1: mid - 3,
x2: bx,
y2: mid - 3,
stroke: "currentColor",
strokeWidth: "1.2",
strokeDasharray: edge.dissolved ? "4 3" : void 0,
opacity: "0.8"
}
),
!edge.dissolved && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
"line",
{
x1: ax,
y1: mid + 3,
x2: bx,
y2: mid + 3,
stroke: "currentColor",
strokeWidth: "1.2",
opacity: "0.8"
}
)
] }, `sp-${i}`);
}),
layout.cards.map((card) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
PersonCard,
{
person: card.person,
x: card.x,
y: card.y,
focused: card.id === focusedId
},
card.id
))
]
}
) });
}
function cardById(layout, id) {
return layout.cards.find((c) => c.id === id);
}
function PersonCard({
person,
x,
y,
focused
}) {
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("g", { transform: `translate(${x}, ${y})`, children: [
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
"rect",
{
width: CARD_W,
height: CARD_H,
rx: 8,
fill: focused ? "var(--af-accent-soft, #eef2ff)" : "var(--af-bg-alt, #f7f7f8)",
stroke: focused ? "var(--af-accent, #2251ff)" : "var(--af-border, #e5e7eb)",
strokeWidth: focused ? 2 : 1
}
),
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("text", { x: 12, y: 24, fontSize: "14", fontWeight: "600", fill: "currentColor", children: person.name }),
person.role && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
"text",
{
x: 12,
y: 44,
fontSize: "11",
fill: "currentColor",
opacity: "0.7",
children: person.role
}
),
person.birthday && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("text", { x: 12, y: 66, fontSize: "11", fill: "currentColor", opacity: "0.7", children: [
"b. ",
person.birthday
] }),
person.deathDate && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("text", { x: 12, y: 82, fontSize: "11", fill: "currentColor", opacity: "0.7", children: [
"d. ",
person.deathDate
] }),
person.address && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("text", { x: 12, y: 100, fontSize: "10", fill: "currentColor", opacity: "0.55", children: truncate(person.address, 30) })
] });
}
function truncate(s, max) {
return s.length <= max ? s : s.slice(0, max - 1) + "\u2026";
}
function computeLayout(persons, rels) {
const byId = new Map(persons.map((p) => [p.id, p]));
const childrenOf = /* @__PURE__ */ new Map();
const parentsOf = /* @__PURE__ */ new Map();
const spouseEdges = [];
for (const r of rels) {
if (r.type === "parent-child") {
if (!byId.has(r.person1Id) || !byId.has(r.person2Id)) continue;
if (!childrenOf.has(r.person1Id)) childrenOf.set(r.person1Id, []);
childrenOf.get(r.person1Id).push(r.person2Id);
if (!parentsOf.has(r.person2Id)) parentsOf.set(r.person2Id, []);
parentsOf.get(r.person2Id).push(r.person1Id);
} else if (r.type === "spouse") {
if (!byId.has(r.person1Id) || !byId.has(r.person2Id)) continue;
spouseEdges.push({
a: r.person1Id,
b: r.person2Id,
dissolved: r.dissolved
});
}
}
const depth = /* @__PURE__ */ new Map();
const seeds = persons.filter((p) => !parentsOf.has(p.id)).map((p) => p.id);
const queue = seeds.map((id) => ({ id, d: 0 }));
while (queue.length > 0) {
const { id, d } = queue.shift();
if (d > MAX_GENERATIONS) continue;
if (depth.has(id)) continue;
depth.set(id, d);
for (const childId of childrenOf.get(id) ?? []) {
if (!depth.has(childId)) queue.push({ id: childId, d: d + 1 });
}
}
for (const s of spouseEdges) {
if (!depth.has(s.a) && depth.has(s.b)) depth.set(s.a, depth.get(s.b));
if (!depth.has(s.b) && depth.has(s.a)) depth.set(s.b, depth.get(s.a));
}
for (const p of persons) {
if (!depth.has(p.id)) depth.set(p.id, 0);
}
const byGen = /* @__PURE__ */ new Map();
for (const p of persons) {
const d = depth.get(p.id);
if (!byGen.has(d)) byGen.set(d, []);
byGen.get(d).push(p);
}
const sortedGens = Array.from(byGen.entries()).sort((a, b) => a[0] - b[0]);
for (const [, row] of sortedGens) {
placeSpousesAdjacent(row, spouseEdges);
}
const rowCount = Math.max(...sortedGens.map(([, r]) => r.length), 1);
const rowWidth = rowCount * CARD_W + (rowCount - 1) * COL_GAP;
const cards = [];
sortedGens.forEach(([d, row]) => {
const y = MARGIN_Y + d * (CARD_H + ROW_GAP);
const thisRowWidth = row.length * CARD_W + (row.length - 1) * COL_GAP;
const offsetX = MARGIN_X + (rowWidth - thisRowWidth) / 2;
row.forEach((p, i) => {
cards.push({
id: p.id,
person: p,
x: offsetX + i * (CARD_W + COL_GAP),
y
});
});
});
const width = MARGIN_X * 2 + rowWidth;
const height = MARGIN_Y * 2 + sortedGens.length * CARD_H + Math.max(sortedGens.length - 1, 0) * ROW_GAP;
const parentChildEdges = [];
for (const r of rels) {
if (r.type !== "parent-child") continue;
if (!byId.has(r.person1Id) || !byId.has(r.person2Id)) continue;
parentChildEdges.push({ parent: r.person1Id, child: r.person2Id });
}
return { cards, parentChildEdges, spouseEdges, width, height };
}
function placeSpousesAdjacent(row, spouseEdges) {
for (const edge of spouseEdges) {
const ai = row.findIndex((p) => p.id === edge.a);
const bi = row.findIndex((p) => p.id === edge.b);
if (ai < 0 || bi < 0 || Math.abs(ai - bi) === 1) continue;
const [b] = row.splice(bi, 1);
const insertAt = ai < bi ? ai + 1 : ai;
row.splice(insertAt, 0, b);
}
}
// src/sections/Fallback.tsx
var import_jsx_runtime14 = require("react/jsx-runtime");
function FallbackSectionView({ section }) {
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "af-fallback", children: [
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
"Renderer for section type ",
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("strong", { children: section.type }),
" is not yet implemented in this viewer."
] }),
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("pre", { children: JSON.stringify(section.data, null, 2) })
] });
}
// src/host.ts

@@ -541,460 +830,12 @@ function fallbackOpenLink(url) {

// src/sections/InheritanceDiagramSection.tsx
var import_jsx_runtime13 = require("react/jsx-runtime");
var MAX_GENERATIONS = 6;
var LINE_H = 22;
var NAME_SIZE = 16;
var NAME_LINE_H = 22;
var DBL_GAP = 4;
var HORIZ_Y_GAP = 90;
var CHILD_V_GAP = 30;
var GEN_X_STEP = 340;
var SPOUSE_GAP = 90;
var TEXT_X = 60;
var CHILD_TEXT_X = 480;
var TRUNK_X = CHILD_TEXT_X - 30;
var DBL_X = 80;
var DEC_TOP_Y = 20;
function InheritanceDiagramSectionView({ section, setHeaderActions }) {
const data = section.data;
const persons = data?.persons ?? [];
const rels = data?.relationships ?? [];
const variant = data?.variant ?? "jp-court";
const svgRef = (0, import_react.useRef)(null);
const host = useHost();
(0, import_react.useEffect)(() => {
if (!setHeaderActions) return;
if (!svgRef.current) return;
if (persons.length === 0 || variant !== "jp-court") {
setHeaderActions(null);
return;
}
const sectionLabel = section.label || "\u76F8\u7D9A\u95A2\u4FC2\u8AAC\u660E\u56F3";
const documentTitle = sectionLabel;
const headerTitle = "\u76F8 \u7D9A \u95A2 \u4FC2 \u8AAC \u660E \u56F3";
const onClick = () => {
const svgEl = svgRef.current;
if (!svgEl) return;
const serialized = new XMLSerializer().serializeToString(svgEl);
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
void downloadPrintableHtml({
svgMarkup: serialized,
titleLabel: headerTitle,
documentTitle,
filename: `inheritance-diagram-${today}.html`,
host
});
};
setHeaderActions(
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
"button",
{
type: "button",
className: "af-action-btn",
onClick,
title: "\u5370\u5237\u30FBPDF \u4FDD\u5B58\u7528\u306E HTML \u3092\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\uFF08\u958B\u3044\u3066 \u2318P \u3067 PDF \u4FDD\u5B58\u3001\u88C1\u5224\u6240\u63D0\u51FA\u7528 A3 \u6A2A\u66F8\u5F0F\uFF09",
children: [
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { "aria-hidden": true, children: "\u2B07" }),
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "PDF" })
]
}
)
);
return () => setHeaderActions(null);
}, [setHeaderActions, section.id, section.label, persons.length, variant, host]);
if (persons.length === 0) {
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "af-empty", children: "No persons in diagram." });
}
if (variant !== "jp-court") {
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("p", { className: "af-empty", children: [
'Inheritance-diagram variant "',
variant,
'" is not yet implemented. Only "jp-court" is supported in v0.1.'
] });
}
const focused = data?.focusedPersonId ? persons.find((p) => p.id === data.focusedPersonId) : null;
const decedent = focused || persons.find((p) => Boolean(p.deathDate)) || persons[0];
if (!decedent) return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "af-empty", children: "No decedent." });
const findSpouseOfRoot = () => {
const rel = rels.find(
(r) => r.type === "spouse" && (r.person1Id === decedent.id || r.person2Id === decedent.id)
);
if (!rel) return null;
const sid = rel.person1Id === decedent.id ? rel.person2Id : rel.person1Id;
return persons.find((p) => p.id === sid) ?? null;
};
const findChildren = (parentId, spouseId) => {
const pids = /* @__PURE__ */ new Set([parentId]);
if (spouseId) pids.add(spouseId);
const kids = [];
const seen = /* @__PURE__ */ new Set();
for (const r of rels) {
if (r.type === "parent-child" && pids.has(r.person1Id)) {
if (seen.has(r.person2Id)) continue;
const c = persons.find((p) => p.id === r.person2Id);
if (c) {
seen.add(r.person2Id);
kids.push(c);
}
}
}
return kids;
};
const findSpouse = (personId) => {
const rel = rels.find(
(r) => r.type === "spouse" && r.person1Id !== decedent.id && r.person2Id !== decedent.id && (r.person1Id === personId || r.person2Id === personId)
);
if (!rel) return null;
const sid = rel.person1Id === personId ? rel.person2Id : rel.person1Id;
return persons.find((p) => p.id === sid) ?? null;
};
const blockHeight = (p) => {
let n = 0;
if (p.address) n++;
if (p.birthday) n++;
if (p.deathDate) n++;
n++;
return n * LINE_H + NAME_LINE_H;
};
let elementKey = 0;
const nextKey = () => `el-${++elementKey}`;
const renderBlock = (p, x, topY, roleLabel) => {
const elements = [];
let y = topY;
if (p.address) {
const lbl = roleLabel === "\u88AB\u76F8\u7D9A\u4EBA" ? "\u6700\u5F8C\u306E\u4F4F\u6240" : "\u4F4F\u6240";
elements.push(
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("text", { x, y, fontSize: "11pt", children: `${lbl}\u3000${p.address}` }, nextKey())
);
y += LINE_H;
}
if (p.birthday) {
elements.push(
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("text", { x, y, fontSize: "11pt", children: `\u51FA\u751F\u3000${p.birthday}` }, nextKey())
);
y += LINE_H;
}
if (p.deathDate) {
elements.push(
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("text", { x, y, fontSize: "11pt", children: `\u6B7B\u4EA1\u3000${p.deathDate}` }, nextKey())
);
y += LINE_H;
}
elements.push(
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("text", { x: x + 8, y, fontSize: "11pt", children: `\uFF08${roleLabel}\uFF09` }, nextKey())
);
y += LINE_H;
elements.push(
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
"text",
{
x,
y,
fontSize: `${NAME_SIZE}pt`,
fontWeight: "bold",
letterSpacing: "0.2em",
children: p.name
},
nextKey()
)
);
const nameBaseY = y;
y += NAME_LINE_H;
return { elements, nameBaseY, blockEndY: y };
};
const measureChildSlot = (c, depth) => {
if (depth > MAX_GENERATIONS) return blockHeight(c);
let h = blockHeight(c);
const sp = findSpouse(c.id);
if (sp) h += SPOUSE_GAP + blockHeight(sp);
const grandkids = findChildren(c.id, sp ? sp.id : null);
if (grandkids.length > 0) {
const subH = measureChildGroup(grandkids, depth + 1);
h = Math.max(h, subH);
}
return h;
};
const measureChildGroup = (childList, depth) => {
let total = 0;
childList.forEach((c, i) => {
if (i > 0) total += CHILD_V_GAP;
total += measureChildSlot(c, depth);
});
return total;
};
const lineProps = {
stroke: "#000",
strokeWidth: 1.2
};
const renderChildGroup = (childList, textX, startY, depth) => {
const elements = [];
const nameYs = [];
let cy = startY;
if (depth > MAX_GENERATIONS) {
elements.push(
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
"text",
{
x: textX,
y: cy,
fontSize: "11pt",
fill: "#999",
children: [
"\u2026 (tree truncated at generation ",
MAX_GENERATIONS,
")"
]
},
nextKey()
)
);
return { elements, nameYs, endY: cy + LINE_H };
}
childList.forEach((c, i) => {
if (i > 0) cy += CHILD_V_GAP;
const cb = renderBlock(c, textX, cy, c.role || "\u76F8\u7D9A\u4EBA");
elements.push(...cb.elements);
nameYs.push(cb.nameBaseY);
const childSpouse = findSpouse(c.id);
let connectorY = cb.nameBaseY;
if (childSpouse) {
const spTopY = cb.blockEndY + SPOUSE_GAP;
const spBlock2 = renderBlock(
childSpouse,
textX,
spTopY,
childSpouse.role || "\u914D\u5076\u8005"
);
elements.push(...spBlock2.elements);
const miniDblX = textX + 20;
const miniGapTop = cb.blockEndY + 5;
const miniGapBot = spTopY - 25;
elements.push(
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
"line",
{
x1: miniDblX - DBL_GAP,
y1: miniGapTop,
x2: miniDblX - DBL_GAP,
y2: miniGapBot,
...lineProps
},
nextKey()
)
);
elements.push(
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
"line",
{
x1: miniDblX + DBL_GAP,
y1: miniGapTop,
x2: miniDblX + DBL_GAP,
y2: miniGapBot,
...lineProps
},
nextKey()
)
);
connectorY = cb.blockEndY + SPOUSE_GAP / 2;
}
const grandkids = findChildren(c.id, childSpouse ? childSpouse.id : null);
if (grandkids.length > 0) {
const gcTextX = textX + GEN_X_STEP;
const gcTrunkX = gcTextX - 30;
const gcResult = renderChildGroup(grandkids, gcTextX, cy, depth + 1);
elements.push(...gcResult.elements);
elements.push(
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
"line",
{
x1: textX + 180,
y1: connectorY,
x2: gcTrunkX,
y2: connectorY,
...lineProps
},
nextKey()
)
);
if (gcResult.nameYs.length > 0) {
const gcTrunkTop = Math.min(connectorY, gcResult.nameYs[0]);
const gcTrunkBot = Math.max(
connectorY,
gcResult.nameYs[gcResult.nameYs.length - 1]
);
elements.push(
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
"line",
{
x1: gcTrunkX,
y1: gcTrunkTop,
x2: gcTrunkX,
y2: gcTrunkBot,
...lineProps
},
nextKey()
)
);
gcResult.nameYs.forEach((gny) => {
elements.push(
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
"line",
{
x1: gcTrunkX,
y1: gny,
x2: gcTextX - 5,
y2: gny,
...lineProps
},
nextKey()
)
);
});
}
}
cy += measureChildSlot(c, depth);
});
return { elements, nameYs, endY: cy };
};
const dec = renderBlock(decedent, TEXT_X, DEC_TOP_Y, "\u88AB\u76F8\u7D9A\u4EBA");
const spouse = findSpouseOfRoot();
const spouseTopY = dec.blockEndY + HORIZ_Y_GAP;
const spBlock = spouse ? renderBlock(spouse, TEXT_X, spouseTopY, spouse.role || "\u76F8\u7D9A\u4EBA") : null;
const dblMidY = dec.blockEndY + HORIZ_Y_GAP / 2;
const children = findChildren(decedent.id, spouse ? spouse.id : null);
const totalChildH = children.length > 0 ? measureChildGroup(children, 0) : 0;
let childGroupTopY = dblMidY - totalChildH / 2;
if (childGroupTopY < 10) childGroupTopY = 10;
const childResult = children.length > 0 ? renderChildGroup(children, CHILD_TEXT_X, childGroupTopY, 0) : { elements: [], nameYs: [], endY: childGroupTopY };
const svgH = Math.max(spBlock ? spBlock.blockEndY : dec.blockEndY, childResult.endY) + 30;
const svgParts = [];
svgParts.push(...dec.elements);
if (spBlock) svgParts.push(...spBlock.elements);
if (spouse) {
const gapTop = dec.blockEndY + 5;
const gapBot = spouseTopY - 25;
svgParts.push(
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
"line",
{
x1: DBL_X - DBL_GAP,
y1: gapTop,
x2: DBL_X - DBL_GAP,
y2: gapBot,
...lineProps
},
nextKey()
)
);
svgParts.push(
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
"line",
{
x1: DBL_X + DBL_GAP,
y1: gapTop,
x2: DBL_X + DBL_GAP,
y2: gapBot,
...lineProps
},
nextKey()
)
);
if (children.length > 0) {
svgParts.push(
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
"line",
{
x1: DBL_X + DBL_GAP,
y1: dblMidY,
x2: TRUNK_X,
y2: dblMidY,
...lineProps
},
nextKey()
)
);
}
} else if (children.length > 0) {
svgParts.push(
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
"line",
{
x1: TEXT_X + 200,
y1: dec.nameBaseY,
x2: TRUNK_X,
y2: dec.nameBaseY,
...lineProps
},
nextKey()
)
);
}
svgParts.push(...childResult.elements);
if (childResult.nameYs.length > 0) {
const trunkTop = Math.min(
spouse ? dblMidY : dec.nameBaseY,
childResult.nameYs[0]
);
const trunkBot = childResult.nameYs[childResult.nameYs.length - 1];
svgParts.push(
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
"line",
{
x1: TRUNK_X,
y1: trunkTop,
x2: TRUNK_X,
y2: trunkBot,
...lineProps
},
nextKey()
)
);
childResult.nameYs.forEach((cny) => {
svgParts.push(
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
"line",
{
x1: TRUNK_X,
y1: cny,
x2: CHILD_TEXT_X - 5,
y2: cny,
...lineProps
},
nextKey()
)
);
});
}
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "af-inheritance-diagram", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
"svg",
{
ref: svgRef,
xmlns: "http://www.w3.org/2000/svg",
width: "100%",
viewBox: `0 0 1400 ${svgH}`,
style: { overflow: "visible" },
children: svgParts
}
) });
}
// src/sections/Fallback.tsx
var import_jsx_runtime14 = require("react/jsx-runtime");
function FallbackSectionView({ section }) {
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "af-fallback", children: [
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
"Renderer for section type ",
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("strong", { children: section.type }),
" is not yet implemented in this viewer."
] }),
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("pre", { children: JSON.stringify(section.data, null, 2) })
] });
}
// src/index.tsx
var import_jsx_runtime15 = require("react/jsx-runtime");
var HostContext = (0, import_react2.createContext)(void 0);
var PluginsContext = (0, import_react2.createContext)([]);
function useHost() {
return (0, import_react2.useContext)(HostContext);
}
function usePlugins() {
return (0, import_react2.useContext)(PluginsContext);
}
function AgentRenderer({

@@ -1004,6 +845,7 @@ data,

host,
showOpenInViewer = true
showOpenInViewer = true,
plugins = []
}) {
const sections = [...data.sections].sort((a, b) => a.order - b.order);
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(HostContext.Provider, { value: host, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: `af-root ${className ?? ""}`, children: [
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(HostContext.Provider, { value: host, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PluginsContext.Provider, { value: plugins, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: `af-root ${className ?? ""}`, children: [
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("header", { className: "af-header", children: [

@@ -1034,3 +876,3 @@ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "af-header-main", children: [

/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "af-sections", children: sections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SectionFrame, { section }, section.id)) })
] }) });
] }) }) });
}

@@ -1079,5 +921,9 @@ function SectionFrame({ section }) {

return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ReferencesSectionView, { section });
case "family-graph":
// `inheritance-diagram` is a deprecated alias for `family-graph`;
// both route to the same component so existing files keep rendering.
// eslint-disable-next-line no-fallthrough
case "inheritance-diagram":
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
InheritanceDiagramSectionView,
FamilyGraphSectionView,
{

@@ -1097,5 +943,7 @@ section,

downloadPrintableHtml,
findVariantComponent,
openInViewer,
useHost
useHost,
usePlugins
});
//# sourceMappingURL=index.cjs.map
import * as react_jsx_runtime from 'react/jsx-runtime';
import { ReactElement } from 'react';
import { ComponentType, ReactElement } from 'react';
type SectionType = 'kanban' | 'checklist' | 'notes' | 'timeline' | 'table' | 'log' | 'metrics' | 'diagram' | 'report' | 'form' | 'links' | 'references' | 'inheritance-diagram';
type SectionType = 'kanban' | 'checklist' | 'notes' | 'timeline' | 'table' | 'log' | 'metrics' | 'diagram' | 'report' | 'form' | 'links' | 'references' | 'family-graph' | 'inheritance-diagram';
interface SectionBase {

@@ -233,3 +233,3 @@ id: string;

}
interface InheritanceDiagramPerson {
interface FamilyGraphPerson {
id: string;

@@ -243,3 +243,3 @@ name: string;

}
interface InheritanceDiagramRelationship {
interface FamilyGraphRelationship {
type: 'spouse' | 'parent-child';

@@ -251,13 +251,37 @@ person1Id: string;

}
interface InheritanceDiagramData {
variant: string;
persons: InheritanceDiagramPerson[];
relationships: InheritanceDiagramRelationship[];
interface FamilyGraphData {
/**
* Optional style template. Core ships the default genealogy layout; known
* plugins can register additional variants (e.g. `jp-court` for the
* Japanese 相続関係説明図 template via `@agent-format/jp-court`). Unknown
* variants fall back to the default layout.
*/
variant?: string;
persons: FamilyGraphPerson[];
relationships: FamilyGraphRelationship[];
focusedPersonId?: string;
}
interface FamilyGraphSection extends SectionBase {
type: 'family-graph';
data: FamilyGraphData;
}
/**
* @deprecated Use `FamilyGraphPerson`. Kept as a re-export so existing
* consumers compile while they migrate.
*/
type InheritanceDiagramPerson = FamilyGraphPerson;
/** @deprecated Use `FamilyGraphRelationship`. */
type InheritanceDiagramRelationship = FamilyGraphRelationship;
/** @deprecated Use `FamilyGraphData`. */
type InheritanceDiagramData = FamilyGraphData;
/**
* @deprecated Use `FamilyGraphSection` with `type: 'family-graph'`. The
* renderer still accepts the `inheritance-diagram` section type at runtime
* as a backward-compatible alias.
*/
interface InheritanceDiagramSection extends SectionBase {
type: 'inheritance-diagram';
data: InheritanceDiagramData;
data: FamilyGraphData;
}
type Section = KanbanSection | ChecklistSection | NotesSection | TimelineSection | TableSection | LogSection | MetricsSection | DiagramSection | ReportSection | FormSection | LinksSection | ReferencesSection | InheritanceDiagramSection;
type Section = KanbanSection | ChecklistSection | NotesSection | TimelineSection | TableSection | LogSection | MetricsSection | DiagramSection | ReportSection | FormSection | LinksSection | ReferencesSection | FamilyGraphSection | InheritanceDiagramSection;
type AgentTaskTrigger = 'manual' | 'daily' | 'weekly';

@@ -313,2 +337,37 @@ interface AgentTask {

interface VariantRendererProps<S extends Section = Section> {
section: S;
/**
* Optional: let a plugin mount header-right action buttons (PDF export,
* format-specific toggles, etc.) via the same hook core renderers use.
* Safe to ignore.
*/
setHeaderActions?: (node: ReactElement | null) => void;
}
type VariantComponent = ComponentType<VariantRendererProps>;
interface RendererPlugin {
/**
* Package identifier, e.g. `@agent-format/jp-court`. Used for diagnostics
* and to de-duplicate if the same plugin gets passed twice.
*/
name: string;
/**
* Nested map: sectionType → variantName → component. Example:
*
* {
* 'family-graph': {
* 'jp-court': JPCourtFamilyGraphView,
* },
* }
*/
variants?: Partial<Record<SectionType | string, Record<string, VariantComponent>>>;
}
/**
* Walk the supplied plugin list in order and return the first registered
* variant component for (sectionType, variant), or undefined if no plugin
* claims it. First-wins so app code can override upstream plugins by placing
* their plugin earlier in the array.
*/
declare function findVariantComponent(plugins: ReadonlyArray<RendererPlugin>, sectionType: string, variant: string | undefined): VariantComponent | undefined;
declare function openInViewer(data: AgentFile, host?: HostBridge): Promise<boolean>;

@@ -333,2 +392,7 @@ declare function buildPrintableHtml({ svgMarkup, titleLabel, documentTitle, pageSize, margin, fontFamily, autoPrint, }: {

declare function useHost(): HostBridge | undefined;
/**
* Returns the plugin list provided to the nearest AgentRenderer. Section
* renderers use this to look up variant-specific components.
*/
declare function usePlugins(): ReadonlyArray<RendererPlugin>;
interface AgentRendererProps {

@@ -349,4 +413,10 @@ data: AgentFile;

showOpenInViewer?: boolean;
/**
* Optional domain-specific plugins (e.g. `@agent-format/jp-court`) that
* register variant renderers for section types like `family-graph`.
* Earlier plugins win on conflicting `(sectionType, variant)` pairs.
*/
plugins?: ReadonlyArray<RendererPlugin>;
}
declare function AgentRenderer({ data, className, host, showOpenInViewer, }: AgentRendererProps): react_jsx_runtime.JSX.Element;
declare function AgentRenderer({ data, className, host, showOpenInViewer, plugins, }: AgentRendererProps): react_jsx_runtime.JSX.Element;
interface SectionViewExtras {

@@ -361,2 +431,2 @@ /**

export { type AgentConfig, type AgentFile, type AgentMemory, AgentRenderer, type AgentTask, type AgentTaskTrigger, type ChecklistGroup, type ChecklistItem, type ChecklistSection, type DiagramNode, type DiagramSection, type FormField, type FormSection, type FormSubmission, type HostBridge, type InheritanceDiagramData, type InheritanceDiagramPerson, type InheritanceDiagramRelationship, type InheritanceDiagramSection, type KanbanColumn, type KanbanData, type KanbanItem, type KanbanItemComment, type KanbanLabel, type KanbanSection, type KanbanTeamMember, type LinkItem, type LinksSection, type LogEntry, type LogSection, type MetricCard, type MetricsSection, type NoteBlock, type NotesSection, type ReferenceFileItem, type ReferencesSection, type ReportEntry, type ReportSection, type Section, type SectionBase, type SectionType, type SectionViewExtras, type TableColumn, type TableColumnType, type TableSection, type TimelineItem, type TimelineMilestone, type TimelineSection, buildPrintableHtml, downloadPrintableHtml, openInViewer, useHost };
export { type AgentConfig, type AgentFile, type AgentMemory, AgentRenderer, type AgentTask, type AgentTaskTrigger, type ChecklistGroup, type ChecklistItem, type ChecklistSection, type DiagramNode, type DiagramSection, type FamilyGraphData, type FamilyGraphPerson, type FamilyGraphRelationship, type FamilyGraphSection, type FormField, type FormSection, type FormSubmission, type HostBridge, type InheritanceDiagramData, type InheritanceDiagramPerson, type InheritanceDiagramRelationship, type InheritanceDiagramSection, type KanbanColumn, type KanbanData, type KanbanItem, type KanbanItemComment, type KanbanLabel, type KanbanSection, type KanbanTeamMember, type LinkItem, type LinksSection, type LogEntry, type LogSection, type MetricCard, type MetricsSection, type NoteBlock, type NotesSection, type ReferenceFileItem, type ReferencesSection, type RendererPlugin, type ReportEntry, type ReportSection, type Section, type SectionBase, type SectionType, type SectionViewExtras, type TableColumn, type TableColumnType, type TableSection, type TimelineItem, type TimelineMilestone, type TimelineSection, type VariantComponent, type VariantRendererProps, buildPrintableHtml, downloadPrintableHtml, findVariantComponent, openInViewer, useHost, usePlugins };
import * as react_jsx_runtime from 'react/jsx-runtime';
import { ReactElement } from 'react';
import { ComponentType, ReactElement } from 'react';
type SectionType = 'kanban' | 'checklist' | 'notes' | 'timeline' | 'table' | 'log' | 'metrics' | 'diagram' | 'report' | 'form' | 'links' | 'references' | 'inheritance-diagram';
type SectionType = 'kanban' | 'checklist' | 'notes' | 'timeline' | 'table' | 'log' | 'metrics' | 'diagram' | 'report' | 'form' | 'links' | 'references' | 'family-graph' | 'inheritance-diagram';
interface SectionBase {

@@ -233,3 +233,3 @@ id: string;

}
interface InheritanceDiagramPerson {
interface FamilyGraphPerson {
id: string;

@@ -243,3 +243,3 @@ name: string;

}
interface InheritanceDiagramRelationship {
interface FamilyGraphRelationship {
type: 'spouse' | 'parent-child';

@@ -251,13 +251,37 @@ person1Id: string;

}
interface InheritanceDiagramData {
variant: string;
persons: InheritanceDiagramPerson[];
relationships: InheritanceDiagramRelationship[];
interface FamilyGraphData {
/**
* Optional style template. Core ships the default genealogy layout; known
* plugins can register additional variants (e.g. `jp-court` for the
* Japanese 相続関係説明図 template via `@agent-format/jp-court`). Unknown
* variants fall back to the default layout.
*/
variant?: string;
persons: FamilyGraphPerson[];
relationships: FamilyGraphRelationship[];
focusedPersonId?: string;
}
interface FamilyGraphSection extends SectionBase {
type: 'family-graph';
data: FamilyGraphData;
}
/**
* @deprecated Use `FamilyGraphPerson`. Kept as a re-export so existing
* consumers compile while they migrate.
*/
type InheritanceDiagramPerson = FamilyGraphPerson;
/** @deprecated Use `FamilyGraphRelationship`. */
type InheritanceDiagramRelationship = FamilyGraphRelationship;
/** @deprecated Use `FamilyGraphData`. */
type InheritanceDiagramData = FamilyGraphData;
/**
* @deprecated Use `FamilyGraphSection` with `type: 'family-graph'`. The
* renderer still accepts the `inheritance-diagram` section type at runtime
* as a backward-compatible alias.
*/
interface InheritanceDiagramSection extends SectionBase {
type: 'inheritance-diagram';
data: InheritanceDiagramData;
data: FamilyGraphData;
}
type Section = KanbanSection | ChecklistSection | NotesSection | TimelineSection | TableSection | LogSection | MetricsSection | DiagramSection | ReportSection | FormSection | LinksSection | ReferencesSection | InheritanceDiagramSection;
type Section = KanbanSection | ChecklistSection | NotesSection | TimelineSection | TableSection | LogSection | MetricsSection | DiagramSection | ReportSection | FormSection | LinksSection | ReferencesSection | FamilyGraphSection | InheritanceDiagramSection;
type AgentTaskTrigger = 'manual' | 'daily' | 'weekly';

@@ -313,2 +337,37 @@ interface AgentTask {

interface VariantRendererProps<S extends Section = Section> {
section: S;
/**
* Optional: let a plugin mount header-right action buttons (PDF export,
* format-specific toggles, etc.) via the same hook core renderers use.
* Safe to ignore.
*/
setHeaderActions?: (node: ReactElement | null) => void;
}
type VariantComponent = ComponentType<VariantRendererProps>;
interface RendererPlugin {
/**
* Package identifier, e.g. `@agent-format/jp-court`. Used for diagnostics
* and to de-duplicate if the same plugin gets passed twice.
*/
name: string;
/**
* Nested map: sectionType → variantName → component. Example:
*
* {
* 'family-graph': {
* 'jp-court': JPCourtFamilyGraphView,
* },
* }
*/
variants?: Partial<Record<SectionType | string, Record<string, VariantComponent>>>;
}
/**
* Walk the supplied plugin list in order and return the first registered
* variant component for (sectionType, variant), or undefined if no plugin
* claims it. First-wins so app code can override upstream plugins by placing
* their plugin earlier in the array.
*/
declare function findVariantComponent(plugins: ReadonlyArray<RendererPlugin>, sectionType: string, variant: string | undefined): VariantComponent | undefined;
declare function openInViewer(data: AgentFile, host?: HostBridge): Promise<boolean>;

@@ -333,2 +392,7 @@ declare function buildPrintableHtml({ svgMarkup, titleLabel, documentTitle, pageSize, margin, fontFamily, autoPrint, }: {

declare function useHost(): HostBridge | undefined;
/**
* Returns the plugin list provided to the nearest AgentRenderer. Section
* renderers use this to look up variant-specific components.
*/
declare function usePlugins(): ReadonlyArray<RendererPlugin>;
interface AgentRendererProps {

@@ -349,4 +413,10 @@ data: AgentFile;

showOpenInViewer?: boolean;
/**
* Optional domain-specific plugins (e.g. `@agent-format/jp-court`) that
* register variant renderers for section types like `family-graph`.
* Earlier plugins win on conflicting `(sectionType, variant)` pairs.
*/
plugins?: ReadonlyArray<RendererPlugin>;
}
declare function AgentRenderer({ data, className, host, showOpenInViewer, }: AgentRendererProps): react_jsx_runtime.JSX.Element;
declare function AgentRenderer({ data, className, host, showOpenInViewer, plugins, }: AgentRendererProps): react_jsx_runtime.JSX.Element;
interface SectionViewExtras {

@@ -361,2 +431,2 @@ /**

export { type AgentConfig, type AgentFile, type AgentMemory, AgentRenderer, type AgentTask, type AgentTaskTrigger, type ChecklistGroup, type ChecklistItem, type ChecklistSection, type DiagramNode, type DiagramSection, type FormField, type FormSection, type FormSubmission, type HostBridge, type InheritanceDiagramData, type InheritanceDiagramPerson, type InheritanceDiagramRelationship, type InheritanceDiagramSection, type KanbanColumn, type KanbanData, type KanbanItem, type KanbanItemComment, type KanbanLabel, type KanbanSection, type KanbanTeamMember, type LinkItem, type LinksSection, type LogEntry, type LogSection, type MetricCard, type MetricsSection, type NoteBlock, type NotesSection, type ReferenceFileItem, type ReferencesSection, type ReportEntry, type ReportSection, type Section, type SectionBase, type SectionType, type SectionViewExtras, type TableColumn, type TableColumnType, type TableSection, type TimelineItem, type TimelineMilestone, type TimelineSection, buildPrintableHtml, downloadPrintableHtml, openInViewer, useHost };
export { type AgentConfig, type AgentFile, type AgentMemory, AgentRenderer, type AgentTask, type AgentTaskTrigger, type ChecklistGroup, type ChecklistItem, type ChecklistSection, type DiagramNode, type DiagramSection, type FamilyGraphData, type FamilyGraphPerson, type FamilyGraphRelationship, type FamilyGraphSection, type FormField, type FormSection, type FormSubmission, type HostBridge, type InheritanceDiagramData, type InheritanceDiagramPerson, type InheritanceDiagramRelationship, type InheritanceDiagramSection, type KanbanColumn, type KanbanData, type KanbanItem, type KanbanItemComment, type KanbanLabel, type KanbanSection, type KanbanTeamMember, type LinkItem, type LinksSection, type LogEntry, type LogSection, type MetricCard, type MetricsSection, type NoteBlock, type NotesSection, type ReferenceFileItem, type ReferencesSection, type RendererPlugin, type ReportEntry, type ReportSection, type Section, type SectionBase, type SectionType, type SectionViewExtras, type TableColumn, type TableColumnType, type TableSection, type TimelineItem, type TimelineMilestone, type TimelineSection, type VariantComponent, type VariantRendererProps, buildPrintableHtml, downloadPrintableHtml, findVariantComponent, openInViewer, useHost, usePlugins };

@@ -392,5 +392,292 @@ // src/index.tsx

// src/sections/InheritanceDiagramSection.tsx
import { useEffect, useRef } from "react";
// src/sections/FamilyGraphSection.tsx
import { useMemo } from "react";
// src/plugins.ts
function findVariantComponent(plugins, sectionType, variant) {
if (!variant) return void 0;
for (const plugin of plugins) {
const component = plugin.variants?.[sectionType]?.[variant];
if (component) return component;
}
return void 0;
}
// src/sections/FamilyGraphSection.tsx
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
var MAX_GENERATIONS = 8;
var CARD_W = 220;
var CARD_H = 120;
var COL_GAP = 40;
var ROW_GAP = 80;
var MARGIN_X = 20;
var MARGIN_Y = 20;
function FamilyGraphSectionView({ section, setHeaderActions }) {
const plugins = usePlugins();
const variant = section.data?.variant;
const VariantComponent = findVariantComponent(plugins, "family-graph", variant);
if (VariantComponent) {
return /* @__PURE__ */ jsx13(VariantComponent, { section, setHeaderActions });
}
if (section.type === "inheritance-diagram") {
const AliasComponent = findVariantComponent(plugins, "inheritance-diagram", variant);
if (AliasComponent) {
return /* @__PURE__ */ jsx13(AliasComponent, { section, setHeaderActions });
}
}
return /* @__PURE__ */ jsx13(DefaultGenealogy, { section });
}
function DefaultGenealogy({ section }) {
const persons = section.data?.persons ?? [];
const rels = section.data?.relationships ?? [];
const focusedId = section.data?.focusedPersonId;
const layout = useMemo(() => computeLayout(persons, rels), [persons, rels]);
if (persons.length === 0) {
return /* @__PURE__ */ jsx13("p", { className: "af-empty", children: "No persons in diagram." });
}
return /* @__PURE__ */ jsx13("div", { className: "af-family-graph", style: { overflow: "auto" }, children: /* @__PURE__ */ jsxs12(
"svg",
{
xmlns: "http://www.w3.org/2000/svg",
width: layout.width,
height: layout.height,
viewBox: `0 0 ${layout.width} ${layout.height}`,
role: "img",
"aria-label": "Family graph",
children: [
layout.parentChildEdges.map((edge, i) => {
const p = cardById(layout, edge.parent);
const c = cardById(layout, edge.child);
if (!p || !c) return null;
const px = p.x + CARD_W / 2;
const py = p.y + CARD_H;
const cx = c.x + CARD_W / 2;
const cy = c.y;
const midY = (py + cy) / 2;
return /* @__PURE__ */ jsx13(
"polyline",
{
points: `${px},${py} ${px},${midY} ${cx},${midY} ${cx},${cy}`,
fill: "none",
stroke: "currentColor",
strokeWidth: "1.2",
opacity: "0.6"
},
`pc-${i}`
);
}),
layout.spouseEdges.map((edge, i) => {
const a = cardById(layout, edge.a);
const b = cardById(layout, edge.b);
if (!a || !b) return null;
const ay = a.y + CARD_H / 2;
const by = b.y + CARD_H / 2;
const ax = a.x + CARD_W;
const bx = b.x;
if (a.y !== b.y) {
return /* @__PURE__ */ jsx13(
"line",
{
x1: a.x + CARD_W / 2,
y1: ay,
x2: b.x + CARD_W / 2,
y2: by,
stroke: "currentColor",
strokeWidth: "1.2",
strokeDasharray: edge.dissolved ? "4 3" : void 0,
opacity: "0.6"
},
`sp-${i}`
);
}
const mid = (ay + by) / 2;
return /* @__PURE__ */ jsxs12("g", { children: [
/* @__PURE__ */ jsx13(
"line",
{
x1: ax,
y1: mid - 3,
x2: bx,
y2: mid - 3,
stroke: "currentColor",
strokeWidth: "1.2",
strokeDasharray: edge.dissolved ? "4 3" : void 0,
opacity: "0.8"
}
),
!edge.dissolved && /* @__PURE__ */ jsx13(
"line",
{
x1: ax,
y1: mid + 3,
x2: bx,
y2: mid + 3,
stroke: "currentColor",
strokeWidth: "1.2",
opacity: "0.8"
}
)
] }, `sp-${i}`);
}),
layout.cards.map((card) => /* @__PURE__ */ jsx13(
PersonCard,
{
person: card.person,
x: card.x,
y: card.y,
focused: card.id === focusedId
},
card.id
))
]
}
) });
}
function cardById(layout, id) {
return layout.cards.find((c) => c.id === id);
}
function PersonCard({
person,
x,
y,
focused
}) {
return /* @__PURE__ */ jsxs12("g", { transform: `translate(${x}, ${y})`, children: [
/* @__PURE__ */ jsx13(
"rect",
{
width: CARD_W,
height: CARD_H,
rx: 8,
fill: focused ? "var(--af-accent-soft, #eef2ff)" : "var(--af-bg-alt, #f7f7f8)",
stroke: focused ? "var(--af-accent, #2251ff)" : "var(--af-border, #e5e7eb)",
strokeWidth: focused ? 2 : 1
}
),
/* @__PURE__ */ jsx13("text", { x: 12, y: 24, fontSize: "14", fontWeight: "600", fill: "currentColor", children: person.name }),
person.role && /* @__PURE__ */ jsx13(
"text",
{
x: 12,
y: 44,
fontSize: "11",
fill: "currentColor",
opacity: "0.7",
children: person.role
}
),
person.birthday && /* @__PURE__ */ jsxs12("text", { x: 12, y: 66, fontSize: "11", fill: "currentColor", opacity: "0.7", children: [
"b. ",
person.birthday
] }),
person.deathDate && /* @__PURE__ */ jsxs12("text", { x: 12, y: 82, fontSize: "11", fill: "currentColor", opacity: "0.7", children: [
"d. ",
person.deathDate
] }),
person.address && /* @__PURE__ */ jsx13("text", { x: 12, y: 100, fontSize: "10", fill: "currentColor", opacity: "0.55", children: truncate(person.address, 30) })
] });
}
function truncate(s, max) {
return s.length <= max ? s : s.slice(0, max - 1) + "\u2026";
}
function computeLayout(persons, rels) {
const byId = new Map(persons.map((p) => [p.id, p]));
const childrenOf = /* @__PURE__ */ new Map();
const parentsOf = /* @__PURE__ */ new Map();
const spouseEdges = [];
for (const r of rels) {
if (r.type === "parent-child") {
if (!byId.has(r.person1Id) || !byId.has(r.person2Id)) continue;
if (!childrenOf.has(r.person1Id)) childrenOf.set(r.person1Id, []);
childrenOf.get(r.person1Id).push(r.person2Id);
if (!parentsOf.has(r.person2Id)) parentsOf.set(r.person2Id, []);
parentsOf.get(r.person2Id).push(r.person1Id);
} else if (r.type === "spouse") {
if (!byId.has(r.person1Id) || !byId.has(r.person2Id)) continue;
spouseEdges.push({
a: r.person1Id,
b: r.person2Id,
dissolved: r.dissolved
});
}
}
const depth = /* @__PURE__ */ new Map();
const seeds = persons.filter((p) => !parentsOf.has(p.id)).map((p) => p.id);
const queue = seeds.map((id) => ({ id, d: 0 }));
while (queue.length > 0) {
const { id, d } = queue.shift();
if (d > MAX_GENERATIONS) continue;
if (depth.has(id)) continue;
depth.set(id, d);
for (const childId of childrenOf.get(id) ?? []) {
if (!depth.has(childId)) queue.push({ id: childId, d: d + 1 });
}
}
for (const s of spouseEdges) {
if (!depth.has(s.a) && depth.has(s.b)) depth.set(s.a, depth.get(s.b));
if (!depth.has(s.b) && depth.has(s.a)) depth.set(s.b, depth.get(s.a));
}
for (const p of persons) {
if (!depth.has(p.id)) depth.set(p.id, 0);
}
const byGen = /* @__PURE__ */ new Map();
for (const p of persons) {
const d = depth.get(p.id);
if (!byGen.has(d)) byGen.set(d, []);
byGen.get(d).push(p);
}
const sortedGens = Array.from(byGen.entries()).sort((a, b) => a[0] - b[0]);
for (const [, row] of sortedGens) {
placeSpousesAdjacent(row, spouseEdges);
}
const rowCount = Math.max(...sortedGens.map(([, r]) => r.length), 1);
const rowWidth = rowCount * CARD_W + (rowCount - 1) * COL_GAP;
const cards = [];
sortedGens.forEach(([d, row]) => {
const y = MARGIN_Y + d * (CARD_H + ROW_GAP);
const thisRowWidth = row.length * CARD_W + (row.length - 1) * COL_GAP;
const offsetX = MARGIN_X + (rowWidth - thisRowWidth) / 2;
row.forEach((p, i) => {
cards.push({
id: p.id,
person: p,
x: offsetX + i * (CARD_W + COL_GAP),
y
});
});
});
const width = MARGIN_X * 2 + rowWidth;
const height = MARGIN_Y * 2 + sortedGens.length * CARD_H + Math.max(sortedGens.length - 1, 0) * ROW_GAP;
const parentChildEdges = [];
for (const r of rels) {
if (r.type !== "parent-child") continue;
if (!byId.has(r.person1Id) || !byId.has(r.person2Id)) continue;
parentChildEdges.push({ parent: r.person1Id, child: r.person2Id });
}
return { cards, parentChildEdges, spouseEdges, width, height };
}
function placeSpousesAdjacent(row, spouseEdges) {
for (const edge of spouseEdges) {
const ai = row.findIndex((p) => p.id === edge.a);
const bi = row.findIndex((p) => p.id === edge.b);
if (ai < 0 || bi < 0 || Math.abs(ai - bi) === 1) continue;
const [b] = row.splice(bi, 1);
const insertAt = ai < bi ? ai + 1 : ai;
row.splice(insertAt, 0, b);
}
}
// src/sections/Fallback.tsx
import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
function FallbackSectionView({ section }) {
return /* @__PURE__ */ jsxs13("div", { className: "af-fallback", children: [
/* @__PURE__ */ jsxs13("div", { children: [
"Renderer for section type ",
/* @__PURE__ */ jsx14("strong", { children: section.type }),
" is not yet implemented in this viewer."
] }),
/* @__PURE__ */ jsx14("pre", { children: JSON.stringify(section.data, null, 2) })
] });
}
// src/host.ts

@@ -512,460 +799,12 @@ function fallbackOpenLink(url) {

// src/sections/InheritanceDiagramSection.tsx
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
var MAX_GENERATIONS = 6;
var LINE_H = 22;
var NAME_SIZE = 16;
var NAME_LINE_H = 22;
var DBL_GAP = 4;
var HORIZ_Y_GAP = 90;
var CHILD_V_GAP = 30;
var GEN_X_STEP = 340;
var SPOUSE_GAP = 90;
var TEXT_X = 60;
var CHILD_TEXT_X = 480;
var TRUNK_X = CHILD_TEXT_X - 30;
var DBL_X = 80;
var DEC_TOP_Y = 20;
function InheritanceDiagramSectionView({ section, setHeaderActions }) {
const data = section.data;
const persons = data?.persons ?? [];
const rels = data?.relationships ?? [];
const variant = data?.variant ?? "jp-court";
const svgRef = useRef(null);
const host = useHost();
useEffect(() => {
if (!setHeaderActions) return;
if (!svgRef.current) return;
if (persons.length === 0 || variant !== "jp-court") {
setHeaderActions(null);
return;
}
const sectionLabel = section.label || "\u76F8\u7D9A\u95A2\u4FC2\u8AAC\u660E\u56F3";
const documentTitle = sectionLabel;
const headerTitle = "\u76F8 \u7D9A \u95A2 \u4FC2 \u8AAC \u660E \u56F3";
const onClick = () => {
const svgEl = svgRef.current;
if (!svgEl) return;
const serialized = new XMLSerializer().serializeToString(svgEl);
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
void downloadPrintableHtml({
svgMarkup: serialized,
titleLabel: headerTitle,
documentTitle,
filename: `inheritance-diagram-${today}.html`,
host
});
};
setHeaderActions(
/* @__PURE__ */ jsxs12(
"button",
{
type: "button",
className: "af-action-btn",
onClick,
title: "\u5370\u5237\u30FBPDF \u4FDD\u5B58\u7528\u306E HTML \u3092\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\uFF08\u958B\u3044\u3066 \u2318P \u3067 PDF \u4FDD\u5B58\u3001\u88C1\u5224\u6240\u63D0\u51FA\u7528 A3 \u6A2A\u66F8\u5F0F\uFF09",
children: [
/* @__PURE__ */ jsx13("span", { "aria-hidden": true, children: "\u2B07" }),
/* @__PURE__ */ jsx13("span", { children: "PDF" })
]
}
)
);
return () => setHeaderActions(null);
}, [setHeaderActions, section.id, section.label, persons.length, variant, host]);
if (persons.length === 0) {
return /* @__PURE__ */ jsx13("p", { className: "af-empty", children: "No persons in diagram." });
}
if (variant !== "jp-court") {
return /* @__PURE__ */ jsxs12("p", { className: "af-empty", children: [
'Inheritance-diagram variant "',
variant,
'" is not yet implemented. Only "jp-court" is supported in v0.1.'
] });
}
const focused = data?.focusedPersonId ? persons.find((p) => p.id === data.focusedPersonId) : null;
const decedent = focused || persons.find((p) => Boolean(p.deathDate)) || persons[0];
if (!decedent) return /* @__PURE__ */ jsx13("p", { className: "af-empty", children: "No decedent." });
const findSpouseOfRoot = () => {
const rel = rels.find(
(r) => r.type === "spouse" && (r.person1Id === decedent.id || r.person2Id === decedent.id)
);
if (!rel) return null;
const sid = rel.person1Id === decedent.id ? rel.person2Id : rel.person1Id;
return persons.find((p) => p.id === sid) ?? null;
};
const findChildren = (parentId, spouseId) => {
const pids = /* @__PURE__ */ new Set([parentId]);
if (spouseId) pids.add(spouseId);
const kids = [];
const seen = /* @__PURE__ */ new Set();
for (const r of rels) {
if (r.type === "parent-child" && pids.has(r.person1Id)) {
if (seen.has(r.person2Id)) continue;
const c = persons.find((p) => p.id === r.person2Id);
if (c) {
seen.add(r.person2Id);
kids.push(c);
}
}
}
return kids;
};
const findSpouse = (personId) => {
const rel = rels.find(
(r) => r.type === "spouse" && r.person1Id !== decedent.id && r.person2Id !== decedent.id && (r.person1Id === personId || r.person2Id === personId)
);
if (!rel) return null;
const sid = rel.person1Id === personId ? rel.person2Id : rel.person1Id;
return persons.find((p) => p.id === sid) ?? null;
};
const blockHeight = (p) => {
let n = 0;
if (p.address) n++;
if (p.birthday) n++;
if (p.deathDate) n++;
n++;
return n * LINE_H + NAME_LINE_H;
};
let elementKey = 0;
const nextKey = () => `el-${++elementKey}`;
const renderBlock = (p, x, topY, roleLabel) => {
const elements = [];
let y = topY;
if (p.address) {
const lbl = roleLabel === "\u88AB\u76F8\u7D9A\u4EBA" ? "\u6700\u5F8C\u306E\u4F4F\u6240" : "\u4F4F\u6240";
elements.push(
/* @__PURE__ */ jsx13("text", { x, y, fontSize: "11pt", children: `${lbl}\u3000${p.address}` }, nextKey())
);
y += LINE_H;
}
if (p.birthday) {
elements.push(
/* @__PURE__ */ jsx13("text", { x, y, fontSize: "11pt", children: `\u51FA\u751F\u3000${p.birthday}` }, nextKey())
);
y += LINE_H;
}
if (p.deathDate) {
elements.push(
/* @__PURE__ */ jsx13("text", { x, y, fontSize: "11pt", children: `\u6B7B\u4EA1\u3000${p.deathDate}` }, nextKey())
);
y += LINE_H;
}
elements.push(
/* @__PURE__ */ jsx13("text", { x: x + 8, y, fontSize: "11pt", children: `\uFF08${roleLabel}\uFF09` }, nextKey())
);
y += LINE_H;
elements.push(
/* @__PURE__ */ jsx13(
"text",
{
x,
y,
fontSize: `${NAME_SIZE}pt`,
fontWeight: "bold",
letterSpacing: "0.2em",
children: p.name
},
nextKey()
)
);
const nameBaseY = y;
y += NAME_LINE_H;
return { elements, nameBaseY, blockEndY: y };
};
const measureChildSlot = (c, depth) => {
if (depth > MAX_GENERATIONS) return blockHeight(c);
let h = blockHeight(c);
const sp = findSpouse(c.id);
if (sp) h += SPOUSE_GAP + blockHeight(sp);
const grandkids = findChildren(c.id, sp ? sp.id : null);
if (grandkids.length > 0) {
const subH = measureChildGroup(grandkids, depth + 1);
h = Math.max(h, subH);
}
return h;
};
const measureChildGroup = (childList, depth) => {
let total = 0;
childList.forEach((c, i) => {
if (i > 0) total += CHILD_V_GAP;
total += measureChildSlot(c, depth);
});
return total;
};
const lineProps = {
stroke: "#000",
strokeWidth: 1.2
};
const renderChildGroup = (childList, textX, startY, depth) => {
const elements = [];
const nameYs = [];
let cy = startY;
if (depth > MAX_GENERATIONS) {
elements.push(
/* @__PURE__ */ jsxs12(
"text",
{
x: textX,
y: cy,
fontSize: "11pt",
fill: "#999",
children: [
"\u2026 (tree truncated at generation ",
MAX_GENERATIONS,
")"
]
},
nextKey()
)
);
return { elements, nameYs, endY: cy + LINE_H };
}
childList.forEach((c, i) => {
if (i > 0) cy += CHILD_V_GAP;
const cb = renderBlock(c, textX, cy, c.role || "\u76F8\u7D9A\u4EBA");
elements.push(...cb.elements);
nameYs.push(cb.nameBaseY);
const childSpouse = findSpouse(c.id);
let connectorY = cb.nameBaseY;
if (childSpouse) {
const spTopY = cb.blockEndY + SPOUSE_GAP;
const spBlock2 = renderBlock(
childSpouse,
textX,
spTopY,
childSpouse.role || "\u914D\u5076\u8005"
);
elements.push(...spBlock2.elements);
const miniDblX = textX + 20;
const miniGapTop = cb.blockEndY + 5;
const miniGapBot = spTopY - 25;
elements.push(
/* @__PURE__ */ jsx13(
"line",
{
x1: miniDblX - DBL_GAP,
y1: miniGapTop,
x2: miniDblX - DBL_GAP,
y2: miniGapBot,
...lineProps
},
nextKey()
)
);
elements.push(
/* @__PURE__ */ jsx13(
"line",
{
x1: miniDblX + DBL_GAP,
y1: miniGapTop,
x2: miniDblX + DBL_GAP,
y2: miniGapBot,
...lineProps
},
nextKey()
)
);
connectorY = cb.blockEndY + SPOUSE_GAP / 2;
}
const grandkids = findChildren(c.id, childSpouse ? childSpouse.id : null);
if (grandkids.length > 0) {
const gcTextX = textX + GEN_X_STEP;
const gcTrunkX = gcTextX - 30;
const gcResult = renderChildGroup(grandkids, gcTextX, cy, depth + 1);
elements.push(...gcResult.elements);
elements.push(
/* @__PURE__ */ jsx13(
"line",
{
x1: textX + 180,
y1: connectorY,
x2: gcTrunkX,
y2: connectorY,
...lineProps
},
nextKey()
)
);
if (gcResult.nameYs.length > 0) {
const gcTrunkTop = Math.min(connectorY, gcResult.nameYs[0]);
const gcTrunkBot = Math.max(
connectorY,
gcResult.nameYs[gcResult.nameYs.length - 1]
);
elements.push(
/* @__PURE__ */ jsx13(
"line",
{
x1: gcTrunkX,
y1: gcTrunkTop,
x2: gcTrunkX,
y2: gcTrunkBot,
...lineProps
},
nextKey()
)
);
gcResult.nameYs.forEach((gny) => {
elements.push(
/* @__PURE__ */ jsx13(
"line",
{
x1: gcTrunkX,
y1: gny,
x2: gcTextX - 5,
y2: gny,
...lineProps
},
nextKey()
)
);
});
}
}
cy += measureChildSlot(c, depth);
});
return { elements, nameYs, endY: cy };
};
const dec = renderBlock(decedent, TEXT_X, DEC_TOP_Y, "\u88AB\u76F8\u7D9A\u4EBA");
const spouse = findSpouseOfRoot();
const spouseTopY = dec.blockEndY + HORIZ_Y_GAP;
const spBlock = spouse ? renderBlock(spouse, TEXT_X, spouseTopY, spouse.role || "\u76F8\u7D9A\u4EBA") : null;
const dblMidY = dec.blockEndY + HORIZ_Y_GAP / 2;
const children = findChildren(decedent.id, spouse ? spouse.id : null);
const totalChildH = children.length > 0 ? measureChildGroup(children, 0) : 0;
let childGroupTopY = dblMidY - totalChildH / 2;
if (childGroupTopY < 10) childGroupTopY = 10;
const childResult = children.length > 0 ? renderChildGroup(children, CHILD_TEXT_X, childGroupTopY, 0) : { elements: [], nameYs: [], endY: childGroupTopY };
const svgH = Math.max(spBlock ? spBlock.blockEndY : dec.blockEndY, childResult.endY) + 30;
const svgParts = [];
svgParts.push(...dec.elements);
if (spBlock) svgParts.push(...spBlock.elements);
if (spouse) {
const gapTop = dec.blockEndY + 5;
const gapBot = spouseTopY - 25;
svgParts.push(
/* @__PURE__ */ jsx13(
"line",
{
x1: DBL_X - DBL_GAP,
y1: gapTop,
x2: DBL_X - DBL_GAP,
y2: gapBot,
...lineProps
},
nextKey()
)
);
svgParts.push(
/* @__PURE__ */ jsx13(
"line",
{
x1: DBL_X + DBL_GAP,
y1: gapTop,
x2: DBL_X + DBL_GAP,
y2: gapBot,
...lineProps
},
nextKey()
)
);
if (children.length > 0) {
svgParts.push(
/* @__PURE__ */ jsx13(
"line",
{
x1: DBL_X + DBL_GAP,
y1: dblMidY,
x2: TRUNK_X,
y2: dblMidY,
...lineProps
},
nextKey()
)
);
}
} else if (children.length > 0) {
svgParts.push(
/* @__PURE__ */ jsx13(
"line",
{
x1: TEXT_X + 200,
y1: dec.nameBaseY,
x2: TRUNK_X,
y2: dec.nameBaseY,
...lineProps
},
nextKey()
)
);
}
svgParts.push(...childResult.elements);
if (childResult.nameYs.length > 0) {
const trunkTop = Math.min(
spouse ? dblMidY : dec.nameBaseY,
childResult.nameYs[0]
);
const trunkBot = childResult.nameYs[childResult.nameYs.length - 1];
svgParts.push(
/* @__PURE__ */ jsx13(
"line",
{
x1: TRUNK_X,
y1: trunkTop,
x2: TRUNK_X,
y2: trunkBot,
...lineProps
},
nextKey()
)
);
childResult.nameYs.forEach((cny) => {
svgParts.push(
/* @__PURE__ */ jsx13(
"line",
{
x1: TRUNK_X,
y1: cny,
x2: CHILD_TEXT_X - 5,
y2: cny,
...lineProps
},
nextKey()
)
);
});
}
return /* @__PURE__ */ jsx13("div", { className: "af-inheritance-diagram", children: /* @__PURE__ */ jsx13(
"svg",
{
ref: svgRef,
xmlns: "http://www.w3.org/2000/svg",
width: "100%",
viewBox: `0 0 1400 ${svgH}`,
style: { overflow: "visible" },
children: svgParts
}
) });
}
// src/sections/Fallback.tsx
import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
function FallbackSectionView({ section }) {
return /* @__PURE__ */ jsxs13("div", { className: "af-fallback", children: [
/* @__PURE__ */ jsxs13("div", { children: [
"Renderer for section type ",
/* @__PURE__ */ jsx14("strong", { children: section.type }),
" is not yet implemented in this viewer."
] }),
/* @__PURE__ */ jsx14("pre", { children: JSON.stringify(section.data, null, 2) })
] });
}
// src/index.tsx
import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
var HostContext = createContext(void 0);
var PluginsContext = createContext([]);
function useHost() {
return useContext(HostContext);
}
function usePlugins() {
return useContext(PluginsContext);
}
function AgentRenderer({

@@ -975,6 +814,7 @@ data,

host,
showOpenInViewer = true
showOpenInViewer = true,
plugins = []
}) {
const sections = [...data.sections].sort((a, b) => a.order - b.order);
return /* @__PURE__ */ jsx15(HostContext.Provider, { value: host, children: /* @__PURE__ */ jsxs14("div", { className: `af-root ${className ?? ""}`, children: [
return /* @__PURE__ */ jsx15(HostContext.Provider, { value: host, children: /* @__PURE__ */ jsx15(PluginsContext.Provider, { value: plugins, children: /* @__PURE__ */ jsxs14("div", { className: `af-root ${className ?? ""}`, children: [
/* @__PURE__ */ jsxs14("header", { className: "af-header", children: [

@@ -1005,3 +845,3 @@ /* @__PURE__ */ jsxs14("div", { className: "af-header-main", children: [

/* @__PURE__ */ jsx15("div", { className: "af-sections", children: sections.map((section) => /* @__PURE__ */ jsx15(SectionFrame, { section }, section.id)) })
] }) });
] }) }) });
}

@@ -1050,5 +890,9 @@ function SectionFrame({ section }) {

return /* @__PURE__ */ jsx15(ReferencesSectionView, { section });
case "family-graph":
// `inheritance-diagram` is a deprecated alias for `family-graph`;
// both route to the same component so existing files keep rendering.
// eslint-disable-next-line no-fallthrough
case "inheritance-diagram":
return /* @__PURE__ */ jsx15(
InheritanceDiagramSectionView,
FamilyGraphSectionView,
{

@@ -1067,5 +911,7 @@ section,

downloadPrintableHtml,
findVariantComponent,
openInViewer,
useHost
useHost,
usePlugins
};
//# sourceMappingURL=index.js.map
{
"name": "@agent-format/renderer",
"version": "0.1.4",
"version": "0.1.5",
"description": "React renderer for the agent file format (.agent).",

@@ -5,0 +5,0 @@ "license": "MIT",

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display