sanity
Version:
Sanity is a real-time content infrastructure with a scalable, hosted backend featuring a Graph Oriented Query Language (GROQ), asset pipelines and fast edge caches
512 lines (511 loc) • 15.6 kB
JavaScript
import { c } from "react-compiler-runtime";
import { ThemeProvider, useRootTheme } from "@sanity/ui";
import { isValidElement, memo, useEffect } from "react";
import { useWorkspace, RELEASES_STUDIO_CLIENT_OPTIONS, isReleasePerspective, useClient, getPublishedId } from "sanity";
import { API_VERSION } from "./presentation.mjs";
import { jsx } from "react/jsx-runtime";
import { renderToString } from "react-dom/server";
import { ServerStyleSheet, StyleSheetManager } from "styled-components";
function isFieldRequired(field) {
const {
validation
} = field.type;
if (!validation)
return !1;
const rules = Array.isArray(validation) ? validation : [validation];
for (const rule of rules) {
let required = !1;
const proxy = new Proxy({}, {
get: (target, methodName) => () => (methodName === "required" && (required = !0), proxy)
});
if (typeof rule == "function" && (rule(proxy), required) || typeof rule == "object" && rule !== null && "_required" in rule && rule._required === "required")
return !0;
}
return !1;
}
function isType(typeDef, typeName) {
let type = typeDef;
for (; type; ) {
if (type.name === typeName || type.type && type.type.name === typeName)
return !0;
type = type.type;
}
return !1;
}
function isObjectType(typeDef) {
return isType(typeDef, "object") || typeDef.jsonType === "object" || "fields" in typeDef;
}
function isArrayType(typeDef) {
return isType(typeDef, "array");
}
function isReferenceType(typeDef) {
return isType(typeDef, "reference");
}
function isCrossDatasetReferenceType(typeDef) {
return isType(typeDef, "crossDatasetReference");
}
function isStringType(typeDef) {
return isType(typeDef, "string");
}
function isNumberType(typeDef) {
return isType(typeDef, "number");
}
function lastType(typeDef) {
let type = typeDef;
for (; type; ) {
if (!type.type)
return type;
type = type.type;
}
}
function gatherFields(type) {
return "fields" in type ? type.type ? gatherFields(type.type).concat(type.fields) : type.fields : [];
}
function sortByDependencies(compiledSchema) {
const seen = /* @__PURE__ */ new Set();
function walkDependencies(schemaType, dependencies) {
if (!seen.has(schemaType)) {
if (seen.add(schemaType), "fields" in schemaType)
for (const field of gatherFields(schemaType)) {
const last = lastType(field.type);
if (last.name === "document") {
dependencies.add(last);
continue;
}
let schemaTypeName;
schemaType.type.type ? schemaTypeName = field.type.type.name : "jsonType" in schemaType.type && (schemaTypeName = field.type.jsonType), (schemaTypeName === "object" || schemaTypeName === "block") && (isReferenceType(field.type) ? field.type.to.forEach((ref) => dependencies.add(ref.type)) : dependencies.add(field.type)), walkDependencies(field.type, dependencies);
}
else if ("of" in schemaType)
for (const item of schemaType.of)
walkDependencies(item, dependencies);
}
}
const dependencyMap = /* @__PURE__ */ new Map();
compiledSchema.getTypeNames().forEach((typeName) => {
const schemaType = compiledSchema.get(typeName);
if (schemaType === void 0 || schemaType.type === null)
return;
const dependencies = /* @__PURE__ */ new Set();
walkDependencies(schemaType, dependencies), dependencyMap.set(schemaType, dependencies), seen.clear();
});
const typeNames = [], currentlyVisiting = /* @__PURE__ */ new Set(), visited = /* @__PURE__ */ new Set();
function visit(type) {
if (visited.has(type) || currentlyVisiting.has(type))
return;
currentlyVisiting.add(type);
const deps = dependencyMap.get(type);
deps !== void 0 && deps.forEach((dep) => visit(dep)), currentlyVisiting.delete(type), visited.add(type), typeNames.includes(type.name) || typeNames.unshift(type.name);
}
for (const [type] of dependencyMap)
visit(type);
return typeNames;
}
const SchemaIcon = function(t0) {
const $ = c(6), {
schemaType,
theme: themeContext
} = t0, {
theme,
scheme,
tone
} = themeContext;
let t1;
$[0] === Symbol.for("react.memo_cache_sentinel") ? (t1 = new ServerStyleSheet(), $[0] = t1) : t1 = $[0];
const sheet = t1, Icon = schemaType.icon;
let t2;
return $[1] !== Icon || $[2] !== scheme || $[3] !== theme || $[4] !== tone ? (t2 = Icon ? /* @__PURE__ */ jsx(StyleSheetManager, { sheet: sheet.instance, children: /* @__PURE__ */ jsx(ThemeProvider, { theme, scheme, tone, children: isValidElement(Icon) ? Icon : /* @__PURE__ */ jsx(Icon, {}) }) }) : null, $[1] = Icon, $[2] = scheme, $[3] = theme, $[4] = tone, $[5] = t2) : t2 = $[5], t2;
}, documentDefaultFields = (typeName) => ({
_id: {
type: "objectField",
name: "_id",
value: {
type: "string"
}
},
_type: {
type: "objectField",
name: "_type",
value: {
type: "string",
value: typeName
}
},
_createdAt: {
type: "objectField",
name: "_createdAt",
value: {
type: "string"
}
},
_updatedAt: {
type: "objectField",
name: "_updatedAt",
value: {
type: "string"
}
},
_rev: {
type: "objectField",
name: "_rev",
value: {
type: "string"
}
}
});
function createStringNodeDefintion(stringSchemaType) {
const listOptions = stringSchemaType.options?.list;
return listOptions && Array.isArray(listOptions) ? {
type: "union",
of: listOptions.map((v) => ({
type: "string",
value: typeof v == "string" ? v : v.value
}))
} : {
type: "string"
};
}
function createNumberNodeDefintion(numberSchemaType) {
const listOptions = numberSchemaType.options?.list;
return listOptions && Array.isArray(listOptions) ? {
type: "union",
of: listOptions.map((v) => ({
type: "number",
value: typeof v == "number" ? v : v.value
}))
} : {
type: "number"
};
}
function createReferenceNode(name, inArray = !1) {
const fields = {
_ref: {
type: "objectField",
name: "_ref",
value: {
type: "string"
}
},
_type: {
type: "objectField",
name: "_type",
value: {
type: "string",
value: "reference"
}
},
_weak: {
type: "objectField",
name: "_weak",
value: {
type: "boolean"
},
optional: !0
}
};
return inArray && (fields._key = {
type: "objectField",
name: "_key",
value: {
type: "string"
}
}), {
type: "object",
fields,
dereferencesTo: name
};
}
function createReferenceNodeDefintion(reference) {
const references = gatherReferenceNames(reference);
return references.length === 1 ? createReferenceNode(references[0]) : {
type: "union",
of: references.map((name) => ({
type: "unionOption",
name,
value: createReferenceNode(name)
}))
};
}
function gatherReferenceNames(type) {
const allReferences = gatherReferenceTypes(type);
return [...new Set(allReferences.map((ref) => ref.name))];
}
function gatherReferenceTypes(type) {
const refTo = "to" in type ? type.to : [];
return "type" in type && isReferenceType(type.type) ? [...gatherReferenceTypes(type.type), ...refTo] : refTo;
}
const typesMap = /* @__PURE__ */ new Map([["text", {
type: "string"
}], ["url", {
type: "string"
}], ["datetime", {
type: "string"
}], ["date", {
type: "string"
}], ["boolean", {
type: "boolean"
}], ["email", {
type: "string"
}]]);
function extractSchema(workspace, theme) {
const inlineFields = /* @__PURE__ */ new Set(), {
schema: schemaDef,
basePath
} = workspace;
return sortByDependencies(schemaDef).map((typeName) => {
const schemaType = schemaDef.get(typeName);
if (schemaType === void 0)
return;
const base = convertBaseType(schemaType);
if (base !== null)
return base.type === "type" && inlineFields.add(schemaType), base;
}).filter((type) => type !== void 0);
function extractIcon(schemaType) {
if (schemaType.icon)
return renderToString(/* @__PURE__ */ jsx(SchemaIcon, { schemaType, theme }));
}
function convertBaseType(schemaType) {
let typeName;
if (schemaType.type ? typeName = schemaType.type.name : "jsonType" in schemaType && (typeName = schemaType.jsonType), typeName === "document") {
const object = createObject(schemaType);
return object.type === "unknown" ? null : {
type: "document",
name: schemaType.name,
title: typeof schemaType.title == "string" ? schemaType.title : void 0,
icon: extractIcon(schemaType),
fields: {
...documentDefaultFields(schemaType.name),
...object.fields
}
};
}
const value = convertSchemaType(schemaType);
return value.type === "unknown" ? null : value.type === "object" ? {
name: schemaType.name,
type: "type",
value: {
type: "object",
fields: {
_type: {
type: "objectField",
name: "_type",
value: {
type: "string",
value: schemaType.name
}
},
...value.fields
}
}
} : {
name: schemaType.name,
title: typeof schemaType.title == "string" ? schemaType.title : void 0,
type: "type",
value
};
}
function createObject(schemaType) {
const fields = {};
for (const field of gatherFields(schemaType)) {
const value = convertSchemaType(field.type);
value !== null && (fields[field.name] = {
type: "objectField",
name: field.name,
title: typeof field.type.title == "string" ? field.type.title : void 0,
value,
optional: isFieldRequired(field) === !1
});
}
return {
type: "object",
fields
};
}
function convertSchemaType(schemaType) {
if (lastType(schemaType)?.name === "document")
return createReferenceNode(schemaType.name);
if (inlineFields.has(schemaType.type))
return {
type: "inline",
name: schemaType.type.name
};
if (schemaType.type?.type?.name === "object")
return {
type: "inline",
name: schemaType.type.name
};
if (isStringType(schemaType))
return createStringNodeDefintion(schemaType);
if (isNumberType(schemaType))
return createNumberNodeDefintion(schemaType);
const mapped = typesMap.get(schemaType.type?.name || "");
if (mapped)
return mapped;
if (schemaType.type && typesMap.has(schemaType.type.name))
return typesMap.get(schemaType.type.name);
if (isCrossDatasetReferenceType(schemaType))
return {
type: "unknown"
};
if (isReferenceType(schemaType))
return createReferenceNodeDefintion(schemaType);
if (isArrayType(schemaType))
return createArray(schemaType);
if (isObjectType(schemaType))
return createObject(schemaType);
throw new Error(`Type "${schemaType.name}" not found`);
}
function createUnionNodeOptions(schemaType, of) {
const {
options
} = schemaType;
if (!options) return;
const opts = {
...options
};
return options.insertMenu && (opts.insertMenu = {
...options.insertMenu,
views: options.insertMenu.views?.map((view) => view.name === "grid" ? {
name: "grid",
previewImageUrls: view.previewImageUrl ? of.reduce((acc, {
name
}) => {
const url = view.previewImageUrl?.(name);
if (!url) return acc;
try {
new URL(url), acc[name] = url;
} catch {
acc[name] = new URL(url, `${window.location.origin}${basePath ? `${basePath}/` : ""}`).toString();
}
return acc;
}, {}) : void 0
} : view)
}), opts;
}
function createArray(arraySchemaType) {
const of = [];
for (const item of arraySchemaType.of) {
let field = convertSchemaType(item);
const option = {
type: "unionOption",
icon: extractIcon(item),
name: item.name,
title: typeof item.title == "string" ? item.title : void 0,
value: field
};
field.type === "inline" ? field = {
type: "object",
fields: {
_key: createKeyField()
},
rest: field
} : field.type === "object" && (field.rest = {
type: "object",
fields: {
_key: createKeyField()
}
}), option.value = field, of.push(option);
}
if (of.length === 0)
return {
type: "null"
};
if (of.length > 1)
return {
type: "union",
of,
options: createUnionNodeOptions(arraySchemaType, of)
};
const {
name,
title,
value
} = of[0];
return {
type: "array",
of: {
type: "arrayItem",
name,
title: typeof title == "string" ? title : void 0,
value
}
};
}
}
function createKeyField() {
return {
type: "objectField",
name: "_key",
value: {
type: "string"
}
};
}
function getDocumentPathArray(paths) {
const documentPathMap = paths.reduce((acc, {
id,
path
}) => (acc[id] ? acc[id].add(path) : acc[id] = /* @__PURE__ */ new Set([path]), acc), {});
return Object.entries(documentPathMap);
}
function PostMessageSchema(props) {
const $ = c(12), {
comlink,
perspective
} = props, workspace = useWorkspace(), theme = useRootTheme();
let t0, t1;
$[0] !== comlink || $[1] !== theme || $[2] !== workspace ? (t0 = () => {
try {
const schema = extractSchema(workspace, theme);
return comlink.post("presentation/schema", {
schema
}), comlink.on("visual-editing/schema", () => ({
schema
}));
} catch {
return;
}
}, t1 = [comlink, theme, workspace], $[0] = comlink, $[1] = theme, $[2] = workspace, $[3] = t0, $[4] = t1) : (t0 = $[3], t1 = $[4]), useEffect(t0, t1);
let t2;
$[5] !== perspective ? (t2 = isReleasePerspective(perspective) ? RELEASES_STUDIO_CLIENT_OPTIONS : {
apiVersion: API_VERSION
}, $[5] = perspective, $[6] = t2) : t2 = $[6];
const client = useClient(t2);
let t3, t4;
return $[7] !== client || $[8] !== comlink || $[9] !== perspective ? (t3 = () => comlink.on("visual-editing/schema-union-types", async (data) => {
const documentPathArray = getDocumentPathArray(data.paths), unionTypes = await Promise.all(documentPathArray.map(async (t5) => {
const [id, paths] = t5, arr = Array.from(paths), query = `*[_id == $id][0]{${arr.map(_temp).join(",")}}`, result = await client.fetch(query, {
id: getPublishedId(id)
}, {
tag: "presentation-schema",
perspective
}), mapped = arr.map((path_0, i_0) => ({
path: path_0,
type: result[i_0]
}));
return {
id,
paths: mapped
};
})), newState = /* @__PURE__ */ new Map();
return unionTypes.forEach((action) => {
newState.set(action.id, new Map(action.paths.map(_temp2)));
}), {
types: newState
};
}), t4 = [comlink, client, perspective], $[7] = client, $[8] = comlink, $[9] = perspective, $[10] = t3, $[11] = t4) : (t3 = $[10], t4 = $[11]), useEffect(t3, t4), null;
}
function _temp2(t0) {
const {
path: path_1,
type
} = t0;
return [path_1, type];
}
function _temp(path, i) {
return `"${i}": ${path}[0]._type`;
}
var PostMessageSchema$1 = memo(PostMessageSchema);
export {
PostMessageSchema$1 as default
};
//# sourceMappingURL=PostMessageSchema.mjs.map