@sanity/assist 2.0.5 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,4159 @@
1
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
+ import { SyncIcon, DocumentIcon, LinkIcon, ImageIcon, BlockContentIcon, OlistIcon, BlockquoteIcon, StringIcon, ArrowLeftIcon, PlayIcon, SparklesIcon, SearchIcon, ErrorOutlineIcon, CheckmarkCircleIcon, CloseCircleIcon, ClockIcon, RetryIcon, ArrowRightIcon, CloseIcon, CheckmarkIcon, icons, TokenIcon, DocumentTextIcon, ThListIcon, CodeIcon, ComposeIcon, LockIcon, TranslateIcon, ControlsIcon } from "@sanity/icons";
3
+ import { Card, Stack, Box, Button, Spinner, Flex, Label, focusFirstDescendant, Text, useToast, Dialog, Tooltip, TextArea, Container, Autocomplete, Breadcrumbs, useClickOutside, Popover, useLayer, useGlobalKeyDown, Badge, useTheme, rgba, Checkbox, Radio, ThemeProvider, ErrorBoundary, MenuButton, Menu, MenuItem, Switch } from "@sanity/ui";
4
+ import { useState, useRef, useEffect, useMemo, useCallback, createContext, useContext, useId, createElement, useReducer, forwardRef } from "react";
5
+ import { useClient, isArraySchemaType, typed, useSchema, isKeySegment, isDocumentSchemaType, pathToString, useDocumentStore, useDocumentPresence, createPatchChannel, FormBuilder, fromMutationPatches, isObjectSchemaType, stringToPath, useCurrentUser, set, useFormCallbacks, FormCallbacksProvider, FormInput, PatchEvent, setIfMissing, insert, useEditState, FormFieldHeaderText, unset, StatusButton, PresenceOverlay, VirtualizerScrollInstanceProvider, useColorSchemeValue, ObjectInputMember, isArrayOfObjectsSchemaType, defineType, defineField, defineArrayMember, getPublishedId, useSyncState, definePlugin } from "sanity";
6
+ import isEqual from "react-fast-compare";
7
+ import { mergeMap, share, take, filter, distinctUntilChanged, catchError, tap } from "rxjs/operators";
8
+ import { throwError, of, partition, merge, switchMap, delay, defer } from "rxjs";
9
+ import { exhaustMapToWithTrailing } from "rxjs-exhaustmap-with-trailing";
10
+ import { extractWithPath } from "@sanity/mutator";
11
+ import { minutesToMilliseconds, isAfter, addSeconds } from "date-fns";
12
+ import { useDocumentPane, usePaneRouter, DocumentInspectorHeader, DocumentPaneProvider } from "sanity/structure";
13
+ import { styled, keyframes } from "styled-components";
14
+ import formatDistanceToNow from "date-fns/formatDistanceToNow";
15
+ import get from "lodash/get.js";
16
+ const fetch = (client, query, params, options2) => defer(
17
+ () => (
18
+ // getVersionedClient(options.apiVersion)
19
+ client.observable.fetch(query, params, {
20
+ tag: options2.tag,
21
+ filterResponse: !0
22
+ })
23
+ )
24
+ ), listen = (client, query, params, options2) => defer(
25
+ () => (
26
+ // getVersionedClient(options.apiVersion)
27
+ client.listen(query, params, {
28
+ events: ["welcome", "mutation", "reconnect"],
29
+ includeResult: !1,
30
+ visibility: "query",
31
+ tag: options2.tag
32
+ })
33
+ )
34
+ );
35
+ function isWelcomeEvent(event) {
36
+ return event.type === "welcome";
37
+ }
38
+ const listenQuery = (client, query, params = {}, options2 = {}) => {
39
+ const fetchQuery = typeof query == "string" ? query : query.fetch, listenerQuery = typeof query == "string" ? query : query.listen, fetchOnce$ = fetch(client, fetchQuery, params, options2), events$ = listen(client, listenerQuery, params, options2).pipe(
40
+ mergeMap((ev, i) => i === 0 && !isWelcomeEvent(ev) ? throwError(
41
+ new Error(
42
+ ev.type === "reconnect" ? "Could not establish EventSource connection" : `Received unexpected type of first event "${ev.type}"`
43
+ )
44
+ ) : of(ev)),
45
+ share()
46
+ ), [welcome$, mutationAndReconnect$] = partition(events$, isWelcomeEvent), isRelevantEvent = (event) => !options2.transitions || event.type !== "mutation" ? !0 : options2.transitions.includes(event.transition);
47
+ return merge(
48
+ welcome$.pipe(take(1)),
49
+ mutationAndReconnect$.pipe(
50
+ filter(isRelevantEvent),
51
+ switchMap((event) => merge(of(event), of(event).pipe(delay(options2.throttleTime || 1e3))))
52
+ )
53
+ ).pipe(exhaustMapToWithTrailing(fetchOnce$));
54
+ }, DEFAULT_PARAMS = {}, DEFAULT_OPTIONS = { apiVersion: "v2022-05-09" };
55
+ function useListeningQuery(query, params = DEFAULT_PARAMS, options2 = DEFAULT_OPTIONS) {
56
+ const [loading, setLoading] = useState(!0), [error, setError] = useState(!1), [data, setData] = useState(null), subscription = useRef(null), client = useClient({ apiVersion: "v2022-05-09" });
57
+ return useEffect(() => (query && (subscription.current = listenQuery(client, query, params, options2).pipe(
58
+ distinctUntilChanged(isEqual),
59
+ catchError((err) => (console.error(err), setError(err), setLoading(!1), setData(null), err))
60
+ ).subscribe((documents) => {
61
+ setData((current) => isEqual(current, documents) ? current : documents), setLoading(!1), setError(!1);
62
+ })), () => subscription.current ? subscription.current.unsubscribe() : void 0), [query, params, options2, client]), { loading, error, data };
63
+ }
64
+ const assistDocumentIdPrefix = "sanity.assist.schemaType.", assistDocumentStatusIdPrefix = "sanity.assist.status.", assistSchemaIdPrefix = "sanity.assist.schema.", assistDocumentTypeName = "sanity.assist.schemaType.annotations", assistFieldTypeName = "sanity.assist.schemaType.field", instructionTypeName = "sanity.assist.instruction", promptTypeName = "sanity.assist.instruction.prompt", userInputTypeName = "sanity.assist.instruction.userInput", instructionContextTypeName = "sanity.assist.instruction.context", fieldReferenceTypeName = "sanity.assist.instruction.fieldRef", contextDocumentTypeName = "assist.instruction.context", assistTasksStatusTypeName = "sanity.assist.task.status", instructionTaskTypeName = "sanity.assist.instructionTask", fieldPresenceTypeName = "sanity.assist.instructionTask.presence", assistSerializedTypeName = "sanity.assist.serialized.type", assistSerializedFieldTypeName = "sanity.assist.serialized.field", outputFieldTypeName = "sanity.assist.output.field", outputTypeTypeName = "sanity.assist.output.type", fieldPathParam = "pathKey", instructionParam = "instruction", documentRootKey = "<document>";
65
+ function isPortableTextArray(type) {
66
+ return type.of.find((t) => isType(t, "block"));
67
+ }
68
+ function isType(schemaType, typeName) {
69
+ return schemaType.name === typeName ? !0 : schemaType.type ? isType(schemaType.type, typeName) : !1;
70
+ }
71
+ function isImage(schemaType) {
72
+ return isType(schemaType, "image");
73
+ }
74
+ function getDescriptionFieldOption(schemaType) {
75
+ var _a, _b;
76
+ return schemaType ? ((_b = (_a = schemaType.options) == null ? void 0 : _a.aiAssist) == null ? void 0 : _b.imageDescriptionField) || getDescriptionFieldOption(schemaType.type) : void 0;
77
+ }
78
+ function getImageInstructionFieldOption(schemaType) {
79
+ var _a, _b;
80
+ return schemaType ? ((_b = (_a = schemaType.options) == null ? void 0 : _a.aiAssist) == null ? void 0 : _b.imageInstructionField) || getImageInstructionFieldOption(schemaType.type) : void 0;
81
+ }
82
+ function isSchemaAssistEnabled(type) {
83
+ var _a, _b;
84
+ return !((_b = (_a = type.options) == null ? void 0 : _a.aiAssist) != null && _b.exclude);
85
+ }
86
+ function isAssistSupported(type) {
87
+ return !isSchemaAssistEnabled(type) || isDisabled(type) ? !1 : type.jsonType === "array" ? !type.of.every((t) => isDisabled(t)) : type.jsonType === "object" ? !type.fields.every((field) => isDisabled(field.type)) : !0;
88
+ }
89
+ function isDisabled(type) {
90
+ return !isSchemaAssistEnabled(type) || isUnsupportedType(type);
91
+ }
92
+ function isUnsupportedType(type) {
93
+ var _a, _b;
94
+ return type.jsonType === "number" || type.name === "sanity.imageCrop" || type.name === "sanity.imageHotspot" || isType(type, "reference") && !((_b = (_a = type == null ? void 0 : type.options) == null ? void 0 : _a.aiAssist) != null && _b.embeddingsIndex) || isType(type, "crossDatasetReference") || isType(type, "slug") || isType(type, "url") || isType(type, "date") || isType(type, "datetime") || isType(type, "file");
95
+ }
96
+ const hiddenTypes = [
97
+ "any",
98
+ "array",
99
+ "block",
100
+ "boolean",
101
+ "crossDatasetReference",
102
+ "date",
103
+ "datetime",
104
+ "document",
105
+ "email",
106
+ "file",
107
+ "image",
108
+ "number",
109
+ "object",
110
+ "reference",
111
+ "span",
112
+ "string",
113
+ "text",
114
+ "url",
115
+ "slug",
116
+ "geopoint",
117
+ "sanity.assetSourceData",
118
+ "sanity.imageAsset",
119
+ "sanity.fileAsset",
120
+ "sanity.imageCrop",
121
+ "sanity.imageHotspot",
122
+ "sanity.imageMetadata",
123
+ "sanity.imageDimensions",
124
+ "sanity.imagePalette",
125
+ "sanity.imagePaletteSwatch",
126
+ assistSerializedTypeName,
127
+ assistSerializedFieldTypeName,
128
+ "sanity-agent.job.document"
129
+ ], inlineTypes = ["document", "object", "image", "file"];
130
+ function serializeSchema(schema, options2) {
131
+ const list = schema.getTypeNames().filter((t) => !(hiddenTypes.includes(t) || t.startsWith("sanity."))).map((t) => schema.get(t)).filter((t) => !!t).map((t) => getSchemaStub(t, schema, options2)).filter((t) => !("to" in t && t.to && !t.to.length || "of" in t && t.of && !t.of.length || "fields" in t && t.fields && !t.fields.length));
132
+ return list.sort((a, b) => {
133
+ var _a, _b;
134
+ return ((_a = a == null ? void 0 : a.name) != null ? _a : "").localeCompare((_b = b == null ? void 0 : b.name) != null ? _b : "");
135
+ }), list;
136
+ }
137
+ function getSchemaStub(schemaType, schema, options2) {
138
+ var _a;
139
+ if (!((_a = schemaType.type) != null && _a.name))
140
+ throw console.error("Missing type name", schemaType.type), new Error("Type is missing name!");
141
+ const baseSchema = {
142
+ // we dont need type or id when we send using POST, so leave these out to save bandwidth
143
+ ...options2 != null && options2.leanFormat ? {} : { _id: `${assistSchemaIdPrefix}${schemaType.name}`, _type: assistSerializedTypeName },
144
+ name: schemaType.name,
145
+ title: schemaType.title,
146
+ type: schemaType.type.name,
147
+ ...getBaseFields(schema, schemaType, schemaType.type.name, options2)
148
+ };
149
+ return removeUndef(baseSchema);
150
+ }
151
+ function getBaseFields(schema, type, typeName, options2) {
152
+ var _a, _b, _c, _d, _e, _f;
153
+ const schemaOptions = removeUndef({
154
+ imagePromptField: (_b = (_a = type.options) == null ? void 0 : _a.aiAssist) == null ? void 0 : _b.imageInstructionField,
155
+ embeddingsIndex: (_d = (_c = type.options) == null ? void 0 : _c.aiAssist) == null ? void 0 : _d.embeddingsIndex
156
+ });
157
+ return removeUndef({
158
+ options: Object.keys(schemaOptions).length ? schemaOptions : void 0,
159
+ values: Array.isArray((_e = type == null ? void 0 : type.options) == null ? void 0 : _e.list) ? (_f = type == null ? void 0 : type.options) == null ? void 0 : _f.list.map(
160
+ (v) => {
161
+ var _a2;
162
+ return typeof v == "string" ? v : (_a2 = v.value) != null ? _a2 : `${v.title}`;
163
+ }
164
+ ) : void 0,
165
+ of: "of" in type && typeName === "array" ? arrayOf(type, schema, options2) : void 0,
166
+ to: "to" in type && typeName === "reference" ? refToTypeNames(type) : void 0,
167
+ fields: "fields" in type && inlineTypes.includes(typeName) ? serializeFields(schema, type, options2) : void 0,
168
+ annotations: typeName === "block" && "fields" in type ? serializeAnnotations(type, schema, options2) : void 0,
169
+ inlineOf: typeName === "block" && "fields" in type ? serializeInlineOf(type, schema, options2) : void 0,
170
+ hidden: typeof type.hidden == "function" ? "function" : type.hidden ? !0 : void 0,
171
+ readOnly: typeof type.readOnly == "function" ? "function" : type.readOnly ? !0 : void 0
172
+ });
173
+ }
174
+ function serializeFields(schema, schemaType, options2) {
175
+ return (schemaType.fieldsets ? schemaType.fieldsets.flatMap(
176
+ (fs) => fs.single ? fs.field : fs.fields.map((f) => ({
177
+ ...f,
178
+ type: {
179
+ ...f.type,
180
+ // if fieldset is (conditionally) hidden, the field must be considered the same way
181
+ // ie, if the field does not show up in conditionalMembers, it is hidden
182
+ // regardless of weather or not it is the field function or the fieldset function that hides it
183
+ hidden: typeof fs.hidden == "function" ? fs.hidden : fs.hidden ? !0 : f.type.hidden
184
+ }
185
+ }))
186
+ ) : schemaType.fields).filter((f) => {
187
+ var _a, _b;
188
+ return !["sanity.imageHotspot", "sanity.imageCrop"].includes((_b = (_a = f.type) == null ? void 0 : _a.name) != null ? _b : "");
189
+ }).filter((f) => isAssistSupported(f.type)).map((field) => serializeMember(schema, field.type, field.name, options2));
190
+ }
191
+ function serializeMember(schema, type, name, options2) {
192
+ var _a, _b;
193
+ const typeName = schema.get(type == null ? void 0 : type.name) ? type.name : (_b = (_a = type.type) == null ? void 0 : _a.name) != null ? _b : "";
194
+ return removeUndef({
195
+ ...options2 != null && options2.leanFormat ? {} : { _type: assistSerializedFieldTypeName },
196
+ name,
197
+ type: typeName,
198
+ title: type.title,
199
+ ...getBaseFields(schema, type, typeName, options2)
200
+ });
201
+ }
202
+ function serializeInlineOf(blockSchemaType, schema, options2) {
203
+ const childrenField = blockSchemaType.fields.find((f) => f.name === "children"), childrenType = childrenField == null ? void 0 : childrenField.type;
204
+ if (!(!childrenType || !isArraySchemaType(childrenType)))
205
+ return arrayOf(
206
+ {
207
+ ...childrenType,
208
+ of: childrenType.of.filter((t) => !isType(t, "span"))
209
+ },
210
+ schema,
211
+ options2
212
+ );
213
+ }
214
+ function serializeAnnotations(blockSchemaType, schema, options2) {
215
+ const markDefs = blockSchemaType.fields.find((f) => f.name === "markDefs"), marksType = markDefs == null ? void 0 : markDefs.type;
216
+ if (!(!marksType || !isArraySchemaType(marksType)))
217
+ return arrayOf(marksType, schema, options2);
218
+ }
219
+ function arrayOf(arrayType, schema, options2) {
220
+ return arrayType.of.filter((type) => isAssistSupported(type)).map((t) => serializeMember(schema, t, t.name, options2));
221
+ }
222
+ function refToTypeNames(type) {
223
+ return type.to.map((t) => ({
224
+ type: typed(t.name)
225
+ }));
226
+ }
227
+ function removeUndef(obj) {
228
+ return Object.keys(obj).forEach((key) => obj[key] === void 0 ? delete obj[key] : {}), obj;
229
+ }
230
+ const NO_DATA = [], defaultTitle = "Sync schema";
231
+ function SchemaTypeTool() {
232
+ const schema = useSchema(), client = useClient({ apiVersion: "2023-01-01" }), [saving, setSaving] = useState(!1), [syncTitle, setSyncTitle] = useState(defaultTitle), { data } = useListeningQuery("*[_type==$type] | order(_type)", {
233
+ type: assistSerializedTypeName
234
+ }), types = useMemo(() => serializeSchema(schema), [schema]), storeTypes = useCallback(() => {
235
+ setSaving(!0);
236
+ let canSave = !0;
237
+ async function store() {
238
+ setSyncTitle(`Syncing 0/${types.length}`);
239
+ const transaction = client.transaction();
240
+ for (let i = 0; i < types.length && canSave; i++) {
241
+ const type = types[i];
242
+ await transaction.createOrReplace(type), i > 0 && i % 50 === 0 && (await transaction.commit(), transaction.reset(), setSyncTitle(`Syncing ${i}/${types.length}`));
243
+ }
244
+ await transaction.commit();
245
+ }
246
+ return store().catch(console.error).finally(() => {
247
+ setSaving(!1), setSyncTitle(defaultTitle);
248
+ }), () => {
249
+ canSave = !1, setSaving(!1), setSyncTitle(defaultTitle);
250
+ };
251
+ }, [types, client, setSaving, setSyncTitle]);
252
+ return /* @__PURE__ */ jsx(Card, { padding: 4, overflow: "auto", style: { height: "calc(100vh - 81px)" }, children: /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
253
+ /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(
254
+ Button,
255
+ {
256
+ icon: saving ? /* @__PURE__ */ jsx(Spinner, { style: { marginTop: 5 } }) : SyncIcon,
257
+ text: syncTitle,
258
+ disabled: saving,
259
+ onClick: storeTypes
260
+ }
261
+ ) }),
262
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
263
+ /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
264
+ /* @__PURE__ */ jsx(Label, { children: "Studio schema" }),
265
+ /* @__PURE__ */ jsx("ul", { children: types.map((type) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(SchemaEntry, { schemaStub: type }) }, type.name)) })
266
+ ] }),
267
+ /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
268
+ /* @__PURE__ */ jsx(Label, { children: "Stored schema" }),
269
+ /* @__PURE__ */ jsx("ul", { children: (data != null ? data : NO_DATA).map((type) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(SchemaEntry, { schemaStub: type }) }, type.name)) })
270
+ ] })
271
+ ] })
272
+ ] }) });
273
+ }
274
+ function SchemaEntry({ schemaStub }) {
275
+ const out = useMemo(() => JSON.stringify(schemaStub, null, 2), [schemaStub]);
276
+ return /* @__PURE__ */ jsx("pre", { children: out });
277
+ }
278
+ const MAX_DEPTH$1 = 6;
279
+ function getDocumentMembersFlat(doc, schemaType) {
280
+ return isDocumentSchemaType(schemaType) ? extractPaths(doc, schemaType, [], MAX_DEPTH$1) : (console.error("Schema type is not a document"), []);
281
+ }
282
+ function extractPaths(doc, schemaType, path, maxDepth2) {
283
+ return path.length >= maxDepth2 ? [] : schemaType.fields.reduce((acc, field) => {
284
+ var _a, _b;
285
+ const fieldPath = [...path, field.name], fieldSchema = field.type, { value } = (_a = extractWithPath(pathToString(fieldPath), doc)[0]) != null ? _a : {};
286
+ if (!value)
287
+ return acc;
288
+ const thisFieldWithPath = {
289
+ path: fieldPath,
290
+ name: field.name,
291
+ schemaType: fieldSchema,
292
+ value
293
+ };
294
+ if (fieldSchema.jsonType === "object") {
295
+ const innerFields = extractPaths(doc, fieldSchema, fieldPath, maxDepth2);
296
+ return [...acc, thisFieldWithPath, ...innerFields];
297
+ } else if (fieldSchema.jsonType === "array" && fieldSchema.of.length && fieldSchema.of.some((item) => "fields" in item)) {
298
+ const { value: arrayValue } = (_b = extractWithPath(pathToString(fieldPath), doc)[0]) != null ? _b : {};
299
+ let arrayPaths = [];
300
+ if (arrayValue != null && arrayValue.length)
301
+ for (const item of arrayValue) {
302
+ const itemPath = [...fieldPath, { _key: item._key }];
303
+ let itemSchema = fieldSchema.of.find((t) => t.name === item._type);
304
+ if (item._type || (itemSchema = fieldSchema.of[0], console.warn(
305
+ "Array item is missing _type - using the first defined type in the array.of schema",
306
+ {
307
+ itemPath,
308
+ item,
309
+ itemSchema
310
+ }
311
+ )), item._key && itemSchema) {
312
+ const innerFields = extractPaths(
313
+ doc,
314
+ itemSchema,
315
+ itemPath,
316
+ maxDepth2
317
+ ), arrayMember = {
318
+ path: itemPath,
319
+ name: item._key,
320
+ schemaType: itemSchema,
321
+ value: item
322
+ };
323
+ arrayPaths = [...arrayPaths, arrayMember, ...innerFields];
324
+ }
325
+ }
326
+ return [...acc, thisFieldWithPath, ...arrayPaths];
327
+ }
328
+ return [...acc, thisFieldWithPath];
329
+ }, []);
330
+ }
331
+ const defaultLanguageOutputs = function(member, enclosingType, translateFromLanguageId, translateToLanguageIds) {
332
+ if (member.schemaType.jsonType === "object" && member.schemaType.name.startsWith("internationalizedArray")) {
333
+ const pathEnd = member.path.slice(-1);
334
+ return (isKeySegment(pathEnd[0]) ? pathEnd[0]._key : null) === translateFromLanguageId ? translateToLanguageIds.map((translateToId) => ({
335
+ id: translateToId,
336
+ outputPath: [...member.path.slice(0, -1), { _key: translateToId }]
337
+ })) : void 0;
338
+ }
339
+ if (enclosingType.jsonType === "object" && enclosingType.name.startsWith("locale"))
340
+ return translateFromLanguageId === member.name ? translateToLanguageIds.map((translateToId) => ({
341
+ id: translateToId,
342
+ outputPath: [...member.path.slice(0, -1), translateToId]
343
+ })) : void 0;
344
+ };
345
+ function getFieldLanguageMap(documentSchema, documentMembers, translateFromLanguageId, outputLanguageIds, langFn) {
346
+ var _a, _b, _c;
347
+ const translationMaps = [];
348
+ for (const member of documentMembers) {
349
+ const parentPath = member.path.slice(0, -1), enclosingType = (_b = (_a = documentMembers.find((m) => pathToString(m.path) === pathToString(parentPath))) == null ? void 0 : _a.schemaType) != null ? _b : documentSchema, translations = (_c = langFn(
350
+ member,
351
+ enclosingType,
352
+ translateFromLanguageId,
353
+ outputLanguageIds
354
+ )) == null ? void 0 : _c.filter((translation) => translation.id !== translateFromLanguageId);
355
+ translations && translationMaps.push({
356
+ inputLanguageId: translateFromLanguageId,
357
+ inputPath: member.path,
358
+ outputs: translations
359
+ });
360
+ }
361
+ return translationMaps;
362
+ }
363
+ const releaseAnnouncementUrl = "https://www.sanity.io/blog/sanity-ai-assist-announcement?utm_source=sanity-assist-plugin&utm_medium=organic_social&utm_campaign=ai-assist&utm_content=", instructionGuideUrl = "https://sanity.io/guides/getting-started-with-ai-assist-instructions?utm_source=sanity-assist-plugin&utm_medium=organic_social&utm_campaign=ai-assist&utm_content=", giveFeedbackUrl = "https://forms.gle/Kwz7CThxGeA2GiEU8", salesUrl = "https://www.sanity.io/contact/sales?utm_source=sanity-assist-plugin&utm_medium=organic_social&utm_campaign=ai-assist&utm_content=", packageName = "@sanity/assist", pluginTitle = "Sanity AI Assist", pluginTitleShort = "AI Assist", maxHistoryVisibilityMs = minutesToMilliseconds(30), assistFormId = "assist", preventDefault = (ev) => ev.preventDefault();
364
+ function DocumentForm(props) {
365
+ var _a;
366
+ const {
367
+ collapsedFieldSets,
368
+ collapsedPaths,
369
+ displayed: value,
370
+ documentId,
371
+ documentType,
372
+ editState,
373
+ formState,
374
+ onBlur,
375
+ onChange,
376
+ onFocus,
377
+ onPathOpen,
378
+ onSetActiveFieldGroup,
379
+ onSetCollapsedFieldSet,
380
+ onSetCollapsedPath,
381
+ ready,
382
+ validation
383
+ } = useDocumentPane(), documentStore = useDocumentStore(), presence = useDocumentPresence(documentId), patchChannel = useMemo(() => createPatchChannel(), []), isLocked = (_a = editState == null ? void 0 : editState.transactionSyncLock) == null ? void 0 : _a.enabled;
384
+ useEffect(() => {
385
+ const sub = documentStore.pair.documentEvents(documentId, documentType).pipe(
386
+ tap((event) => {
387
+ event.type === "mutation" && patchChannel.publish(prepareMutationEvent(event)), event.type === "rebase" && patchChannel.publish(prepareRebaseEvent(event));
388
+ })
389
+ ).subscribe();
390
+ return () => {
391
+ sub.unsubscribe();
392
+ };
393
+ }, [documentId, documentStore, documentType, patchChannel]);
394
+ const hasRev = !!(value != null && value._rev);
395
+ useEffect(() => {
396
+ hasRev && patchChannel.publish({
397
+ type: "mutation",
398
+ patches: [],
399
+ snapshot: value
400
+ });
401
+ }, [hasRev]);
402
+ const formRef = useRef(null);
403
+ return useEffect(() => {
404
+ focusFirstDescendant(formRef.current);
405
+ }, []), isLocked ? /* @__PURE__ */ jsx(Box, { as: "form", ...props, ref: formRef, children: /* @__PURE__ */ jsx(
406
+ Flex,
407
+ {
408
+ align: "center",
409
+ direction: "column",
410
+ height: "fill",
411
+ justify: "center",
412
+ padding: 3,
413
+ sizing: "border",
414
+ children: /* @__PURE__ */ jsx(Text, { size: 1, children: "Please hold tight while the document is synced. This usually happens right after the document has been published, and it shouldn\u2019t take more than a few seconds" })
415
+ }
416
+ ) }) : /* @__PURE__ */ jsx(Box, { as: "form", ...props, onSubmit: preventDefault, ref: formRef, children: ready ? formState === null ? /* @__PURE__ */ jsx(
417
+ Flex,
418
+ {
419
+ align: "center",
420
+ direction: "column",
421
+ height: "fill",
422
+ justify: "center",
423
+ padding: 3,
424
+ sizing: "border",
425
+ children: /* @__PURE__ */ jsx(Text, { size: 1, children: "This form is hidden" })
426
+ }
427
+ ) : /* @__PURE__ */ jsx(
428
+ FormBuilder,
429
+ {
430
+ __internal_patchChannel: patchChannel,
431
+ collapsedFieldSets,
432
+ collapsedPaths,
433
+ focusPath: formState.focusPath,
434
+ changed: formState.changed,
435
+ focused: formState.focused,
436
+ groups: formState.groups,
437
+ id: assistFormId,
438
+ members: formState.members,
439
+ onChange,
440
+ onFieldGroupSelect: onSetActiveFieldGroup,
441
+ onPathBlur: onBlur,
442
+ onPathFocus: onFocus,
443
+ onPathOpen,
444
+ onSetFieldSetCollapsed: onSetCollapsedFieldSet,
445
+ onSetPathCollapsed: onSetCollapsedPath,
446
+ presence,
447
+ readOnly: formState.readOnly,
448
+ schemaType: formState.schemaType,
449
+ validation,
450
+ value: formState.value
451
+ }
452
+ ) : /* @__PURE__ */ jsxs(
453
+ Flex,
454
+ {
455
+ align: "center",
456
+ direction: "column",
457
+ height: "fill",
458
+ justify: "center",
459
+ padding: 3,
460
+ sizing: "border",
461
+ children: [
462
+ /* @__PURE__ */ jsx(Spinner, { muted: !0 }),
463
+ /* @__PURE__ */ jsx(Box, { marginTop: 3, children: /* @__PURE__ */ jsx(Text, { align: "center", muted: !0, size: 1, children: "Loading document" }) })
464
+ ]
465
+ }
466
+ ) });
467
+ }
468
+ function prepareMutationEvent(event) {
469
+ const patches = event.mutations.map((mut) => mut.patch).filter(Boolean);
470
+ return {
471
+ type: "mutation",
472
+ snapshot: event.document,
473
+ patches: fromMutationPatches(event.origin, patches)
474
+ };
475
+ }
476
+ function prepareRebaseEvent(event) {
477
+ const remotePatches = event.remoteMutations.map((mut) => mut.patch).filter(Boolean), localPatches = event.localMutations.map((mut) => mut.patch).filter(Boolean);
478
+ return {
479
+ type: "rebase",
480
+ snapshot: event.document,
481
+ patches: fromMutationPatches("remote", remotePatches).concat(
482
+ fromMutationPatches("local", localPatches)
483
+ )
484
+ };
485
+ }
486
+ const SelectedFieldContext = createContext(void 0), SelectedFieldContextProvider = SelectedFieldContext.Provider, maxDepth = 6;
487
+ function getTypeIcon(schemaType) {
488
+ let t = schemaType;
489
+ for (; t; ) {
490
+ if (t.icon)
491
+ return t.icon;
492
+ t = t.type;
493
+ }
494
+ return isType(schemaType, "slug") ? LinkIcon : isType(schemaType, "image") ? ImageIcon : schemaType.jsonType === "array" && isPortableTextArray(schemaType) ? BlockContentIcon : schemaType.jsonType === "array" ? OlistIcon : schemaType.jsonType === "object" ? BlockquoteIcon : schemaType.jsonType === "string" ? StringIcon : DocumentIcon;
495
+ }
496
+ function getFieldRefsWithDocument(schemaType) {
497
+ var _a;
498
+ const fields = getFieldRefs(schemaType);
499
+ return [
500
+ {
501
+ key: documentRootKey,
502
+ icon: (_a = schemaType.icon) != null ? _a : DocumentIcon,
503
+ title: "The entire document",
504
+ path: [],
505
+ schemaType
506
+ },
507
+ ...fields
508
+ ];
509
+ }
510
+ function getFieldRefs(schemaType, parent, depth = 0) {
511
+ return depth >= maxDepth ? [] : schemaType.fields.filter((f) => !f.name.startsWith("_")).flatMap((field) => {
512
+ var _a;
513
+ const path = parent ? [...parent.path, field.name] : [field.name], title = (_a = field.type.title) != null ? _a : field.name, fieldRef = {
514
+ key: patchableKey(pathToString(path)),
515
+ path,
516
+ title: parent ? [parent.title, title].join(" / ") : title,
517
+ schemaType: field.type,
518
+ icon: getTypeIcon(field.type)
519
+ }, fields = field.type.jsonType === "object" ? getFieldRefs(field.type, fieldRef, depth + 1) : [], syntheticFields = field.type.jsonType === "array" ? getSyntheticFields(field.type, fieldRef, depth + 1) : [];
520
+ return isAssistSupported(field.type) ? [fieldRef, ...fields, ...syntheticFields] : [...fields, ...syntheticFields];
521
+ });
522
+ }
523
+ function getSyntheticFields(schemaType, parent, depth = 0) {
524
+ return depth >= maxDepth ? [] : schemaType.of.filter((itemType) => !isType(itemType, "block")).flatMap((itemType) => {
525
+ var _a;
526
+ const segment = { _key: itemType.name }, title = (_a = itemType.title) != null ? _a : itemType.name, path = parent ? [...parent.path, segment] : [segment], fieldRef = {
527
+ key: patchableKey(pathToString(path)),
528
+ path,
529
+ title: parent ? [parent.title, title].join(" / ") : title,
530
+ schemaType: itemType,
531
+ icon: getTypeIcon(itemType),
532
+ synthetic: !0
533
+ }, fields = itemType.jsonType === "object" ? getFieldRefs(itemType, fieldRef, depth + 1) : [];
534
+ return isAssistSupported(itemType) ? [fieldRef, ...fields] : fields;
535
+ });
536
+ }
537
+ function getTypePath(doc, pathString) {
538
+ if (!pathString)
539
+ return;
540
+ const path = stringToPath(pathString), currentPath = [];
541
+ let valid = !0;
542
+ const syntheticPath = path.map((segment) => {
543
+ if (currentPath.push(segment), isKeySegment(segment)) {
544
+ const match = extractWithPath(pathToString(currentPath), doc)[0], value = match == null ? void 0 : match.value;
545
+ if (match && value && typeof value == "object" && "_type" in value)
546
+ return { _key: value._type };
547
+ valid = !1;
548
+ }
549
+ return segment;
550
+ });
551
+ return valid ? patchableKey(pathToString(syntheticPath)) : void 0;
552
+ }
553
+ function patchableKey(pathKey) {
554
+ return pathKey.replace(/[=]=/g, ":").replace(/[[\]]/g, "|").replace(/"/g, "");
555
+ }
556
+ function useTypePath(doc, pathString) {
557
+ return useMemo(() => getTypePath(doc, pathString), [doc, pathString]);
558
+ }
559
+ function useSelectedField(documentSchemaType, path) {
560
+ const selectableFields = useMemo(
561
+ () => documentSchemaType && isObjectSchemaType(documentSchemaType) ? getFieldRefsWithDocument(documentSchemaType) : [],
562
+ [documentSchemaType]
563
+ );
564
+ return useMemo(() => path ? selectableFields == null ? void 0 : selectableFields.find((f) => f.key === path) : void 0, [selectableFields, path]);
565
+ }
566
+ function getFieldTitle(field) {
567
+ var _a, _b, _c;
568
+ const schemaType = field == null ? void 0 : field.schemaType;
569
+ return (_c = (_b = (_a = field == null ? void 0 : field.title) != null ? _a : schemaType == null ? void 0 : schemaType.title) != null ? _b : schemaType == null ? void 0 : schemaType.name) != null ? _c : "Untitled";
570
+ }
571
+ function useAiPaneRouter() {
572
+ const paneRouter = usePaneRouter();
573
+ return useMemo(
574
+ () => {
575
+ var _a;
576
+ return { ...paneRouter, params: (_a = paneRouter.params) != null ? _a : {} };
577
+ },
578
+ [paneRouter]
579
+ );
580
+ }
581
+ const basePath = "/assist/tasks/instruction";
582
+ function canUseAssist(status) {
583
+ return (status == null ? void 0 : status.enabled) && status.initialized && status.validToken;
584
+ }
585
+ function useApiClient(customApiClient) {
586
+ const client = useClient({ apiVersion: "2023-06-05" });
587
+ return useMemo(
588
+ () => customApiClient ? customApiClient(client) : client,
589
+ [client, customApiClient]
590
+ );
591
+ }
592
+ function useTranslate(apiClient) {
593
+ const [loading, setLoading] = useState(!1), user = useCurrentUser(), schema = useSchema(), types = useMemo(() => serializeSchema(schema, { leanFormat: !0 }), [schema]), toast = useToast(), translate = useCallback(
594
+ ({
595
+ documentId,
596
+ languagePath,
597
+ translatePath,
598
+ fieldLanguageMap,
599
+ conditionalMembers
600
+ }) => (setLoading(!0), apiClient.request({
601
+ method: "POST",
602
+ url: `/assist/tasks/translate/${apiClient.config().dataset}?projectId=${apiClient.config().projectId}`,
603
+ body: {
604
+ documentId,
605
+ types,
606
+ languagePath,
607
+ fieldLanguageMap,
608
+ conditionalMembers,
609
+ translatePath: translatePath.length === 0 ? documentRootKey : pathToString(translatePath),
610
+ userId: user == null ? void 0 : user.id
611
+ }
612
+ }).catch((e) => {
613
+ throw toast.push({
614
+ status: "error",
615
+ title: "Translate failed",
616
+ description: e.message
617
+ }), setLoading(!1), e;
618
+ }).finally(() => {
619
+ setTimeout(() => {
620
+ setLoading(!1);
621
+ }, 2e3);
622
+ })),
623
+ [setLoading, apiClient, toast, user, types]
624
+ );
625
+ return useMemo(
626
+ () => ({
627
+ translate,
628
+ loading
629
+ }),
630
+ [translate, loading]
631
+ );
632
+ }
633
+ function useGenerateCaption(apiClient) {
634
+ const [loading, setLoading] = useState(!1), user = useCurrentUser(), schema = useSchema(), types = useMemo(() => serializeSchema(schema, { leanFormat: !0 }), [schema]), toast = useToast(), generateCaption = useCallback(
635
+ ({ path, documentId }) => (setLoading(!0), apiClient.request({
636
+ method: "POST",
637
+ url: `/assist/tasks/generate-caption/${apiClient.config().dataset}?projectId=${apiClient.config().projectId}`,
638
+ body: {
639
+ path,
640
+ documentId,
641
+ types,
642
+ userId: user == null ? void 0 : user.id
643
+ }
644
+ }).catch((e) => {
645
+ throw toast.push({
646
+ status: "error",
647
+ title: "Generate image description failed",
648
+ description: e.message
649
+ }), setLoading(!1), e;
650
+ }).finally(() => {
651
+ setTimeout(() => {
652
+ setLoading(!1);
653
+ }, 2e3);
654
+ })),
655
+ [setLoading, apiClient, toast, user, types]
656
+ );
657
+ return useMemo(
658
+ () => ({
659
+ generateCaption,
660
+ loading
661
+ }),
662
+ [generateCaption, loading]
663
+ );
664
+ }
665
+ function useGenerateImage(apiClient) {
666
+ const [loading, setLoading] = useState(!1), user = useCurrentUser(), schema = useSchema(), types = useMemo(() => serializeSchema(schema, { leanFormat: !0 }), [schema]), toast = useToast(), generateImage = useCallback(
667
+ ({ path, documentId }) => (setLoading(!0), apiClient.request({
668
+ method: "POST",
669
+ url: `/assist/tasks/generate-image/${apiClient.config().dataset}?projectId=${apiClient.config().projectId}`,
670
+ body: {
671
+ path,
672
+ documentId,
673
+ types,
674
+ userId: user == null ? void 0 : user.id
675
+ }
676
+ }).catch((e) => {
677
+ throw toast.push({
678
+ status: "error",
679
+ title: "Generate image from prompt failed",
680
+ description: e.message
681
+ }), setLoading(!1), e;
682
+ }).finally(() => {
683
+ setTimeout(() => {
684
+ setLoading(!1);
685
+ }, 2e3);
686
+ })),
687
+ [setLoading, apiClient, toast, user, types]
688
+ );
689
+ return useMemo(
690
+ () => ({
691
+ generateImage,
692
+ loading
693
+ }),
694
+ [generateImage, loading]
695
+ );
696
+ }
697
+ function useGetInstructStatus(apiClient) {
698
+ const [loading, setLoading] = useState(!0), getInstructStatus = useCallback(async () => {
699
+ setLoading(!0);
700
+ const projectId = apiClient.config().projectId;
701
+ try {
702
+ return await apiClient.request({
703
+ method: "GET",
704
+ url: `${basePath}/${apiClient.config().dataset}/status?projectId=${projectId}`
705
+ });
706
+ } finally {
707
+ setLoading(!1);
708
+ }
709
+ }, [setLoading, apiClient]);
710
+ return {
711
+ loading,
712
+ getInstructStatus
713
+ };
714
+ }
715
+ function useInitInstruct(apiClient) {
716
+ const [loading, setLoading] = useState(!1), initInstruct = useCallback(() => (setLoading(!0), apiClient.request({
717
+ method: "GET",
718
+ url: `${basePath}/${apiClient.config().dataset}/init?projectId=${apiClient.config().projectId}`
719
+ }).finally(() => {
720
+ setLoading(!1);
721
+ })), [setLoading, apiClient]);
722
+ return {
723
+ loading,
724
+ initInstruct
725
+ };
726
+ }
727
+ function useRunInstructionApi(apiClient) {
728
+ const toast = useToast(), [loading, setLoading] = useState(!1), user = useCurrentUser(), schema = useSchema(), types = useMemo(() => serializeSchema(schema, { leanFormat: !0 }), [schema]), runInstruction = useCallback(
729
+ (request) => (setLoading(!0), apiClient.request({
730
+ method: "POST",
731
+ url: `${basePath}/${apiClient.config().dataset}?projectId=${apiClient.config().projectId}`,
732
+ body: {
733
+ ...request,
734
+ types,
735
+ userId: user == null ? void 0 : user.id
736
+ }
737
+ }).catch((e) => {
738
+ throw toast.push({
739
+ status: "error",
740
+ title: "Instruction failed",
741
+ description: e.message
742
+ }), e;
743
+ }).finally(() => {
744
+ setLoading(!1);
745
+ })),
746
+ [apiClient, types, user, toast]
747
+ );
748
+ return useMemo(
749
+ () => ({
750
+ runInstruction,
751
+ loading
752
+ }),
753
+ [runInstruction, loading]
754
+ );
755
+ }
756
+ const AiAssistanceConfigContext = createContext({});
757
+ function useAiAssistanceConfig() {
758
+ const context = useContext(AiAssistanceConfigContext);
759
+ if (!context)
760
+ throw new Error("Missing AiAssistanceConfigContext");
761
+ return context;
762
+ }
763
+ function AiAssistanceConfigProvider(props) {
764
+ var _a;
765
+ const [status, setStatus] = useState(), [error, setError] = useState(), apiClient = useApiClient((_a = props.config) == null ? void 0 : _a.__customApiClient), { getInstructStatus, loading: statusLoading } = useGetInstructStatus(apiClient), { initInstruct, loading: initLoading } = useInitInstruct(apiClient);
766
+ useEffect(() => {
767
+ getInstructStatus().then((s) => setStatus(s)).catch((e) => {
768
+ console.error(e), setError(e);
769
+ });
770
+ }, [getInstructStatus]);
771
+ const init = useCallback(async () => {
772
+ setError(void 0);
773
+ try {
774
+ await initInstruct();
775
+ const status2 = await getInstructStatus();
776
+ setStatus(status2);
777
+ } catch (e) {
778
+ console.error("Failed to init ai assistance", e), setError(e);
779
+ }
780
+ }, [initInstruct, getInstructStatus, setStatus]), { config, children } = props, context = useMemo(() => ({
781
+ config,
782
+ status,
783
+ statusLoading,
784
+ init,
785
+ initLoading,
786
+ error
787
+ }), [config, status, init, statusLoading, initLoading, error]);
788
+ return /* @__PURE__ */ jsx(AiAssistanceConfigContext.Provider, { value: context, children });
789
+ }
790
+ const aiDocPrefixPattern = new RegExp(`^${assistDocumentIdPrefix}`);
791
+ function publicId(id) {
792
+ return id.replace("drafts.", "");
793
+ }
794
+ function assistDocumentId(documentType) {
795
+ return `${assistDocumentIdPrefix}${documentType}`;
796
+ }
797
+ function documentTypeFromAiDocumentId(id) {
798
+ return id.replace(aiDocPrefixPattern, "");
799
+ }
800
+ function assistTasksStatusId(documentId) {
801
+ return `${assistDocumentStatusIdPrefix}${publicId(documentId)}`;
802
+ }
803
+ const aiInspectorId = "ai-assistance";
804
+ function BackToInstructionListLink() {
805
+ const { openInspector } = useDocumentPane(), goBack = useCallback(
806
+ () => openInspector(aiInspectorId, { [instructionParam]: void 0 }),
807
+ [openInspector]
808
+ );
809
+ return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
810
+ Button,
811
+ {
812
+ as: "a",
813
+ fontSize: 1,
814
+ icon: ArrowLeftIcon,
815
+ mode: "bleed",
816
+ padding: 1,
817
+ space: 2,
818
+ onClick: goBack,
819
+ text: " Instructions",
820
+ textAlign: "left"
821
+ }
822
+ ) });
823
+ }
824
+ const EMPTY_FIELDS = [], TypePathContext = createContext(void 0);
825
+ function AssistDocumentForm(props) {
826
+ return props.readOnly ? /* @__PURE__ */ jsx(Card, { border: !0, tone: "caution", padding: 2, children: /* @__PURE__ */ jsx(Text, { size: 1, children: " You do not have sufficient permissions to manage instructions." }) }) : /* @__PURE__ */ jsx(AssistDocumentFormEditable, { ...props });
827
+ }
828
+ function AssistDocumentFormEditable(props) {
829
+ const { onChange } = props, value = props.value, id = value == null ? void 0 : value._id, fields = value == null ? void 0 : value.fields, targetDocumentType = useMemo(() => {
830
+ if (id)
831
+ return documentTypeFromAiDocumentId(id);
832
+ }, [id]), { params, setParams } = useAiPaneRouter(), pathKey = params[fieldPathParam], typePath = useContext(TypePathContext), instruction2 = params[instructionParam], activeKey = useMemo(() => {
833
+ var _a;
834
+ if (typePath)
835
+ return (_a = (fields != null ? fields : EMPTY_FIELDS).find((f) => f.path === typePath)) == null ? void 0 : _a._key;
836
+ }, [fields, typePath]), activePath = useMemo(() => {
837
+ if (!activeKey)
838
+ return;
839
+ const base = ["fields", { _key: activeKey }];
840
+ return instruction2 ? [...base, "instructions", { _key: instruction2 }] : base;
841
+ }, [activeKey, instruction2]), schema = useSchema(), documentSchema = useMemo(() => {
842
+ if (targetDocumentType)
843
+ return schema.get(targetDocumentType);
844
+ }, [schema, targetDocumentType]), fieldSchema = useSelectedSchema(pathKey, documentSchema), context = useMemo(
845
+ () => ({
846
+ documentSchema,
847
+ fieldSchema: fieldSchema != null ? fieldSchema : documentSchema
848
+ }),
849
+ [fieldSchema, documentSchema]
850
+ ), title = value == null ? void 0 : value.title;
851
+ useEffect(() => {
852
+ var _a;
853
+ !title && documentSchema && !(id != null && id.startsWith("drafts.")) && onChange(set((_a = documentSchema.title) != null ? _a : documentSchema.name, ["title"]));
854
+ }, [title, documentSchema, onChange, id]);
855
+ const { onPathOpen, ...formCallbacks } = useFormCallbacks(), newCallbacks = useMemo(
856
+ () => ({
857
+ ...formCallbacks,
858
+ onPathOpen: (path) => {
859
+ var _a;
860
+ !instruction2 && path.length === 4 && path[2] === "instructions" ? (setParams(
861
+ typed({
862
+ ...params,
863
+ [instructionParam]: (_a = path[3]) == null ? void 0 : _a._key
864
+ })
865
+ ), onPathOpen([])) : setTimeout(() => onPathOpen(path), 0);
866
+ }
867
+ }),
868
+ [formCallbacks, onPathOpen, params, setParams, instruction2]
869
+ );
870
+ return useEffect(() => {
871
+ activePath && !instruction2 && onPathOpen([]);
872
+ }, [activePath, instruction2, onPathOpen]), /* @__PURE__ */ jsx(SelectedFieldContextProvider, { value: context, children: /* @__PURE__ */ jsxs(Stack, { space: 5, children: [
873
+ /* @__PURE__ */ jsx(
874
+ FieldsInitializer,
875
+ {
876
+ pathKey: typePath,
877
+ activePath,
878
+ fields,
879
+ documentSchema,
880
+ onChange
881
+ },
882
+ typePath
883
+ ),
884
+ instruction2 && /* @__PURE__ */ jsx(BackToInstructionListLink, {}),
885
+ activePath && /* @__PURE__ */ jsx(FormCallbacksProvider, { ...newCallbacks, children: /* @__PURE__ */ jsx("div", { style: { lineHeight: "1.25em" }, children: /* @__PURE__ */ jsx(FormInput, { ...props, absolutePath: activePath }) }) }),
886
+ !activePath && props.renderDefault(props)
887
+ ] }) });
888
+ }
889
+ function useSelectedSchema(fieldPath, documentSchema) {
890
+ return useMemo(() => {
891
+ if (!fieldPath)
892
+ return;
893
+ if (fieldPath === documentRootKey)
894
+ return documentSchema;
895
+ const path = stringToPath(fieldPath);
896
+ let currentSchema = documentSchema;
897
+ for (let i = 0; i < path.length; i++) {
898
+ const segment = path[i], field = currentSchema == null ? void 0 : currentSchema.fields.find((f) => f.name === segment);
899
+ if (!field)
900
+ return;
901
+ if (i === path.length - 1)
902
+ return field.type;
903
+ if (field.type.jsonType !== "object")
904
+ return;
905
+ currentSchema = field.type;
906
+ }
907
+ return currentSchema;
908
+ }, [documentSchema, fieldPath]);
909
+ }
910
+ function FieldsInitializer({
911
+ pathKey,
912
+ activePath,
913
+ fields,
914
+ documentSchema,
915
+ onChange
916
+ }) {
917
+ const {
918
+ config: { __presets: presets }
919
+ } = useAiAssistanceConfig(), existingField = fields == null ? void 0 : fields.find((f) => f._key === pathKey), documentPresets = !!(documentSchema != null && documentSchema.name) && (presets == null ? void 0 : presets[documentSchema == null ? void 0 : documentSchema.name]), missingPresetInstructions = useMemo(() => {
920
+ var _a, _b;
921
+ if (!documentPresets || !pathKey)
922
+ return;
923
+ const existingInstructions = existingField == null ? void 0 : existingField.instructions, presetField = (_a = documentPresets.fields) == null ? void 0 : _a.find((f) => f.path === pathKey);
924
+ return (_b = presetField == null ? void 0 : presetField.instructions) == null ? void 0 : _b.filter(
925
+ (i) => !(existingInstructions != null && existingInstructions.some((ei) => ei._key === i._key))
926
+ );
927
+ }, [documentPresets, pathKey, existingField]), initialized = useRef(!1);
928
+ return useEffect(() => {
929
+ var _a;
930
+ if (initialized.current || !pathKey || existingField && !(missingPresetInstructions != null && missingPresetInstructions.length))
931
+ return;
932
+ let event = PatchEvent.from([setIfMissing([], ["fields"])]);
933
+ existingField || (event = event.append(
934
+ insert(
935
+ [
936
+ typed({
937
+ _key: pathKey,
938
+ _type: assistFieldTypeName,
939
+ path: pathKey,
940
+ instructions: []
941
+ })
942
+ ],
943
+ "after",
944
+ ["fields", -1]
945
+ )
946
+ )), (_a = existingField == null ? void 0 : existingField.instructions) != null && _a.length || (event = event.append([setIfMissing([], ["fields", { _key: pathKey }, "instructions"])])), missingPresetInstructions != null && missingPresetInstructions.length && (event = event.append(
947
+ insert(
948
+ missingPresetInstructions.map(
949
+ (preset) => {
950
+ var _a2;
951
+ return {
952
+ ...preset,
953
+ _type: "sanity.assist.instruction",
954
+ prompt: (_a2 = preset.prompt) == null ? void 0 : _a2.map((p) => ({ markDefs: [], ...p }))
955
+ };
956
+ }
957
+ ),
958
+ "after",
959
+ ["fields", { _key: pathKey }, "instructions", -1]
960
+ )
961
+ )), onChange(event), initialized.current = !0;
962
+ }, [activePath, onChange, pathKey, existingField, missingPresetInstructions]), null;
963
+ }
964
+ function useDocumentState(id, docType) {
965
+ const state = useEditState(id, docType);
966
+ return state.draft || state.published;
967
+ }
968
+ function useStudioAssistDocument({
969
+ documentId,
970
+ schemaType,
971
+ initDoc
972
+ }) {
973
+ const documentTypeName = schemaType.name, currentUser = useCurrentUser(), assistDocument = useDocumentState(
974
+ assistDocumentId(documentTypeName),
975
+ assistDocumentTypeName
976
+ ), assistTasksStatus = useDocumentState(
977
+ assistTasksStatusId(documentId != null ? documentId : ""),
978
+ assistTasksStatusTypeName
979
+ ), client = useClient({ apiVersion: "2023-01-01" });
980
+ return useEffect(() => {
981
+ !assistDocument && initDoc && client.createIfNotExists({
982
+ _id: assistDocumentId(documentTypeName),
983
+ _type: assistDocumentTypeName
984
+ }).catch(() => {
985
+ });
986
+ }, [client, assistDocument, documentTypeName, initDoc]), useMemo(() => {
987
+ var _a, _b;
988
+ if (!assistDocument)
989
+ return;
990
+ const tasks = (_a = assistTasksStatus == null ? void 0 : assistTasksStatus.tasks) != null ? _a : [], fields = ((_b = assistDocument == null ? void 0 : assistDocument.fields) != null ? _b : []).map((assistField) => {
991
+ var _a2;
992
+ return {
993
+ ...assistField,
994
+ tasks: tasks.filter((task) => task.path === assistField.path),
995
+ instructions: (_a2 = assistField.instructions) == null ? void 0 : _a2.filter((p) => !p.userId || p.userId === (currentUser == null ? void 0 : currentUser.id)).map((instruction2) => asStudioInstruction(instruction2, tasks))
996
+ };
997
+ });
998
+ return typed({
999
+ ...assistDocument,
1000
+ tasks: tasks == null ? void 0 : tasks.map((task) => {
1001
+ var _a2, _b2;
1002
+ const instruction2 = (_b2 = (_a2 = fields.find((f) => f.path === task.path)) == null ? void 0 : _a2.instructions) == null ? void 0 : _b2.find((i) => i._key === task.instructionKey);
1003
+ return {
1004
+ ...task,
1005
+ instruction: instruction2
1006
+ };
1007
+ }),
1008
+ fields
1009
+ });
1010
+ }, [assistDocument, assistTasksStatus, currentUser]);
1011
+ }
1012
+ function asStudioInstruction(instruction2, run) {
1013
+ return {
1014
+ ...instruction2,
1015
+ tasks: run.filter((task) => task.instructionKey === instruction2._key).filter(
1016
+ (task) => task.started && (/* @__PURE__ */ new Date()).getTime() - new Date(task.started).getTime() < maxHistoryVisibilityMs
1017
+ )
1018
+ };
1019
+ }
1020
+ function usePathKey(path) {
1021
+ return useMemo(() => getPathKey(path), [path]);
1022
+ }
1023
+ function getPathKey(path) {
1024
+ return path.length ? Array.isArray(path) ? pathToString(path) : path : documentRootKey;
1025
+ }
1026
+ function getInstructionTitle(instruction2) {
1027
+ var _a;
1028
+ return (_a = instruction2 == null ? void 0 : instruction2.title) != null ? _a : "Untitled";
1029
+ }
1030
+ const NO_INPUT = {}, RunInstructionContext = createContext({
1031
+ runInstruction: () => {
1032
+ },
1033
+ instructionLoading: !1
1034
+ });
1035
+ function useRunInstruction() {
1036
+ return useContext(RunInstructionContext);
1037
+ }
1038
+ function isUserInputBlock(block) {
1039
+ return block._type === userInputTypeName;
1040
+ }
1041
+ function RunInstructionProvider(props) {
1042
+ var _a;
1043
+ const { config } = useAiAssistanceConfig(), apiClient = useApiClient(config == null ? void 0 : config.__customApiClient), { runInstruction: runInstructionRequest, loading } = useRunInstructionApi(apiClient), id = useId(), [inputs, setInputs] = useState(NO_INPUT), [runRequest, setRunRequest] = useState(), runInstruction = useCallback(
1044
+ (req) => {
1045
+ var _a2;
1046
+ if (loading)
1047
+ return;
1048
+ const { instruction: instruction2, ...request } = req, instructionKey = instruction2._key, userInputBlocks = (_a2 = instruction2 == null ? void 0 : instruction2.prompt) == null ? void 0 : _a2.flatMap(
1049
+ (block) => block._type === "block" ? block.children.filter(isUserInputBlock) : [block]
1050
+ ).filter(isUserInputBlock);
1051
+ if (!(userInputBlocks != null && userInputBlocks.length)) {
1052
+ runInstructionRequest({
1053
+ ...request,
1054
+ instructionKey,
1055
+ userTexts: void 0
1056
+ });
1057
+ return;
1058
+ }
1059
+ setRunRequest({
1060
+ ...req,
1061
+ userInputBlocks
1062
+ });
1063
+ },
1064
+ [runInstructionRequest, loading]
1065
+ ), close = useCallback(() => {
1066
+ setRunRequest(void 0), setInputs(NO_INPUT);
1067
+ }, []), runWithInput = useCallback(() => {
1068
+ if (runRequest) {
1069
+ const { instruction: instruction2, userTexts, ...request } = runRequest;
1070
+ runInstructionRequest({
1071
+ ...request,
1072
+ instructionKey: instruction2._key,
1073
+ userTexts: Object.entries(inputs).map(([key, value]) => ({
1074
+ blockKey: key,
1075
+ userInput: value
1076
+ }))
1077
+ });
1078
+ }
1079
+ close();
1080
+ }, [close, runInstructionRequest, runRequest, inputs]), open = !!runRequest, runDisabled = useMemo(
1081
+ () => {
1082
+ var _a2, _b;
1083
+ return ((_b = (_a2 = runRequest == null ? void 0 : runRequest.userInputBlocks) == null ? void 0 : _a2.length) != null ? _b : 0) > Object.entries(inputs).filter(([, value]) => !!value).length;
1084
+ },
1085
+ [runRequest == null ? void 0 : runRequest.userInputBlocks, inputs]
1086
+ ), runButton = /* @__PURE__ */ jsx(
1087
+ Button,
1088
+ {
1089
+ text: "Run instruction",
1090
+ onClick: runWithInput,
1091
+ tone: "primary",
1092
+ icon: PlayIcon,
1093
+ style: { width: "100%" },
1094
+ disabled: runDisabled
1095
+ }
1096
+ ), contextValue = useMemo(
1097
+ () => ({ runInstruction, instructionLoading: loading }),
1098
+ [runInstruction, loading]
1099
+ );
1100
+ return /* @__PURE__ */ jsxs(RunInstructionContext.Provider, { value: contextValue, children: [
1101
+ open ? /* @__PURE__ */ jsx(
1102
+ Dialog,
1103
+ {
1104
+ id,
1105
+ open,
1106
+ onClose: close,
1107
+ width: 1,
1108
+ header: getInstructionTitle(runRequest == null ? void 0 : runRequest.instruction),
1109
+ footer: /* @__PURE__ */ jsx(Flex, { justify: "space-between", padding: 2, flex: 1, children: runDisabled ? /* @__PURE__ */ jsx(
1110
+ Tooltip,
1111
+ {
1112
+ content: /* @__PURE__ */ jsx(Flex, { padding: 2, children: /* @__PURE__ */ jsx(Text, { children: "Unable to run instruction. All fields must have a value." }) }),
1113
+ placement: "top",
1114
+ children: /* @__PURE__ */ jsx(Flex, { flex: 1, children: runButton })
1115
+ }
1116
+ ) : runButton }),
1117
+ children: /* @__PURE__ */ jsx(Stack, { padding: 4, space: 2, children: (_a = runRequest == null ? void 0 : runRequest.userInputBlocks) == null ? void 0 : _a.map((block, i) => /* @__PURE__ */ jsx(
1118
+ UserInput,
1119
+ {
1120
+ block,
1121
+ autoFocus: i === 0,
1122
+ inputs,
1123
+ setInputs
1124
+ },
1125
+ block._key
1126
+ )) })
1127
+ }
1128
+ ) : null,
1129
+ props.children
1130
+ ] });
1131
+ }
1132
+ function UserInput(props) {
1133
+ var _a;
1134
+ const { block, autoFocus, setInputs, inputs } = props, key = block._key, textAreaRef = useRef(null), onChange = useCallback(
1135
+ (e) => {
1136
+ setInputs((current) => {
1137
+ var _a2;
1138
+ return {
1139
+ ...current,
1140
+ [key]: ((_a2 = e.currentTarget) != null ? _a2 : e.target).value
1141
+ };
1142
+ });
1143
+ },
1144
+ [key, setInputs]
1145
+ ), value = useMemo(() => inputs[key], [inputs, key]);
1146
+ return useEffect(() => {
1147
+ autoFocus && setTimeout(() => {
1148
+ var _a2;
1149
+ return (_a2 = textAreaRef.current) == null ? void 0 : _a2.focus();
1150
+ }, 0);
1151
+ }, [autoFocus]), /* @__PURE__ */ jsxs(Stack, { padding: 2, space: 3, children: [
1152
+ /* @__PURE__ */ jsx(
1153
+ FormFieldHeaderText,
1154
+ {
1155
+ title: (_a = block == null ? void 0 : block.message) != null ? _a : "Provide more context",
1156
+ description: block.description
1157
+ }
1158
+ ),
1159
+ /* @__PURE__ */ jsx(
1160
+ TextArea,
1161
+ {
1162
+ ref: textAreaRef,
1163
+ rows: 4,
1164
+ value,
1165
+ onChange,
1166
+ style: { resize: "vertical" }
1167
+ }
1168
+ )
1169
+ ] });
1170
+ }
1171
+ function isDocAssistable(documentSchemaType, published, draft) {
1172
+ return !!(documentSchemaType.liveEdit ? published : draft);
1173
+ }
1174
+ function getAssistableDocId(documentSchemaType, documentId) {
1175
+ const baseId = publicId(documentId);
1176
+ return documentSchemaType.liveEdit ? baseId : `drafts.${baseId}`;
1177
+ }
1178
+ function useRequestRunInstruction(args) {
1179
+ const { runInstruction, instructionLoading } = useRunInstruction(), requestRunInstruction = useDraftDelayedTask({
1180
+ ...args,
1181
+ task: runInstruction
1182
+ });
1183
+ return {
1184
+ instructionLoading,
1185
+ requestRunInstruction
1186
+ };
1187
+ }
1188
+ function useDraftDelayedTask(args) {
1189
+ const { documentOnChange, isDocAssistable: isDocAssistable2, task } = args, [queuedArgs, setQueuedArgs] = useState(void 0);
1190
+ return useEffect(() => {
1191
+ queuedArgs && isDocAssistable2 && (task(queuedArgs), setQueuedArgs(void 0));
1192
+ }, [queuedArgs, isDocAssistable2, task]), useCallback(
1193
+ (taskArgs) => {
1194
+ documentOnChange(PatchEvent.from([unset(["_force_document_creation"])])), setQueuedArgs(taskArgs);
1195
+ },
1196
+ [setQueuedArgs, documentOnChange]
1197
+ );
1198
+ }
1199
+ const MAX_DEPTH = 8;
1200
+ function getConditionalMembers(docState) {
1201
+ return [{
1202
+ path: "",
1203
+ hidden: !1,
1204
+ readOnly: !!docState.readOnly,
1205
+ conditional: typeof docState.schemaType.hidden == "function"
1206
+ }, ...extractConditionalPaths(docState, MAX_DEPTH)].filter((v) => v.conditional).map(({ conditional, ...state }) => ({ ...state }));
1207
+ }
1208
+ function isConditional(schemaType) {
1209
+ return typeof schemaType.hidden == "function" || typeof schemaType.readOnly == "function";
1210
+ }
1211
+ function conditionalState(memberState) {
1212
+ return {
1213
+ path: pathToString(memberState.path),
1214
+ readOnly: !!memberState.readOnly,
1215
+ hidden: !1,
1216
+ // if its in members, its not hidden
1217
+ conditional: isConditional(memberState.schemaType)
1218
+ };
1219
+ }
1220
+ function extractConditionalPaths(node, maxDepth2) {
1221
+ return node.path.length >= maxDepth2 ? [] : node.members.reduce((acc, member) => {
1222
+ var _a, _b;
1223
+ if (member.kind === "error")
1224
+ return acc;
1225
+ if (member.kind === "field") {
1226
+ const schemaType = member.field.schemaType;
1227
+ if (schemaType.jsonType === "object") {
1228
+ const innerFields = member.field.readOnly ? [] : extractConditionalPaths(member.field, maxDepth2);
1229
+ return [...acc, conditionalState(member.field), ...innerFields];
1230
+ } else if (schemaType.jsonType === "array") {
1231
+ const array = member.field;
1232
+ let arrayPaths = [];
1233
+ const isObjectsArray = array.members.some(
1234
+ (m) => m.kind === "item" && isObjectSchemaType(m.item.schemaType)
1235
+ );
1236
+ if (!array.readOnly)
1237
+ for (const arrayMember of array.members) {
1238
+ if (arrayMember.kind === "error")
1239
+ continue;
1240
+ const innerFields = isObjectsArray && !arrayMember.item.readOnly ? extractConditionalPaths(arrayMember.item, maxDepth2) : [];
1241
+ arrayPaths = [...arrayPaths, conditionalState(arrayMember.item), ...innerFields];
1242
+ }
1243
+ return [...acc, conditionalState(array), ...arrayPaths];
1244
+ }
1245
+ return [...acc, conditionalState(member.field)];
1246
+ } else if (member.kind === "fieldSet") {
1247
+ const conditionalFieldset = !!((_b = (_a = node.schemaType) == null ? void 0 : _a.fieldsets) != null && _b.some(
1248
+ (f) => !f.single && f.name === member.fieldSet.name && typeof f.hidden == "function"
1249
+ )), innerFields = extractConditionalPaths(member.fieldSet, maxDepth2).map((f) => ({
1250
+ ...f,
1251
+ // if fieldset is conditional, visible fields must also be considered conditional
1252
+ conditional: conditionalFieldset != null ? conditionalFieldset : f.conditional
1253
+ }));
1254
+ return [...acc, ...innerFields];
1255
+ }
1256
+ return acc;
1257
+ }, []);
1258
+ }
1259
+ const SparklesIllustration = styled(SparklesIcon)({
1260
+ fontSize: "3.125em",
1261
+ "& path": {
1262
+ strokeWidth: "0.6px !important"
1263
+ }
1264
+ });
1265
+ function InspectorOnboarding(props) {
1266
+ const { onDismiss } = props;
1267
+ return /* @__PURE__ */ jsx(Box, { padding: 4, children: /* @__PURE__ */ jsx(Container, { width: 0, children: /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
1268
+ /* @__PURE__ */ jsx("div", { style: { textAlign: "center" }, children: /* @__PURE__ */ jsx(SparklesIllustration, {}) }),
1269
+ /* @__PURE__ */ jsx(Text, { align: "center", size: 1, children: "Create reusable AI instructions that can be applied across all documents of a certain type." }),
1270
+ /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, justify: "center", children: [
1271
+ /* @__PURE__ */ jsx(
1272
+ Button,
1273
+ {
1274
+ as: "a",
1275
+ href: releaseAnnouncementUrl,
1276
+ rel: "noreferrer",
1277
+ target: "_blank",
1278
+ fontSize: 1,
1279
+ mode: "default",
1280
+ onClick: onDismiss,
1281
+ padding: 2,
1282
+ text: "Learn more",
1283
+ tone: "primary"
1284
+ }
1285
+ ),
1286
+ /* @__PURE__ */ jsx(Button, { fontSize: 1, mode: "bleed", onClick: onDismiss, padding: 2, text: "Dismiss" })
1287
+ ] })
1288
+ ] }) }) });
1289
+ }
1290
+ const inspectorOnboardingKey = "sanityStudio:assist:inspector:onboarding:dismissed", fieldOnboardingKey = "sanityStudio:assist:field:onboarding:dismissed";
1291
+ function isFeatureOnboardingDismissed(featureKey) {
1292
+ return typeof localStorage > "u" ? !1 : localStorage.getItem(featureKey) === "true";
1293
+ }
1294
+ function dismissFeatureOnboarding(featureKey) {
1295
+ typeof localStorage > "u" || localStorage.setItem(featureKey, "true");
1296
+ }
1297
+ function useOnboardingFeature(featureKey) {
1298
+ const [showOnboarding, setShowOnboarding] = useState(
1299
+ () => !isFeatureOnboardingDismissed(featureKey)
1300
+ ), dismissOnboarding = useCallback(() => {
1301
+ setShowOnboarding(!1), dismissFeatureOnboarding(featureKey);
1302
+ }, [setShowOnboarding, featureKey]);
1303
+ return { showOnboarding, dismissOnboarding };
1304
+ }
1305
+ function FieldAutocomplete(props) {
1306
+ const { id, schemaType, fieldPath, onSelect, includeDocument, filter: filter2 } = props, fieldRefs = useMemo(() => includeDocument ? getFieldRefsWithDocument(schemaType) : getFieldRefs(schemaType), [schemaType, includeDocument]), currentField = useMemo(
1307
+ () => fieldRefs.find((f) => f.key === fieldPath),
1308
+ [fieldPath, fieldRefs]
1309
+ ), autocompleteOptions = useMemo(
1310
+ () => fieldRefs.filter((field) => filter2 ? filter2(field) : !0).filter((f) => !isType(f.schemaType, "reference")).map((field) => ({ value: field.key, field })),
1311
+ [fieldRefs, filter2]
1312
+ ), renderOption = useCallback((option) => {
1313
+ const { value, field } = option;
1314
+ return value ? isType(field.schemaType, "document") ? /* @__PURE__ */ jsx(Card, { as: "button", padding: 3, radius: 1, children: /* @__PURE__ */ jsx(Text, { size: 1, weight: "semibold", children: "The entire document" }) }) : /* @__PURE__ */ jsx(Card, { as: "button", padding: 3, radius: 1, children: /* @__PURE__ */ jsxs(Flex, { gap: 3, children: [
1315
+ /* @__PURE__ */ jsx(Text, { size: 1, children: createElement(field.icon) }),
1316
+ /* @__PURE__ */ jsx(FieldTitle, { field })
1317
+ ] }) }) : /* @__PURE__ */ jsx(Card, { as: "button", padding: 3, radius: 1, children: /* @__PURE__ */ jsx(Text, { accent: !0, size: 1, children: option.value }) });
1318
+ }, []), renderValue = useCallback((value, option) => {
1319
+ var _a;
1320
+ return (_a = option == null ? void 0 : option.field.title) != null ? _a : value;
1321
+ }, []), filterOption = useCallback((query, option) => {
1322
+ var _a, _b, _c;
1323
+ const lQuery = query.toLowerCase();
1324
+ return ((_a = option == null ? void 0 : option.value) == null ? void 0 : _a.toLowerCase().includes(lQuery)) || ((_c = (_b = option == null ? void 0 : option.field) == null ? void 0 : _b.title) == null ? void 0 : _c.toLowerCase().includes(lQuery));
1325
+ }, []);
1326
+ return /* @__PURE__ */ jsx(
1327
+ Autocomplete,
1328
+ {
1329
+ fontSize: 1,
1330
+ icon: currentField ? currentField.icon : SearchIcon,
1331
+ onChange: onSelect,
1332
+ openButton: !0,
1333
+ id,
1334
+ options: autocompleteOptions,
1335
+ placeholder: "Search for a field",
1336
+ radius: 2,
1337
+ renderOption,
1338
+ renderValue,
1339
+ value: currentField == null ? void 0 : currentField.key,
1340
+ filterOption
1341
+ }
1342
+ );
1343
+ }
1344
+ function FieldTitle(props) {
1345
+ const splitTitle = props.field.title.split("/");
1346
+ return /* @__PURE__ */ jsx(Box, { flex: "none", children: /* @__PURE__ */ jsxs(
1347
+ Breadcrumbs,
1348
+ {
1349
+ style: {
1350
+ display: "flex",
1351
+ flexWrap: "wrap",
1352
+ alignItems: "center",
1353
+ marginTop: "-4px"
1354
+ },
1355
+ separator: /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, children: "/" }) }),
1356
+ space: 1,
1357
+ children: [
1358
+ splitTitle.slice(0, splitTitle.length - 1).map((pt, i) => (
1359
+ // eslint-disable-next-line react/no-array-index-key
1360
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, children: pt.trim() }) }, i)
1361
+ )),
1362
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { size: 1, weight: "medium", children: splitTitle[splitTitle.length - 1] }) })
1363
+ ]
1364
+ }
1365
+ ) });
1366
+ }
1367
+ function useInterval(ms) {
1368
+ const [tick, update] = useReducer((n) => n + 1, 0);
1369
+ return useEffect(() => {
1370
+ const i = setInterval(update, ms);
1371
+ return () => clearInterval(i);
1372
+ }, [ms]), tick;
1373
+ }
1374
+ function TimeAgo({ date }) {
1375
+ useInterval(1e3);
1376
+ const timeSince = formatDistanceToNow(date ? new Date(date) : /* @__PURE__ */ new Date());
1377
+ return /* @__PURE__ */ jsxs("span", { title: timeSince, children: [
1378
+ timeSince,
1379
+ " ago"
1380
+ ] });
1381
+ }
1382
+ const rotate = keyframes`
1383
+ 0% {
1384
+ transform: rotate(0);
1385
+ }
1386
+ 100% {
1387
+ transform: rotate(360deg);
1388
+ }
1389
+ `, SyncSpinningIcon = styled(SyncIcon)`
1390
+ animation: ${rotate} 1s linear infinite;
1391
+ `, TASK_CONFIG = {
1392
+ aborted: {
1393
+ title: "Canceled",
1394
+ icon: CloseCircleIcon,
1395
+ tone: "transparent"
1396
+ },
1397
+ error: {
1398
+ title: "Error",
1399
+ icon: ErrorOutlineIcon,
1400
+ tone: "critical"
1401
+ },
1402
+ success: {
1403
+ title: "Completed",
1404
+ icon: CheckmarkCircleIcon,
1405
+ tone: "positive"
1406
+ },
1407
+ timeout: {
1408
+ title: "Timeout",
1409
+ icon: ClockIcon,
1410
+ tone: "caution"
1411
+ }
1412
+ };
1413
+ function InstructionTaskHistoryButton(props) {
1414
+ const { tasks, instructions, documentId, showTitles } = props, client = useClient({ apiVersion: "2023-01-01" }), cancelRun = useCallback(
1415
+ (taskKey) => {
1416
+ if (!documentId)
1417
+ return;
1418
+ const statusDocId = assistTasksStatusId(documentId), basePath2 = `${typed("tasks")}[_key=="${taskKey}"]`;
1419
+ client.patch(statusDocId).set({
1420
+ [`${basePath2}.${typed("ended")}`]: (/* @__PURE__ */ new Date()).toISOString(),
1421
+ [`${basePath2}.${typed("reason")}`]: typed("aborted")
1422
+ }).commit().catch(console.error);
1423
+ },
1424
+ [client, documentId]
1425
+ ), titledTasks = useMemo(() => {
1426
+ var _a;
1427
+ const t = (_a = tasks == null ? void 0 : tasks.filter(
1428
+ (task) => task.started && (/* @__PURE__ */ new Date()).getTime() - new Date(task.started).getTime() < maxHistoryVisibilityMs
1429
+ ).map((task) => {
1430
+ var _a2;
1431
+ const instruction2 = instructions == null ? void 0 : instructions.find((i) => i._key === task.instructionKey);
1432
+ return {
1433
+ ...task,
1434
+ title: showTitles ? (_a2 = task.title) != null ? _a2 : getInstructionTitle(instruction2) : void 0,
1435
+ cancel: () => cancelRun(task._key)
1436
+ };
1437
+ })) != null ? _a : [];
1438
+ return t.sort((a, b) => {
1439
+ var _a2, _b;
1440
+ return new Date((_a2 = b.started) != null ? _a2 : "").getTime() - new Date((_b = a.started) != null ? _b : "").getTime();
1441
+ }), t;
1442
+ }, [tasks, instructions, cancelRun, showTitles]), isRunning = useMemo(() => titledTasks.some((r) => !r.ended), [titledTasks]), hasErrors = useMemo(
1443
+ () => titledTasks.some((r) => r.reason === "error" || r.reason === "timeout"),
1444
+ [titledTasks]
1445
+ ), [open, setOpen] = useState(!1), toggleOpen = useCallback(() => setOpen((v) => !v), []), [button, setButton] = useState(null), [popover, setPopover] = useState(null), handleClickOutside = useCallback(() => {
1446
+ setOpen(!1);
1447
+ }, []);
1448
+ useClickOutside(handleClickOutside, [button, popover]);
1449
+ const handleEscape = useCallback(() => {
1450
+ setOpen(!1), button == null || button.focus();
1451
+ }, [button]);
1452
+ return /* @__PURE__ */ jsx(
1453
+ Popover,
1454
+ {
1455
+ constrainSize: !0,
1456
+ content: /* @__PURE__ */ jsx(TaskList, { onEscape: handleEscape, tasks: titledTasks }),
1457
+ open: open && !!(titledTasks != null && titledTasks.length),
1458
+ placement: "top",
1459
+ portal: !0,
1460
+ ref: setPopover,
1461
+ width: 0,
1462
+ children: /* @__PURE__ */ jsx(
1463
+ TaskStatusButton,
1464
+ {
1465
+ disabled: !(titledTasks != null && titledTasks.length),
1466
+ hasErrors,
1467
+ isRunning,
1468
+ onClick: toggleOpen,
1469
+ ref: setButton,
1470
+ selected: open
1471
+ }
1472
+ )
1473
+ }
1474
+ );
1475
+ }
1476
+ const TASK_STATUS_BUTTON_TOOLTIP_PROPS = {
1477
+ placement: "top"
1478
+ }, TaskStatusButton = forwardRef(function(props, ref) {
1479
+ const { disabled, hasErrors, isRunning, onClick, selected } = props;
1480
+ return /* @__PURE__ */ jsx(
1481
+ StatusButton,
1482
+ {
1483
+ label: `${pluginTitle} status`,
1484
+ icon: isRunning ? SyncSpinningIcon : hasErrors ? ErrorOutlineIcon : CheckmarkCircleIcon,
1485
+ mode: "bleed",
1486
+ onClick,
1487
+ tone: hasErrors ? "critical" : void 0,
1488
+ disabled,
1489
+ ref,
1490
+ selected,
1491
+ tooltipProps: TASK_STATUS_BUTTON_TOOLTIP_PROPS
1492
+ }
1493
+ );
1494
+ });
1495
+ function TaskList(props) {
1496
+ const { onEscape, tasks } = props, { isTopLayer } = useLayer();
1497
+ return useGlobalKeyDown(
1498
+ useCallback(
1499
+ (event) => {
1500
+ isTopLayer && event.key === "Escape" && onEscape();
1501
+ },
1502
+ [isTopLayer, onEscape]
1503
+ )
1504
+ ), /* @__PURE__ */ jsx(Stack, { padding: 1, space: 1, children: tasks.map((task) => /* @__PURE__ */ jsx(TaskItem, { task }, task._key)) });
1505
+ }
1506
+ function TaskItem(props) {
1507
+ var _a;
1508
+ const { task } = props, taskType = task.reason && TASK_CONFIG[task.reason];
1509
+ return /* @__PURE__ */ jsx(Card, { radius: 2, tone: taskType && (taskType == null ? void 0 : taskType.tone), children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 1, children: [
1510
+ /* @__PURE__ */ jsxs(Flex, { align: "flex-start", flex: 1, gap: 3, padding: 3, children: [
1511
+ /* @__PURE__ */ jsx(Box, { flex: "none", children: /* @__PURE__ */ jsxs(Text, { size: 1, children: [
1512
+ taskType && createElement(taskType.icon),
1513
+ !task.reason && /* @__PURE__ */ jsx(Spinner, {})
1514
+ ] }) }),
1515
+ /* @__PURE__ */ jsxs(Stack, { flex: 1, space: 2, children: [
1516
+ /* @__PURE__ */ jsxs(Text, { size: 1, weight: "medium", children: [
1517
+ taskType ? taskType.title : "Running",
1518
+ task.title && /* @__PURE__ */ jsxs(Fragment, { children: [
1519
+ ": ",
1520
+ task.title
1521
+ ] })
1522
+ ] }),
1523
+ task.message ? /* @__PURE__ */ jsx(Text, { size: 1, children: task.message }) : null,
1524
+ /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, children: /* @__PURE__ */ jsx(TimeAgo, { date: (_a = task.ended) != null ? _a : task.started }) })
1525
+ ] })
1526
+ ] }),
1527
+ !task.ended && /* @__PURE__ */ jsx(Box, { flex: "none", padding: 1, children: /* @__PURE__ */ jsx(Button, { fontSize: 1, mode: "bleed", onClick: task.cancel, text: "Cancel" }) })
1528
+ ] }) });
1529
+ }
1530
+ const CardWithShadowBelow = styled(Card)`
1531
+ position: relative;
1532
+
1533
+ &:after {
1534
+ content: '';
1535
+ display: block;
1536
+ position: absolute;
1537
+ left: 0;
1538
+ right: 0;
1539
+ bottom: -1px;
1540
+ border-bottom: 1px solid var(--card-border-color);
1541
+ opacity: 0.5;
1542
+ z-index: 100;
1543
+ }
1544
+ `, CardWithShadowAbove = styled(Card)`
1545
+ position: relative;
1546
+
1547
+ &:after {
1548
+ content: '';
1549
+ display: block;
1550
+ position: absolute;
1551
+ left: 0;
1552
+ right: 0;
1553
+ top: -1px;
1554
+ border-top: 1px solid var(--card-border-color);
1555
+ opacity: 0.5;
1556
+ z-index: 100;
1557
+ }
1558
+ `;
1559
+ function AssistInspectorWrapper(props) {
1560
+ const context = useAiAssistanceConfig();
1561
+ if (context.statusLoading)
1562
+ return /* @__PURE__ */ jsx(Flex, { align: "center", height: "fill", justify: "center", padding: 4, sizing: "border", children: /* @__PURE__ */ jsxs(Stack, { space: 3, style: { textAlign: "center" }, children: [
1563
+ /* @__PURE__ */ jsx(Spinner, { muted: !0 }),
1564
+ /* @__PURE__ */ jsxs(Text, { muted: !0, size: 1, children: [
1565
+ "Loading ",
1566
+ pluginTitle,
1567
+ "..."
1568
+ ] })
1569
+ ] }) });
1570
+ const status = context.status;
1571
+ return status != null && status.enabled ? !(status != null && status.initialized) || !status.validToken ? /* @__PURE__ */ jsxs(Flex, { direction: "column", height: "fill", children: [
1572
+ /* @__PURE__ */ jsx(
1573
+ DocumentInspectorHeader,
1574
+ {
1575
+ closeButtonLabel: "Close",
1576
+ onClose: props.onClose,
1577
+ title: pluginTitle
1578
+ }
1579
+ ),
1580
+ /* @__PURE__ */ jsxs(Stack, { padding: 4, space: 3, children: [
1581
+ context.error ? /* @__PURE__ */ jsxs(Text, { size: 1, weight: "semibold", children: [
1582
+ "Failed to start ",
1583
+ pluginTitle
1584
+ ] }) : null,
1585
+ !context.error && !(status != null && status.initialized) ? /* @__PURE__ */ jsxs(Text, { size: 1, weight: "semibold", children: [
1586
+ pluginTitle,
1587
+ " is not enabled"
1588
+ ] }) : null,
1589
+ !context.error && status != null && status.initialized && !status.validToken ? /* @__PURE__ */ jsxs(Fragment, { children: [
1590
+ /* @__PURE__ */ jsx(Text, { size: 1, weight: "semibold", children: "Invalid token" }),
1591
+ /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, children: "The token used by the AI Assistant is not valid and has to be regenerated." })
1592
+ ] }) : null,
1593
+ context.error && /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, children: "Something went wrong. See console for details." }),
1594
+ !context.error && !(status != null && status.initialized) && /* @__PURE__ */ jsxs(Text, { size: 1, muted: !0, children: [
1595
+ "Please enable ",
1596
+ pluginTitle,
1597
+ "."
1598
+ ] }),
1599
+ /* @__PURE__ */ jsx(
1600
+ Button,
1601
+ {
1602
+ fontSize: 1,
1603
+ icon: context.initLoading ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Spinner, {}) }) : context.error ? RetryIcon : void 0,
1604
+ text: context.error ? "Retry" : status != null && status.initialized && !status.validToken ? `Restore ${pluginTitle}` : `Enable ${pluginTitle} now`,
1605
+ tone: "primary",
1606
+ onClick: context.init,
1607
+ disabled: context.initLoading
1608
+ }
1609
+ )
1610
+ ] })
1611
+ ] }) : /* @__PURE__ */ jsx(AssistInspector, { ...props }) : /* @__PURE__ */ jsxs(Flex, { direction: "column", height: "fill", children: [
1612
+ /* @__PURE__ */ jsx(
1613
+ DocumentInspectorHeader,
1614
+ {
1615
+ closeButtonLabel: "Close",
1616
+ onClose: props.onClose,
1617
+ title: pluginTitle
1618
+ }
1619
+ ),
1620
+ /* @__PURE__ */ jsxs(Stack, { flex: 1, overflow: "auto", padding: 4, space: 3, children: [
1621
+ /* @__PURE__ */ jsxs(Text, { as: "p", size: 1, weight: "semibold", children: [
1622
+ pluginTitle,
1623
+ " is not available"
1624
+ ] }),
1625
+ /* @__PURE__ */ jsxs(Text, { as: "p", muted: !0, size: 1, children: [
1626
+ "Please get in touch with a Sanity account manager or",
1627
+ " ",
1628
+ /* @__PURE__ */ jsx("a", { href: salesUrl, target: "_blank", rel: "noreferrer", children: "contact our sales team" }),
1629
+ " ",
1630
+ "to get started with ",
1631
+ pluginTitle,
1632
+ ".",
1633
+ " ",
1634
+ /* @__PURE__ */ jsx("a", { href: releaseAnnouncementUrl, target: "_blank", rel: "noreferrer", children: "Learn more \u2192" })
1635
+ ] })
1636
+ ] })
1637
+ ] });
1638
+ }
1639
+ function AssistInspector(props) {
1640
+ var _a, _b;
1641
+ const { params } = useAiPaneRouter(), boundary = useRef(null), pathKey = params == null ? void 0 : params[fieldPathParam], instructionKey = params == null ? void 0 : params[instructionParam], documentPane = useDocumentPane(), {
1642
+ documentId,
1643
+ documentType,
1644
+ value: docValue,
1645
+ schemaType,
1646
+ onChange: documentOnChange,
1647
+ formState
1648
+ } = documentPane, { published, draft } = useEditState(documentId, documentType, "low"), formStateRef = useRef(formState);
1649
+ formStateRef.current = formState;
1650
+ const assistableDocId = getAssistableDocId(schemaType, documentId), { instructionLoading, requestRunInstruction } = useRequestRunInstruction({
1651
+ documentOnChange,
1652
+ isDocAssistable: isDocAssistable(schemaType, published, draft)
1653
+ }), typePath = useTypePath(docValue, pathKey != null ? pathKey : ""), selectedField = useSelectedField(schemaType, typePath), aiDocId = assistDocumentId(documentType), assistDocument = useStudioAssistDocument({ documentId, schemaType, initDoc: !0 }), assistField = (_a = assistDocument == null ? void 0 : assistDocument.fields) == null ? void 0 : _a.find((f) => f.path === typePath), instruction2 = (_b = assistField == null ? void 0 : assistField.instructions) == null ? void 0 : _b.find((i) => i._key === instructionKey), tasks = useMemo(
1654
+ () => {
1655
+ var _a2;
1656
+ return (_a2 = assistDocument == null ? void 0 : assistDocument.tasks) == null ? void 0 : _a2.filter((i) => !instructionKey || i.instructionKey === instructionKey);
1657
+ },
1658
+ [assistDocument == null ? void 0 : assistDocument.tasks, instructionKey]
1659
+ ), instructions = useMemo(
1660
+ () => {
1661
+ var _a2;
1662
+ return (_a2 = assistDocument == null ? void 0 : assistDocument.fields) == null ? void 0 : _a2.flatMap((f) => {
1663
+ var _a3;
1664
+ return (_a3 = f.instructions) != null ? _a3 : [];
1665
+ });
1666
+ },
1667
+ [assistDocument == null ? void 0 : assistDocument.fields]
1668
+ ), promptValue = instruction2 == null ? void 0 : instruction2.prompt, isEmptyPrompt = useMemo(() => {
1669
+ var _a2, _b2;
1670
+ if (!(promptValue != null && promptValue.length))
1671
+ return !0;
1672
+ const firstBlock = promptValue[0], children = firstBlock == null ? void 0 : firstBlock.children;
1673
+ return promptValue.length == 1 && (children == null ? void 0 : children.length) === 1 && !((_b2 = (_a2 = children == null ? void 0 : children[0]) == null ? void 0 : _a2.text) != null && _b2.length);
1674
+ }, [promptValue]), paneNode = useMemo(
1675
+ () => ({
1676
+ type: "document",
1677
+ id: aiDocId,
1678
+ title: pluginTitle,
1679
+ options: {
1680
+ id: aiDocId,
1681
+ type: assistDocumentTypeName
1682
+ }
1683
+ }),
1684
+ [aiDocId]
1685
+ ), runCurrentInstruction = useCallback(
1686
+ () => instruction2 && pathKey && typePath && requestRunInstruction({
1687
+ documentId: assistableDocId,
1688
+ path: pathKey,
1689
+ typePath,
1690
+ assistDocumentId: assistDocumentId(documentType),
1691
+ instruction: instruction2,
1692
+ conditionalMembers: formStateRef.current ? getConditionalMembers(formStateRef.current) : []
1693
+ }),
1694
+ [pathKey, instruction2, typePath, documentType, assistableDocId, requestRunInstruction]
1695
+ ), Region = useCallback((_props) => /* @__PURE__ */ jsx("div", { ..._props, style: { height: "100%", flex: 1, overflow: "auto" } }), []);
1696
+ return !documentId || !schemaType || schemaType.jsonType !== "object" ? /* @__PURE__ */ jsx(Card, { flex: 1, padding: 4, children: /* @__PURE__ */ jsx(Text, { children: "Document not ready yet." }) }) : /* @__PURE__ */ jsxs(
1697
+ Flex,
1698
+ {
1699
+ ref: boundary,
1700
+ direction: "column",
1701
+ height: "fill",
1702
+ overflow: "hidden",
1703
+ sizing: "border",
1704
+ style: { lineHeight: 0 },
1705
+ children: [
1706
+ /* @__PURE__ */ jsx(
1707
+ AiInspectorHeader,
1708
+ {
1709
+ onClose: props.onClose,
1710
+ field: selectedField,
1711
+ fieldTitle: getFieldTitle(selectedField)
1712
+ }
1713
+ ),
1714
+ /* @__PURE__ */ jsx(Card, { as: Region, flex: 1, overflow: "auto", children: /* @__PURE__ */ jsxs(Flex, { direction: "column", style: { minHeight: "100%" }, children: [
1715
+ /* @__PURE__ */ jsx(Box, { flex: 1, children: /* @__PURE__ */ jsx(PresenceOverlay, { children: /* @__PURE__ */ jsx(Box, { padding: 4, children: selectedField && /* @__PURE__ */ jsx(TypePathContext.Provider, { value: typePath, children: /* @__PURE__ */ jsx(
1716
+ VirtualizerScrollInstanceProvider,
1717
+ {
1718
+ scrollElement: boundary.current,
1719
+ containerElement: boundary,
1720
+ children: /* @__PURE__ */ jsx(
1721
+ DocumentPaneProvider,
1722
+ {
1723
+ paneKey: documentPane.paneKey,
1724
+ index: documentPane.index,
1725
+ itemId: "ai",
1726
+ pane: paneNode,
1727
+ children: /* @__PURE__ */ jsx(DocumentForm, {})
1728
+ }
1729
+ )
1730
+ }
1731
+ ) }) }) }) }),
1732
+ /* @__PURE__ */ jsx(Box, { flex: "none", padding: 4, children: /* @__PURE__ */ jsxs(Text, { muted: !0, size: 1, children: [
1733
+ "How is Sanity AI Assist working for you?",
1734
+ " ",
1735
+ /* @__PURE__ */ jsxs(
1736
+ "a",
1737
+ {
1738
+ href: giveFeedbackUrl,
1739
+ target: "_blank",
1740
+ rel: "noreferrer",
1741
+ style: { whiteSpace: "nowrap" },
1742
+ children: [
1743
+ "Let us know ",
1744
+ /* @__PURE__ */ jsx(ArrowRightIcon, {})
1745
+ ]
1746
+ }
1747
+ )
1748
+ ] }) })
1749
+ ] }) }),
1750
+ /* @__PURE__ */ jsx(CardWithShadowAbove, { flex: "none", paddingX: 4, paddingY: 3, style: { justifySelf: "flex-end" }, children: /* @__PURE__ */ jsxs(Flex, { gap: 2, flex: 1, justify: "flex-end", children: [
1751
+ (schemaType == null ? void 0 : schemaType.name) && pathKey && instructionKey && /* @__PURE__ */ jsx(Stack, { flex: 1, children: /* @__PURE__ */ jsx(
1752
+ Button,
1753
+ {
1754
+ mode: "ghost",
1755
+ disabled: isEmptyPrompt || instructionLoading,
1756
+ fontSize: 1,
1757
+ icon: instructionLoading ? /* @__PURE__ */ jsx(Spinner, {}) : PlayIcon,
1758
+ onClick: runCurrentInstruction,
1759
+ padding: 3,
1760
+ text: "Run instruction"
1761
+ }
1762
+ ) }),
1763
+ /* @__PURE__ */ jsx(
1764
+ InstructionTaskHistoryButton,
1765
+ {
1766
+ documentId: assistableDocId,
1767
+ tasks,
1768
+ instructions,
1769
+ showTitles: !instructionKey
1770
+ }
1771
+ )
1772
+ ] }) })
1773
+ ]
1774
+ }
1775
+ );
1776
+ }
1777
+ function AiInspectorHeader(props) {
1778
+ const { onClose, field, fieldTitle } = props, { showOnboarding, dismissOnboarding } = useOnboardingFeature(inspectorOnboardingKey);
1779
+ return /* @__PURE__ */ jsxs(CardWithShadowBelow, { flex: "none", padding: 2, children: [
1780
+ /* @__PURE__ */ jsxs(Flex, { flex: 1, align: "center", children: [
1781
+ /* @__PURE__ */ jsx(Flex, { flex: 1, padding: 3, gap: 2, align: "center", children: /* @__PURE__ */ jsxs(Flex, { gap: 1, align: "center", wrap: "wrap", style: { marginTop: "-4px" }, children: [
1782
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { size: 1, weight: "semibold", children: "AI instructions for" }) }),
1783
+ /* @__PURE__ */ jsx(Card, { radius: 2, border: !0, padding: 1, marginTop: 1, children: field ? /* @__PURE__ */ jsx(FieldTitle, { field }) : /* @__PURE__ */ jsx(Text, { size: 1, weight: "semibold", children: fieldTitle }) })
1784
+ ] }) }),
1785
+ /* @__PURE__ */ jsx(Box, { flex: "none", children: /* @__PURE__ */ jsx(Button, { fontSize: 1, icon: CloseIcon, mode: "bleed", onClick: onClose }) })
1786
+ ] }),
1787
+ showOnboarding && /* @__PURE__ */ jsx(InspectorOnboarding, { onDismiss: dismissOnboarding })
1788
+ ] });
1789
+ }
1790
+ const assistInspector = {
1791
+ name: aiInspectorId,
1792
+ useMenuItem: () => ({
1793
+ icon: SparklesIcon,
1794
+ title: pluginTitle,
1795
+ hidden: !0,
1796
+ showAsAction: !1
1797
+ }),
1798
+ component: AssistInspectorWrapper,
1799
+ onClose({ params }) {
1800
+ return {
1801
+ params: typed({
1802
+ ...params,
1803
+ [fieldPathParam]: void 0,
1804
+ [instructionParam]: void 0
1805
+ })
1806
+ };
1807
+ }
1808
+ };
1809
+ function AssistFeatureBadge() {
1810
+ return /* @__PURE__ */ jsx(Badge, { fontSize: 0, style: { margin: "-2px 0" }, tone: "primary", children: "Beta" });
1811
+ }
1812
+ function AssistOnboardingPopover(props) {
1813
+ const { dismiss } = props;
1814
+ return /* @__PURE__ */ jsx(
1815
+ Popover,
1816
+ {
1817
+ content: /* @__PURE__ */ jsx(AssistIntroCard, { dismiss }),
1818
+ open: !0,
1819
+ portal: !0,
1820
+ placeholder: "bottom",
1821
+ tone: "default",
1822
+ width: 0,
1823
+ children: /* @__PURE__ */ jsx(Card, { radius: 2, shadow: 2, style: { padding: 2, lineHeight: 0 }, children: /* @__PURE__ */ jsx(Button, { disabled: !0, fontSize: 1, icon: SparklesIcon, mode: "bleed", padding: 2 }) })
1824
+ }
1825
+ );
1826
+ }
1827
+ function AssistIntroCard(props) {
1828
+ const buttonRef = useRef(null);
1829
+ return /* @__PURE__ */ jsxs(Stack, { as: "section", padding: 3, space: 3, children: [
1830
+ /* @__PURE__ */ jsxs(Stack, { padding: 2, space: 4, children: [
1831
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, align: "center", children: [
1832
+ /* @__PURE__ */ jsx(Text, { as: "h1", size: 1, weight: "semibold", children: pluginTitle }),
1833
+ /* @__PURE__ */ jsx("div", { "aria-hidden": !0, style: { margin: "-3px 0", lineHeight: 0 }, children: /* @__PURE__ */ jsx(AssistFeatureBadge, {}) })
1834
+ ] }),
1835
+ /* @__PURE__ */ jsx(Stack, { space: 3, children: /* @__PURE__ */ jsxs(Text, { as: "p", muted: !0, size: 1, children: [
1836
+ "Manage reusable AI instructions to boost your content creation and reduce amount of repetitive chores.",
1837
+ " ",
1838
+ /* @__PURE__ */ jsxs("a", { href: releaseAnnouncementUrl, target: "_blank", rel: "noreferrer", children: [
1839
+ "Learn more ",
1840
+ /* @__PURE__ */ jsx(ArrowRightIcon, {})
1841
+ ] })
1842
+ ] }) })
1843
+ ] }),
1844
+ /* @__PURE__ */ jsx(
1845
+ Button,
1846
+ {
1847
+ fontSize: 1,
1848
+ icon: CheckmarkIcon,
1849
+ onClick: props.dismiss,
1850
+ padding: 3,
1851
+ ref: buttonRef,
1852
+ text: "Ok, good to know!",
1853
+ tone: "primary"
1854
+ }
1855
+ )
1856
+ ] });
1857
+ }
1858
+ const FirstAssistedPathContext = createContext(void 0);
1859
+ function FirstAssistedPathProvider(props) {
1860
+ const { members } = props, firstAssistedPath = useMemo(() => {
1861
+ const firstAssisted = members.find(
1862
+ (member) => member.kind === "field" && isAssistSupported(member.field.schemaType)
1863
+ );
1864
+ return firstAssisted != null && firstAssisted.field.path ? pathToString(firstAssisted == null ? void 0 : firstAssisted.field.path) : void 0;
1865
+ }, [members]);
1866
+ return /* @__PURE__ */ jsx(FirstAssistedPathContext.Provider, { value: firstAssistedPath, children: props.children });
1867
+ }
1868
+ const fadeIn = keyframes`
1869
+ 0% {
1870
+ opacity: 0;
1871
+ transform: scale(0.75);
1872
+ }
1873
+ 40% {
1874
+ opacity: 0;
1875
+ transform: scale(0.75);
1876
+ }
1877
+ 100% {
1878
+ opacity: 1;
1879
+ transform: scale(1);
1880
+ }
1881
+ `, FadeInDiv = styled.div`
1882
+ animation-name: ${fadeIn};
1883
+ animation-timing-function: ease-in-out;
1884
+ `, FadeInContent = forwardRef(function({
1885
+ children,
1886
+ durationMs = 250
1887
+ }, ref) {
1888
+ return /* @__PURE__ */ jsx(FadeInDiv, { ref, style: { animationDuration: `${durationMs}ms` }, children });
1889
+ }), purple = {
1890
+ 50: {
1891
+ title: "Purple 50",
1892
+ hex: "#f8f5ff"
1893
+ },
1894
+ 100: {
1895
+ title: "Purple 100",
1896
+ hex: "#f1ebff"
1897
+ },
1898
+ 200: {
1899
+ title: "Purple 200",
1900
+ hex: "#ece1fe"
1901
+ },
1902
+ 300: {
1903
+ title: "Purple 300",
1904
+ hex: "#ccb1fc"
1905
+ },
1906
+ 400: {
1907
+ title: "Purple 400",
1908
+ hex: "#b087f7"
1909
+ },
1910
+ 500: {
1911
+ title: "Purple 500",
1912
+ hex: "#8f57ef"
1913
+ },
1914
+ 600: {
1915
+ title: "Purple 600",
1916
+ hex: "#721fe5"
1917
+ },
1918
+ 700: {
1919
+ title: "Purple 700",
1920
+ hex: "#4c1a9e"
1921
+ },
1922
+ 800: {
1923
+ title: "Purple 800",
1924
+ hex: "#2f1862"
1925
+ },
1926
+ 900: {
1927
+ title: "Purple 900",
1928
+ hex: "#23173f"
1929
+ },
1930
+ 950: {
1931
+ title: "Purple 950",
1932
+ hex: "#181128"
1933
+ }
1934
+ }, Root = styled.span`
1935
+ display: block;
1936
+ width: 25px;
1937
+ height: 25px;
1938
+ position: relative;
1939
+ `, dash = keyframes`
1940
+ 0% {
1941
+ transform: rotate(0);
1942
+ }
1943
+ 100% {
1944
+ transform: rotate(43deg);
1945
+ }
1946
+ `, Outline = styled.svg`
1947
+ display: block;
1948
+ position: absolute;
1949
+ top: 0;
1950
+ left: 0;
1951
+
1952
+ & > circle {
1953
+ stroke: var(--ai-avatar-stroke-color);
1954
+ stroke-width: 1.5px;
1955
+ stroke-linecap: round;
1956
+ transform-origin: center;
1957
+ animation: ${dash} 500ms ease-in-out infinite;
1958
+ transition: stroke-dasharray 200ms ease-in-out;
1959
+
1960
+ stroke-dasharray: 2.34px 0;
1961
+
1962
+ [data-state='active'] > & {
1963
+ stroke-dasharray: 2px 2.34px;
1964
+ }
1965
+ }
1966
+ `, IconDisc = styled.span`
1967
+ background: var(--ai-avatar-disc-color);
1968
+ color: white;
1969
+ width: 21px;
1970
+ height: 21px;
1971
+ display: flex;
1972
+ align-items: center;
1973
+ justify-content: center;
1974
+ border-radius: 10.5px;
1975
+ position: absolute;
1976
+ top: 2px;
1977
+ left: 2px;
1978
+ `;
1979
+ function AssistAvatar(props) {
1980
+ const { state = "present" } = props, scheme = useColorSchemeValue(), style = useMemo(() => scheme === "dark" ? {
1981
+ "--ai-avatar-stroke-color": purple[400].hex,
1982
+ "--ai-avatar-disc-color": purple[600].hex
1983
+ } : {
1984
+ "--ai-avatar-stroke-color": purple[500].hex,
1985
+ "--ai-avatar-disc-color": purple[600].hex
1986
+ }, [scheme]);
1987
+ return /* @__PURE__ */ jsxs(Root, { "data-state": state, style, children: [
1988
+ /* @__PURE__ */ jsx(
1989
+ Outline,
1990
+ {
1991
+ width: "25",
1992
+ height: "25",
1993
+ viewBox: "0 0 25 25",
1994
+ fill: "none",
1995
+ xmlns: "http://www.w3.org/2000/svg",
1996
+ children: /* @__PURE__ */ jsx("circle", { cx: "12.5", cy: "12.5", r: "11.75" })
1997
+ }
1998
+ ),
1999
+ /* @__PURE__ */ jsx(IconDisc, { children: /* @__PURE__ */ jsx(Text, { as: "span", size: 0, style: { color: "inherit" }, children: /* @__PURE__ */ jsx(SparklesIcon, { style: { color: "inherit" } }) }) })
2000
+ ] });
2001
+ }
2002
+ function AiFieldPresence(props) {
2003
+ return /* @__PURE__ */ jsx(Card, { style: { position: "relative", background: "transparent" }, contentEditable: !1, children: /* @__PURE__ */ jsx(
2004
+ Tooltip,
2005
+ {
2006
+ placement: "left",
2007
+ content: /* @__PURE__ */ jsx(Card, { padding: 3, border: !0, children: /* @__PURE__ */ jsx(Flex, { align: "center", children: /* @__PURE__ */ jsx(Text, { size: 1, children: "Running instruction..." }) }) }),
2008
+ children: /* @__PURE__ */ jsx(FadeInContent, { durationMs: 300, children: /* @__PURE__ */ jsx(AssistAvatar, { state: "active" }) })
2009
+ }
2010
+ ) });
2011
+ }
2012
+ const AssistDocumentContext = createContext(
2013
+ void 0
2014
+ );
2015
+ function useAssistDocumentContext() {
2016
+ const context = useContext(AssistDocumentContext);
2017
+ if (!context)
2018
+ throw new Error("AssistDocumentContext value is missing");
2019
+ return context;
2020
+ }
2021
+ const NO_PRESENCE = [];
2022
+ function useAssistPresence(path, showFocusWithin) {
2023
+ const context = useAssistDocumentContext(), assistDocument = context && "assistDocument" in context ? context.assistDocument : void 0, tasks = assistDocument == null ? void 0 : assistDocument.tasks;
2024
+ return useMemo(() => {
2025
+ var _a, _b;
2026
+ const activePresence = (_b = (_a = tasks == null ? void 0 : tasks.filter((task) => !task.ended)) == null ? void 0 : _a.flatMap((task) => {
2027
+ var _a2;
2028
+ return (_a2 = task.presence) != null ? _a2 : [];
2029
+ })) == null ? void 0 : _b.filter(
2030
+ (p) => p.started && (/* @__PURE__ */ new Date()).getTime() - new Date(p.started).getTime() < maxHistoryVisibilityMs
2031
+ ).filter((presence) => {
2032
+ if (!presence.path || !path.length)
2033
+ return !1;
2034
+ const statusPath = stringToPath(presence.path);
2035
+ return !showFocusWithin && statusPath.length !== path.length ? !1 : path.every((pathSegment, i) => {
2036
+ const statusSegment = statusPath[i];
2037
+ return typeof pathSegment == "string" ? pathSegment === statusSegment : isKeySegment(pathSegment) && isKeySegment(statusSegment) ? pathSegment._key === statusSegment._key : !1;
2038
+ });
2039
+ });
2040
+ return activePresence != null && activePresence.length ? activePresence.map((status) => aiPresence(status, path)) : NO_PRESENCE;
2041
+ }, [showFocusWithin, tasks, path]);
2042
+ }
2043
+ function aiPresence(presence, path, title) {
2044
+ var _a;
2045
+ return {
2046
+ user: {
2047
+ id: `sanity-assistant_${presence._key}`,
2048
+ displayName: pluginTitle
2049
+ },
2050
+ path,
2051
+ sessionId: "not-available",
2052
+ lastActiveAt: (_a = presence == null ? void 0 : presence.started) != null ? _a : (/* @__PURE__ */ new Date()).toISOString()
2053
+ };
2054
+ }
2055
+ function AssistFieldWrapper(props) {
2056
+ const { schemaType } = props;
2057
+ return !useMemo(() => isAssistSupported(schemaType), [schemaType]) || schemaType.name.startsWith("sanity.") || schemaType.name === contextDocumentTypeName ? props.renderDefault(props) : !isType(props.schemaType, "document") && props.inputId !== "root" && props.inputId !== assistFormId ? /* @__PURE__ */ jsx(AssistField, { ...props, children: props.children }) : props.renderDefault(props);
2058
+ }
2059
+ function AssistField(props) {
2060
+ const { path } = props, isPortableText = useMemo(
2061
+ () => !!(isArraySchemaType(props.schemaType) && isPortableTextArray(props.schemaType)),
2062
+ [props.schemaType]
2063
+ ), presence = useAssistPresence(props.path, isPortableText), firstAssistedPath = useContext(FirstAssistedPathContext), isFirstAssisted = useMemo(
2064
+ () => pathToString(path) === firstAssistedPath,
2065
+ [path, firstAssistedPath]
2066
+ ), { showOnboarding, dismissOnboarding } = useOnboardingFeature(fieldOnboardingKey), singlePresence = presence[0], actions = /* @__PURE__ */ jsxs(Flex, { gap: 2, align: "center", justify: "space-between", children: [
2067
+ singlePresence && /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(AiFieldPresence, { presence: singlePresence }) }),
2068
+ isFirstAssisted && showOnboarding && /* @__PURE__ */ jsx(AssistOnboardingPopover, { dismiss: dismissOnboarding })
2069
+ ] });
2070
+ return props.renderDefault({
2071
+ ...props,
2072
+ // When showing the onboarding, prevent default field actions from being rendered
2073
+ actions: isFirstAssisted && showOnboarding ? [] : props.actions,
2074
+ // Render presence (and possibly onboarding) in the internal slot (between presence and the field actions)
2075
+ // eslint-disable-next-line camelcase
2076
+ __internal_slot: actions
2077
+ });
2078
+ }
2079
+ function hasOverflowScroll(el) {
2080
+ const overflow = getComputedStyle(el).overflow;
2081
+ return overflow.includes("auto") || overflow.includes("hidden") || overflow.includes("scroll");
2082
+ }
2083
+ function useRegionRects() {
2084
+ const ref = useRef(null), [relativeBoundsRect, setRelativeBoundsRect] = useState(null), [relativeElementRect, setRelativeElementRect] = useState(null), [boundsScroll, setBoundsScroll] = useState({ x: 0, y: 0 }), [scroll, setScroll] = useState({ x: 0, y: 0 }), boundsScrollXRef = useRef(0), boundsScrollYRef = useRef(0), elementScrollXRef = useRef(0), elementScrollYRef = useRef(0);
2085
+ useEffect(() => {
2086
+ const el = ref.current;
2087
+ if (!el)
2088
+ return;
2089
+ const scrollParents = [];
2090
+ let parent = el.parentElement;
2091
+ for (; parent && parent !== document.body; )
2092
+ hasOverflowScroll(parent) && scrollParents.push(parent), parent = parent.parentElement;
2093
+ function handleResize() {
2094
+ const scrollParent = scrollParents[0], boundsRect = (scrollParent == null ? void 0 : scrollParent.getBoundingClientRect()) || {
2095
+ x: 0,
2096
+ y: 0,
2097
+ width: window.innerWidth,
2098
+ height: window.innerHeight
2099
+ }, domRect = el.getBoundingClientRect();
2100
+ setRelativeBoundsRect({
2101
+ x: boundsRect.x + boundsScrollXRef.current,
2102
+ y: boundsRect.y + boundsScrollYRef.current,
2103
+ w: boundsRect.width,
2104
+ h: boundsRect.height
2105
+ }), setRelativeElementRect({
2106
+ x: domRect.x + elementScrollXRef.current,
2107
+ y: domRect.y + elementScrollYRef.current,
2108
+ w: domRect.width,
2109
+ h: domRect.height
2110
+ });
2111
+ }
2112
+ function handleScroll() {
2113
+ let scrollX = window.scrollX, scrollY = window.scrollY;
2114
+ for (const scrollParent2 of scrollParents)
2115
+ scrollX += scrollParent2.scrollLeft, scrollY += scrollParent2.scrollTop;
2116
+ const scrollParent = scrollParents[0];
2117
+ boundsScrollXRef.current = scrollX - ((scrollParent == null ? void 0 : scrollParent.scrollLeft) || window.scrollX), boundsScrollYRef.current = scrollY - ((scrollParent == null ? void 0 : scrollParent.scrollTop) || window.scrollY), setBoundsScroll({
2118
+ x: boundsScrollXRef.current,
2119
+ y: boundsScrollYRef.current
2120
+ }), elementScrollXRef.current = scrollX, elementScrollYRef.current = scrollY, setScroll({ x: scrollX, y: scrollY });
2121
+ }
2122
+ window.addEventListener("scroll", handleScroll, { passive: !0 });
2123
+ const ro = new ResizeObserver(handleResize);
2124
+ ro.observe(el);
2125
+ for (const scrollParent of scrollParents)
2126
+ scrollParent.addEventListener("scroll", handleScroll, { passive: !0 }), ro.observe(scrollParent);
2127
+ return handleScroll(), () => {
2128
+ ro.unobserve(el);
2129
+ for (const scrollParent of scrollParents)
2130
+ ro.unobserve(scrollParent), scrollParent.removeEventListener("scroll", handleScroll);
2131
+ ro.disconnect(), window.removeEventListener("scroll", handleScroll);
2132
+ };
2133
+ }, []);
2134
+ const bounds = useMemo(
2135
+ () => relativeBoundsRect && {
2136
+ x: relativeBoundsRect.x - boundsScroll.x,
2137
+ y: relativeBoundsRect.y - boundsScroll.y,
2138
+ w: relativeBoundsRect.w,
2139
+ h: relativeBoundsRect.h
2140
+ },
2141
+ [relativeBoundsRect, boundsScroll]
2142
+ ), element = useMemo(
2143
+ () => relativeElementRect && {
2144
+ x: relativeElementRect.x - scroll.x,
2145
+ y: relativeElementRect.y - scroll.y,
2146
+ w: relativeElementRect.w,
2147
+ h: relativeElementRect.h
2148
+ },
2149
+ [relativeElementRect, scroll]
2150
+ );
2151
+ return { bounds, element, ref };
2152
+ }
2153
+ function ConnectorRegion(props) {
2154
+ const { children, onRectsChange, ...restProps } = props, { bounds, element, ref } = useRegionRects();
2155
+ return useEffect(() => {
2156
+ onRectsChange == null || onRectsChange(bounds && element ? { bounds, element } : null);
2157
+ }, [bounds, element, onRectsChange]), /* @__PURE__ */ jsx("div", { ...restProps, ref, children });
2158
+ }
2159
+ const ConnectorsStoreContext = createContext(null);
2160
+ function useConnectorsStore() {
2161
+ const store = useContext(ConnectorsStoreContext);
2162
+ if (!store)
2163
+ throw new Error("Missing connectors store context");
2164
+ return store;
2165
+ }
2166
+ function ConnectFromRegion(props) {
2167
+ const { children, _key: key, zIndex, ...restProps } = props, store = useConnectorsStore(), [rects, setRects] = useState(null);
2168
+ return useEffect(() => store.from.subscribe(key, { zIndex }), [key, store, zIndex]), useEffect(() => {
2169
+ rects && store.from.next(key, rects);
2170
+ }, [key, rects, store]), /* @__PURE__ */ jsx(ConnectorRegion, { ...restProps, onRectsChange: setRects, children });
2171
+ }
2172
+ function createConnectorsStore() {
2173
+ const configKeys = [], fieldKeys = [], channels = {
2174
+ from: /* @__PURE__ */ new Map(),
2175
+ to: /* @__PURE__ */ new Map()
2176
+ }, payloads = {
2177
+ from: /* @__PURE__ */ new Map(),
2178
+ to: /* @__PURE__ */ new Map()
2179
+ }, observers = [];
2180
+ function notifyObservers() {
2181
+ const connectors = [];
2182
+ for (const key of configKeys) {
2183
+ const toRects = channels.to.get(key), toPayload = payloads.from.get(key), fromRects = channels.from.get(key), fromPayload = payloads.from.get(key);
2184
+ toRects && fromRects && connectors.push({
2185
+ key,
2186
+ from: { ...fromRects, payload: fromPayload },
2187
+ to: { ...toRects, payload: toPayload }
2188
+ });
2189
+ }
2190
+ for (const observer of observers)
2191
+ observer(connectors);
2192
+ }
2193
+ return {
2194
+ to: {
2195
+ subscribe(key, payload) {
2196
+ return channels.to.set(key, null), payloads.to.set(key, payload), configKeys.push(key), () => {
2197
+ channels.to.delete(key), payloads.to.delete(key);
2198
+ const idx = configKeys.indexOf(key);
2199
+ idx > -1 && configKeys.splice(idx, 1), notifyObservers();
2200
+ };
2201
+ },
2202
+ next(key, rects) {
2203
+ channels.to.set(key, rects), fieldKeys.includes(key) && notifyObservers();
2204
+ }
2205
+ },
2206
+ connectors: {
2207
+ subscribe(observer) {
2208
+ return observers.push(observer), () => {
2209
+ const idx = observers.indexOf(observer);
2210
+ idx > -1 && observers.splice(idx, 1);
2211
+ };
2212
+ }
2213
+ },
2214
+ from: {
2215
+ subscribe(key, payload) {
2216
+ return channels.from.set(key, null), payloads.from.set(key, payload), fieldKeys.push(key), () => {
2217
+ channels.from.delete(key), payloads.from.delete(key);
2218
+ const idx = fieldKeys.indexOf(key);
2219
+ idx > -1 && fieldKeys.splice(idx, 1), notifyObservers();
2220
+ };
2221
+ },
2222
+ next(key, rects) {
2223
+ channels.from.set(key, rects), configKeys.includes(key) && notifyObservers();
2224
+ }
2225
+ }
2226
+ };
2227
+ }
2228
+ function ConnectorsProvider(props) {
2229
+ const { children, onConnectorsChange } = props, store = useMemo(() => createConnectorsStore(), []);
2230
+ return useEffect(
2231
+ () => onConnectorsChange && store.connectors.subscribe(onConnectorsChange),
2232
+ [onConnectorsChange, store]
2233
+ ), /* @__PURE__ */ jsx(ConnectorsStoreContext.Provider, { value: store, children });
2234
+ }
2235
+ function getConnectorLinePoint(options2, rect, bounds) {
2236
+ const centerY = rect.y + rect.h / 2, isAbove = rect.y + rect.h < bounds.y + options2.arrow.marginY, isBelow = rect.y > bounds.y + bounds.h - options2.arrow.marginY;
2237
+ return {
2238
+ bounds,
2239
+ x: rect.x,
2240
+ y: centerY,
2241
+ centerY,
2242
+ startY: rect.y + options2.path.marginY,
2243
+ endY: rect.y + rect.h - options2.path.marginY,
2244
+ isAbove,
2245
+ isBelow,
2246
+ outOfBounds: isAbove || isBelow
2247
+ };
2248
+ }
2249
+ function mapConnectorToLine(options2, connector) {
2250
+ const fromBounds = {
2251
+ y: connector.from.bounds.y + options2.arrow.threshold,
2252
+ // bottom: connector.from.bounds.y + connector.from.bounds.h - options.arrow.threshold,
2253
+ x: connector.from.bounds.x,
2254
+ // right: connector.from.bounds.x + connector.from.bounds.w,
2255
+ w: connector.from.bounds.w,
2256
+ h: connector.from.bounds.h - options2.arrow.threshold * 2
2257
+ }, from = getConnectorLinePoint(options2, connector.from.element, fromBounds);
2258
+ from.x = connector.from.element.x + connector.from.element.w;
2259
+ const fromBottom = fromBounds.y + fromBounds.h, toBounds = {
2260
+ y: connector.to.bounds.y + options2.arrow.threshold,
2261
+ // bottom: connector.to.bounds.y + connector.to.bounds.h - options.arrow.threshold,
2262
+ x: connector.to.bounds.x,
2263
+ // right: connector.to.bounds.x + connector.to.bounds.w,
2264
+ w: connector.to.bounds.w,
2265
+ h: connector.to.bounds.h - options2.arrow.threshold * 2
2266
+ }, toBottom = toBounds.y + toBounds.h, to = getConnectorLinePoint(options2, connector.to.element, toBounds), maxStartY = Math.max(to.startY, from.startY);
2267
+ return from.y = Math.min(maxStartY, from.endY), from.y < toBounds.y ? from.y = Math.min(toBounds.y, from.endY) : from.y > toBottom && (from.y = Math.max(toBottom, from.startY)), to.y = Math.min(maxStartY, to.endY), to.y < fromBounds.y ? to.y = Math.min(fromBounds.y, to.endY) : to.y > fromBottom && (to.y = Math.max(fromBottom, to.startY)), from.y = Math.min(Math.max(from.y, fromBounds.y), fromBottom), to.y = Math.min(Math.max(to.y, toBounds.y), toBottom), { from, to };
2268
+ }
2269
+ function arrowPath(options2, x, y, dir) {
2270
+ return [
2271
+ `M ${x - options2.arrow.size} ${y - options2.arrow.size * dir} `,
2272
+ `L ${x} ${y}`,
2273
+ `L ${x + options2.arrow.size} ${y - options2.arrow.size * dir}`
2274
+ ].join("");
2275
+ }
2276
+ function moveTo(x, y) {
2277
+ return `M${x} ${y}`;
2278
+ }
2279
+ function lineTo(x, y) {
2280
+ return `L${x} ${y}`;
2281
+ }
2282
+ function join(strings, delim = "") {
2283
+ return strings.join(delim);
2284
+ }
2285
+ function quadCurve(x1, y1, x, y) {
2286
+ return `Q${x1} ${y1} ${x} ${y}`;
2287
+ }
2288
+ function drawConnectorPath(options2, line) {
2289
+ const { cornerRadius } = options2.path, { from, to } = line, { x: fromX, y: fromY } = from, { x: _toX, y: toY } = to, toX = _toX - 1, dividerX = to.bounds.x + options2.divider.offsetX, fromPathX = from.isAbove || from.isBelow ? fromX + options2.arrow.marginX : fromX, r0 = Math.min(cornerRadius, Math.abs(fromPathX - dividerX) / 2), r1 = Math.min(cornerRadius, Math.abs(fromY - toY) / 2), cmds = [];
2290
+ return from.isAbove ? cmds.push(
2291
+ moveTo(
2292
+ fromX + options2.arrow.marginX,
2293
+ fromY - options2.arrow.threshold + options2.arrow.marginY
2294
+ ),
2295
+ lineTo(fromX + options2.arrow.marginX, fromY - r0),
2296
+ quadCurve(fromX + options2.arrow.marginX, fromY, fromX + options2.arrow.marginX + r0, fromY)
2297
+ ) : from.isBelow ? cmds.push(
2298
+ moveTo(
2299
+ fromX + options2.arrow.marginX,
2300
+ fromY + options2.arrow.threshold - options2.arrow.marginY
2301
+ ),
2302
+ lineTo(fromX + options2.arrow.marginX, fromY + r0),
2303
+ quadCurve(fromX + options2.arrow.marginX, fromY, fromX + options2.arrow.marginX + r0, fromY)
2304
+ ) : cmds.push(moveTo(fromX, fromY)), to.isAbove ? fromY < to.bounds.y ? cmds.push(
2305
+ lineTo(dividerX - r1, fromY),
2306
+ quadCurve(dividerX, fromY, dividerX, fromY + r1),
2307
+ lineTo(dividerX, toY - r1),
2308
+ quadCurve(dividerX, toY, dividerX + r1, toY),
2309
+ lineTo(dividerX - cornerRadius, toY),
2310
+ quadCurve(dividerX, toY, dividerX, toY - cornerRadius),
2311
+ lineTo(dividerX, toY - options2.arrow.threshold + options2.arrow.marginY)
2312
+ ) : cmds.push(
2313
+ lineTo(dividerX - cornerRadius, fromY),
2314
+ quadCurve(dividerX, fromY, dividerX, fromY - cornerRadius),
2315
+ lineTo(dividerX, toY - options2.arrow.threshold + options2.arrow.marginY)
2316
+ ) : to.isBelow ? fromY > to.bounds.y + to.bounds.h ? cmds.push(
2317
+ lineTo(dividerX - options2.arrow.marginX - r1, fromY),
2318
+ quadCurve(
2319
+ dividerX - options2.arrow.marginX,
2320
+ fromY,
2321
+ dividerX - options2.arrow.marginX,
2322
+ fromY - r1
2323
+ ),
2324
+ lineTo(dividerX - options2.arrow.marginX, toY + r1),
2325
+ quadCurve(
2326
+ dividerX - options2.arrow.marginX,
2327
+ toY,
2328
+ dividerX - options2.arrow.marginX + r1,
2329
+ toY
2330
+ ),
2331
+ lineTo(dividerX - cornerRadius, toY),
2332
+ quadCurve(dividerX, toY, dividerX, toY + cornerRadius),
2333
+ lineTo(dividerX, toY + options2.arrow.threshold - options2.arrow.marginY)
2334
+ ) : cmds.push(
2335
+ lineTo(dividerX - cornerRadius, fromY),
2336
+ quadCurve(dividerX, fromY, dividerX, fromY + cornerRadius),
2337
+ lineTo(dividerX, toY + options2.arrow.threshold - options2.arrow.marginY)
2338
+ ) : fromY < toY ? cmds.push(
2339
+ lineTo(dividerX - r0, fromY),
2340
+ quadCurve(dividerX, fromY, dividerX, fromY + r1),
2341
+ lineTo(dividerX, toY - r1),
2342
+ quadCurve(dividerX, toY, dividerX + r1, toY),
2343
+ lineTo(toX, toY)
2344
+ ) : cmds.push(
2345
+ lineTo(dividerX - Math.min(r0, r1), fromY),
2346
+ quadCurve(dividerX, fromY, dividerX, fromY - Math.min(r0, r1)),
2347
+ lineTo(dividerX, toY + r1),
2348
+ quadCurve(dividerX, toY, dividerX + r1, toY),
2349
+ lineTo(toX, toY)
2350
+ ), join(cmds);
2351
+ }
2352
+ function ConnectorPath(props) {
2353
+ const { from, options: options2, to } = props, { strokeWidth } = options2.path, theme = useTheme(), line = useMemo(() => mapConnectorToLine(options2, { from, to }), [from, options2, to]);
2354
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
2355
+ /* @__PURE__ */ jsx(
2356
+ "path",
2357
+ {
2358
+ d: drawConnectorPath(options2, line),
2359
+ stroke: theme.sanity.color.base.bg,
2360
+ strokeWidth: strokeWidth + 4
2361
+ }
2362
+ ),
2363
+ /* @__PURE__ */ jsx(
2364
+ "path",
2365
+ {
2366
+ d: drawConnectorPath(options2, line),
2367
+ stroke: rgba(theme.sanity.color.base.border, 0.5),
2368
+ strokeWidth
2369
+ }
2370
+ ),
2371
+ line.from.isAbove && /* @__PURE__ */ jsx(
2372
+ "path",
2373
+ {
2374
+ d: arrowPath(
2375
+ options2,
2376
+ line.from.x + options2.arrow.marginX,
2377
+ line.from.bounds.y - options2.arrow.threshold + options2.arrow.marginY,
2378
+ -1
2379
+ ),
2380
+ stroke: theme.sanity.color.base.border,
2381
+ strokeWidth
2382
+ }
2383
+ ),
2384
+ line.from.isBelow && /* @__PURE__ */ jsx(
2385
+ "path",
2386
+ {
2387
+ d: arrowPath(
2388
+ options2,
2389
+ line.from.x + options2.arrow.marginX,
2390
+ line.from.bounds.y + line.from.bounds.h + options2.arrow.threshold - options2.arrow.marginY,
2391
+ 1
2392
+ ),
2393
+ stroke: theme.sanity.color.base.border,
2394
+ strokeWidth
2395
+ }
2396
+ )
2397
+ ] });
2398
+ }
2399
+ const DEBUG = !1, options = {
2400
+ arrow: {
2401
+ marginX: 10.5,
2402
+ marginY: 5,
2403
+ size: 4,
2404
+ threshold: 16.5
2405
+ },
2406
+ divider: {
2407
+ offsetX: -10.5
2408
+ },
2409
+ path: {
2410
+ cornerRadius: 3,
2411
+ marginY: 10.5,
2412
+ strokeWidth: 1
2413
+ }
2414
+ };
2415
+ function AssistConnectorsOverlay(props) {
2416
+ const { connectors } = props, [, setRedraw] = useState(!1);
2417
+ return useEffect(() => {
2418
+ setRedraw(!0);
2419
+ }, []), /* @__PURE__ */ jsxs(Fragment, { children: [
2420
+ /* @__PURE__ */ jsx(
2421
+ "svg",
2422
+ {
2423
+ fill: "none",
2424
+ width: window.innerWidth,
2425
+ height: window.innerHeight,
2426
+ style: {
2427
+ position: "absolute",
2428
+ top: 0,
2429
+ left: 0,
2430
+ width: "100%",
2431
+ height: "100%",
2432
+ pointerEvents: "none",
2433
+ zIndex: 150
2434
+ // zIndex,
2435
+ },
2436
+ children: connectors.map((connector) => /* @__PURE__ */ jsx(
2437
+ ConnectorPath,
2438
+ {
2439
+ from: connector.from,
2440
+ options,
2441
+ to: connector.to
2442
+ },
2443
+ connector.key
2444
+ ))
2445
+ }
2446
+ ),
2447
+ DEBUG
2448
+ ] });
2449
+ }
2450
+ const getLanguageParams = (select, document2) => {
2451
+ if (!select || !document2)
2452
+ return {};
2453
+ const selection = select || {}, selectedValue = {};
2454
+ for (const [key, path] of Object.entries(selection)) {
2455
+ let value = get(document2, path);
2456
+ Array.isArray(value) && (value = value.filter(
2457
+ (item) => typeof item == "object" ? (item == null ? void 0 : item._type) !== "reference" || "_ref" in item : !0
2458
+ )), selectedValue[key] = value;
2459
+ }
2460
+ return selectedValue;
2461
+ }, toFieldLanguagesKeyPrefix = "sanityStudio:assist:field-languages:from:";
2462
+ function getPreferredToFieldLanguages(fromLanguageId) {
2463
+ if (typeof localStorage > "u")
2464
+ return [];
2465
+ const value = localStorage.getItem(`${toFieldLanguagesKeyPrefix}${fromLanguageId}`);
2466
+ return value ? JSON.parse(value) : [];
2467
+ }
2468
+ function setPreferredToFieldLanguages(fromLanguageId, languageIds) {
2469
+ typeof localStorage > "u" || localStorage.setItem(`${toFieldLanguagesKeyPrefix}${fromLanguageId}`, JSON.stringify(languageIds));
2470
+ }
2471
+ const FieldTranslationContext = createContext({
2472
+ openFieldTranslation: () => {
2473
+ },
2474
+ translationLoading: !1
2475
+ });
2476
+ function useFieldTranslation() {
2477
+ return useContext(FieldTranslationContext);
2478
+ }
2479
+ function hasValuesToTranslate(fieldLanguageMaps, fromLanguage, basePath2) {
2480
+ return fieldLanguageMaps == null ? void 0 : fieldLanguageMaps.some(
2481
+ (map) => map.inputLanguageId === (fromLanguage == null ? void 0 : fromLanguage.id) && map.inputPath && pathToString(map.inputPath).startsWith(pathToString(basePath2))
2482
+ );
2483
+ }
2484
+ function FieldTranslationProvider(props) {
2485
+ var _a, _b, _c;
2486
+ const { config: assistConfig } = useAiAssistanceConfig(), apiClient = useApiClient(assistConfig.__customApiClient), config = (_a = assistConfig.translate) == null ? void 0 : _a.field, { translate: runTranslate } = useTranslate(apiClient), [dialogOpen, setDialogOpen] = useState(!1), [fieldTranslationParams, setFieldTranslationParams] = useState(), [languages, setLanguages] = useState(), [fromLanguage, setFromLanguage] = useState(void 0), [toLanguages, setToLanguages] = useState(void 0), [fieldLanguageMaps, setFieldLanguageMaps] = useState(), close = useCallback(() => {
2487
+ setDialogOpen(!1), setLanguages(void 0), setFieldTranslationParams(void 0);
2488
+ }, []), languageClient = useClient({ apiVersion: (_b = config == null ? void 0 : config.apiVersion) != null ? _b : "2022-11-27" }), documentId = (_c = fieldTranslationParams == null ? void 0 : fieldTranslationParams.document) == null ? void 0 : _c._id, id = useId(), selectFromLanguage = useCallback(
2489
+ (from, languages2, params) => {
2490
+ var _a2, _b2;
2491
+ const { document: document2, documentSchema } = params != null ? params : {};
2492
+ if (setFromLanguage(from), !document2 || !documentSchema || !params || !languages2) {
2493
+ setFieldLanguageMaps(void 0);
2494
+ return;
2495
+ }
2496
+ const preferred = getPreferredToFieldLanguages(from.id), allToLanguages = languages2.filter((l) => l.id !== (from == null ? void 0 : from.id)), filteredToLanguages = allToLanguages.filter(
2497
+ (l) => !preferred.length || preferred.includes(l.id)
2498
+ );
2499
+ setToLanguages(filteredToLanguages);
2500
+ const fromId = from == null ? void 0 : from.id, allToIds = (_a2 = allToLanguages == null ? void 0 : allToLanguages.map((l) => l.id)) != null ? _a2 : [], docMembers = getDocumentMembersFlat(document2, documentSchema);
2501
+ if (fromId && allToIds != null && allToIds.length) {
2502
+ const transMap = getFieldLanguageMap(
2503
+ documentSchema,
2504
+ docMembers,
2505
+ fromId,
2506
+ allToIds.filter((toId) => fromId !== toId),
2507
+ (_b2 = config == null ? void 0 : config.translationOutputs) != null ? _b2 : defaultLanguageOutputs
2508
+ );
2509
+ setFieldLanguageMaps(transMap);
2510
+ } else
2511
+ setFieldLanguageMaps(void 0);
2512
+ },
2513
+ [config]
2514
+ ), toggleToLanguage = useCallback(
2515
+ (toggledLang, toLanguages2, languages2) => {
2516
+ if (!languages2 || !fromLanguage)
2517
+ return;
2518
+ const wasSelected = !!(toLanguages2 != null && toLanguages2.find((l) => l.id === toggledLang.id)), newToLangs = languages2.filter(
2519
+ (anyLang) => !!(toLanguages2 != null && toLanguages2.find(
2520
+ (selectedLang) => toggledLang.id !== selectedLang.id && selectedLang.id === anyLang.id
2521
+ )) || toggledLang.id === anyLang.id && !wasSelected
2522
+ );
2523
+ setToLanguages(newToLangs), setPreferredToFieldLanguages(
2524
+ fromLanguage.id,
2525
+ newToLangs.map((l) => l.id)
2526
+ );
2527
+ },
2528
+ [fromLanguage]
2529
+ ), openFieldTranslation = useCallback(
2530
+ async (params) => {
2531
+ setDialogOpen(!0);
2532
+ const languageParams = getLanguageParams(config == null ? void 0 : config.selectLanguageParams, params.document), languages2 = await (typeof (config == null ? void 0 : config.languages) == "function" ? config == null ? void 0 : config.languages(languageClient, languageParams) : Promise.resolve(config == null ? void 0 : config.languages));
2533
+ setLanguages(languages2), setFieldTranslationParams(params);
2534
+ const fromLanguage2 = languages2 == null ? void 0 : languages2[0];
2535
+ fromLanguage2 ? selectFromLanguage(fromLanguage2, languages2, params) : console.error("No languages available for selected language params", languageParams);
2536
+ },
2537
+ [selectFromLanguage, config, languageClient]
2538
+ ), contextValue = useMemo(() => ({
2539
+ openFieldTranslation,
2540
+ translationLoading: !1
2541
+ }), [openFieldTranslation]), runDisabled = !fromLanguage || !(toLanguages != null && toLanguages.length) || !(fieldLanguageMaps != null && fieldLanguageMaps.length) || !documentId || !hasValuesToTranslate(fieldLanguageMaps, fromLanguage, fieldTranslationParams.translatePath), onRunTranslation = useCallback(() => {
2542
+ const translatePath = fieldTranslationParams == null ? void 0 : fieldTranslationParams.translatePath;
2543
+ fieldLanguageMaps && documentId && translatePath && runTranslate({
2544
+ documentId,
2545
+ translatePath,
2546
+ fieldLanguageMap: fieldLanguageMaps.map((map) => ({
2547
+ ...map,
2548
+ // eslint-disable-next-line max-nested-callbacks
2549
+ outputs: map.outputs.filter((out) => !!(toLanguages != null && toLanguages.find((l) => l.id === out.id)))
2550
+ })),
2551
+ conditionalMembers: fieldTranslationParams == null ? void 0 : fieldTranslationParams.conditionalMembers
2552
+ }), close();
2553
+ }, [
2554
+ fieldLanguageMaps,
2555
+ documentId,
2556
+ runTranslate,
2557
+ close,
2558
+ toLanguages,
2559
+ fieldTranslationParams == null ? void 0 : fieldTranslationParams.translatePath,
2560
+ fieldTranslationParams == null ? void 0 : fieldTranslationParams.conditionalMembers
2561
+ ]), runButton = /* @__PURE__ */ jsx(
2562
+ Button,
2563
+ {
2564
+ text: "Translate",
2565
+ tone: "primary",
2566
+ icon: PlayIcon,
2567
+ style: { width: "100%" },
2568
+ disabled: runDisabled,
2569
+ onClick: onRunTranslation
2570
+ }
2571
+ );
2572
+ return /* @__PURE__ */ jsxs(FieldTranslationContext.Provider, { value: contextValue, children: [
2573
+ dialogOpen ? /* @__PURE__ */ jsx(
2574
+ Dialog,
2575
+ {
2576
+ id,
2577
+ width: 1,
2578
+ open: dialogOpen,
2579
+ onClose: close,
2580
+ header: "Translate fields",
2581
+ footer: /* @__PURE__ */ jsx(Flex, { justify: "space-between", padding: 2, flex: 1, children: runDisabled ? /* @__PURE__ */ jsx(
2582
+ Tooltip,
2583
+ {
2584
+ content: /* @__PURE__ */ jsx(Flex, { padding: 2, children: /* @__PURE__ */ jsx(Text, { children: "There is nothing to translate in the selected from-language." }) }),
2585
+ placement: "top",
2586
+ children: /* @__PURE__ */ jsx(Flex, { flex: 1, children: runButton })
2587
+ }
2588
+ ) : runButton }),
2589
+ children: languages ? /* @__PURE__ */ jsxs(Flex, { padding: 4, gap: 5, align: "flex-start", justify: "center", children: [
2590
+ /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
2591
+ /* @__PURE__ */ jsx(Box, { marginBottom: 2, children: /* @__PURE__ */ jsx(Text, { weight: "semibold", children: "From" }) }),
2592
+ languages == null ? void 0 : languages.map((radioLanguage) => /* @__PURE__ */ jsx(
2593
+ FromLanguageRadio,
2594
+ {
2595
+ radioLanguage,
2596
+ fromLanguage,
2597
+ selectFromLanguage,
2598
+ languages,
2599
+ fieldTranslationParams
2600
+ },
2601
+ radioLanguage.id
2602
+ ))
2603
+ ] }),
2604
+ /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
2605
+ /* @__PURE__ */ jsx(Box, { marginBottom: 2, children: /* @__PURE__ */ jsx(Text, { weight: "semibold", children: "To" }) }),
2606
+ languages.map((checkboxLanguage) => /* @__PURE__ */ jsx(
2607
+ ToLanguageCheckbox,
2608
+ {
2609
+ checkboxLanguage,
2610
+ fromLanguage,
2611
+ toLanguages,
2612
+ toggleToLanguage,
2613
+ languages
2614
+ },
2615
+ checkboxLanguage.id
2616
+ ))
2617
+ ] })
2618
+ ] }) : /* @__PURE__ */ jsxs(Flex, { padding: 4, gap: 2, align: "flex-start", justify: "center", children: [
2619
+ /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Spinner, {}) }),
2620
+ /* @__PURE__ */ jsx(Text, { children: "Loading languages..." })
2621
+ ] })
2622
+ }
2623
+ ) : null,
2624
+ props.children
2625
+ ] });
2626
+ }
2627
+ function ToLanguageCheckbox(props) {
2628
+ var _a;
2629
+ const { checkboxLanguage, fromLanguage, toLanguages, toggleToLanguage, languages } = props, langId = checkboxLanguage.id, onChange = useCallback(
2630
+ () => toggleToLanguage(checkboxLanguage, toLanguages, languages),
2631
+ [toggleToLanguage, checkboxLanguage, toLanguages, languages]
2632
+ );
2633
+ return /* @__PURE__ */ jsxs(
2634
+ Flex,
2635
+ {
2636
+ gap: 3,
2637
+ align: "center",
2638
+ as: "label",
2639
+ style: langId === (fromLanguage == null ? void 0 : fromLanguage.id) ? { opacity: 0.5 } : void 0,
2640
+ children: [
2641
+ /* @__PURE__ */ jsx(
2642
+ Checkbox,
2643
+ {
2644
+ name: "toLang",
2645
+ value: langId,
2646
+ checked: langId !== (fromLanguage == null ? void 0 : fromLanguage.id) && !!(toLanguages != null && toLanguages.find((tl) => tl.id === langId)),
2647
+ onChange,
2648
+ disabled: langId === (fromLanguage == null ? void 0 : fromLanguage.id)
2649
+ }
2650
+ ),
2651
+ /* @__PURE__ */ jsx(Text, { muted: langId === (fromLanguage == null ? void 0 : fromLanguage.id), children: (_a = checkboxLanguage.title) != null ? _a : langId })
2652
+ ]
2653
+ },
2654
+ langId
2655
+ );
2656
+ }
2657
+ function FromLanguageRadio(props) {
2658
+ var _a;
2659
+ const { languages, radioLanguage, selectFromLanguage, fromLanguage, fieldTranslationParams } = props, langId = radioLanguage.id, onChange = useCallback(
2660
+ () => selectFromLanguage(radioLanguage, languages, fieldTranslationParams),
2661
+ [selectFromLanguage, radioLanguage, languages, fieldTranslationParams]
2662
+ );
2663
+ return /* @__PURE__ */ jsxs(Flex, { gap: 3, align: "center", as: "label", children: [
2664
+ /* @__PURE__ */ jsx(
2665
+ Radio,
2666
+ {
2667
+ name: "fromLang",
2668
+ value: langId,
2669
+ checked: langId === (fromLanguage == null ? void 0 : fromLanguage.id),
2670
+ onChange
2671
+ }
2672
+ ),
2673
+ /* @__PURE__ */ jsx(Text, { children: (_a = radioLanguage.title) != null ? _a : radioLanguage.id })
2674
+ ] }, langId);
2675
+ }
2676
+ function AssistLayout(props) {
2677
+ const [connectors, setConnectors] = useState([]);
2678
+ return /* @__PURE__ */ jsx(AiAssistanceConfigProvider, { config: props.config, children: /* @__PURE__ */ jsx(RunInstructionProvider, { children: /* @__PURE__ */ jsx(FieldTranslationProvider, { children: /* @__PURE__ */ jsxs(ConnectorsProvider, { onConnectorsChange: setConnectors, children: [
2679
+ props.renderDefault(props),
2680
+ /* @__PURE__ */ jsx(ThemeProvider, { tone: "default", children: /* @__PURE__ */ jsx(AssistConnectorsOverlay, { connectors }) })
2681
+ ] }) }) }) });
2682
+ }
2683
+ const WrapPreCard = styled(Card)`
2684
+ & pre {
2685
+ white-space: pre-wrap !important;
2686
+ }
2687
+ `;
2688
+ function SafeValueInput(props) {
2689
+ return /* @__PURE__ */ jsx(ErrorWrapper, { onChange: props.onChange, children: /* @__PURE__ */ jsx(PteValueFixer, { ...props }) });
2690
+ }
2691
+ function ErrorWrapper(props) {
2692
+ const { onChange } = props, [error, setError] = useState(), catchError2 = useCallback((params) => {
2693
+ setError(params.error);
2694
+ }, []), unsetValue = useCallback(() => {
2695
+ onChange(PatchEvent.from(unset())), setError(void 0);
2696
+ }, [onChange]), dismiss = useCallback(() => setError(void 0), []), catcher = /* @__PURE__ */ jsx(ErrorBoundary, { onCatch: catchError2, children: props.children });
2697
+ return error ? /* @__PURE__ */ jsx(Card, { border: !0, tone: "critical", padding: 2, contentEditable: !1, children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
2698
+ /* @__PURE__ */ jsx(Text, { muted: !0, weight: "semibold", children: "An error occurred." }),
2699
+ /* @__PURE__ */ jsx(WrapPreCard, { flex: 1, padding: 2, tone: "critical", border: !0, children: catcher }),
2700
+ /* @__PURE__ */ jsxs(Flex, { width: "fill", flex: 1, gap: 3, children: [
2701
+ /* @__PURE__ */ jsx(Box, { flex: 1, children: /* @__PURE__ */ jsx(Button, { text: "Dismiss", onClick: dismiss, tone: "primary" }) }),
2702
+ /* @__PURE__ */ jsx(Button, { text: "Unset value", onClick: unsetValue, tone: "critical" })
2703
+ ] })
2704
+ ] }) }) : catcher;
2705
+ }
2706
+ function PteValueFixer(props) {
2707
+ const isPortableText = useMemo(
2708
+ () => isArraySchemaType(props.schemaType) && isPortableTextArray(props.schemaType),
2709
+ [props.schemaType]
2710
+ ), value = props.value;
2711
+ return isPortableText && value && !value.length ? props.renderDefault({ ...props, value: void 0 }) : props.renderDefault(props);
2712
+ }
2713
+ function AssistFormBlock(props) {
2714
+ const presence = useAssistPresence(props.path, !0), { onChange } = useFormCallbacks(), key = props.value._key, localOnChange = useCallback(
2715
+ (patchEvent) => {
2716
+ key && onChange(PatchEvent.from(patchEvent).prefixAll({ _key: key }));
2717
+ },
2718
+ [onChange, key]
2719
+ ), singlePresence = presence[0];
2720
+ return /* @__PURE__ */ jsx(ErrorWrapper, { onChange: localOnChange, children: /* @__PURE__ */ jsxs(Flex, { align: "center", justify: "space-between", children: [
2721
+ /* @__PURE__ */ jsx(Box, { flex: 1, children: props.renderDefault(props) }),
2722
+ singlePresence && /* @__PURE__ */ jsx(AiFieldPresence, { presence: singlePresence })
2723
+ ] }) });
2724
+ }
2725
+ function AssistItem(props) {
2726
+ const { path } = props, presence = useAssistPresence(path, !0);
2727
+ return /* @__PURE__ */ jsxs(Flex, { align: "center", width: "fill", style: { position: "relative" }, children: [
2728
+ /* @__PURE__ */ jsx(Box, { flex: 1, children: props.renderDefault({ ...props }) }),
2729
+ presence.map((pre) => /* @__PURE__ */ jsx(Box, { style: { position: "absolute", right: 35 }, children: /* @__PURE__ */ jsx(AiFieldPresence, { presence: pre }) }, pre.user.id))
2730
+ ] });
2731
+ }
2732
+ const InlineBlockValueContext = createContext(void 0);
2733
+ function AssistInlineFormBlock(props) {
2734
+ return /* @__PURE__ */ jsx(InlineBlockValueContext.Provider, { value: props.value, children: /* @__PURE__ */ jsx(Fragment, { children: props.renderDefault(props) }) });
2735
+ }
2736
+ function FieldRefPreview(props) {
2737
+ var _a, _b, _c, _d;
2738
+ const documentSchema = (_a = useContext(SelectedFieldContext)) == null ? void 0 : _a.documentSchema, path = (_c = (_b = useContext(InlineBlockValueContext)) == null ? void 0 : _b.path) != null ? _c : props.path, selectedField = useSelectedField(documentSchema, path);
2739
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, align: "center", style: { width: "100%" }, children: [
2740
+ /* @__PURE__ */ jsx(Flex, { flex: 1, gap: 2, align: "center", paddingY: 3, paddingX: 1, children: /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { size: 1, textOverflow: "ellipsis", children: (_d = selectedField == null ? void 0 : selectedField.title) != null ? _d : "Select field" }) }) }),
2741
+ /* @__PURE__ */ jsx(Fragment, { children: props.actions })
2742
+ ] });
2743
+ }
2744
+ function HiddenFieldTitle(props) {
2745
+ return props.renderDefault({ ...props, title: "", level: props.level - 2, changed: !1 });
2746
+ }
2747
+ function IconInput(props) {
2748
+ const { value, onChange } = props, id = useId(), items = useMemo(
2749
+ () => Object.entries(icons).map(([key, icon]) => /* @__PURE__ */ jsx(IconItem, { iconKey: key, icon, onChange }, key)),
2750
+ [onChange]
2751
+ ), selectedIcon = useMemo(() => getIcon(value), [value]);
2752
+ return /* @__PURE__ */ jsx(
2753
+ MenuButton,
2754
+ {
2755
+ button: /* @__PURE__ */ jsx(Button, { icon: selectedIcon, title: "Select icon", padding: 3, mode: "ghost", radius: 1 }),
2756
+ id,
2757
+ menu: /* @__PURE__ */ jsx(Menu, { style: { maxHeight: 300 }, children: items }),
2758
+ popover: { portal: !0 }
2759
+ }
2760
+ );
2761
+ }
2762
+ function IconItem({
2763
+ icon,
2764
+ iconKey: key,
2765
+ onChange
2766
+ }) {
2767
+ const onClick = useCallback(() => onChange(set(key)), [onChange, key]);
2768
+ return /* @__PURE__ */ jsx(MenuItem, { icon, title: key, text: key, onClick });
2769
+ }
2770
+ function getIcon(iconName) {
2771
+ var _a, _b;
2772
+ return (_b = (_a = Object.entries(icons).find(([key]) => key === iconName)) == null ? void 0 : _a[1]) != null ? _b : icons.sparkles;
2773
+ }
2774
+ function InstructionVisibility(props) {
2775
+ const { value, onChange } = props, user = useCurrentUser(), handleChange = useCallback(() => {
2776
+ var _a;
2777
+ const newValue = value ? "" : (_a = user == null ? void 0 : user.id) != null ? _a : "";
2778
+ onChange(newValue ? set(newValue) : unset());
2779
+ }, [onChange, user, value]), id = useId();
2780
+ return /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsxs(Flex, { gap: 2, align: "flex-start", children: [
2781
+ /* @__PURE__ */ jsx("div", { style: { margin: "-3px 0" }, children: /* @__PURE__ */ jsx(
2782
+ Switch,
2783
+ {
2784
+ ...props.elementProps,
2785
+ id,
2786
+ value: `${!value}`,
2787
+ checked: !value,
2788
+ onChange: handleChange,
2789
+ disabled: props.elementProps.readOnly
2790
+ }
2791
+ ) }),
2792
+ /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, weight: "medium", children: /* @__PURE__ */ jsx("label", { htmlFor: id, children: "Make visible to all Studio members" }) })
2793
+ ] }) });
2794
+ }
2795
+ function FieldRefPathInput(props) {
2796
+ var _a;
2797
+ const documentSchema = (_a = useContext(SelectedFieldContext)) == null ? void 0 : _a.documentSchema, typePath = useContext(TypePathContext), ref = useRef(null), id = useId(), { onChange } = props;
2798
+ useEffect(() => {
2799
+ var _a2, _b;
2800
+ (_b = (_a2 = ref.current) == null ? void 0 : _a2.querySelector("input")) == null || _b.focus();
2801
+ }, []);
2802
+ const onSelect = useCallback((path) => onChange(set(path)), [onChange]), filter2 = useCallback(
2803
+ (field) => {
2804
+ if (!field.key.includes("|") || !typePath)
2805
+ return !0;
2806
+ if (field.key.includes("|") && !typePath.includes("|"))
2807
+ return !1;
2808
+ const fieldSegments = field.key.split("."), lastArrayItemIndex = fieldSegments.findLastIndex((s) => s.includes("|")), mustStartWith = fieldSegments.slice(0, lastArrayItemIndex + 1).join(".");
2809
+ return typePath.startsWith(mustStartWith);
2810
+ },
2811
+ [typePath]
2812
+ );
2813
+ return documentSchema ? /* @__PURE__ */ jsx(Box, { flex: 1, style: { minWidth: 300 }, ref, children: /* @__PURE__ */ jsx(
2814
+ FieldAutocomplete,
2815
+ {
2816
+ id,
2817
+ schemaType: documentSchema,
2818
+ onSelect,
2819
+ fieldPath: props.value,
2820
+ filter: filter2
2821
+ }
2822
+ ) }) : props.renderDefault(props);
2823
+ }
2824
+ function findFieldMember(members, fieldName) {
2825
+ return members.find(
2826
+ (m) => m.kind === "field" && m.name === fieldName || m.kind === "error" && m.fieldName === fieldName
2827
+ );
2828
+ }
2829
+ function findFieldsetMember(members, fieldsetName) {
2830
+ return members.find(
2831
+ (m) => m.kind === "fieldSet" && m.fieldSet.name === fieldsetName
2832
+ );
2833
+ }
2834
+ function InstructionInput(props) {
2835
+ return /* @__PURE__ */ jsxs(Stack, { space: [4, 4, 4, 5], children: [
2836
+ /* @__PURE__ */ jsx(NameField, { ...props }),
2837
+ /* @__PURE__ */ jsx(ShareField, { ...props }),
2838
+ /* @__PURE__ */ jsx(ObjectMember, { fieldName: "prompt", ...props }),
2839
+ /* @__PURE__ */ jsx(ObjectMember, { fieldName: "output", ...props })
2840
+ ] });
2841
+ }
2842
+ function ObjectMember({ fieldName, ...props }) {
2843
+ const member = findFieldMember(props.members, fieldName);
2844
+ return member ? /* @__PURE__ */ jsx(ObjectInputMember, { ...props, member }) : null;
2845
+ }
2846
+ const NONE = [];
2847
+ function NameField(props) {
2848
+ var _a;
2849
+ const fieldsetMember = findFieldsetMember(props.members, "appearance"), titleId = useId(), members = (_a = fieldsetMember == null ? void 0 : fieldsetMember.fieldSet.members) != null ? _a : NONE, iconMember = findFieldMember(members, "icon"), titleMember = findFieldMember(members, "title"), titlePlaceholder = "Untitled", moddedTitleMember = useMemo(() => {
2850
+ if (titleMember)
2851
+ return titleMember.kind === "error" ? titleMember : {
2852
+ ...titleMember,
2853
+ field: {
2854
+ ...titleMember == null ? void 0 : titleMember.field,
2855
+ schemaType: {
2856
+ ...titleMember == null ? void 0 : titleMember.field.schemaType,
2857
+ placeholder: titlePlaceholder
2858
+ }
2859
+ }
2860
+ };
2861
+ }, [titleMember, titlePlaceholder]);
2862
+ return /* @__PURE__ */ jsx(Stack, { space: 5, children: /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
2863
+ /* @__PURE__ */ jsx(Flex, { gap: 1, children: /* @__PURE__ */ jsx(Text, { as: "label", weight: "semibold", size: 1, htmlFor: titleId, children: "Name" }) }),
2864
+ /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, children: "How this instruction appears in menus" }),
2865
+ /* @__PURE__ */ jsxs(Flex, { align: "center", children: [
2866
+ iconMember && /* @__PURE__ */ jsx(Box, { flex: "none", children: /* @__PURE__ */ jsx(ObjectInputMember, { ...props, member: iconMember }) }),
2867
+ moddedTitleMember && /* @__PURE__ */ jsx(Box, { flex: 1, style: { marginLeft: -1 }, children: /* @__PURE__ */ jsx(ObjectInputMember, { ...props, member: moddedTitleMember }) })
2868
+ ] })
2869
+ ] }) });
2870
+ }
2871
+ function ShareField(props) {
2872
+ var _a;
2873
+ const fieldsetMember = findFieldsetMember(props.members, "appearance"), members = (_a = fieldsetMember == null ? void 0 : fieldsetMember.fieldSet.members) != null ? _a : NONE, visibilityMember = findFieldMember(members, "userId");
2874
+ return /* @__PURE__ */ jsx(Fragment, { children: visibilityMember && /* @__PURE__ */ jsx(ObjectInputMember, { ...props, member: visibilityMember }) });
2875
+ }
2876
+ function InstructionOutputField(props) {
2877
+ var _a;
2878
+ const { fieldSchema } = (_a = useContext(SelectedFieldContext)) != null ? _a : {};
2879
+ return !fieldSchema || !(isObjectSchemaType(fieldSchema) || isArrayOfObjectsSchemaType(fieldSchema)) ? null : /* @__PURE__ */ jsx(EnabledOutputField, { ...props, fieldSchema, children: props.children });
2880
+ }
2881
+ function EnabledOutputField({
2882
+ fieldSchema,
2883
+ ...props
2884
+ }) {
2885
+ var _a;
2886
+ const [open, setOpen] = useState(!!((_a = props.value) != null && _a.length)), onExpand = useCallback(() => setOpen(!0), []), onCollapse = useCallback(() => setOpen(!1), []);
2887
+ return props.renderDefault({
2888
+ ...props,
2889
+ collapsible: !0,
2890
+ onExpand,
2891
+ onCollapse,
2892
+ collapsed: !open,
2893
+ level: 1,
2894
+ title: isObjectSchemaType(fieldSchema) ? "Allowed fields" : "Allowed types"
2895
+ });
2896
+ }
2897
+ function InstructionOutputInput(props) {
2898
+ var _a;
2899
+ const { fieldSchema } = (_a = useContext(SelectedFieldContext)) != null ? _a : {};
2900
+ return fieldSchema ? isObjectSchemaType(fieldSchema) ? /* @__PURE__ */ jsx(ObjectOutputInput, { ...props, fieldSchema }) : isArrayOfObjectsSchemaType(fieldSchema) ? /* @__PURE__ */ jsx(ArrayOutputInput, { ...props, fieldSchema }) : null : null;
2901
+ }
2902
+ function useEmptySelectAllValue(value, allowedValues, onChange) {
2903
+ useEffect(() => {
2904
+ var _a, _b;
2905
+ const validValues = value == null ? void 0 : value.filter(
2906
+ (v) => allowedValues.find(
2907
+ (f) => f.name === (v._type === outputFieldTypeName ? v.relativePath : v.type)
2908
+ )
2909
+ ), valueLength = (_a = value == null ? void 0 : value.length) != null ? _a : 0, validLength = (_b = validValues == null ? void 0 : validValues.length) != null ? _b : 0;
2910
+ (!validLength && valueLength || validLength >= allowedValues.length) && onChange(PatchEvent.from([unset()]));
2911
+ }, [allowedValues, value, onChange]);
2912
+ }
2913
+ function ObjectOutputInput({
2914
+ fieldSchema,
2915
+ ...props
2916
+ }) {
2917
+ const { value, onChange } = props, fields = useMemo(
2918
+ () => fieldSchema.fields.filter((field) => isAssistSupported(field.type)),
2919
+ [fieldSchema.fields]
2920
+ );
2921
+ useEmptySelectAllValue(value, fields, onChange);
2922
+ const onSelectChange = useCallback(
2923
+ (checked, selectedValue) => {
2924
+ if (checked)
2925
+ if (value != null && value.length)
2926
+ onChange(PatchEvent.from(unset([{ _key: selectedValue }])));
2927
+ else {
2928
+ const items = fields.filter((f) => f.name !== selectedValue).map(
2929
+ (field) => typed({
2930
+ _key: field.name,
2931
+ _type: "sanity.assist.output.field",
2932
+ relativePath: field.name
2933
+ })
2934
+ );
2935
+ onChange(PatchEvent.from([setIfMissing([]), insert(items, "after", [-1])]));
2936
+ }
2937
+ else {
2938
+ const patchValue = {
2939
+ _key: selectedValue,
2940
+ _type: "sanity.assist.output.field",
2941
+ relativePath: selectedValue
2942
+ };
2943
+ onChange(PatchEvent.from([setIfMissing([]), insert([patchValue], "after", [-1])]));
2944
+ }
2945
+ },
2946
+ [onChange, value, fields]
2947
+ );
2948
+ return /* @__PURE__ */ jsx(Stack, { space: 2, children: fields.map((field) => {
2949
+ var _a;
2950
+ return /* @__PURE__ */ jsx(Flex, { align: "center", gap: 2, children: /* @__PURE__ */ jsx(
2951
+ Selectable,
2952
+ {
2953
+ value: field.name,
2954
+ title: (_a = field.type.title) != null ? _a : field.name,
2955
+ arrayValue: value,
2956
+ onChange: onSelectChange
2957
+ }
2958
+ ) }, field.name);
2959
+ }) });
2960
+ }
2961
+ function ArrayOutputInput({
2962
+ fieldSchema,
2963
+ ...props
2964
+ }) {
2965
+ const { value, onChange } = props, ofItems = useMemo(
2966
+ () => fieldSchema.of.filter((itemType) => isAssistSupported(itemType)),
2967
+ [fieldSchema.of]
2968
+ );
2969
+ useEmptySelectAllValue(value, ofItems, onChange);
2970
+ const onSelectChange = useCallback(
2971
+ (checked, selectedValue) => {
2972
+ if (checked)
2973
+ if (value != null && value.length)
2974
+ onChange(PatchEvent.from(unset([{ _key: selectedValue }])));
2975
+ else {
2976
+ const items = ofItems.filter((f) => f.name !== selectedValue).map(
2977
+ (field) => typed({
2978
+ _key: field.name,
2979
+ _type: "sanity.assist.output.type",
2980
+ type: field.name
2981
+ })
2982
+ );
2983
+ onChange(PatchEvent.from([setIfMissing([]), insert(items, "after", [-1])]));
2984
+ }
2985
+ else {
2986
+ const patchValue = {
2987
+ _key: selectedValue,
2988
+ _type: "sanity.assist.output.type",
2989
+ type: selectedValue
2990
+ };
2991
+ onChange(PatchEvent.from([setIfMissing([]), insert([patchValue], "after", [-1])]));
2992
+ }
2993
+ },
2994
+ [onChange, value, ofItems]
2995
+ );
2996
+ return /* @__PURE__ */ jsx(Stack, { space: 2, children: ofItems.map((itemType) => {
2997
+ var _a;
2998
+ return /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
2999
+ Selectable,
3000
+ {
3001
+ value: itemType.name,
3002
+ title: isType(itemType, "block") ? "Text" : (_a = itemType.title) != null ? _a : itemType.name,
3003
+ arrayValue: value,
3004
+ onChange: onSelectChange
3005
+ }
3006
+ ) }, itemType.name);
3007
+ }) });
3008
+ }
3009
+ function Selectable({
3010
+ title,
3011
+ arrayValue,
3012
+ value,
3013
+ onChange
3014
+ }) {
3015
+ const checked = !(arrayValue != null && arrayValue.length) || !!(arrayValue != null && arrayValue.find((v) => v._key === value)), handleChange = useCallback(() => onChange(checked, value), [onChange, checked, value]);
3016
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, align: "flex-start", children: [
3017
+ /* @__PURE__ */ jsx(Checkbox, { checked, onChange: handleChange }),
3018
+ /* @__PURE__ */ jsx(Card, { marginTop: 1, onClick: handleChange, children: /* @__PURE__ */ jsx(Text, { style: { cursor: "default" }, size: 1, children: title }) })
3019
+ ] });
3020
+ }
3021
+ function getRandomValues(typedArray) {
3022
+ const crypto = typeof window < "u" && "crypto" in window ? window.crypto : globalThis.crypto;
3023
+ if (!crypto || !crypto.getRandomValues)
3024
+ throw new Error("WebCrypto not available in this environment");
3025
+ return crypto.getRandomValues(typedArray);
3026
+ }
3027
+ function whatwgRNG(length = 16) {
3028
+ const rnds8 = new Uint8Array(length);
3029
+ return getRandomValues(rnds8), rnds8;
3030
+ }
3031
+ const getByteHexTable = /* @__PURE__ */ (() => {
3032
+ let table;
3033
+ return () => {
3034
+ if (table)
3035
+ return table;
3036
+ table = [];
3037
+ for (let i = 0; i < 256; ++i)
3038
+ table[i] = (i + 256).toString(16).substring(1);
3039
+ return table;
3040
+ };
3041
+ })();
3042
+ function randomKey(length) {
3043
+ const table = getByteHexTable();
3044
+ return whatwgRNG(length).reduce((str, n) => str + table[n], "").slice(0, length);
3045
+ }
3046
+ const PteMods = styled(Box)`
3047
+ & [data-testid='pt-editor__toolbar-card'] > div > div:last-child {
3048
+ display: none;
3049
+ }
3050
+ & [data-testid='pt-editor'] {
3051
+ min-height: 300px;
3052
+ }
3053
+ & [data-testid='pt-editor'] .pt-inline-object * {
3054
+ max-width: 400px;
3055
+ }
3056
+ `;
3057
+ function PromptInput(props) {
3058
+ return useOnlyInlineBlocks(props), /* @__PURE__ */ jsx(PteMods, { children: props.renderDefault(props) });
3059
+ }
3060
+ function useOnlyInlineBlocks(props) {
3061
+ useEffect(() => {
3062
+ var _a;
3063
+ let needsFix = !1;
3064
+ const val = ((_a = props.value) != null ? _a : []).map((block) => block._type === "block" ? block : (needsFix = !0, typed({
3065
+ _key: randomKey(12),
3066
+ _type: "block",
3067
+ level: 0,
3068
+ markDefs: [],
3069
+ style: "normal",
3070
+ children: [block]
3071
+ })));
3072
+ needsFix && props.onChange(set(val));
3073
+ }, []);
3074
+ }
3075
+ function InstructionsArrayField(props) {
3076
+ return props.renderDefault({
3077
+ ...props,
3078
+ title: " "
3079
+ });
3080
+ }
3081
+ function InstructionsArrayInput(props) {
3082
+ const user = useCurrentUser(), originalValue = props.value, originalMembers = props.members, value = useMemo(
3083
+ () => (originalValue != null ? originalValue : []).filter((v) => !v.userId || v.userId === (user == null ? void 0 : user.id)),
3084
+ [originalValue, user]
3085
+ ), members = useMemo(
3086
+ () => (originalMembers != null ? originalMembers : []).filter((v) => {
3087
+ var _a;
3088
+ if (v.kind === "error")
3089
+ return !0;
3090
+ const value2 = (_a = v == null ? void 0 : v.item) == null ? void 0 : _a.value;
3091
+ return !value2.userId || value2.userId === (user == null ? void 0 : user.id);
3092
+ }),
3093
+ [originalMembers, user]
3094
+ );
3095
+ return props.renderDefault({ ...props, value, members });
3096
+ }
3097
+ function HideReferenceChangedBannerInput(props) {
3098
+ const ref = useRef(null);
3099
+ return useEffect(() => {
3100
+ var _a;
3101
+ const parent = (_a = ref.current) == null ? void 0 : _a.closest('[data-testid="pane-content"]');
3102
+ if (!parent)
3103
+ return;
3104
+ const style = document.createElement("style"), parentId = `id-${Math.random()}`.replace(".", "-");
3105
+ parent.id = parentId, style.innerText = `
3106
+ #${parentId} [data-testid="reference-changed-banner"] { display: none; }
3107
+ `, parent.prepend(style);
3108
+ }, [ref]), /* @__PURE__ */ jsx(Box, { ref, children: props.renderDefault(props) });
3109
+ }
3110
+ const contextDocumentSchema = defineType({
3111
+ type: "document",
3112
+ name: contextDocumentTypeName,
3113
+ title: "AI context",
3114
+ liveEdit: !0,
3115
+ icon: TokenIcon,
3116
+ components: {
3117
+ input: HideReferenceChangedBannerInput
3118
+ },
3119
+ fields: [
3120
+ defineField({
3121
+ type: "string",
3122
+ name: "title",
3123
+ title: "Title"
3124
+ }),
3125
+ defineField({
3126
+ name: "context",
3127
+ type: "array",
3128
+ title: "Context",
3129
+ of: [
3130
+ defineArrayMember({
3131
+ type: "block",
3132
+ styles: [{ title: "Normal", value: "normal" }],
3133
+ lists: [],
3134
+ marks: {
3135
+ decorators: [],
3136
+ annotations: []
3137
+ }
3138
+ })
3139
+ ]
3140
+ })
3141
+ ],
3142
+ preview: {
3143
+ select: {
3144
+ title: "title",
3145
+ context: "context"
3146
+ },
3147
+ prepare({ title, context }) {
3148
+ var _a;
3149
+ const text = context == null ? void 0 : context.flatMap((block) => block == null ? void 0 : block.children).flatMap((child) => {
3150
+ var _a2;
3151
+ return (_a2 = child == null ? void 0 : child.text) == null ? void 0 : _a2.split(" ");
3152
+ }).filter(Boolean), words = (_a = text == null ? void 0 : text.length) != null ? _a : 0;
3153
+ return {
3154
+ title,
3155
+ subtitle: `Words: ${words}`,
3156
+ media: DocumentTextIcon
3157
+ };
3158
+ }
3159
+ }
3160
+ }), fieldReference = defineType({
3161
+ type: "object",
3162
+ name: fieldReferenceTypeName,
3163
+ title: "Field",
3164
+ icon: ThListIcon,
3165
+ fields: [
3166
+ defineField({
3167
+ type: "string",
3168
+ name: "path",
3169
+ title: "Field",
3170
+ components: {
3171
+ input: FieldRefPathInput
3172
+ },
3173
+ validation: (rule) => rule.custom((value, context) => {
3174
+ var _a;
3175
+ if (!value)
3176
+ return "Please select a field";
3177
+ try {
3178
+ const docId = (_a = context.document) == null ? void 0 : _a._id;
3179
+ if (!docId)
3180
+ return "Field reference cannot be used outside document inspector context. Could not resolve document id.";
3181
+ const targetDocType = docId.replace(new RegExp(`^${assistDocumentIdPrefix}`), ""), schema = context.schema.get(targetDocType);
3182
+ return schema ? getFieldRefsWithDocument(schema).find((r) => r.key === value) ? !0 : `Field with path "${value}" does not exist in the schema.` : `Field reference cannot be used outside document inspector context. Could not resolve schema: ${targetDocType}`;
3183
+ } catch (e) {
3184
+ return console.error("Failed to resolve field reference", e), "Invalid field reference.";
3185
+ }
3186
+ })
3187
+ })
3188
+ ],
3189
+ preview: {
3190
+ select: {
3191
+ path: "path"
3192
+ },
3193
+ prepare({ path }) {
3194
+ return {
3195
+ title: path,
3196
+ path,
3197
+ icon: CodeIcon
3198
+ };
3199
+ }
3200
+ },
3201
+ components: {
3202
+ preview: FieldRefPreview
3203
+ },
3204
+ options: {
3205
+ modal: {
3206
+ type: "popover"
3207
+ }
3208
+ }
3209
+ }), userInput = defineType({
3210
+ type: "object",
3211
+ name: userInputTypeName,
3212
+ title: "User input",
3213
+ icon: ComposeIcon,
3214
+ fields: [
3215
+ defineField({
3216
+ type: "string",
3217
+ name: "message",
3218
+ title: "User input title",
3219
+ placeholder: "Provide instruction text",
3220
+ description: "The header above the user input text field",
3221
+ validation: (rule) => rule.required()
3222
+ }),
3223
+ defineField({
3224
+ type: "text",
3225
+ rows: 3,
3226
+ name: "description",
3227
+ title: "User input description",
3228
+ description: "The description above the user input text field"
3229
+ })
3230
+ ],
3231
+ preview: {
3232
+ select: {
3233
+ title: "message"
3234
+ }
3235
+ },
3236
+ options: {
3237
+ modal: {
3238
+ type: "popover",
3239
+ width: 1
3240
+ }
3241
+ }
3242
+ }), promptContext = defineType({
3243
+ type: "object",
3244
+ name: instructionContextTypeName,
3245
+ title: contextDocumentSchema.title,
3246
+ icon: contextDocumentSchema.icon,
3247
+ fields: [
3248
+ defineField({
3249
+ type: "reference",
3250
+ name: "reference",
3251
+ to: [{ type: contextDocumentSchema.name }],
3252
+ title: "Context",
3253
+ description: "The referenced context will be inserted into the instruction",
3254
+ validation: (rule) => rule.required(),
3255
+ components: {
3256
+ input: function(props) {
3257
+ return /* @__PURE__ */ jsx(Box, { style: { maxWidth: 300 }, children: props.renderDefault(props) });
3258
+ }
3259
+ }
3260
+ })
3261
+ ],
3262
+ preview: {
3263
+ select: {
3264
+ ref: "reference._ref",
3265
+ title: "reference.title",
3266
+ context: "reference.context"
3267
+ },
3268
+ prepare(select) {
3269
+ var _a, _b, _c, _d;
3270
+ return select.ref ? (_d = (_c = (_b = (_a = contextDocumentSchema) == null ? void 0 : _a.preview) == null ? void 0 : _b.prepare) == null ? void 0 : _c.call(_b, select)) != null ? _d : select : { title: "No reference selected", media: contextDocumentSchema.icon };
3271
+ }
3272
+ },
3273
+ options: {
3274
+ modal: {
3275
+ type: "popover",
3276
+ width: "auto"
3277
+ }
3278
+ }
3279
+ }), prompt = defineType({
3280
+ type: "array",
3281
+ name: promptTypeName,
3282
+ title: "Prompt",
3283
+ of: [
3284
+ defineArrayMember({
3285
+ type: "block",
3286
+ styles: [{ title: "Normal", value: "normal" }],
3287
+ lists: [],
3288
+ marks: {
3289
+ decorators: [],
3290
+ annotations: []
3291
+ },
3292
+ of: [
3293
+ defineArrayMember({
3294
+ type: fieldReference.name
3295
+ }),
3296
+ defineArrayMember({
3297
+ type: promptContext.name
3298
+ }),
3299
+ defineArrayMember({
3300
+ type: userInput.name
3301
+ })
3302
+ ]
3303
+ })
3304
+ /* defineArrayMember({
3305
+ type: fieldReference.name,
3306
+ }),
3307
+ defineArrayMember({
3308
+ type: promptContext.name,
3309
+ }),
3310
+ defineArrayMember({
3311
+ type: userInput.name,
3312
+ }),*/
3313
+ ]
3314
+ }), outputFieldType = defineType({
3315
+ type: "object",
3316
+ name: outputFieldTypeName,
3317
+ title: "Output field",
3318
+ fields: [
3319
+ defineField({
3320
+ type: "string",
3321
+ name: "path",
3322
+ title: "Path"
3323
+ })
3324
+ ]
3325
+ }), outputTypeType = defineType({
3326
+ type: "object",
3327
+ name: outputTypeTypeName,
3328
+ title: "Output type",
3329
+ fields: [
3330
+ defineField({
3331
+ type: "string",
3332
+ name: "type",
3333
+ title: "Type"
3334
+ })
3335
+ ]
3336
+ }), instruction = defineType({
3337
+ type: "object",
3338
+ name: instructionTypeName,
3339
+ title: "Instruction",
3340
+ fieldsets: [
3341
+ { name: "appearance", title: "Appearance", options: { collapsible: !0, collapsed: !0 } }
3342
+ ],
3343
+ preview: {
3344
+ select: {
3345
+ icon: "icon",
3346
+ title: "title",
3347
+ userId: "userId"
3348
+ },
3349
+ prepare: ({ icon, title, userId }) => ({
3350
+ title,
3351
+ icon: icon ? icons[icon] : SparklesIcon,
3352
+ userId
3353
+ })
3354
+ },
3355
+ components: {
3356
+ input: InstructionInput,
3357
+ preview: (props) => /* @__PURE__ */ jsxs(Flex, { gap: 3, align: "center", padding: 2, children: [
3358
+ props.icon && /* @__PURE__ */ jsx(Box, { flex: "none", children: /* @__PURE__ */ jsx(Text, { size: 1, children: createElement(props.icon) }) }),
3359
+ /* @__PURE__ */ jsx(Stack, { flex: 1, space: 2, children: /* @__PURE__ */ jsx(Text, { size: 1, textOverflow: "ellipsis", weight: "medium", children: getInstructionTitle(props) }) }),
3360
+ props.userId && /* @__PURE__ */ jsx(Text, { size: 1, children: /* @__PURE__ */ jsx(
3361
+ Tooltip,
3362
+ {
3363
+ content: /* @__PURE__ */ jsx(Text, { size: 1, children: "Only visible to you" }),
3364
+ padding: 2,
3365
+ placement: "top",
3366
+ portal: !0,
3367
+ children: /* @__PURE__ */ jsx(LockIcon, {})
3368
+ }
3369
+ ) })
3370
+ ] })
3371
+ },
3372
+ fields: [
3373
+ defineField({
3374
+ type: prompt.name,
3375
+ name: "prompt",
3376
+ title: "Instruction",
3377
+ description: /* @__PURE__ */ jsxs(Fragment, { children: [
3378
+ "Learn from",
3379
+ " ",
3380
+ /* @__PURE__ */ jsxs("a", { href: instructionGuideUrl, target: "_blank", rel: "noreferrer", children: [
3381
+ "our instruction guide ",
3382
+ /* @__PURE__ */ jsx(ArrowRightIcon, {})
3383
+ ] })
3384
+ ] }),
3385
+ components: {
3386
+ input: PromptInput
3387
+ }
3388
+ }),
3389
+ defineField({
3390
+ type: "string",
3391
+ name: "icon",
3392
+ title: "Icon",
3393
+ fieldset: "appearance",
3394
+ components: {
3395
+ field: HiddenFieldTitle,
3396
+ input: IconInput
3397
+ }
3398
+ }),
3399
+ defineField({
3400
+ type: "string",
3401
+ name: "title",
3402
+ title: "Title",
3403
+ fieldset: "appearance",
3404
+ components: {
3405
+ field: HiddenFieldTitle
3406
+ }
3407
+ }),
3408
+ defineField({
3409
+ type: "string",
3410
+ name: "userId",
3411
+ title: "Visibility",
3412
+ fieldset: "appearance",
3413
+ components: {
3414
+ field: HiddenFieldTitle,
3415
+ input: InstructionVisibility
3416
+ },
3417
+ initialValue: (params, context) => {
3418
+ var _a, _b;
3419
+ return (_b = (_a = context.currentUser) == null ? void 0 : _a.id) != null ? _b : "";
3420
+ },
3421
+ readOnly: (context) => {
3422
+ var _a, _b, _c;
3423
+ return !!((_a = context.parent) != null && _a.createdById && ((_b = context.parent) == null ? void 0 : _b.createdById) !== ((_c = context.currentUser) == null ? void 0 : _c.id));
3424
+ }
3425
+ }),
3426
+ defineField({
3427
+ type: "string",
3428
+ name: "createdById",
3429
+ title: "Created by",
3430
+ hidden: !0,
3431
+ fieldset: "appearance",
3432
+ initialValue: (params, context) => {
3433
+ var _a, _b;
3434
+ return (_b = (_a = context.currentUser) == null ? void 0 : _a.id) != null ? _b : "";
3435
+ }
3436
+ }),
3437
+ defineField({
3438
+ type: "array",
3439
+ name: "output",
3440
+ title: "Output filter",
3441
+ components: {
3442
+ input: InstructionOutputInput,
3443
+ field: InstructionOutputField
3444
+ },
3445
+ of: [
3446
+ defineArrayMember({ type: outputFieldType.name }),
3447
+ defineArrayMember({ type: outputTypeType.name })
3448
+ ]
3449
+ })
3450
+ ]
3451
+ }), fieldInstructions = defineType({
3452
+ type: "object",
3453
+ name: assistFieldTypeName,
3454
+ title: "Field prompt",
3455
+ /* components: {
3456
+ input: FieldPromptInput,
3457
+ },*/
3458
+ fields: [
3459
+ defineField({
3460
+ type: "string",
3461
+ name: "path",
3462
+ title: "Path",
3463
+ readOnly: !0,
3464
+ hidden: !0
3465
+ }),
3466
+ defineField({
3467
+ type: "array",
3468
+ name: "instructions",
3469
+ title: "Instructions",
3470
+ of: [{ type: instruction.name }],
3471
+ components: {
3472
+ field: InstructionsArrayField,
3473
+ input: InstructionsArrayInput
3474
+ }
3475
+ })
3476
+ ],
3477
+ preview: {
3478
+ select: {
3479
+ title: "path"
3480
+ }
3481
+ }
3482
+ }), assistDocumentSchema = defineType({
3483
+ //NOTE: this is a document type. Using object here ensures it does not appear in structure menus
3484
+ type: "object",
3485
+ liveEdit: !0,
3486
+ name: assistDocumentTypeName,
3487
+ title: "AI Document",
3488
+ components: {
3489
+ input: AssistDocumentForm,
3490
+ field: (props) => props.renderDefault({ ...props, title: "" })
3491
+ },
3492
+ fields: [
3493
+ defineField({
3494
+ type: "string",
3495
+ name: "title",
3496
+ title: "Title"
3497
+ }),
3498
+ defineField({
3499
+ type: "array",
3500
+ name: "fields",
3501
+ title: "Fields",
3502
+ of: [{ type: fieldInstructions.name }]
3503
+ })
3504
+ ],
3505
+ preview: {
3506
+ select: {
3507
+ title: "title"
3508
+ }
3509
+ }
3510
+ }), instructionTask = defineType({
3511
+ type: "object",
3512
+ name: instructionTaskTypeName,
3513
+ title: "Instruction task",
3514
+ fields: [
3515
+ defineField({
3516
+ type: "string",
3517
+ name: "path",
3518
+ title: "Path"
3519
+ }),
3520
+ defineField({
3521
+ type: "string",
3522
+ name: "instructionKey",
3523
+ title: "Instruction key"
3524
+ }),
3525
+ defineField({
3526
+ type: "datetime",
3527
+ name: "started",
3528
+ title: "Started"
3529
+ }),
3530
+ defineField({
3531
+ type: "datetime",
3532
+ name: "updated",
3533
+ title: "Updated"
3534
+ }),
3535
+ defineField({
3536
+ type: "string",
3537
+ name: "info",
3538
+ title: "Info"
3539
+ })
3540
+ ]
3541
+ }), documentInstructionStatus = defineType({
3542
+ //NOTE: this is a document type. Using object here ensures it does not appear in structure menus
3543
+ type: "object",
3544
+ liveEdit: !0,
3545
+ name: assistTasksStatusTypeName,
3546
+ title: "Document instruction status",
3547
+ fields: [
3548
+ defineField({
3549
+ type: "array",
3550
+ name: "tasks",
3551
+ title: "Tasks",
3552
+ of: [{ type: instructionTask.name }]
3553
+ })
3554
+ ]
3555
+ });
3556
+ function excludeComments(type) {
3557
+ var _a, _b, _c;
3558
+ const existingRender = (_a = type == null ? void 0 : type.components) == null ? void 0 : _a.field;
3559
+ return {
3560
+ ...type,
3561
+ ..."components" in type ? {
3562
+ components: {
3563
+ ...type.components,
3564
+ field: (props) => {
3565
+ const newProps = { ...props, __internal_comments: void 0 };
3566
+ return typeof existingRender == "function" ? existingRender(newProps) : props.renderDefault(newProps);
3567
+ }
3568
+ }
3569
+ } : {},
3570
+ ..."fields" in type ? {
3571
+ // recursively disable comments in fields
3572
+ fields: (_b = type.fields) == null ? void 0 : _b.map((field) => excludeComments(field))
3573
+ } : {},
3574
+ ..."of" in type ? {
3575
+ // recursively disable comments in array items
3576
+ of: (_c = type.of) == null ? void 0 : _c.map((arrayItemType) => excludeComments(arrayItemType))
3577
+ } : {}
3578
+ };
3579
+ }
3580
+ const instructionForm = [
3581
+ fieldInstructions,
3582
+ instruction,
3583
+ fieldReference,
3584
+ prompt,
3585
+ userInput,
3586
+ promptContext
3587
+ ].map(excludeComments), schemaTypes = [
3588
+ ...instructionForm,
3589
+ outputFieldType,
3590
+ outputTypeType,
3591
+ assistDocumentSchema,
3592
+ documentInstructionStatus,
3593
+ instructionTask,
3594
+ contextDocumentSchema
3595
+ ];
3596
+ function useAssistDocumentContextValue(documentId, documentSchemaType) {
3597
+ const { published, draft } = useEditState(
3598
+ getPublishedId(documentId),
3599
+ documentSchemaType.name,
3600
+ "low"
3601
+ ), assistableDocumentId = (draft == null ? void 0 : draft._id) || (published == null ? void 0 : published._id) || documentId, documentIsNew = !(draft != null && draft._id) && !(published != null && published._id), documentIsAssistable = isDocAssistable(documentSchemaType, published, draft), { params } = useAiPaneRouter(), selectedPath = params[fieldPathParam], { openInspector, closeInspector, inspector, onChange: documentOnChange } = useDocumentPane(), assistDocument = useStudioAssistDocument({
3602
+ documentId,
3603
+ schemaType: documentSchemaType
3604
+ });
3605
+ return useMemo(() => {
3606
+ const base = {
3607
+ documentId,
3608
+ assistableDocumentId,
3609
+ documentSchemaType,
3610
+ documentIsNew,
3611
+ documentIsAssistable,
3612
+ openInspector,
3613
+ closeInspector,
3614
+ inspector,
3615
+ documentOnChange,
3616
+ selectedPath
3617
+ };
3618
+ return assistDocument ? {
3619
+ ...base,
3620
+ loading: !1,
3621
+ assistDocument
3622
+ } : { ...base, loading: !0, assistDocument: void 0 };
3623
+ }, [
3624
+ assistDocument,
3625
+ documentIsAssistable,
3626
+ documentId,
3627
+ assistableDocumentId,
3628
+ documentSchemaType,
3629
+ documentIsNew,
3630
+ openInspector,
3631
+ closeInspector,
3632
+ inspector,
3633
+ documentOnChange,
3634
+ selectedPath
3635
+ ]);
3636
+ }
3637
+ function useAssistSupported(path, schemaType) {
3638
+ return useMemo(() => isAssistSupported(schemaType), [schemaType]);
3639
+ }
3640
+ const translateActions = {
3641
+ name: "sanity-assist-translate",
3642
+ useAction(props) {
3643
+ var _a, _b, _c, _d, _e, _f, _g, _h;
3644
+ const { config, status } = useAiAssistanceConfig(), apiClient = useApiClient(config == null ? void 0 : config.__customApiClient), {
3645
+ schemaType: fieldSchemaType,
3646
+ path,
3647
+ documentId,
3648
+ documentSchemaType,
3649
+ documentIsAssistable
3650
+ } = props, isDocumentLevel = path.length === 0, readOnly = fieldSchemaType.readOnly === !0, docTransTypes = (_b = (_a = config.translate) == null ? void 0 : _a.document) == null ? void 0 : _b.documentTypes, options2 = fieldSchemaType == null ? void 0 : fieldSchemaType.options, addFieldAction = isDocumentLevel || ((_c = options2 == null ? void 0 : options2.aiAssist) == null ? void 0 : _c.translateAction), fieldTransEnabled = addFieldAction && documentSchemaType && ((_f = (_e = (_d = config.translate) == null ? void 0 : _d.field) == null ? void 0 : _e.documentTypes) == null ? void 0 : _f.includes(documentSchemaType.name)), documentTranslationEnabled = addFieldAction && documentSchemaType && (!docTransTypes && isAssistSupported(fieldSchemaType) || (docTransTypes == null ? void 0 : docTransTypes.includes(documentSchemaType.name)));
3651
+ if (documentSchemaType && (documentTranslationEnabled || fieldTransEnabled)) {
3652
+ const { value: documentValue, onChange: documentOnChange, formState } = useDocumentPane(), docRef = useRef(documentValue);
3653
+ docRef.current = documentValue;
3654
+ const formStateRef = useRef(formState);
3655
+ formStateRef.current = formState;
3656
+ const translationApi = useTranslate(apiClient), translate = useDraftDelayedTask({
3657
+ documentOnChange,
3658
+ isDocAssistable: documentIsAssistable != null ? documentIsAssistable : !1,
3659
+ task: translationApi.translate
3660
+ }), languagePath = (_h = (_g = config.translate) == null ? void 0 : _g.document) == null ? void 0 : _h.languageField, translateDocumentAction = useMemo(() => {
3661
+ if (!languagePath || !documentTranslationEnabled)
3662
+ return;
3663
+ const title = path.length ? "Translate" : "Translate document";
3664
+ return {
3665
+ type: "action",
3666
+ icon: translationApi.loading ? () => /* @__PURE__ */ jsx(Box, { style: { height: 17 }, children: /* @__PURE__ */ jsx(Spinner, { style: { transform: "translateY(6px)" } }) }) : TranslateIcon,
3667
+ title,
3668
+ onAction: () => {
3669
+ translationApi.loading || !languagePath || !documentId || translate({
3670
+ languagePath,
3671
+ translatePath: path,
3672
+ documentId: documentId != null ? documentId : "",
3673
+ conditionalMembers: formStateRef.current ? getConditionalMembers(formStateRef.current) : []
3674
+ });
3675
+ },
3676
+ renderAsButton: !0,
3677
+ disabled: translationApi.loading || readOnly
3678
+ };
3679
+ }, [
3680
+ languagePath,
3681
+ translate,
3682
+ documentId,
3683
+ translationApi.loading,
3684
+ documentTranslationEnabled,
3685
+ path,
3686
+ readOnly
3687
+ ]), fieldTranslate = useFieldTranslation(), openFieldTranslation = useDraftDelayedTask({
3688
+ documentOnChange,
3689
+ isDocAssistable: documentIsAssistable != null ? documentIsAssistable : !1,
3690
+ task: fieldTranslate.openFieldTranslation
3691
+ }), translateFieldsAction = useMemo(
3692
+ () => fieldTransEnabled ? {
3693
+ type: "action",
3694
+ icon: fieldTranslate.translationLoading ? () => /* @__PURE__ */ jsx(Box, { style: { height: 17 }, children: /* @__PURE__ */ jsx(Spinner, { style: { transform: "translateY(6px)" } }) }) : TranslateIcon,
3695
+ title: "Translate fields...",
3696
+ onAction: () => {
3697
+ fieldTranslate.translationLoading || !documentId || (formStateRef.current && getConditionalMembers(formStateRef.current), openFieldTranslation({
3698
+ document: docRef.current,
3699
+ documentSchema: documentSchemaType,
3700
+ translatePath: path,
3701
+ conditionalMembers: formStateRef.current ? getConditionalMembers(formStateRef.current) : []
3702
+ }));
3703
+ },
3704
+ renderAsButton: !0,
3705
+ disabled: fieldTranslate.translationLoading || readOnly
3706
+ } : void 0,
3707
+ [
3708
+ openFieldTranslation,
3709
+ documentSchemaType,
3710
+ documentId,
3711
+ fieldTranslate.translationLoading,
3712
+ fieldTransEnabled,
3713
+ path,
3714
+ readOnly
3715
+ ]
3716
+ );
3717
+ return useMemo(() => {
3718
+ if (status != null && status.initialized)
3719
+ return {
3720
+ type: "group",
3721
+ icon: () => null,
3722
+ title: "Translation",
3723
+ children: [translateDocumentAction, translateFieldsAction].filter(
3724
+ (c) => !!c
3725
+ ),
3726
+ expanded: !0
3727
+ };
3728
+ }, [translateDocumentAction, translateFieldsAction, status]);
3729
+ }
3730
+ }
3731
+ }, ImageContext = createContext({});
3732
+ function ImageContextProvider(props) {
3733
+ var _a, _b;
3734
+ const { schemaType, path, value, readOnly } = props, assetRef = (_a = value == null ? void 0 : value.asset) == null ? void 0 : _a._ref, [assetRefState, setAssetRefState] = useState(assetRef), { documentId, documentSchemaType } = useAssistDocumentContext(), { config, status } = useAiAssistanceConfig(), apiClient = useApiClient(config == null ? void 0 : config.__customApiClient), { generateCaption } = useGenerateCaption(apiClient), { isSyncing } = useSyncState(publicId(documentId), documentSchemaType.name), isShowingOlderRevision = !!((_b = usePaneRouter().params) != null && _b.rev);
3735
+ useEffect(() => {
3736
+ const descriptionField = getDescriptionFieldOption(schemaType);
3737
+ assetRef && documentId && descriptionField && assetRef !== assetRefState && !isSyncing && !isShowingOlderRevision && !readOnly && (setAssetRefState(assetRef), canUseAssist(status) && generateCaption({ path: pathToString([...path, descriptionField]), documentId }));
3738
+ }, [
3739
+ schemaType,
3740
+ path,
3741
+ assetRef,
3742
+ assetRefState,
3743
+ documentId,
3744
+ generateCaption,
3745
+ isSyncing,
3746
+ status,
3747
+ readOnly,
3748
+ isShowingOlderRevision
3749
+ ]);
3750
+ const context = useMemo(() => {
3751
+ const descriptionField = getDescriptionFieldOption(schemaType), imageInstructionField = getImageInstructionFieldOption(schemaType);
3752
+ return {
3753
+ imageDescriptionPath: descriptionField ? pathToString([...path, descriptionField]) : void 0,
3754
+ imageInstructionPath: imageInstructionField ? pathToString([...path, imageInstructionField]) : void 0,
3755
+ assetRef
3756
+ };
3757
+ }, [schemaType, path, assetRef]);
3758
+ return /* @__PURE__ */ jsx(ImageContext.Provider, { value: context, children: props.renderDefault(props) });
3759
+ }
3760
+ const generateCaptionsActions = {
3761
+ name: "sanity-assist-generate-captions",
3762
+ useAction(props) {
3763
+ const pathKey = usePathKey(props.path), { openInspector } = useDocumentPane(), { config, status } = useAiAssistanceConfig(), apiClient = useApiClient(config == null ? void 0 : config.__customApiClient), { generateCaption, loading } = useGenerateCaption(apiClient), imageContext = useContext(ImageContext);
3764
+ if (imageContext && pathKey === (imageContext == null ? void 0 : imageContext.imageDescriptionPath)) {
3765
+ const { documentId } = useAssistDocumentContext();
3766
+ return useMemo(() => ({
3767
+ type: "action",
3768
+ icon: loading ? () => /* @__PURE__ */ jsx(Box, { style: { height: 17 }, children: /* @__PURE__ */ jsx(Spinner, { style: { transform: "translateY(6px)" } }) }) : ImageIcon,
3769
+ title: "Generate image description",
3770
+ onAction: () => {
3771
+ if (!loading) {
3772
+ if (!canUseAssist(status)) {
3773
+ openInspector(aiInspectorId, {
3774
+ [fieldPathParam]: pathKey,
3775
+ [instructionParam]: void 0
3776
+ });
3777
+ return;
3778
+ }
3779
+ generateCaption({ path: pathKey, documentId: documentId != null ? documentId : "" });
3780
+ }
3781
+ },
3782
+ renderAsButton: !0,
3783
+ disabled: loading,
3784
+ hidden: !imageContext.assetRef
3785
+ }), [generateCaption, pathKey, documentId, loading, imageContext, status, openInspector]);
3786
+ }
3787
+ }
3788
+ }, generateImagActions = {
3789
+ name: "sanity-assist-generate-image",
3790
+ useAction(props) {
3791
+ const pathKey = usePathKey(props.path), { config } = useAiAssistanceConfig(), apiClient = useApiClient(config == null ? void 0 : config.__customApiClient), { generateImage, loading } = useGenerateImage(apiClient), imageContext = useContext(ImageContext);
3792
+ if (imageContext && pathKey === (imageContext == null ? void 0 : imageContext.imageInstructionPath)) {
3793
+ const { documentId } = useAssistDocumentContext();
3794
+ return useMemo(() => ({
3795
+ type: "action",
3796
+ icon: loading ? () => /* @__PURE__ */ jsx(Box, { style: { height: 17 }, children: /* @__PURE__ */ jsx(Spinner, { style: { transform: "translateY(6px)" } }) }) : ImageIcon,
3797
+ title: "Generate image from prompt",
3798
+ onAction: () => {
3799
+ loading || generateImage({ path: pathKey, documentId: documentId != null ? documentId : "" });
3800
+ },
3801
+ renderAsButton: !0,
3802
+ disabled: loading
3803
+ }), [generateImage, pathKey, documentId, loading]);
3804
+ }
3805
+ }
3806
+ };
3807
+ function PrivateIcon() {
3808
+ return /* @__PURE__ */ jsx(
3809
+ Tooltip,
3810
+ {
3811
+ content: /* @__PURE__ */ jsx(Text, { size: 1, style: { whiteSpace: "nowrap" }, children: "Only visible to you" }),
3812
+ fallbackPlacements: ["bottom"],
3813
+ padding: 2,
3814
+ placement: "top",
3815
+ portal: !0,
3816
+ children: /* @__PURE__ */ jsx(LockIcon, {})
3817
+ }
3818
+ );
3819
+ }
3820
+ const assistFieldActions = {
3821
+ name: "sanity-assist-actions",
3822
+ useAction(props) {
3823
+ const { schemaType } = props, isDocumentLevel = props.path.length === 0, {
3824
+ assistDocument,
3825
+ documentIsNew,
3826
+ documentIsAssistable,
3827
+ openInspector,
3828
+ closeInspector,
3829
+ inspector,
3830
+ documentOnChange,
3831
+ documentSchemaType,
3832
+ documentId,
3833
+ selectedPath,
3834
+ assistableDocumentId
3835
+ } = (
3836
+ // document field actions do not have access to the document context
3837
+ // conditional hook _should_ be safe here since the logical path will be stable
3838
+ isDocumentLevel ? (
3839
+ // eslint-disable-next-line react-hooks/rules-of-hooks
3840
+ useAssistDocumentContextValue(props.documentId, schemaType)
3841
+ ) : (
3842
+ // eslint-disable-next-line react-hooks/rules-of-hooks
3843
+ useAssistDocumentContext()
3844
+ )
3845
+ ), { value: docValue, formState } = useDocumentPane(), formStateRef = useRef(formState);
3846
+ formStateRef.current = formState;
3847
+ const currentUser = useCurrentUser(), isHidden = !assistDocument, pathKey = usePathKey(props.path), typePath = useTypePath(docValue, pathKey), assistDocumentId2 = assistDocument == null ? void 0 : assistDocument._id, assistableDocId = getAssistableDocId(documentSchemaType, documentId), { requestRunInstruction } = useRequestRunInstruction({
3848
+ documentOnChange,
3849
+ isDocAssistable: documentIsAssistable != null ? documentIsAssistable : !1
3850
+ }), isSelectable = !!useSelectedField(documentSchemaType, typePath), assistSupported = useAssistSupported(props.path, schemaType) && isSelectable && isSchemaAssistEnabled(documentSchemaType) && schemaType.readOnly !== !0, fieldAssist = useMemo(
3851
+ () => {
3852
+ var _a;
3853
+ return ((_a = assistDocument == null ? void 0 : assistDocument.fields) != null ? _a : []).find(
3854
+ (f) => f.path === typePath || pathKey === documentRootKey && f.path === pathKey
3855
+ );
3856
+ },
3857
+ [assistDocument == null ? void 0 : assistDocument.fields, pathKey, typePath]
3858
+ ), fieldAssistKey = fieldAssist == null ? void 0 : fieldAssist._key, isSelected = (inspector == null ? void 0 : inspector.name) === aiInspectorId && pathKey === selectedPath, imageCaptionAction = generateCaptionsActions.useAction(props), imageGenAction = generateImagActions.useAction(props), translateAction = translateActions.useAction(
3859
+ typed({
3860
+ ...props,
3861
+ documentId: assistableDocumentId,
3862
+ documentIsAssistable,
3863
+ documentSchemaType
3864
+ })
3865
+ ), manageInstructions = useCallback(
3866
+ () => isSelected ? closeInspector(aiInspectorId) : openInspector(aiInspectorId, {
3867
+ [fieldPathParam]: pathKey,
3868
+ [instructionParam]: void 0
3869
+ }),
3870
+ [openInspector, closeInspector, isSelected, pathKey]
3871
+ ), onInstructionAction = useCallback(
3872
+ (instruction2) => {
3873
+ !pathKey || !fieldAssistKey || !assistDocumentId2 || !assistableDocId || requestRunInstruction({
3874
+ documentId: assistableDocId,
3875
+ assistDocumentId: assistDocumentId2,
3876
+ path: pathKey,
3877
+ typePath,
3878
+ instruction: instruction2,
3879
+ conditionalMembers: formStateRef.current ? getConditionalMembers(formStateRef.current) : []
3880
+ });
3881
+ },
3882
+ [requestRunInstruction, assistableDocId, pathKey, typePath, assistDocumentId2, fieldAssistKey]
3883
+ ), privateInstructions = useMemo(
3884
+ () => {
3885
+ var _a;
3886
+ return ((_a = fieldAssist == null ? void 0 : fieldAssist.instructions) == null ? void 0 : _a.filter((i) => i.userId && i.userId === (currentUser == null ? void 0 : currentUser.id))) || [];
3887
+ },
3888
+ [fieldAssist == null ? void 0 : fieldAssist.instructions, currentUser]
3889
+ ), sharedInstructions = useMemo(
3890
+ () => {
3891
+ var _a;
3892
+ return ((_a = fieldAssist == null ? void 0 : fieldAssist.instructions) == null ? void 0 : _a.filter((i) => !i.userId)) || [];
3893
+ },
3894
+ [fieldAssist == null ? void 0 : fieldAssist.instructions]
3895
+ ), instructions = useMemo(
3896
+ () => [...privateInstructions, ...sharedInstructions],
3897
+ [privateInstructions, sharedInstructions]
3898
+ ), runInstructionsGroup = useMemo(() => instructions != null && instructions.length || imageCaptionAction || translateAction || imageGenAction ? {
3899
+ type: "group",
3900
+ icon: () => null,
3901
+ title: "Run instructions",
3902
+ children: [
3903
+ ...(instructions == null ? void 0 : instructions.map(
3904
+ (instruction2) => instructionItem({
3905
+ instruction: instruction2,
3906
+ isPrivate: !!(instruction2.userId && instruction2.userId === (currentUser == null ? void 0 : currentUser.id)),
3907
+ onInstructionAction,
3908
+ hidden: isHidden,
3909
+ documentIsNew: !!documentIsNew,
3910
+ assistSupported
3911
+ })
3912
+ )) || [],
3913
+ imageCaptionAction,
3914
+ imageGenAction
3915
+ ].filter((a) => !!a),
3916
+ expanded: !0
3917
+ } : void 0, [
3918
+ instructions,
3919
+ currentUser == null ? void 0 : currentUser.id,
3920
+ onInstructionAction,
3921
+ isHidden,
3922
+ documentIsNew,
3923
+ assistSupported,
3924
+ imageCaptionAction,
3925
+ translateAction,
3926
+ imageGenAction
3927
+ ]), instructionsLength = (instructions == null ? void 0 : instructions.length) || 0, manageInstructionsItem = useMemo(
3928
+ () => ({
3929
+ type: "action",
3930
+ icon: ControlsIcon,
3931
+ title: "Manage instructions",
3932
+ onAction: manageInstructions,
3933
+ selected: isSelected
3934
+ }),
3935
+ [manageInstructions, isSelected]
3936
+ ), group = useMemo(
3937
+ () => ({
3938
+ type: "group",
3939
+ icon: SparklesIcon,
3940
+ title: pluginTitleShort,
3941
+ children: [
3942
+ runInstructionsGroup,
3943
+ translateAction,
3944
+ assistSupported && manageInstructionsItem
3945
+ ].filter((c) => !!c).filter((c) => c.type === "group" ? c.children.length : !0),
3946
+ expanded: !1,
3947
+ renderAsButton: !0,
3948
+ hidden: !assistSupported && !imageCaptionAction && !translateAction && !imageGenAction
3949
+ }),
3950
+ [
3951
+ //documentIsNew,
3952
+ runInstructionsGroup,
3953
+ manageInstructionsItem,
3954
+ assistSupported,
3955
+ imageCaptionAction,
3956
+ translateAction,
3957
+ imageGenAction
3958
+ ]
3959
+ ), emptyAction = useMemo(
3960
+ () => ({
3961
+ type: "action",
3962
+ hidden: !assistSupported,
3963
+ icon: SparklesIcon,
3964
+ onAction: manageInstructions,
3965
+ renderAsButton: !0,
3966
+ title: pluginTitleShort,
3967
+ selected: isSelected
3968
+ }),
3969
+ [assistSupported, manageInstructions, isSelected]
3970
+ );
3971
+ return instructionsLength === 0 && !imageCaptionAction && !translateAction && !imageGenAction ? emptyAction : group;
3972
+ }
3973
+ };
3974
+ function instructionItem(props) {
3975
+ const { hidden, isPrivate, onInstructionAction, assistSupported, instruction: instruction2 } = props;
3976
+ return {
3977
+ type: "action",
3978
+ icon: getIcon(instruction2.icon),
3979
+ iconRight: isPrivate ? PrivateIcon : void 0,
3980
+ title: getInstructionTitle(instruction2),
3981
+ onAction: () => onInstructionAction(instruction2),
3982
+ disabled: !assistSupported,
3983
+ hidden
3984
+ };
3985
+ }
3986
+ function AssistDocumentContextProvider(props) {
3987
+ const { documentId, schemaType } = props, value = useAssistDocumentContextValue(documentId, schemaType);
3988
+ return /* @__PURE__ */ jsx(AssistDocumentContext.Provider, { value, children: props.children });
3989
+ }
3990
+ const NO_TASKS = [];
3991
+ function useInstructionToaster(documentId, documentSchemaType) {
3992
+ const assistDocument = useStudioAssistDocument({ documentId, schemaType: documentSchemaType }), assistDocLoaded = !!assistDocument, currentUser = useCurrentUser(), toast = useToast(), tasks = assistDocument == null ? void 0 : assistDocument.tasks, previousTasks = useRef("initial");
3993
+ useEffect(() => {
3994
+ var _a;
3995
+ if (assistDocLoaded) {
3996
+ if (previousTasks.current !== "initial") {
3997
+ const prevTaskByKey = Object.fromEntries(
3998
+ ((_a = previousTasks.current) != null ? _a : NO_TASKS).map((run) => [run._key, run])
3999
+ ), endedTasks = tasks == null ? void 0 : tasks.filter((task) => task.startedByUserId === (currentUser == null ? void 0 : currentUser.id)).filter((task) => {
4000
+ const prevTask = prevTaskByKey[task._key];
4001
+ return !prevTask && task.ended || !(prevTask != null && prevTask.ended) && task.ended;
4002
+ }).filter((task) => task.ended && isAfter(addSeconds(new Date(task.ended), 30), /* @__PURE__ */ new Date()));
4003
+ endedTasks == null || endedTasks.forEach((task) => {
4004
+ var _a2, _b;
4005
+ const title = (_a2 = task.title) != null ? _a2 : getInstructionTitle(task.instruction);
4006
+ task.reason === "error" ? toast.push({
4007
+ title: `Failed: ${title}`,
4008
+ status: "error",
4009
+ description: `Instruction failed. ${(_b = task.message) != null ? _b : ""}`,
4010
+ closable: !0,
4011
+ duration: 1e4
4012
+ }) : task.reason === "timeout" ? toast.push({
4013
+ title: `Timeout: ${title}`,
4014
+ status: "error",
4015
+ description: "Instruction timed out.",
4016
+ closable: !0
4017
+ }) : task.reason === "success" ? toast.push({
4018
+ title: `Success: ${title}`,
4019
+ status: "success",
4020
+ description: "Instruction completed.",
4021
+ closable: !0
4022
+ }) : task.reason === "aborted" && toast.push({
4023
+ title: `Canceled: ${title}`,
4024
+ status: "warning",
4025
+ description: "Instruction canceled.",
4026
+ closable: !0
4027
+ });
4028
+ });
4029
+ }
4030
+ previousTasks.current = tasks;
4031
+ }
4032
+ }, [tasks, previousTasks, toast, currentUser, assistDocLoaded]);
4033
+ }
4034
+ function AssistDocumentInputWrapper(props) {
4035
+ var _a;
4036
+ if (!isType(props.schemaType, "document") && props.id !== "root" && props.id !== assistFormId)
4037
+ return /* @__PURE__ */ jsx(AssistInput, { ...props });
4038
+ const documentId = (_a = props.value) == null ? void 0 : _a._id;
4039
+ return documentId ? /* @__PURE__ */ jsx(AssistDocumentInput, { ...props, documentId }) : props.renderDefault(props);
4040
+ }
4041
+ function AssistDocumentInput({ documentId, ...props }) {
4042
+ useInstructionToaster(documentId, props.schemaType);
4043
+ const schemaType = useMemo(() => props.schemaType.name !== assistDocumentTypeName ? props.schemaType : {
4044
+ ...props.schemaType,
4045
+ type: {
4046
+ ...props.schemaType.type,
4047
+ // compatability with i18nArrays plugin that requires this to be document
4048
+ name: "document"
4049
+ }
4050
+ }, [props.schemaType]);
4051
+ return /* @__PURE__ */ jsx(FirstAssistedPathProvider, { members: props.members, children: /* @__PURE__ */ jsx(AssistDocumentContextProvider, { schemaType, documentId, children: props.renderDefault({
4052
+ ...props,
4053
+ schemaType
4054
+ }) }) });
4055
+ }
4056
+ function AssistInput(props) {
4057
+ const { zIndex } = useLayer(), { paneKey } = useDocumentPane(), pathKey = usePathKey(props.path);
4058
+ return /* @__PURE__ */ jsx(ConnectFromRegion, { _key: `${paneKey}_${pathKey}`, zIndex, style: { minWidth: 0 }, children: props.renderDefault(props) });
4059
+ }
4060
+ function createAssistDocumentPresence(documentId, schemaType) {
4061
+ return function() {
4062
+ return documentId ? /* @__PURE__ */ jsx(AssistDocumentPresence, { documentId, schemaType }) : null;
4063
+ };
4064
+ }
4065
+ function AssistDocumentPresence(props) {
4066
+ const { assistDocument } = useAssistDocumentContextValue(
4067
+ props.documentId,
4068
+ props.schemaType
4069
+ ), anyPresence = useMemo(() => {
4070
+ var _a, _b, _c, _d;
4071
+ const anyPresence2 = (_b = (_a = assistDocument == null ? void 0 : assistDocument.tasks) == null ? void 0 : _a.filter((run) => !run.ended && !run.reason)) == null ? void 0 : _b.flatMap((run) => {
4072
+ var _a2;
4073
+ return (_a2 = run.presence) != null ? _a2 : [];
4074
+ }).find((f) => f.started && (/* @__PURE__ */ new Date()).getTime() - new Date(f.started).getTime() < 3e4);
4075
+ if (anyPresence2)
4076
+ return aiPresence(anyPresence2, []);
4077
+ const anyRun = (_d = (_c = assistDocument == null ? void 0 : assistDocument.tasks) == null ? void 0 : _c.filter((run) => !run.ended && !run.reason)) == null ? void 0 : _d.find((f) => f.started && (/* @__PURE__ */ new Date()).getTime() - new Date(f.started).getTime() < 3e4);
4078
+ return anyRun ? aiPresence(
4079
+ {
4080
+ started: anyRun.started,
4081
+ path: documentRootKey,
4082
+ _key: anyRun._key,
4083
+ _type: fieldPresenceTypeName
4084
+ },
4085
+ []
4086
+ ) : void 0;
4087
+ }, [assistDocument == null ? void 0 : assistDocument.tasks]);
4088
+ return /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx(Flex, { flex: 1, justify: "flex-end", children: /* @__PURE__ */ jsx(Flex, { gap: 2, align: "center", children: anyPresence && /* @__PURE__ */ jsx(AiFieldPresence, { presence: anyPresence }) }) }) });
4089
+ }
4090
+ const assist = definePlugin((config) => {
4091
+ const configWithDefaults = config != null ? config : {};
4092
+ return {
4093
+ name: packageName,
4094
+ schema: {
4095
+ types: schemaTypes
4096
+ },
4097
+ i18n: {
4098
+ bundles: [{}]
4099
+ },
4100
+ document: {
4101
+ inspectors: (prev, context) => {
4102
+ const documentType = context.documentType, docSchema = context.schema.get(documentType);
4103
+ return docSchema && isSchemaAssistEnabled(docSchema) ? [...prev, assistInspector] : prev;
4104
+ },
4105
+ unstable_fieldActions: (prev, { documentType, schema }) => {
4106
+ if (documentType === assistDocumentTypeName)
4107
+ return [];
4108
+ const docSchema = schema.get(documentType);
4109
+ return docSchema && isSchemaAssistEnabled(docSchema) ? [...prev, assistFieldActions] : prev;
4110
+ },
4111
+ unstable_languageFilter: (prev, { documentId, schema, schemaType }) => {
4112
+ if (schemaType === assistDocumentTypeName)
4113
+ return [];
4114
+ const docSchema = schema.get(schemaType);
4115
+ return docSchema && isObjectSchemaType(docSchema) && isSchemaAssistEnabled(docSchema) ? [...prev, createAssistDocumentPresence(documentId, docSchema)] : prev;
4116
+ }
4117
+ },
4118
+ studio: {
4119
+ components: {
4120
+ layout: function(props) {
4121
+ return /* @__PURE__ */ jsx(AssistLayout, { ...props, config: configWithDefaults });
4122
+ }
4123
+ }
4124
+ },
4125
+ form: {
4126
+ components: {
4127
+ input: AssistDocumentInputWrapper,
4128
+ field: AssistFieldWrapper,
4129
+ item: AssistItem,
4130
+ block: AssistFormBlock,
4131
+ inlineBlock: AssistInlineFormBlock
4132
+ }
4133
+ },
4134
+ plugins: [
4135
+ definePlugin({
4136
+ name: `${packageName}/safe-value-input`,
4137
+ form: { components: { input: SafeValueInput } }
4138
+ })(),
4139
+ definePlugin({
4140
+ name: `${packageName}/generate-caption`,
4141
+ form: {
4142
+ components: {
4143
+ input: (props) => {
4144
+ const { schemaType } = props;
4145
+ return isImage(schemaType) ? /* @__PURE__ */ jsx(ImageContextProvider, { ...props }) : props.renderDefault(props);
4146
+ }
4147
+ }
4148
+ }
4149
+ })()
4150
+ ]
4151
+ };
4152
+ });
4153
+ export {
4154
+ SchemaTypeTool,
4155
+ assist,
4156
+ contextDocumentTypeName,
4157
+ defaultLanguageOutputs
4158
+ };
4159
+ //# sourceMappingURL=index.mjs.map