@green-on-grey/ui-kit 1.14.0 → 1.15.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/dist/components/Graph.d.ts +3 -0
- package/dist/index.js +41 -22
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +3 -1
- package/dist/styles.css +9 -0
- package/package.json +1 -1
|
@@ -15,12 +15,15 @@ export type GraphNode = {
|
|
|
15
15
|
row?: string;
|
|
16
16
|
order?: number;
|
|
17
17
|
};
|
|
18
|
+
/** A link; `double` draws it as a double line — another layer of links, told apart without colour
|
|
19
|
+
* (FTR.HMR.DEV-0003 R15); it combines with `dashed`. */
|
|
18
20
|
export type GraphEdge = {
|
|
19
21
|
source: string;
|
|
20
22
|
target: string;
|
|
21
23
|
weight?: number;
|
|
22
24
|
directed?: boolean;
|
|
23
25
|
dashed?: boolean;
|
|
26
|
+
double?: boolean;
|
|
24
27
|
title?: string;
|
|
25
28
|
};
|
|
26
29
|
export type GraphSelection = {
|
package/dist/index.js
CHANGED
|
@@ -316,33 +316,52 @@ function U({ nodes: e, edges: t, ariaLabel: n, selected: i, onSelect: a, focus:
|
|
|
316
316
|
if (!n || !r) return null;
|
|
317
317
|
let i = H(n, r, !!e.directed, !!d), o = e.directed ? `url(#${C})` : void 0;
|
|
318
318
|
return /* @__PURE__ */ g("g", {
|
|
319
|
-
className: `g-e${e.dashed ? " dashed" : ""}${te(e) ? " hl" : ""}`,
|
|
319
|
+
className: `g-e${e.dashed ? " dashed" : ""}${e.double ? " double" : ""}${te(e) ? " hl" : ""}`,
|
|
320
320
|
onClick: () => a({
|
|
321
321
|
kind: "edge",
|
|
322
322
|
source: e.source,
|
|
323
323
|
target: e.target
|
|
324
324
|
}),
|
|
325
|
-
children: [i.d ? /* @__PURE__ */ g(m, { children: [
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
325
|
+
children: [i.d ? /* @__PURE__ */ g(m, { children: [
|
|
326
|
+
/* @__PURE__ */ h("path", {
|
|
327
|
+
d: i.d,
|
|
328
|
+
strokeWidth: 1 + (e.weight ?? 1) * .5 + (e.double ? 3 : 0),
|
|
329
|
+
markerEnd: e.double ? void 0 : o
|
|
330
|
+
}),
|
|
331
|
+
e.double && /* @__PURE__ */ h("path", {
|
|
332
|
+
className: "inner",
|
|
333
|
+
d: i.d,
|
|
334
|
+
markerEnd: o
|
|
335
|
+
}),
|
|
336
|
+
/* @__PURE__ */ h("path", {
|
|
337
|
+
className: "hit",
|
|
338
|
+
d: i.hit
|
|
339
|
+
})
|
|
340
|
+
] }) : /* @__PURE__ */ g(m, { children: [
|
|
341
|
+
/* @__PURE__ */ h("line", {
|
|
342
|
+
x1: i.x1,
|
|
343
|
+
y1: i.y1,
|
|
344
|
+
x2: i.x2,
|
|
345
|
+
y2: i.y2,
|
|
346
|
+
strokeWidth: 1 + (e.weight ?? 1) * .5 + (e.double ? 3 : 0),
|
|
347
|
+
markerEnd: e.double ? void 0 : o
|
|
348
|
+
}),
|
|
349
|
+
e.double && /* @__PURE__ */ h("line", {
|
|
350
|
+
className: "inner",
|
|
351
|
+
x1: i.x1,
|
|
352
|
+
y1: i.y1,
|
|
353
|
+
x2: i.x2,
|
|
354
|
+
y2: i.y2,
|
|
355
|
+
markerEnd: o
|
|
356
|
+
}),
|
|
357
|
+
/* @__PURE__ */ h("line", {
|
|
358
|
+
className: "hit",
|
|
359
|
+
x1: n.x,
|
|
360
|
+
y1: n.y,
|
|
361
|
+
x2: r.x,
|
|
362
|
+
y2: r.y
|
|
363
|
+
})
|
|
364
|
+
] }), e.title && /* @__PURE__ */ h("title", { children: e.title })]
|
|
346
365
|
}, `${e.source}\u0000${e.target}\u0000${t}`);
|
|
347
366
|
}),
|
|
348
367
|
K.map((e) => {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["_Fragment","Switch","useToast","GitHubIcon","Icon","Tabs","Empty","ToastProvider","Loading","useOutside","Avatar","Markdown","useKitT","UIKIT_NS","Button","rest","cls","variant","size","className","IconButton","fill","on","label","Menu","ref","onClose","useEffect","opener","TopBar","t","profileOpen","setProfileOpen","useState","sectionsOpen","setSectionsOpen","closeSections","useCallback","closeProfile","links","sections","Link","s","home","logo","name","center","actions","v","avatar","menu","profileMenu","W","H","radius","zoomed","k","factor","f","neighbours","near","from","frontier","d","depth","next","id","e","edges","other","layout","placed","nodes","n","ids","sim","forceSimulation","forceLink","l","forceManyBody","forceCenter","forceCollide","i","GUTTER","COL","ROW","rowLayout","index","rows","r","byRow","used","a","b","bw","bh","field","x0","y0","y","j","edgeLine","x1","y1","bx","by","x2","y2","arc","arcs","cx","cy","directed","fx","fy","dx","dy","len","Graph","arrow","useId","hover","setHover","view","setView","drag","useRef","nodeDrag","movedAt","svg","layoutEdges","base","useMemo","moved","setMoved","at","p","focused","focus","byId","active","selected","dimmed","edgeOn","zoom","pick","onSelect","pinned","unit","box","el","wheel","ariaLabel","u","panned","marker","Fragment","nodeLabel","draggable","m","wasMoved","onOpen","legend","Modal"],"sources":["../src/components/Button.tsx","../src/components/Menu.tsx","../src/components/TopBar.tsx","../src/components/Graph.tsx"],"sourcesContent":["import type { ButtonHTMLAttributes } from \"react\";\n\ntype Native = ButtonHTMLAttributes<HTMLButtonElement>;\n\n/** `button.btn` with its variants. The classes stay a legitimate way to use a\n * button (FTR.NAB.CMN-0005 tech, decision 1); the component is for new code. */\nexport function Button({ variant, size, className, type = \"button\", ...rest }: Native & {\n variant?: \"primary\" | \"ghost\" | \"danger\"; size?: \"sm\";\n}) {\n const cls = [\"btn\", variant, size, className].filter(Boolean).join(\" \");\n return <button type={type} className={cls} {...rest} />;\n}\n\n/** `button.iconbtn`: a button with an icon only, so the label is required. */\nexport function IconButton({ label, fill, on, className, type = \"button\", ...rest }: Omit<Native, \"aria-label\"> & {\n label: string; fill?: boolean; on?: boolean;\n}) {\n const cls = [\"iconbtn\", fill && \"fill\", on && \"on\", className].filter(Boolean).join(\" \");\n return <button type={type} className={cls} aria-label={label} {...rest} />;\n}\n","import { useEffect, type ReactNode } from \"react\";\nimport { useOutside } from \"./ui\";\n\n/** `.menu`: a popover closed by Escape and by a click outside; it is mounted while\n * open. `onClose` must keep its identity between renders. What is inside\n * (sections `.sec`, lines `.line`, actions `.action`) belongs to the product. */\nexport function Menu({ onClose, label, className, children }: {\n onClose: () => void; label?: string; className?: string; children: ReactNode;\n}) {\n const ref = useOutside<HTMLDivElement>(true, onClose);\n // the focus returns to what opened the menu (CMP-05)\n useEffect(() => {\n const opener = document.activeElement as HTMLElement | null;\n return () => opener?.focus?.();\n }, []);\n return (\n <div className={`menu${className ? ` ${className}` : \"\"}`} role=\"dialog\" aria-label={label} ref={ref}>\n {children}\n </div>\n );\n}\n","import { useCallback, useState, type ReactNode } from \"react\";\nimport { useKitT } from \"../i18n\";\nimport { Icon } from \"./Icon\";\nimport { useOutside } from \"./ui\";\n\n/** The link of the product: the kit does not depend on a router (arch §4.2). */\nexport type LinkComponent = (props: {\n href: string; className?: string; onClick?: () => void; \"aria-current\"?: \"page\"; children: ReactNode;\n}) => ReactNode;\n\nexport interface TopBarSection { key: string; label: ReactNode; href: string; active: boolean }\n\n/** The top bar (FTR.NAB.CMN-0005 R5, design §4): the logo and the name, the\n * sections in a row and behind the burger on a phone, the actions of the product,\n * the avatar that opens the profile menu. The profile menu and the list of\n * sections are never open together. A part of the product with its own\n * navigation (the administration) puts it behind the burger in place of the\n * sections: `menu`, with the side panel marked `in-burger`, hidden on a phone. */\nexport function TopBar({ logo, name, home = \"/\", sections, Link, center, actions, avatar, profileMenu, menu }: {\n logo: string; name: string; home?: string; sections: TopBarSection[]; Link: LinkComponent;\n /** Between the sections and the actions: the search of Hammurapi. */\n center?: ReactNode;\n /** Before the avatar. */\n actions?: ReactNode;\n avatar: ReactNode;\n profileMenu: (close: () => void) => ReactNode;\n /** The burger of a phone in place of the sections: the navigation of the current part of the product and\n * its name, which the burger is called by. */\n menu?: { label: string; render: (close: () => void) => ReactNode };\n}) {\n const t = useKitT();\n const [profileOpen, setProfileOpen] = useState(false);\n const [sectionsOpen, setSectionsOpen] = useState(false);\n const closeSections = useCallback(() => setSectionsOpen(false), []);\n const closeProfile = useCallback(() => setProfileOpen(false), []);\n const ref = useOutside<HTMLDivElement>(sectionsOpen, closeSections);\n const links = sections.map((s) => (\n <Link key={s.key} href={s.href} className={s.active ? \"on\" : undefined} aria-current={s.active ? \"page\" : undefined} onClick={closeSections}>\n {s.label}\n </Link>\n ));\n return (\n <div className=\"topbar\">\n <Link href={home} className=\"brand\">\n <img src={logo} alt=\"\" />\n <span className=\"hide-m\">{name}</span>\n </Link>\n <nav className=\"nav hide-m\" aria-label={t(\"topbar.sections\")}>{links}</nav>\n {center}\n <div className=\"top-actions\">\n {actions}\n <button className=\"avatar\" style={profileOpen ? { boxShadow: \"0 0 0 2px var(--violet)\" } : undefined}\n onClick={() => { setSectionsOpen(false); setProfileOpen((v) => !v); }} aria-label={t(\"topbar.profile\")} aria-expanded={profileOpen}>\n {avatar}\n </button>\n <div className=\"burger\" ref={ref}>\n <button className={`iconbtn${sectionsOpen ? \" on\" : \"\"}`} onClick={() => { setProfileOpen(false); setSectionsOpen((v) => !v); }}\n aria-label={menu?.label ?? t(\"topbar.sections\")} aria-expanded={sectionsOpen} aria-controls=\"nav-sections\">\n <Icon name={sectionsOpen ? \"x\" : \"menu\"} />\n </button>\n {sectionsOpen && (menu\n ? <div id=\"nav-sections\" className=\"navmenu\">{menu.render(closeSections)}</div>\n : <nav id=\"nav-sections\" className=\"navmenu\" aria-label={t(\"topbar.sections\")}>{links}</nav>)}\n </div>\n </div>\n {profileOpen && profileMenu(closeProfile)}\n </div>\n );\n}\n","import { useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { forceCenter, forceCollide, forceLink, forceManyBody, forceSimulation } from \"d3-force\";\nimport { useKitT } from \"../i18n\";\nimport { Icon } from \"./Icon\";\n\nconst W = 760;\nconst H = 500;\n\n/** A node: `group` picks the colour (g-c1…g-c6), `size` the radius. */\nexport type GraphNode = {\n id: string; label: string; title?: string; group?: number; size?: number;\n /** Not in the data of the product, only referred to: a dashed outline. */\n dashed?: boolean;\n /** Context around the shown set: drawn faded. */\n muted?: boolean;\n /** The label shows only on hover, focus or highlight. */\n hideLabel?: boolean;\n /** With `rows` on the graph: the id of the row of the node and its place in it, ascending left to right. */\n row?: string;\n order?: number;\n};\nexport type GraphEdge = { source: string; target: string; weight?: number; directed?: boolean; dashed?: boolean; title?: string };\nexport type GraphSelection = { kind: \"node\"; id: string } | { kind: \"edge\"; source: string; target: string } | null;\n/** A row of the row layout, top to bottom in the order given; the label is drawn at its left. */\nexport type GraphRow = { id: string; label: string };\n\n/** A node with its place; the fields of d3-force are spelled out, so the types of the kit need no d3 types. */\ntype Placed = GraphNode & { r: number; index?: number; x?: number; y?: number; vx?: number; vy?: number; fx?: number | null; fy?: number | null };\ntype Field = { w: number; h: number };\n/** The places of the nodes, the size of the field and, in the row layout, the rows with their middle line. */\ntype Placement = { placed: Placed[]; field: Field; rows?: { id: string; label: string; y: number; x: number; x2: number }[] };\ntype Point = { x: number; y: number };\n\nconst radius = (size = 1) => 7 + Math.sqrt(size) * 3.2;\n\ntype View = { k: number; x: number; y: number };\n/** The view zoomed by `factor`, between 0.5 and 4, keeping the centre of the field in place. */\nconst zoomed = (v: View, factor: number, f: Field): View => {\n const k = Math.max(0.5, Math.min(4, v.k * factor));\n return { k, x: f.w / 2 - ((f.w / 2 - v.x) / v.k) * k, y: f.h / 2 - ((f.h / 2 - v.y) / v.k) * k };\n};\n\n/** Ids within `depth` steps of `from`, edges taken both ways. */\nexport function neighbours(edges: GraphEdge[], from: string, depth: number): Set<string> {\n const near = new Set([from]);\n let frontier = [from];\n for (let d = 0; d < depth; d++) {\n const next: string[] = [];\n for (const id of frontier) {\n for (const e of edges) {\n const other = e.source === id ? e.target : e.target === id ? e.source : null;\n if (other && !near.has(other)) { near.add(other); next.push(other); }\n }\n }\n frontier = next;\n }\n return near;\n}\n\n/** Positions of the nodes (exported for the tests): a force layout computed once per data. The start of\n * d3-force is deterministic, so the same data gives the same picture. */\nexport function layout(nodes: GraphNode[], edges: GraphEdge[]): Placed[] {\n const placed: Placed[] = nodes.map((n) => ({ ...n, r: radius(n.size) }));\n const ids = new Set(placed.map((n) => n.id));\n const links = edges.filter((e) => ids.has(e.source) && ids.has(e.target)).map((e) => ({ source: e.source, target: e.target, weight: e.weight ?? 1 }));\n const sim = forceSimulation(placed)\n .force(\"link\", forceLink<Placed, (typeof links)[number]>(links).id((d) => d.id).distance(90).strength((l) => Math.min(1, 0.2 + l.weight * 0.08)))\n .force(\"charge\", forceManyBody().strength(-260))\n .force(\"center\", forceCenter(W / 2, H / 2))\n .force(\"collide\", forceCollide<Placed>().radius((d) => d.r + 14))\n .stop();\n for (let i = 0; i < 260; i++) sim.tick();\n for (const n of placed) { // keep the labels inside the field\n n.x = Math.max(n.r + 30, Math.min(W - n.r - 30, n.x ?? W / 2));\n n.y = Math.max(n.r + 10, Math.min(H - n.r - 24, n.y ?? H / 2));\n }\n return placed;\n}\n\nconst GUTTER = 130; // the labels of the rows\nconst COL = 104;\nconst ROW = 76;\n\n/** The row layout (FTR.HMR.DEV-0002 R15, exported for the tests): a row per `rows` entry that has nodes, top to\n * bottom in the given order; in a row the nodes by `order`, then id, left to right. A node whose row is not\n * among `rows` goes to a last row without a label. The block is centred in a field at least as big as that of\n * the force layout. */\nexport function rowLayout(nodes: GraphNode[], rows: GraphRow[]): Placement {\n const index = new Map(rows.map((r, i) => [r.id, i]));\n const byRow = new Map<number, Placed[]>();\n const placed: Placed[] = nodes.map((n) => ({ ...n, r: radius(n.size) }));\n for (const n of placed) {\n const i = index.get(n.row ?? \"\") ?? rows.length;\n byRow.set(i, [...(byRow.get(i) ?? []), n]);\n }\n const used = [...byRow.keys()].toSorted((a, b) => a - b);\n const cols = Math.max(1, ...used.map((i) => byRow.get(i)!.length));\n const bw = GUTTER + cols * COL, bh = used.length * ROW;\n const field = { w: Math.max(W, bw + 40), h: Math.max(H, bh + 40) };\n const x0 = (field.w - bw) / 2, y0 = (field.h - bh) / 2;\n const lines = used.map((i, k) => {\n const y = y0 + ROW * (k + 0.5) - 8; // the label under a node takes the lower part of the row\n const inRow = byRow.get(i)!.toSorted((a, b) => (a.order ?? Infinity) - (b.order ?? Infinity) || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));\n inRow.forEach((n, j) => { n.x = x0 + GUTTER + COL * (j + 0.5); n.y = y; });\n return { id: rows[i]?.id ?? \"\", label: rows[i]?.label ?? \"\", y, x: x0 + 8, x2: x0 + bw };\n });\n return { placed, field, rows: lines };\n}\n\n/** The line of an edge: straight, or in the row layout an arc between two nodes of one row — above when it goes\n * right, below when it goes left, so links both ways do not cover each other. A directed line ends at the\n * circle of the target. */\nexport function edgeLine(a: Placed, b: Placed, directed: boolean, arcs: boolean): { d?: string; hit?: string; x1: number; y1: number; x2: number; y2: number } {\n const x1 = a.x ?? 0, y1 = a.y ?? 0;\n const bx = b.x ?? 0, by = b.y ?? 0;\n let x2 = bx, y2 = by;\n const arc = arcs && Math.abs(y2 - y1) < 1 && x1 !== x2;\n const cx = (x1 + x2) / 2;\n const cy = y1 - Math.sign(x2 - x1) * Math.min(ROW * 0.8, 14 + Math.abs(x2 - x1) * 0.25);\n if (directed) {\n const fx = arc ? cx : x1, fy = arc ? cy : y1; // the direction at the end: from the control point of the arc\n const dx = x2 - fx, dy = y2 - fy, len = Math.hypot(dx, dy) || 1;\n x2 -= (dx / len) * (b.r + 2);\n y2 -= (dy / len) * (b.r + 2);\n }\n // the line to click runs to the centre of the target, as the straight one does\n return arc ? { d: `M${x1},${y1} Q${cx},${cy} ${x2},${y2}`, hit: `M${x1},${y1} Q${cx},${cy} ${bx},${by}`, x1, y1, x2, y2 } : { x1, y1, x2, y2 };\n}\n\n/** A graph of nodes and links (FTR.NAB.CMN-0003 R19, FTR.HMR.DEV-0002 R15, R16).\n * Hovering highlights the neighbours, a click pins the selection; the wheel zooms,\n * dragging the field moves it. `focus` highlights a node and its neighbours within `depth`\n * steps; `onOpen` is called on a double click or Enter on a node. With `rows` the nodes stand in\n * rows (`GraphNode.row`, `order`) instead of the force layout; with `draggable` a node can be moved\n * and a button puts the moved nodes back. The kit knows nothing of what the nodes are: labels,\n * rows and the legend come from the product.\n * The layout runs when `nodes`, `edges` or `rows` change identity: keep them stable (useMemo). */\nexport function Graph({ nodes, edges, ariaLabel, selected, onSelect, focus, depth = 1, onOpen, legend, nodeLabel, rows, draggable }: {\n nodes: GraphNode[]; edges: GraphEdge[]; ariaLabel: string;\n selected: GraphSelection; onSelect: (s: GraphSelection) => void;\n focus?: string; depth?: 1 | 2;\n onOpen?: (id: string) => void;\n legend?: { group: number; label: string }[];\n nodeLabel?: (n: GraphNode) => string;\n rows?: GraphRow[];\n draggable?: boolean;\n}) {\n const t = useKitT();\n const arrow = `g-arrow-${useId().replace(/:/g, \"\")}`;\n const [hover, setHover] = useState<string | null>(null);\n const [view, setView] = useState<View>({ k: 1, x: 0, y: 0 });\n const drag = useRef<{ x: number; y: number; moved: boolean } | null>(null);\n const nodeDrag = useRef<{ id: string; x: number; y: number; moved: boolean } | null>(null);\n const movedAt = useRef(-Infinity); // the time of the end of the last move: a double click right after it opens nothing\n const svg = useRef<SVGSVGElement>(null);\n\n const layoutEdges = rows ? undefined : edges; // the rows do not depend on the edges: new edges keep the moved nodes\n const base = useMemo<Placement>(() => (rows ? rowLayout(nodes, rows) : { placed: layout(nodes, layoutEdges ?? []), field: { w: W, h: H } }), [nodes, layoutEdges, rows]);\n const { field } = base;\n // the moved nodes belong to one layout: new data puts every node back in its place\n const [moved, setMoved] = useState<{ of: Placement; at: Map<string, Point> } | null>(null);\n const at = moved?.of === base ? moved.at : undefined;\n const { placed, byId } = useMemo(() => {\n const p = at ? base.placed.map((n) => (at.has(n.id) ? { ...n, ...at.get(n.id) } : n)) : base.placed;\n return { placed: p, byId: new Map(p.map((n) => [n.id, n])) };\n }, [base, at]);\n\n const focused = focus !== undefined && byId.has(focus) ? focus : undefined; // a focus outside the data fades nothing\n const active = hover ?? (selected?.kind === \"node\" ? selected.id : null);\n const near = useMemo(() => {\n if (selected?.kind === \"edge\" && !hover) return new Set([selected.source, selected.target]);\n if (active) return neighbours(edges, active, 1);\n if (focused) return neighbours(edges, focused, depth);\n return new Set<string>();\n }, [active, selected, hover, focused, depth, edges]);\n const dimmed = near.size > 0;\n const edgeOn = (e: GraphEdge) => {\n if (selected?.kind === \"edge\" && !hover) return selected.source === e.source && selected.target === e.target;\n if (active) return e.source === active || e.target === active;\n return focused !== undefined && near.has(e.source) && near.has(e.target);\n };\n\n const zoom = (factor: number) => setView((v) => zoomed(v, factor, field));\n const pick = (id: string, pinned: boolean) => onSelect(pinned ? null : { kind: \"node\", id });\n /** Units of the field per pixel of the screen: the field is fitted into the box keeping its proportions. */\n const unit = (el: Element) => {\n const box = el.getBoundingClientRect();\n return 1 / (Math.min(box.width / field.w, box.height / field.h) || 1);\n };\n\n // The wheel zooms and does not scroll the page: React's onWheel is passive.\n useEffect(() => {\n const el = svg.current;\n if (!el) return;\n const wheel = (e: WheelEvent) => { e.preventDefault(); setView((v) => zoomed(v, e.deltaY < 0 ? 1.15 : 1 / 1.15, field)); };\n el.addEventListener(\"wheel\", wheel, { passive: false });\n return () => el.removeEventListener(\"wheel\", wheel);\n }, [field]);\n\n return (\n <div className=\"gwrap\">\n <svg ref={svg} viewBox={`0 0 ${field.w} ${field.h}`} role=\"group\" aria-label={ariaLabel} className={dimmed ? \"dimmed\" : undefined}\n onPointerDown={(e) => { if (e.target === e.currentTarget) { drag.current = { x: e.clientX, y: e.clientY, moved: false }; e.currentTarget.setPointerCapture(e.pointerId); } }}\n onPointerMove={(e) => {\n if (!drag.current) return;\n const u = unit(e.currentTarget);\n const dx = (e.clientX - drag.current.x) * u;\n const dy = (e.clientY - drag.current.y) * u;\n drag.current = { x: e.clientX, y: e.clientY, moved: drag.current.moved || dx !== 0 || dy !== 0 };\n setView((v) => ({ ...v, x: v.x + dx, y: v.y + dy }));\n }}\n onPointerUp={() => { if (!drag.current?.moved) drag.current = null; }}\n onClick={(e) => {\n const panned = drag.current?.moved; // a pan ends with a click on the field: it keeps the selection\n drag.current = null;\n if (!panned && e.target === e.currentTarget) onSelect(null);\n }}>\n {edges.some((e) => e.directed) && (\n <defs>\n <marker id={arrow} viewBox=\"0 0 10 10\" refX=\"10\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\">\n <path d=\"M0,0 L10,5 L0,10 z\" />\n </marker>\n </defs>\n )}\n <g transform={`translate(${view.x} ${view.y}) scale(${view.k})`}>\n {base.rows?.map((r, i) => (\n <g key={`${r.id}\\u0000${i}`} className=\"g-row\">\n {i > 0 && <line x1={r.x} x2={r.x2} y1={r.y - ROW / 2 + 8} y2={r.y - ROW / 2 + 8} />}\n <text x={r.x} y={r.y}>{r.label}</text>\n </g>\n ))}\n {edges.map((e, i) => {\n const a = byId.get(e.source), b = byId.get(e.target);\n if (!a || !b) return null;\n const l = edgeLine(a, b, !!e.directed, !!rows);\n const marker = e.directed ? `url(#${arrow})` : undefined;\n return (\n <g key={`${e.source}\\u0000${e.target}\\u0000${i}`} className={`g-e${e.dashed ? \" dashed\" : \"\"}${edgeOn(e) ? \" hl\" : \"\"}`}\n onClick={() => onSelect({ kind: \"edge\", source: e.source, target: e.target })}>\n {l.d ? (\n <>\n <path d={l.d} strokeWidth={1 + (e.weight ?? 1) * 0.5} markerEnd={marker} />\n <path className=\"hit\" d={l.hit} />\n </>\n ) : (\n <>\n <line x1={l.x1} y1={l.y1} x2={l.x2} y2={l.y2} strokeWidth={1 + (e.weight ?? 1) * 0.5} markerEnd={marker} />\n <line className=\"hit\" x1={a.x} y1={a.y} x2={b.x} y2={b.y} />\n </>\n )}\n {e.title && <title>{e.title}</title>}\n </g>\n );\n })}\n {placed.map((n) => {\n const pinned = selected?.kind === \"node\" && selected.id === n.id;\n const cls = [\"g-n\", `g-c${n.group ?? 1}`, n.hideLabel && \"small\", n.dashed && \"dashed\", n.muted && \"muted\",\n near.has(n.id) && \"hl\", pinned && \"pin\", focused === n.id && \"focus\"].filter(Boolean).join(\" \");\n return (\n <g key={n.id} className={cls}\n tabIndex={0} role=\"button\" aria-pressed={pinned} aria-label={nodeLabel ? nodeLabel(n) : n.label}\n onMouseEnter={() => setHover(n.id)} onMouseLeave={() => setHover(null)} onFocus={() => setHover(n.id)} onBlur={() => setHover(null)}\n onPointerDown={draggable ? (e) => {\n if (e.button !== 0) return;\n nodeDrag.current = { id: n.id, x: e.clientX, y: e.clientY, moved: false };\n e.currentTarget.setPointerCapture(e.pointerId);\n } : undefined}\n onPointerMove={draggable ? (e) => {\n const d = nodeDrag.current;\n if (!d || d.id !== n.id) return;\n if (!d.moved && Math.hypot(e.clientX - d.x, e.clientY - d.y) < 4) return; // a click is not a move\n const u = svg.current ? unit(svg.current) / view.k : 1;\n const dx = (e.clientX - d.x) * u, dy = (e.clientY - d.y) * u;\n nodeDrag.current = { id: n.id, x: e.clientX, y: e.clientY, moved: true };\n setMoved((m) => {\n const next = new Map(m?.of === base ? m.at : []);\n const p = next.get(n.id) ?? { x: n.x ?? 0, y: n.y ?? 0 };\n next.set(n.id, { x: p.x + dx, y: p.y + dy });\n return { of: base, at: next };\n });\n } : undefined}\n onPointerUp={draggable ? (e) => {\n if (!nodeDrag.current?.moved) return;\n movedAt.current = e.timeStamp;\n // the click that ends a move comes right after: if none comes, the move must not swallow the next one\n setTimeout(() => { nodeDrag.current = null; }, 0);\n } : undefined}\n onPointerCancel={draggable ? () => { nodeDrag.current = null; } : undefined}\n onClick={() => {\n const wasMoved = nodeDrag.current?.moved; // a move ends with a click on the node: it neither pins nor opens\n nodeDrag.current = null;\n if (!wasMoved) pick(n.id, pinned);\n }}\n onDoubleClick={(e) => { if (e.timeStamp - movedAt.current > 600) onOpen?.(n.id); }}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && onOpen) { e.preventDefault(); onOpen(n.id); return; }\n if (e.key === \"Enter\" || e.key === \" \") { e.preventDefault(); pick(n.id, pinned); }\n }}>\n <circle cx={n.x} cy={n.y} r={n.r} />\n <text x={n.x} y={(n.y ?? 0) + n.r + 14}>{n.label}</text>\n {n.title && <title>{n.title}</title>}\n </g>\n );\n })}\n </g>\n </svg>\n {legend && legend.length > 0 && (\n <div className=\"gleg\">{legend.map((l) => <span key={l.group}><i className={`g-c${l.group}`} />{l.label}</span>)}</div>\n )}\n <div className=\"gzoom\">\n <button type=\"button\" onClick={() => zoom(1.3)} aria-label={t(\"graph.zoomIn\")}>+</button>\n <button type=\"button\" onClick={() => zoom(1 / 1.3)} aria-label={t(\"graph.zoomOut\")}>−</button>\n {at && at.size > 0 && (\n <button type=\"button\" onClick={() => setMoved(null)} aria-label={t(\"graph.resetLayout\")} title={t(\"graph.resetLayout\")}>\n <Icon name=\"reset\" size={14} />\n </button>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["_Fragment","Switch","useToast","GitHubIcon","Icon","Tabs","Empty","ToastProvider","Loading","useOutside","Avatar","Markdown","useKitT","UIKIT_NS","Button","rest","cls","variant","size","className","IconButton","fill","on","label","Menu","ref","onClose","useEffect","opener","TopBar","t","profileOpen","setProfileOpen","useState","sectionsOpen","setSectionsOpen","closeSections","useCallback","closeProfile","links","sections","Link","s","home","logo","name","center","actions","v","avatar","menu","profileMenu","W","H","radius","zoomed","k","factor","f","neighbours","near","from","frontier","d","depth","next","id","e","edges","other","layout","placed","nodes","n","ids","sim","forceSimulation","forceLink","l","forceManyBody","forceCenter","forceCollide","i","GUTTER","COL","ROW","rowLayout","index","rows","r","byRow","used","a","b","bw","bh","field","x0","y0","y","j","edgeLine","x1","y1","bx","by","x2","y2","arc","arcs","cx","cy","directed","fx","fy","dx","dy","len","Graph","arrow","useId","hover","setHover","view","setView","drag","useRef","nodeDrag","movedAt","svg","layoutEdges","base","useMemo","moved","setMoved","at","p","focused","focus","byId","active","selected","dimmed","edgeOn","zoom","pick","onSelect","pinned","unit","box","el","wheel","ariaLabel","u","panned","marker","Fragment","nodeLabel","draggable","m","wasMoved","onOpen","legend","Modal"],"sources":["../src/components/Button.tsx","../src/components/Menu.tsx","../src/components/TopBar.tsx","../src/components/Graph.tsx"],"sourcesContent":["import type { ButtonHTMLAttributes } from \"react\";\n\ntype Native = ButtonHTMLAttributes<HTMLButtonElement>;\n\n/** `button.btn` with its variants. The classes stay a legitimate way to use a\n * button (FTR.NAB.CMN-0005 tech, decision 1); the component is for new code. */\nexport function Button({ variant, size, className, type = \"button\", ...rest }: Native & {\n variant?: \"primary\" | \"ghost\" | \"danger\"; size?: \"sm\";\n}) {\n const cls = [\"btn\", variant, size, className].filter(Boolean).join(\" \");\n return <button type={type} className={cls} {...rest} />;\n}\n\n/** `button.iconbtn`: a button with an icon only, so the label is required. */\nexport function IconButton({ label, fill, on, className, type = \"button\", ...rest }: Omit<Native, \"aria-label\"> & {\n label: string; fill?: boolean; on?: boolean;\n}) {\n const cls = [\"iconbtn\", fill && \"fill\", on && \"on\", className].filter(Boolean).join(\" \");\n return <button type={type} className={cls} aria-label={label} {...rest} />;\n}\n","import { useEffect, type ReactNode } from \"react\";\nimport { useOutside } from \"./ui\";\n\n/** `.menu`: a popover closed by Escape and by a click outside; it is mounted while\n * open. `onClose` must keep its identity between renders. What is inside\n * (sections `.sec`, lines `.line`, actions `.action`) belongs to the product. */\nexport function Menu({ onClose, label, className, children }: {\n onClose: () => void; label?: string; className?: string; children: ReactNode;\n}) {\n const ref = useOutside<HTMLDivElement>(true, onClose);\n // the focus returns to what opened the menu (CMP-05)\n useEffect(() => {\n const opener = document.activeElement as HTMLElement | null;\n return () => opener?.focus?.();\n }, []);\n return (\n <div className={`menu${className ? ` ${className}` : \"\"}`} role=\"dialog\" aria-label={label} ref={ref}>\n {children}\n </div>\n );\n}\n","import { useCallback, useState, type ReactNode } from \"react\";\nimport { useKitT } from \"../i18n\";\nimport { Icon } from \"./Icon\";\nimport { useOutside } from \"./ui\";\n\n/** The link of the product: the kit does not depend on a router (arch §4.2). */\nexport type LinkComponent = (props: {\n href: string; className?: string; onClick?: () => void; \"aria-current\"?: \"page\"; children: ReactNode;\n}) => ReactNode;\n\nexport interface TopBarSection { key: string; label: ReactNode; href: string; active: boolean }\n\n/** The top bar (FTR.NAB.CMN-0005 R5, design §4): the logo and the name, the\n * sections in a row and behind the burger on a phone, the actions of the product,\n * the avatar that opens the profile menu. The profile menu and the list of\n * sections are never open together. A part of the product with its own\n * navigation (the administration) puts it behind the burger in place of the\n * sections: `menu`, with the side panel marked `in-burger`, hidden on a phone. */\nexport function TopBar({ logo, name, home = \"/\", sections, Link, center, actions, avatar, profileMenu, menu }: {\n logo: string; name: string; home?: string; sections: TopBarSection[]; Link: LinkComponent;\n /** Between the sections and the actions: the search of Hammurapi. */\n center?: ReactNode;\n /** Before the avatar. */\n actions?: ReactNode;\n avatar: ReactNode;\n profileMenu: (close: () => void) => ReactNode;\n /** The burger of a phone in place of the sections: the navigation of the current part of the product and\n * its name, which the burger is called by. */\n menu?: { label: string; render: (close: () => void) => ReactNode };\n}) {\n const t = useKitT();\n const [profileOpen, setProfileOpen] = useState(false);\n const [sectionsOpen, setSectionsOpen] = useState(false);\n const closeSections = useCallback(() => setSectionsOpen(false), []);\n const closeProfile = useCallback(() => setProfileOpen(false), []);\n const ref = useOutside<HTMLDivElement>(sectionsOpen, closeSections);\n const links = sections.map((s) => (\n <Link key={s.key} href={s.href} className={s.active ? \"on\" : undefined} aria-current={s.active ? \"page\" : undefined} onClick={closeSections}>\n {s.label}\n </Link>\n ));\n return (\n <div className=\"topbar\">\n <Link href={home} className=\"brand\">\n <img src={logo} alt=\"\" />\n <span className=\"hide-m\">{name}</span>\n </Link>\n <nav className=\"nav hide-m\" aria-label={t(\"topbar.sections\")}>{links}</nav>\n {center}\n <div className=\"top-actions\">\n {actions}\n <button className=\"avatar\" style={profileOpen ? { boxShadow: \"0 0 0 2px var(--violet)\" } : undefined}\n onClick={() => { setSectionsOpen(false); setProfileOpen((v) => !v); }} aria-label={t(\"topbar.profile\")} aria-expanded={profileOpen}>\n {avatar}\n </button>\n <div className=\"burger\" ref={ref}>\n <button className={`iconbtn${sectionsOpen ? \" on\" : \"\"}`} onClick={() => { setProfileOpen(false); setSectionsOpen((v) => !v); }}\n aria-label={menu?.label ?? t(\"topbar.sections\")} aria-expanded={sectionsOpen} aria-controls=\"nav-sections\">\n <Icon name={sectionsOpen ? \"x\" : \"menu\"} />\n </button>\n {sectionsOpen && (menu\n ? <div id=\"nav-sections\" className=\"navmenu\">{menu.render(closeSections)}</div>\n : <nav id=\"nav-sections\" className=\"navmenu\" aria-label={t(\"topbar.sections\")}>{links}</nav>)}\n </div>\n </div>\n {profileOpen && profileMenu(closeProfile)}\n </div>\n );\n}\n","import { useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { forceCenter, forceCollide, forceLink, forceManyBody, forceSimulation } from \"d3-force\";\nimport { useKitT } from \"../i18n\";\nimport { Icon } from \"./Icon\";\n\nconst W = 760;\nconst H = 500;\n\n/** A node: `group` picks the colour (g-c1…g-c6), `size` the radius. */\nexport type GraphNode = {\n id: string; label: string; title?: string; group?: number; size?: number;\n /** Not in the data of the product, only referred to: a dashed outline. */\n dashed?: boolean;\n /** Context around the shown set: drawn faded. */\n muted?: boolean;\n /** The label shows only on hover, focus or highlight. */\n hideLabel?: boolean;\n /** With `rows` on the graph: the id of the row of the node and its place in it, ascending left to right. */\n row?: string;\n order?: number;\n};\n/** A link; `double` draws it as a double line — another layer of links, told apart without colour\n * (FTR.HMR.DEV-0003 R15); it combines with `dashed`. */\nexport type GraphEdge = { source: string; target: string; weight?: number; directed?: boolean; dashed?: boolean; double?: boolean; title?: string };\nexport type GraphSelection = { kind: \"node\"; id: string } | { kind: \"edge\"; source: string; target: string } | null;\n/** A row of the row layout, top to bottom in the order given; the label is drawn at its left. */\nexport type GraphRow = { id: string; label: string };\n\n/** A node with its place; the fields of d3-force are spelled out, so the types of the kit need no d3 types. */\ntype Placed = GraphNode & { r: number; index?: number; x?: number; y?: number; vx?: number; vy?: number; fx?: number | null; fy?: number | null };\ntype Field = { w: number; h: number };\n/** The places of the nodes, the size of the field and, in the row layout, the rows with their middle line. */\ntype Placement = { placed: Placed[]; field: Field; rows?: { id: string; label: string; y: number; x: number; x2: number }[] };\ntype Point = { x: number; y: number };\n\nconst radius = (size = 1) => 7 + Math.sqrt(size) * 3.2;\n\ntype View = { k: number; x: number; y: number };\n/** The view zoomed by `factor`, between 0.5 and 4, keeping the centre of the field in place. */\nconst zoomed = (v: View, factor: number, f: Field): View => {\n const k = Math.max(0.5, Math.min(4, v.k * factor));\n return { k, x: f.w / 2 - ((f.w / 2 - v.x) / v.k) * k, y: f.h / 2 - ((f.h / 2 - v.y) / v.k) * k };\n};\n\n/** Ids within `depth` steps of `from`, edges taken both ways. */\nexport function neighbours(edges: GraphEdge[], from: string, depth: number): Set<string> {\n const near = new Set([from]);\n let frontier = [from];\n for (let d = 0; d < depth; d++) {\n const next: string[] = [];\n for (const id of frontier) {\n for (const e of edges) {\n const other = e.source === id ? e.target : e.target === id ? e.source : null;\n if (other && !near.has(other)) { near.add(other); next.push(other); }\n }\n }\n frontier = next;\n }\n return near;\n}\n\n/** Positions of the nodes (exported for the tests): a force layout computed once per data. The start of\n * d3-force is deterministic, so the same data gives the same picture. */\nexport function layout(nodes: GraphNode[], edges: GraphEdge[]): Placed[] {\n const placed: Placed[] = nodes.map((n) => ({ ...n, r: radius(n.size) }));\n const ids = new Set(placed.map((n) => n.id));\n const links = edges.filter((e) => ids.has(e.source) && ids.has(e.target)).map((e) => ({ source: e.source, target: e.target, weight: e.weight ?? 1 }));\n const sim = forceSimulation(placed)\n .force(\"link\", forceLink<Placed, (typeof links)[number]>(links).id((d) => d.id).distance(90).strength((l) => Math.min(1, 0.2 + l.weight * 0.08)))\n .force(\"charge\", forceManyBody().strength(-260))\n .force(\"center\", forceCenter(W / 2, H / 2))\n .force(\"collide\", forceCollide<Placed>().radius((d) => d.r + 14))\n .stop();\n for (let i = 0; i < 260; i++) sim.tick();\n for (const n of placed) { // keep the labels inside the field\n n.x = Math.max(n.r + 30, Math.min(W - n.r - 30, n.x ?? W / 2));\n n.y = Math.max(n.r + 10, Math.min(H - n.r - 24, n.y ?? H / 2));\n }\n return placed;\n}\n\nconst GUTTER = 130; // the labels of the rows\nconst COL = 104;\nconst ROW = 76;\n\n/** The row layout (FTR.HMR.DEV-0002 R15, exported for the tests): a row per `rows` entry that has nodes, top to\n * bottom in the given order; in a row the nodes by `order`, then id, left to right. A node whose row is not\n * among `rows` goes to a last row without a label. The block is centred in a field at least as big as that of\n * the force layout. */\nexport function rowLayout(nodes: GraphNode[], rows: GraphRow[]): Placement {\n const index = new Map(rows.map((r, i) => [r.id, i]));\n const byRow = new Map<number, Placed[]>();\n const placed: Placed[] = nodes.map((n) => ({ ...n, r: radius(n.size) }));\n for (const n of placed) {\n const i = index.get(n.row ?? \"\") ?? rows.length;\n byRow.set(i, [...(byRow.get(i) ?? []), n]);\n }\n const used = [...byRow.keys()].toSorted((a, b) => a - b);\n const cols = Math.max(1, ...used.map((i) => byRow.get(i)!.length));\n const bw = GUTTER + cols * COL, bh = used.length * ROW;\n const field = { w: Math.max(W, bw + 40), h: Math.max(H, bh + 40) };\n const x0 = (field.w - bw) / 2, y0 = (field.h - bh) / 2;\n const lines = used.map((i, k) => {\n const y = y0 + ROW * (k + 0.5) - 8; // the label under a node takes the lower part of the row\n const inRow = byRow.get(i)!.toSorted((a, b) => (a.order ?? Infinity) - (b.order ?? Infinity) || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));\n inRow.forEach((n, j) => { n.x = x0 + GUTTER + COL * (j + 0.5); n.y = y; });\n return { id: rows[i]?.id ?? \"\", label: rows[i]?.label ?? \"\", y, x: x0 + 8, x2: x0 + bw };\n });\n return { placed, field, rows: lines };\n}\n\n/** The line of an edge: straight, or in the row layout an arc between two nodes of one row — above when it goes\n * right, below when it goes left, so links both ways do not cover each other. A directed line ends at the\n * circle of the target. */\nexport function edgeLine(a: Placed, b: Placed, directed: boolean, arcs: boolean): { d?: string; hit?: string; x1: number; y1: number; x2: number; y2: number } {\n const x1 = a.x ?? 0, y1 = a.y ?? 0;\n const bx = b.x ?? 0, by = b.y ?? 0;\n let x2 = bx, y2 = by;\n const arc = arcs && Math.abs(y2 - y1) < 1 && x1 !== x2;\n const cx = (x1 + x2) / 2;\n const cy = y1 - Math.sign(x2 - x1) * Math.min(ROW * 0.8, 14 + Math.abs(x2 - x1) * 0.25);\n if (directed) {\n const fx = arc ? cx : x1, fy = arc ? cy : y1; // the direction at the end: from the control point of the arc\n const dx = x2 - fx, dy = y2 - fy, len = Math.hypot(dx, dy) || 1;\n x2 -= (dx / len) * (b.r + 2);\n y2 -= (dy / len) * (b.r + 2);\n }\n // the line to click runs to the centre of the target, as the straight one does\n return arc ? { d: `M${x1},${y1} Q${cx},${cy} ${x2},${y2}`, hit: `M${x1},${y1} Q${cx},${cy} ${bx},${by}`, x1, y1, x2, y2 } : { x1, y1, x2, y2 };\n}\n\n/** A graph of nodes and links (FTR.NAB.CMN-0003 R19, FTR.HMR.DEV-0002 R15, R16).\n * Hovering highlights the neighbours, a click pins the selection; the wheel zooms,\n * dragging the field moves it. `focus` highlights a node and its neighbours within `depth`\n * steps; `onOpen` is called on a double click or Enter on a node. With `rows` the nodes stand in\n * rows (`GraphNode.row`, `order`) instead of the force layout; with `draggable` a node can be moved\n * and a button puts the moved nodes back. The kit knows nothing of what the nodes are: labels,\n * rows and the legend come from the product.\n * The layout runs when `nodes`, `edges` or `rows` change identity: keep them stable (useMemo). */\nexport function Graph({ nodes, edges, ariaLabel, selected, onSelect, focus, depth = 1, onOpen, legend, nodeLabel, rows, draggable }: {\n nodes: GraphNode[]; edges: GraphEdge[]; ariaLabel: string;\n selected: GraphSelection; onSelect: (s: GraphSelection) => void;\n focus?: string; depth?: 1 | 2;\n onOpen?: (id: string) => void;\n legend?: { group: number; label: string }[];\n nodeLabel?: (n: GraphNode) => string;\n rows?: GraphRow[];\n draggable?: boolean;\n}) {\n const t = useKitT();\n const arrow = `g-arrow-${useId().replace(/:/g, \"\")}`;\n const [hover, setHover] = useState<string | null>(null);\n const [view, setView] = useState<View>({ k: 1, x: 0, y: 0 });\n const drag = useRef<{ x: number; y: number; moved: boolean } | null>(null);\n const nodeDrag = useRef<{ id: string; x: number; y: number; moved: boolean } | null>(null);\n const movedAt = useRef(-Infinity); // the time of the end of the last move: a double click right after it opens nothing\n const svg = useRef<SVGSVGElement>(null);\n\n const layoutEdges = rows ? undefined : edges; // the rows do not depend on the edges: new edges keep the moved nodes\n const base = useMemo<Placement>(() => (rows ? rowLayout(nodes, rows) : { placed: layout(nodes, layoutEdges ?? []), field: { w: W, h: H } }), [nodes, layoutEdges, rows]);\n const { field } = base;\n // the moved nodes belong to one layout: new data puts every node back in its place\n const [moved, setMoved] = useState<{ of: Placement; at: Map<string, Point> } | null>(null);\n const at = moved?.of === base ? moved.at : undefined;\n const { placed, byId } = useMemo(() => {\n const p = at ? base.placed.map((n) => (at.has(n.id) ? { ...n, ...at.get(n.id) } : n)) : base.placed;\n return { placed: p, byId: new Map(p.map((n) => [n.id, n])) };\n }, [base, at]);\n\n const focused = focus !== undefined && byId.has(focus) ? focus : undefined; // a focus outside the data fades nothing\n const active = hover ?? (selected?.kind === \"node\" ? selected.id : null);\n const near = useMemo(() => {\n if (selected?.kind === \"edge\" && !hover) return new Set([selected.source, selected.target]);\n if (active) return neighbours(edges, active, 1);\n if (focused) return neighbours(edges, focused, depth);\n return new Set<string>();\n }, [active, selected, hover, focused, depth, edges]);\n const dimmed = near.size > 0;\n const edgeOn = (e: GraphEdge) => {\n if (selected?.kind === \"edge\" && !hover) return selected.source === e.source && selected.target === e.target;\n if (active) return e.source === active || e.target === active;\n return focused !== undefined && near.has(e.source) && near.has(e.target);\n };\n\n const zoom = (factor: number) => setView((v) => zoomed(v, factor, field));\n const pick = (id: string, pinned: boolean) => onSelect(pinned ? null : { kind: \"node\", id });\n /** Units of the field per pixel of the screen: the field is fitted into the box keeping its proportions. */\n const unit = (el: Element) => {\n const box = el.getBoundingClientRect();\n return 1 / (Math.min(box.width / field.w, box.height / field.h) || 1);\n };\n\n // The wheel zooms and does not scroll the page: React's onWheel is passive.\n useEffect(() => {\n const el = svg.current;\n if (!el) return;\n const wheel = (e: WheelEvent) => { e.preventDefault(); setView((v) => zoomed(v, e.deltaY < 0 ? 1.15 : 1 / 1.15, field)); };\n el.addEventListener(\"wheel\", wheel, { passive: false });\n return () => el.removeEventListener(\"wheel\", wheel);\n }, [field]);\n\n return (\n <div className=\"gwrap\">\n <svg ref={svg} viewBox={`0 0 ${field.w} ${field.h}`} role=\"group\" aria-label={ariaLabel} className={dimmed ? \"dimmed\" : undefined}\n onPointerDown={(e) => { if (e.target === e.currentTarget) { drag.current = { x: e.clientX, y: e.clientY, moved: false }; e.currentTarget.setPointerCapture(e.pointerId); } }}\n onPointerMove={(e) => {\n if (!drag.current) return;\n const u = unit(e.currentTarget);\n const dx = (e.clientX - drag.current.x) * u;\n const dy = (e.clientY - drag.current.y) * u;\n drag.current = { x: e.clientX, y: e.clientY, moved: drag.current.moved || dx !== 0 || dy !== 0 };\n setView((v) => ({ ...v, x: v.x + dx, y: v.y + dy }));\n }}\n onPointerUp={() => { if (!drag.current?.moved) drag.current = null; }}\n onClick={(e) => {\n const panned = drag.current?.moved; // a pan ends with a click on the field: it keeps the selection\n drag.current = null;\n if (!panned && e.target === e.currentTarget) onSelect(null);\n }}>\n {edges.some((e) => e.directed) && (\n <defs>\n <marker id={arrow} viewBox=\"0 0 10 10\" refX=\"10\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\">\n <path d=\"M0,0 L10,5 L0,10 z\" />\n </marker>\n </defs>\n )}\n <g transform={`translate(${view.x} ${view.y}) scale(${view.k})`}>\n {base.rows?.map((r, i) => (\n <g key={`${r.id}\\u0000${i}`} className=\"g-row\">\n {i > 0 && <line x1={r.x} x2={r.x2} y1={r.y - ROW / 2 + 8} y2={r.y - ROW / 2 + 8} />}\n <text x={r.x} y={r.y}>{r.label}</text>\n </g>\n ))}\n {edges.map((e, i) => {\n const a = byId.get(e.source), b = byId.get(e.target);\n if (!a || !b) return null;\n const l = edgeLine(a, b, !!e.directed, !!rows);\n const marker = e.directed ? `url(#${arrow})` : undefined;\n return (\n <g key={`${e.source}\\u0000${e.target}\\u0000${i}`} className={`g-e${e.dashed ? \" dashed\" : \"\"}${e.double ? \" double\" : \"\"}${edgeOn(e) ? \" hl\" : \"\"}`}\n onClick={() => onSelect({ kind: \"edge\", source: e.source, target: e.target })}>\n {l.d ? (\n <>\n {/* a double line takes the arrow on its inner line: the size of a marker follows the width of the line */}\n <path d={l.d} strokeWidth={1 + (e.weight ?? 1) * 0.5 + (e.double ? 3 : 0)} markerEnd={e.double ? undefined : marker} />\n {e.double && <path className=\"inner\" d={l.d} markerEnd={marker} />}\n <path className=\"hit\" d={l.hit} />\n </>\n ) : (\n <>\n <line x1={l.x1} y1={l.y1} x2={l.x2} y2={l.y2} strokeWidth={1 + (e.weight ?? 1) * 0.5 + (e.double ? 3 : 0)} markerEnd={e.double ? undefined : marker} />\n {e.double && <line className=\"inner\" x1={l.x1} y1={l.y1} x2={l.x2} y2={l.y2} markerEnd={marker} />}\n <line className=\"hit\" x1={a.x} y1={a.y} x2={b.x} y2={b.y} />\n </>\n )}\n {e.title && <title>{e.title}</title>}\n </g>\n );\n })}\n {placed.map((n) => {\n const pinned = selected?.kind === \"node\" && selected.id === n.id;\n const cls = [\"g-n\", `g-c${n.group ?? 1}`, n.hideLabel && \"small\", n.dashed && \"dashed\", n.muted && \"muted\",\n near.has(n.id) && \"hl\", pinned && \"pin\", focused === n.id && \"focus\"].filter(Boolean).join(\" \");\n return (\n <g key={n.id} className={cls}\n tabIndex={0} role=\"button\" aria-pressed={pinned} aria-label={nodeLabel ? nodeLabel(n) : n.label}\n onMouseEnter={() => setHover(n.id)} onMouseLeave={() => setHover(null)} onFocus={() => setHover(n.id)} onBlur={() => setHover(null)}\n onPointerDown={draggable ? (e) => {\n if (e.button !== 0) return;\n nodeDrag.current = { id: n.id, x: e.clientX, y: e.clientY, moved: false };\n e.currentTarget.setPointerCapture(e.pointerId);\n } : undefined}\n onPointerMove={draggable ? (e) => {\n const d = nodeDrag.current;\n if (!d || d.id !== n.id) return;\n if (!d.moved && Math.hypot(e.clientX - d.x, e.clientY - d.y) < 4) return; // a click is not a move\n const u = svg.current ? unit(svg.current) / view.k : 1;\n const dx = (e.clientX - d.x) * u, dy = (e.clientY - d.y) * u;\n nodeDrag.current = { id: n.id, x: e.clientX, y: e.clientY, moved: true };\n setMoved((m) => {\n const next = new Map(m?.of === base ? m.at : []);\n const p = next.get(n.id) ?? { x: n.x ?? 0, y: n.y ?? 0 };\n next.set(n.id, { x: p.x + dx, y: p.y + dy });\n return { of: base, at: next };\n });\n } : undefined}\n onPointerUp={draggable ? (e) => {\n if (!nodeDrag.current?.moved) return;\n movedAt.current = e.timeStamp;\n // the click that ends a move comes right after: if none comes, the move must not swallow the next one\n setTimeout(() => { nodeDrag.current = null; }, 0);\n } : undefined}\n onPointerCancel={draggable ? () => { nodeDrag.current = null; } : undefined}\n onClick={() => {\n const wasMoved = nodeDrag.current?.moved; // a move ends with a click on the node: it neither pins nor opens\n nodeDrag.current = null;\n if (!wasMoved) pick(n.id, pinned);\n }}\n onDoubleClick={(e) => { if (e.timeStamp - movedAt.current > 600) onOpen?.(n.id); }}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && onOpen) { e.preventDefault(); onOpen(n.id); return; }\n if (e.key === \"Enter\" || e.key === \" \") { e.preventDefault(); pick(n.id, pinned); }\n }}>\n <circle cx={n.x} cy={n.y} r={n.r} />\n <text x={n.x} y={(n.y ?? 0) + n.r + 14}>{n.label}</text>\n {n.title && <title>{n.title}</title>}\n </g>\n );\n })}\n </g>\n </svg>\n {legend && legend.length > 0 && (\n <div className=\"gleg\">{legend.map((l) => <span key={l.group}><i className={`g-c${l.group}`} />{l.label}</span>)}</div>\n )}\n <div className=\"gzoom\">\n <button type=\"button\" onClick={() => zoom(1.3)} aria-label={t(\"graph.zoomIn\")}>+</button>\n <button type=\"button\" onClick={() => zoom(1 / 1.3)} aria-label={t(\"graph.zoomOut\")}>−</button>\n {at && at.size > 0 && (\n <button type=\"button\" onClick={() => setMoved(null)} aria-label={t(\"graph.resetLayout\")} title={t(\"graph.resetLayout\")}>\n <Icon name=\"reset\" size={14} />\n </button>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
package/dist/manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.
|
|
2
|
+
"version": "1.15.0",
|
|
3
3
|
"classes": [
|
|
4
4
|
"a",
|
|
5
5
|
"action",
|
|
@@ -73,6 +73,7 @@
|
|
|
73
73
|
"dimmed",
|
|
74
74
|
"dl",
|
|
75
75
|
"dot",
|
|
76
|
+
"double",
|
|
76
77
|
"draft",
|
|
77
78
|
"ds",
|
|
78
79
|
"edit",
|
|
@@ -125,6 +126,7 @@
|
|
|
125
126
|
"image",
|
|
126
127
|
"in-burger",
|
|
127
128
|
"inherit",
|
|
129
|
+
"inner",
|
|
128
130
|
"inp",
|
|
129
131
|
"it",
|
|
130
132
|
"keys",
|
package/dist/styles.css
CHANGED
|
@@ -526,6 +526,15 @@ h3.sec {
|
|
|
526
526
|
stroke: var(--violet);
|
|
527
527
|
stroke-dasharray: 6 4;
|
|
528
528
|
}
|
|
529
|
+
/* a double line: the line 3 wider (Graph.tsx), a line of the colour of the field inside it (FTR.HMR.DEV-0003 R15) */
|
|
530
|
+
.g-e.double .inner {
|
|
531
|
+
stroke: var(--surface);
|
|
532
|
+
stroke-width: 1.5;
|
|
533
|
+
pointer-events: none;
|
|
534
|
+
}
|
|
535
|
+
.g-e.double.dashed .inner {
|
|
536
|
+
stroke-dasharray: 6 4;
|
|
537
|
+
}
|
|
529
538
|
.gwrap marker path {
|
|
530
539
|
fill: var(--border-strong);
|
|
531
540
|
}
|
package/package.json
CHANGED