sanity-plugin-graph-view

5.0.135.0.14
dist/GraphView.js
dist/GraphView.jsDeleted
−286
Index: package/dist/GraphView.js
===================================================================
--- package/dist/GraphView.js
+++ package/dist/GraphView.js
@@ -1,286 +0,0 @@
-import { useEffect, useState } from "react";
-import { useClient, useUserColorManager } from "sanity";
-import { useRouter } from "sanity/router";
-import { jsx, jsxs } from "react/jsx-runtime";
-import { COLOR_HUES, black, gray, hues, white } from "@sanity/color";
-import { useTheme } from "@sanity/ui";
-import BezierEasing from "bezier-easing";
-import deepEqual from "deep-equal";
-import { rgba } from "polished";
-import ForceGraph2D from "react-force-graph-2d";
-import { v4 } from "uuid";
-import { styled } from "styled-components";
-const GraphRoot = styled.div.withConfig({
-	displayName: "GraphRoot",
-	componentId: "sc-kbb958-0"
-})`font-family:${({ theme }) => theme.fonts.text.family};position:absolute;top:0;left:0;width:100%;height:100%;background:${black.hex};`, GraphWrapper = styled.div.withConfig({
-	displayName: "GraphWrapper",
-	componentId: "sc-kbb958-1"
-})`position:relative;width:100%;height:100%;`, HoverNode = styled.div.withConfig({
-	displayName: "HoverNode",
-	componentId: "sc-kbb958-2"
-})`font-family:${({ theme }) => theme.fonts.text.family};display:none;position:absolute;bottom:${({ theme }) => theme.space[0]}px;left:50%;transform:translate3d(-50%,0,0);background:var(--component-bg);border-radius:${({ theme }) => theme.radius[2]}px;padding:${({ theme }) => theme.space[2]}px;z-index:1000;&:empty{display:none;}`, Legend = styled.div.withConfig({
-	displayName: "Legend",
-	componentId: "sc-kbb958-3"
-})`color:#ccc;position:absolute;top:${({ theme }) => theme.space[4]}px;left:${({ theme }) => theme.space[4]}px;& > div{margin:5px 0;}`, LegendRow = styled.div.withConfig({
-	displayName: "LegendRow",
-	componentId: "sc-kbb958-4"
-})`display:flex;`, LegendBadge = styled.div.withConfig({
-	displayName: "LegendBadge",
-	componentId: "sc-kbb958-5"
-})`width:1.25em;height:1.25em;background:currentColor;border-radius:50%;margin-right:${({ theme }) => theme.space[2]}px;`;
-function sizeOf(value) {
-	return value === null ? 0 : typeof value == "object" ? Object.entries(value).reduce((total, [k, v]) => total + sizeOf(k) + sizeOf(v), 0) : Array.isArray(value) ? Object.entries(value).reduce((total, v) => total + sizeOf(v), 0) : typeof value == "string" ? value.length : 1;
-}
-function loadImage(url, w, h) {
-	return new Promise((resolve) => {
-		let img = new Image(w, h);
-		img.onload = () => {
-			resolve(img);
-		}, img.onerror = (event) => {
-			console.error("Image error", event), resolve(null);
-		}, img.src = url;
-	});
-}
-function sortBy(array, f) {
-	return array.sort((a, b) => {
-		let va = f(a), vb = f(b);
-		return va < vb ? -1 : +(va > vb);
-	});
-}
-function truncate(s, limit) {
-	return s.length > limit ? `${s.substring(0, limit)}…` : s;
-}
-const fadeEasing = BezierEasing(0, .9, 1, 1), softEasing = BezierEasing(.25, .1, 0, 1), idleTimeout = 1e4;
-function getTopDocTypes(counts) {
-	return sortBy(Object.keys(counts), (docType) => counts[docType] || 0).reverse().slice(0, 10);
-}
-function formatDocType(docType) {
-	return (docType.substring(0, 1).toUpperCase() + docType.substring(1)).replace(/\./g, " ").replace(/[A-Z]/g, " $&").trim();
-}
-function getDocTypeCounts(docs) {
-	let types = {};
-	for (let doc of docs) types[doc._type] = (types[doc._type] || 0) + 1;
-	return types;
-}
-function labelFor(doc) {
-	return `${doc.title || doc.name || doc._id}`.trim();
-}
-function valueFor(doc, maxSize) {
-	return 5 + 100 * (sizeOf(doc) / maxSize);
-}
-function findRefs(obj, dest = []) {
-	if (obj !== null) {
-		if (typeof obj == "object") for (let [k, v] of Object.entries(obj)) k === "_ref" && typeof v == "string" && v.length > 0 && dest.push(stripDraftId(v)), findRefs(v, dest);
-		else if (Array.isArray(obj)) for (let v of obj) findRefs(v, dest);
-	}
-	return dest;
-}
-function stripDraftId(id) {
-	return id.replace(/^drafts\./, "");
-}
-function deduplicateDrafts(docs) {
-	let deduped = {};
-	for (let doc of docs) doc._id.startsWith("drafts.") || (deduped[doc._id] = doc);
-	for (let doc of docs) if (doc._id.startsWith("drafts.")) {
-		let id = stripDraftId(doc._id);
-		deduped[id] = Object.assign(doc, { _id: id });
-	}
-	return Object.values(deduped);
-}
-var Users = class {
-	_users = [];
-	async getById(id, client) {
-		let user = this._users.find((u) => u._id === id);
-		return user || (user = await client.users.getById(id), this._users.push(user), user.image = await loadImage(user.imageUrl || "https://raw.githubusercontent.com/sanity-io/sanity-plugin-graph-view/main/assets/head-silhouette.jpg", 40, 40)), user;
-	}
-}, Session = class {
-	id = null;
-	user = null;
-	doc = null;
-	lastActive = 0;
-	startTime = 0;
-	angle = 0;
-}, GraphData = class GraphData {
-	sessions = [];
-	data;
-	constructor(docs = []) {
-		let docsById = {};
-		for (let doc of docs) docsById[doc._id] = doc;
-		this.data = {
-			nodes: docs.map((d) => Object.assign({
-				id: d._id,
-				type: "document",
-				doc: d
-			})),
-			links: docs.flatMap((doc) => findRefs(doc).map((ref) => ({
-				source: doc._id,
-				target: ref
-			}))).filter((link) => docsById[link.source] && docsById[link.target])
-		};
-	}
-	setSession(user, docNode) {
-		let session = this.sessions.find((s) => s.user.id === user.id && s.doc?._id === docNode.doc._id);
-		session || (session = new Session(), session.id = v4(), session.user = user, session.startTime = Date.now(), session.doc = docNode.doc, session.angle = Math.random() * 2 * Math.PI, this.sessions.push(session)), session.lastActive = Date.now();
-	}
-	reapSessions() {
-		for (let i = 0; i < this.sessions.length; i++) {
-			let session = this.sessions[i];
-			Date.now() - session.lastActive > idleTimeout && (this.sessions = [...this.sessions.slice(0, i), ...this.sessions.slice(i + 1)], i--);
-		}
-	}
-	clone() {
-		let copy = new GraphData();
-		return Object.assign(copy, this), copy.data = {
-			nodes: [...this.data.nodes],
-			links: [...this.data.links]
-		}, copy;
-	}
-};
-const users = new Users();
-function GraphView({ tool: { options: props } }) {
-	let query = props.query || "\n  *[\n    !(_id in path(\"_.*\")) &&\n    !(_type match \"system.*\") &&\n    !(_type match \"sanity.*\")\n  ]\n", apiVersion = props.apiVersion ?? "2022-09-01", userColorManager = useUserColorManager(), [maxSize, setMaxSize] = useState(0), [hoverNode, setHoverNode] = useState(null), [documents, setDocuments] = useState([]), [docTypes, setDocTypes] = useState({}), [graph, setGraph] = useState(() => new GraphData()), router = useRouter(), client = useClient({ apiVersion });
-	useEffect(() => {
-		client.fetch(query).then((_docs) => {
-			let docs = deduplicateDrafts(_docs);
-			setMaxSize(Math.max(...docs.map(sizeOf))), setDocuments(docs), setDocTypes(getDocTypeCounts(docs)), setGraph(new GraphData(docs));
-		});
-	}, [client, query]), useEffect(() => {
-		let subscription = client.listen(query, {}, {}).subscribe(async (update) => {
-			if (update.type !== "mutation") return;
-			let doc = update.result;
-			if (doc) {
-				doc._id = stripDraftId(doc._id);
-				let docsById = {};
-				for (let d of documents) docsById[d._id] = d;
-				let oldDoc, docs_0 = [...documents], idx = documents.findIndex((d_0) => d_0._id === doc._id);
-				idx >= 0 ? (oldDoc = docs_0[idx], docs_0[idx] = doc) : docs_0.push(doc), setDocuments(docs_0), setDocTypes(getDocTypeCounts(docs_0)), setMaxSize(Math.max(...docs_0.map(sizeOf)));
-				let newGraph = graph.clone(), oldRefs = findRefs(oldDoc || {}).filter((id) => id === doc._id || docsById[id] !== null), newRefs = findRefs(doc).filter((id_0) => id_0 === doc._id || docsById[id_0] !== null), graphChanged = !deepEqual(oldRefs, newRefs);
-				graphChanged && (newGraph.data.links = newGraph.data.links.filter((l) => l.source.id !== doc._id).concat(newRefs.map((ref) => ({
-					source: doc._id,
-					target: ref
-				}))));
-				let docNode, nodeIdx = graph.data.nodes.findIndex((n) => n.doc && n.doc._id === doc._id);
-				nodeIdx >= 0 ? (docNode = graph.data.nodes[nodeIdx], docNode.doc = doc) : (docNode = {
-					id: doc._id,
-					type: "document",
-					doc
-				}, newGraph.data.nodes.push(docNode), graphChanged = !0), graphChanged && setGraph(newGraph);
-				let user = await users.getById(update.identity, client);
-				graph.setSession(user, docNode);
-			} else if (update.transition === "disappear") {
-				let docId = stripDraftId(update.documentId), docs_1 = documents.filter((d_1) => d_1._id !== docId);
-				setDocuments(docs_1), setDocTypes(getDocTypeCounts(docs_1)), setMaxSize(Math.max(...docs_1.map(sizeOf)));
-				let newGraph_0 = graph.clone();
-				newGraph_0.data.links = newGraph_0.data.links.filter((l_0) => l_0.source.id !== docId && l_0.target.id !== docId), newGraph_0.data.nodes = newGraph_0.data.nodes.filter((n_0) => n_0.id !== docId), setGraph(newGraph_0);
-			}
-		});
-		return () => {
-			subscription.unsubscribe();
-		};
-	}, [
-		client,
-		query,
-		documents,
-		graph
-	]), useEffect(() => {
-		let interval = setInterval(() => graph.reapSessions(), 1e3);
-		return () => clearInterval(interval);
-	}, [graph]);
-	let theme = useTheme().sanity;
-	return /* @__PURE__ */ jsx(GraphWrapper, {
-		theme,
-		children: /* @__PURE__ */ jsxs(GraphRoot, {
-			theme,
-			children: [
-				/* @__PURE__ */ jsx(Legend, {
-					theme,
-					children: getTopDocTypes(docTypes).map((docType) => /* @__PURE__ */ jsxs(LegendRow, {
-						className: "legend__row",
-						style: { color: getDocTypeColor(docType).fill },
-						children: [/* @__PURE__ */ jsx(LegendBadge, { theme }), /* @__PURE__ */ jsx("div", { children: formatDocType(docType) })]
-					}, docType))
-				}),
-				hoverNode && /* @__PURE__ */ jsx(HoverNode, {
-					theme,
-					children: labelFor(hoverNode.doc)
-				}),
-				/* @__PURE__ */ jsx(ForceGraph2D, {
-					graphData: graph.data,
-					nodeAutoColorBy: "group",
-					enableNodeDrag: !1,
-					onNodeHover: (node) => setHoverNode(node),
-					onNodeClick: (node_0) => {
-						router.navigateIntent("edit", {
-							id: node_0.doc._id,
-							documentType: node_0.doc._type
-						});
-					},
-					linkColor: () => rgba(gray[500].hex, .25),
-					nodeLabel: () => "",
-					nodeRelSize: 1,
-					nodeVal: (node_1) => valueFor(node_1.doc, maxSize),
-					onRenderFramePost: (ctx, globalScale) => {
-						for (let session of graph.sessions) {
-							let node_2 = graph.data.nodes.find((n_1) => n_1.doc && n_1.doc._id === session?.doc?._id);
-							if (node_2) {
-								let idleFactorRange = idleTimeout, angle = session.angle, radius = Math.sqrt(valueFor(node_2.doc, maxSize)), image = session.user.image, userColor = userColorManager.get(session.user.displayName).tints[400].hex, distance = radius * globalScale + 40, imgW = image ? image.width : 0, imgH = image ? image.height : 0, x = node_2.x + Math.sin(angle) * distance / globalScale, y = node_2.y + Math.cos(angle) * distance / globalScale;
-								ctx.save();
-								try {
-									if (ctx.globalAlpha = fadeEasing(1 - Math.min(idleFactorRange, Date.now() - session.lastActive) / idleFactorRange), ctx.font = `bold ${Math.round(12 / globalScale)}px sans-serif`, ctx.beginPath(), ctx.strokeStyle = rgba(white.hex, 1), ctx.lineWidth = 2 / globalScale, ctx.moveTo(node_2.x + Math.sin(angle) * (distance - imgW / 2) / globalScale, node_2.y + Math.cos(angle) * (distance - imgH / 2) / globalScale), ctx.lineTo(node_2.x + Math.sin(angle) * radius, node_2.y + Math.cos(angle) * radius), ctx.stroke(), ctx.beginPath(), ctx.strokeStyle = rgba(white.hex, 1), ctx.lineWidth = 2 / globalScale, ctx.arc(node_2.x, node_2.y, radius, 0, 2 * Math.PI, !1), ctx.stroke(), image) {
-										ctx.save();
-										try {
-											let f = softEasing(Math.max(0, (700 - (Date.now() - session.startTime)) / 700));
-											f > 0 && (ctx.beginPath(), ctx.fillStyle = rgba(userColor, f), ctx.arc(x, y, (imgW / 2 + 10) / globalScale, 0, 2 * Math.PI, !1), ctx.fill()), ctx.beginPath(), ctx.fillStyle = rgba(white.hex, 1), ctx.arc(x, y, imgW / globalScale / 2, 0, 2 * Math.PI, !1), ctx.clip(), ctx.drawImage(image, x - imgW / globalScale / 2, y - imgH / globalScale / 2, imgW / globalScale, imgH / globalScale), ctx.strokeStyle = black.hex, ctx.lineWidth = 6 / globalScale, ctx.stroke(), ctx.strokeStyle = userColor, ctx.lineWidth = 4 / globalScale, ctx.stroke();
-										} finally {
-											ctx.restore();
-										}
-									}
-									ctx.beginPath(), ctx.strokeStyle = rgba(black.hex, 1), ctx.lineWidth = .5 / globalScale, ctx.arc(x, y, imgW / globalScale / 2, 0, 2 * Math.PI, !1), ctx.stroke();
-									let above = angle >= Math.PI / 2 && angle < Math.PI * 1.5, textY = above ? y - (imgH / 2 + 5) / globalScale : y + (imgH / 2 + 5) / globalScale;
-									ctx.fillStyle = rgba(white.hex, 1), ctx.textAlign = "center", ctx.textBaseline = above ? "bottom" : "top", ctx.fillText(session.user.displayName, x, textY);
-								} finally {
-									ctx.restore();
-								}
-							}
-						}
-					},
-					nodeCanvasObject: (node_3, ctx_0, globalScale_0) => {
-						switch (node_3.type) {
-							case "document": {
-								let nodeColor = getDocTypeColor(node_3.doc._type), radius_0 = Math.sqrt(valueFor(node_3.doc, maxSize)), fontSize = Math.min(100, 10 / globalScale_0);
-								if (ctx_0.beginPath(), ctx_0.fillStyle = hoverNode !== null && node_3.doc._id === hoverNode.doc._id ? rgba(gray[500].hex, .8) : nodeColor.fill, ctx_0.strokeStyle = nodeColor.border, ctx_0.lineWidth = .5, ctx_0.arc(node_3.x, node_3.y, radius_0, 0, 2 * Math.PI, !1), ctx_0.stroke(), ctx_0.fill(), radius_0 * globalScale_0 > 10) {
-									ctx_0.font = `${fontSize}px sans-serif`;
-									let w = radius_0 * 2 + 30 / globalScale_0;
-									for (let len = 50; len >= 5; len /= 1.2) {
-										let label = truncate(labelFor(node_3.doc), Math.round(len));
-										if (ctx_0.measureText(label).width < w) {
-											ctx_0.textAlign = "center", ctx_0.textBaseline = "top", ctx_0.strokeStyle = rgba(black.hex, .5), ctx_0.lineWidth = 2 / globalScale_0, ctx_0.strokeText(label, node_3.x, node_3.y + radius_0 + 5 / globalScale_0), ctx_0.fillText(label, node_3.x, node_3.y + radius_0 + 5 / globalScale_0);
-											break;
-										}
-									}
-								}
-							}
-						}
-					},
-					linkCanvasObject: (link, ctx_1, globalScale_1) => {
-						ctx_1.beginPath(), ctx_1.strokeStyle = rgba(gray[500].hex, .125), ctx_1.lineWidth = 2 / globalScale_1, ctx_1.moveTo(link.source.x, link.source.y), ctx_1.lineTo(link.target.x, link.target.y), ctx_1.stroke();
-					}
-				})
-			]
-		})
-	});
-}
-const colorCache = {};
-let typeColorNum = 0;
-function getDocTypeColor(docType) {
-	if (colorCache[docType]) return colorCache[docType];
-	let hue = COLOR_HUES[typeColorNum % COLOR_HUES.length];
-	return typeColorNum += 1, colorCache[docType] = {
-		fill: hues[hue][400].hex,
-		border: rgba(black.hex, .5)
-	}, colorCache[docType];
-}
-export { GraphView as default };
-
-//# sourceMappingURL=GraphView.js.map
\ No newline at end of file