@ai-stack/payloadcms 3.2.20-beta → 3.2.22-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai/models/anthropic/index.js +9 -15
- package/dist/ai/models/anthropic/index.js.map +1 -1
- package/dist/ai/models/generateObject.d.ts +11 -0
- package/dist/ai/models/generateObject.js +22 -0
- package/dist/ai/models/generateObject.js.map +1 -0
- package/dist/ai/models/openai/index.js +19 -17
- package/dist/ai/models/openai/index.js.map +1 -1
- package/dist/collections/Instructions.js +2 -0
- package/dist/collections/Instructions.js.map +1 -1
- package/dist/endpoints/index.js +55 -6
- package/dist/endpoints/index.js.map +1 -1
- package/dist/fields/ComposeField/ComposeField.js +5 -3
- package/dist/fields/ComposeField/ComposeField.js.map +1 -1
- package/dist/fields/ComposeField/ComposeField.jsx +32 -0
- package/dist/fields/LexicalEditor/ComposeFeatureComponent.js +1 -1
- package/dist/fields/LexicalEditor/ComposeFeatureComponent.js.map +1 -1
- package/dist/fields/LexicalEditor/ComposeFeatureComponent.jsx +24 -0
- package/dist/fields/LexicalEditor/feature.client.jsx +21 -0
- package/dist/fields/PromptEditorField/PromptEditorField.jsx +42 -0
- package/dist/fields/SelectField/SelectField.jsx +38 -0
- package/dist/providers/FieldProvider/FieldProvider.d.ts +7 -4
- package/dist/providers/FieldProvider/FieldProvider.js +7 -6
- package/dist/providers/FieldProvider/FieldProvider.js.map +1 -1
- package/dist/providers/FieldProvider/FieldProvider.jsx +27 -0
- package/dist/providers/FieldProvider/useFieldProps.d.ts +1 -1
- package/dist/providers/FieldProvider/useFieldProps.js +2 -2
- package/dist/providers/FieldProvider/useFieldProps.js.map +1 -1
- package/dist/providers/InstructionsProvider/InstructionsProvider.jsx +45 -0
- package/dist/types.d.ts +4 -4
- package/dist/types.js.map +1 -1
- package/dist/ui/Compose/Compose.js +12 -81
- package/dist/ui/Compose/Compose.js.map +1 -1
- package/dist/ui/Compose/Compose.jsx +141 -0
- package/dist/ui/Compose/UndoRedoActions.jsx +34 -0
- package/dist/ui/Compose/compose.module.css +99 -12
- package/dist/ui/Compose/hooks/menu/Item.jsx +15 -0
- package/dist/ui/Compose/hooks/menu/TranslateMenu.js +1 -2
- package/dist/ui/Compose/hooks/menu/TranslateMenu.js.map +1 -1
- package/dist/ui/Compose/hooks/menu/TranslateMenu.jsx +58 -0
- package/dist/ui/Compose/hooks/menu/items.jsx +10 -0
- package/dist/ui/Compose/hooks/menu/useMenu.js +1 -1
- package/dist/ui/Compose/hooks/menu/useMenu.js.map +1 -1
- package/dist/ui/Compose/hooks/menu/useMenu.jsx +89 -0
- package/dist/ui/Compose/hooks/useActiveFieldTracking.d.ts +5 -0
- package/dist/ui/Compose/hooks/useActiveFieldTracking.js +225 -0
- package/dist/ui/Compose/hooks/useActiveFieldTracking.js.map +1 -0
- package/dist/ui/Compose/hooks/useGenerate.js +46 -79
- package/dist/ui/Compose/hooks/useGenerate.js.map +1 -1
- package/dist/ui/Icons/Icons.jsx +78 -0
- package/dist/ui/Icons/LottieAnimation.jsx +64 -0
- package/dist/utilities/extractPromptAttachments.d.ts +2 -2
- package/dist/utilities/extractPromptAttachments.js.map +1 -1
- package/dist/utilities/fieldToJsonSchema.d.ts +37 -0
- package/dist/utilities/fieldToJsonSchema.js +274 -0
- package/dist/utilities/fieldToJsonSchema.js.map +1 -0
- package/dist/utilities/getFieldBySchemaPath.d.ts +12 -1
- package/dist/utilities/getFieldBySchemaPath.js +63 -29
- package/dist/utilities/getFieldBySchemaPath.js.map +1 -1
- package/package.json +2 -1
- package/dist/ai/models/anthropic/generateRichText.d.ts +0 -1
- package/dist/ai/models/anthropic/generateRichText.js +0 -36
- package/dist/ai/models/anthropic/generateRichText.js.map +0 -1
- package/dist/ai/models/openai/generateRichText.d.ts +0 -1
- package/dist/ai/models/openai/generateRichText.js +0 -37
- package/dist/ai/models/openai/generateRichText.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/ui/Compose/hooks/useGenerate.ts"],"sourcesContent":["import { useCompletion, experimental_useObject as useObject } from '@ai-sdk/react'\nimport { useEditorConfigContext } from '@payloadcms/richtext-lexical/client'\nimport { toast, useConfig, useDocumentInfo, useField, useForm, useLocale } from '@payloadcms/ui'\nimport { jsonSchema } from 'ai'\nimport { useCallback, useEffect, useMemo, useRef } from 'react'\n\nimport type { ActionMenuItems, GenerateTextarea } from '../../../types.js'\n\nimport {\n PLUGIN_API_ENDPOINT_GENERATE,\n PLUGIN_API_ENDPOINT_GENERATE_UPLOAD,\n PLUGIN_INSTRUCTIONS_TABLE,\n PLUGIN_NAME,\n} from '../../../defaults.js'\nimport { useFieldProps } from '../../../providers/FieldProvider/useFieldProps.js'\nimport { editorSchemaValidator } from '../../../utilities/editorSchemaValidator.js'\nimport { setSafeLexicalState } from '../../../utilities/setSafeLexicalState.js'\nimport { useHistory } from './useHistory.js'\n\ntype ActionCallbackParams = { action: ActionMenuItems; params?: unknown }\n\nexport const useGenerate = ({ instructionId }: { instructionId: string }) => {\n // Create a ref to hold the current instructionId\n const instructionIdRef = useRef(instructionId)\n\n // Update the ref whenever instructionId changes\n useEffect(() => {\n instructionIdRef.current = instructionId\n }, [instructionId])\n\n const { type, path: pathFromContext } = useFieldProps()\n const editorConfigContext = useEditorConfigContext()\n\n const { editor } = editorConfigContext\n\n const { config } = useConfig()\n const {\n routes: { api },\n serverURL,\n } = config\n\n const { setValue } = useField<string>({\n path: pathFromContext ?? '',\n })\n\n const { set: setHistory } = useHistory()\n\n const { getData } = useForm()\n const { id: documentId, collectionSlug } = useDocumentInfo()\n\n const localFromContext = useLocale()\n const {\n config: { collections },\n } = useConfig()\n\n const collection = collections.find((collection) => collection.slug === PLUGIN_INSTRUCTIONS_TABLE)\n const { custom: { [PLUGIN_NAME]: { editorConfig = {} } = {} } = {} } = collection?.admin ?? {}\n const { schema: editorSchema = {} } = editorConfig\n\n const memoizedValidator = useMemo(() => {\n return editorSchemaValidator(editorSchema)\n }, [editorSchema])\n\n const memoizedSchema = useMemo(\n () =>\n jsonSchema(editorSchema, {\n validate: (value) => {\n const isValid = memoizedValidator(value)\n\n if (isValid) {\n return {\n success: true,\n value,\n }\n } else {\n return {\n error: new Error('Invalid schema'),\n success: false,\n }\n }\n },\n }),\n [memoizedValidator],\n )\n\n const {\n isLoading: loadingObject,\n object,\n stop: objectStop,\n submit,\n } = useObject({\n api: `/api${PLUGIN_API_ENDPOINT_GENERATE}`,\n onError: (error: any) => {\n toast.error(`Failed to generate: ${error.message}`)\n console.error('Error generating object:', error)\n },\n onFinish: (result) => {\n if (result.object) {\n setHistory(result.object)\n setValue(result.object)\n } else {\n console.log('onFinish: result ', result)\n }\n },\n schema: memoizedSchema,\n })\n\n useEffect(() => {\n if (!object) {\n return\n }\n\n requestAnimationFrame(() => {\n // TODO: Temporary disabled pre validation, sometimes it fails to validate\n // const validateObject = await memoizedSchema?.validate?.(object)\n // if (validateObject?.success) {\n setSafeLexicalState(object, editor)\n // }\n })\n }, [object, editor])\n\n const {\n complete,\n completion,\n isLoading: loadingCompletion,\n stop: completionStop,\n } = useCompletion({\n api: `${serverURL}${api}${PLUGIN_API_ENDPOINT_GENERATE}`,\n onError: (error: any) => {\n toast.error(`Failed to generate: ${error.message}`)\n console.error('Error generating text:', error)\n },\n onFinish: (prompt, result) => {\n setHistory(result)\n },\n streamProtocol: 'data',\n })\n\n useEffect(() => {\n if (!completion) {\n return\n }\n\n requestAnimationFrame(() => {\n setValue(completion)\n })\n }, [completion])\n\n const streamObject = useCallback(\n ({ action = 'Compose', params }: ActionCallbackParams) => {\n const doc = getData()\n\n const currentInstructionId = instructionIdRef.current\n\n const options = {\n action,\n actionParams: params,\n instructionId: currentInstructionId,\n }\n\n submit({\n allowedEditorNodes: Array.from(editor?._nodes?.keys() || []),\n doc: {\n ...doc,\n id: documentId,\n },\n locale: localFromContext?.code,\n options,\n })\n },\n [localFromContext?.code, instructionIdRef, documentId],\n )\n\n const streamText = useCallback(\n async ({ action = 'Compose', params }: ActionCallbackParams) => {\n const doc = getData()\n const currentInstructionId = instructionIdRef.current\n\n const options = {\n action,\n actionParams: params,\n instructionId: currentInstructionId,\n }\n\n await complete('', {\n body: {\n doc: {\n ...doc,\n id: documentId,\n },\n locale: localFromContext?.code,\n options,\n },\n })\n },\n [getData, localFromContext?.code, instructionIdRef, complete, documentId],\n )\n\n const generateUpload = useCallback(async () => {\n const doc = getData()\n const currentInstructionId = instructionIdRef.current\n\n return fetch(`${serverURL}${api}${PLUGIN_API_ENDPOINT_GENERATE_UPLOAD}`, {\n body: JSON.stringify({\n collectionSlug: collectionSlug ?? '',\n doc,\n documentId,\n locale: localFromContext?.code,\n options: {\n instructionId: currentInstructionId,\n },\n } satisfies Parameters<GenerateTextarea>[0]),\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n .then(async (uploadResponse) => {\n if (uploadResponse.ok) {\n const { result } = await uploadResponse.json()\n if (!result) {\n throw new Error('generateUpload: Something went wrong')\n }\n\n setValue(result?.id)\n setHistory(result?.id)\n console.log('Image updated...', result)\n } else {\n const { errors = [] } = await uploadResponse.json()\n const errStr = errors.map((error: any) => error.message).join(', ')\n throw new Error(errStr)\n }\n return uploadResponse\n })\n .catch((error) => {\n toast.error(`Failed to generate: ${error.message}`)\n console.error(\n 'Error generating or setting your upload, please set it manually if its saved in your media files.',\n error\n )\n })\n }, [getData, localFromContext?.code, instructionIdRef, setValue, documentId, collectionSlug])\n\n const generate = useCallback(\n async (options?: ActionCallbackParams) => {\n if (type === 'richText') {\n return streamObject(options ?? { action: 'Compose' })\n }\n\n if (['text', 'textarea'].includes(type ?? '') && type) {\n return streamText(options ?? { action: 'Compose' })\n }\n\n if (type === 'upload') {\n return generateUpload()\n }\n },\n [generateUpload, streamObject, streamText, type],\n )\n\n const stop = useCallback(() => {\n console.log('Stopping...')\n objectStop()\n completionStop()\n }, [objectStop, completionStop])\n\n return {\n generate,\n isLoading: loadingCompletion || loadingObject,\n stop,\n }\n}\n"],"names":["useCompletion","experimental_useObject","useObject","useEditorConfigContext","toast","useConfig","useDocumentInfo","useField","useForm","useLocale","jsonSchema","useCallback","useEffect","useMemo","useRef","PLUGIN_API_ENDPOINT_GENERATE","PLUGIN_API_ENDPOINT_GENERATE_UPLOAD","PLUGIN_INSTRUCTIONS_TABLE","PLUGIN_NAME","useFieldProps","editorSchemaValidator","setSafeLexicalState","useHistory","useGenerate","instructionId","instructionIdRef","current","type","path","pathFromContext","editorConfigContext","editor","config","routes","api","serverURL","setValue","set","setHistory","getData","id","documentId","collectionSlug","localFromContext","collections","collection","find","slug","custom","editorConfig","admin","schema","editorSchema","memoizedValidator","memoizedSchema","validate","value","isValid","success","error","Error","isLoading","loadingObject","object","stop","objectStop","submit","onError","message","console","onFinish","result","log","requestAnimationFrame","complete","completion","loadingCompletion","completionStop","prompt","streamProtocol","streamObject","action","params","doc","currentInstructionId","options","actionParams","allowedEditorNodes","Array","from","_nodes","keys","locale","code","streamText","body","generateUpload","fetch","JSON","stringify","credentials","headers","method","then","uploadResponse","ok","json","errors","errStr","map","join","catch","generate","includes"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/ui/Compose/hooks/useGenerate.ts"],"sourcesContent":["import { experimental_useObject as useObject } from '@ai-sdk/react'\nimport { useEditorConfigContext } from '@payloadcms/richtext-lexical/client'\nimport { toast, useConfig, useDocumentInfo, useField, useForm, useLocale } from '@payloadcms/ui'\nimport { jsonSchema } from 'ai'\nimport { useCallback, useEffect, useMemo, useRef } from 'react'\n\nimport type { ActionMenuItems, GenerateTextarea } from '../../../types.js'\n\nimport {\n PLUGIN_API_ENDPOINT_GENERATE,\n PLUGIN_API_ENDPOINT_GENERATE_UPLOAD,\n PLUGIN_INSTRUCTIONS_TABLE,\n PLUGIN_NAME,\n} from '../../../defaults.js'\nimport { useFieldProps } from '../../../providers/FieldProvider/useFieldProps.js'\nimport { editorSchemaValidator } from '../../../utilities/editorSchemaValidator.js'\nimport { fieldToJsonSchema } from '../../../utilities/fieldToJsonSchema.js'\nimport { setSafeLexicalState } from '../../../utilities/setSafeLexicalState.js'\nimport { useHistory } from './useHistory.js'\n\ntype ActionCallbackParams = { action: ActionMenuItems; params?: unknown }\n\nexport const useGenerate = ({ instructionId }: { instructionId: string }) => {\n // Create a ref to hold the current instructionId\n const instructionIdRef = useRef(instructionId)\n\n // Update the ref whenever instructionId changes\n useEffect(() => {\n instructionIdRef.current = instructionId\n }, [instructionId])\n\n const { field, path: pathFromContext } = useFieldProps()\n const editorConfigContext = useEditorConfigContext()\n\n const { editor } = editorConfigContext\n\n const { config } = useConfig()\n const {\n routes: { api },\n serverURL,\n } = config\n\n const { setValue } = useField<any>({\n path: pathFromContext ?? '',\n })\n\n const { set: setHistory } = useHistory()\n\n const { getData } = useForm()\n const { id: documentId, collectionSlug } = useDocumentInfo()\n\n const localFromContext = useLocale()\n const {\n config: { collections },\n } = useConfig()\n\n const collection = collections.find((collection) => collection.slug === PLUGIN_INSTRUCTIONS_TABLE)\n const { custom: { [PLUGIN_NAME]: { editorConfig = {} } = {} } = {} } = collection?.admin ?? {}\n const { schema: editorSchema = {} } = editorConfig\n\n const memoizedValidator = useMemo(() => {\n return editorSchemaValidator(editorSchema)\n }, [editorSchema])\n\n const memoizedSchema = useMemo(\n () =>\n jsonSchema(editorSchema, {\n validate: (value) => {\n const isValid = memoizedValidator(value)\n\n if (isValid) {\n return {\n success: true,\n value,\n }\n } else {\n return {\n error: new Error('Invalid schema'),\n success: false,\n }\n }\n },\n }),\n [memoizedValidator],\n )\n\n // Active JSON schema for useObject based on field type\n const activeSchema = useMemo(() => {\n const f = field as any\n const fieldType = f?.type as string | undefined\n if (fieldType === 'richText') {\n return memoizedSchema\n }\n if (f && f.name && fieldType) {\n const schemaJson = fieldToJsonSchema(f)\n if (schemaJson && Object.keys(schemaJson).length > 0) {\n return jsonSchema(schemaJson)\n }\n }\n return undefined\n }, [field, memoizedSchema])\n\n const {\n isLoading: loadingObject,\n object,\n stop: objectStop,\n submit,\n } = useObject({\n api: `/api${PLUGIN_API_ENDPOINT_GENERATE}`,\n onError: (error: any) => {\n toast.error(`Failed to generate: ${error.message}`)\n console.error('Error generating object:', error)\n },\n onFinish: (result) => {\n if (result.object && field) {\n if (field.type === 'richText') {\n setHistory(result.object)\n setValue(result.object)\n } else if ('name' in field) {\n setHistory(result.object[field.name])\n setValue(result.object[field.name])\n }\n } else {\n console.log('onFinish: result, field ', result, field)\n }\n },\n schema: activeSchema as any,\n })\n\n useEffect(() => {\n if (!object) {\n return\n }\n\n requestAnimationFrame(() => {\n if (field?.type === 'richText') {\n setSafeLexicalState(object, editor)\n } else if (field && 'name' in field && object[field.name]) {\n setValue(object[field.name])\n }\n })\n }, [object, editor, field])\n\n const streamObject = useCallback(\n ({ action = 'Compose', params }: ActionCallbackParams) => {\n const doc = getData()\n\n const currentInstructionId = instructionIdRef.current\n\n const options = {\n action,\n actionParams: params,\n instructionId: currentInstructionId,\n }\n\n submit({\n allowedEditorNodes: Array.from(editor?._nodes?.keys() || []),\n doc: {\n ...doc,\n id: documentId,\n },\n locale: localFromContext?.code,\n options,\n })\n },\n [localFromContext?.code, instructionIdRef, documentId],\n )\n\n const generateUpload = useCallback(async () => {\n const doc = getData()\n const currentInstructionId = instructionIdRef.current\n\n return fetch(`${serverURL}${api}${PLUGIN_API_ENDPOINT_GENERATE_UPLOAD}`, {\n body: JSON.stringify({\n collectionSlug: collectionSlug ?? '',\n doc,\n documentId,\n locale: localFromContext?.code,\n options: {\n instructionId: currentInstructionId,\n },\n } satisfies Parameters<GenerateTextarea>[0]),\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n .then(async (uploadResponse) => {\n if (uploadResponse.ok) {\n const { result } = await uploadResponse.json()\n if (!result) {\n throw new Error('generateUpload: Something went wrong')\n }\n\n setValue(result?.id)\n setHistory(result?.id)\n console.log('Image updated...', result)\n } else {\n const { errors = [] } = await uploadResponse.json()\n const errStr = errors.map((error: any) => error.message).join(', ')\n throw new Error(errStr)\n }\n return uploadResponse\n })\n .catch((error) => {\n toast.error(`Failed to generate: ${error.message}`)\n console.error(\n 'Error generating or setting your upload, please set it manually if its saved in your media files.',\n error,\n )\n })\n }, [getData, localFromContext?.code, instructionIdRef, setValue, documentId, collectionSlug])\n\n const generate = useCallback(\n async (options?: ActionCallbackParams) => {\n if ((field as any)?.type === 'upload') {\n return generateUpload()\n }\n // All supported types use structured object generation when schema is provided server-side\n return streamObject(options ?? { action: 'Compose' })\n },\n [generateUpload, streamObject, field],\n )\n\n const stop = useCallback(() => {\n console.log('Stopping...')\n objectStop()\n }, [objectStop])\n\n return {\n generate,\n isLoading: loadingObject,\n stop,\n }\n}\n"],"names":["experimental_useObject","useObject","useEditorConfigContext","toast","useConfig","useDocumentInfo","useField","useForm","useLocale","jsonSchema","useCallback","useEffect","useMemo","useRef","PLUGIN_API_ENDPOINT_GENERATE","PLUGIN_API_ENDPOINT_GENERATE_UPLOAD","PLUGIN_INSTRUCTIONS_TABLE","PLUGIN_NAME","useFieldProps","editorSchemaValidator","fieldToJsonSchema","setSafeLexicalState","useHistory","useGenerate","instructionId","instructionIdRef","current","field","path","pathFromContext","editorConfigContext","editor","config","routes","api","serverURL","setValue","set","setHistory","getData","id","documentId","collectionSlug","localFromContext","collections","collection","find","slug","custom","editorConfig","admin","schema","editorSchema","memoizedValidator","memoizedSchema","validate","value","isValid","success","error","Error","activeSchema","f","fieldType","type","name","schemaJson","Object","keys","length","undefined","isLoading","loadingObject","object","stop","objectStop","submit","onError","message","console","onFinish","result","log","requestAnimationFrame","streamObject","action","params","doc","currentInstructionId","options","actionParams","allowedEditorNodes","Array","from","_nodes","locale","code","generateUpload","fetch","body","JSON","stringify","credentials","headers","method","then","uploadResponse","ok","json","errors","errStr","map","join","catch","generate"],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styles from './icons.module.css';
|
|
3
|
+
import LottieAnimation from './LottieAnimation.js';
|
|
4
|
+
export const PluginIcon = ({ color = 'white', isLoading, }) => {
|
|
5
|
+
return (<span className={styles.actions_icon}>
|
|
6
|
+
<LottieAnimation isLoading={isLoading}/>
|
|
7
|
+
</span>);
|
|
8
|
+
};
|
|
9
|
+
export const TuneIcon = ({ color = 'white', size = 24 }) => {
|
|
10
|
+
return (<span className={styles.icon}>
|
|
11
|
+
<svg height={size} viewBox="0 -960 960 960" width={size} xmlns="http://www.w3.org/2000/svg">
|
|
12
|
+
<path d="M450-130v-220h60v80h320v60H510v80h-60Zm-320-80v-60h220v60H130Zm160-160v-80H130v-60h160v-80h60v220h-60Zm160-80v-60h380v60H450Zm160-160v-220h60v80h160v60H670v80h-60Zm-480-80v-60h380v60H130Z"/>
|
|
13
|
+
</svg>
|
|
14
|
+
</span>);
|
|
15
|
+
};
|
|
16
|
+
export const LocalLibraryIcon = ({ color = 'white', size = 24 }) => {
|
|
17
|
+
return (<span className={styles.icon}>
|
|
18
|
+
<svg height={size} viewBox="0 -960 960 960" width={size} xmlns="http://www.w3.org/2000/svg">
|
|
19
|
+
<path d="M480-115.38q-67.38-54.93-148.85-86.7Q249.69-233.85 160-240v-373.85q91.77 5.39 174.38 43.81Q417-531.62 480-474.92q63-56.7 145.62-95.12 82.61-38.42 174.38-43.81V-240q-89.92 6.15-171.27 37.92-81.35 31.77-148.73 86.7Zm0-50.16q63-46.23 134-74.56 71-28.33 146-37.44v-291.38q-78.38 13-149.65 50.57-71.27 37.58-130.35 96.66-59.08-59.08-130.35-96.66-71.27-37.57-149.65-50.57v291.38q75 9.11 146 37.44t134 74.56Zm0-451.38q-53.31 0-91.27-37.96-37.96-37.97-37.96-91.27 0-53.31 37.96-91.27 37.96-37.96 91.27-37.96 53.31 0 91.27 37.96 37.96 37.96 37.96 91.27 0 53.3-37.96 91.27-37.96 37.96-91.27 37.96Zm.03-40q36.82 0 63.01-26.22 26.19-26.22 26.19-63.04t-26.22-63.01q-26.22-26.19-63.04-26.19t-63.01 26.21q-26.19 26.22-26.19 63.04t26.22 63.01q26.22 26.2 63.04 26.2Zm-.03-89.23Zm0 324.46Z"/>
|
|
20
|
+
</svg>
|
|
21
|
+
</span>);
|
|
22
|
+
};
|
|
23
|
+
export const SpellCheckIcon = ({ color = 'white', size = 24 }) => {
|
|
24
|
+
return (<span className={styles.icon}>
|
|
25
|
+
<svg height={size} viewBox="0 -960 960 960" width={size} xmlns="http://www.w3.org/2000/svg">
|
|
26
|
+
<path d="M564-93.85 407.85-250 450-292.15l114 114 226.77-226.77 42.15 42.15L564-93.85ZM135.39-320l191.69-520h69.38l190.92 520h-68.92l-49.07-142H250.92l-49.84 142h-65.69ZM272-518h178.31L362-765.54h-3.23L272-518Z"/>
|
|
27
|
+
</svg>
|
|
28
|
+
</span>);
|
|
29
|
+
};
|
|
30
|
+
export const TranslateIcon = ({ color = 'white', size = 24 }) => {
|
|
31
|
+
return (<span className={styles.icon}>
|
|
32
|
+
<svg height={size} viewBox="0 -960 960 960" width={size} xmlns="http://www.w3.org/2000/svg">
|
|
33
|
+
<path d="m476-100 178.15-460h62.46l178.16 460h-63.62l-45.3-122H584.92l-45.31 122H476ZM160.38-217.69l-42.15-42.16 198.92-199.3q-34.61-35-65.8-83.08Q220.15-590.31 200-640h63.61q17.31 36.31 42.12 72.62 24.81 36.3 53.58 66.07 42.61-43 80.61-104.42T493.62-720H67.69v-60H330v-64.61h60V-780h262.31v60h-97.93q-19.46 67.38-62.03 140.88-42.58 73.5-90.89 121.2l98.69 101.07-22.69 61.62-118.15-121.16-198.93 198.7Zm443.77-57.39h162.46l-81.23-218.23-81.23 218.23Z"/>
|
|
34
|
+
</svg>
|
|
35
|
+
</span>);
|
|
36
|
+
};
|
|
37
|
+
export const DocsAddOnIcon = ({ color = 'white', size = 24 }) => {
|
|
38
|
+
return (<span className={styles.icon}>
|
|
39
|
+
<svg height={size} viewBox="0 -960 960 960" width={size} xmlns="http://www.w3.org/2000/svg">
|
|
40
|
+
<path d="M650-131v-120H530v-60h120v-120h60v120h120v60H710v120h-60ZM170-250v-60h281.85q-1.85 15.8-1.35 30.09t2.35 29.91H170Zm0-160v-60h379.08q-17.23 12.15-31.5 27.15-14.27 15-25.96 32.85H170Zm0-160v-60h580v60H170Zm0-160v-60h580v60H170Z"/>
|
|
41
|
+
</svg>
|
|
42
|
+
</span>);
|
|
43
|
+
};
|
|
44
|
+
export const SummarizeIcon = ({ color = 'white', size = 24 }) => {
|
|
45
|
+
return (<span className={styles.icon}>
|
|
46
|
+
<svg height={size} viewBox="0 -960 960 960" width={size} xmlns="http://www.w3.org/2000/svg">
|
|
47
|
+
<path d="M320-603.85q15.08 0 25.62-10.53 10.53-10.54 10.53-25.62 0-15.08-10.53-25.62-10.54-10.53-25.62-10.53-15.08 0-25.62 10.53-10.53 10.54-10.53 25.62 0 15.08 10.53 25.62 10.54 10.53 25.62 10.53Zm0 160q15.08 0 25.62-10.53 10.53-10.54 10.53-25.62 0-15.08-10.53-25.62-10.54-10.53-25.62-10.53-15.08 0-25.62 10.53-10.53 10.54-10.53 25.62 0 15.08 10.53 25.62 10.54 10.53 25.62 10.53Zm0 160q15.08 0 25.62-10.53 10.53-10.54 10.53-25.62 0-15.08-10.53-25.62-10.54-10.53-25.62-10.53-15.08 0-25.62 10.53-10.53 10.54-10.53 25.62 0 15.08 10.53 25.62 10.54 10.53 25.62 10.53ZM212.31-140Q182-140 161-161q-21-21-21-51.31v-535.38Q140-778 161-799q21-21 51.31-21h419.23L820-631.54v419.23Q820-182 799-161q-21 21-51.31 21H212.31Zm0-60h535.38q5.39 0 8.85-3.46t3.46-8.85V-600H600v-160H212.31q-5.39 0-8.85 3.46t-3.46 8.85v535.38q0 5.39 3.46 8.85t8.85 3.46ZM200-760v160-160V-200v-560Z"/>
|
|
48
|
+
</svg>
|
|
49
|
+
</span>);
|
|
50
|
+
};
|
|
51
|
+
export const SegmentIcon = ({ color = 'white', size = 24 }) => {
|
|
52
|
+
return (<span className={styles.icon}>
|
|
53
|
+
<svg height={size} viewBox="0 -960 960 960" width={size} xmlns="http://www.w3.org/2000/svg">
|
|
54
|
+
<path d="M380-254.62v-59.99h440v59.99H380ZM380-450v-60h440v60H380ZM140-645.39v-59.99h680v59.99H140Z"/>
|
|
55
|
+
</svg>
|
|
56
|
+
</span>);
|
|
57
|
+
};
|
|
58
|
+
export const StylusNoteIcon = ({ color = 'white', size = 24 }) => {
|
|
59
|
+
return (<span className={styles.icon}>
|
|
60
|
+
<svg height={size} viewBox="0 -960 960 960" width={size} xmlns="http://www.w3.org/2000/svg">
|
|
61
|
+
<path d="m487.46-283.15 332.31-332.31q2.69-2.69 2.69-6.54t-2.69-6.54l-38.92-38.92q-2.7-2.69-6.54-2.69-3.85 0-6.54 2.69L435.46-335.15l52 52Zm-251 72.38q-89.23-5-134-39.69-44.77-34.69-44.77-98.16 0-60.76 51-98.57 51-37.81 141.77-45.81 43.62-3.77 65.43-15.77 21.8-12 21.8-33.23 0-29.46-29.5-44.96t-96.73-22.27l5.46-59.62q92.23 8.77 136.5 39.77 44.27 31 44.27 87.08 0 47.61-36.57 75.5-36.58 27.88-106.2 33.5-68.61 5.77-102.92 26.77t-34.31 57.61q0 37.31 28.58 55.51 28.58 18.19 92.65 22.34l-2.46 60Zm260.38 3.15L359.92-344.54l373.54-373.15q17.69-17.69 41.35-17.5 23.65.19 41.34 17.5L870-663.85q17.69 17.7 17.69 41.54 0 23.85-17.69 41.54L496.84-207.62ZM363.23-180q-13.54 3.23-23.84-7.08-10.31-10.31-7.08-23.84l27.61-133.62 136.92 136.92L363.23-180Z"/>
|
|
62
|
+
</svg>
|
|
63
|
+
</span>);
|
|
64
|
+
};
|
|
65
|
+
export const EditNoteIcon = ({ color = 'white', size = 24 }) => {
|
|
66
|
+
return (<span className={styles.icon}>
|
|
67
|
+
<svg height={size} viewBox="0 -960 960 960" width={size} xmlns="http://www.w3.org/2000/svg">
|
|
68
|
+
<path d="M180-400v-60h280v60H180Zm0-160v-60h440v60H180Zm0-160v-60h440v60H180Zm344.62 540v-105.69l217.15-216.16q7.46-7.46 16.11-10.5 8.65-3.03 17.3-3.03 9.43 0 18.25 3.53 8.82 3.54 16.03 10.62l37 37.38q6.46 7.47 10 16.16Q860-439 860-430.31t-3.23 17.69q-3.23 9-10.31 16.46L630.31-180H524.62Zm287.69-250.31-37-37.38 37 37.38Zm-240 202.62h38l129.84-130.47-18.38-19-18.62-18.76-130.84 130.23v38Zm149.46-149.47-18.62-18.76 37 37.76-18.38-19Z"/>
|
|
69
|
+
</svg>
|
|
70
|
+
</span>);
|
|
71
|
+
};
|
|
72
|
+
export const ArrowIcon = ({ color = 'white', size = 24 }) => {
|
|
73
|
+
return (<span className={styles.icon}>
|
|
74
|
+
<svg height={size} viewBox="0 -960 960 960" width={size} xmlns="http://www.w3.org/2000/svg">
|
|
75
|
+
<path d="m531.69-480-184-184L376-692.31 588.31-480 376-267.69 347.69-296l184-184Z"/>
|
|
76
|
+
</svg>
|
|
77
|
+
</span>);
|
|
78
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import styles from './icons.module.css';
|
|
4
|
+
const LottieAnimation = ({ isLoading = false }) => {
|
|
5
|
+
const svgRef = useRef(null);
|
|
6
|
+
const [animations, setAnimations] = useState([]);
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
const svg = svgRef.current;
|
|
9
|
+
if (!svg)
|
|
10
|
+
return;
|
|
11
|
+
const animateTransform = (element, keyframes) => {
|
|
12
|
+
const animation = element.animate(keyframes, {
|
|
13
|
+
direction: 'alternate',
|
|
14
|
+
duration: 1000,
|
|
15
|
+
easing: 'ease-in-out',
|
|
16
|
+
iterations: Infinity,
|
|
17
|
+
});
|
|
18
|
+
return animation;
|
|
19
|
+
};
|
|
20
|
+
// Animate Group 2 (Rectangle)
|
|
21
|
+
const rectangle = svg.querySelector('#group2');
|
|
22
|
+
const rectangleAnimation = animateTransform(rectangle, [
|
|
23
|
+
{ transform: 'translate(0, 0) scale(1)' },
|
|
24
|
+
{ transform: 'translate(0, 0) scale(2.54)' },
|
|
25
|
+
{ transform: 'translate(0, 0) scale(1)' },
|
|
26
|
+
]);
|
|
27
|
+
// Animate Group 3 (Triangle)
|
|
28
|
+
const triangle = svg.querySelector('#group3');
|
|
29
|
+
const triangleAnimation = animateTransform(triangle, [
|
|
30
|
+
{ transform: 'translate(-69.5px, 77.5px) scale(1)' },
|
|
31
|
+
{ transform: 'translate(-70px, 73px) scale(0.36)' },
|
|
32
|
+
{ transform: 'translate(-69.5px, 77.5px) scale(1)' },
|
|
33
|
+
]);
|
|
34
|
+
setAnimations([rectangleAnimation, triangleAnimation]);
|
|
35
|
+
// Clean up animations on unmount
|
|
36
|
+
return () => {
|
|
37
|
+
rectangleAnimation.cancel();
|
|
38
|
+
triangleAnimation.cancel();
|
|
39
|
+
};
|
|
40
|
+
}, []);
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
if (isLoading) {
|
|
43
|
+
animations.forEach((animation) => animation.play());
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
animations.forEach((animation) => animation.pause());
|
|
47
|
+
}
|
|
48
|
+
}, [isLoading, animations]);
|
|
49
|
+
return (<span style={{
|
|
50
|
+
left: '3px',
|
|
51
|
+
position: 'relative',
|
|
52
|
+
top: '-6px',
|
|
53
|
+
}}>
|
|
54
|
+
<svg height="41" ref={svgRef} viewBox="-250 -250 500 500" width="41">
|
|
55
|
+
<g id="group2">
|
|
56
|
+
<rect className={styles.color_fill} height="41" width="41" x="-20.5" y="-20.5"/>
|
|
57
|
+
</g>
|
|
58
|
+
<g id="group3">
|
|
59
|
+
<path className={styles.color_fill} d="M48.5 57.5L48.5 -57.5L-49.5 -1.093L48.5 57.5Z"/>
|
|
60
|
+
</g>
|
|
61
|
+
</svg>
|
|
62
|
+
</span>);
|
|
63
|
+
};
|
|
64
|
+
export default LottieAnimation;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare function extractPromptAttachments(prompt: string):
|
|
1
|
+
import type { ModelMessage } from 'ai';
|
|
2
|
+
export declare function extractPromptAttachments(prompt: string): ModelMessage[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/extractPromptAttachments.ts"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/extractPromptAttachments.ts"],"sourcesContent":["import type { ModelMessage } from 'ai'\n\n// Converts prompt into messages, extracting images in the process\nexport function extractPromptAttachments(prompt: string): ModelMessage[] {\n // Regex to match absolute HTTPS URLs with image extensions\n const imageUrlRegex = /https:\\/\\/\\S+\\.(?:png|jpe?g|webp)/gi\n \n const messages: ModelMessage[] = []\n const imageUrls: string[] = []\n \n // Find all image URLs in the prompt\n let match\n while ((match = imageUrlRegex.exec(prompt)) !== null) {\n imageUrls.push(match[0])\n }\n \n // Create image messages first\n for (const imageUrl of imageUrls) {\n messages.push({\n content: [\n {\n type: 'image',\n image: new URL(imageUrl)\n }\n ],\n role: 'user'\n })\n }\n \n // Add the text prompt as a regular user message if there's any text left\n messages.push({\n content: prompt,\n role: 'user'\n })\n\n return messages\n}"],"names":["extractPromptAttachments","prompt","imageUrlRegex","messages","imageUrls","match","exec","push","imageUrl","content","type","image","URL","role"],"mappings":"AAEA,kEAAkE;AAClE,OAAO,SAASA,yBAAyBC,MAAc;IACrD,2DAA2D;IAC3D,MAAMC,gBAAgB;IAEtB,MAAMC,WAA2B,EAAE;IACnC,MAAMC,YAAsB,EAAE;IAE9B,oCAAoC;IACpC,IAAIC;IACJ,MAAO,AAACA,CAAAA,QAAQH,cAAcI,IAAI,CAACL,OAAM,MAAO,KAAM;QACpDG,UAAUG,IAAI,CAACF,KAAK,CAAC,EAAE;IACzB;IAEA,8BAA8B;IAC9B,KAAK,MAAMG,YAAYJ,UAAW;QAChCD,SAASI,IAAI,CAAC;YACZE,SAAS;gBACP;oBACEC,MAAM;oBACNC,OAAO,IAAIC,IAAIJ;gBACjB;aACD;YACDK,MAAM;QACR;IACF;IAEA,yEAAyE;IACzEV,SAASI,IAAI,CAAC;QACZE,SAASR;QACTY,MAAM;IACR;IAEA,OAAOV;AACT"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fieldToJsonSchema
|
|
3
|
+
* Convert a Payload Field (server or client) into a minimal JSON Schema object,
|
|
4
|
+
* wrapped as { type: 'object', properties: { [name]: valueSchema }, required: [...] }
|
|
5
|
+
*
|
|
6
|
+
* Supported types:
|
|
7
|
+
* - text, textarea, select, number, date, code, email, json
|
|
8
|
+
* Arrays are emitted only when field.hasMany is true and the field type supports hasMany
|
|
9
|
+
* (text, textarea, select; for others only if your config truly sets hasMany).
|
|
10
|
+
*/
|
|
11
|
+
export type JsonSchema = Record<string, any>;
|
|
12
|
+
type BaseField = {
|
|
13
|
+
admin?: {
|
|
14
|
+
description?: unknown;
|
|
15
|
+
language?: unknown;
|
|
16
|
+
};
|
|
17
|
+
hasMany?: boolean;
|
|
18
|
+
jsonSchema?: unknown;
|
|
19
|
+
max?: number;
|
|
20
|
+
maxRows?: number;
|
|
21
|
+
min?: number;
|
|
22
|
+
minRows?: number;
|
|
23
|
+
name?: string;
|
|
24
|
+
options?: Array<{
|
|
25
|
+
label?: unknown;
|
|
26
|
+
value: number | string;
|
|
27
|
+
} | number | string>;
|
|
28
|
+
required?: boolean;
|
|
29
|
+
schema?: unknown;
|
|
30
|
+
type?: string;
|
|
31
|
+
typescriptSchema?: unknown;
|
|
32
|
+
};
|
|
33
|
+
export declare function fieldToJsonSchema(fieldInput: BaseField, opts?: {
|
|
34
|
+
nameOverride?: string;
|
|
35
|
+
wrapObject?: boolean;
|
|
36
|
+
}): JsonSchema;
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fieldToJsonSchema
|
|
3
|
+
* Convert a Payload Field (server or client) into a minimal JSON Schema object,
|
|
4
|
+
* wrapped as { type: 'object', properties: { [name]: valueSchema }, required: [...] }
|
|
5
|
+
*
|
|
6
|
+
* Supported types:
|
|
7
|
+
* - text, textarea, select, number, date, code, email, json
|
|
8
|
+
* Arrays are emitted only when field.hasMany is true and the field type supports hasMany
|
|
9
|
+
* (text, textarea, select; for others only if your config truly sets hasMany).
|
|
10
|
+
*/ function isString(s) {
|
|
11
|
+
return typeof s === 'string';
|
|
12
|
+
}
|
|
13
|
+
function isPlainObject(o) {
|
|
14
|
+
return !!o && typeof o === 'object' && !Array.isArray(o);
|
|
15
|
+
}
|
|
16
|
+
function getDescription(field) {
|
|
17
|
+
const d = field?.admin?.description;
|
|
18
|
+
return typeof d === 'string' ? d : undefined;
|
|
19
|
+
}
|
|
20
|
+
function stringWithDescription(field) {
|
|
21
|
+
const out = {
|
|
22
|
+
type: 'string'
|
|
23
|
+
};
|
|
24
|
+
const description = getDescription(field);
|
|
25
|
+
if (description) {
|
|
26
|
+
out.description = description;
|
|
27
|
+
}
|
|
28
|
+
return out;
|
|
29
|
+
}
|
|
30
|
+
function numberWithBounds(field) {
|
|
31
|
+
const out = {
|
|
32
|
+
type: 'number'
|
|
33
|
+
};
|
|
34
|
+
if (typeof field.min === 'number') {
|
|
35
|
+
out.minimum = field.min;
|
|
36
|
+
}
|
|
37
|
+
if (typeof field.max === 'number') {
|
|
38
|
+
out.maximum = field.max;
|
|
39
|
+
}
|
|
40
|
+
const description = getDescription(field);
|
|
41
|
+
if (description) {
|
|
42
|
+
out.description = description;
|
|
43
|
+
}
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
function dateSchema(field) {
|
|
47
|
+
const out = {
|
|
48
|
+
type: 'string',
|
|
49
|
+
format: 'date-time'
|
|
50
|
+
};
|
|
51
|
+
const description = getDescription(field);
|
|
52
|
+
if (description) {
|
|
53
|
+
out.description = description;
|
|
54
|
+
}
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
57
|
+
function codeSchema(field) {
|
|
58
|
+
const out = {
|
|
59
|
+
type: 'string'
|
|
60
|
+
};
|
|
61
|
+
let description = getDescription(field);
|
|
62
|
+
const lang = field?.admin?.language;
|
|
63
|
+
if (typeof lang === 'string' && lang.trim()) {
|
|
64
|
+
description = description ? `${description} (language: ${lang})` : `language: ${lang}`;
|
|
65
|
+
}
|
|
66
|
+
if (description) {
|
|
67
|
+
out.description = description;
|
|
68
|
+
}
|
|
69
|
+
return out;
|
|
70
|
+
}
|
|
71
|
+
function emailSchema(field) {
|
|
72
|
+
const out = {
|
|
73
|
+
type: 'string',
|
|
74
|
+
format: 'email'
|
|
75
|
+
};
|
|
76
|
+
const description = getDescription(field);
|
|
77
|
+
if (description) {
|
|
78
|
+
out.description = description;
|
|
79
|
+
}
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
82
|
+
function jsonValueSchema(field) {
|
|
83
|
+
// Prefer a provided JSON Schema object
|
|
84
|
+
if (isPlainObject(field.jsonSchema)) {
|
|
85
|
+
return field.jsonSchema;
|
|
86
|
+
}
|
|
87
|
+
if (isPlainObject(field.schema)) {
|
|
88
|
+
return field.schema;
|
|
89
|
+
}
|
|
90
|
+
// typescriptSchema cannot be executed here; default to object
|
|
91
|
+
return {
|
|
92
|
+
type: 'object'
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function normalizeSelectOptions(field) {
|
|
96
|
+
const raw = field.options || [];
|
|
97
|
+
const values = [];
|
|
98
|
+
for (const opt of raw){
|
|
99
|
+
if (typeof opt === 'string' || typeof opt === 'number') {
|
|
100
|
+
values.push(opt);
|
|
101
|
+
} else if (isPlainObject(opt) && 'value' in opt) {
|
|
102
|
+
const v = opt.value;
|
|
103
|
+
if (typeof v === 'string' || typeof v === 'number') {
|
|
104
|
+
values.push(v);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Infer primitive type
|
|
109
|
+
const allNumbers = values.length > 0 && values.every((v)=>typeof v === 'number');
|
|
110
|
+
const valueType = allNumbers ? 'number' : 'string';
|
|
111
|
+
return {
|
|
112
|
+
values,
|
|
113
|
+
valueType
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function supportsHasMany(fieldType) {
|
|
117
|
+
// Out of the box: text, textarea, select support hasMany
|
|
118
|
+
// Others can be arrays only if your config truly sets hasMany; we return boolean based on type here.
|
|
119
|
+
return fieldType === 'text' || fieldType === 'textarea' || fieldType === 'select';
|
|
120
|
+
}
|
|
121
|
+
export function fieldToJsonSchema(fieldInput, opts) {
|
|
122
|
+
const field = fieldInput || {};
|
|
123
|
+
const name = isString(opts?.nameOverride) && opts?.nameOverride.length ? opts.nameOverride : field.name || 'value';
|
|
124
|
+
const type = field.type;
|
|
125
|
+
let valueSchema = null;
|
|
126
|
+
switch(type){
|
|
127
|
+
case 'code':
|
|
128
|
+
{
|
|
129
|
+
const base = codeSchema(field);
|
|
130
|
+
if (field.hasMany) {
|
|
131
|
+
valueSchema = {
|
|
132
|
+
type: 'array',
|
|
133
|
+
items: base
|
|
134
|
+
};
|
|
135
|
+
} else {
|
|
136
|
+
valueSchema = base;
|
|
137
|
+
}
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
case 'date':
|
|
141
|
+
{
|
|
142
|
+
const base = dateSchema(field);
|
|
143
|
+
if (field.hasMany) {
|
|
144
|
+
valueSchema = {
|
|
145
|
+
type: 'array',
|
|
146
|
+
items: base
|
|
147
|
+
};
|
|
148
|
+
} else {
|
|
149
|
+
valueSchema = base;
|
|
150
|
+
}
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
case 'email':
|
|
154
|
+
{
|
|
155
|
+
const base = emailSchema(field);
|
|
156
|
+
if (field.hasMany) {
|
|
157
|
+
valueSchema = {
|
|
158
|
+
type: 'array',
|
|
159
|
+
items: base
|
|
160
|
+
};
|
|
161
|
+
} else {
|
|
162
|
+
valueSchema = base;
|
|
163
|
+
}
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
case 'json':
|
|
167
|
+
{
|
|
168
|
+
const base = jsonValueSchema(field);
|
|
169
|
+
if (field.hasMany) {
|
|
170
|
+
valueSchema = {
|
|
171
|
+
type: 'array',
|
|
172
|
+
items: base
|
|
173
|
+
};
|
|
174
|
+
} else {
|
|
175
|
+
valueSchema = base;
|
|
176
|
+
}
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
case 'number':
|
|
180
|
+
{
|
|
181
|
+
const base = numberWithBounds(field);
|
|
182
|
+
if (field.hasMany) {
|
|
183
|
+
// Respect hasMany only if truly configured; Payload rarely uses hasMany for number, but allow if present.
|
|
184
|
+
valueSchema = {
|
|
185
|
+
type: 'array',
|
|
186
|
+
items: base
|
|
187
|
+
};
|
|
188
|
+
} else {
|
|
189
|
+
valueSchema = base;
|
|
190
|
+
}
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
case 'select':
|
|
194
|
+
{
|
|
195
|
+
const { values, valueType } = normalizeSelectOptions(field);
|
|
196
|
+
const baseSingle = {
|
|
197
|
+
type: valueType,
|
|
198
|
+
enum: values
|
|
199
|
+
};
|
|
200
|
+
const description = getDescription(field);
|
|
201
|
+
if (description) {
|
|
202
|
+
baseSingle.description = description;
|
|
203
|
+
}
|
|
204
|
+
if (field.hasMany && supportsHasMany(type)) {
|
|
205
|
+
valueSchema = {
|
|
206
|
+
type: 'array',
|
|
207
|
+
items: {
|
|
208
|
+
type: valueType,
|
|
209
|
+
enum: values
|
|
210
|
+
},
|
|
211
|
+
...description ? {
|
|
212
|
+
description
|
|
213
|
+
} : {}
|
|
214
|
+
};
|
|
215
|
+
} else {
|
|
216
|
+
valueSchema = baseSingle;
|
|
217
|
+
}
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
case 'text':
|
|
221
|
+
case 'textarea':
|
|
222
|
+
{
|
|
223
|
+
const base = stringWithDescription(field);
|
|
224
|
+
if (field.hasMany && supportsHasMany(type)) {
|
|
225
|
+
const arr = {
|
|
226
|
+
type: 'array',
|
|
227
|
+
items: {
|
|
228
|
+
type: 'string'
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
if (typeof field.minRows === 'number') {
|
|
232
|
+
arr.minItems = field.minRows;
|
|
233
|
+
}
|
|
234
|
+
if (typeof field.maxRows === 'number') {
|
|
235
|
+
arr.maxItems = field.maxRows;
|
|
236
|
+
}
|
|
237
|
+
if (base.description) {
|
|
238
|
+
arr.description = base.description;
|
|
239
|
+
}
|
|
240
|
+
valueSchema = arr;
|
|
241
|
+
} else {
|
|
242
|
+
valueSchema = base;
|
|
243
|
+
}
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
default:
|
|
247
|
+
{
|
|
248
|
+
// Unsupported type: return null to allow caller to decide how to proceed (e.g., no schema)
|
|
249
|
+
valueSchema = null;
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
const wrap = opts?.wrapObject !== false;
|
|
254
|
+
if (!wrap) {
|
|
255
|
+
return valueSchema || {};
|
|
256
|
+
}
|
|
257
|
+
if (!valueSchema) {
|
|
258
|
+
// Return undefined-like schema if not supported; caller may choose to skip passing schema
|
|
259
|
+
return {};
|
|
260
|
+
}
|
|
261
|
+
const schema = {
|
|
262
|
+
type: 'object',
|
|
263
|
+
additionalProperties: false,
|
|
264
|
+
properties: {
|
|
265
|
+
[name]: valueSchema
|
|
266
|
+
},
|
|
267
|
+
required: [
|
|
268
|
+
name
|
|
269
|
+
]
|
|
270
|
+
};
|
|
271
|
+
return schema;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
//# sourceMappingURL=fieldToJsonSchema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/fieldToJsonSchema.ts"],"sourcesContent":["/**\n * fieldToJsonSchema\n * Convert a Payload Field (server or client) into a minimal JSON Schema object,\n * wrapped as { type: 'object', properties: { [name]: valueSchema }, required: [...] }\n *\n * Supported types:\n * - text, textarea, select, number, date, code, email, json\n * Arrays are emitted only when field.hasMany is true and the field type supports hasMany\n * (text, textarea, select; for others only if your config truly sets hasMany).\n */\n\nexport type JsonSchema = Record<string, any>;\n\n// Narrowed minimal typing to avoid anywhere possible without pulling the full payload types at runtime.\n// In a Payload project, you can import type { Field, ClientField } from 'payload' and use those instead.\ntype BaseField = {\n admin?: {\n description?: unknown;\n language?: unknown;\n };\n hasMany?: boolean;\n // json\n jsonSchema?: unknown;\n max?: number;\n maxRows?: number;\n // number\n min?: number;\n // text/textarea\n minRows?: number;\n name?: string;\n // select\n options?: Array<\n | {\n label?: unknown;\n value: number | string;\n }\n | number\n | string\n >;\n required?: boolean;\n schema?: unknown;\n type?: string;\n typescriptSchema?: unknown;\n};\n\nfunction isString(s: unknown): s is string {\n return typeof s === 'string';\n}\n\nfunction isPlainObject(o: unknown): o is Record<string, unknown> {\n return !!o && typeof o === 'object' && !Array.isArray(o);\n}\n\nfunction getDescription(field: BaseField): string | undefined {\n const d = field?.admin?.description;\n return typeof d === 'string' ? d : undefined;\n}\n\nfunction stringWithDescription(field: BaseField) {\n const out: Record<string, any> = { type: 'string' };\n const description = getDescription(field);\n if (description) {out.description = description;}\n return out;\n}\n\nfunction numberWithBounds(field: BaseField) {\n const out: Record<string, any> = { type: 'number' };\n if (typeof field.min === 'number') {out.minimum = field.min;}\n if (typeof field.max === 'number') {out.maximum = field.max;}\n const description = getDescription(field);\n if (description) {out.description = description;}\n return out;\n}\n\nfunction dateSchema(field: BaseField) {\n const out: Record<string, any> = { type: 'string', format: 'date-time' };\n const description = getDescription(field);\n if (description) {out.description = description;}\n return out;\n}\n\nfunction codeSchema(field: BaseField) {\n const out: Record<string, any> = { type: 'string' };\n let description = getDescription(field);\n const lang = field?.admin?.language;\n if (typeof lang === 'string' && lang.trim()) {\n description = description ? `${description} (language: ${lang})` : `language: ${lang}`;\n }\n if (description) {out.description = description;}\n return out;\n}\n\nfunction emailSchema(field: BaseField) {\n const out: Record<string, any> = { type: 'string', format: 'email' };\n const description = getDescription(field);\n if (description) {out.description = description;}\n return out;\n}\n\nfunction jsonValueSchema(field: BaseField) {\n // Prefer a provided JSON Schema object\n if (isPlainObject(field.jsonSchema)) {return field.jsonSchema as object;}\n if (isPlainObject(field.schema)) {return field.schema as object;}\n\n // typescriptSchema cannot be executed here; default to object\n return { type: 'object' };\n}\n\nfunction normalizeSelectOptions(field: BaseField): { values: Array<number | string>; valueType: 'number' | 'string' } {\n const raw = field.options || [];\n const values: Array<number | string> = [];\n\n for (const opt of raw) {\n if (typeof opt === 'string' || typeof opt === 'number') {\n values.push(opt);\n } else if (isPlainObject(opt) && ('value' in opt)) {\n const v = (opt as any).value;\n if (typeof v === 'string' || typeof v === 'number') {\n values.push(v);\n }\n }\n }\n\n // Infer primitive type\n const allNumbers = values.length > 0 && values.every((v) => typeof v === 'number');\n const valueType: 'number' | 'string' = allNumbers ? 'number' : 'string';\n return { values, valueType };\n}\n\nfunction supportsHasMany(fieldType: string | undefined): boolean {\n // Out of the box: text, textarea, select support hasMany\n // Others can be arrays only if your config truly sets hasMany; we return boolean based on type here.\n return fieldType === 'text' || fieldType === 'textarea' || fieldType === 'select';\n}\n\nexport function fieldToJsonSchema(\n fieldInput: BaseField,\n opts?: { nameOverride?: string; wrapObject?: boolean },\n): JsonSchema {\n const field: BaseField = fieldInput || {};\n const name = isString(opts?.nameOverride) && opts?.nameOverride.length ? opts.nameOverride : (field.name || 'value');\n const type = field.type;\n\n let valueSchema: null | Record<string, any> = null;\n\n switch (type) {\n case 'code': {\n const base = codeSchema(field);\n if (field.hasMany) {\n valueSchema = { type: 'array', items: base };\n } else {\n valueSchema = base;\n }\n break;\n }\n case 'date': {\n const base = dateSchema(field);\n if (field.hasMany) {\n valueSchema = { type: 'array', items: base };\n } else {\n valueSchema = base;\n }\n break;\n }\n\n case 'email': {\n const base = emailSchema(field);\n if (field.hasMany) {\n valueSchema = { type: 'array', items: base };\n } else {\n valueSchema = base;\n }\n break;\n }\n\n case 'json': {\n const base = jsonValueSchema(field);\n if (field.hasMany) {\n valueSchema = { type: 'array', items: base };\n } else {\n valueSchema = base as Record<string, any>;\n }\n break;\n }\n\n case 'number': {\n const base = numberWithBounds(field);\n if (field.hasMany) {\n // Respect hasMany only if truly configured; Payload rarely uses hasMany for number, but allow if present.\n valueSchema = { type: 'array', items: base };\n } else {\n valueSchema = base;\n }\n break;\n }\n\n case 'select': {\n const { values, valueType } = normalizeSelectOptions(field);\n const baseSingle: Record<string, any> = { type: valueType, enum: values };\n const description = getDescription(field);\n if (description) {baseSingle.description = description;}\n\n if (field.hasMany && supportsHasMany(type)) {\n valueSchema = {\n type: 'array',\n items: { type: valueType, enum: values },\n ...(description ? { description } : {}),\n };\n } else {\n valueSchema = baseSingle;\n }\n break;\n }\n\n case 'text':\n case 'textarea': {\n const base = stringWithDescription(field);\n if (field.hasMany && supportsHasMany(type)) {\n const arr: Record<string, any> = {\n type: 'array',\n items: { type: 'string' },\n };\n if (typeof field.minRows === 'number') {arr.minItems = field.minRows;}\n if (typeof field.maxRows === 'number') {arr.maxItems = field.maxRows;}\n if (base.description) {arr.description = base.description;}\n valueSchema = arr;\n } else {\n valueSchema = base;\n }\n break;\n }\n\n default: {\n // Unsupported type: return null to allow caller to decide how to proceed (e.g., no schema)\n valueSchema = null;\n break;\n }\n }\n\n const wrap = opts?.wrapObject !== false;\n\n if (!wrap) {\n return (valueSchema || {}) as JsonSchema;\n }\n\n if (!valueSchema) {\n // Return undefined-like schema if not supported; caller may choose to skip passing schema\n return {} as JsonSchema;\n }\n\n const schema: JsonSchema = {\n type: 'object',\n additionalProperties: false,\n properties: {\n [name]: valueSchema,\n },\n required: [name]\n };\n\n return schema;\n}\n"],"names":["isString","s","isPlainObject","o","Array","isArray","getDescription","field","d","admin","description","undefined","stringWithDescription","out","type","numberWithBounds","min","minimum","max","maximum","dateSchema","format","codeSchema","lang","language","trim","emailSchema","jsonValueSchema","jsonSchema","schema","normalizeSelectOptions","raw","options","values","opt","push","v","value","allNumbers","length","every","valueType","supportsHasMany","fieldType","fieldToJsonSchema","fieldInput","opts","name","nameOverride","valueSchema","base","hasMany","items","baseSingle","enum","arr","minRows","minItems","maxRows","maxItems","wrap","wrapObject","additionalProperties","properties","required"],"mappings":"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"}
|
|
@@ -1,2 +1,13 @@
|
|
|
1
1
|
import type { ClientCollectionConfig, CollectionConfig, Field } from 'payload';
|
|
2
|
-
|
|
2
|
+
type AnyCollectionConfig = ClientCollectionConfig | CollectionConfig;
|
|
3
|
+
/**
|
|
4
|
+
* Resolve a Payload field definition by a full schemaPath like:
|
|
5
|
+
* "{collectionSlug}.fieldA.subFieldB.blockSlug.innerField"
|
|
6
|
+
*
|
|
7
|
+
* Notes:
|
|
8
|
+
* - Tabs are a UI construct and are not part of schemaPath (fields inside tabs are at the same level).
|
|
9
|
+
* - Blocks include the block slug as part of the path (we must consume it between the block field and its inner fields).
|
|
10
|
+
* - Rows are skipped by this plugin's schema path mapping; support added defensively.
|
|
11
|
+
*/
|
|
12
|
+
export declare const getFieldBySchemaPath: (collectionConfig: AnyCollectionConfig, schemaPath: string) => Field | null;
|
|
13
|
+
export {};
|