@tinacms/vercel-previews
Version:
⚠️ You must be a Vercel Enterprise customer for Visual Editing ⚠️
138 lines (137 loc) • 4.1 kB
JavaScript
import { vercelStegaCombine } from "@vercel/stega";
import React, { useCallback, useEffect } from "react";
function useEditState() {
const [edit, setEdit] = React.useState(false);
React.useEffect(() => {
if (typeof window !== "undefined") {
parent.postMessage({ type: "isEditMode" }, window.location.origin);
window.addEventListener("message", (event) => {
var _a;
if (((_a = event.data) == null ? void 0 : _a.type) === "tina:editMode") {
setEdit(true);
}
});
}
}, []);
return { edit };
}
const tinaField = (object, property, index) => {
const contentSource = object == null ? void 0 : object._content_source;
if (!contentSource) {
return "";
}
const { queryId, path } = contentSource;
if (!property) {
return `${queryId}---${path.join(".")}`;
}
const fullPath = typeof index === "number" ? [...path, property, index] : [...path, property];
return `${queryId}---${fullPath.join(".")}`;
};
const vercelEditInfo = (obj, field, index) => {
const fieldName = tinaField(obj, field, index);
return JSON.stringify({ origin: "tinacms", data: { fieldName } });
};
const useVisualEditing = ({
data,
query,
variables,
enabled,
redirect,
stringEncoding
}) => {
const stringifiedQuery = JSON.stringify({
query,
variables
});
const id = React.useMemo(
() => hashFromQuery(stringifiedQuery),
[stringifiedQuery]
);
const { edit } = useEditState();
const handleOpenEvent = useCallback(
(event) => {
var _a, _b;
if (edit) {
parent.postMessage(
{ type: "field:selected", fieldName: (_b = (_a = event.detail) == null ? void 0 : _a.data) == null ? void 0 : _b.fieldName },
window.location.origin
);
} else {
const tinaAdminBasePath = redirect.startsWith("/") ? redirect : `/${redirect}`;
const tinaAdminPath = `${tinaAdminBasePath}/index.html#/~${window.location.pathname}?active-field=${event.detail.data.fieldName}`;
window.location.assign(tinaAdminPath);
}
},
[edit]
);
useEffect(() => {
window.addEventListener("edit:open", handleOpenEvent);
return () => {
window.removeEventListener("edit:open", handleOpenEvent);
};
}, [redirect, edit]);
function appendMetadata(obj, path = [], id2) {
if (typeof obj !== "object" || obj === null) {
if (typeof obj === "string" && stringEncoding) {
if (typeof stringEncoding === "boolean") {
if (stringEncoding) {
return encodeEditInfo(path, obj, id2);
}
} else if (stringEncoding.skipPaths) {
if (!stringEncoding.skipPaths(path.join("."), obj)) {
return encodeEditInfo(path, obj, id2);
}
}
}
return obj;
}
if (Array.isArray(obj)) {
return obj.map(
(item, index) => appendMetadata(item, [...path, index], id2)
);
}
const transformedObj = {};
for (const [key, value] of Object.entries(obj)) {
const currentPath = [...path, key];
if ([
"__typename",
"_sys",
"_internalSys",
"_values",
"_internalValues",
"_content_source",
"_tina_metadata"
].includes(key)) {
transformedObj[key] = value;
} else {
transformedObj[key] = appendMetadata(value, currentPath, id2);
}
}
return { ...transformedObj, _content_source: { queryId: id2, path } };
}
if (enabled) {
return appendMetadata(data, [], id);
}
return data;
};
function encodeEditInfo(path, value, id) {
return vercelStegaCombine(value, {
origin: "tina.io",
data: { fieldName: `${id}---${path.join(".")}` }
});
}
const hashFromQuery = (input) => {
let hash = 0;
for (let i = 0; i < input.length; i++) {
const char = input.charCodeAt(i);
hash = (hash << 5) - hash + char & 4294967295;
}
const nonNegativeHash = Math.abs(hash);
const alphanumericHash = nonNegativeHash.toString(36);
return alphanumericHash;
};
export {
hashFromQuery,
useVisualEditing,
vercelEditInfo
};