@sanity/assist 5.0.4 → 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 +3181 -2649
  6. package/dist/index.js.map +1 -1
  7. package/package.json +38 -78
  8. package/dist/index.cjs +0 -4239
  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 -287
  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 -127
  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 -419
  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,4239 +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"), color = require("@sanity/color"), operators = require("rxjs/operators"), get = require("lodash/get.js"), getRandomValues = require("get-random-values-esm"), 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), getRandomValues__default = /* @__PURE__ */ _interopDefaultCompat(getRandomValues), 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
- editState
880
- } = structure.useDocumentPane(), { selectedReleaseId } = sanity.usePerspective(), { 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({
881
- documentId: assistableDocumentId,
882
- schemaType: documentSchemaType
883
- }), { syntheticTasks, addSyntheticTask, removeSyntheticTask } = useSyntheticTasks(assistableDocumentId);
884
- return react.useMemo(() => {
885
- const base = {
886
- assistableDocumentId,
887
- documentSchemaType,
888
- documentIsNew,
889
- documentIsAssistable,
890
- openInspector,
891
- closeInspector,
892
- inspector,
893
- documentOnChange,
894
- selectedPath,
895
- syntheticTasks,
896
- addSyntheticTask,
897
- removeSyntheticTask,
898
- fieldRefs,
899
- fieldRefsByTypePath
900
- };
901
- return assistDocument ? {
902
- ...base,
903
- loading: !1,
904
- assistDocument
905
- } : { ...base, loading: !0, assistDocument: void 0 };
906
- }, [
907
- assistDocument,
908
- documentIsAssistable,
909
- assistableDocumentId,
910
- documentSchemaType,
911
- documentIsNew,
912
- openInspector,
913
- closeInspector,
914
- inspector,
915
- documentOnChange,
916
- selectedPath,
917
- syntheticTasks,
918
- addSyntheticTask,
919
- removeSyntheticTask,
920
- fieldRefs,
921
- fieldRefsByTypePath
922
- ]);
923
- }
924
- function useSyntheticTasks(assistableDocumentId) {
925
- const [syntheticTasks, setSyntheticTasks] = react.useState(() => []), addSyntheticTask = react.useCallback((task) => {
926
- setSyntheticTasks((current) => [...current, task]);
927
- }, []), removeSyntheticTask = react.useCallback((task) => {
928
- setSyntheticTasks((current) => current.filter((t) => task._key !== t._key));
929
- }, []);
930
- return react.useEffect(() => {
931
- setSyntheticTasks([]);
932
- }, [assistableDocumentId]), {
933
- syntheticTasks,
934
- addSyntheticTask,
935
- removeSyntheticTask
936
- };
937
- }
938
- function AssistDocumentContextProvider(props) {
939
- const { documentId, documentType } = props, value = useAssistDocumentContextValue(documentId, documentType);
940
- return /* @__PURE__ */ jsxRuntime.jsx(AssistDocumentContext.Provider, { value, children: props.children });
941
- }
942
- function AssistDocumentLayout(props) {
943
- const { documentId, documentType } = props;
944
- return /* @__PURE__ */ jsxRuntime.jsx(AssistDocumentContextProvider, { documentType, documentId, children: props.renderDefault(props) });
945
- }
946
- const fadeIn = styledComponents.keyframes`
947
- 0% {
948
- opacity: 0;
949
- transform: scale(0.75);
950
- }
951
- 40% {
952
- opacity: 0;
953
- transform: scale(0.75);
954
- }
955
- 100% {
956
- opacity: 1;
957
- transform: scale(1);
958
- }
959
- `, FadeInDiv = styledComponents.styled.div`
960
- animation-name: ${fadeIn};
961
- animation-timing-function: ease-in-out;
962
- `, FadeInContent = react.forwardRef(function({
963
- children,
964
- durationMs = 250
965
- }, ref) {
966
- return /* @__PURE__ */ jsxRuntime.jsx(FadeInDiv, { ref, style: { animationDuration: `${durationMs}ms` }, children });
967
- }), Root = styledComponents.styled.span`
968
- display: block;
969
- width: 25px;
970
- height: 25px;
971
- position: relative;
972
- `, dash = styledComponents.keyframes`
973
- 0% {
974
- transform: rotate(0);
975
- }
976
- 100% {
977
- transform: rotate(43deg);
978
- }
979
- `, Outline = styledComponents.styled.svg`
980
- display: block;
981
- position: absolute;
982
- top: 0;
983
- left: 0;
984
-
985
- & > circle {
986
- stroke: var(--ai-avatar-stroke-color);
987
- stroke-width: 1.5px;
988
- stroke-linecap: round;
989
- transform-origin: center;
990
- animation: ${dash} 500ms ease-in-out infinite;
991
- transition: stroke-dasharray 200ms ease-in-out;
992
-
993
- stroke-dasharray: 2.34px 0;
994
-
995
- [data-state='active'] > & {
996
- stroke-dasharray: 2px 2.34px;
997
- }
998
- }
999
- `, IconDisc = styledComponents.styled.span`
1000
- background: var(--ai-avatar-disc-color);
1001
- color: white;
1002
- width: 21px;
1003
- height: 21px;
1004
- display: flex;
1005
- align-items: center;
1006
- justify-content: center;
1007
- border-radius: 10.5px;
1008
- position: absolute;
1009
- top: 2px;
1010
- left: 2px;
1011
- `;
1012
- function AssistAvatar(props) {
1013
- const { state = "present" } = props, scheme = sanity.useColorSchemeValue(), style = react.useMemo(() => scheme === "dark" ? {
1014
- "--ai-avatar-stroke-color": color.purple[400].hex,
1015
- "--ai-avatar-disc-color": color.purple[600].hex
1016
- } : {
1017
- "--ai-avatar-stroke-color": color.purple[500].hex,
1018
- "--ai-avatar-disc-color": color.purple[600].hex
1019
- }, [scheme]);
1020
- return /* @__PURE__ */ jsxRuntime.jsxs(Root, { "data-state": state, style, children: [
1021
- /* @__PURE__ */ jsxRuntime.jsx(
1022
- Outline,
1023
- {
1024
- width: "25",
1025
- height: "25",
1026
- viewBox: "0 0 25 25",
1027
- fill: "none",
1028
- xmlns: "http://www.w3.org/2000/svg",
1029
- children: /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12.5", cy: "12.5", r: "11.75" })
1030
- }
1031
- ),
1032
- /* @__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" } }) }) })
1033
- ] });
1034
- }
1035
- function AiFieldPresence(props) {
1036
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { style: { position: "relative", background: "transparent" }, contentEditable: !1, children: /* @__PURE__ */ jsxRuntime.jsx(
1037
- ui.Tooltip,
1038
- {
1039
- placement: "left",
1040
- 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..." }) }) }),
1041
- children: /* @__PURE__ */ jsxRuntime.jsx(FadeInContent, { durationMs: 300, children: /* @__PURE__ */ jsxRuntime.jsx(AssistAvatar, { state: "active" }) })
1042
- }
1043
- ) });
1044
- }
1045
- const NO_PRESENCE = [];
1046
- function useAssistPresence(path, showFocusWithin) {
1047
- const context = useAssistDocumentContext(), tasks = (context && "assistDocument" in context ? context.assistDocument : void 0)?.tasks;
1048
- return react.useMemo(() => {
1049
- const activePresence = tasks?.filter((task) => !task.ended)?.flatMap((task) => task.presence ?? [])?.filter(
1050
- (p) => p.started && (/* @__PURE__ */ new Date()).getTime() - new Date(p.started).getTime() < maxHistoryVisibilityMs
1051
- ).filter((presence) => {
1052
- if (!presence.path || !path.length)
1053
- return !1;
1054
- const statusPath = sanity.stringToPath(presence.path);
1055
- return !showFocusWithin && statusPath.length !== path.length ? !1 : path.every((pathSegment, i) => {
1056
- const statusSegment = statusPath[i];
1057
- return typeof pathSegment == "string" ? pathSegment === statusSegment : sanity.isKeySegment(pathSegment) && sanity.isKeySegment(statusSegment) ? pathSegment._key === statusSegment._key : !1;
1058
- });
1059
- });
1060
- return activePresence?.length ? activePresence.map((status) => aiPresence(status, path)) : NO_PRESENCE;
1061
- }, [showFocusWithin, tasks, path]);
1062
- }
1063
- function aiPresence(presence, path, title) {
1064
- return {
1065
- user: {
1066
- id: `sanity-assistant_${presence._key}`,
1067
- displayName: pluginTitle
1068
- },
1069
- path,
1070
- sessionId: "not-available",
1071
- lastActiveAt: presence?.started ?? (/* @__PURE__ */ new Date()).toISOString()
1072
- };
1073
- }
1074
- function AssistFieldWrapper(props) {
1075
- const { schemaType } = props;
1076
- 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);
1077
- }
1078
- function AssistField(props) {
1079
- const isPortableText = react.useMemo(
1080
- () => !!(sanity.isArraySchemaType(props.schemaType) && isPortableTextArray(props.schemaType)),
1081
- [props.schemaType]
1082
- ), 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 }) }) });
1083
- return props.renderDefault({
1084
- ...props,
1085
- actions: props.actions,
1086
- // Render presence in the internal slot (between presence and the field actions)
1087
- // eslint-disable-next-line camelcase
1088
- __internal_slot: actions
1089
- });
1090
- }
1091
- const WrapPreCard = styledComponents.styled(ui.Card)`
1092
- & pre {
1093
- white-space: pre-wrap !important;
1094
- }
1095
- `;
1096
- function SafeValueInput(props) {
1097
- return /* @__PURE__ */ jsxRuntime.jsx(ErrorWrapper, { onChange: props.onChange, children: /* @__PURE__ */ jsxRuntime.jsx(PteValueFixer, { ...props }) });
1098
- }
1099
- function ErrorWrapper(props) {
1100
- const { onChange } = props, [error, setError] = react.useState(), catchError = react.useCallback((params) => {
1101
- setError(params.error);
1102
- }, []), unsetValue = react.useCallback(() => {
1103
- onChange(sanity.PatchEvent.from(sanity.unset())), setError(void 0);
1104
- }, [onChange]), dismiss = react.useCallback(() => setError(void 0), []), catcher = /* @__PURE__ */ jsxRuntime.jsx(ui.ErrorBoundary, { onCatch: catchError, children: props.children });
1105
- return error ? /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { border: !0, tone: "critical", padding: 2, contentEditable: !1, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
1106
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, weight: "semibold", children: "An error occurred." }),
1107
- /* @__PURE__ */ jsxRuntime.jsx(WrapPreCard, { flex: 1, padding: 2, tone: "critical", border: !0, children: catcher }),
1108
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { width: "fill", flex: 1, gap: 3, children: [
1109
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { flex: 1, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { text: "Dismiss", onClick: dismiss, tone: "primary" }) }),
1110
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { text: "Unset value", onClick: unsetValue, tone: "critical" })
1111
- ] })
1112
- ] }) }) : catcher;
1113
- }
1114
- function PteValueFixer(props) {
1115
- const isPortableText = react.useMemo(
1116
- () => sanity.isArraySchemaType(props.schemaType) && isPortableTextArray(props.schemaType),
1117
- [props.schemaType]
1118
- ), value = props.value;
1119
- return isPortableText && value && !value.length ? props.renderDefault({ ...props, value: void 0 }) : props.renderDefault(props);
1120
- }
1121
- function AssistFormBlock(props) {
1122
- const presence = useAssistPresence(props.path, !0), { onChange } = sanity.useFormCallbacks(), key = props.value._key, localOnChange = react.useCallback(
1123
- (patchEvent) => {
1124
- key && onChange(sanity.PatchEvent.from(patchEvent).prefixAll({ _key: key }));
1125
- },
1126
- [onChange, key]
1127
- ), singlePresence = presence[0];
1128
- return /* @__PURE__ */ jsxRuntime.jsx(ErrorWrapper, { onChange: localOnChange, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", justify: "space-between", children: [
1129
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { flex: 1, children: props.renderDefault(props) }),
1130
- singlePresence && /* @__PURE__ */ jsxRuntime.jsx(AiFieldPresence, { presence: singlePresence })
1131
- ] }) });
1132
- }
1133
- const InlineBlockValueContext = react.createContext(void 0);
1134
- function AssistInlineFormBlock(props) {
1135
- return /* @__PURE__ */ jsxRuntime.jsx(InlineBlockValueContext.Provider, { value: props.value, children: /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: props.renderDefault(props) }) });
1136
- }
1137
- function AssistItem(props) {
1138
- const { path } = props, presence = useAssistPresence(path, !0);
1139
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", width: "fill", style: { position: "relative" }, children: [
1140
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { flex: 1, children: props.renderDefault({ ...props }) }),
1141
- presence.map((pre) => /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { style: { position: "absolute", right: 35 }, children: /* @__PURE__ */ jsxRuntime.jsx(AiFieldPresence, { presence: pre }) }, pre.user.id))
1142
- ] });
1143
- }
1144
- const preventDefault = (ev) => ev.preventDefault();
1145
- function DocumentForm(props) {
1146
- const {
1147
- collapsedFieldSets,
1148
- collapsedPaths,
1149
- displayed: value,
1150
- documentId,
1151
- documentType,
1152
- editState,
1153
- formState,
1154
- onBlur,
1155
- onChange,
1156
- onFocus,
1157
- onPathOpen,
1158
- onSetActiveFieldGroup,
1159
- onSetCollapsedFieldSet,
1160
- onSetCollapsedPath,
1161
- ready,
1162
- validation
1163
- } = structure.useDocumentPane(), documentStore = sanity.useDocumentStore(), presence = sanity.useDocumentPresence(documentId), patchChannel = react.useMemo(() => sanity.createPatchChannel(), []), isLocked = editState?.transactionSyncLock?.enabled;
1164
- react.useEffect(() => {
1165
- const sub = documentStore.pair.documentEvents(documentId, documentType).pipe(
1166
- operators.tap((event) => {
1167
- event.type === "mutation" && patchChannel.publish(prepareMutationEvent(event)), event.type === "rebase" && patchChannel.publish(prepareRebaseEvent(event));
1168
- })
1169
- ).subscribe();
1170
- return () => {
1171
- sub.unsubscribe();
1172
- };
1173
- }, [documentId, documentStore, documentType, patchChannel]);
1174
- const hasRev = !!value?._rev;
1175
- react.useEffect(() => {
1176
- hasRev && patchChannel.publish({
1177
- type: "mutation",
1178
- patches: [],
1179
- snapshot: value
1180
- });
1181
- }, [hasRev]);
1182
- const formRef = react.useRef(null);
1183
- return react.useEffect(() => {
1184
- ui.focusFirstDescendant(formRef.current);
1185
- }, []), isLocked ? /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { as: "form", ...props, ref: formRef, children: /* @__PURE__ */ jsxRuntime.jsx(
1186
- ui.Flex,
1187
- {
1188
- align: "center",
1189
- direction: "column",
1190
- height: "fill",
1191
- justify: "center",
1192
- padding: 3,
1193
- sizing: "border",
1194
- 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" })
1195
- }
1196
- ) }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { as: "form", ...props, onSubmit: preventDefault, ref: formRef, children: ready ? formState === null ? /* @__PURE__ */ jsxRuntime.jsx(
1197
- ui.Flex,
1198
- {
1199
- align: "center",
1200
- direction: "column",
1201
- height: "fill",
1202
- justify: "center",
1203
- padding: 3,
1204
- sizing: "border",
1205
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, children: "This form is hidden" })
1206
- }
1207
- ) : /* @__PURE__ */ jsxRuntime.jsx(
1208
- sanity.FormBuilder,
1209
- {
1210
- __internal_patchChannel: patchChannel,
1211
- collapsedFieldSets,
1212
- collapsedPaths,
1213
- focusPath: formState.focusPath,
1214
- changed: formState.changed,
1215
- focused: formState.focused,
1216
- groups: formState.groups,
1217
- id: assistFormId,
1218
- members: formState.members,
1219
- onChange,
1220
- onFieldGroupSelect: onSetActiveFieldGroup,
1221
- onPathBlur: onBlur,
1222
- onPathFocus: onFocus,
1223
- onPathOpen,
1224
- onSetFieldSetCollapsed: onSetCollapsedFieldSet,
1225
- onSetPathCollapsed: onSetCollapsedPath,
1226
- presence,
1227
- readOnly: formState.readOnly,
1228
- schemaType: formState.schemaType,
1229
- validation,
1230
- value: formState.value,
1231
- hasUpstreamVersion: !1
1232
- }
1233
- ) : /* @__PURE__ */ jsxRuntime.jsxs(
1234
- ui.Flex,
1235
- {
1236
- align: "center",
1237
- direction: "column",
1238
- height: "fill",
1239
- justify: "center",
1240
- padding: 3,
1241
- sizing: "border",
1242
- children: [
1243
- /* @__PURE__ */ jsxRuntime.jsx(ui.Spinner, { muted: !0 }),
1244
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginTop: 3, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { align: "center", muted: !0, size: 1, children: "Loading document" }) })
1245
- ]
1246
- }
1247
- ) });
1248
- }
1249
- function prepareMutationEvent(event) {
1250
- const patches = event.mutations.map((mut) => mut.patch).filter(Boolean);
1251
- return {
1252
- type: "mutation",
1253
- snapshot: event.document,
1254
- patches: sanity.fromMutationPatches(event.origin, patches)
1255
- };
1256
- }
1257
- function prepareRebaseEvent(event) {
1258
- const remotePatches = event.remoteMutations.map((mut) => mut.patch).filter(Boolean), localPatches = event.localMutations.map((mut) => mut.patch).filter(Boolean);
1259
- return {
1260
- type: "rebase",
1261
- snapshot: event.document,
1262
- patches: sanity.fromMutationPatches("remote", remotePatches).concat(
1263
- sanity.fromMutationPatches("local", localPatches)
1264
- )
1265
- };
1266
- }
1267
- const AssistTypeContext = react.createContext({}), DEFAULT_MAX_DEPTH$1 = 8, ABSOLUTE_MAX_DEPTH$1 = 50;
1268
- function getConditionalMembers(docState, maxDepth2 = DEFAULT_MAX_DEPTH$1) {
1269
- return [{
1270
- path: "",
1271
- hidden: !1,
1272
- readOnly: !!docState.readOnly,
1273
- conditional: isConditional(docState.schemaType)
1274
- }, ...extractConditionalPaths(docState, Math.min(maxDepth2, ABSOLUTE_MAX_DEPTH$1))].filter((v) => v.conditional).map(({ conditional, ...state }) => ({ ...state }));
1275
- }
1276
- function isConditional(schemaType) {
1277
- return typeof schemaType.hidden == "function" || typeof schemaType.readOnly == "function";
1278
- }
1279
- function conditionalState(memberState) {
1280
- return {
1281
- path: sanity.pathToString(memberState.path),
1282
- readOnly: !!memberState.readOnly,
1283
- // Use actual form state readOnly value
1284
- hidden: !1,
1285
- // If it's in form state members, it's not hidden
1286
- conditional: isConditional(memberState.schemaType)
1287
- };
1288
- }
1289
- function extractConditionalPaths(node, maxDepth2) {
1290
- return node.path.length >= maxDepth2 ? [] : node.members.reduce((acc, member) => {
1291
- if (member.kind === "error")
1292
- return acc;
1293
- if (member.kind === "field") {
1294
- const schemaType = member.field.schemaType;
1295
- if (schemaType.jsonType === "object") {
1296
- const innerFields = member.field.readOnly ? [] : extractConditionalPaths(member.field, maxDepth2);
1297
- return [...acc, conditionalState(member.field), ...innerFields];
1298
- } else if (schemaType.jsonType === "array") {
1299
- const array = member.field;
1300
- let arrayPaths = [];
1301
- const isObjectsArray = array.members.some(
1302
- (m) => m.kind === "item" && sanity.isObjectSchemaType(m.item.schemaType)
1303
- );
1304
- if (!array.readOnly)
1305
- for (const arrayMember of array.members) {
1306
- if (arrayMember.kind === "error")
1307
- continue;
1308
- const innerFields = isObjectsArray && !arrayMember.item.readOnly ? extractConditionalPaths(arrayMember.item, maxDepth2) : [];
1309
- arrayPaths = [...arrayPaths, conditionalState(arrayMember.item), ...innerFields];
1310
- }
1311
- return [...acc, conditionalState(array), ...arrayPaths];
1312
- }
1313
- return [...acc, conditionalState(member.field)];
1314
- } else if (member.kind === "fieldSet") {
1315
- const conditionalFieldset = !!node.schemaType?.fieldsets?.some(
1316
- (f) => !f.single && f.name === member.fieldSet.name && typeof f.hidden == "function"
1317
- ), innerFields = extractConditionalPaths(member.fieldSet, maxDepth2).map((f) => ({
1318
- ...f,
1319
- // if fieldset is conditional, visible fields must also be considered conditional
1320
- conditional: conditionalFieldset || f.conditional
1321
- }));
1322
- return [...acc, ...innerFields];
1323
- }
1324
- return acc;
1325
- }, []);
1326
- }
1327
- const SparklesIllustration = styledComponents.styled(icons.SparklesIcon)({
1328
- fontSize: "3.125em",
1329
- "& path": {
1330
- strokeWidth: "0.6px !important"
1331
- }
1332
- });
1333
- function InspectorOnboarding(props) {
1334
- const { onDismiss } = props;
1335
- 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: [
1336
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { textAlign: "center" }, children: /* @__PURE__ */ jsxRuntime.jsx(SparklesIllustration, {}) }),
1337
- /* @__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." }),
1338
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", gap: 2, justify: "center", children: [
1339
- /* @__PURE__ */ jsxRuntime.jsx(
1340
- ui.Button,
1341
- {
1342
- as: "a",
1343
- href: releaseAnnouncementUrl,
1344
- rel: "noreferrer",
1345
- target: "_blank",
1346
- fontSize: 1,
1347
- mode: "default",
1348
- onClick: onDismiss,
1349
- padding: 2,
1350
- text: "Learn more",
1351
- tone: "primary"
1352
- }
1353
- ),
1354
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { fontSize: 1, mode: "bleed", onClick: onDismiss, padding: 2, text: "Dismiss" })
1355
- ] })
1356
- ] }) }) });
1357
- }
1358
- function FieldAutocomplete(props) {
1359
- const { id, schemaType, fieldPath, onSelect, includeDocument, filter } = props, { getFieldRefs: getFieldRefs2 } = useAiAssistanceConfig(), fieldRefs = react.useMemo(() => {
1360
- const refs = getFieldRefs2(schemaType.name);
1361
- return includeDocument ? [getDocumentFieldRef(schemaType), ...refs] : refs;
1362
- }, [schemaType, includeDocument, getFieldRefs2]), currentField = react.useMemo(
1363
- () => fieldRefs.find((f) => f.key === fieldPath),
1364
- [fieldPath, fieldRefs]
1365
- ), autocompleteOptions = react.useMemo(
1366
- () => fieldRefs.filter((field) => filter ? filter(field) : !0).filter((f) => !isType(f.schemaType, "reference")).map((field) => ({ value: field.key, field })),
1367
- [fieldRefs, filter]
1368
- ), renderOption = react.useCallback((option) => {
1369
- const { value, field } = option;
1370
- 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: [
1371
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, children: react.createElement(field.icon) }),
1372
- /* @__PURE__ */ jsxRuntime.jsx(FieldTitle, { field })
1373
- ] }) }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { as: "button", padding: 3, radius: 1, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { accent: !0, size: 1, children: option.value }) });
1374
- }, []), renderValue = react.useCallback((value, option) => option?.field.title ?? value, []), filterOption = react.useCallback((query, option) => {
1375
- const lQuery = query.toLowerCase();
1376
- return option?.value?.toLowerCase().includes(lQuery) || option?.field?.title?.toLowerCase().includes(lQuery);
1377
- }, []);
1378
- return /* @__PURE__ */ jsxRuntime.jsx(
1379
- ui.Autocomplete,
1380
- {
1381
- fontSize: 1,
1382
- icon: currentField ? currentField.icon : icons.SearchIcon,
1383
- onChange: onSelect,
1384
- openButton: !0,
1385
- id,
1386
- options: autocompleteOptions,
1387
- placeholder: "Search for a field",
1388
- radius: 2,
1389
- renderOption,
1390
- renderValue,
1391
- value: currentField?.key,
1392
- filterOption
1393
- }
1394
- );
1395
- }
1396
- function FieldTitle(props) {
1397
- const splitTitle = props.field.title.split("/");
1398
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { flex: "none", children: /* @__PURE__ */ jsxRuntime.jsxs(
1399
- ui.Breadcrumbs,
1400
- {
1401
- style: {
1402
- display: "flex",
1403
- flexWrap: "wrap",
1404
- alignItems: "center",
1405
- marginTop: "-4px"
1406
- },
1407
- separator: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginTop: 1, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 1, children: "/" }) }),
1408
- space: 1,
1409
- children: [
1410
- splitTitle.slice(0, splitTitle.length - 1).map((pt, i) => (
1411
- // eslint-disable-next-line react/no-array-index-key
1412
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginTop: 1, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 1, children: pt.trim() }) }, i)
1413
- )),
1414
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginTop: 1, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, weight: "medium", children: splitTitle[splitTitle.length - 1] }) })
1415
- ]
1416
- }
1417
- ) });
1418
- }
1419
- function useInterval(ms) {
1420
- const [tick, update] = react.useReducer((n) => n + 1, 0);
1421
- return react.useEffect(() => {
1422
- const i = setInterval(update, ms);
1423
- return () => clearInterval(i);
1424
- }, [ms]), tick;
1425
- }
1426
- function TimeAgo({ date }) {
1427
- useInterval(1e3);
1428
- const timeSince = dateFns.formatDistanceToNow(date ? new Date(date) : /* @__PURE__ */ new Date());
1429
- return /* @__PURE__ */ jsxRuntime.jsxs("span", { title: timeSince, children: [
1430
- timeSince,
1431
- " ago"
1432
- ] });
1433
- }
1434
- const rotate = styledComponents.keyframes`
1435
- 0% {
1436
- transform: rotate(0);
1437
- }
1438
- 100% {
1439
- transform: rotate(360deg);
1440
- }
1441
- `, SyncSpinningIcon = styledComponents.styled(icons.SyncIcon)`
1442
- animation: ${rotate} 1s linear infinite;
1443
- `, TASK_CONFIG = {
1444
- aborted: {
1445
- title: "Canceled",
1446
- icon: icons.CloseCircleIcon,
1447
- tone: "transparent"
1448
- },
1449
- error: {
1450
- title: "Error",
1451
- icon: icons.ErrorOutlineIcon,
1452
- tone: "critical"
1453
- },
1454
- success: {
1455
- title: "Completed",
1456
- icon: icons.CheckmarkCircleIcon,
1457
- tone: "positive"
1458
- },
1459
- timeout: {
1460
- title: "Timeout",
1461
- icon: icons.ClockIcon,
1462
- tone: "caution"
1463
- }
1464
- };
1465
- function InstructionTaskHistoryButton(props) {
1466
- const { tasks, instructions, documentId, showTitles } = props, client = sanity.useClient({ apiVersion: "2023-01-01" }), cancelRun = react.useCallback(
1467
- (taskKey) => {
1468
- if (!documentId)
1469
- return;
1470
- const statusDocId = assistTasksStatusId(documentId), basePath2 = `${sanity.typed("tasks")}[_key=="${taskKey}"]`;
1471
- client.patch(statusDocId).set({
1472
- [`${basePath2}.${sanity.typed("ended")}`]: (/* @__PURE__ */ new Date()).toISOString(),
1473
- [`${basePath2}.${sanity.typed("reason")}`]: sanity.typed("aborted")
1474
- }).commit().catch(console.error);
1475
- },
1476
- [client, documentId]
1477
- ), titledTasks = react.useMemo(() => {
1478
- const t = tasks?.filter(
1479
- (task) => task.started && (/* @__PURE__ */ new Date()).getTime() - new Date(task.started).getTime() < maxHistoryVisibilityMs
1480
- ).map((task) => {
1481
- const instruction2 = instructions?.find((i) => i._key === task.instructionKey);
1482
- return {
1483
- ...task,
1484
- title: showTitles ? task.title ?? getInstructionTitle(instruction2) : void 0,
1485
- cancel: () => cancelRun(task._key)
1486
- };
1487
- }) ?? [];
1488
- return t.sort((a, b) => new Date(b.started ?? "").getTime() - new Date(a.started ?? "").getTime()), t;
1489
- }, [tasks, instructions, cancelRun, showTitles]), isRunning = react.useMemo(() => titledTasks.some((r) => !r.ended), [titledTasks]), hasErrors = react.useMemo(
1490
- () => titledTasks.some((r) => r.reason === "error" || r.reason === "timeout"),
1491
- [titledTasks]
1492
- ), [open, setOpen] = react.useState(!1), toggleOpen = react.useCallback(() => setOpen((v) => !v), []), [button, setButton] = react.useState(null), [popover, setPopover] = react.useState(null), handleClickOutside = react.useCallback(() => {
1493
- setOpen(!1);
1494
- }, []);
1495
- ui.useClickOutside(handleClickOutside, [button, popover]);
1496
- const handleEscape = react.useCallback(() => {
1497
- setOpen(!1), button?.focus();
1498
- }, [button]);
1499
- return /* @__PURE__ */ jsxRuntime.jsx(
1500
- ui.Popover,
1501
- {
1502
- constrainSize: !0,
1503
- content: /* @__PURE__ */ jsxRuntime.jsx(TaskList, { onEscape: handleEscape, tasks: titledTasks }),
1504
- open: open && !!titledTasks?.length,
1505
- placement: "top",
1506
- portal: !0,
1507
- ref: setPopover,
1508
- width: 0,
1509
- children: /* @__PURE__ */ jsxRuntime.jsx(
1510
- TaskStatusButton,
1511
- {
1512
- disabled: !titledTasks?.length,
1513
- hasErrors,
1514
- isRunning,
1515
- onClick: toggleOpen,
1516
- ref: setButton,
1517
- selected: open
1518
- }
1519
- )
1520
- }
1521
- );
1522
- }
1523
- const TASK_STATUS_BUTTON_TOOLTIP_PROPS = {
1524
- placement: "top"
1525
- }, TaskStatusButton = react.forwardRef(function(props, ref) {
1526
- const { disabled, hasErrors, isRunning, onClick, selected } = props;
1527
- return /* @__PURE__ */ jsxRuntime.jsx(
1528
- sanity.StatusButton,
1529
- {
1530
- label: `${pluginTitle} status`,
1531
- "aria-label": `${pluginTitle} status`,
1532
- icon: isRunning ? SyncSpinningIcon : hasErrors ? icons.ErrorOutlineIcon : icons.CheckmarkCircleIcon,
1533
- mode: "bleed",
1534
- onClick,
1535
- tone: hasErrors ? "critical" : void 0,
1536
- disabled,
1537
- ref,
1538
- selected,
1539
- tooltipProps: TASK_STATUS_BUTTON_TOOLTIP_PROPS
1540
- }
1541
- );
1542
- });
1543
- function TaskList(props) {
1544
- const { onEscape, tasks } = props, { isTopLayer } = ui.useLayer();
1545
- return ui.useGlobalKeyDown(
1546
- react.useCallback(
1547
- (event) => {
1548
- isTopLayer && event.key === "Escape" && onEscape();
1549
- },
1550
- [isTopLayer, onEscape]
1551
- )
1552
- ), /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, { padding: 1, space: 1, children: tasks.map((task) => /* @__PURE__ */ jsxRuntime.jsx(TaskItem, { task }, task._key)) });
1553
- }
1554
- function TaskItem(props) {
1555
- const { task } = props, taskType = task.reason && TASK_CONFIG[task.reason];
1556
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { radius: 2, tone: taskType && taskType?.tone, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", gap: 1, children: [
1557
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "flex-start", flex: 1, gap: 3, padding: 3, children: [
1558
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { flex: "none", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: 1, children: [
1559
- taskType && react.createElement(taskType.icon),
1560
- !task.reason && /* @__PURE__ */ jsxRuntime.jsx(ui.Spinner, {})
1561
- ] }) }),
1562
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { flex: 1, space: 2, children: [
1563
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: 1, weight: "medium", children: [
1564
- taskType ? taskType.title : "Running",
1565
- task.title && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1566
- ": ",
1567
- task.title
1568
- ] })
1569
- ] }),
1570
- task.message ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, children: task.message }) : null,
1571
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 1, children: /* @__PURE__ */ jsxRuntime.jsx(TimeAgo, { date: task.ended ?? task.started }) })
1572
- ] })
1573
- ] }),
1574
- !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" }) })
1575
- ] }) });
1576
- }
1577
- const inspectorOnboardingKey = "sanityStudio:assist:inspector:onboarding:dismissed";
1578
- function isFeatureOnboardingDismissed(featureKey) {
1579
- return typeof localStorage > "u" ? !1 : localStorage.getItem(featureKey) === "true";
1580
- }
1581
- function dismissFeatureOnboarding(featureKey) {
1582
- typeof localStorage > "u" || localStorage.setItem(featureKey, "true");
1583
- }
1584
- function useOnboardingFeature(featureKey) {
1585
- const [showOnboarding, setShowOnboarding] = react.useState(
1586
- () => !isFeatureOnboardingDismissed(featureKey)
1587
- ), dismissOnboarding = react.useCallback(() => {
1588
- setShowOnboarding(!1), dismissFeatureOnboarding(featureKey);
1589
- }, [setShowOnboarding, featureKey]);
1590
- return { showOnboarding, dismissOnboarding };
1591
- }
1592
- const CardWithShadowBelow = styledComponents.styled(ui.Card)`
1593
- position: relative;
1594
-
1595
- &:after {
1596
- content: '';
1597
- display: block;
1598
- position: absolute;
1599
- left: 0;
1600
- right: 0;
1601
- bottom: -1px;
1602
- border-bottom: 1px solid var(--card-border-color);
1603
- opacity: 0.5;
1604
- z-index: 100;
1605
- }
1606
- `, CardWithShadowAbove = styledComponents.styled(ui.Card)`
1607
- position: relative;
1608
-
1609
- &:after {
1610
- content: '';
1611
- display: block;
1612
- position: absolute;
1613
- left: 0;
1614
- right: 0;
1615
- top: -1px;
1616
- border-top: 1px solid var(--card-border-color);
1617
- opacity: 0.5;
1618
- z-index: 100;
1619
- }
1620
- `;
1621
- function AssistInspectorWrapper(props) {
1622
- const context = useAiAssistanceConfig();
1623
- if (context.statusLoading)
1624
- 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: [
1625
- /* @__PURE__ */ jsxRuntime.jsx(ui.Spinner, { muted: !0 }),
1626
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { muted: !0, size: 1, children: [
1627
- "Loading ",
1628
- pluginTitle,
1629
- "..."
1630
- ] })
1631
- ] }) });
1632
- const status = context.status;
1633
- return status?.enabled ? !status?.initialized || !status.validToken ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { direction: "column", height: "fill", children: [
1634
- /* @__PURE__ */ jsxRuntime.jsx(
1635
- structure.DocumentInspectorHeader,
1636
- {
1637
- closeButtonLabel: "Close",
1638
- onClose: props.onClose,
1639
- title: pluginTitle
1640
- }
1641
- ),
1642
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { padding: 4, space: 3, children: [
1643
- context.error ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: 1, weight: "semibold", children: [
1644
- "Failed to start ",
1645
- pluginTitle
1646
- ] }) : null,
1647
- !context.error && !status?.initialized ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: 1, weight: "semibold", children: [
1648
- pluginTitle,
1649
- " is not enabled"
1650
- ] }) : null,
1651
- !context.error && status?.initialized && !status.validToken ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1652
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, weight: "semibold", children: "Invalid token" }),
1653
- /* @__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." })
1654
- ] }) : null,
1655
- context.error && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 1, children: "Something went wrong. See console for details." }),
1656
- !context.error && !status?.initialized && /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: 1, muted: !0, children: [
1657
- "Please enable ",
1658
- pluginTitle,
1659
- "."
1660
- ] }),
1661
- /* @__PURE__ */ jsxRuntime.jsx(
1662
- ui.Button,
1663
- {
1664
- fontSize: 1,
1665
- icon: context.initLoading ? /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginTop: 1, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Spinner, {}) }) : context.error ? icons.RetryIcon : void 0,
1666
- text: context.error ? "Retry" : status?.initialized && !status.validToken ? `Restore ${pluginTitle}` : `Enable ${pluginTitle} now`,
1667
- tone: "primary",
1668
- onClick: context.init,
1669
- disabled: context.initLoading
1670
- }
1671
- )
1672
- ] })
1673
- ] }) : /* @__PURE__ */ jsxRuntime.jsx(AssistInspector, { ...props }) : /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { direction: "column", height: "fill", children: [
1674
- /* @__PURE__ */ jsxRuntime.jsx(
1675
- structure.DocumentInspectorHeader,
1676
- {
1677
- closeButtonLabel: "Close",
1678
- onClose: props.onClose,
1679
- title: pluginTitle
1680
- }
1681
- ),
1682
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { flex: 1, overflow: "auto", padding: 4, space: 3, children: [
1683
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { as: "p", size: 1, weight: "semibold", children: [
1684
- pluginTitle,
1685
- " is not available"
1686
- ] }),
1687
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { as: "p", muted: !0, size: 1, children: [
1688
- "Please get in touch with a Sanity account manager or",
1689
- " ",
1690
- /* @__PURE__ */ jsxRuntime.jsx("a", { href: salesUrl, target: "_blank", rel: "noreferrer", children: "contact our sales team" }),
1691
- " ",
1692
- "to get started with ",
1693
- pluginTitle,
1694
- ".",
1695
- " ",
1696
- /* @__PURE__ */ jsxRuntime.jsx("a", { href: releaseAnnouncementUrl, target: "_blank", rel: "noreferrer", children: "Learn more \u2192" })
1697
- ] })
1698
- ] })
1699
- ] });
1700
- }
1701
- function AssistInspector(props) {
1702
- const { params } = useAiPaneRouter(), boundary = react.useRef(null), pathKey = params?.[fieldPathParam], instructionKey = params?.[instructionParam], documentPane = structure.useDocumentPane(), {
1703
- documentId,
1704
- documentType,
1705
- value: docValue,
1706
- schemaType,
1707
- onChange: documentOnChange,
1708
- formState
1709
- } = documentPane, { assistableDocumentId, documentIsAssistable } = useAssistDocumentContext(), formStateRef = react.useRef(formState);
1710
- formStateRef.current = formState;
1711
- const { instructionLoading, requestRunInstruction } = useRequestRunInstruction({
1712
- documentOnChange,
1713
- isDocAssistable: documentIsAssistable
1714
- }), 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(
1715
- () => assistDocument?.tasks?.filter((i) => !instructionKey || i.instructionKey === instructionKey),
1716
- [assistDocument?.tasks, instructionKey]
1717
- ), instructions = react.useMemo(
1718
- () => assistDocument?.fields?.flatMap((f) => f.instructions ?? []),
1719
- [assistDocument?.fields]
1720
- ), promptValue = instruction2?.prompt, isEmptyPrompt = react.useMemo(() => {
1721
- if (!promptValue?.length)
1722
- return !0;
1723
- const children = promptValue[0]?.children;
1724
- return promptValue.length == 1 && children?.length === 1 && !children?.[0]?.text?.length;
1725
- }, [promptValue]), paneNode = react.useMemo(
1726
- () => ({
1727
- type: "document",
1728
- id: aiDocId,
1729
- title: pluginTitle,
1730
- options: {
1731
- id: aiDocId,
1732
- type: assistDocumentTypeName
1733
- }
1734
- }),
1735
- [aiDocId]
1736
- ), runCurrentInstruction = react.useCallback(
1737
- () => instruction2 && pathKey && typePath && requestRunInstruction({
1738
- documentId: assistableDocumentId,
1739
- path: pathKey,
1740
- typePath,
1741
- assistDocumentId: assistDocumentId(documentType),
1742
- instruction: instruction2,
1743
- conditionalMembers: formStateRef.current ? getConditionalMembers(formStateRef.current) : []
1744
- }),
1745
- [pathKey, instruction2, typePath, documentType, assistableDocumentId, requestRunInstruction]
1746
- ), Region = react.useCallback((_props) => /* @__PURE__ */ jsxRuntime.jsx("div", { ..._props, style: { height: "100%", flex: 1, overflow: "auto" } }), []), assistTypeContext = react.useMemo(() => ({ typePath, documentType }), [typePath, documentType]);
1747
- 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(
1748
- ui.Flex,
1749
- {
1750
- ref: boundary,
1751
- direction: "column",
1752
- height: "fill",
1753
- overflow: "hidden",
1754
- sizing: "border",
1755
- style: { lineHeight: 0 },
1756
- children: [
1757
- /* @__PURE__ */ jsxRuntime.jsx(
1758
- AiInspectorHeader,
1759
- {
1760
- onClose: props.onClose,
1761
- field: selectedField,
1762
- fieldTitle: getFieldTitle(selectedField)
1763
- }
1764
- ),
1765
- /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { as: Region, flex: 1, overflow: "auto", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { direction: "column", style: { minHeight: "100%" }, children: [
1766
- /* @__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(
1767
- sanity.VirtualizerScrollInstanceProvider,
1768
- {
1769
- scrollElement: boundary.current,
1770
- containerElement: boundary,
1771
- children: /* @__PURE__ */ jsxRuntime.jsx(sanity.PerspectiveProvider, { selectedPerspectiveName: void 0, children: /* @__PURE__ */ jsxRuntime.jsx(
1772
- structure.DocumentPaneProvider,
1773
- {
1774
- paneKey: documentPane.paneKey,
1775
- index: documentPane.index,
1776
- itemId: "ai",
1777
- pane: paneNode,
1778
- children: /* @__PURE__ */ jsxRuntime.jsx(DocumentForm, {})
1779
- }
1780
- ) })
1781
- }
1782
- ) }) }) }) }),
1783
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { flex: "none", padding: 4, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { muted: !0, size: 1, children: [
1784
- "How is Sanity AI Assist working for you?",
1785
- " ",
1786
- /* @__PURE__ */ jsxRuntime.jsxs(
1787
- "a",
1788
- {
1789
- href: giveFeedbackUrl,
1790
- target: "_blank",
1791
- rel: "noreferrer",
1792
- style: { whiteSpace: "nowrap" },
1793
- children: [
1794
- "Let us know ",
1795
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowRightIcon, {})
1796
- ]
1797
- }
1798
- )
1799
- ] }) })
1800
- ] }) }),
1801
- /* @__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: [
1802
- schemaType?.name && pathKey && instructionKey && /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, { flex: 1, children: /* @__PURE__ */ jsxRuntime.jsx(
1803
- ui.Button,
1804
- {
1805
- mode: "ghost",
1806
- disabled: isEmptyPrompt || instructionLoading,
1807
- fontSize: 1,
1808
- icon: instructionLoading ? /* @__PURE__ */ jsxRuntime.jsx(ui.Spinner, { style: { marginTop: 3 } }) : icons.PlayIcon,
1809
- onClick: runCurrentInstruction,
1810
- padding: 3,
1811
- text: "Run instruction"
1812
- }
1813
- ) }),
1814
- /* @__PURE__ */ jsxRuntime.jsx(
1815
- InstructionTaskHistoryButton,
1816
- {
1817
- documentId: assistableDocumentId,
1818
- tasks,
1819
- instructions,
1820
- showTitles: !instructionKey
1821
- }
1822
- )
1823
- ] }) })
1824
- ]
1825
- }
1826
- );
1827
- }
1828
- function AiInspectorHeader(props) {
1829
- const { onClose, field, fieldTitle } = props, { showOnboarding, dismissOnboarding } = useOnboardingFeature(inspectorOnboardingKey);
1830
- return /* @__PURE__ */ jsxRuntime.jsxs(CardWithShadowBelow, { flex: "none", padding: 2, children: [
1831
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { flex: 1, align: "center", children: [
1832
- /* @__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: [
1833
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginTop: 1, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, weight: "semibold", children: "AI instructions for" }) }),
1834
- /* @__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 }) })
1835
- ] }) }),
1836
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { flex: "none", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { fontSize: 1, icon: icons.CloseIcon, mode: "bleed", onClick: onClose }) })
1837
- ] }),
1838
- showOnboarding && /* @__PURE__ */ jsxRuntime.jsx(InspectorOnboarding, { onDismiss: dismissOnboarding })
1839
- ] });
1840
- }
1841
- const aiInspectorId = "ai-assistance", assistInspector = {
1842
- name: aiInspectorId,
1843
- useMenuItem: () => ({
1844
- icon: icons.SparklesIcon,
1845
- title: pluginTitle,
1846
- hidden: !0,
1847
- showAsAction: !1
1848
- }),
1849
- component: AssistInspectorWrapper,
1850
- onClose({ params }) {
1851
- return {
1852
- params: sanity.typed({
1853
- ...params,
1854
- [fieldPathParam]: void 0,
1855
- [instructionParam]: void 0
1856
- })
1857
- };
1858
- }
1859
- };
1860
- function arrowPath(options2, x, y, dir) {
1861
- return [
1862
- `M ${x - options2.arrow.size} ${y - options2.arrow.size * dir} `,
1863
- `L ${x} ${y}`,
1864
- `L ${x + options2.arrow.size} ${y - options2.arrow.size * dir}`
1865
- ].join("");
1866
- }
1867
- function moveTo(x, y) {
1868
- return `M${x} ${y}`;
1869
- }
1870
- function lineTo(x, y) {
1871
- return `L${x} ${y}`;
1872
- }
1873
- function join(strings, delim = "") {
1874
- return strings.join(delim);
1875
- }
1876
- function quadCurve(x1, y1, x, y) {
1877
- return `Q${x1} ${y1} ${x} ${y}`;
1878
- }
1879
- function drawConnectorPath(options2, line) {
1880
- 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 = [];
1881
- return from.isAbove ? cmds.push(
1882
- moveTo(
1883
- fromX + options2.arrow.marginX,
1884
- fromY - options2.arrow.threshold + options2.arrow.marginY
1885
- ),
1886
- lineTo(fromX + options2.arrow.marginX, fromY - r0),
1887
- quadCurve(fromX + options2.arrow.marginX, fromY, fromX + options2.arrow.marginX + r0, fromY)
1888
- ) : from.isBelow ? cmds.push(
1889
- moveTo(
1890
- fromX + options2.arrow.marginX,
1891
- fromY + options2.arrow.threshold - options2.arrow.marginY
1892
- ),
1893
- lineTo(fromX + options2.arrow.marginX, fromY + r0),
1894
- quadCurve(fromX + options2.arrow.marginX, fromY, fromX + options2.arrow.marginX + r0, fromY)
1895
- ) : cmds.push(moveTo(fromX, fromY)), to.isAbove ? fromY < to.bounds.y ? cmds.push(
1896
- lineTo(dividerX - r1, fromY),
1897
- quadCurve(dividerX, fromY, dividerX, fromY + r1),
1898
- lineTo(dividerX, toY - r1),
1899
- quadCurve(dividerX, toY, dividerX + r1, toY),
1900
- lineTo(dividerX - cornerRadius, toY),
1901
- quadCurve(dividerX, toY, dividerX, toY - cornerRadius),
1902
- lineTo(dividerX, toY - options2.arrow.threshold + options2.arrow.marginY)
1903
- ) : cmds.push(
1904
- lineTo(dividerX - cornerRadius, fromY),
1905
- quadCurve(dividerX, fromY, dividerX, fromY - cornerRadius),
1906
- lineTo(dividerX, toY - options2.arrow.threshold + options2.arrow.marginY)
1907
- ) : to.isBelow ? fromY > to.bounds.y + to.bounds.h ? cmds.push(
1908
- lineTo(dividerX - options2.arrow.marginX - r1, fromY),
1909
- quadCurve(
1910
- dividerX - options2.arrow.marginX,
1911
- fromY,
1912
- dividerX - options2.arrow.marginX,
1913
- fromY - r1
1914
- ),
1915
- lineTo(dividerX - options2.arrow.marginX, toY + r1),
1916
- quadCurve(
1917
- dividerX - options2.arrow.marginX,
1918
- toY,
1919
- dividerX - options2.arrow.marginX + r1,
1920
- toY
1921
- ),
1922
- lineTo(dividerX - cornerRadius, toY),
1923
- quadCurve(dividerX, toY, dividerX, toY + cornerRadius),
1924
- lineTo(dividerX, toY + options2.arrow.threshold - options2.arrow.marginY)
1925
- ) : cmds.push(
1926
- lineTo(dividerX - cornerRadius, fromY),
1927
- quadCurve(dividerX, fromY, dividerX, fromY + cornerRadius),
1928
- lineTo(dividerX, toY + options2.arrow.threshold - options2.arrow.marginY)
1929
- ) : fromY < toY ? cmds.push(
1930
- lineTo(dividerX - r0, fromY),
1931
- quadCurve(dividerX, fromY, dividerX, fromY + r1),
1932
- lineTo(dividerX, toY - r1),
1933
- quadCurve(dividerX, toY, dividerX + r1, toY),
1934
- lineTo(toX, toY)
1935
- ) : cmds.push(
1936
- lineTo(dividerX - Math.min(r0, r1), fromY),
1937
- quadCurve(dividerX, fromY, dividerX, fromY - Math.min(r0, r1)),
1938
- lineTo(dividerX, toY + r1),
1939
- quadCurve(dividerX, toY, dividerX + r1, toY),
1940
- lineTo(toX, toY)
1941
- ), join(cmds);
1942
- }
1943
- function ConnectorPath(props) {
1944
- const { from, options: options2, to } = props, { strokeWidth } = options2.path, theme = ui.useTheme(), line = react.useMemo(() => mapConnectorToLine(options2, { from, to }), [from, options2, to]);
1945
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1946
- /* @__PURE__ */ jsxRuntime.jsx(
1947
- "path",
1948
- {
1949
- d: drawConnectorPath(options2, line),
1950
- stroke: theme.sanity.color.base.bg,
1951
- strokeWidth: strokeWidth + 4
1952
- }
1953
- ),
1954
- /* @__PURE__ */ jsxRuntime.jsx(
1955
- "path",
1956
- {
1957
- d: drawConnectorPath(options2, line),
1958
- stroke: ui.rgba(theme.sanity.color.base.border, 0.5),
1959
- strokeWidth
1960
- }
1961
- ),
1962
- line.from.isAbove && /* @__PURE__ */ jsxRuntime.jsx(
1963
- "path",
1964
- {
1965
- d: arrowPath(
1966
- options2,
1967
- line.from.x + options2.arrow.marginX,
1968
- line.from.bounds.y - options2.arrow.threshold + options2.arrow.marginY,
1969
- -1
1970
- ),
1971
- stroke: theme.sanity.color.base.border,
1972
- strokeWidth
1973
- }
1974
- ),
1975
- line.from.isBelow && /* @__PURE__ */ jsxRuntime.jsx(
1976
- "path",
1977
- {
1978
- d: arrowPath(
1979
- options2,
1980
- line.from.x + options2.arrow.marginX,
1981
- line.from.bounds.y + line.from.bounds.h + options2.arrow.threshold - options2.arrow.marginY,
1982
- 1
1983
- ),
1984
- stroke: theme.sanity.color.base.border,
1985
- strokeWidth
1986
- }
1987
- )
1988
- ] });
1989
- }
1990
- const DEBUG = !1, options = {
1991
- arrow: {
1992
- marginX: 10.5,
1993
- marginY: 5,
1994
- size: 4,
1995
- threshold: 16.5
1996
- },
1997
- divider: {
1998
- offsetX: -10.5
1999
- },
2000
- path: {
2001
- cornerRadius: 3,
2002
- marginY: 10.5,
2003
- strokeWidth: 1
2004
- }
2005
- };
2006
- function AssistConnectorsOverlay(props) {
2007
- const { connectors } = props, [, setRedraw] = react.useState(!1);
2008
- return react.useEffect(() => {
2009
- setRedraw(!0);
2010
- }, []), /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2011
- /* @__PURE__ */ jsxRuntime.jsx(
2012
- "svg",
2013
- {
2014
- fill: "none",
2015
- width: window.innerWidth,
2016
- height: window.innerHeight,
2017
- style: {
2018
- position: "absolute",
2019
- top: 0,
2020
- left: 0,
2021
- width: "100%",
2022
- height: "100%",
2023
- pointerEvents: "none",
2024
- zIndex: 150
2025
- // zIndex,
2026
- },
2027
- children: connectors.map((connector) => /* @__PURE__ */ jsxRuntime.jsx(
2028
- ConnectorPath,
2029
- {
2030
- from: connector.from,
2031
- options,
2032
- to: connector.to
2033
- },
2034
- connector.key
2035
- ))
2036
- }
2037
- ),
2038
- DEBUG
2039
- ] });
2040
- }
2041
- function validateStyleguide(styleguide) {
2042
- if (styleguide && styleguide.length > 2e3)
2043
- throw new Error(
2044
- `[${packageName}]: \`translate.styleguide\` value is too long. It must be 2000 characters or less, but was ${styleguide.length} characters`
2045
- );
2046
- return styleguide;
2047
- }
2048
- function createStyleGuideResolver(styleguide, context) {
2049
- return async () => {
2050
- if (typeof styleguide != "function")
2051
- return styleguide;
2052
- const styleguideResult = await styleguide(context);
2053
- return validateStyleguide(styleguideResult);
2054
- };
2055
- }
2056
- const getLanguageParams = (select, document2) => {
2057
- if (!select || !document2)
2058
- return {};
2059
- const selection = select || {}, selectedValue = {};
2060
- for (const [key, path] of Object.entries(selection)) {
2061
- let value = get__default.default(document2, path);
2062
- Array.isArray(value) && (value = value.filter(
2063
- (item) => typeof item == "object" ? item?._type !== "reference" || "_ref" in item : !0
2064
- )), selectedValue[key] = value;
2065
- }
2066
- return selectedValue;
2067
- }, toFieldLanguagesKeyPrefix = "sanityStudio:assist:field-languages:from:";
2068
- function getPreferredToFieldLanguages(fromLanguageId) {
2069
- if (typeof localStorage > "u")
2070
- return [];
2071
- const value = localStorage.getItem(`${toFieldLanguagesKeyPrefix}${fromLanguageId}`);
2072
- return value ? JSON.parse(value) : [];
2073
- }
2074
- function setPreferredToFieldLanguages(fromLanguageId, languageIds) {
2075
- typeof localStorage > "u" || localStorage.setItem(`${toFieldLanguagesKeyPrefix}${fromLanguageId}`, JSON.stringify(languageIds));
2076
- }
2077
- const DEFAULT_MAX_DEPTH = 6, ABSOLUTE_MAX_DEPTH = 50;
2078
- function getDocumentMembersFlat(doc, schemaType, maxDepth2 = DEFAULT_MAX_DEPTH) {
2079
- return sanity.isDocumentSchemaType(schemaType) ? extractPaths(doc, schemaType, [], Math.min(maxDepth2, ABSOLUTE_MAX_DEPTH)) : (console.error("Schema type is not a document"), []);
2080
- }
2081
- function extractPaths(doc, schemaType, path, maxDepth2) {
2082
- return path.length >= maxDepth2 ? [] : schemaType.fields.reduce((acc, field) => {
2083
- const fieldPath = [...path, field.name], fieldSchema = field.type, { value } = mutator.extractWithPath(sanity.pathToString(fieldPath), doc)[0] ?? {};
2084
- if (!value)
2085
- return acc;
2086
- const thisFieldWithPath = {
2087
- path: fieldPath,
2088
- name: field.name,
2089
- schemaType: fieldSchema,
2090
- value
2091
- };
2092
- if (fieldSchema.jsonType === "object") {
2093
- const innerFields = extractPaths(doc, fieldSchema, fieldPath, maxDepth2);
2094
- return [...acc, thisFieldWithPath, ...innerFields];
2095
- } 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
2096
- path.length + 1 < maxDepth2) {
2097
- const { value: arrayValue } = mutator.extractWithPath(sanity.pathToString(fieldPath), doc)[0] ?? {};
2098
- let arrayPaths = [];
2099
- if (arrayValue?.length)
2100
- for (const item of arrayValue) {
2101
- const itemPath = [...fieldPath, { _key: item._key }];
2102
- let itemSchema = fieldSchema.of.find((t) => t.name === item._type);
2103
- if (item._type || (itemSchema = fieldSchema.of[0], console.warn(
2104
- "Array item is missing _type - using the first defined type in the array.of schema",
2105
- {
2106
- itemPath,
2107
- item,
2108
- itemSchema
2109
- }
2110
- )), item._key && itemSchema) {
2111
- const innerFields = extractPaths(
2112
- doc,
2113
- itemSchema,
2114
- itemPath,
2115
- maxDepth2
2116
- ), arrayMember = {
2117
- path: itemPath,
2118
- name: item._key,
2119
- schemaType: itemSchema,
2120
- value: item
2121
- };
2122
- arrayPaths = [...arrayPaths, arrayMember, ...innerFields];
2123
- }
2124
- }
2125
- return [...acc, thisFieldWithPath, ...arrayPaths];
2126
- }
2127
- return [...acc, thisFieldWithPath];
2128
- }, []);
2129
- }
2130
- const defaultLanguageOutputs = function(member, enclosingType, translateFromLanguageId, translateToLanguageIds) {
2131
- if (member.schemaType.jsonType === "object" && member.schemaType.name.startsWith("internationalizedArray")) {
2132
- const pathEnd = member.path.slice(-1);
2133
- return (sanity.isKeySegment(pathEnd[0]) ? pathEnd[0]._key : null) === translateFromLanguageId ? translateToLanguageIds.map((translateToId) => ({
2134
- id: translateToId,
2135
- outputPath: [...member.path.slice(0, -1), { _key: translateToId }]
2136
- })) : void 0;
2137
- }
2138
- if (enclosingType.jsonType === "object" && enclosingType.name.startsWith("locale"))
2139
- return translateFromLanguageId === member.name ? translateToLanguageIds.map((translateToId) => ({
2140
- id: translateToId,
2141
- outputPath: [...member.path.slice(0, -1), translateToId]
2142
- })) : void 0;
2143
- };
2144
- function getFieldLanguageMap(documentSchema, documentMembers, translateFromLanguageId, outputLanguageIds, langFn) {
2145
- const translationMaps = [];
2146
- for (const member of documentMembers) {
2147
- const parentPath = member.path.slice(0, -1), enclosingType = documentMembers.find((m) => sanity.pathToString(m.path) === sanity.pathToString(parentPath))?.schemaType ?? documentSchema, translations = langFn(
2148
- member,
2149
- enclosingType,
2150
- translateFromLanguageId,
2151
- outputLanguageIds
2152
- )?.filter((translation) => translation.id !== translateFromLanguageId);
2153
- translations && translationMaps.push({
2154
- inputLanguageId: translateFromLanguageId,
2155
- inputPath: member.path,
2156
- outputs: translations
2157
- });
2158
- }
2159
- return translationMaps;
2160
- }
2161
- const FieldTranslationContext = react.createContext({
2162
- openFieldTranslation: () => {
2163
- },
2164
- translationLoading: !1
2165
- });
2166
- function useFieldTranslation() {
2167
- return react.useContext(FieldTranslationContext);
2168
- }
2169
- function hasValuesToTranslate(fieldLanguageMaps, fromLanguage, basePath2) {
2170
- return fieldLanguageMaps?.some(
2171
- (map) => map.inputLanguageId === fromLanguage?.id && map.inputPath && sanity.pathToString(map.inputPath).startsWith(sanity.pathToString(basePath2))
2172
- );
2173
- }
2174
- function FieldTranslationProvider(props) {
2175
- 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(() => {
2176
- setDialogOpen(!1), setLanguages(void 0), setFieldTranslationParams(void 0);
2177
- }, []), languageClient = sanity.useClient({
2178
- apiVersion: config?.apiVersion ?? API_VERSION_WITH_EXTENDED_TYPES
2179
- }), documentId = fieldTranslationParams?.document?._id, id = react.useId(), selectFromLanguage = react.useCallback(
2180
- (from, languages2, params) => {
2181
- const { document: document2, documentSchema } = params ?? {};
2182
- if (setFromLanguage(from), !document2 || !documentSchema || !params || !languages2) {
2183
- setFieldLanguageMaps(void 0);
2184
- return;
2185
- }
2186
- const preferred = getPreferredToFieldLanguages(from.id), allToLanguages = languages2.filter((l) => l.id !== from?.id), filteredToLanguages = allToLanguages.filter(
2187
- (l) => !preferred.length || preferred.includes(l.id)
2188
- );
2189
- setToLanguages(filteredToLanguages);
2190
- const fromId = from?.id, allToIds = allToLanguages?.map((l) => l.id) ?? [], docMembers = getDocumentMembersFlat(document2, documentSchema, config?.maxPathDepth);
2191
- if (fromId && allToIds?.length) {
2192
- const transMap = getFieldLanguageMap(
2193
- documentSchema,
2194
- docMembers,
2195
- fromId,
2196
- allToIds.filter((toId) => fromId !== toId),
2197
- config?.translationOutputs ?? defaultLanguageOutputs
2198
- );
2199
- setFieldLanguageMaps(transMap);
2200
- } else
2201
- setFieldLanguageMaps(void 0);
2202
- },
2203
- [config]
2204
- ), toggleToLanguage = react.useCallback(
2205
- (toggledLang, toLanguages2, languages2) => {
2206
- if (!languages2 || !fromLanguage)
2207
- return;
2208
- const wasSelected = !!toLanguages2?.find((l) => l.id === toggledLang.id), newToLangs = languages2.filter(
2209
- (anyLang) => !!toLanguages2?.find(
2210
- (selectedLang) => toggledLang.id !== selectedLang.id && selectedLang.id === anyLang.id
2211
- ) || toggledLang.id === anyLang.id && !wasSelected
2212
- );
2213
- setToLanguages(newToLangs), setPreferredToFieldLanguages(
2214
- fromLanguage.id,
2215
- newToLangs.map((l) => l.id)
2216
- );
2217
- },
2218
- [fromLanguage]
2219
- ), openFieldTranslation = react.useCallback(
2220
- async (params) => {
2221
- setDialogOpen(!0);
2222
- const languageParams = getLanguageParams(config?.selectLanguageParams, params.document), languages2 = await (typeof config?.languages == "function" ? config?.languages(languageClient, languageParams) : Promise.resolve(config?.languages));
2223
- setLanguages(languages2), setFieldTranslationParams(params);
2224
- const fromLanguage2 = languages2?.[0];
2225
- fromLanguage2 ? selectFromLanguage(fromLanguage2, languages2, params) : console.error("No languages available for selected language params", languageParams);
2226
- },
2227
- [selectFromLanguage, config, languageClient]
2228
- ), contextValue = react.useMemo(() => ({
2229
- openFieldTranslation,
2230
- translationLoading: !1
2231
- }), [openFieldTranslation]), runDisabled = !fromLanguage || !toLanguages?.length || !fieldLanguageMaps?.length || !documentId || !hasValuesToTranslate(fieldLanguageMaps, fromLanguage, fieldTranslationParams.translatePath), onRunTranslation = react.useCallback(() => {
2232
- const translatePath = fieldTranslationParams?.translatePath;
2233
- fieldLanguageMaps && documentId && translatePath && runTranslate({
2234
- documentId,
2235
- translatePath,
2236
- styleguide: createStyleGuideResolver(styleguide, {
2237
- client: languageClient,
2238
- documentId,
2239
- schemaType: fieldTranslationParams?.documentSchema,
2240
- translatePath
2241
- }),
2242
- fieldLanguageMap: fieldLanguageMaps.map((map) => ({
2243
- ...map,
2244
- // eslint-disable-next-line max-nested-callbacks
2245
- outputs: map.outputs.filter((out) => !!toLanguages?.find((l) => l.id === out.id))
2246
- })),
2247
- conditionalMembers: fieldTranslationParams?.conditionalMembers
2248
- }), close();
2249
- }, [
2250
- fieldLanguageMaps,
2251
- documentId,
2252
- runTranslate,
2253
- styleguide,
2254
- close,
2255
- toLanguages,
2256
- fieldTranslationParams?.translatePath,
2257
- fieldTranslationParams?.conditionalMembers,
2258
- fieldTranslationParams?.documentSchema,
2259
- languageClient
2260
- ]), runButton = /* @__PURE__ */ jsxRuntime.jsx(
2261
- ui.Button,
2262
- {
2263
- text: "Translate",
2264
- tone: "primary",
2265
- icon: icons.PlayIcon,
2266
- style: { width: "100%" },
2267
- disabled: runDisabled,
2268
- onClick: onRunTranslation
2269
- }
2270
- );
2271
- return /* @__PURE__ */ jsxRuntime.jsxs(FieldTranslationContext.Provider, { value: contextValue, children: [
2272
- dialogOpen ? /* @__PURE__ */ jsxRuntime.jsx(
2273
- ui.Dialog,
2274
- {
2275
- id,
2276
- width: 1,
2277
- open: dialogOpen,
2278
- onClose: close,
2279
- header: "Translate fields",
2280
- footer: /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { justify: "space-between", padding: 2, flex: 1, children: runDisabled ? /* @__PURE__ */ jsxRuntime.jsx(
2281
- ui.Tooltip,
2282
- {
2283
- 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." }) }),
2284
- placement: "top",
2285
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { flex: 1, children: runButton })
2286
- }
2287
- ) : runButton }),
2288
- children: languages ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { padding: 4, gap: 5, align: "flex-start", justify: "center", children: [
2289
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 2, children: [
2290
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginBottom: 2, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { weight: "semibold", children: "From" }) }),
2291
- languages?.map((radioLanguage) => /* @__PURE__ */ jsxRuntime.jsx(
2292
- FromLanguageRadio,
2293
- {
2294
- radioLanguage,
2295
- fromLanguage,
2296
- selectFromLanguage,
2297
- languages,
2298
- fieldTranslationParams
2299
- },
2300
- radioLanguage.id
2301
- ))
2302
- ] }),
2303
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 2, children: [
2304
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginBottom: 2, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { weight: "semibold", children: "To" }) }),
2305
- languages.map((checkboxLanguage) => /* @__PURE__ */ jsxRuntime.jsx(
2306
- ToLanguageCheckbox,
2307
- {
2308
- checkboxLanguage,
2309
- fromLanguage,
2310
- toLanguages,
2311
- toggleToLanguage,
2312
- languages
2313
- },
2314
- checkboxLanguage.id
2315
- ))
2316
- ] })
2317
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { padding: 4, gap: 2, align: "flex-start", justify: "center", children: [
2318
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Spinner, {}) }),
2319
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "Loading languages..." })
2320
- ] })
2321
- }
2322
- ) : null,
2323
- props.children
2324
- ] });
2325
- }
2326
- function ToLanguageCheckbox(props) {
2327
- const { checkboxLanguage, fromLanguage, toLanguages, toggleToLanguage, languages } = props, langId = checkboxLanguage.id, onChange = react.useCallback(
2328
- () => toggleToLanguage(checkboxLanguage, toLanguages, languages),
2329
- [toggleToLanguage, checkboxLanguage, toLanguages, languages]
2330
- );
2331
- return /* @__PURE__ */ jsxRuntime.jsxs(
2332
- ui.Flex,
2333
- {
2334
- gap: 3,
2335
- align: "center",
2336
- as: "label",
2337
- style: langId === fromLanguage?.id ? { opacity: 0.5 } : void 0,
2338
- children: [
2339
- /* @__PURE__ */ jsxRuntime.jsx(
2340
- ui.Checkbox,
2341
- {
2342
- name: "toLang",
2343
- value: langId,
2344
- checked: langId !== fromLanguage?.id && !!toLanguages?.find((tl) => tl.id === langId),
2345
- onChange,
2346
- disabled: langId === fromLanguage?.id
2347
- }
2348
- ),
2349
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: langId === fromLanguage?.id, children: checkboxLanguage.title ?? langId })
2350
- ]
2351
- },
2352
- langId
2353
- );
2354
- }
2355
- function FromLanguageRadio(props) {
2356
- const { languages, radioLanguage, selectFromLanguage, fromLanguage, fieldTranslationParams } = props, langId = radioLanguage.id, onChange = react.useCallback(
2357
- () => selectFromLanguage(radioLanguage, languages, fieldTranslationParams),
2358
- [selectFromLanguage, radioLanguage, languages, fieldTranslationParams]
2359
- );
2360
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gap: 3, align: "center", as: "label", children: [
2361
- /* @__PURE__ */ jsxRuntime.jsx(
2362
- ui.Radio,
2363
- {
2364
- name: "fromLang",
2365
- value: langId,
2366
- checked: langId === fromLanguage?.id,
2367
- onChange
2368
- }
2369
- ),
2370
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: radioLanguage.title ?? radioLanguage.id })
2371
- ] }, langId);
2372
- }
2373
- const hiddenTypes = [
2374
- "any",
2375
- "array",
2376
- "block",
2377
- "boolean",
2378
- "crossDatasetReference",
2379
- "date",
2380
- "datetime",
2381
- "document",
2382
- "email",
2383
- "file",
2384
- "globalDocumentReference",
2385
- "image",
2386
- "number",
2387
- "object",
2388
- "reference",
2389
- "span",
2390
- "string",
2391
- "text",
2392
- "url",
2393
- "slug",
2394
- "geopoint",
2395
- "sanity.assetSourceData",
2396
- "sanity.imageAsset",
2397
- "sanity.fileAsset",
2398
- "sanity.imageCrop",
2399
- "sanity.imageHotspot",
2400
- "sanity.imageMetadata",
2401
- "sanity.imageDimensions",
2402
- "sanity.imagePalette",
2403
- "sanity.imagePaletteSwatch",
2404
- assistSerializedTypeName,
2405
- assistSerializedFieldTypeName,
2406
- "sanity-agent.job.document"
2407
- ], inlineTypes = ["document", "object", "image", "file"];
2408
- function serializeSchema(schema, options2) {
2409
- 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));
2410
- return list.sort((a, b) => (a?.name ?? "").localeCompare(b?.name ?? "")), list;
2411
- }
2412
- function getSchemaStub(schemaType, schema, options2) {
2413
- if (!schemaType.type?.name)
2414
- throw console.error("Missing type name", schemaType.type), new Error("Type is missing name!");
2415
- const baseSchema = {
2416
- // we dont need type or id when we send using POST, so leave these out to save bandwidth
2417
- ...options2?.leanFormat ? {} : { _id: `${assistSchemaIdPrefix}${schemaType.name}`, _type: assistSerializedTypeName },
2418
- name: schemaType.name,
2419
- title: schemaType.title,
2420
- type: schemaType.type.name,
2421
- ...getBaseFields(schema, schemaType, schemaType.type.name, options2)
2422
- };
2423
- return removeUndef(baseSchema);
2424
- }
2425
- function getBaseFields(schema, type, typeName, options2) {
2426
- const schemaOptions = removeUndef({
2427
- imagePromptField: type.options?.aiAssist?.imageInstructionField,
2428
- embeddingsIndex: type.options?.aiAssist?.embeddingsIndex
2429
- });
2430
- return removeUndef({
2431
- options: Object.keys(schemaOptions).length ? schemaOptions : void 0,
2432
- values: Array.isArray(type?.options?.list) ? type?.options?.list.map(
2433
- (v) => typeof v == "string" ? v : v.value ?? `${v.title}`
2434
- ) : void 0,
2435
- of: "of" in type && typeName === "array" ? arrayOf(type, schema, options2) : void 0,
2436
- to: "to" in type && typeName === "reference" ? refToTypeNames(type) : void 0,
2437
- fields: "fields" in type && inlineTypes.includes(typeName) ? serializeFields(schema, type, options2) : void 0,
2438
- annotations: typeName === "block" && "fields" in type ? serializeAnnotations(type, schema, options2) : void 0,
2439
- inlineOf: typeName === "block" && "fields" in type ? serializeInlineOf(type, schema, options2) : void 0,
2440
- hidden: typeof type.hidden == "function" ? "function" : type.hidden ? !0 : void 0,
2441
- readOnly: typeof type.readOnly == "function" ? "function" : type.readOnly ? !0 : void 0
2442
- });
2443
- }
2444
- function serializeFields(schema, schemaType, options2) {
2445
- return (schemaType.fieldsets ? schemaType.fieldsets.flatMap(
2446
- (fs) => fs.single ? fs.field : fs.fields.map((f) => ({
2447
- ...f,
2448
- type: {
2449
- ...f.type,
2450
- // if fieldset is (conditionally) hidden, the field must be considered the same way
2451
- // ie, if the field does not show up in conditionalMembers, it is hidden
2452
- // regardless of weather or not it is the field function or the fieldset function that hides it
2453
- hidden: typeof fs.hidden == "function" ? fs.hidden : fs.hidden ? !0 : f.type.hidden
2454
- }
2455
- }))
2456
- ) : 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));
2457
- }
2458
- function serializeMember(schema, type, name, options2) {
2459
- const typeName = schema.get(type?.name) ? type.name : type.type?.name ?? "";
2460
- return removeUndef({
2461
- ...options2?.leanFormat ? {} : { _type: assistSerializedFieldTypeName },
2462
- name,
2463
- type: typeName,
2464
- title: type.title,
2465
- ...getBaseFields(schema, type, typeName, options2)
2466
- });
2467
- }
2468
- function serializeInlineOf(blockSchemaType, schema, options2) {
2469
- const childrenType = blockSchemaType.fields.find((f) => f.name === "children")?.type;
2470
- if (!(!childrenType || !sanity.isArraySchemaType(childrenType)))
2471
- return arrayOf(
2472
- {
2473
- of: childrenType.of.filter((t) => !isType(t, "span"))
2474
- },
2475
- schema,
2476
- options2
2477
- );
2478
- }
2479
- function serializeAnnotations(blockSchemaType, schema, options2) {
2480
- const marksType = blockSchemaType.fields.find((f) => f.name === "markDefs")?.type;
2481
- if (!(!marksType || !sanity.isArraySchemaType(marksType)))
2482
- return arrayOf(marksType, schema, options2);
2483
- }
2484
- function arrayOf(arrayType, schema, options2) {
2485
- return arrayType.of.filter((type) => isAssistSupported(type)).map((t) => serializeMember(schema, t, t.name, options2));
2486
- }
2487
- function refToTypeNames(type) {
2488
- return type.to.map((t) => ({
2489
- type: sanity.typed(t.name)
2490
- }));
2491
- }
2492
- function removeUndef(obj) {
2493
- return Object.keys(obj).forEach((key) => obj[key] === void 0 ? delete obj[key] : {}), obj;
2494
- }
2495
- function createFieldRefCache() {
2496
- const byType = {};
2497
- function getRefsForType(schemaType) {
2498
- const documentType = schemaType.name, cached = byType[documentType];
2499
- if (cached) return cached;
2500
- const fieldRefs = getFieldRefs(schemaType), fieldRefsByTypePath = asFieldRefsByTypePath(fieldRefs), refs = {
2501
- fieldRefs,
2502
- fieldRefsByTypePath
2503
- };
2504
- return byType[documentType] = refs, refs;
2505
- }
2506
- return getRefsForType;
2507
- }
2508
- function AiAssistanceConfigProvider(props) {
2509
- 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);
2510
- react.useEffect(() => {
2511
- getInstructStatus().then((s) => setStatus(s)).catch((e) => {
2512
- console.error(e), setError(e);
2513
- });
2514
- }, [getInstructStatus]);
2515
- const init = react.useCallback(async () => {
2516
- setError(void 0);
2517
- try {
2518
- await initInstruct();
2519
- const status2 = await getInstructStatus();
2520
- setStatus(status2);
2521
- } catch (e) {
2522
- console.error("Failed to init ai assistance", e), setError(e);
2523
- }
2524
- }, [initInstruct, getInstructStatus, setStatus]), { config, children } = props, context = react.useMemo(() => ({
2525
- config,
2526
- status,
2527
- statusLoading,
2528
- init,
2529
- initLoading,
2530
- error,
2531
- serializedTypes,
2532
- getFieldRefs: getFieldRefs2,
2533
- getFieldRefsByTypePath
2534
- }), [
2535
- config,
2536
- status,
2537
- init,
2538
- statusLoading,
2539
- initLoading,
2540
- error,
2541
- serializedTypes,
2542
- getFieldRefs2,
2543
- getFieldRefsByTypePath
2544
- ]);
2545
- return /* @__PURE__ */ jsxRuntime.jsx(AiAssistanceConfigContext.Provider, { value: context, children });
2546
- }
2547
- function useFieldRefGetters(schema) {
2548
- return react.useMemo(() => {
2549
- const getForSchemaType = createFieldRefCache();
2550
- function getRefsForType(documentType) {
2551
- const schemaType = schema.get(documentType);
2552
- if (!schemaType)
2553
- throw new Error(`Schema type "${documentType}" not found`);
2554
- return getForSchemaType(schemaType);
2555
- }
2556
- return {
2557
- getFieldRefs: (documentType) => getRefsForType(documentType).fieldRefs,
2558
- getFieldRefsByTypePath: (documentType) => getRefsForType(documentType).fieldRefsByTypePath
2559
- };
2560
- }, [schema]);
2561
- }
2562
- function AssistLayout(props) {
2563
- const [connectors, setConnectors] = react.useState([]);
2564
- 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: [
2565
- props.renderDefault(props),
2566
- /* @__PURE__ */ jsxRuntime.jsx(ui.ThemeProvider, { tone: "default", children: /* @__PURE__ */ jsxRuntime.jsx(AssistConnectorsOverlay, { connectors }) })
2567
- ] }) }) }) });
2568
- }
2569
- const ImageContext = react.createContext({});
2570
- function ImageContextProvider(props) {
2571
- const { schemaType, path, value, readOnly } = props, assetRef = value?.asset?._ref, { selectedReleaseId } = sanity.usePerspective(), [assetRefState, setAssetRefState] = react.useState(assetRef), { assistableDocumentId, documentSchemaType } = useAssistDocumentContext(), { config, status } = useAiAssistanceConfig(), apiClient = useApiClient(config?.__customApiClient), { generateCaption } = useGenerateCaption(apiClient), { isSyncing } = sanity.useSyncState(
2572
- sanity.getPublishedId(assistableDocumentId),
2573
- documentSchemaType.name,
2574
- selectedReleaseId
2575
- ), isShowingOlderRevision = !!structure.usePaneRouter().params?.rev;
2576
- react.useEffect(() => {
2577
- const descriptionField = getDescriptionFieldOption(schemaType);
2578
- assetRef && assistableDocumentId && descriptionField?.updateOnImageChange && assetRef !== assetRefState && !isSyncing && !isShowingOlderRevision && !readOnly && (setAssetRefState(assetRef), canUseAssist(status) && generateCaption({
2579
- path: sanity.pathToString([...path, descriptionField.path]),
2580
- documentId: assistableDocumentId
2581
- }));
2582
- }, [
2583
- schemaType,
2584
- path,
2585
- assetRef,
2586
- assetRefState,
2587
- assistableDocumentId,
2588
- generateCaption,
2589
- isSyncing,
2590
- status,
2591
- readOnly,
2592
- isShowingOlderRevision
2593
- ]);
2594
- const context = react.useMemo(() => {
2595
- const descriptionField = getDescriptionFieldOption(schemaType), imageInstructionField = getImageInstructionFieldOption(schemaType);
2596
- return {
2597
- imageDescriptionPath: descriptionField?.path ? sanity.pathToString([...path, descriptionField.path]) : void 0,
2598
- imageInstructionPath: imageInstructionField ? sanity.pathToString([...path, imageInstructionField]) : void 0,
2599
- assetRef
2600
- };
2601
- }, [schemaType, path, assetRef]);
2602
- return /* @__PURE__ */ jsxRuntime.jsx(ImageContext.Provider, { value: context, children: props.renderDefault(props) });
2603
- }
2604
- function IconInput(props) {
2605
- const { value, onChange } = props, id = react.useId(), items = react.useMemo(
2606
- () => Object.entries(icons.icons).map(([key, icon]) => /* @__PURE__ */ jsxRuntime.jsx(IconItem, { iconKey: key, icon, onChange }, key)),
2607
- [onChange]
2608
- ), selectedIcon = react.useMemo(() => getIcon(value), [value]);
2609
- return /* @__PURE__ */ jsxRuntime.jsx(
2610
- ui.MenuButton,
2611
- {
2612
- button: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { icon: selectedIcon, title: "Select icon", padding: 3, mode: "ghost", radius: 1 }),
2613
- id,
2614
- menu: /* @__PURE__ */ jsxRuntime.jsx(ui.Menu, { style: { maxHeight: 300 }, children: items }),
2615
- popover: { portal: !0 }
2616
- }
2617
- );
2618
- }
2619
- function IconItem({
2620
- icon,
2621
- iconKey: key,
2622
- onChange
2623
- }) {
2624
- const onClick = react.useCallback(() => onChange(sanity.set(key)), [onChange, key]);
2625
- return /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, { icon, title: key, text: key, onClick });
2626
- }
2627
- function getIcon(iconName) {
2628
- return Object.entries(icons.icons).find(([key]) => key === iconName)?.[1] ?? icons.icons.sparkles;
2629
- }
2630
- function useAssistSupported(path, schemaType) {
2631
- return react.useMemo(() => isAssistSupported(schemaType), [schemaType]);
2632
- }
2633
- const translateActions = {
2634
- name: "sanity-assist-translate",
2635
- useAction(props) {
2636
- const { config, status } = useAiAssistanceConfig(), apiClient = useApiClient(config?.__customApiClient), client = sanity.useClient({ apiVersion: API_VERSION_WITH_EXTENDED_TYPES }), {
2637
- schemaType: fieldSchemaType,
2638
- path,
2639
- documentId,
2640
- documentSchemaType,
2641
- documentIsAssistable
2642
- } = 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));
2643
- if (documentSchemaType && (documentTranslationEnabled || fieldTransEnabled)) {
2644
- const { value: documentValue, onChange: documentOnChange, formState } = structure.useDocumentPane(), docRef = react.useRef(documentValue);
2645
- docRef.current = documentValue;
2646
- const formStateRef = react.useRef(formState);
2647
- formStateRef.current = formState;
2648
- const translationApi = useTranslate(apiClient), translate = useDraftDelayedTask({
2649
- documentOnChange,
2650
- isDocAssistable: documentIsAssistable ?? !1,
2651
- task: translationApi.translate
2652
- }), styleguide = config.translate?.styleguide, languagePath = config.translate?.document?.languageField, translateDocumentAction = react.useMemo(() => {
2653
- if (!languagePath || !documentTranslationEnabled)
2654
- return;
2655
- const title = path.length ? "Translate" : "Translate document";
2656
- return {
2657
- type: "action",
2658
- icon: translationApi.loading ? () => /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { style: { height: 17 }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Spinner, { style: { transform: "translateY(6px)" } }) }) : icons.TranslateIcon,
2659
- title,
2660
- onAction: () => {
2661
- translationApi.loading || !languagePath || !documentId || translate({
2662
- languagePath,
2663
- translatePath: path,
2664
- styleguide: createStyleGuideResolver(styleguide, {
2665
- client,
2666
- documentId,
2667
- schemaType: documentSchemaType
2668
- }),
2669
- documentId: documentId ?? "",
2670
- conditionalMembers: formStateRef.current ? getConditionalMembers(formStateRef.current) : []
2671
- });
2672
- },
2673
- renderAsButton: !0,
2674
- disabled: translationApi.loading || readOnly
2675
- };
2676
- }, [
2677
- languagePath,
2678
- translate,
2679
- styleguide,
2680
- documentId,
2681
- translationApi.loading,
2682
- documentTranslationEnabled,
2683
- path,
2684
- readOnly,
2685
- client,
2686
- documentSchemaType
2687
- ]), fieldTranslate = useFieldTranslation(), openFieldTranslation = useDraftDelayedTask({
2688
- documentOnChange,
2689
- isDocAssistable: documentIsAssistable ?? !1,
2690
- task: fieldTranslate.openFieldTranslation
2691
- }), maxDepth2 = config.translate?.field?.maxPathDepth, translateFieldsAction = react.useMemo(
2692
- () => fieldTransEnabled ? {
2693
- type: "action",
2694
- icon: fieldTranslate.translationLoading ? () => /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { style: { height: 17 }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Spinner, { style: { transform: "translateY(6px)" } }) }) : icons.TranslateIcon,
2695
- title: "Translate fields...",
2696
- onAction: () => {
2697
- fieldTranslate.translationLoading || !documentId || (formStateRef.current && getConditionalMembers(formStateRef.current), openFieldTranslation({
2698
- document: {
2699
- ...docRef.current,
2700
- _id: documentId
2701
- },
2702
- documentSchema: documentSchemaType,
2703
- translatePath: path,
2704
- conditionalMembers: formStateRef.current ? getConditionalMembers(formStateRef.current, maxDepth2) : []
2705
- }));
2706
- },
2707
- renderAsButton: !0,
2708
- disabled: fieldTranslate.translationLoading || readOnly
2709
- } : void 0,
2710
- [
2711
- openFieldTranslation,
2712
- documentSchemaType,
2713
- documentId,
2714
- fieldTranslate.translationLoading,
2715
- fieldTransEnabled,
2716
- path,
2717
- readOnly,
2718
- maxDepth2
2719
- ]
2720
- );
2721
- return react.useMemo(() => {
2722
- if (status?.initialized)
2723
- return {
2724
- type: "group",
2725
- icon: () => null,
2726
- title: "Translation",
2727
- children: [translateDocumentAction, translateFieldsAction].filter(
2728
- (c) => !!c
2729
- ),
2730
- expanded: !0
2731
- };
2732
- }, [translateDocumentAction, translateFieldsAction, status]);
2733
- }
2734
- }
2735
- }, generateCaptionsActions = {
2736
- name: "sanity-assist-generate-captions",
2737
- useAction(props) {
2738
- const pathKey = usePathKey(props.path), { openInspector } = structure.useDocumentPane(), { config, status } = useAiAssistanceConfig(), apiClient = useApiClient(config?.__customApiClient), { generateCaption, loading } = useGenerateCaption(apiClient), imageContext = react.useContext(ImageContext);
2739
- if (imageContext && pathKey === imageContext?.imageDescriptionPath) {
2740
- const { assistableDocumentId } = useAssistDocumentContext();
2741
- return react.useMemo(() => ({
2742
- type: "action",
2743
- icon: loading ? () => /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { style: { height: 17 }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Spinner, { style: { transform: "translateY(6px)" } }) }) : icons.ImageIcon,
2744
- title: "Generate image description",
2745
- onAction: () => {
2746
- if (!loading) {
2747
- if (!canUseAssist(status)) {
2748
- openInspector(aiInspectorId, {
2749
- [fieldPathParam]: pathKey,
2750
- [instructionParam]: void 0
2751
- });
2752
- return;
2753
- }
2754
- generateCaption({ path: pathKey, documentId: assistableDocumentId });
2755
- }
2756
- },
2757
- renderAsButton: !0,
2758
- disabled: loading,
2759
- hidden: !imageContext.assetRef
2760
- }), [
2761
- generateCaption,
2762
- pathKey,
2763
- assistableDocumentId,
2764
- loading,
2765
- imageContext,
2766
- status,
2767
- openInspector
2768
- ]);
2769
- }
2770
- }
2771
- }, generateImagActions = {
2772
- name: "sanity-assist-generate-image",
2773
- useAction(props) {
2774
- const pathKey = usePathKey(props.path), { config } = useAiAssistanceConfig(), apiClient = useApiClient(config?.__customApiClient), { generateImage, loading } = useGenerateImage(apiClient), imageContext = react.useContext(ImageContext);
2775
- if (imageContext && pathKey === imageContext?.imageInstructionPath) {
2776
- const { assistableDocumentId } = useAssistDocumentContext();
2777
- return react.useMemo(() => ({
2778
- type: "action",
2779
- icon: loading ? () => /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { style: { height: 17 }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Spinner, { style: { transform: "translateY(6px)" } }) }) : icons.ImageIcon,
2780
- title: "Generate image from prompt",
2781
- onAction: () => {
2782
- loading || generateImage({ path: pathKey, documentId: assistableDocumentId });
2783
- },
2784
- renderAsButton: !0,
2785
- disabled: loading
2786
- }), [generateImage, pathKey, assistableDocumentId, loading]);
2787
- }
2788
- }
2789
- };
2790
- function PrivateIcon() {
2791
- return /* @__PURE__ */ jsxRuntime.jsx(
2792
- ui.Tooltip,
2793
- {
2794
- content: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, style: { whiteSpace: "nowrap" }, children: "Only visible to you" }),
2795
- fallbackPlacements: ["bottom"],
2796
- padding: 2,
2797
- placement: "top",
2798
- portal: !0,
2799
- children: /* @__PURE__ */ jsxRuntime.jsx(icons.LockIcon, {})
2800
- }
2801
- );
2802
- }
2803
- function whatwgRNG(length = 16) {
2804
- const rnds8 = new Uint8Array(length);
2805
- return getRandomValues__default.default(rnds8), rnds8;
2806
- }
2807
- const getByteHexTable = /* @__PURE__ */ (() => {
2808
- let table;
2809
- return () => {
2810
- if (table)
2811
- return table;
2812
- table = [];
2813
- for (let i = 0; i < 256; ++i)
2814
- table[i] = (i + 256).toString(16).substring(1);
2815
- return table;
2816
- };
2817
- })();
2818
- function randomKey(length) {
2819
- const table = getByteHexTable();
2820
- return whatwgRNG(length).reduce((str, n) => str + table[n], "").slice(0, length);
2821
- }
2822
- function defineAssistFieldAction(action) {
2823
- return {
2824
- ...action,
2825
- type: "action"
2826
- };
2827
- }
2828
- function defineFieldActionDivider() {
2829
- return {
2830
- type: "divider"
2831
- };
2832
- }
2833
- function defineAssistFieldActionGroup(group) {
2834
- return {
2835
- ...group,
2836
- type: "group"
2837
- };
2838
- }
2839
- function useCustomFieldActions(props) {
2840
- const {
2841
- config: { fieldActions }
2842
- } = useAiAssistanceConfig(), { addSyntheticTask, removeSyntheticTask } = useAssistDocumentContext(), schemaId = sanity.useWorkspaceSchemaId(), { push: pushToast } = ui.useToast(), configActions = fieldActions?.useFieldActions?.({
2843
- ...props,
2844
- schemaId,
2845
- path: props.path
2846
- });
2847
- return react.useMemo(() => {
2848
- const title = fieldActions?.title, customActions = configActions?.filter(isDefined).map((node) => createSafeNode({
2849
- node,
2850
- pushToast,
2851
- addSyntheticTask,
2852
- removeSyntheticTask
2853
- })).filter(isDefined), onlyGroups = customActions?.length && customActions?.every((node) => node.type === "group");
2854
- return (customActions?.length ? onlyGroups ? customActions : [
2855
- {
2856
- type: "group",
2857
- title: title || "Custom actions",
2858
- children: customActions,
2859
- expanded: !0
2860
- }
2861
- ] : []) ?? [];
2862
- }, [configActions, fieldActions, pushToast]);
2863
- }
2864
- function createSafeNode(args) {
2865
- const { node } = args;
2866
- switch (node.type) {
2867
- case "action":
2868
- return createSafeAction({ ...args, action: node });
2869
- case "group":
2870
- const children = node.children?.filter(isDefined).map((child) => createSafeNode({ ...args, node: child })).filter(isDefined);
2871
- return children?.length ? {
2872
- ...node,
2873
- renderAsButton: !1,
2874
- expanded: !0,
2875
- children
2876
- } : void 0;
2877
- default:
2878
- return node;
2879
- }
2880
- }
2881
- function createSafeAction(args) {
2882
- const { action, pushToast, addSyntheticTask, removeSyntheticTask } = args;
2883
- return {
2884
- ...action,
2885
- onAction: () => {
2886
- async function runAction() {
2887
- const task = {
2888
- _type: instructionTaskTypeName,
2889
- _key: randomKey(12),
2890
- started: (/* @__PURE__ */ new Date()).toISOString(),
2891
- presence: [
2892
- {
2893
- _type: fieldPresenceTypeName,
2894
- _key: randomKey(12),
2895
- path: documentRootKey,
2896
- started: (/* @__PURE__ */ new Date()).toISOString()
2897
- }
2898
- ]
2899
- };
2900
- try {
2901
- addSyntheticTask(task);
2902
- const actionResult = action.onAction?.();
2903
- actionResult instanceof Promise && await actionResult;
2904
- } catch (err) {
2905
- console.error("Failed to execute action", action, err), pushToast({
2906
- title: "Failed to execute action",
2907
- description: err?.message,
2908
- status: "error"
2909
- });
2910
- } finally {
2911
- removeSyntheticTask(task);
2912
- }
2913
- }
2914
- runAction();
2915
- },
2916
- renderAsButton: !1,
2917
- selected: !1
2918
- };
2919
- }
2920
- const assistFieldActions = {
2921
- name: "sanity-assist-actions",
2922
- useAction(props) {
2923
- const { schemaType } = props, {
2924
- assistDocument,
2925
- documentIsNew,
2926
- documentIsAssistable,
2927
- openInspector,
2928
- closeInspector,
2929
- inspector,
2930
- documentOnChange,
2931
- documentSchemaType,
2932
- selectedPath,
2933
- assistableDocumentId,
2934
- fieldRefsByTypePath
2935
- } = useAssistDocumentContext(), { value: docValue, formState } = structure.useDocumentPane(), docValueRef = react.useRef(docValue), formStateRef = react.useRef(formState);
2936
- formStateRef.current = formState;
2937
- const currentUser = sanity.useCurrentUser(), isHidden = !assistDocument, pathKey = usePathKey(props.path), typePath = useTypePath(docValue, pathKey), assistDocumentId2 = assistDocument?._id, { requestRunInstruction } = useRequestRunInstruction({
2938
- documentOnChange,
2939
- isDocAssistable: documentIsAssistable ?? !1
2940
- }), isSelectable = !!useSelectedField(documentSchemaType, typePath), assistSupported = useAssistSupported(props.path, schemaType) && isSelectable && isSchemaAssistEnabled(documentSchemaType) && schemaType.readOnly !== !0, fieldAssist = react.useMemo(
2941
- () => (assistDocument?.fields ?? []).find(
2942
- (f) => f.path === typePath || pathKey === documentRootKey && f.path === pathKey
2943
- ),
2944
- [assistDocument?.fields, pathKey, typePath]
2945
- ), fieldAssistKey = fieldAssist?._key, isSelected = inspector?.name === aiInspectorId && pathKey === selectedPath, imageCaptionAction = generateCaptionsActions.useAction(props), imageGenAction = generateImagActions.useAction(props), translateAction = translateActions.useAction(
2946
- sanity.typed({
2947
- ...props,
2948
- documentId: assistableDocumentId,
2949
- documentIsAssistable,
2950
- documentSchemaType
2951
- })
2952
- ), manageInstructions = react.useCallback(
2953
- () => isSelected ? closeInspector(aiInspectorId) : openInspector(aiInspectorId, {
2954
- [fieldPathParam]: pathKey,
2955
- [instructionParam]: void 0
2956
- }),
2957
- [openInspector, closeInspector, isSelected, pathKey]
2958
- ), onInstructionAction = react.useCallback(
2959
- (instruction2) => {
2960
- !pathKey || !fieldAssistKey || !assistDocumentId2 || !assistableDocumentId || requestRunInstruction({
2961
- documentId: assistableDocumentId,
2962
- assistDocumentId: assistDocumentId2,
2963
- path: pathKey,
2964
- typePath,
2965
- instruction: instruction2,
2966
- conditionalMembers: formStateRef.current ? getConditionalMembers(formStateRef.current) : []
2967
- });
2968
- },
2969
- [
2970
- requestRunInstruction,
2971
- assistableDocumentId,
2972
- pathKey,
2973
- typePath,
2974
- assistDocumentId2,
2975
- fieldAssistKey
2976
- ]
2977
- ), privateInstructions = react.useMemo(
2978
- () => fieldAssist?.instructions?.filter((i) => i.userId && i.userId === currentUser?.id) || [],
2979
- [fieldAssist?.instructions, currentUser]
2980
- ), sharedInstructions = react.useMemo(
2981
- () => fieldAssist?.instructions?.filter((i) => !i.userId) || [],
2982
- [fieldAssist?.instructions]
2983
- ), instructions = react.useMemo(
2984
- () => [...privateInstructions, ...sharedInstructions],
2985
- [privateInstructions, sharedInstructions]
2986
- ), runInstructionsGroup = react.useMemo(() => instructions?.length || imageCaptionAction || translateAction || imageGenAction ? {
2987
- type: "group",
2988
- icon: () => null,
2989
- title: "Run instructions",
2990
- children: [
2991
- ...instructions?.map(
2992
- (instruction2) => instructionItem({
2993
- instruction: instruction2,
2994
- isPrivate: !!(instruction2.userId && instruction2.userId === currentUser?.id),
2995
- onInstructionAction,
2996
- hidden: isHidden,
2997
- assistSupported
2998
- })
2999
- ) || [],
3000
- imageCaptionAction,
3001
- imageGenAction
3002
- ].filter((a) => !!a),
3003
- expanded: !0
3004
- } : void 0, [
3005
- instructions,
3006
- currentUser?.id,
3007
- onInstructionAction,
3008
- isHidden,
3009
- documentIsNew,
3010
- assistSupported,
3011
- imageCaptionAction,
3012
- translateAction,
3013
- imageGenAction
3014
- ]), getDocumentValue = react.useCallback(() => docValueRef.current, []), getConditionalPaths = react.useCallback(() => (formStateRef.current ? getConditionalMembers(formStateRef.current) : []).flatMap(
3015
- (cm) => {
3016
- const path = sanity.stringToPath(cm.path);
3017
- return path.some((s) => typeof s == "number") ? [] : {
3018
- ...cm,
3019
- path
3020
- };
3021
- }
3022
- ), []), parentSchemaType = react.useMemo(() => {
3023
- if (props.path.length) {
3024
- if (props.path.length === 1)
3025
- return documentSchemaType;
3026
- } else return;
3027
- const parentPath = props.path.slice(0, -1), typePath2 = getTypePath(docValueRef.current, sanity.pathToString(parentPath));
3028
- return typePath2 ? fieldRefsByTypePath[typePath2]?.schemaType : void 0;
3029
- }, [fieldRefsByTypePath, props.path, documentSchemaType]), customActions = useCustomFieldActions({
3030
- actionType: props.path.length ? "field" : "document",
3031
- documentIdForAction: assistableDocumentId,
3032
- schemaType,
3033
- documentSchemaType,
3034
- path: props.path,
3035
- getDocumentValue,
3036
- getConditionalPaths,
3037
- parentSchemaType
3038
- }), manageInstructionsItem = react.useMemo(
3039
- () => ({
3040
- type: "action",
3041
- icon: icons.ControlsIcon,
3042
- title: "Manage instructions",
3043
- onAction: manageInstructions,
3044
- selected: isSelected
3045
- }),
3046
- [manageInstructions, isSelected]
3047
- ), group = react.useMemo(
3048
- () => ({
3049
- type: "group",
3050
- icon: icons.SparklesIcon,
3051
- title: pluginTitleShort,
3052
- children: [
3053
- runInstructionsGroup,
3054
- translateAction,
3055
- ...customActions,
3056
- assistSupported && manageInstructionsItem
3057
- ].filter((c) => !!c).filter((c) => c.type === "group" ? c.children.length : !0),
3058
- expanded: !1,
3059
- renderAsButton: !0,
3060
- hidden: !assistSupported && !imageCaptionAction && !translateAction && !imageGenAction
3061
- }),
3062
- [
3063
- //documentIsNew,
3064
- runInstructionsGroup,
3065
- manageInstructionsItem,
3066
- assistSupported,
3067
- imageCaptionAction,
3068
- translateAction,
3069
- imageGenAction,
3070
- customActions
3071
- ]
3072
- ), emptyAction = react.useMemo(
3073
- () => ({
3074
- type: "action",
3075
- hidden: !assistSupported,
3076
- icon: icons.SparklesIcon,
3077
- onAction: manageInstructions,
3078
- renderAsButton: !0,
3079
- title: pluginTitleShort,
3080
- selected: isSelected
3081
- }),
3082
- [assistSupported, manageInstructions, isSelected]
3083
- );
3084
- return !instructions?.length && !imageCaptionAction && !translateAction && !imageGenAction && !customActions.length ? emptyAction : group;
3085
- }
3086
- };
3087
- function instructionItem(props) {
3088
- const { hidden, isPrivate, onInstructionAction, assistSupported, instruction: instruction2 } = props;
3089
- return {
3090
- type: "action",
3091
- icon: getIcon(instruction2.icon),
3092
- iconRight: isPrivate ? PrivateIcon : void 0,
3093
- title: getInstructionTitle(instruction2),
3094
- onAction: () => onInstructionAction(instruction2),
3095
- disabled: !assistSupported,
3096
- hidden
3097
- };
3098
- }
3099
- function createAssistDocumentPresence(documentId) {
3100
- return function() {
3101
- return documentId ? /* @__PURE__ */ jsxRuntime.jsx(AssistDocumentPresence, {}) : null;
3102
- };
3103
- }
3104
- function AssistDocumentPresence() {
3105
- const { assistDocument, syntheticTasks } = useAssistDocumentContext(), anyPresence = react.useMemo(() => {
3106
- 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);
3107
- if (anyPresence2)
3108
- return aiPresence(anyPresence2, []);
3109
- const anyRun = assistDocument?.tasks?.filter((run) => !run.ended && !run.reason)?.find((f) => f.started && (/* @__PURE__ */ new Date()).getTime() - new Date(f.started).getTime() < 3e4);
3110
- return anyRun ? aiPresence(
3111
- {
3112
- started: anyRun.started,
3113
- _key: anyRun._key
3114
- },
3115
- []
3116
- ) : void 0;
3117
- }, [assistDocument?.tasks, syntheticTasks]);
3118
- 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 }) }) }) });
3119
- }
3120
- function BackToInstructionListLink() {
3121
- const { openInspector } = structure.useDocumentPane(), goBack = react.useCallback(
3122
- () => openInspector(aiInspectorId, { [instructionParam]: void 0 }),
3123
- [openInspector]
3124
- );
3125
- return /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(
3126
- ui.Button,
3127
- {
3128
- as: "a",
3129
- fontSize: 1,
3130
- icon: icons.ArrowLeftIcon,
3131
- mode: "bleed",
3132
- padding: 1,
3133
- space: 2,
3134
- onClick: goBack,
3135
- text: " Instructions",
3136
- textAlign: "left"
3137
- }
3138
- ) });
3139
- }
3140
- const SelectedFieldContext = react.createContext(void 0), SelectedFieldContextProvider = SelectedFieldContext.Provider, EMPTY_FIELDS = [];
3141
- function AssistDocumentForm(props) {
3142
- 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 });
3143
- }
3144
- function AssistDocumentFormEditable(props) {
3145
- 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(() => {
3146
- if (typePath)
3147
- return (fields ?? EMPTY_FIELDS).find((f) => f.path === typePath)?._key;
3148
- }, [fields, typePath]), activePath = react.useMemo(() => {
3149
- if (!activeKey)
3150
- return;
3151
- const base = ["fields", { _key: activeKey }];
3152
- return instruction2 ? [...base, "instructions", { _key: instruction2 }] : base;
3153
- }, [activeKey, instruction2]), schema = sanity.useSchema(), documentSchema = react.useMemo(() => {
3154
- if (targetDocumentType)
3155
- return schema.get(targetDocumentType);
3156
- }, [schema, targetDocumentType]), fieldSchema = useSelectedSchema(pathKey, documentSchema), context = react.useMemo(
3157
- () => ({
3158
- documentSchema,
3159
- fieldSchema: fieldSchema ?? documentSchema
3160
- }),
3161
- [fieldSchema, documentSchema]
3162
- ), title = value?.title;
3163
- react.useEffect(() => {
3164
- !title && documentSchema && !id?.startsWith("drafts.") && onChange(sanity.set(documentSchema.title ?? documentSchema.name, ["title"]));
3165
- }, [title, documentSchema, onChange, id]);
3166
- const { onPathOpen, ...formCallbacks } = sanity.useFormCallbacks(), newCallbacks = react.useMemo(
3167
- () => ({
3168
- ...formCallbacks,
3169
- onPathOpen: (path) => {
3170
- !instruction2 && path.length === 4 && path[2] === "instructions" ? setParams(
3171
- sanity.typed({
3172
- ...params,
3173
- [instructionParam]: path[3]?._key
3174
- })
3175
- ) : setTimeout(() => onPathOpen(path), 0);
3176
- }
3177
- }),
3178
- [formCallbacks, onPathOpen, params, setParams, instruction2]
3179
- );
3180
- react.useEffect(() => {
3181
- activePath && !instruction2 && onPathOpen(activePath);
3182
- }, [activePath, instruction2, onPathOpen]);
3183
- const fieldError = react.useMemo(() => {
3184
- const fieldError2 = props.members.find(
3185
- (m) => m.kind === "error" && m.fieldName === "fields"
3186
- );
3187
- if (fieldError2)
3188
- return /* @__PURE__ */ jsxRuntime.jsx(sanity.MemberFieldError, { member: fieldError2 });
3189
- }, [props.members]);
3190
- return /* @__PURE__ */ jsxRuntime.jsx(SelectedFieldContextProvider, { value: context, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 5, children: [
3191
- /* @__PURE__ */ jsxRuntime.jsx(
3192
- FieldsInitializer,
3193
- {
3194
- pathKey: typePath,
3195
- activePath,
3196
- fields,
3197
- documentSchema,
3198
- onChange
3199
- },
3200
- typePath
3201
- ),
3202
- instruction2 && /* @__PURE__ */ jsxRuntime.jsx(BackToInstructionListLink, {}),
3203
- 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 }) }) }),
3204
- fieldError,
3205
- !activePath && props.renderDefault(props)
3206
- ] }) });
3207
- }
3208
- function useSelectedSchema(fieldPath, documentSchema) {
3209
- return react.useMemo(() => {
3210
- if (!fieldPath)
3211
- return;
3212
- if (fieldPath === documentRootKey)
3213
- return documentSchema;
3214
- const path = sanity.stringToPath(fieldPath);
3215
- let currentSchema = documentSchema;
3216
- for (let i = 0; i < path.length; i++) {
3217
- const segment = path[i], field = currentSchema?.fields.find((f) => f.name === segment);
3218
- if (!field)
3219
- return;
3220
- if (i === path.length - 1)
3221
- return field.type;
3222
- if (field.type.jsonType !== "object")
3223
- return;
3224
- currentSchema = field.type;
3225
- }
3226
- return currentSchema;
3227
- }, [documentSchema, fieldPath]);
3228
- }
3229
- function FieldsInitializer({
3230
- pathKey,
3231
- activePath,
3232
- fields,
3233
- documentSchema,
3234
- onChange
3235
- }) {
3236
- const {
3237
- config: { __presets: presets }
3238
- } = useAiAssistanceConfig(), existingField = fields?.find((f) => f._key === pathKey), documentPresets = !!documentSchema?.name && presets?.[documentSchema?.name], missingPresetInstructions = react.useMemo(() => {
3239
- if (!documentPresets || !pathKey)
3240
- return;
3241
- const existingInstructions = existingField?.instructions;
3242
- return documentPresets.fields?.find((f) => f.path === pathKey)?.instructions?.filter(
3243
- (i) => !existingInstructions?.some((ei) => ei._key === i._key)
3244
- );
3245
- }, [documentPresets, pathKey, existingField]), initialized = react.useRef(!1);
3246
- return react.useEffect(() => {
3247
- if (initialized.current || !pathKey || existingField && !missingPresetInstructions?.length)
3248
- return;
3249
- let event = sanity.PatchEvent.from([sanity.setIfMissing([], ["fields"])]);
3250
- existingField || (event = event.append(
3251
- sanity.insert(
3252
- [
3253
- sanity.typed({
3254
- _key: pathKey,
3255
- _type: assistFieldTypeName,
3256
- path: pathKey,
3257
- instructions: []
3258
- })
3259
- ],
3260
- "after",
3261
- ["fields", -1]
3262
- )
3263
- )), existingField?.instructions?.length || (event = event.append([sanity.setIfMissing([], ["fields", { _key: pathKey }, "instructions"])])), missingPresetInstructions?.length && (event = event.append(
3264
- sanity.insert(
3265
- missingPresetInstructions.map(
3266
- (preset) => ({
3267
- ...preset,
3268
- _type: "sanity.assist.instruction",
3269
- prompt: preset.prompt?.map((p) => ({ markDefs: [], ...p }))
3270
- })
3271
- ),
3272
- "after",
3273
- ["fields", { _key: pathKey }, "instructions", -1]
3274
- )
3275
- )), onChange(event), initialized.current = !0;
3276
- }, [activePath, onChange, pathKey, existingField, missingPresetInstructions]), null;
3277
- }
3278
- function FieldRefPreview(props) {
3279
- const { actions } = props, documentSchema = react.useContext(SelectedFieldContext)?.documentSchema, path = react.useContext(InlineBlockValueContext)?.path ?? props.path, selectedField = useSelectedField(documentSchema, path);
3280
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gap: 2, align: "center", style: { width: "100%" }, children: [
3281
- /* @__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" }) }) }),
3282
- actions
3283
- ] });
3284
- }
3285
- function HiddenFieldTitle(props) {
3286
- return props.renderDefault({ ...props, title: "", level: props.level - 2, changed: !1 });
3287
- }
3288
- function InstructionVisibility(props) {
3289
- const { value, onChange } = props, user = sanity.useCurrentUser(), handleChange = react.useCallback(() => {
3290
- const newValue = value ? "" : user?.id ?? "";
3291
- onChange(newValue ? sanity.set(newValue) : sanity.unset());
3292
- }, [onChange, user, value]), id = react.useId();
3293
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gap: 2, align: "flex-start", children: [
3294
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { margin: "-3px 0" }, children: /* @__PURE__ */ jsxRuntime.jsx(
3295
- ui.Switch,
3296
- {
3297
- ...props.elementProps,
3298
- id,
3299
- value: `${!value}`,
3300
- checked: !value,
3301
- onChange: handleChange,
3302
- disabled: props.elementProps.readOnly
3303
- }
3304
- ) }),
3305
- /* @__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" }) })
3306
- ] }) });
3307
- }
3308
- function FieldRefPathInput(props) {
3309
- const documentSchema = react.useContext(SelectedFieldContext)?.documentSchema, { typePath } = react.useContext(AssistTypeContext), ref = react.useRef(null), id = react.useId(), { onChange } = props;
3310
- react.useEffect(() => {
3311
- ref.current?.querySelector("input")?.focus();
3312
- }, []);
3313
- const onSelect = react.useCallback((path) => onChange(sanity.set(path)), [onChange]), filter = react.useCallback(
3314
- (field) => {
3315
- if (!field.key.includes("|") || !typePath)
3316
- return !0;
3317
- if (field.key.includes("|") && !typePath.includes("|"))
3318
- return !1;
3319
- const fieldSegments = field.key.split("."), lastArrayItemIndex = fieldSegments.findLastIndex((s) => s.includes("|")), mustStartWith = fieldSegments.slice(0, lastArrayItemIndex + 1).join(".");
3320
- return typePath.startsWith(mustStartWith);
3321
- },
3322
- [typePath]
3323
- );
3324
- return documentSchema ? /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { flex: 1, style: { minWidth: 300 }, ref, children: /* @__PURE__ */ jsxRuntime.jsx(
3325
- FieldAutocomplete,
3326
- {
3327
- id,
3328
- schemaType: documentSchema,
3329
- onSelect,
3330
- fieldPath: props.value,
3331
- filter
3332
- }
3333
- ) }) : props.renderDefault(props);
3334
- }
3335
- function findFieldMember(members, fieldName) {
3336
- return members.find(
3337
- (m) => m.kind === "field" && m.name === fieldName || m.kind === "error" && m.fieldName === fieldName
3338
- );
3339
- }
3340
- function findFieldsetMember(members, fieldsetName) {
3341
- return members.find(
3342
- (m) => m.kind === "fieldSet" && m.fieldSet.name === fieldsetName
3343
- );
3344
- }
3345
- function InstructionInput(props) {
3346
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: [4, 4, 4, 5], children: [
3347
- /* @__PURE__ */ jsxRuntime.jsx(NameField, { ...props }),
3348
- /* @__PURE__ */ jsxRuntime.jsx(ShareField, { ...props }),
3349
- /* @__PURE__ */ jsxRuntime.jsx(ObjectMember, { fieldName: "prompt", ...props }),
3350
- /* @__PURE__ */ jsxRuntime.jsx(ObjectMember, { fieldName: "output", ...props })
3351
- ] });
3352
- }
3353
- function ObjectMember({ fieldName, ...props }) {
3354
- const member = findFieldMember(props.members, fieldName);
3355
- return member ? /* @__PURE__ */ jsxRuntime.jsx(sanity.ObjectInputMember, { ...props, member }) : null;
3356
- }
3357
- const NONE = [];
3358
- function NameField(props) {
3359
- 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(() => {
3360
- if (titleMember)
3361
- return titleMember.kind === "error" ? titleMember : {
3362
- ...titleMember,
3363
- field: {
3364
- ...titleMember?.field,
3365
- schemaType: {
3366
- ...titleMember?.field.schemaType,
3367
- placeholder: titlePlaceholder
3368
- }
3369
- }
3370
- };
3371
- }, [titleMember, titlePlaceholder]);
3372
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, { space: 5, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 2, children: [
3373
- /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { gap: 1, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { as: "label", weight: "semibold", size: 1, htmlFor: titleId, children: "Name" }) }),
3374
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 1, children: "How this instruction appears in menus" }),
3375
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", children: [
3376
- iconMember && /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { flex: "none", children: /* @__PURE__ */ jsxRuntime.jsx(sanity.ObjectInputMember, { ...props, member: iconMember }) }),
3377
- moddedTitleMember && /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { flex: 1, style: { marginLeft: -1 }, children: /* @__PURE__ */ jsxRuntime.jsx(sanity.ObjectInputMember, { ...props, member: moddedTitleMember }) })
3378
- ] })
3379
- ] }) });
3380
- }
3381
- function ShareField(props) {
3382
- const members = findFieldsetMember(props.members, "appearance")?.fieldSet.members ?? NONE, visibilityMember = findFieldMember(members, "userId");
3383
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: visibilityMember && /* @__PURE__ */ jsxRuntime.jsx(sanity.ObjectInputMember, { ...props, member: visibilityMember }) });
3384
- }
3385
- function InstructionOutputField(props) {
3386
- const { fieldSchema } = react.useContext(SelectedFieldContext) ?? {};
3387
- return !fieldSchema || !(sanity.isObjectSchemaType(fieldSchema) || sanity.isArrayOfObjectsSchemaType(fieldSchema)) ? null : /* @__PURE__ */ jsxRuntime.jsx(EnabledOutputField, { ...props, fieldSchema, children: props.children });
3388
- }
3389
- function EnabledOutputField({
3390
- fieldSchema,
3391
- ...props
3392
- }) {
3393
- const [open, setOpen] = react.useState(!!props.value?.length), onExpand = react.useCallback(() => setOpen(!0), []), onCollapse = react.useCallback(() => setOpen(!1), []);
3394
- return props.renderDefault({
3395
- ...props,
3396
- collapsible: !0,
3397
- onExpand,
3398
- onCollapse,
3399
- collapsed: !open,
3400
- level: 1,
3401
- title: sanity.isObjectSchemaType(fieldSchema) ? "Allowed fields" : "Allowed types"
3402
- });
3403
- }
3404
- function InstructionOutputInput(props) {
3405
- const { fieldSchema } = react.useContext(SelectedFieldContext) ?? {};
3406
- return fieldSchema ? sanity.isObjectSchemaType(fieldSchema) ? /* @__PURE__ */ jsxRuntime.jsx(ObjectOutputInput, { ...props, fieldSchema }) : sanity.isArrayOfObjectsSchemaType(fieldSchema) ? /* @__PURE__ */ jsxRuntime.jsx(ArrayOutputInput, { ...props, fieldSchema }) : null : null;
3407
- }
3408
- function useEmptySelectAllValue(value, allowedValues, onChange) {
3409
- react.useEffect(() => {
3410
- const validValues = value?.filter(
3411
- (v) => allowedValues.find(
3412
- (f) => f.name === (v._type === outputFieldTypeName ? v.relativePath : v.type)
3413
- )
3414
- ), valueLength = value?.length ?? 0, validLength = validValues?.length ?? 0;
3415
- (!validLength && valueLength || validLength >= allowedValues.length) && onChange(sanity.PatchEvent.from([sanity.unset()]));
3416
- }, [allowedValues, value, onChange]);
3417
- }
3418
- function ObjectOutputInput({
3419
- fieldSchema,
3420
- ...props
3421
- }) {
3422
- const { value, onChange } = props, fields = react.useMemo(
3423
- () => fieldSchema.fields.filter((field) => isAssistSupported(field.type)),
3424
- [fieldSchema.fields]
3425
- );
3426
- useEmptySelectAllValue(value, fields, onChange);
3427
- const onSelectChange = react.useCallback(
3428
- (checked, selectedValue) => {
3429
- if (checked)
3430
- if (value?.length)
3431
- onChange(sanity.PatchEvent.from(sanity.unset([{ _key: selectedValue }])));
3432
- else {
3433
- const items = fields.filter((f) => f.name !== selectedValue).map(
3434
- (field) => sanity.typed({
3435
- _key: field.name,
3436
- _type: "sanity.assist.output.field",
3437
- relativePath: field.name
3438
- })
3439
- );
3440
- onChange(sanity.PatchEvent.from([sanity.setIfMissing([]), sanity.insert(items, "after", [-1])]));
3441
- }
3442
- else {
3443
- const patchValue = {
3444
- _key: selectedValue,
3445
- _type: "sanity.assist.output.field",
3446
- relativePath: selectedValue
3447
- };
3448
- onChange(sanity.PatchEvent.from([sanity.setIfMissing([]), sanity.insert([patchValue], "after", [-1])]));
3449
- }
3450
- },
3451
- [onChange, value, fields]
3452
- );
3453
- 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(
3454
- Selectable,
3455
- {
3456
- value: field.name,
3457
- title: field.type.title ?? field.name,
3458
- arrayValue: value,
3459
- onChange: onSelectChange
3460
- }
3461
- ) }, field.name)) });
3462
- }
3463
- function ArrayOutputInput({
3464
- fieldSchema,
3465
- ...props
3466
- }) {
3467
- const { value, onChange } = props, ofItems = react.useMemo(
3468
- () => fieldSchema.of.filter((itemType) => isAssistSupported(itemType)),
3469
- [fieldSchema.of]
3470
- );
3471
- useEmptySelectAllValue(value, ofItems, onChange);
3472
- const onSelectChange = react.useCallback(
3473
- (checked, selectedValue) => {
3474
- if (checked)
3475
- if (value?.length)
3476
- onChange(sanity.PatchEvent.from(sanity.unset([{ _key: selectedValue }])));
3477
- else {
3478
- const items = ofItems.filter((f) => f.name !== selectedValue).map(
3479
- (field) => sanity.typed({
3480
- _key: field.name,
3481
- _type: "sanity.assist.output.type",
3482
- type: field.name
3483
- })
3484
- );
3485
- onChange(sanity.PatchEvent.from([sanity.setIfMissing([]), sanity.insert(items, "after", [-1])]));
3486
- }
3487
- else {
3488
- const patchValue = {
3489
- _key: selectedValue,
3490
- _type: "sanity.assist.output.type",
3491
- type: selectedValue
3492
- };
3493
- onChange(sanity.PatchEvent.from([sanity.setIfMissing([]), sanity.insert([patchValue], "after", [-1])]));
3494
- }
3495
- },
3496
- [onChange, value, ofItems]
3497
- );
3498
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, { space: 2, children: ofItems.map((itemType) => /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { children: /* @__PURE__ */ jsxRuntime.jsx(
3499
- Selectable,
3500
- {
3501
- value: itemType.name,
3502
- title: isType(itemType, "block") ? "Text" : itemType.title ?? itemType.name,
3503
- arrayValue: value,
3504
- onChange: onSelectChange
3505
- }
3506
- ) }, itemType.name)) });
3507
- }
3508
- function Selectable({
3509
- title,
3510
- arrayValue,
3511
- value,
3512
- onChange
3513
- }) {
3514
- const checked = !arrayValue?.length || !!arrayValue?.find((v) => v._key === value), handleChange = react.useCallback(() => onChange(checked, value), [onChange, checked, value]);
3515
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gap: 2, align: "flex-start", children: [
3516
- /* @__PURE__ */ jsxRuntime.jsx(ui.Checkbox, { checked, onChange: handleChange }),
3517
- /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { marginTop: 1, onClick: handleChange, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { style: { cursor: "default" }, size: 1, children: title }) })
3518
- ] });
3519
- }
3520
- const PteMods = styledComponents.styled(ui.Box)`
3521
- & [data-testid='pt-editor__toolbar-card'] > div > div:last-child {
3522
- display: none;
3523
- }
3524
- & [data-testid='pt-editor'] {
3525
- min-height: 300px;
3526
- }
3527
- & [data-testid='pt-editor'] .pt-inline-object * {
3528
- max-width: 400px;
3529
- }
3530
- `;
3531
- function PromptInput(props) {
3532
- return useOnlyInlineBlocks(props), /* @__PURE__ */ jsxRuntime.jsx(PteMods, { children: props.renderDefault(props) });
3533
- }
3534
- function useOnlyInlineBlocks(props) {
3535
- react.useEffect(() => {
3536
- let needsFix = !1;
3537
- const val = (props.value ?? []).map((block) => block._type === "block" ? block : (needsFix = !0, sanity.typed({
3538
- _key: randomKey(12),
3539
- _type: "block",
3540
- level: 0,
3541
- markDefs: [],
3542
- style: "normal",
3543
- children: [block]
3544
- })));
3545
- needsFix && props.onChange(sanity.set(val));
3546
- }, []);
3547
- }
3548
- function InstructionsArrayField(props) {
3549
- return props.renderDefault({
3550
- ...props,
3551
- title: " "
3552
- });
3553
- }
3554
- function InstructionsArrayInput(props) {
3555
- const user = sanity.useCurrentUser(), originalValue = props.value, originalMembers = props.members, value = react.useMemo(
3556
- () => (originalValue ?? []).filter((v) => !v.userId || v.userId === user?.id),
3557
- [originalValue, user]
3558
- ), members = react.useMemo(
3559
- () => (originalMembers ?? []).filter((v) => {
3560
- if (v.kind === "error")
3561
- return !0;
3562
- const value2 = v?.item?.value;
3563
- return !value2.userId || value2.userId === user?.id;
3564
- }),
3565
- [originalMembers, user]
3566
- );
3567
- return props.renderDefault({ ...props, value, members });
3568
- }
3569
- function HideReferenceChangedBannerInput(props) {
3570
- const ref = react.useRef(null);
3571
- return react.useEffect(() => {
3572
- const parent = ref.current?.closest('[data-testid="pane-content"]');
3573
- if (!parent)
3574
- return;
3575
- const style = document.createElement("style"), parentId = `id-${Math.random()}`.replace(".", "-");
3576
- parent.id = parentId, style.innerText = `
3577
- #${parentId} [data-testid="reference-changed-banner"] { display: none; }
3578
- `, parent.prepend(style);
3579
- }, [ref]), /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { ref, children: props.renderDefault(props) });
3580
- }
3581
- const contextDocumentSchema = sanity.defineType({
3582
- type: "document",
3583
- name: contextDocumentTypeName,
3584
- title: "AI context",
3585
- liveEdit: !0,
3586
- icon: icons.TokenIcon,
3587
- components: {
3588
- input: HideReferenceChangedBannerInput
3589
- },
3590
- fields: [
3591
- sanity.defineField({
3592
- type: "string",
3593
- name: "title",
3594
- title: "Title"
3595
- }),
3596
- sanity.defineField({
3597
- name: "context",
3598
- type: "array",
3599
- title: "Context",
3600
- of: [
3601
- sanity.defineArrayMember({
3602
- type: "block",
3603
- styles: [{ title: "Normal", value: "normal" }],
3604
- lists: [],
3605
- marks: {
3606
- decorators: [],
3607
- annotations: []
3608
- }
3609
- })
3610
- ]
3611
- })
3612
- ],
3613
- preview: {
3614
- select: {
3615
- title: "title",
3616
- context: "context"
3617
- },
3618
- prepare({ title, context }) {
3619
- const words = context?.flatMap((block) => block?.children).flatMap((child) => child?.text?.split(" ")).filter(Boolean)?.length ?? 0;
3620
- return {
3621
- title,
3622
- subtitle: `Words: ${words}`,
3623
- media: icons.DocumentTextIcon
3624
- };
3625
- }
3626
- }
3627
- }), fieldReference = sanity.defineType({
3628
- type: "object",
3629
- name: fieldReferenceTypeName,
3630
- title: "Field",
3631
- icon: icons.ThListIcon,
3632
- fields: [
3633
- sanity.defineField({
3634
- type: "string",
3635
- name: "path",
3636
- title: "Field",
3637
- components: {
3638
- input: FieldRefPathInput
3639
- },
3640
- validation: (rule) => {
3641
- const getForSchemaType = createFieldRefCache();
3642
- return rule.custom((value, context) => {
3643
- if (!value)
3644
- return "Please select a field";
3645
- try {
3646
- const docId = context.document?._id;
3647
- if (!docId)
3648
- return "Field reference cannot be used outside document inspector context. Could not resolve document id.";
3649
- const targetDocType = docId.replace(new RegExp(`^${assistDocumentIdPrefix}`), ""), schema = context.schema.get(targetDocType);
3650
- if (!schema)
3651
- return `Field reference cannot be used outside document inspector context. Could not resolve schema: ${targetDocType}`;
3652
- const { fieldRefs } = getForSchemaType(schema);
3653
- return fieldRefs.find((r) => r.key === value) ? !0 : `Field with path "${value}" does not exist in the schema.`;
3654
- } catch (e) {
3655
- return console.error("Failed to resolve field reference", e), "Invalid field reference.";
3656
- }
3657
- });
3658
- }
3659
- })
3660
- ],
3661
- preview: {
3662
- select: {
3663
- path: "path"
3664
- },
3665
- prepare({ path }) {
3666
- return {
3667
- title: path,
3668
- path,
3669
- icon: icons.CodeIcon
3670
- };
3671
- }
3672
- },
3673
- components: {
3674
- preview: FieldRefPreview
3675
- },
3676
- options: {
3677
- modal: {
3678
- type: "popover"
3679
- }
3680
- }
3681
- }), userInput = sanity.defineType({
3682
- type: "object",
3683
- name: userInputTypeName,
3684
- title: "User input",
3685
- icon: icons.ComposeIcon,
3686
- fields: [
3687
- sanity.defineField({
3688
- type: "string",
3689
- name: "message",
3690
- title: "User input title",
3691
- placeholder: "Provide instruction text",
3692
- description: "The header above the user input text field",
3693
- validation: (rule) => rule.required()
3694
- }),
3695
- sanity.defineField({
3696
- type: "text",
3697
- rows: 3,
3698
- name: "description",
3699
- title: "User input description",
3700
- description: "The description above the user input text field"
3701
- })
3702
- ],
3703
- preview: {
3704
- select: {
3705
- title: "message"
3706
- }
3707
- },
3708
- options: {
3709
- modal: {
3710
- type: "popover",
3711
- width: 1
3712
- }
3713
- }
3714
- }), promptContext = sanity.defineType({
3715
- type: "object",
3716
- name: instructionContextTypeName,
3717
- title: contextDocumentSchema.title,
3718
- icon: contextDocumentSchema.icon,
3719
- fields: [
3720
- sanity.defineField({
3721
- type: "reference",
3722
- name: "reference",
3723
- to: [{ type: contextDocumentSchema.name }],
3724
- title: "Context",
3725
- description: "The referenced context will be inserted into the instruction",
3726
- validation: (rule) => rule.required(),
3727
- components: {
3728
- input: function(props) {
3729
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { style: { maxWidth: 300 }, children: props.renderDefault(props) });
3730
- }
3731
- }
3732
- })
3733
- ],
3734
- preview: {
3735
- select: {
3736
- ref: "reference._id",
3737
- title: "reference.title",
3738
- context: "reference.context"
3739
- },
3740
- prepare(select) {
3741
- return select.ref ? contextDocumentSchema?.preview?.prepare?.(select) ?? select : { title: "No reference selected", media: contextDocumentSchema.icon };
3742
- }
3743
- },
3744
- options: {
3745
- modal: {
3746
- type: "popover",
3747
- width: "auto"
3748
- }
3749
- }
3750
- }), prompt = sanity.defineType({
3751
- type: "array",
3752
- name: promptTypeName,
3753
- title: "Prompt",
3754
- of: [
3755
- sanity.defineArrayMember({
3756
- type: "block",
3757
- styles: [{ title: "Normal", value: "normal" }],
3758
- lists: [],
3759
- marks: {
3760
- decorators: [],
3761
- annotations: []
3762
- },
3763
- of: [
3764
- sanity.defineArrayMember({
3765
- type: fieldReference.name
3766
- }),
3767
- sanity.defineArrayMember({
3768
- type: promptContext.name
3769
- }),
3770
- sanity.defineArrayMember({
3771
- type: userInput.name
3772
- })
3773
- ]
3774
- })
3775
- /* defineArrayMember({
3776
- type: fieldReference.name,
3777
- }),
3778
- defineArrayMember({
3779
- type: promptContext.name,
3780
- }),
3781
- defineArrayMember({
3782
- type: userInput.name,
3783
- }),*/
3784
- ]
3785
- }), outputFieldType = sanity.defineType({
3786
- type: "object",
3787
- name: outputFieldTypeName,
3788
- title: "Output field",
3789
- fields: [
3790
- sanity.defineField({
3791
- type: "string",
3792
- name: "path",
3793
- title: "Path"
3794
- })
3795
- ]
3796
- }), outputTypeType = sanity.defineType({
3797
- type: "object",
3798
- name: outputTypeTypeName,
3799
- title: "Output type",
3800
- fields: [
3801
- sanity.defineField({
3802
- type: "string",
3803
- name: "type",
3804
- title: "Type"
3805
- })
3806
- ]
3807
- }), instruction = sanity.defineType({
3808
- type: "object",
3809
- name: instructionTypeName,
3810
- title: "Instruction",
3811
- fieldsets: [
3812
- { name: "appearance", title: "Appearance", options: { collapsible: !0, collapsed: !0 } }
3813
- ],
3814
- preview: {
3815
- select: {
3816
- icon: "icon",
3817
- title: "title",
3818
- userId: "userId"
3819
- },
3820
- prepare: ({ icon, title, userId }) => ({
3821
- title,
3822
- icon: icon ? icons.icons[icon] : icons.SparklesIcon,
3823
- userId
3824
- })
3825
- },
3826
- components: {
3827
- input: InstructionInput,
3828
- preview: (props) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gap: 3, align: "center", padding: 2, children: [
3829
- props.icon && /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { flex: "none", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, children: react.createElement(props.icon) }) }),
3830
- /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, { flex: 1, space: 2, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, textOverflow: "ellipsis", weight: "medium", children: getInstructionTitle(props) }) }),
3831
- props.userId && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, children: /* @__PURE__ */ jsxRuntime.jsx(
3832
- ui.Tooltip,
3833
- {
3834
- content: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, children: "Only visible to you" }),
3835
- padding: 2,
3836
- placement: "top",
3837
- portal: !0,
3838
- children: /* @__PURE__ */ jsxRuntime.jsx(icons.LockIcon, {})
3839
- }
3840
- ) })
3841
- ] })
3842
- },
3843
- fields: [
3844
- sanity.defineField({
3845
- type: prompt.name,
3846
- name: "prompt",
3847
- title: "Instruction",
3848
- description: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3849
- "Learn from",
3850
- " ",
3851
- /* @__PURE__ */ jsxRuntime.jsxs("a", { href: instructionGuideUrl, target: "_blank", rel: "noreferrer", children: [
3852
- "our instruction guide ",
3853
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowRightIcon, {})
3854
- ] })
3855
- ] }),
3856
- components: {
3857
- input: PromptInput
3858
- }
3859
- }),
3860
- sanity.defineField({
3861
- type: "string",
3862
- name: "icon",
3863
- title: "Icon",
3864
- fieldset: "appearance",
3865
- components: {
3866
- field: HiddenFieldTitle,
3867
- input: IconInput
3868
- }
3869
- }),
3870
- sanity.defineField({
3871
- type: "string",
3872
- name: "title",
3873
- title: "Title",
3874
- fieldset: "appearance",
3875
- components: {
3876
- field: HiddenFieldTitle
3877
- }
3878
- }),
3879
- sanity.defineField({
3880
- type: "string",
3881
- name: "userId",
3882
- title: "Visibility",
3883
- fieldset: "appearance",
3884
- components: {
3885
- field: HiddenFieldTitle,
3886
- input: InstructionVisibility
3887
- },
3888
- initialValue: (params, context) => context.currentUser?.id ?? "",
3889
- readOnly: (context) => !!(context.parent?.createdById && context.parent?.createdById !== context.currentUser?.id)
3890
- }),
3891
- sanity.defineField({
3892
- type: "string",
3893
- name: "createdById",
3894
- title: "Created by",
3895
- hidden: !0,
3896
- fieldset: "appearance",
3897
- initialValue: (params, context) => context.currentUser?.id ?? ""
3898
- }),
3899
- sanity.defineField({
3900
- type: "array",
3901
- name: "output",
3902
- title: "Output filter",
3903
- components: {
3904
- input: InstructionOutputInput,
3905
- field: InstructionOutputField
3906
- },
3907
- of: [
3908
- sanity.defineArrayMember({ type: outputFieldType.name }),
3909
- sanity.defineArrayMember({ type: outputTypeType.name })
3910
- ]
3911
- })
3912
- ]
3913
- }), fieldInstructions = sanity.defineType({
3914
- type: "object",
3915
- name: assistFieldTypeName,
3916
- title: "Field prompt",
3917
- /* components: {
3918
- input: FieldPromptInput,
3919
- },*/
3920
- fields: [
3921
- sanity.defineField({
3922
- type: "string",
3923
- name: "path",
3924
- title: "Path",
3925
- readOnly: !0,
3926
- hidden: !0
3927
- }),
3928
- sanity.defineField({
3929
- type: "array",
3930
- name: "instructions",
3931
- title: "Instructions",
3932
- of: [{ type: instruction.name }],
3933
- components: {
3934
- field: InstructionsArrayField,
3935
- input: InstructionsArrayInput
3936
- }
3937
- })
3938
- ],
3939
- preview: {
3940
- select: {
3941
- title: "path"
3942
- }
3943
- }
3944
- }), assistDocumentSchema = sanity.defineType({
3945
- //NOTE: this is a document type. Using object here ensures it does not appear in structure menus
3946
- type: "object",
3947
- liveEdit: !0,
3948
- name: assistDocumentTypeName,
3949
- title: "AI Document",
3950
- components: {
3951
- input: AssistDocumentForm,
3952
- field: (props) => props.renderDefault({ ...props, title: "" })
3953
- },
3954
- fields: [
3955
- sanity.defineField({
3956
- type: "string",
3957
- name: "title",
3958
- title: "Title"
3959
- }),
3960
- sanity.defineField({
3961
- type: "array",
3962
- name: "fields",
3963
- title: "Fields",
3964
- of: [{ type: fieldInstructions.name }]
3965
- })
3966
- ],
3967
- preview: {
3968
- select: {
3969
- title: "title"
3970
- }
3971
- }
3972
- }), instructionTask = sanity.defineType({
3973
- type: "object",
3974
- name: instructionTaskTypeName,
3975
- title: "Instruction task",
3976
- fields: [
3977
- sanity.defineField({
3978
- type: "string",
3979
- name: "path",
3980
- title: "Path"
3981
- }),
3982
- sanity.defineField({
3983
- type: "string",
3984
- name: "instructionKey",
3985
- title: "Instruction key"
3986
- }),
3987
- sanity.defineField({
3988
- type: "datetime",
3989
- name: "started",
3990
- title: "Started"
3991
- }),
3992
- sanity.defineField({
3993
- type: "datetime",
3994
- name: "updated",
3995
- title: "Updated"
3996
- }),
3997
- sanity.defineField({
3998
- type: "string",
3999
- name: "info",
4000
- title: "Info"
4001
- })
4002
- ]
4003
- }), documentInstructionStatus = sanity.defineType({
4004
- //NOTE: this is a document type. Using object here ensures it does not appear in structure menus
4005
- type: "object",
4006
- liveEdit: !0,
4007
- name: assistTasksStatusTypeName,
4008
- title: "Document instruction status",
4009
- fields: [
4010
- sanity.defineField({
4011
- type: "array",
4012
- name: "tasks",
4013
- title: "Tasks",
4014
- of: [{ type: instructionTask.name }]
4015
- })
4016
- ]
4017
- });
4018
- function excludeComments(type) {
4019
- const existingRender = type?.components?.field;
4020
- return {
4021
- ...type,
4022
- ..."components" in type ? {
4023
- components: {
4024
- ...type.components,
4025
- field: (props) => {
4026
- const newProps = { ...props, __internal_comments: void 0 };
4027
- return typeof existingRender == "function" ? existingRender(newProps) : props.renderDefault(newProps);
4028
- }
4029
- }
4030
- } : {},
4031
- ..."fields" in type ? {
4032
- // recursively disable comments in fields
4033
- fields: type.fields?.map((field) => excludeComments(field))
4034
- } : {},
4035
- ..."of" in type ? {
4036
- // recursively disable comments in array items
4037
- of: type.of?.map((arrayItemType) => excludeComments(arrayItemType))
4038
- } : {}
4039
- };
4040
- }
4041
- const instructionForm = [
4042
- fieldInstructions,
4043
- instruction,
4044
- fieldReference,
4045
- prompt,
4046
- userInput,
4047
- promptContext
4048
- ].map(excludeComments), schemaTypes = [
4049
- ...instructionForm,
4050
- outputFieldType,
4051
- outputTypeType,
4052
- assistDocumentSchema,
4053
- documentInstructionStatus,
4054
- instructionTask,
4055
- contextDocumentSchema
4056
- ], assist = sanity.definePlugin((config) => {
4057
- const configWithDefaults = config ?? {}, styleguide = configWithDefaults.translate?.styleguide || "", maxPathDepth = configWithDefaults.assist?.maxPathDepth, temperature = configWithDefaults.assist?.temperature;
4058
- if (typeof styleguide == "string" && validateStyleguide(styleguide), maxPathDepth !== void 0 && (maxPathDepth < 1 || maxPathDepth > 12))
4059
- throw new Error(
4060
- `[${packageName}]: \`assist.maxPathDepth\` must be be in the range [1,12] inclusive, but was ${maxPathDepth}`
4061
- );
4062
- if (temperature !== void 0 && (temperature < 0 || temperature > 1))
4063
- throw new Error(
4064
- `[${packageName}]: \`assist.maxPathDepth\` must be be in the range [0,1] inclusive, but was ${temperature}`
4065
- );
4066
- return {
4067
- name: packageName,
4068
- handlesGDR: !0,
4069
- schema: {
4070
- types: schemaTypes
4071
- },
4072
- i18n: {
4073
- bundles: [{}]
4074
- },
4075
- document: {
4076
- inspectors: (prev, context) => {
4077
- const documentType = context.documentType, docSchema = context.schema.get(documentType);
4078
- return docSchema && isSchemaAssistEnabled(docSchema) ? [...prev, assistInspector] : prev;
4079
- },
4080
- unstable_fieldActions: (prev, { documentType, schema }) => {
4081
- if (documentType === assistDocumentTypeName)
4082
- return [];
4083
- const docSchema = schema.get(documentType);
4084
- return docSchema && isSchemaAssistEnabled(docSchema) ? [...prev, assistFieldActions] : prev;
4085
- },
4086
- unstable_languageFilter: (prev, { documentId, schema, schemaType }) => {
4087
- if (schemaType === assistDocumentTypeName)
4088
- return [];
4089
- const docSchema = schema.get(schemaType);
4090
- return docSchema && sanity.isObjectSchemaType(docSchema) && isSchemaAssistEnabled(docSchema) ? [...prev, createAssistDocumentPresence(documentId)] : prev;
4091
- },
4092
- components: {
4093
- unstable_layout: AssistDocumentLayout
4094
- }
4095
- },
4096
- studio: {
4097
- components: {
4098
- layout: function(props) {
4099
- return /* @__PURE__ */ jsxRuntime.jsx(AssistLayout, { ...props, config: configWithDefaults });
4100
- }
4101
- }
4102
- },
4103
- form: {
4104
- components: {
4105
- input: AssistDocumentInputWrapper,
4106
- field: AssistFieldWrapper,
4107
- item: AssistItem,
4108
- block: AssistFormBlock,
4109
- inlineBlock: AssistInlineFormBlock
4110
- }
4111
- },
4112
- plugins: [
4113
- sanity.definePlugin({
4114
- name: `${packageName}/safe-value-input`,
4115
- form: { components: { input: SafeValueInput } }
4116
- })(),
4117
- sanity.definePlugin({
4118
- name: `${packageName}/generate-caption`,
4119
- form: {
4120
- components: {
4121
- input: (props) => {
4122
- const { schemaType } = props;
4123
- return isImage(schemaType) ? /* @__PURE__ */ jsxRuntime.jsx(ImageContextProvider, { ...props }) : props.renderDefault(props);
4124
- }
4125
- }
4126
- }
4127
- })()
4128
- ]
4129
- };
4130
- }), fetch = (client, query, params, options2) => rxjs.defer(
4131
- () => (
4132
- // getVersionedClient(options.apiVersion)
4133
- client.observable.fetch(query, params, {
4134
- tag: options2.tag,
4135
- filterResponse: !0
4136
- })
4137
- )
4138
- ), listen = (client, query, params, options2) => rxjs.defer(
4139
- () => (
4140
- // getVersionedClient(options.apiVersion)
4141
- client.listen(query, params, {
4142
- events: ["welcome", "mutation", "reconnect"],
4143
- includeResult: !1,
4144
- visibility: "query",
4145
- tag: options2.tag
4146
- })
4147
- )
4148
- );
4149
- function isWelcomeEvent(event) {
4150
- return event.type === "welcome";
4151
- }
4152
- const listenQuery = (client, query, params = {}, options2 = {}) => {
4153
- const fetchQuery = query, listenerQuery = query, fetchOnce$ = fetch(client, fetchQuery, params, options2), events$ = listen(client, listenerQuery, params, options2).pipe(
4154
- operators.mergeMap((ev, i) => i === 0 && !isWelcomeEvent(ev) ? rxjs.throwError(
4155
- new Error(
4156
- ev.type === "reconnect" ? "Could not establish EventSource connection" : `Received unexpected type of first event "${ev.type}"`
4157
- )
4158
- ) : rxjs.of(ev)),
4159
- operators.share()
4160
- ), [welcome$, mutationAndReconnect$] = rxjs.partition(events$, isWelcomeEvent), isRelevantEvent = (event) => !options2.transitions || event.type !== "mutation" ? !0 : options2.transitions.includes(event.transition);
4161
- return rxjs.merge(
4162
- welcome$.pipe(operators.take(1)),
4163
- mutationAndReconnect$.pipe(
4164
- operators.filter(isRelevantEvent),
4165
- rxjs.switchMap((event) => rxjs.merge(rxjs.of(event), rxjs.of(event).pipe(rxjs.delay(options2.throttleTime || 1e3))))
4166
- )
4167
- ).pipe(rxjsExhaustmapWithTrailing.exhaustMapToWithTrailing(fetchOnce$));
4168
- }, DEFAULT_PARAMS = {}, DEFAULT_OPTIONS = { apiVersion: "v2022-05-09" };
4169
- function useListeningQuery(query, params = DEFAULT_PARAMS, options2 = DEFAULT_OPTIONS) {
4170
- 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" });
4171
- return react.useEffect(() => (subscription.current = listenQuery(client, query, params, options2).pipe(
4172
- operators.distinctUntilChanged(isEqual__default.default),
4173
- operators.catchError((err) => (console.error(err), setError(err), setLoading(!1), setData(null), err))
4174
- ).subscribe((documents) => {
4175
- setData((current) => isEqual__default.default(current, documents) ? current : documents), setLoading(!1), setError(!1);
4176
- }), () => subscription.current ? subscription.current.unsubscribe() : void 0), [query, params, options2, client]), { loading, error, data };
4177
- }
4178
- const NO_DATA = [], defaultTitle = "Sync schema";
4179
- function SchemaTypeTool() {
4180
- 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)", {
4181
- type: assistSerializedTypeName
4182
- }), types = react.useMemo(() => serializeSchema(schema), [schema]), storeTypes = react.useCallback(() => {
4183
- setSaving(!0);
4184
- let canSave = !0;
4185
- async function store() {
4186
- setSyncTitle(`Syncing 0/${types.length}`);
4187
- const transaction = client.transaction();
4188
- for (let i = 0; i < types.length && canSave; i++) {
4189
- const type = types[i];
4190
- await transaction.createOrReplace(type), i > 0 && i % 50 === 0 && (await transaction.commit(), transaction.reset(), setSyncTitle(`Syncing ${i}/${types.length}`));
4191
- }
4192
- await transaction.commit();
4193
- }
4194
- return store().catch(console.error).finally(() => {
4195
- setSaving(!1), setSyncTitle(defaultTitle);
4196
- }), () => {
4197
- canSave = !1, setSaving(!1), setSyncTitle(defaultTitle);
4198
- };
4199
- }, [types, client, setSaving, setSyncTitle]);
4200
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { padding: 4, overflow: "auto", style: { height: "calc(100vh - 81px)" }, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 4, children: [
4201
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { children: /* @__PURE__ */ jsxRuntime.jsx(
4202
- ui.Button,
4203
- {
4204
- icon: saving ? /* @__PURE__ */ jsxRuntime.jsx(ui.Spinner, { style: { marginTop: 5 } }) : icons.SyncIcon,
4205
- text: syncTitle,
4206
- disabled: saving,
4207
- onClick: storeTypes
4208
- }
4209
- ) }),
4210
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gap: 2, children: [
4211
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 2, children: [
4212
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: "Studio schema" }),
4213
- /* @__PURE__ */ jsxRuntime.jsx("ul", { children: types.map((type) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(SchemaEntry, { schemaStub: type }) }, type.name)) })
4214
- ] }),
4215
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 2, children: [
4216
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: "Stored schema" }),
4217
- /* @__PURE__ */ jsxRuntime.jsx("ul", { children: (data ?? NO_DATA).map((type) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(SchemaEntry, { schemaStub: type }) }, type.name)) })
4218
- ] })
4219
- ] })
4220
- ] }) });
4221
- }
4222
- function SchemaEntry({ schemaStub }) {
4223
- const out = react.useMemo(() => JSON.stringify(schemaStub, null, 2), [schemaStub]);
4224
- return /* @__PURE__ */ jsxRuntime.jsx("pre", { children: out });
4225
- }
4226
- function useUserInput() {
4227
- const { getUserInput } = useRunInstruction();
4228
- return getUserInput;
4229
- }
4230
- exports.SchemaTypeTool = SchemaTypeTool;
4231
- exports.assist = assist;
4232
- exports.contextDocumentTypeName = contextDocumentTypeName;
4233
- exports.defaultLanguageOutputs = defaultLanguageOutputs;
4234
- exports.defineAssistFieldAction = defineAssistFieldAction;
4235
- exports.defineAssistFieldActionGroup = defineAssistFieldActionGroup;
4236
- exports.defineFieldActionDivider = defineFieldActionDivider;
4237
- exports.isType = isType;
4238
- exports.useUserInput = useUserInput;
4239
- //# sourceMappingURL=index.cjs.map