@sanity/assist 2.0.5 → 3.0.1

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