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
869 lines (868 loc) • 36.8 kB
JavaScript
import { jsxs, jsx } from "react/jsx-runtime";
import { c } from "react-compiler-runtime";
import { useState, useEffect, memo, Fragment } from "react";
import { isRecord, useDocumentStore, useTranslation, usePerspective, useEditState, useSchema, unstable_useValuePreview, _isCustomDocumentTypeDefinition, useWorkspace, SourceProvider } from "sanity";
import { generateHelpUrl, Button, ErrorBoundary } from "./generate-help-url.esm.mjs";
import { useStructureTool, LOADING_PANE, useDocumentLastRev, PaneLayout, LoadingPane, StructureToolPane, setActivePanes } from "./pane.mjs";
import { structureLocaleNamespace, SerializeError, StructureToolProvider } from "./StructureToolProvider.mjs";
import { useRouter, useRouterState } from "sanity/router";
import omit from "lodash/omit.js";
import { from, of, isObservable, firstValueFrom, NEVER, concat, ReplaySubject } from "rxjs";
import { nanoid } from "nanoid";
import { switchMap, publishReplay, refCount, map, startWith, pairwise, scan, distinctUntilChanged } from "rxjs/operators";
import { uuid } from "@sanity/uuid";
import { SyncIcon, WarningOutlineIcon } from "@sanity/icons";
import { Stack, Text, Code, Box, Card, Container, Heading, Flex, useToast, useTheme, PortalProvider } from "@sanity/ui";
import { styled } from "styled-components";
import "../_singletons.mjs";
import { isHotkey } from "is-hotkey-esm";
import isEqual from "lodash/isEqual.js";
class PaneResolutionError extends Error {
constructor({
message,
context,
helpId,
cause
}) {
super(message), this.name = "PaneResolutionError", this.context = context, this.helpId = helpId, this.cause = cause;
}
}
const randomIdCache = /* @__PURE__ */ new WeakMap();
function assignId(obj) {
const cachedValue = randomIdCache.get(obj);
if (cachedValue) return cachedValue;
const id = nanoid();
return randomIdCache.set(obj, id), id;
}
const isPromise = (thing) => !!thing && typeof thing?.then == "function", isSerializable = (thing) => isRecord(thing) ? typeof thing.serialize == "function" : !1, rethrowWithPaneResolutionErrors = (next) => (unresolvedPane, context, flatIndex) => {
try {
return next(unresolvedPane, context, flatIndex);
} catch (e) {
throw e instanceof PaneResolutionError ? e : new PaneResolutionError({
message: typeof e?.message == "string" ? e.message : "",
context,
cause: e
});
}
}, wrapWithPublishReplay = (next) => (...args) => next(...args).pipe(
// need to add publishReplay + refCount to ensure new subscribers always
// get an emission. without this, memoized observables may get stuck
// waiting for their first emissions resulting in a loading pane
publishReplay(1),
refCount()
);
function createPaneResolver(middleware) {
const resolvePane = rethrowWithPaneResolutionErrors(wrapWithPublishReplay(middleware((unresolvedPane, context, flatIndex) => {
if (!unresolvedPane)
throw new PaneResolutionError({
message: "Pane returned no child",
context,
helpId: "structure-item-returned-no-child"
});
return isPromise(unresolvedPane) || isObservable(unresolvedPane) ? from(unresolvedPane).pipe(switchMap((result) => resolvePane(result, context, flatIndex))) : isSerializable(unresolvedPane) ? resolvePane(unresolvedPane.serialize(context), context, flatIndex) : typeof unresolvedPane == "function" ? resolvePane(unresolvedPane(context.id, context), context, flatIndex) : of(unresolvedPane);
})));
return resolvePane;
}
const bindCache = /* @__PURE__ */ new WeakMap();
function memoBind(obj, methodKey) {
const boundMethods = bindCache.get(obj) || /* @__PURE__ */ new Map();
if (boundMethods) {
const bound2 = boundMethods.get(methodKey);
if (bound2) return bound2;
}
const method = obj[methodKey];
if (typeof method != "function")
throw new Error(`Expected property \`${methodKey}\` to be a function but got ${typeof method} instead.`);
const bound = method.bind(obj);
return boundMethods.set(methodKey, bound), bindCache.set(obj, boundMethods), bound;
}
async function resolveIntent(options) {
const resolvedPaneCache = /* @__PURE__ */ new Map(), resolvePane = createPaneResolver((nextFn) => (unresolvedPane, context, flatIndex) => {
const key = unresolvedPane && `${assignId(unresolvedPane)}-${context.path.join("__")}`, cachedResolvedPane = key && resolvedPaneCache.get(key);
if (cachedResolvedPane) return cachedResolvedPane;
const result = nextFn(unresolvedPane, context, flatIndex);
return key && resolvedPaneCache.set(key, result), result;
}), fallbackEditorPanes = [[{
id: `__edit__${options.params.id}`,
params: {
...omit(options.params, ["id"]),
type: options.params.type
},
payload: options.payload
}]];
async function traverse({
currentId,
flatIndex,
intent,
params,
parent: parent2,
path,
payload,
unresolvedPane,
levelIndex,
structureContext
}) {
if (!unresolvedPane) return [];
const {
id: targetId,
type: schemaTypeName,
...otherParams
} = params, resolvedPane = await firstValueFrom(resolvePane(unresolvedPane, {
id: currentId,
splitIndex: 0,
parent: parent2,
path,
index: flatIndex,
params: {},
payload: void 0,
structureContext
}, flatIndex));
return resolvedPane.type === "document" && resolvedPane.id === targetId ? [{
panes: [...path.slice(0, path.length - 1).map((i) => [{
id: i
}]), [{
id: targetId,
params: otherParams,
payload
}]],
depthIndex: path.length,
levelIndex
}] : (
// if the resolve pane's `canHandleIntent` returns true, then resolve
resolvedPane.canHandleIntent?.(intent, params, {
pane: resolvedPane,
index: flatIndex
}) || // if the pane's `canHandleIntent` did not return true, then match against
// this default case. we will resolve the intent if:
resolvedPane.type === "documentList" && // 1. the schema type matches (this required for the document to render)
resolvedPane.schemaTypeName === schemaTypeName && // 2. the filter is the default filter.
//
// NOTE: this case is to prevent false positive matches where the user
// has configured a more specific filter for a particular type. In that
// case, the user can implement their own `canHandleIntent` function
resolvedPane.options.filter === "_type == $type" ? [{
panes: [
// map the current path to router panes
...path.map((id) => [{
id
}]),
// then augment with the intents IDs and params
[{
id: params.id,
params: otherParams,
payload
}]
],
depthIndex: path.length,
levelIndex
}] : resolvedPane.type === "list" && resolvedPane.child && resolvedPane.items ? (await Promise.all(resolvedPane.items.map((item, nextLevelIndex) => item.type === "divider" ? Promise.resolve([]) : traverse({
currentId: item._id || item.id,
flatIndex: flatIndex + 1,
intent,
params,
parent: resolvedPane,
path: [...path, item.id],
payload,
unresolvedPane: typeof resolvedPane.child == "function" ? memoBind(resolvedPane, "child") : resolvedPane.child,
levelIndex: nextLevelIndex,
structureContext
})))).flat() : []
);
}
const closestPaneToRoot = (await traverse({
currentId: "root",
flatIndex: 0,
levelIndex: 0,
intent: options.intent,
params: options.params,
parent: null,
path: [],
payload: options.payload,
unresolvedPane: options.rootPaneNode,
structureContext: options.structureContext
})).sort((a, b) => a.depthIndex === b.depthIndex ? a.levelIndex - b.levelIndex : a.depthIndex - b.depthIndex)[0];
return closestPaneToRoot ? closestPaneToRoot.panes : fallbackEditorPanes;
}
const fallbackEditorChild = (nodeId, context) => {
const id = nodeId.replace(/^__edit__/, ""), {
params,
payload,
structureContext: {
resolveDocumentNode
}
} = context, {
type,
template
} = params;
if (!type)
throw new Error(`Document type for document with ID ${id} was not provided in the router params.`);
let defaultDocumentBuilder = resolveDocumentNode({
schemaType: type,
documentId: id
}).id("editor");
return template && (defaultDocumentBuilder = defaultDocumentBuilder.initialValueTemplate(template, payload)), defaultDocumentBuilder.serialize();
};
function hashContext(context) {
return `contextHash(${JSON.stringify({
id: context.id,
parentId: parent && assignId(parent),
path: context.path,
index: context.index,
splitIndex: context.splitIndex,
serializeOptionsIndex: context.serializeOptions?.index,
serializeOptionsPath: context.serializeOptions?.path
})})`;
}
const hashResolvedPaneMeta = (meta) => {
const normalized = {
type: meta.type,
id: meta.routerPaneSibling.id,
params: meta.routerPaneSibling.params || {},
payload: meta.routerPaneSibling.payload || null,
flatIndex: meta.flatIndex,
groupIndex: meta.groupIndex,
siblingIndex: meta.siblingIndex,
path: meta.path,
paneNode: meta.type === "resolvedMeta" ? assignId(meta.paneNode) : null
};
return `metaHash(${JSON.stringify(normalized)})`;
};
function resolvePaneTree({
unresolvedPane,
flattenedRouterPanes,
parent: parent2,
path,
resolvePane,
structureContext
}) {
const [current, ...rest] = flattenedRouterPanes, next = rest[0], context = {
id: current.routerPaneSibling.id,
splitIndex: current.siblingIndex,
parent: parent2,
path: [...path, current.routerPaneSibling.id],
index: current.flatIndex,
params: current.routerPaneSibling.params || {},
payload: current.routerPaneSibling.payload,
structureContext
};
try {
return resolvePane(unresolvedPane, context, current.flatIndex).pipe(
// this switch map receives a resolved pane
switchMap((paneNode) => {
const resolvedPaneMeta = {
type: "resolvedMeta",
...current,
paneNode,
path: context.path
}, loadingPanes = rest.map((i, restIndex) => ({
type: "loading",
path: [...context.path, ...rest.slice(restIndex).map((_, currentIndex) => `[${i.flatIndex + currentIndex}]`)],
paneNode: null,
...i
}));
if (!rest.length)
return of([resolvedPaneMeta]);
let nextStream;
return (
/* the fallback editor case */
next?.routerPaneSibling.id.startsWith("__edit__") ? nextStream = resolvePaneTree({
unresolvedPane: fallbackEditorChild,
flattenedRouterPanes: rest,
parent: parent2,
path: context.path,
resolvePane,
structureContext
}) : current.groupIndex === next?.groupIndex ? nextStream = resolvePaneTree({
unresolvedPane,
flattenedRouterPanes: rest,
parent: parent2,
path,
resolvePane,
structureContext
}) : nextStream = resolvePaneTree({
unresolvedPane: typeof paneNode.child == "function" ? memoBind(paneNode, "child") : paneNode.child,
flattenedRouterPanes: rest,
parent: paneNode,
path: context.path,
resolvePane,
structureContext
}), concat(
// we emit the loading panes first in a concat (this emits immediately)
of([resolvedPaneMeta, ...loadingPanes]),
// then whenever the next stream is done, the results will be combined.
nextStream.pipe(map((nextResolvedPanes) => [resolvedPaneMeta, ...nextResolvedPanes]))
)
);
})
);
} catch (e) {
if (e instanceof PaneResolutionError && (e.context && console.warn(`Pane resolution error at index ${e.context.index}${e.context.splitIndex > 0 ? ` for split pane index ${e.context.splitIndex}` : ""}: ${e.message}${e.helpId ? ` - see ${generateHelpUrl(e.helpId)}` : ""}`, e), e.helpId === "structure-item-returned-no-child"))
return of([]);
throw e;
}
}
function createResolvedPaneNodeStream({
routerPanesStream,
rootPaneNode,
initialCacheState = {
cacheKeysByFlatIndex: [],
flattenedRouterPanes: [],
resolvedPaneCache: /* @__PURE__ */ new Map(),
resolvePane: () => NEVER
},
structureContext
}) {
return routerPanesStream.pipe(
// add in implicit "root" router pane
map((rawRouterPanes) => [[{
id: "root"
}], ...rawRouterPanes]),
// create flattened router panes
map((routerPanes) => routerPanes.flatMap((routerPaneGroup, groupIndex) => routerPaneGroup.map((routerPaneSibling, siblingIndex) => ({
routerPaneSibling,
groupIndex,
siblingIndex
}))).map((i, index) => ({
...i,
flatIndex: index
}))),
// calculate a "diffIndex" used for clearing the memo cache
startWith([]),
pairwise(),
map(([prev, curr]) => {
for (let i = 0; i < curr.length; i++) {
const prevValue = prev[i], currValue = curr[i];
if (!isEqual(prevValue, currValue))
return {
flattenedRouterPanes: curr,
diffIndex: i
};
}
return {
flattenedRouterPanes: curr,
diffIndex: curr.length
};
}),
// create the memoized `resolvePane` function and manage the memo cache
scan((acc, next) => {
const {
cacheKeysByFlatIndex,
resolvedPaneCache
} = acc, {
flattenedRouterPanes,
diffIndex
} = next, beforeDiffIndex = cacheKeysByFlatIndex.slice(0, diffIndex + 1), afterDiffIndex = cacheKeysByFlatIndex.slice(diffIndex + 1), keysToKeep = new Set(beforeDiffIndex.flatMap((keySet) => Array.from(keySet))), keysToDelete = afterDiffIndex.flatMap((keySet) => Array.from(keySet)).filter((key) => !keysToKeep.has(key));
for (const key of keysToDelete)
resolvedPaneCache.delete(key);
return {
flattenedRouterPanes,
cacheKeysByFlatIndex,
resolvedPaneCache,
resolvePane: createPaneResolver((nextFn) => (unresolvedPane, context, flatIndex) => {
const key = unresolvedPane && `${assignId(unresolvedPane)}-${hashContext(context)}`, cachedResolvedPane = key && resolvedPaneCache.get(key);
if (cachedResolvedPane) return cachedResolvedPane;
const result = nextFn(unresolvedPane, context, flatIndex);
if (!key) return result;
const cacheKeySet = cacheKeysByFlatIndex[flatIndex] || /* @__PURE__ */ new Set();
return cacheKeySet.add(key), cacheKeysByFlatIndex[flatIndex] = cacheKeySet, resolvedPaneCache.set(key, result), result;
})
};
}, initialCacheState),
// run the memoized, recursive resolving
switchMap(({
flattenedRouterPanes,
resolvePane
}) => resolvePaneTree({
unresolvedPane: rootPaneNode,
flattenedRouterPanes,
parent: null,
path: [],
resolvePane,
structureContext
}))
).pipe(
// this diffs the previous emission with the current one. if there is a new
// loading pane at the same position where a previous pane already had a
// resolved value (looking at the IDs to compare), then return the previous
// pane instead of the loading pane
scan((prev, next) => next.map((nextPane, index) => {
const prevPane = prev[index];
return !prevPane || nextPane.type !== "loading" ? nextPane : prevPane.routerPaneSibling.id === nextPane.routerPaneSibling.id ? prevPane : nextPane;
}), []),
// this prevents duplicate emissions
distinctUntilChanged((prev, next) => {
if (prev.length !== next.length) return !1;
for (let i = 0; i < next.length; i++) {
const prevValue = prev[i], nextValue = next[i];
if (hashResolvedPaneMeta(prevValue) !== hashResolvedPaneMeta(nextValue))
return !1;
}
return !0;
})
);
}
function useRouterPanesStream() {
const $ = c(6), [routerStateSubject] = useState(_temp$5);
let t0, t1;
$[0] !== routerStateSubject ? (t1 = routerStateSubject.asObservable().pipe(map(_temp2$3)), $[0] = routerStateSubject, $[1] = t1) : t1 = $[1], t0 = t1;
const routerPanes$ = t0, {
state: routerState
} = useRouter();
let t2, t3;
return $[2] !== routerState || $[3] !== routerStateSubject ? (t2 = () => {
routerStateSubject.next(routerState);
}, t3 = [routerState, routerStateSubject], $[2] = routerState, $[3] = routerStateSubject, $[4] = t2, $[5] = t3) : (t2 = $[4], t3 = $[5]), useEffect(t2, t3), routerPanes$;
}
function _temp2$3(_routerState) {
return _routerState?.panes || [];
}
function _temp$5() {
return new ReplaySubject(1);
}
function useResolvedPanes() {
const $ = c(6), [error, setError] = useState();
if (error)
throw error;
const {
structureContext,
rootPaneNode
} = useStructureTool();
let t0;
$[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = {
paneDataItems: [],
resolvedPanes: [],
routerPanes: []
}, $[0] = t0) : t0 = $[0];
const [data, setData] = useState(t0), routerPanesStream = useRouterPanesStream();
let t1, t2;
return $[1] !== rootPaneNode || $[2] !== routerPanesStream || $[3] !== structureContext ? (t1 = () => {
const subscription = createResolvedPaneNodeStream({
rootPaneNode,
routerPanesStream,
structureContext
}).pipe(map(_temp5)).subscribe({
next: (result) => setData(result),
error: (e) => setError(e)
});
return () => subscription.unsubscribe();
}, t2 = [rootPaneNode, routerPanesStream, structureContext], $[1] = rootPaneNode, $[2] = routerPanesStream, $[3] = structureContext, $[4] = t1, $[5] = t2) : (t1 = $[4], t2 = $[5]), useEffect(t1, t2), data;
}
function _temp5(resolvedPanes) {
const routerPanes = resolvedPanes.reduce(_temp3, []), groupsLen = routerPanes.length, paneDataItems = resolvedPanes.map((pane) => {
const {
groupIndex,
flatIndex,
siblingIndex,
routerPaneSibling,
path
} = pane, itemId = routerPaneSibling.id, nextGroup = routerPanes[groupIndex + 1];
return {
active: groupIndex === groupsLen - 2,
childItemId: nextGroup?.[0].id ?? null,
index: flatIndex,
itemId: routerPaneSibling.id,
groupIndex,
key: `${pane.type === "loading" ? "unknown" : pane.paneNode.id}-${itemId}-${siblingIndex}`,
pane: pane.type === "loading" ? LOADING_PANE : pane.paneNode,
params: routerPaneSibling.params || {},
path: path.join(";"),
payload: routerPaneSibling.payload,
selected: flatIndex === resolvedPanes.length - 1,
siblingIndex
};
});
return {
paneDataItems,
routerPanes,
resolvedPanes: paneDataItems.map(_temp4)
};
}
function _temp4(pane_0) {
return pane_0.pane;
}
function _temp3(acc, next) {
const currentGroup = acc[next.groupIndex] || [];
return currentGroup[next.siblingIndex] = next.routerPaneSibling, acc[next.groupIndex] = currentGroup, acc;
}
async function ensureDocumentIdAndType(documentStore, id, type) {
if (id && type) return {
id,
type
};
if (!id && type) return {
id: uuid(),
type
};
if (id && !type) {
const resolvedType = await firstValueFrom(documentStore.resolveTypeForDocument(id));
return {
id,
type: resolvedType
};
}
throw new PaneResolutionError({
message: "Neither document `id` or `type` was provided when trying to resolve intent."
});
}
const EMPTY_RECORD = {}, IntentResolver = memo(function() {
const $ = c(7), {
navigate
} = useRouter(), maybeIntent = useRouterState(_temp$4), {
rootPaneNode,
structureContext
} = useStructureTool(), documentStore = useDocumentStore(), [error, setError] = useState(null);
if (error)
throw error;
let t0, t1;
return $[0] !== documentStore || $[1] !== maybeIntent || $[2] !== navigate || $[3] !== rootPaneNode || $[4] !== structureContext ? (t0 = () => {
if (maybeIntent) {
const {
intent,
params,
payload
} = maybeIntent;
let cancelled = !1;
return async function() {
const {
id,
type
} = await ensureDocumentIdAndType(documentStore, typeof params.id == "string" ? params.id : void 0, typeof params.type == "string" ? params.type : void 0);
if (cancelled)
return;
const panes = await resolveIntent({
intent,
params: {
...params,
id,
type
},
payload,
rootPaneNode,
structureContext
});
cancelled || navigate({
panes
}, {
replace: !0
});
}().catch(setError), () => {
cancelled = !0;
};
}
}, t1 = [documentStore, maybeIntent, navigate, rootPaneNode, structureContext], $[0] = documentStore, $[1] = maybeIntent, $[2] = navigate, $[3] = rootPaneNode, $[4] = structureContext, $[5] = t0, $[6] = t1) : (t0 = $[5], t1 = $[6]), useEffect(t0, t1), null;
});
function _temp$4(routerState) {
const intentName = typeof routerState.intent == "string" ? routerState.intent : void 0;
return intentName ? {
intent: intentName,
params: isRecord(routerState.params) ? routerState.params : EMPTY_RECORD,
payload: routerState.payload
} : void 0;
}
const PathSegment = styled.span`
&:not(:last-child)::after {
content: ' ➝ ';
opacity: 0.5;
}
`;
function formatStack(stack) {
return stack.replace(/\(\.\.\.\)\./g, `(...)
.`).replace(/__WEBPACK_IMPORTED_MODULE_\d+_+/g, "").replace(/___default\./g, ".").replace(new RegExp(` \\(https?:\\/\\/${window.location.host}`, "g"), " (");
}
function StructureError(t0) {
const $ = c(37), {
error
} = t0;
if (!(error instanceof PaneResolutionError))
throw error;
const {
cause
} = error, {
t
} = useTranslation(structureLocaleNamespace), stack = cause?.stack || error.stack, showStack = stack && !(cause instanceof SerializeError) && !error.message.includes("Module build failed:");
let t1;
$[0] !== cause ? (t1 = cause instanceof SerializeError ? cause.path : [], $[0] = cause, $[1] = t1) : t1 = $[1];
const path = t1, helpId = cause instanceof SerializeError && cause.helpId || error.helpId, handleReload = _temp$3;
let t2;
$[2] !== t ? (t2 = t("structure-error.header.text"), $[2] = t, $[3] = t2) : t2 = $[3];
let t3;
$[4] !== t2 ? (t3 = /* @__PURE__ */ jsx(Heading, { as: "h2", children: t2 }), $[4] = t2, $[5] = t3) : t3 = $[5];
let t4;
$[6] !== path || $[7] !== t ? (t4 = path.length > 0 && /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
/* @__PURE__ */ jsx(Text, { size: 1, weight: "medium", children: t("structure-error.structure-path.label") }),
/* @__PURE__ */ jsx(Code, { children: path.slice(1).map(_temp2$2) })
] }), $[6] = path, $[7] = t, $[8] = t4) : t4 = $[8];
let t5;
$[9] !== t ? (t5 = t("structure-error.error.label"), $[9] = t, $[10] = t5) : t5 = $[10];
let t6;
$[11] !== t5 ? (t6 = /* @__PURE__ */ jsx(Text, { size: 1, weight: "medium", children: t5 }), $[11] = t5, $[12] = t6) : t6 = $[12];
let t7;
$[13] !== error.message || $[14] !== showStack || $[15] !== stack ? (t7 = showStack ? formatStack(stack) : error.message, $[13] = error.message, $[14] = showStack, $[15] = stack, $[16] = t7) : t7 = $[16];
let t8;
$[17] !== t7 ? (t8 = /* @__PURE__ */ jsx(Code, { children: t7 }), $[17] = t7, $[18] = t8) : t8 = $[18];
let t9;
$[19] !== t6 || $[20] !== t8 ? (t9 = /* @__PURE__ */ jsxs(Stack, { marginTop: 4, space: 2, children: [
t6,
t8
] }), $[19] = t6, $[20] = t8, $[21] = t9) : t9 = $[21];
let t10;
$[22] !== helpId || $[23] !== t ? (t10 = helpId && /* @__PURE__ */ jsx(Box, { marginTop: 4, children: /* @__PURE__ */ jsx(Text, { children: /* @__PURE__ */ jsx("a", { href: generateHelpUrl(helpId), rel: "noopener noreferrer", target: "_blank", children: t("structure-error.docs-link.text") }) }) }), $[22] = helpId, $[23] = t, $[24] = t10) : t10 = $[24];
let t11;
$[25] !== t ? (t11 = t("structure-error.reload-button.text"), $[25] = t, $[26] = t11) : t11 = $[26];
let t12;
$[27] !== t11 ? (t12 = /* @__PURE__ */ jsx(Box, { marginTop: 4, children: /* @__PURE__ */ jsx(Button, { text: t11, icon: SyncIcon, tone: "primary", onClick: handleReload }) }), $[27] = t11, $[28] = t12) : t12 = $[28];
let t13;
$[29] !== t10 || $[30] !== t12 || $[31] !== t4 || $[32] !== t9 ? (t13 = /* @__PURE__ */ jsxs(Card, { marginTop: 4, padding: 4, radius: 2, overflow: "auto", shadow: 1, tone: "inherit", children: [
t4,
t9,
t10,
t12
] }), $[29] = t10, $[30] = t12, $[31] = t4, $[32] = t9, $[33] = t13) : t13 = $[33];
let t14;
return $[34] !== t13 || $[35] !== t3 ? (t14 = /* @__PURE__ */ jsx(Card, { height: "fill", overflow: "auto", padding: 4, sizing: "border", tone: "critical", children: /* @__PURE__ */ jsxs(Container, { children: [
t3,
t13
] }) }), $[34] = t13, $[35] = t3, $[36] = t14) : t14 = $[36], t14;
}
function _temp2$2(segment, i) {
return /* @__PURE__ */ jsx(PathSegment, { children: segment }, `${segment}-${i}`);
}
function _temp$3() {
window.location.reload();
}
function NoDocumentTypesScreen() {
const $ = c(17), {
t
} = useTranslation(structureLocaleNamespace);
let t0;
$[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { size: 1, children: /* @__PURE__ */ jsx(WarningOutlineIcon, {}) }) }), $[0] = t0) : t0 = $[0];
let t1;
$[1] !== t ? (t1 = t("no-document-types-screen.title"), $[1] = t, $[2] = t1) : t1 = $[2];
let t2;
$[3] !== t1 ? (t2 = /* @__PURE__ */ jsx(Text, { as: "h1", size: 1, weight: "medium", children: t1 }), $[3] = t1, $[4] = t2) : t2 = $[4];
let t3;
$[5] !== t ? (t3 = t("no-document-types-screen.subtitle"), $[5] = t, $[6] = t3) : t3 = $[6];
let t4;
$[7] !== t3 ? (t4 = /* @__PURE__ */ jsx(Text, { as: "p", muted: !0, size: 1, children: t3 }), $[7] = t3, $[8] = t4) : t4 = $[8];
let t5;
$[9] !== t ? (t5 = t("no-document-types-screen.link-text"), $[9] = t, $[10] = t5) : t5 = $[10];
let t6;
$[11] !== t5 ? (t6 = /* @__PURE__ */ jsx(Text, { as: "p", muted: !0, size: 1, children: /* @__PURE__ */ jsx("a", { href: "https://www.sanity.io/docs/create-a-schema-and-configure-sanity-studio", target: "_blank", rel: "noreferrer", children: t5 }) }), $[11] = t5, $[12] = t6) : t6 = $[12];
let t7;
return $[13] !== t2 || $[14] !== t4 || $[15] !== t6 ? (t7 = /* @__PURE__ */ jsx(Card, { height: "fill", children: /* @__PURE__ */ jsx(Flex, { align: "center", height: "fill", justify: "center", padding: 4, sizing: "border", children: /* @__PURE__ */ jsx(Container, { width: 0, children: /* @__PURE__ */ jsx(Card, { padding: 4, radius: 2, shadow: 1, tone: "caution", children: /* @__PURE__ */ jsxs(Flex, { children: [
t0,
/* @__PURE__ */ jsxs(Stack, { flex: 1, marginLeft: 3, space: 3, children: [
t2,
t4,
t6
] })
] }) }) }) }) }), $[13] = t2, $[14] = t4, $[15] = t6, $[16] = t7) : t7 = $[16], t7;
}
const DocumentTitle = (props) => {
const $ = c(7), {
documentId,
documentType
} = props, {
selectedReleaseId
} = usePerspective(), editState = useEditState(documentId, documentType, "default", selectedReleaseId), schema = useSchema(), {
t
} = useTranslation(structureLocaleNamespace), isNewDocument = !editState?.published && !editState?.draft, documentValue = editState?.version || editState?.draft || editState?.published, schemaType = schema.get(documentType), {
value,
isLoading: previewValueIsLoading
} = unstable_useValuePreview({
enabled: !!documentValue,
schemaType,
value: documentValue
}), {
lastRevisionDocument
} = useDocumentLastRev(documentId, documentType), documentTitle = lastRevisionDocument && !documentValue ? "" : isNewDocument ? t("browser-document-title.new-document", {
schemaType: schemaType?.title || schemaType?.name
}) : value?.title || t("browser-document-title.untitled-document"), settled = editState.ready && !previewValueIsLoading, newTitle = useConstructDocumentTitle(documentTitle);
let t0;
$[0] !== newTitle || $[1] !== settled ? (t0 = () => {
settled && (document.title = newTitle);
}, $[0] = newTitle, $[1] = settled, $[2] = t0) : t0 = $[2];
let t1;
return $[3] !== documentTitle || $[4] !== newTitle || $[5] !== settled ? (t1 = [documentTitle, settled, newTitle], $[3] = documentTitle, $[4] = newTitle, $[5] = settled, $[6] = t1) : t1 = $[6], useEffect(t0, t1), null;
}, PassthroughTitle = (props) => {
const $ = c(5), {
title
} = props, newTitle = useConstructDocumentTitle(title);
let t0;
$[0] !== newTitle ? (t0 = () => {
document.title = newTitle;
}, $[0] = newTitle, $[1] = t0) : t0 = $[1];
let t1;
return $[2] !== newTitle || $[3] !== title ? (t1 = [newTitle, title], $[2] = newTitle, $[3] = title, $[4] = t1) : t1 = $[4], useEffect(t0, t1), null;
}, StructureTitle = (props) => {
const $ = c(8), {
resolvedPanes
} = props;
if (!resolvedPanes?.length)
return null;
const lastPane = resolvedPanes[resolvedPanes.length - 1];
if (isLoadingPane(lastPane)) {
let t02;
return $[0] === Symbol.for("react.memo_cache_sentinel") ? (t02 = /* @__PURE__ */ jsx(PassthroughTitle, {}), $[0] = t02) : t02 = $[0], t02;
}
if (isDocumentPane(lastPane)) {
if (lastPane?.title) {
let t03;
return $[1] !== lastPane.title ? (t03 = /* @__PURE__ */ jsx(PassthroughTitle, { title: lastPane.title }), $[1] = lastPane.title, $[2] = t03) : t03 = $[2], t03;
}
let t02;
return $[3] !== lastPane.options.id || $[4] !== lastPane.options.type ? (t02 = /* @__PURE__ */ jsx(DocumentTitle, { documentId: lastPane.options.id, documentType: lastPane.options.type }), $[3] = lastPane.options.id, $[4] = lastPane.options.type, $[5] = t02) : t02 = $[5], t02;
}
const t0 = lastPane?.title;
let t1;
return $[6] !== t0 ? (t1 = /* @__PURE__ */ jsx(PassthroughTitle, { title: t0 }), $[6] = t0, $[7] = t1) : t1 = $[7], t1;
};
function useConstructDocumentTitle(activeTitle) {
const $ = c(3), structureToolBaseTitle = useStructureTool().structureContext.title;
let t0;
return $[0] !== activeTitle || $[1] !== structureToolBaseTitle ? (t0 = [activeTitle, structureToolBaseTitle].filter(_temp$2), $[0] = activeTitle, $[1] = structureToolBaseTitle, $[2] = t0) : t0 = $[2], t0.join(" | ");
}
function _temp$2(title) {
return title;
}
function isDocumentPane(pane) {
return pane !== LOADING_PANE && pane.type === "document";
}
function isLoadingPane(pane) {
return pane === LOADING_PANE;
}
const StyledPaneLayout = styled(PaneLayout)`
min-height: 100%;
min-width: 320px;
`, isSaveHotkey = isHotkey("mod+s"), StructureTool = memo(function(t0) {
const $ = c(31), {
onPaneChange
} = t0, {
push: pushToast
} = useToast(), schema = useSchema(), {
layoutCollapsed,
setLayoutCollapsed
} = useStructureTool(), {
paneDataItems,
resolvedPanes
} = useResolvedPanes(), isResolvingIntent = useRouterState(_temp$1), {
sanity: t1
} = useTheme(), {
media
} = t1, [portalElement, setPortalElement] = useState(null);
let t2;
$[0] !== setLayoutCollapsed ? (t2 = () => setLayoutCollapsed(!0), $[0] = setLayoutCollapsed, $[1] = t2) : t2 = $[1];
const handleRootCollapse = t2;
let t3;
$[2] !== setLayoutCollapsed ? (t3 = () => setLayoutCollapsed(!1), $[2] = setLayoutCollapsed, $[3] = t3) : t3 = $[3];
const handleRootExpand = t3;
let t4, t5;
$[4] !== onPaneChange || $[5] !== resolvedPanes ? (t4 = () => {
resolvedPanes.length && onPaneChange(resolvedPanes);
}, t5 = [onPaneChange, resolvedPanes], $[4] = onPaneChange, $[5] = resolvedPanes, $[6] = t4, $[7] = t5) : (t4 = $[6], t5 = $[7]), useEffect(t4, t5);
let t6, t7;
if ($[8] !== pushToast ? (t6 = () => {
const handleGlobalKeyDown = (event) => {
isSaveHotkey(event) && (event.preventDefault(), pushToast({
closable: !0,
id: "auto-save-message",
status: "info",
title: "Your work is automatically saved!",
duration: 4e3
}));
};
return window.addEventListener("keydown", handleGlobalKeyDown), () => window.removeEventListener("keydown", handleGlobalKeyDown);
}, t7 = [pushToast], $[8] = pushToast, $[9] = t6, $[10] = t7) : (t6 = $[9], t7 = $[10]), useEffect(t6, t7), !schema._original?.types.some(_isCustomDocumentTypeDefinition)) {
let t82;
return $[11] === Symbol.for("react.memo_cache_sentinel") ? (t82 = /* @__PURE__ */ jsx(NoDocumentTypesScreen, {}), $[11] = t82) : t82 = $[11], t82;
}
const t8 = portalElement || null, t9 = layoutCollapsed ? void 0 : "fill", t10 = media[1];
let t11;
$[12] !== paneDataItems ? (t11 = paneDataItems.map(_temp2$1), $[12] = paneDataItems, $[13] = t11) : t11 = $[13];
let t12;
$[14] !== isResolvingIntent || $[15] !== paneDataItems.length ? (t12 = paneDataItems.length <= 1 && isResolvingIntent && /* @__PURE__ */ jsx(LoadingPane, { paneKey: "intent-resolver" }), $[14] = isResolvingIntent, $[15] = paneDataItems.length, $[16] = t12) : t12 = $[16];
let t13;
$[17] !== handleRootCollapse || $[18] !== handleRootExpand || $[19] !== media[1] || $[20] !== t11 || $[21] !== t12 || $[22] !== t9 ? (t13 = /* @__PURE__ */ jsxs(StyledPaneLayout, { flex: 1, height: t9, minWidth: t10, onCollapse: handleRootCollapse, onExpand: handleRootExpand, children: [
t11,
t12
] }), $[17] = handleRootCollapse, $[18] = handleRootExpand, $[19] = media[1], $[20] = t11, $[21] = t12, $[22] = t9, $[23] = t13) : t13 = $[23];
let t14;
$[24] !== resolvedPanes ? (t14 = /* @__PURE__ */ jsx(StructureTitle, { resolvedPanes }), $[24] = resolvedPanes, $[25] = t14) : t14 = $[25];
let t15;
$[26] === Symbol.for("react.memo_cache_sentinel") ? (t15 = /* @__PURE__ */ jsx("div", { "data-portal": "", ref: setPortalElement }), $[26] = t15) : t15 = $[26];
let t16;
return $[27] !== t13 || $[28] !== t14 || $[29] !== t8 ? (t16 = /* @__PURE__ */ jsxs(PortalProvider, { element: t8, children: [
t13,
t14,
t15
] }), $[27] = t13, $[28] = t14, $[29] = t8, $[30] = t16) : t16 = $[30], t16;
});
function _temp$1(routerState) {
return typeof routerState.intent == "string";
}
function _temp2$1(t0) {
const {
active,
childItemId,
groupIndex,
itemId,
key: paneKey,
pane,
index: paneIndex,
params: paneParams,
path,
payload,
siblingIndex,
selected
} = t0;
return /* @__PURE__ */ jsx(Fragment, { children: pane === LOADING_PANE ? /* @__PURE__ */ jsx(LoadingPane, { paneKey, path, selected }) : /* @__PURE__ */ jsx(StructureToolPane, { active, groupIndex, index: paneIndex, pane, childItemId, itemId, paneKey, params: paneParams, payload, path, selected, siblingIndex }) }, `${pane === LOADING_PANE ? "loading" : pane.type}-${paneIndex}`);
}
function StructureToolBoundary(t0) {
const $ = c(14), {
tool: t1
} = t0, {
options
} = t1, {
unstable_sources: sources
} = useWorkspace(), [firstSource] = sources;
let t2;
$[0] !== options ? (t2 = options || {}, $[0] = options, $[1] = t2) : t2 = $[1];
const {
source,
defaultDocumentNode,
structure
} = t2;
let t3;
$[2] === Symbol.for("react.memo_cache_sentinel") ? (t3 = [], $[2] = t3) : t3 = $[2], useEffect(_temp2, t3);
let t4;
$[3] === Symbol.for("react.memo_cache_sentinel") ? (t4 = {
error: null
}, $[3] = t4) : t4 = $[3];
const [t5, setError] = useState(t4), {
error
} = t5;
if (error) {
let t62;
return $[4] !== error ? (t62 = /* @__PURE__ */ jsx(StructureError, { error }), $[4] = error, $[5] = t62) : t62 = $[5], t62;
}
const t6 = source || firstSource.name;
let t7, t8;
$[6] === Symbol.for("react.memo_cache_sentinel") ? (t7 = /* @__PURE__ */ jsx(StructureTool, { onPaneChange: setActivePanes }), t8 = /* @__PURE__ */ jsx(IntentResolver, {}), $[6] = t7, $[7] = t8) : (t7 = $[6], t8 = $[7]);
let t9;
$[8] !== defaultDocumentNode || $[9] !== structure ? (t9 = /* @__PURE__ */ jsxs(StructureToolProvider, { defaultDocumentNode, structure, children: [
t7,
t8
] }), $[8] = defaultDocumentNode, $[9] = structure, $[10] = t9) : t9 = $[10];
let t10;
return $[11] !== t6 || $[12] !== t9 ? (t10 = /* @__PURE__ */ jsx(ErrorBoundary, { onCatch: setError, children: /* @__PURE__ */ jsx(SourceProvider, { name: t6, children: t9 }) }), $[11] = t6, $[12] = t9, $[13] = t10) : t10 = $[13], t10;
}
function _temp2() {
return setActivePanes([]), _temp;
}
function _temp() {
return setActivePanes([]);
}
export {
StructureToolBoundary as default
};
//# sourceMappingURL=index3.mjs.map