UNPKG

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

985 lines (984 loc) 43.8 kB
import { jsxs, jsx } from "react/jsx-runtime"; import { c } from "react/compiler-runtime"; import { useState, useEffect, memo, useRef, Fragment } from "react"; import { isRecord, useDocumentStore, useTranslation, usePerspective, useEditState, useSchema, unstable_useValuePreview, _isCustomDocumentTypeDefinition, useWorkspace, SourceProvider } from "sanity"; import { Button, ErrorBoundary } from "./TooltipDelayGroupProvider.js"; import { useStructureTool, LOADING_PANE, useDocumentLastRev, PaneLayout, LoadingPane, StructureToolPane, setActivePanes } from "./pane.js"; import { structureLocaleNamespace, SerializeError, StructureToolProvider } from "./StructureToolProvider.js"; import { useRouter, useRouterState } from "sanity/router"; import { ResolvedPanesProvider } from "../_singletons.js"; import { omit, isEqual } from "lodash-es"; 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 { generateHelpUrl } from "./generate-help-url.esm.js"; 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 { isHotkey } from "is-hotkey-esm"; 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; $[0] !== routerStateSubject ? (t0 = routerStateSubject.asObservable().pipe(map(_temp2$3)), $[0] = routerStateSubject, $[1] = t0) : t0 = $[1]; const routerPanes$ = t0, { state: routerState } = useRouter(); let t1, t2; return $[2] !== routerState || $[3] !== routerStateSubject ? (t1 = () => { routerStateSubject.next(routerState); }, t2 = [routerState, routerStateSubject], $[2] = routerState, $[3] = routerStateSubject, $[4] = t1, $[5] = t2) : (t1 = $[4], t2 = $[5]), useEffect(t1, t2), routerPanes$; } function _temp2$3(_routerState) { return _routerState?.panes || []; } function _temp$5() { return new ReplaySubject(1); } function useResolvedPanes() { const $ = c(15), [error, setError] = useState(), [maximizedPane, setMaximizedPane] = useState(null); if (error) throw error; const { structureContext, rootPaneNode } = useStructureTool(); let t0; $[0] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (t0 = { paneDataItems: [], resolvedPanes: [], routerPanes: [] }, $[0] = t0) : t0 = $[0]; const [data, setData] = useState(t0), routerPanesStream = useRouterPanesStream(); let t1, t2; $[1] !== rootPaneNode || $[2] !== routerPanesStream || $[3] !== structureContext ? (t1 = () => { const subscription = createResolvedPaneNodeStream({ rootPaneNode, routerPanesStream, structureContext }).pipe(map(_temp5$1)).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); let t3; if ($[6] !== data.paneDataItems || $[7] !== maximizedPane) { let t42; $[9] !== maximizedPane ? (t42 = (item) => ({ ...item, maximized: maximizedPane ? item.key === maximizedPane.key : !1 }), $[9] = maximizedPane, $[10] = t42) : t42 = $[10], t3 = data.paneDataItems.map(t42), $[6] = data.paneDataItems, $[7] = maximizedPane, $[8] = t3; } else t3 = $[8]; const paneDataItemsWithMaximized = t3; let t4; return $[11] !== data || $[12] !== maximizedPane || $[13] !== paneDataItemsWithMaximized ? (t4 = { ...data, paneDataItems: paneDataItemsWithMaximized, maximizedPane, setMaximizedPane }, $[11] = data, $[12] = maximizedPane, $[13] = paneDataItemsWithMaximized, $[14] = t4) : t4 = $[14], t4; } function _temp5$1(resolvedPanes) { const routerPanes = resolvedPanes.reduce(_temp3$1, []), 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, maximized: !1 }; }); return { paneDataItems, routerPanes, resolvedPanes: paneDataItems.map(_temp4$1) }; } function _temp4$1(pane_0) { return pane_0.pane; } function _temp3$1(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(74), { error } = t0; if (!(error instanceof PaneResolutionError)) throw error; const { cause } = error, { t } = useTranslation(structureLocaleNamespace), stack = cause?.stack || error.stack; let t1; $[0] !== cause || $[1] !== error.message || $[2] !== stack ? (t1 = stack && !(cause instanceof SerializeError) && !error.message.includes("Module build failed:"), $[0] = cause, $[1] = error.message, $[2] = stack, $[3] = t1) : t1 = $[3]; const showStack = t1; let T0, T1, T2, handleReload, helpId, t10, t11, t12, t13, t14, t2, t3, t4, t5, t6, t7, t8, t9; if ($[4] !== cause || $[5] !== error.helpId || $[6] !== t) { const path = cause instanceof SerializeError ? cause.path : []; helpId = cause instanceof SerializeError && cause.helpId || error.helpId, handleReload = _temp$3, T2 = Card, t10 = "fill", t11 = "auto", t12 = 4, t13 = "border", t14 = "critical", T1 = Container; let t152; $[25] !== t ? (t152 = t("structure-error.header.text"), $[25] = t, $[26] = t152) : t152 = $[26], $[27] !== t152 ? (t9 = /* @__PURE__ */ jsx(Heading, { as: "h2", children: t152 }), $[27] = t152, $[28] = t9) : t9 = $[28], T0 = Card, t2 = 4, t3 = 4, t4 = 2, t5 = "auto", t6 = 1, t7 = "inherit", t8 = 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) }) ] }), $[4] = cause, $[5] = error.helpId, $[6] = t, $[7] = T0, $[8] = T1, $[9] = T2, $[10] = handleReload, $[11] = helpId, $[12] = t10, $[13] = t11, $[14] = t12, $[15] = t13, $[16] = t14, $[17] = t2, $[18] = t3, $[19] = t4, $[20] = t5, $[21] = t6, $[22] = t7, $[23] = t8, $[24] = t9; } else T0 = $[7], T1 = $[8], T2 = $[9], handleReload = $[10], helpId = $[11], t10 = $[12], t11 = $[13], t12 = $[14], t13 = $[15], t14 = $[16], t2 = $[17], t3 = $[18], t4 = $[19], t5 = $[20], t6 = $[21], t7 = $[22], t8 = $[23], t9 = $[24]; let t15; $[29] !== t ? (t15 = t("structure-error.error.label"), $[29] = t, $[30] = t15) : t15 = $[30]; let t16; $[31] !== t15 ? (t16 = /* @__PURE__ */ jsx(Text, { size: 1, weight: "medium", children: t15 }), $[31] = t15, $[32] = t16) : t16 = $[32]; let t17; $[33] !== error.message || $[34] !== showStack || $[35] !== stack ? (t17 = showStack ? formatStack(stack) : error.message, $[33] = error.message, $[34] = showStack, $[35] = stack, $[36] = t17) : t17 = $[36]; let t18; $[37] !== t17 ? (t18 = /* @__PURE__ */ jsx(Code, { children: t17 }), $[37] = t17, $[38] = t18) : t18 = $[38]; let t19; $[39] !== t16 || $[40] !== t18 ? (t19 = /* @__PURE__ */ jsxs(Stack, { marginTop: 4, space: 2, children: [ t16, t18 ] }), $[39] = t16, $[40] = t18, $[41] = t19) : t19 = $[41]; let t20; $[42] !== helpId || $[43] !== t ? (t20 = 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") }) }) }), $[42] = helpId, $[43] = t, $[44] = t20) : t20 = $[44]; let t21; $[45] !== t ? (t21 = t("structure-error.reload-button.text"), $[45] = t, $[46] = t21) : t21 = $[46]; let t22; $[47] !== handleReload || $[48] !== t21 ? (t22 = /* @__PURE__ */ jsx(Box, { marginTop: 4, children: /* @__PURE__ */ jsx(Button, { text: t21, icon: SyncIcon, tone: "primary", onClick: handleReload }) }), $[47] = handleReload, $[48] = t21, $[49] = t22) : t22 = $[49]; let t23; $[50] !== T0 || $[51] !== t19 || $[52] !== t2 || $[53] !== t20 || $[54] !== t22 || $[55] !== t3 || $[56] !== t4 || $[57] !== t5 || $[58] !== t6 || $[59] !== t7 || $[60] !== t8 ? (t23 = /* @__PURE__ */ jsxs(T0, { marginTop: t2, padding: t3, radius: t4, overflow: t5, shadow: t6, tone: t7, children: [ t8, t19, t20, t22 ] }), $[50] = T0, $[51] = t19, $[52] = t2, $[53] = t20, $[54] = t22, $[55] = t3, $[56] = t4, $[57] = t5, $[58] = t6, $[59] = t7, $[60] = t8, $[61] = t23) : t23 = $[61]; let t24; $[62] !== T1 || $[63] !== t23 || $[64] !== t9 ? (t24 = /* @__PURE__ */ jsxs(T1, { children: [ t9, t23 ] }), $[62] = T1, $[63] = t23, $[64] = t9, $[65] = t24) : t24 = $[65]; let t25; return $[66] !== T2 || $[67] !== t10 || $[68] !== t11 || $[69] !== t12 || $[70] !== t13 || $[71] !== t14 || $[72] !== t24 ? (t25 = /* @__PURE__ */ jsx(T2, { height: t10, overflow: t11, padding: t12, sizing: t13, tone: t14, children: t24 }), $[66] = T2, $[67] = t10, $[68] = t11, $[69] = t12, $[70] = t13, $[71] = t14, $[72] = t24, $[73] = t25) : t25 = $[73], t25; } 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] === /* @__PURE__ */ 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] === /* @__PURE__ */ 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(58), { onPaneChange } = t0, { push: pushToast } = useToast(), schema = useSchema(), { navigate } = useRouter(), routerState = useRouterState(), { layoutCollapsed, setLayoutCollapsed } = useStructureTool(), resolvedPanesValue = useResolvedPanes(), { paneDataItems, resolvedPanes, setMaximizedPane, maximizedPane } = resolvedPanesValue, 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; if ($[4] !== paneDataItems) { const maximizedLastIndex = paneDataItems.findLastIndex(_temp2$1); t4 = maximizedLastIndex === -1 ? paneDataItems : paneDataItems.slice(maximizedLastIndex).filter((pane_0) => pane_0.groupIndex <= paneDataItems[maximizedLastIndex].groupIndex), $[4] = paneDataItems, $[5] = t4; } else t4 = $[5]; const paneItemsToShow = t4; let t5, t6; $[6] !== onPaneChange || $[7] !== resolvedPanes ? (t5 = () => { resolvedPanes.length && onPaneChange(resolvedPanes); }, t6 = [onPaneChange, resolvedPanes], $[6] = onPaneChange, $[7] = resolvedPanes, $[8] = t5, $[9] = t6) : (t5 = $[8], t6 = $[9]), useEffect(t5, t6); let t7, t8; $[10] !== pushToast ? (t7 = () => { 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); }, t8 = [pushToast], $[10] = pushToast, $[11] = t7, $[12] = t8) : (t7 = $[11], t8 = $[12]), useEffect(t7, t8); const hasDefinedDocumentTypes = schema._original?.types.some(_isCustomDocumentTypeDefinition); let t9; $[13] !== navigate || $[14] !== routerState?.panes || $[15] !== setMaximizedPane ? (t9 = (paneData) => { if (!paneData) return; const currentPanes = routerState?.panes || []; if (paneData.maximized) { setMaximizedPane(null), navigate({ panes: currentPanes }); return; } if (paneData.pane !== LOADING_PANE && paneData.pane.type === "document") { const slicedPanes = currentPanes.slice(0, paneData.groupIndex); setMaximizedPane(paneData), navigate({ panes: slicedPanes }); } }, $[13] = navigate, $[14] = routerState?.panes, $[15] = setMaximizedPane, $[16] = t9) : t9 = $[16]; const onSetMaximizedPane = t9, previousSelectedIndexRef = useRef(-1); let t10; $[17] !== navigate || $[18] !== paneDataItems || $[19] !== routerState?.panes || $[20] !== setMaximizedPane ? (t10 = () => { const focusedPaneAccordingToParams = paneDataItems.find(_temp3); if (!focusedPaneAccordingToParams) return; focusedPaneAccordingToParams.pane !== LOADING_PANE && focusedPaneAccordingToParams.pane.type === "document" && setMaximizedPane(focusedPaneAccordingToParams); const panesWithoutFocus = (routerState?.panes || []).map(_temp5); navigate({ panes: panesWithoutFocus }, { replace: !0 }); }, $[17] = navigate, $[18] = paneDataItems, $[19] = routerState?.panes, $[20] = setMaximizedPane, $[21] = t10) : t10 = $[21]; const t11 = routerState?.panes; let t12; $[22] !== navigate || $[23] !== paneDataItems || $[24] !== setMaximizedPane || $[25] !== t11 ? (t12 = [navigate, paneDataItems, t11, setMaximizedPane], $[22] = navigate, $[23] = paneDataItems, $[24] = setMaximizedPane, $[25] = t11, $[26] = t12) : t12 = $[26], useEffect(t10, t12); let t13, t14; if ($[27] !== maximizedPane || $[28] !== paneDataItems || $[29] !== setMaximizedPane ? (t13 = () => { const selectedIndex = paneDataItems.findIndex(_temp6), prevSelectedIndex = previousSelectedIndexRef.current; if (previousSelectedIndexRef.current = selectedIndex, !!maximizedPane) { if (maximizedPane.pane !== LOADING_PANE && maximizedPane.pane.type !== "document") { setMaximizedPane(null); return; } if (selectedIndex !== -1 && selectedIndex !== prevSelectedIndex) { const selectedPane = paneDataItems[selectedIndex]; setMaximizedPane(selectedPane); return; } if (!paneDataItems.some((pane_3) => pane_3.key === maximizedPane.key)) { const fallbackPane = paneDataItems.find((pane_4) => pane_4.groupIndex === maximizedPane.groupIndex && pane_4.siblingIndex === maximizedPane.siblingIndex && pane_4.pane !== LOADING_PANE && pane_4.pane.type === "document"); setMaximizedPane(fallbackPane || null); } } }, t14 = [maximizedPane, paneDataItems, setMaximizedPane], $[27] = maximizedPane, $[28] = paneDataItems, $[29] = setMaximizedPane, $[30] = t13, $[31] = t14) : (t13 = $[30], t14 = $[31]), useEffect(t13, t14), !hasDefinedDocumentTypes) { let t152; return $[32] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (t152 = /* @__PURE__ */ jsx(NoDocumentTypesScreen, {}), $[32] = t152) : t152 = $[32], t152; } const t15 = portalElement || null, t16 = layoutCollapsed ? void 0 : "fill", t17 = media[1]; let t18; if ($[33] !== onSetMaximizedPane || $[34] !== paneItemsToShow) { let t192; $[36] !== onSetMaximizedPane ? (t192 = (paneData_0) => { const { active, childItemId, groupIndex, itemId, key: paneKey, pane: pane_5, index: paneIndex, params: paneParams, path, payload, siblingIndex, selected, maximized } = paneData_0; return /* @__PURE__ */ jsx(Fragment, { children: pane_5 === LOADING_PANE ? /* @__PURE__ */ jsx(LoadingPane, { paneKey, path, selected }) : /* @__PURE__ */ jsx(StructureToolPane, { active, groupIndex, index: paneIndex, pane: pane_5, childItemId, itemId, paneKey, params: paneParams, payload, path, selected, siblingIndex, maximized, onSetMaximizedPane: () => onSetMaximizedPane(paneData_0) }) }, `${pane_5 === LOADING_PANE ? "loading" : pane_5.type}-${paneIndex}`); }, $[36] = onSetMaximizedPane, $[37] = t192) : t192 = $[37], t18 = paneItemsToShow.map(t192), $[33] = onSetMaximizedPane, $[34] = paneItemsToShow, $[35] = t18; } else t18 = $[35]; let t19; $[38] !== isResolvingIntent || $[39] !== paneDataItems.length ? (t19 = paneDataItems.length <= 1 && isResolvingIntent && /* @__PURE__ */ jsx(LoadingPane, { paneKey: "intent-resolver" }), $[38] = isResolvingIntent, $[39] = paneDataItems.length, $[40] = t19) : t19 = $[40]; let t20; $[41] !== handleRootCollapse || $[42] !== handleRootExpand || $[43] !== media[1] || $[44] !== t16 || $[45] !== t18 || $[46] !== t19 ? (t20 = /* @__PURE__ */ jsxs(StyledPaneLayout, { flex: 1, height: t16, minWidth: t17, onCollapse: handleRootCollapse, onExpand: handleRootExpand, children: [ t18, t19 ] }), $[41] = handleRootCollapse, $[42] = handleRootExpand, $[43] = media[1], $[44] = t16, $[45] = t18, $[46] = t19, $[47] = t20) : t20 = $[47]; let t21; $[48] !== resolvedPanes ? (t21 = /* @__PURE__ */ jsx(StructureTitle, { resolvedPanes }), $[48] = resolvedPanes, $[49] = t21) : t21 = $[49]; let t22; $[50] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (t22 = /* @__PURE__ */ jsx("div", { "data-portal": "", ref: setPortalElement }), $[50] = t22) : t22 = $[50]; let t23; $[51] !== t15 || $[52] !== t20 || $[53] !== t21 ? (t23 = /* @__PURE__ */ jsxs(PortalProvider, { element: t15, children: [ t20, t21, t22 ] }), $[51] = t15, $[52] = t20, $[53] = t21, $[54] = t23) : t23 = $[54]; let t24; return $[55] !== resolvedPanesValue || $[56] !== t23 ? (t24 = /* @__PURE__ */ jsx(ResolvedPanesProvider, { value: resolvedPanesValue, children: t23 }), $[55] = resolvedPanesValue, $[56] = t23, $[57] = t24) : t24 = $[57], t24; }); function _temp$1(state) { return typeof state.intent == "string"; } function _temp2$1(pane) { return pane.maximized; } function _temp3(p) { return p.params?.mode === "focus"; } function _temp4(pane_1) { const { mode: _omitMode, ...rest } = pane_1.params || {}, nextParams = Object.keys(rest).length ? rest : void 0; return { ...pane_1, params: nextParams }; } function _temp5(group) { return group.map(_temp4); } function _temp6(pane_2) { return pane_2.selected; } 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] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (t3 = [], $[2] = t3) : t3 = $[2], useEffect(_temp2, t3); let t4; $[3] === /* @__PURE__ */ 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] === /* @__PURE__ */ 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.js.map