@sanity/assist 5.0.3 → 6.0.0

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