@ai-stack/payloadcms 3.76.0-beta.2 → 3.76.0-beta.4
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/README.md +5 -5
- package/dist/ai/core/media/image/handlers/multimodal.js +2 -2
- package/dist/ai/core/media/image/handlers/multimodal.js.map +1 -1
- package/dist/ai/providers/blocks/anthropic.js +2 -2
- package/dist/ai/providers/blocks/anthropic.js.map +1 -1
- package/dist/ai/providers/blocks/elevenlabs.js +3 -3
- package/dist/ai/providers/blocks/elevenlabs.js.map +1 -1
- package/dist/ai/providers/blocks/fal.js +2 -2
- package/dist/ai/providers/blocks/fal.js.map +1 -1
- package/dist/ai/providers/blocks/google.js +4 -3
- package/dist/ai/providers/blocks/google.js.map +1 -1
- package/dist/ai/providers/blocks/openai-compatible.js +2 -2
- package/dist/ai/providers/blocks/openai-compatible.js.map +1 -1
- package/dist/ai/providers/blocks/openai.js +2 -2
- package/dist/ai/providers/blocks/openai.js.map +1 -1
- package/dist/ai/providers/blocks/xai.js +2 -2
- package/dist/ai/providers/blocks/xai.js.map +1 -1
- package/dist/ai/utilities/nodeToSchemaMap.js +6 -6
- package/dist/ai/utilities/nodeToSchemaMap.js.map +1 -1
- package/dist/collections/AIProviders.js +13 -13
- package/dist/collections/AIProviders.js.map +1 -1
- package/dist/collections/Instructions.js +6 -6
- package/dist/collections/Instructions.js.map +1 -1
- package/dist/endpoints/index.js +1 -1
- package/dist/endpoints/index.js.map +1 -1
- package/dist/exports/types.d.ts +1 -1
- package/dist/exports/types.js.map +1 -1
- package/dist/fields/LexicalEditor/feature.server.d.ts +1 -1
- package/dist/fields/LexicalEditor/feature.server.js +2 -2
- package/dist/fields/LexicalEditor/feature.server.js.map +1 -1
- package/dist/fields/PromptEditorField/feature.client.js.map +1 -1
- package/dist/fields/PromptEditorField/feature.server.js +1 -1
- package/dist/fields/PromptEditorField/feature.server.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/plugin.d.ts +2 -2
- package/dist/plugin.js +3 -3
- package/dist/plugin.js.map +1 -1
- package/dist/providers/FieldProvider/FieldProvider.js +1 -1
- package/dist/providers/FieldProvider/FieldProvider.js.map +1 -1
- package/dist/providers/FieldProvider/FieldProvider.jsx +2 -2
- package/dist/providers/InstructionsProvider/InstructionsProvider.js +1 -1
- package/dist/providers/InstructionsProvider/InstructionsProvider.js.map +1 -1
- package/dist/providers/InstructionsProvider/InstructionsProvider.jsx +2 -2
- package/dist/types.d.ts +10 -0
- package/dist/types.js.map +1 -1
- package/dist/ui/Compose/Compose.js.map +1 -1
- package/dist/ui/Compose/hooks/menu/Item.js.map +1 -1
- package/dist/ui/Compose/hooks/menu/TranslateMenu.js +12 -4
- package/dist/ui/Compose/hooks/menu/TranslateMenu.js.map +1 -1
- package/dist/ui/Compose/hooks/menu/TranslateMenu.jsx +8 -4
- package/dist/ui/Compose/hooks/useHistory.js +1 -1
- package/dist/ui/Compose/hooks/useHistory.js.map +1 -1
- package/dist/ui/DynamicModelSelect/index.js +1 -1
- package/dist/ui/DynamicModelSelect/index.js.map +1 -1
- package/dist/ui/DynamicModelSelect/index.jsx +1 -1
- package/dist/ui/DynamicProviderSelect/index.js +1 -1
- package/dist/ui/DynamicProviderSelect/index.js.map +1 -1
- package/dist/ui/DynamicProviderSelect/index.jsx +1 -1
- package/dist/ui/DynamicVoiceSelect/index.js +1 -1
- package/dist/ui/DynamicVoiceSelect/index.js.map +1 -1
- package/dist/ui/DynamicVoiceSelect/index.jsx +1 -1
- package/dist/ui/InstructionProviderOptions/ProviderOptionsTree.js.map +1 -1
- package/dist/ui/hooks/useAISettings.js.map +1 -1
- package/dist/ui/providerOptions/updateProviderOptionsValue.d.ts +1 -1
- package/dist/ui/providerOptions/updateProviderOptionsValue.js.map +1 -1
- package/dist/utilities/ai/resolveEffectiveInstructionSettings.js.map +1 -1
- package/dist/utilities/fields/updateFieldsConfig.js +1 -1
- package/dist/utilities/fields/updateFieldsConfig.js.map +1 -1
- package/dist/utilities/lexical/lexicalToPromptTemplate.d.ts +1 -1
- package/dist/utilities/lexical/lexicalToPromptTemplate.js +1 -1
- package/dist/utilities/lexical/lexicalToPromptTemplate.js.map +1 -1
- package/dist/utilities/lexical/stringToLexicalJSON.js +1 -1
- package/dist/utilities/lexical/stringToLexicalJSON.js.map +1 -1
- package/dist/utilities/seedProperties.js +19 -2
- package/dist/utilities/seedProperties.js.map +1 -1
- package/package.json +37 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/fields/PromptEditorField/feature.server.ts"],"sourcesContent":["import { createServerFeature } from '@payloadcms/richtext-lexical'\n\n// Mock the node for server-side usage to avoid import issues with the library\nconst BeautifulMentionNode = {\n clone: (node: any) => ({ ...node }),\n getType: () => 'beautifulMention',\n importJSON: (serializedNode: any) => {\n // Return a basic object that satisfies the lexical node interface purely for server validation\n return {\n ...serializedNode,\n exportJSON: () => serializedNode,\n getType: () => 'beautifulMention',\n }\n },\n}\n\nexport const PromptMentionsFeature = createServerFeature({\n feature: {\n ClientFeature: '@ai-stack/payloadcms/fields#PromptMentionsClient',\n nodes: [\n {\n converters: {},\n node: BeautifulMentionNode,\n },\n ],\n },\n key: 'promptMentions',\n})\n"],"names":["createServerFeature","BeautifulMentionNode","clone","node","getType","importJSON","serializedNode","exportJSON","PromptMentionsFeature","feature","ClientFeature","nodes","converters","key"],"mappings":"AAAA,SAASA,mBAAmB,QAAQ,+BAA8B;AAElE,8EAA8E;AAC9E,MAAMC,uBAAuB;IAC3BC,OAAO,CAACC,OAAe,CAAA;YAAE,GAAGA,IAAI;QAAC,CAAA;IACjCC,SAAS,IAAM;IACfC,YAAY,CAACC;QACX,+FAA+F;QAC/F,OAAO;YACL,GAAGA,cAAc;YACjBC,YAAY,IAAMD;YAClBF,SAAS,IAAM;QACjB;IACF;AACF;AAEA,OAAO,MAAMI,wBAAwBR,oBAAoB;IACvDS,SAAS;QACPC,eAAe;QACfC,OAAO;YACL;gBACEC,YAAY,CAAC;gBACbT,MAAMF;YACR;SACD;IACH;IACAY,KAAK;AACP,GAAE"}
|
|
1
|
+
{"version":3,"sources":["../../../src/fields/PromptEditorField/feature.server.ts"],"sourcesContent":["import { createServerFeature } from '@payloadcms/richtext-lexical'\n\n// Mock the node for server-side usage to avoid import issues with the library\nconst BeautifulMentionNode = {\n clone: (node: any) => ({ ...node }),\n getType: () => 'beautifulMention',\n importJSON: (serializedNode: any) => {\n // Return a basic object that satisfies the lexical node interface purely for server validation\n return {\n ...serializedNode,\n exportJSON: () => serializedNode,\n getType: () => 'beautifulMention',\n }\n },\n}\n\nexport const PromptMentionsFeature = createServerFeature({\n feature: {\n ClientFeature: '@ai-stack/payloadcms/fields/PromptEditorField/feature.client.js#PromptMentionsClient',\n nodes: [\n {\n converters: {},\n node: BeautifulMentionNode,\n },\n ],\n },\n key: 'promptMentions',\n})\n"],"names":["createServerFeature","BeautifulMentionNode","clone","node","getType","importJSON","serializedNode","exportJSON","PromptMentionsFeature","feature","ClientFeature","nodes","converters","key"],"mappings":"AAAA,SAASA,mBAAmB,QAAQ,+BAA8B;AAElE,8EAA8E;AAC9E,MAAMC,uBAAuB;IAC3BC,OAAO,CAACC,OAAe,CAAA;YAAE,GAAGA,IAAI;QAAC,CAAA;IACjCC,SAAS,IAAM;IACfC,YAAY,CAACC;QACX,+FAA+F;QAC/F,OAAO;YACL,GAAGA,cAAc;YACjBC,YAAY,IAAMD;YAClBF,SAAS,IAAM;QACjB;IACF;AACF;AAEA,OAAO,MAAMI,wBAAwBR,oBAAoB;IACvDS,SAAS;QACPC,eAAe;QACfC,OAAO;YACL;gBACEC,YAAY,CAAC;gBACbT,MAAMF;YACR;SACD;IACH;IACAY,KAAK;AACP,GAAE"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { defaultPrompts } from './ai/utilities/prompts.js';
|
|
2
2
|
export { promptMentionsEndpoint } from './endpoints/promptMentions.js';
|
|
3
|
-
export {
|
|
3
|
+
export { aiPluginLexicalEditorFeature } from './fields/LexicalEditor/feature.server.js';
|
|
4
4
|
export { PromptField } from './fields/PromptField.js';
|
|
5
5
|
export type {} from './payload-ai.d.ts';
|
|
6
|
-
export {
|
|
6
|
+
export { aiPlugin } from './plugin.js';
|
|
7
7
|
export { fieldToJsonSchema } from './utilities/fields/fieldToJsonSchema.js';
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export { defaultPrompts } from './ai/utilities/prompts.js';
|
|
2
2
|
export { promptMentionsEndpoint } from './endpoints/promptMentions.js';
|
|
3
|
-
export {
|
|
3
|
+
export { aiPluginLexicalEditorFeature } from './fields/LexicalEditor/feature.server.js';
|
|
4
4
|
export { PromptField } from './fields/PromptField.js';
|
|
5
|
-
export {
|
|
5
|
+
export { aiPlugin } from './plugin.js';
|
|
6
6
|
export { fieldToJsonSchema } from './utilities/fields/fieldToJsonSchema.js';
|
|
7
7
|
|
|
8
8
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { defaultPrompts } from './ai/utilities/prompts.js'\nexport { promptMentionsEndpoint } from './endpoints/promptMentions.js'\nexport {
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { defaultPrompts } from './ai/utilities/prompts.js'\nexport { promptMentionsEndpoint } from './endpoints/promptMentions.js'\nexport { aiPluginLexicalEditorFeature } from './fields/LexicalEditor/feature.server.js'\nexport { PromptField } from './fields/PromptField.js'\n// Re-export to ensure payload.ai module augmentation is included\nexport type {} from './payload-ai.d.ts'\nexport { aiPlugin } from './plugin.js'\nexport { fieldToJsonSchema } from './utilities/fields/fieldToJsonSchema.js'\n"],"names":["defaultPrompts","promptMentionsEndpoint","aiPluginLexicalEditorFeature","PromptField","aiPlugin","fieldToJsonSchema"],"mappings":"AAAA,SAASA,cAAc,QAAQ,4BAA2B;AAC1D,SAASC,sBAAsB,QAAQ,gCAA+B;AACtE,SAASC,4BAA4B,QAAQ,2CAA0C;AACvF,SAASC,WAAW,QAAQ,0BAAyB;AAGrD,SAASC,QAAQ,QAAQ,cAAa;AACtC,SAASC,iBAAiB,QAAQ,0CAAyC"}
|
package/dist/plugin.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { Config } from 'payload';
|
|
2
2
|
import type { PluginConfig } from './types.js';
|
|
3
|
-
declare const
|
|
4
|
-
export {
|
|
3
|
+
declare const aiPlugin: (pluginConfig: PluginConfig) => (incomingConfig: Config) => Config;
|
|
4
|
+
export { aiPlugin };
|
package/dist/plugin.js
CHANGED
|
@@ -50,7 +50,7 @@ const securityMessage = `
|
|
|
50
50
|
║ them explicitly in your plugin configuration. ║
|
|
51
51
|
╚═══════════════════════════════════════════════════════════════╝
|
|
52
52
|
`;
|
|
53
|
-
const
|
|
53
|
+
const aiPlugin = (pluginConfig)=>(incomingConfig)=>{
|
|
54
54
|
pluginConfig = {
|
|
55
55
|
...defaultPluginConfig,
|
|
56
56
|
...pluginConfig,
|
|
@@ -97,7 +97,7 @@ const payloadAiPlugin = (pluginConfig)=>(incomingConfig)=>{
|
|
|
97
97
|
const updatedProviders = [
|
|
98
98
|
...providers ?? [],
|
|
99
99
|
{
|
|
100
|
-
path: '@ai-stack/payloadcms/
|
|
100
|
+
path: '@ai-stack/payloadcms/providers/InstructionsProvider/InstructionsProvider.js#InstructionsProvider'
|
|
101
101
|
}
|
|
102
102
|
];
|
|
103
103
|
incomingConfig.admin = {
|
|
@@ -221,6 +221,6 @@ const payloadAiPlugin = (pluginConfig)=>(incomingConfig)=>{
|
|
|
221
221
|
};
|
|
222
222
|
return updatedConfig;
|
|
223
223
|
};
|
|
224
|
-
export {
|
|
224
|
+
export { aiPlugin };
|
|
225
225
|
|
|
226
226
|
//# sourceMappingURL=plugin.js.map
|
package/dist/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/plugin.ts"],"sourcesContent":["import type { CollectionConfig, Config, GlobalConfig } from 'payload'\n\nimport { deepMergeSimple } from 'payload/shared'\n\nimport type {\n PayloadGenerateMediaArgs,\n PayloadGenerateObjectArgs,\n PayloadGenerateTextArgs,\n} from './ai/core/types.js'\nimport type { PluginConfig } from './types.js'\n\nimport { lexicalJsonSchema } from './ai/schemas/lexicalJsonSchema.js'\nimport { aiJobsCollection } from './collections/AIJobs.js'\nimport { AIProvidersGlobal } from './collections/AIProviders.js'\nimport { instructionsCollection } from './collections/Instructions.js'\nimport { PLUGIN_NAME } from './defaults.js'\nimport { fetchFields } from './endpoints/fetchFields.js'\nimport { fetchVoices } from './endpoints/fetchVoices.js'\nimport { endpoints } from './endpoints/index.js'\nimport { translations } from './translations/index.js'\nimport { updateFieldsConfig } from './utilities/fields/updateFieldsConfig.js'\nimport { autoSetupProviders } from './utilities/init/autoSetupProviders.js'\n\nconst defaultPluginConfig: PluginConfig = {\n access: {\n generate: ({ req }) => !!req.user,\n settings: ({ req }) => !!req.user,\n },\n disableSponsorMessage: false,\n}\n\nconst sponsorMessage = `\n╔═══════════════════════════════════════════════════════════════╗\n║ THANK YOU FOR USING THE PAYLOAD AI PLUGIN! ║\n║ ║\n║ If this plugin makes your life easier, please ║\n║ consider supporting its development and maintenance: ║\n║ ║\n║ • Buy me a coffee: https://buymeacoffee.com/ashbuilds ║\n║ • Sponsor on GitHub: https://github.com/sponsors/ashbuilds ║\n║ ║\n║ Your support fuels continued improvements, ║\n║ new features, and more caffeinated coding sessions! ☕ ║\n║ ║\n║ Got feedback or need help? Submit an issue here: ║\n║ • https://github.com/ashbuilds/payload-ai/issues/new ║\n║ ║\n║ Thank you again, and happy building! ║\n╚═══════════════════════════════════════════════════════════════╝\n`\n\nconst securityMessage = `\n╔═══════════════════════════════════════════════════════════════╗\n║ SECURITY NOTICE ║\n║ ║\n║ The AI Plugin now requires authentication by default. ║\n║ All AI features are restricted to authenticated users. ║\n║ ║\n║ To customize access control, configure the 'access' option ║\n║ in your plugin settings. See documentation for details. ║\n║ ║\n║ If you need different access patterns, please configure ║\n║ them explicitly in your plugin configuration. ║\n╚═══════════════════════════════════════════════════════════════╝\n`\n\nconst payloadAiPlugin =\n (pluginConfig: PluginConfig) =>\n (incomingConfig: Config): Config => {\n pluginConfig = {\n ...defaultPluginConfig,\n ...pluginConfig,\n access: {\n ...defaultPluginConfig.access,\n ...pluginConfig.access,\n },\n }\n\n const isActivated = !!pluginConfig\n let updatedConfig: Config = { ...incomingConfig }\n\n if (isActivated) {\n const Instructions = instructionsCollection(pluginConfig)\n const AIJobs = aiJobsCollection()\n // Inject editor schema to config, so that it can be accessed when /textarea endpoint will hit\n const lexicalSchema = lexicalJsonSchema(pluginConfig.editorConfig?.nodes)\n\n if (!Instructions.admin) {\n Instructions.admin = {}\n }\n\n if (pluginConfig.debugging) {\n Instructions.admin.hidden = false\n }\n\n Instructions.admin.custom = {\n ...(Instructions.admin.custom || {}),\n [PLUGIN_NAME]: {\n editorConfig: {\n // Used in admin client for useObject hook\n schema: lexicalSchema,\n },\n },\n }\n\n const collections = [...(incomingConfig.collections ?? []), Instructions, AIJobs]\n const globals = [...(incomingConfig.globals ?? []), AIProvidersGlobal]\n const { globals: globalsSlugs } = pluginConfig\n\n const { components: { providers = [] } = {} } = incomingConfig.admin || {}\n const updatedProviders = [\n ...(providers ?? []),\n {\n path: '@ai-stack/payloadcms/client#InstructionsProvider',\n },\n ]\n\n incomingConfig.admin = {\n ...(incomingConfig.admin || {}),\n components: {\n ...(incomingConfig.admin?.components ?? {}),\n providers: updatedProviders,\n },\n }\n\n const pluginEndpoints = endpoints(pluginConfig)\n updatedConfig = {\n ...incomingConfig,\n collections: collections.map((collection) => {\n // Always inject fields, but they will be dynamically enabled/disabled by the InstructionsProvider\n const { updatedCollectionConfig } = updateFieldsConfig(collection)\n return updatedCollectionConfig as CollectionConfig\n }),\n endpoints: [\n ...(incomingConfig.endpoints ?? []),\n pluginEndpoints.promptMentions,\n pluginEndpoints.textarea,\n pluginEndpoints.upload,\n ...(pluginEndpoints.videogenWebhook ? [pluginEndpoints.videogenWebhook] : []),\n fetchFields(pluginConfig),\n fetchVoices,\n ],\n globals: globals.map((global) => {\n if (globalsSlugs && globalsSlugs[global.slug]) {\n const { updatedCollectionConfig } = updateFieldsConfig(global)\n return updatedCollectionConfig as GlobalConfig\n }\n\n return global\n }),\n i18n: {\n ...(incomingConfig.i18n || {}),\n translations: deepMergeSimple(translations, incomingConfig.i18n?.translations ?? {}),\n },\n }\n }\n\n updatedConfig.onInit = async (payload) => {\n if (incomingConfig.onInit) {\n await incomingConfig.onInit(payload)\n }\n\n if (!isActivated) {\n payload.logger.warn(`— AI Plugin: Not activated. Please verify your environment keys.`)\n return\n }\n\n if (!pluginConfig.disableSponsorMessage) {\n setTimeout(() => {\n payload.logger.info(securityMessage)\n }, 1000)\n setTimeout(() => {\n payload.logger.info(sponsorMessage)\n }, 3000)\n }\n\n // Inject AI capabilities with the abstraction layer\n const ai = {\n // Core generation methods\n generateObject: async (args: Omit<PayloadGenerateObjectArgs, 'payload'>) => {\n const { generateObject } = await import('./ai/core/index.js')\n return generateObject({ ...args, payload })\n },\n\n generateText: async (args: Omit<PayloadGenerateTextArgs, 'payload'>) => {\n const { generateText } = await import('./ai/core/index.js')\n return generateText({ ...args, payload })\n },\n\n generateMedia: async (args: Omit<PayloadGenerateMediaArgs, 'payload'>) => {\n const { generateMedia } = await import('./ai/core/index.js')\n return generateMedia({ ...args, payload })\n },\n\n // Streaming variants\n streamObject: async (args: Omit<PayloadGenerateObjectArgs, 'payload'>) => {\n const { streamObject } = await import('./ai/core/index.js')\n const result = await streamObject({ ...args, payload })\n return result.toTextStreamResponse()\n },\n\n streamText: async (args: Omit<PayloadGenerateTextArgs, 'payload'>) => {\n const { streamText } = await import('./ai/core/index.js')\n return streamText({ ...args, payload })\n },\n\n // Helper utilities\n getModel: async (provider: string, modelId: string, type?: 'image' | 'text' | 'tts') => {\n const { getImageModel, getLanguageModel, getTTSModel } = await import(\n './ai/providers/registry.js'\n )\n if (type === 'image') {\n return getImageModel(payload, provider, modelId)\n }\n if (type === 'tts') {\n return getTTSModel(payload, provider, modelId)\n }\n return getLanguageModel(payload, provider, modelId)\n },\n\n getRegistry: async () => {\n const { getProviderRegistry } = await import('./ai/providers/registry.js')\n return getProviderRegistry(payload)\n },\n }\n\n // Use Object.defineProperty to safely add ai to payload\n Object.defineProperty(payload, 'ai', { value: ai, writable: true })\n\n // Handle Provider Options & seeding auto-setup\n await autoSetupProviders(payload, pluginConfig)\n }\n\n return updatedConfig\n }\n\nexport { payloadAiPlugin }\n"],"names":["deepMergeSimple","lexicalJsonSchema","aiJobsCollection","AIProvidersGlobal","instructionsCollection","PLUGIN_NAME","fetchFields","fetchVoices","endpoints","translations","updateFieldsConfig","autoSetupProviders","defaultPluginConfig","access","generate","req","user","settings","disableSponsorMessage","sponsorMessage","securityMessage","payloadAiPlugin","pluginConfig","incomingConfig","isActivated","updatedConfig","Instructions","AIJobs","lexicalSchema","editorConfig","nodes","admin","debugging","hidden","custom","schema","collections","globals","globalsSlugs","components","providers","updatedProviders","path","pluginEndpoints","map","collection","updatedCollectionConfig","promptMentions","textarea","upload","videogenWebhook","global","slug","i18n","onInit","payload","logger","warn","setTimeout","info","ai","generateObject","args","generateText","generateMedia","streamObject","result","toTextStreamResponse","streamText","getModel","provider","modelId","type","getImageModel","getLanguageModel","getTTSModel","getRegistry","getProviderRegistry","Object","defineProperty","value","writable"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts"],"sourcesContent":["import type { CollectionConfig, Config, GlobalConfig } from 'payload'\n\nimport { deepMergeSimple } from 'payload/shared'\n\nimport type {\n PayloadGenerateMediaArgs,\n PayloadGenerateObjectArgs,\n PayloadGenerateTextArgs,\n} from './ai/core/types.js'\nimport type { PluginConfig } from './types.js'\n\nimport { lexicalJsonSchema } from './ai/schemas/lexicalJsonSchema.js'\nimport { aiJobsCollection } from './collections/AIJobs.js'\nimport { AIProvidersGlobal } from './collections/AIProviders.js'\nimport { instructionsCollection } from './collections/Instructions.js'\nimport { PLUGIN_NAME } from './defaults.js'\nimport { fetchFields } from './endpoints/fetchFields.js'\nimport { fetchVoices } from './endpoints/fetchVoices.js'\nimport { endpoints } from './endpoints/index.js'\nimport { translations } from './translations/index.js'\nimport { updateFieldsConfig } from './utilities/fields/updateFieldsConfig.js'\nimport { autoSetupProviders } from './utilities/init/autoSetupProviders.js'\n\nconst defaultPluginConfig: PluginConfig = {\n access: {\n generate: ({ req }) => !!req.user,\n settings: ({ req }) => !!req.user,\n },\n disableSponsorMessage: false,\n}\n\nconst sponsorMessage = `\n╔═══════════════════════════════════════════════════════════════╗\n║ THANK YOU FOR USING THE PAYLOAD AI PLUGIN! ║\n║ ║\n║ If this plugin makes your life easier, please ║\n║ consider supporting its development and maintenance: ║\n║ ║\n║ • Buy me a coffee: https://buymeacoffee.com/ashbuilds ║\n║ • Sponsor on GitHub: https://github.com/sponsors/ashbuilds ║\n║ ║\n║ Your support fuels continued improvements, ║\n║ new features, and more caffeinated coding sessions! ☕ ║\n║ ║\n║ Got feedback or need help? Submit an issue here: ║\n║ • https://github.com/ashbuilds/payload-ai/issues/new ║\n║ ║\n║ Thank you again, and happy building! ║\n╚═══════════════════════════════════════════════════════════════╝\n`\n\nconst securityMessage = `\n╔═══════════════════════════════════════════════════════════════╗\n║ SECURITY NOTICE ║\n║ ║\n║ The AI Plugin now requires authentication by default. ║\n║ All AI features are restricted to authenticated users. ║\n║ ║\n║ To customize access control, configure the 'access' option ║\n║ in your plugin settings. See documentation for details. ║\n║ ║\n║ If you need different access patterns, please configure ║\n║ them explicitly in your plugin configuration. ║\n╚═══════════════════════════════════════════════════════════════╝\n`\n\nconst aiPlugin =\n (pluginConfig: PluginConfig) =>\n (incomingConfig: Config): Config => {\n pluginConfig = {\n ...defaultPluginConfig,\n ...pluginConfig,\n access: {\n ...defaultPluginConfig.access,\n ...pluginConfig.access,\n },\n }\n\n const isActivated = !!pluginConfig\n let updatedConfig: Config = { ...incomingConfig }\n\n if (isActivated) {\n const Instructions = instructionsCollection(pluginConfig)\n const AIJobs = aiJobsCollection()\n // Inject editor schema to config, so that it can be accessed when /textarea endpoint will hit\n const lexicalSchema = lexicalJsonSchema(pluginConfig.editorConfig?.nodes)\n\n if (!Instructions.admin) {\n Instructions.admin = {}\n }\n\n if (pluginConfig.debugging) {\n Instructions.admin.hidden = false\n }\n\n Instructions.admin.custom = {\n ...(Instructions.admin.custom || {}),\n [PLUGIN_NAME]: {\n editorConfig: {\n // Used in admin client for useObject hook\n schema: lexicalSchema,\n },\n },\n }\n\n const collections = [...(incomingConfig.collections ?? []), Instructions, AIJobs]\n const globals = [...(incomingConfig.globals ?? []), AIProvidersGlobal]\n const { globals: globalsSlugs } = pluginConfig\n\n const { components: { providers = [] } = {} } = incomingConfig.admin || {}\n const updatedProviders = [\n ...(providers ?? []),\n {\n path: '@ai-stack/payloadcms/providers/InstructionsProvider/InstructionsProvider.js#InstructionsProvider',\n },\n ]\n\n incomingConfig.admin = {\n ...(incomingConfig.admin || {}),\n components: {\n ...(incomingConfig.admin?.components ?? {}),\n providers: updatedProviders,\n },\n }\n\n const pluginEndpoints = endpoints(pluginConfig)\n updatedConfig = {\n ...incomingConfig,\n collections: collections.map((collection) => {\n // Always inject fields, but they will be dynamically enabled/disabled by the InstructionsProvider\n const { updatedCollectionConfig } = updateFieldsConfig(collection)\n return updatedCollectionConfig as CollectionConfig\n }),\n endpoints: [\n ...(incomingConfig.endpoints ?? []),\n pluginEndpoints.promptMentions,\n pluginEndpoints.textarea,\n pluginEndpoints.upload,\n ...(pluginEndpoints.videogenWebhook ? [pluginEndpoints.videogenWebhook] : []),\n fetchFields(pluginConfig),\n fetchVoices,\n ],\n globals: globals.map((global) => {\n if (globalsSlugs && globalsSlugs[global.slug]) {\n const { updatedCollectionConfig } = updateFieldsConfig(global)\n return updatedCollectionConfig as GlobalConfig\n }\n\n return global\n }),\n i18n: {\n ...(incomingConfig.i18n || {}),\n translations: deepMergeSimple(translations, incomingConfig.i18n?.translations ?? {}),\n },\n }\n }\n\n updatedConfig.onInit = async (payload) => {\n if (incomingConfig.onInit) {\n await incomingConfig.onInit(payload)\n }\n\n if (!isActivated) {\n payload.logger.warn(`— AI Plugin: Not activated. Please verify your environment keys.`)\n return\n }\n\n if (!pluginConfig.disableSponsorMessage) {\n setTimeout(() => {\n payload.logger.info(securityMessage)\n }, 1000)\n setTimeout(() => {\n payload.logger.info(sponsorMessage)\n }, 3000)\n }\n\n // Inject AI capabilities with the abstraction layer\n const ai = {\n // Core generation methods\n generateObject: async (args: Omit<PayloadGenerateObjectArgs, 'payload'>) => {\n const { generateObject } = await import('./ai/core/index.js')\n return generateObject({ ...args, payload })\n },\n\n generateText: async (args: Omit<PayloadGenerateTextArgs, 'payload'>) => {\n const { generateText } = await import('./ai/core/index.js')\n return generateText({ ...args, payload })\n },\n\n generateMedia: async (args: Omit<PayloadGenerateMediaArgs, 'payload'>) => {\n const { generateMedia } = await import('./ai/core/index.js')\n return generateMedia({ ...args, payload })\n },\n\n // Streaming variants\n streamObject: async (args: Omit<PayloadGenerateObjectArgs, 'payload'>) => {\n const { streamObject } = await import('./ai/core/index.js')\n const result = await streamObject({ ...args, payload })\n return result.toTextStreamResponse()\n },\n\n streamText: async (args: Omit<PayloadGenerateTextArgs, 'payload'>) => {\n const { streamText } = await import('./ai/core/index.js')\n return streamText({ ...args, payload })\n },\n\n // Helper utilities\n getModel: async (provider: string, modelId: string, type?: 'image' | 'text' | 'tts') => {\n const { getImageModel, getLanguageModel, getTTSModel } = await import(\n './ai/providers/registry.js'\n )\n if (type === 'image') {\n return getImageModel(payload, provider, modelId)\n }\n if (type === 'tts') {\n return getTTSModel(payload, provider, modelId)\n }\n return getLanguageModel(payload, provider, modelId)\n },\n\n getRegistry: async () => {\n const { getProviderRegistry } = await import('./ai/providers/registry.js')\n return getProviderRegistry(payload)\n },\n }\n\n // Use Object.defineProperty to safely add ai to payload\n Object.defineProperty(payload, 'ai', { value: ai, writable: true })\n\n // Handle Provider Options & seeding auto-setup\n await autoSetupProviders(payload, pluginConfig)\n }\n\n return updatedConfig\n }\n\nexport { aiPlugin }\n"],"names":["deepMergeSimple","lexicalJsonSchema","aiJobsCollection","AIProvidersGlobal","instructionsCollection","PLUGIN_NAME","fetchFields","fetchVoices","endpoints","translations","updateFieldsConfig","autoSetupProviders","defaultPluginConfig","access","generate","req","user","settings","disableSponsorMessage","sponsorMessage","securityMessage","aiPlugin","pluginConfig","incomingConfig","isActivated","updatedConfig","Instructions","AIJobs","lexicalSchema","editorConfig","nodes","admin","debugging","hidden","custom","schema","collections","globals","globalsSlugs","components","providers","updatedProviders","path","pluginEndpoints","map","collection","updatedCollectionConfig","promptMentions","textarea","upload","videogenWebhook","global","slug","i18n","onInit","payload","logger","warn","setTimeout","info","ai","generateObject","args","generateText","generateMedia","streamObject","result","toTextStreamResponse","streamText","getModel","provider","modelId","type","getImageModel","getLanguageModel","getTTSModel","getRegistry","getProviderRegistry","Object","defineProperty","value","writable"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/providers/FieldProvider/FieldProvider.tsx"],"sourcesContent":["import type { ClientField } from 'payload'\n\nimport React, { createContext, useMemo } from 'react'\n\ntype FieldContextType = {\n field?: ClientField\n path?: string\n schemaPath?: string\n}\n\nconst initialContext: FieldContextType = {\n field: undefined,\n path: '',\n schemaPath: '',\n}\n\nexport const FieldContext = createContext<FieldContextType>(initialContext)\n\nexport const FieldProvider = ({\n children,\n context,\n}: {\n children: React.ReactNode\n context: {\n field?: ClientField\n path: string\n schemaPath: unknown\n }\n}) => {\n const value = useMemo(\n () => ({\n field: context.field,\n path: context.path,\n schemaPath: String(context.schemaPath ?? ''),\n }),\n [context.field, context.path, context.schemaPath],\n )\n\n return (\n <FieldContext
|
|
1
|
+
{"version":3,"sources":["../../../src/providers/FieldProvider/FieldProvider.tsx"],"sourcesContent":["import type { ClientField } from 'payload'\n\nimport React, { createContext, useMemo } from 'react'\n\ntype FieldContextType = {\n field?: ClientField\n path?: string\n schemaPath?: string\n}\n\nconst initialContext: FieldContextType = {\n field: undefined,\n path: '',\n schemaPath: '',\n}\n\nexport const FieldContext = createContext<FieldContextType>(initialContext)\n\nexport const FieldProvider = ({\n children,\n context,\n}: {\n children: React.ReactNode\n context: {\n field?: ClientField\n path: string\n schemaPath: unknown\n }\n}) => {\n const value = useMemo(\n () => ({\n field: context.field,\n path: context.path,\n schemaPath: String(context.schemaPath ?? ''),\n }),\n [context.field, context.path, context.schemaPath],\n )\n\n return (\n <FieldContext value={value}>\n {children}\n </FieldContext>\n )\n}\n"],"names":["React","createContext","useMemo","initialContext","field","undefined","path","schemaPath","FieldContext","FieldProvider","children","context","value","String"],"mappings":";AAEA,OAAOA,SAASC,aAAa,EAAEC,OAAO,QAAQ,QAAO;AAQrD,MAAMC,iBAAmC;IACvCC,OAAOC;IACPC,MAAM;IACNC,YAAY;AACd;AAEA,OAAO,MAAMC,6BAAeP,cAAgCE,gBAAe;AAE3E,OAAO,MAAMM,gBAAgB,CAAC,EAC5BC,QAAQ,EACRC,OAAO,EAQR;IACC,MAAMC,QAAQV,QACZ,IAAO,CAAA;YACLE,OAAOO,QAAQP,KAAK;YACpBE,MAAMK,QAAQL,IAAI;YAClBC,YAAYM,OAAOF,QAAQJ,UAAU,IAAI;QAC3C,CAAA,GACA;QAACI,QAAQP,KAAK;QAAEO,QAAQL,IAAI;QAAEK,QAAQJ,UAAU;KAAC;IAGnD,qBACE,KAACC;QAAaI,OAAOA;kBAClBF;;AAGP,EAAC"}
|
|
@@ -11,7 +11,7 @@ export const FieldProvider = ({ children, context, }) => {
|
|
|
11
11
|
path: context.path,
|
|
12
12
|
schemaPath: String(context.schemaPath ?? ''),
|
|
13
13
|
}), [context.field, context.path, context.schemaPath]);
|
|
14
|
-
return (<FieldContext
|
|
14
|
+
return (<FieldContext value={value}>
|
|
15
15
|
{children}
|
|
16
|
-
</FieldContext
|
|
16
|
+
</FieldContext>);
|
|
17
17
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/providers/InstructionsProvider/InstructionsProvider.tsx"],"sourcesContent":["'use client'\n\nimport { useAuth, useConfig, useDocumentDrawer } from '@payloadcms/ui'\nimport React, { useCallback, useEffect, useState } from 'react'\n\nimport type { SerializedPromptField } from '../../types.js'\n\nimport { PLUGIN_FETCH_FIELDS_ENDPOINT, PLUGIN_INSTRUCTIONS_TABLE } from '../../defaults.js'\nimport { useActiveFieldTracking } from '../../ui/Compose/hooks/useActiveFieldTracking.js'\nimport { InstructionsContext } from './context.js'\n\nexport const InstructionsProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {\n // Initialize field tracking globally so ai-plugin-active class is added on field focus\n useActiveFieldTracking()\n\n const [instructions, setInstructionsState] = useState({})\n const [promptFields, setPromptFields] = useState<SerializedPromptField[]>([])\n const [activeCollection, setActiveCollection] = useState('')\n const [isConfigAllowed, setIsConfigAllowed] = useState(false)\n const [enabledLanguages, setEnabledLanguages] = useState<string[]>()\n const [enabledCollections, setEnabledCollections] = useState<string[]>()\n const [debugging, setDebugging] = useState(false)\n const { user } = useAuth()\n\n const { config } = useConfig()\n const {\n routes: { api },\n serverURL,\n } = config\n\n // Global Document Drawer state\n const [drawerInstructionId, setDrawerInstructionId] = useState<string>('')\n const [drawerOpenCount, setDrawerOpenCount] = useState(0)\n\n const [DocumentDrawer, _, { openDrawer: openPayloadDrawer }] = useDocumentDrawer({\n id: drawerInstructionId,\n collectionSlug: PLUGIN_INSTRUCTIONS_TABLE,\n })\n\n const openDrawer = useCallback((id: string) => {\n setDrawerInstructionId(id)\n setDrawerOpenCount((prev) => prev + 1)\n }, [])\n\n // Open drawer when count changes\n useEffect(() => {\n if (drawerOpenCount > 0) {\n openPayloadDrawer()\n }\n }, [drawerOpenCount, openPayloadDrawer])\n\n const handleSave = useCallback(\n ({ doc }: { doc: any }) => {\n setInstructionsState((prev) => {\n return {\n ...prev,\n [doc['schema-path']]: {\n id: doc.id,\n alwaysShow: !!doc.alwaysShow,\n appendGenerated: !!doc.appendGenerated,\n disabled: !!doc.disabled,\n fieldType: doc['field-type'],\n hasMany: !!doc.hasMany,\n },\n }\n })\n },\n [setInstructionsState],\n )\n\n const fetchFieldsData = useCallback(async () => {\n // Only fetch if we have a user ID - prevents fetching on every user object reference change\n if (!user?.id) {\n return\n }\n\n try {\n const res = await fetch(`${serverURL}${api}${PLUGIN_FETCH_FIELDS_ENDPOINT}`)\n const data = await res.json()\n setIsConfigAllowed(data?.isConfigAllowed || false)\n setEnabledLanguages(data?.enabledLanguages || [])\n setEnabledCollections(data?.enabledCollections || [])\n setInstructionsState(data?.fields || {})\n setPromptFields(data?.promptFields || [])\n setDebugging(data?.debugging || false)\n } catch (err) {\n console.error('InstructionsProvider:', err)\n }\n }, [api, serverURL, user?.id])\n\n useEffect(() => {\n void fetchFieldsData()\n }, [fetchFieldsData])\n\n const refresh = useCallback(async () => {\n await fetchFieldsData()\n }, [fetchFieldsData])\n\n return (\n <InstructionsContext
|
|
1
|
+
{"version":3,"sources":["../../../src/providers/InstructionsProvider/InstructionsProvider.tsx"],"sourcesContent":["'use client'\n\nimport { useAuth, useConfig, useDocumentDrawer } from '@payloadcms/ui'\nimport React, { useCallback, useEffect, useState } from 'react'\n\nimport type { SerializedPromptField } from '../../types.js'\n\nimport { PLUGIN_FETCH_FIELDS_ENDPOINT, PLUGIN_INSTRUCTIONS_TABLE } from '../../defaults.js'\nimport { useActiveFieldTracking } from '../../ui/Compose/hooks/useActiveFieldTracking.js'\nimport { InstructionsContext } from './context.js'\n\nexport const InstructionsProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {\n // Initialize field tracking globally so ai-plugin-active class is added on field focus\n useActiveFieldTracking()\n\n const [instructions, setInstructionsState] = useState({})\n const [promptFields, setPromptFields] = useState<SerializedPromptField[]>([])\n const [activeCollection, setActiveCollection] = useState('')\n const [isConfigAllowed, setIsConfigAllowed] = useState(false)\n const [enabledLanguages, setEnabledLanguages] = useState<string[]>()\n const [enabledCollections, setEnabledCollections] = useState<string[]>()\n const [debugging, setDebugging] = useState(false)\n const { user } = useAuth()\n\n const { config } = useConfig()\n const {\n routes: { api },\n serverURL,\n } = config\n\n // Global Document Drawer state\n const [drawerInstructionId, setDrawerInstructionId] = useState<string>('')\n const [drawerOpenCount, setDrawerOpenCount] = useState(0)\n\n const [DocumentDrawer, _, { openDrawer: openPayloadDrawer }] = useDocumentDrawer({\n id: drawerInstructionId,\n collectionSlug: PLUGIN_INSTRUCTIONS_TABLE,\n })\n\n const openDrawer = useCallback((id: string) => {\n setDrawerInstructionId(id)\n setDrawerOpenCount((prev) => prev + 1)\n }, [])\n\n // Open drawer when count changes\n useEffect(() => {\n if (drawerOpenCount > 0) {\n openPayloadDrawer()\n }\n }, [drawerOpenCount, openPayloadDrawer])\n\n const handleSave = useCallback(\n ({ doc }: { doc: any }) => {\n setInstructionsState((prev) => {\n return {\n ...prev,\n [doc['schema-path']]: {\n id: doc.id,\n alwaysShow: !!doc.alwaysShow,\n appendGenerated: !!doc.appendGenerated,\n disabled: !!doc.disabled,\n fieldType: doc['field-type'],\n hasMany: !!doc.hasMany,\n },\n }\n })\n },\n [setInstructionsState],\n )\n\n const fetchFieldsData = useCallback(async () => {\n // Only fetch if we have a user ID - prevents fetching on every user object reference change\n if (!user?.id) {\n return\n }\n\n try {\n const res = await fetch(`${serverURL}${api}${PLUGIN_FETCH_FIELDS_ENDPOINT}`)\n const data = await res.json()\n setIsConfigAllowed(data?.isConfigAllowed || false)\n setEnabledLanguages(data?.enabledLanguages || [])\n setEnabledCollections(data?.enabledCollections || [])\n setInstructionsState(data?.fields || {})\n setPromptFields(data?.promptFields || [])\n setDebugging(data?.debugging || false)\n } catch (err) {\n console.error('InstructionsProvider:', err)\n }\n }, [api, serverURL, user?.id])\n\n useEffect(() => {\n void fetchFieldsData()\n }, [fetchFieldsData])\n\n const refresh = useCallback(async () => {\n await fetchFieldsData()\n }, [fetchFieldsData])\n\n return (\n <InstructionsContext\n value={{\n activeCollection,\n debugging,\n enabledCollections,\n enabledLanguages,\n hasInstructions: instructions && Object.keys(instructions).length > 0,\n instructions,\n isConfigAllowed,\n openDrawer,\n promptFields,\n refresh,\n setActiveCollection,\n setEnabledCollections,\n }}\n >\n {children}\n <DocumentDrawer onSave={handleSave} />\n </InstructionsContext>\n )\n}\n"],"names":["useAuth","useConfig","useDocumentDrawer","React","useCallback","useEffect","useState","PLUGIN_FETCH_FIELDS_ENDPOINT","PLUGIN_INSTRUCTIONS_TABLE","useActiveFieldTracking","InstructionsContext","InstructionsProvider","children","instructions","setInstructionsState","promptFields","setPromptFields","activeCollection","setActiveCollection","isConfigAllowed","setIsConfigAllowed","enabledLanguages","setEnabledLanguages","enabledCollections","setEnabledCollections","debugging","setDebugging","user","config","routes","api","serverURL","drawerInstructionId","setDrawerInstructionId","drawerOpenCount","setDrawerOpenCount","DocumentDrawer","_","openDrawer","openPayloadDrawer","id","collectionSlug","prev","handleSave","doc","alwaysShow","appendGenerated","disabled","fieldType","hasMany","fetchFieldsData","res","fetch","data","json","fields","err","console","error","refresh","value","hasInstructions","Object","keys","length","onSave"],"mappings":"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"}
|
|
@@ -74,7 +74,7 @@ export const InstructionsProvider = ({ children }) => {
|
|
|
74
74
|
const refresh = useCallback(async () => {
|
|
75
75
|
await fetchFieldsData();
|
|
76
76
|
}, [fetchFieldsData]);
|
|
77
|
-
return (<InstructionsContext
|
|
77
|
+
return (<InstructionsContext value={{
|
|
78
78
|
activeCollection,
|
|
79
79
|
debugging,
|
|
80
80
|
enabledCollections,
|
|
@@ -90,5 +90,5 @@ export const InstructionsProvider = ({ children }) => {
|
|
|
90
90
|
}}>
|
|
91
91
|
{children}
|
|
92
92
|
<DocumentDrawer onSave={handleSave}/>
|
|
93
|
-
</InstructionsContext
|
|
93
|
+
</InstructionsContext>);
|
|
94
94
|
};
|
package/dist/types.d.ts
CHANGED
|
@@ -212,7 +212,17 @@ export interface AIFieldConfig {
|
|
|
212
212
|
* Admin `disabled` in Instructions still takes priority.
|
|
213
213
|
*/
|
|
214
214
|
alwaysShow?: boolean;
|
|
215
|
+
/**
|
|
216
|
+
* When true and the field hasMany, generated values are appended
|
|
217
|
+
* instead of replacing current field value(s).
|
|
218
|
+
*/
|
|
219
|
+
appendGenerated?: boolean;
|
|
215
220
|
beforeGenerate?: BeforeGenerateHook[];
|
|
221
|
+
/**
|
|
222
|
+
* Default hidden state for Compose in instructions.
|
|
223
|
+
* When true, Compose is hidden for this field.
|
|
224
|
+
*/
|
|
225
|
+
disabled?: boolean;
|
|
216
226
|
/**
|
|
217
227
|
* Set to false to opt-out of compose button injection for this field.
|
|
218
228
|
* When false, no compose button is injected at build time.
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type { GenerateObjectResult, ModelMessage } from 'ai'\nimport type { JSONSchema } from 'openai/lib/jsonschema'\nimport type { ImageGenerateParams } from 'openai/resources/images'\nimport type {\n CollectionConfig,\n CollectionSlug,\n DataFromCollectionSlug,\n Endpoint,\n Field,\n File,\n GlobalConfig,\n GroupField,\n PayloadRequest,\n TypedCollection,\n} from 'payload'\n\nimport type { MediaResult } from './ai/core/index.js'\nimport type { PLUGIN_INSTRUCTIONS_TABLE } from './defaults.js'\n\nexport interface PluginConfigAccess {\n /**\n * Control access to AI generation features (generate text, images, audio)\n * @default () => !!req.user (requires authentication)\n */\n generate?: ({ req }: { req: PayloadRequest }) => boolean | Promise<boolean>\n /**\n * Control access to AI settings/configuration\n * @default () => !!req.user (requires authentication)\n */\n settings?: ({ req }: { req: PayloadRequest }) => boolean | Promise<boolean>\n}\n\nexport interface PluginOptions {\n /**\n * Provide local tags to filter language options from the Translate Menu\n * Check for the available local tags,\n * visit: https://www.npmjs.com/package/locale-codes\n * Example: [\"en-US\", \"zh-SG\", \"zh-CN\", \"en\"]\n */\n enabledLanguages?: string[]\n}\n\nexport type PluginConfigMediaUploadFunction = (\n result: MediaResult,\n {\n collection,\n request,\n }: {\n collection: CollectionSlug\n request: PayloadRequest\n },\n) => Promise<DataFromCollectionSlug<CollectionSlug>>\n\nexport interface PluginConfig {\n /**\n * Access control configuration for AI features\n * By default, all AI features require authentication\n */\n access?: PluginConfigAccess\n debugging?: boolean\n disableSponsorMessage?: boolean\n editorConfig?: { nodes: JSONSchema[] }\n fields?: Field[]\n /**\n * Defines default provider and models to be selected\n * when creating initial database records for Generation Defaults.\n */\n generationDefaults?: {\n image?: { model: string; provider: string }\n text?: { model: string; provider: string }\n tts?: { model: string; provider: string; voice?: string }\n video?: { model: string; provider: string }\n }\n generationModels?: ((defaultModels: GenerationModel[]) => GenerationModel[]) | GenerationModel[]\n globals?: {\n [key: GlobalConfig['slug']]: boolean\n }\n interfaceName?: string\n mediaUpload?: PluginConfigMediaUploadFunction\n options?: PluginOptions\n overrideInstructions?: any\n promptFields?: any[]\n prompts?: ActionPrompt[]\n /**\n * Pre-configured options that get passed directly to AI SDK providers.\n * This allows devs to define AI options safely via payload.config.ts.\n */\n providerOptions?: {\n [key: string]: Record<string, any> | undefined // generic fallback\n anthropic?: Record<string, any>\n elevenlabs?: Record<string, any>\n fal?: Record<string, any>\n google?: Record<string, any>\n openai?: Record<string, any>\n }\n /**\n * Custom seed prompt function for generating field-specific prompts\n * If not provided, fields will have empty prompts by default\n */\n seedPrompts?: SeedPromptFunction\n uploadCollectionSlug?: CollectionSlug\n}\n\nexport interface GenerationModel {\n fields: string[]\n generateText?: (prompt: string, system: string) => Promise<string>\n handler?: (prompt: string, options: any) => File | Promise<any> | Response\n id: string\n name: string\n output: 'audio' | 'file' | 'image' | 'json' | 'text' | 'video'\n settings?: GroupField\n supportsPromptOptimization?: boolean\n}\n\nexport interface GenerationConfig {\n models: GenerationModel[]\n provider: string\n}\n\nexport type GenerateTextarea<T = any> = (args: {\n collectionSlug: CollectionSlug\n doc: T\n documentId?: number | string\n locale?: string\n options?: any\n}) => Promise<string> | string\n\nexport interface Endpoints {\n fetchVoices?: Omit<Endpoint, 'root'>\n promptMentions: Endpoint\n textarea: Omit<Endpoint, 'root'>\n upload: Omit<Endpoint, 'root'>\n videogenWebhook?: Omit<Endpoint, 'root'>\n}\n\nexport type ActionMenuItems =\n | 'Compose'\n | 'Expand'\n | 'Proofread'\n | 'Rephrase'\n | 'Settings'\n | 'Simplify'\n | 'Summarize'\n | 'Tone'\n | 'Translate'\n\nexport type ActionPromptOptions = {\n layout?: string\n locale?: string\n prompt?: string\n systemPrompt?: string\n}\n\nexport type ActionPrompt = {\n layout?: (options?: ActionPromptOptions) => string\n name: ActionMenuItems\n system: (options: ActionPromptOptions) => string\n}\n\nexport type SeedPromptOptions = {\n fieldLabel: string\n fieldSchemaPaths: Record<string, any>\n fieldType: string\n path: string\n}\n\nexport type SeedPromptData = Omit<\n TypedCollection[typeof PLUGIN_INSTRUCTIONS_TABLE],\n 'createdAt' | 'id' | 'updatedAt'\n>\n\nexport type SeedPromptResult =\n | {\n data?: SeedPromptData\n }\n | {\n data?: SeedPromptData\n prompt: string\n system: string\n }\n | false\n | undefined\n | void\n\nexport type SeedPromptFunction = (\n options: SeedPromptOptions,\n) => Promise<SeedPromptResult> | SeedPromptResult\n\nexport type ImageReference = {\n data: Blob\n name: string\n size: number\n type: string\n url: string\n}\n\nexport type GenerateImageParams = {\n images?: ImageReference[]\n size?: ImageGenerateParams['size']\n style?: ImageGenerateParams['style']\n version?: ImageGenerateParams['model']\n}\n\nexport type SerializedPromptField = {\n collections?: CollectionSlug[]\n name: string\n}\n\nexport type PromptFieldGetterContext = {\n collection: CollectionSlug\n type: string\n}\n\nexport type PromptField = {\n // If not provided, the value will be returned from the data object as-is\n getter?: (data: object, ctx: PromptFieldGetterContext) => Promise<string> | string\n} & SerializedPromptField\n\nexport interface BeforeGenerateArgs<T = any> {\n doc: T\n field: Field\n headers: Record<string, string>\n instructions: Record<string, unknown> // The instruction document\n messages?: ModelMessage[]\n payload: PayloadRequest['payload']\n prompt: string\n req: PayloadRequest\n system: string\n}\n\nexport type BeforeGenerateResult = {\n messages?: ModelMessage[]\n prompt?: string\n system?: string\n} | void\n\nexport type BeforeGenerateHook<T = any> = (\n args: BeforeGenerateArgs<T>,\n) => BeforeGenerateResult | Promise<BeforeGenerateResult>\n\nexport interface AfterGenerateArgs<T = any> {\n doc: T\n field: Field\n headers: Record<string, string>\n instructions: Record<string, unknown>\n payload: PayloadRequest['payload']\n req: PayloadRequest\n result: GenerateObjectResult<any> | MediaResult | string // depends on context\n}\n\nexport type AfterGenerateHook<T = any> = (args: AfterGenerateArgs<T>) => Promise<void> | void\n\n// Add to PluginConfig or a new interface if accessed via custom.ai\nexport interface AIFieldConfig {\n [key: string]: unknown\n afterGenerate?: AfterGenerateHook[]\n /**\n * When true, the Compose button is always visible on this field,\n * bypassing the focus-based show/hide system.\n * Admin `disabled` in Instructions still takes priority.\n */\n alwaysShow?: boolean\n beforeGenerate?: BeforeGenerateHook[]\n /**\n * Set to false to opt-out of compose button injection for this field.\n * When false, no compose button is injected at build time.\n * @default true (compose is auto-injected on supported field types)\n */\n enabled?: boolean\n /** Custom prompt template for this field */\n prompt?: string\n /** Custom system prompt for this field */\n system?: string\n}\n"],"names":[],"mappings":"AA4PA,mEAAmE;AACnE,
|
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type { GenerateObjectResult, ModelMessage } from 'ai'\nimport type { JSONSchema } from 'openai/lib/jsonschema'\nimport type { ImageGenerateParams } from 'openai/resources/images'\nimport type {\n CollectionConfig,\n CollectionSlug,\n DataFromCollectionSlug,\n Endpoint,\n Field,\n File,\n GlobalConfig,\n GroupField,\n PayloadRequest,\n TypedCollection,\n} from 'payload'\n\nimport type { MediaResult } from './ai/core/index.js'\nimport type { PLUGIN_INSTRUCTIONS_TABLE } from './defaults.js'\n\nexport interface PluginConfigAccess {\n /**\n * Control access to AI generation features (generate text, images, audio)\n * @default () => !!req.user (requires authentication)\n */\n generate?: ({ req }: { req: PayloadRequest }) => boolean | Promise<boolean>\n /**\n * Control access to AI settings/configuration\n * @default () => !!req.user (requires authentication)\n */\n settings?: ({ req }: { req: PayloadRequest }) => boolean | Promise<boolean>\n}\n\nexport interface PluginOptions {\n /**\n * Provide local tags to filter language options from the Translate Menu\n * Check for the available local tags,\n * visit: https://www.npmjs.com/package/locale-codes\n * Example: [\"en-US\", \"zh-SG\", \"zh-CN\", \"en\"]\n */\n enabledLanguages?: string[]\n}\n\nexport type PluginConfigMediaUploadFunction = (\n result: MediaResult,\n {\n collection,\n request,\n }: {\n collection: CollectionSlug\n request: PayloadRequest\n },\n) => Promise<DataFromCollectionSlug<CollectionSlug>>\n\nexport interface PluginConfig {\n /**\n * Access control configuration for AI features\n * By default, all AI features require authentication\n */\n access?: PluginConfigAccess\n debugging?: boolean\n disableSponsorMessage?: boolean\n editorConfig?: { nodes: JSONSchema[] }\n fields?: Field[]\n /**\n * Defines default provider and models to be selected\n * when creating initial database records for Generation Defaults.\n */\n generationDefaults?: {\n image?: { model: string; provider: string }\n text?: { model: string; provider: string }\n tts?: { model: string; provider: string; voice?: string }\n video?: { model: string; provider: string }\n }\n generationModels?: ((defaultModels: GenerationModel[]) => GenerationModel[]) | GenerationModel[]\n globals?: {\n [key: GlobalConfig['slug']]: boolean\n }\n interfaceName?: string\n mediaUpload?: PluginConfigMediaUploadFunction\n options?: PluginOptions\n overrideInstructions?: any\n promptFields?: any[]\n prompts?: ActionPrompt[]\n /**\n * Pre-configured options that get passed directly to AI SDK providers.\n * This allows devs to define AI options safely via payload.config.ts.\n */\n providerOptions?: {\n [key: string]: Record<string, any> | undefined // generic fallback\n anthropic?: Record<string, any>\n elevenlabs?: Record<string, any>\n fal?: Record<string, any>\n google?: Record<string, any>\n openai?: Record<string, any>\n }\n /**\n * Custom seed prompt function for generating field-specific prompts\n * If not provided, fields will have empty prompts by default\n */\n seedPrompts?: SeedPromptFunction\n uploadCollectionSlug?: CollectionSlug\n}\n\nexport interface GenerationModel {\n fields: string[]\n generateText?: (prompt: string, system: string) => Promise<string>\n handler?: (prompt: string, options: any) => File | Promise<any> | Response\n id: string\n name: string\n output: 'audio' | 'file' | 'image' | 'json' | 'text' | 'video'\n settings?: GroupField\n supportsPromptOptimization?: boolean\n}\n\nexport interface GenerationConfig {\n models: GenerationModel[]\n provider: string\n}\n\nexport type GenerateTextarea<T = any> = (args: {\n collectionSlug: CollectionSlug\n doc: T\n documentId?: number | string\n locale?: string\n options?: any\n}) => Promise<string> | string\n\nexport interface Endpoints {\n fetchVoices?: Omit<Endpoint, 'root'>\n promptMentions: Endpoint\n textarea: Omit<Endpoint, 'root'>\n upload: Omit<Endpoint, 'root'>\n videogenWebhook?: Omit<Endpoint, 'root'>\n}\n\nexport type ActionMenuItems =\n | 'Compose'\n | 'Expand'\n | 'Proofread'\n | 'Rephrase'\n | 'Settings'\n | 'Simplify'\n | 'Summarize'\n | 'Tone'\n | 'Translate'\n\nexport type ActionPromptOptions = {\n layout?: string\n locale?: string\n prompt?: string\n systemPrompt?: string\n}\n\nexport type ActionPrompt = {\n layout?: (options?: ActionPromptOptions) => string\n name: ActionMenuItems\n system: (options: ActionPromptOptions) => string\n}\n\nexport type SeedPromptOptions = {\n fieldLabel: string\n fieldSchemaPaths: Record<string, any>\n fieldType: string\n path: string\n}\n\nexport type SeedPromptData = Omit<\n TypedCollection[typeof PLUGIN_INSTRUCTIONS_TABLE],\n 'createdAt' | 'id' | 'updatedAt'\n>\n\nexport type SeedPromptResult =\n | {\n data?: SeedPromptData\n }\n | {\n data?: SeedPromptData\n prompt: string\n system: string\n }\n | false\n | undefined\n | void\n\nexport type SeedPromptFunction = (\n options: SeedPromptOptions,\n) => Promise<SeedPromptResult> | SeedPromptResult\n\nexport type ImageReference = {\n data: Blob\n name: string\n size: number\n type: string\n url: string\n}\n\nexport type GenerateImageParams = {\n images?: ImageReference[]\n size?: ImageGenerateParams['size']\n style?: ImageGenerateParams['style']\n version?: ImageGenerateParams['model']\n}\n\nexport type SerializedPromptField = {\n collections?: CollectionSlug[]\n name: string\n}\n\nexport type PromptFieldGetterContext = {\n collection: CollectionSlug\n type: string\n}\n\nexport type PromptField = {\n // If not provided, the value will be returned from the data object as-is\n getter?: (data: object, ctx: PromptFieldGetterContext) => Promise<string> | string\n} & SerializedPromptField\n\nexport interface BeforeGenerateArgs<T = any> {\n doc: T\n field: Field\n headers: Record<string, string>\n instructions: Record<string, unknown> // The instruction document\n messages?: ModelMessage[]\n payload: PayloadRequest['payload']\n prompt: string\n req: PayloadRequest\n system: string\n}\n\nexport type BeforeGenerateResult = {\n messages?: ModelMessage[]\n prompt?: string\n system?: string\n} | void\n\nexport type BeforeGenerateHook<T = any> = (\n args: BeforeGenerateArgs<T>,\n) => BeforeGenerateResult | Promise<BeforeGenerateResult>\n\nexport interface AfterGenerateArgs<T = any> {\n doc: T\n field: Field\n headers: Record<string, string>\n instructions: Record<string, unknown>\n payload: PayloadRequest['payload']\n req: PayloadRequest\n result: GenerateObjectResult<any> | MediaResult | string // depends on context\n}\n\nexport type AfterGenerateHook<T = any> = (args: AfterGenerateArgs<T>) => Promise<void> | void\n\n// Add to PluginConfig or a new interface if accessed via custom.ai\nexport interface AIFieldConfig {\n [key: string]: unknown\n afterGenerate?: AfterGenerateHook[]\n /**\n * When true, the Compose button is always visible on this field,\n * bypassing the focus-based show/hide system.\n * Admin `disabled` in Instructions still takes priority.\n */\n alwaysShow?: boolean\n /**\n * When true and the field hasMany, generated values are appended\n * instead of replacing current field value(s).\n */\n appendGenerated?: boolean\n beforeGenerate?: BeforeGenerateHook[]\n /**\n * Default hidden state for Compose in instructions.\n * When true, Compose is hidden for this field.\n */\n disabled?: boolean\n /**\n * Set to false to opt-out of compose button injection for this field.\n * When false, no compose button is injected at build time.\n * @default true (compose is auto-injected on supported field types)\n */\n enabled?: boolean\n /** Custom prompt template for this field */\n prompt?: string\n /** Custom system prompt for this field */\n system?: string\n}\n"],"names":[],"mappings":"AA4PA,mEAAmE;AACnE,WA8BC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/ui/Compose/Compose.tsx"],"sourcesContent":["'use client'\n\nimport type { ClientField } from 'payload'\nimport type { FC } from 'react'\n\nimport { useEditorConfigContext } from '@payloadcms/richtext-lexical/client'\nimport { Popup, useField, useTranslation } from '@payloadcms/ui'\nimport React, { useCallback, useMemo, useState } from 'react'\n\nimport type { ActionMenuItems } from '../../types.js'\nimport type { PluginAITranslationKeys, PluginAITranslations } from '../../translations/index.js'\n\nimport { useInstructions } from '../../providers/InstructionsProvider/useInstructions.js'\nimport { setSafeLexicalState } from '../../utilities/lexical/setSafeLexicalState.js'\nimport { PluginIcon } from '../Icons/Icons.js'\nimport styles from './compose.module.scss'\nimport { useMenu } from './hooks/menu/useMenu.js'\nimport { useActiveFieldTracking } from './hooks/useActiveFieldTracking.js'\nimport { useGenerate } from './hooks/useGenerate.js'\nimport { UndoRedoActions } from './UndoRedoActions.js'\n\nexport type ComposeProps = {\n descriptionProps?: {\n field: ClientField\n path: string\n schemaPath: string\n }\n forceVisible?: boolean\n instructionId: string\n isConfigAllowed: boolean\n}\n\nexport const Compose: FC<ComposeProps> = ({\n descriptionProps,\n forceVisible,\n instructionId,\n isConfigAllowed,\n}) => {\n const pathFromContext = descriptionProps?.path\n const { editor: lexicalEditor } = useEditorConfigContext()\n\n // Get global openDrawer from context\n const { openDrawer } = useInstructions()\n\n // Initialize global active-field tracking\n useActiveFieldTracking()\n\n const { t } = useTranslation<PluginAITranslations, PluginAITranslationKeys>()\n\n const [isProcessing, setIsProcessing] = useState<boolean>(false)\n const { generate, isJobActive, isLoading, jobProgress, jobStatus, stop } = useGenerate({\n instructionId,\n })\n\n // Single factory for all action callbacks, eliminating duplication\n const createAction = useCallback(\n (action: ActionMenuItems, params?: unknown) => {\n setIsProcessing(true)\n generate({ action, params })\n .catch((reason) => {\n console.error(`AI Plugin — ${action}:`, reason)\n })\n .finally(() => {\n setIsProcessing(false)\n })\n },\n [generate],\n )\n\n const onCompose = useCallback(() => createAction('Compose'), [createAction])\n const onExpand = useCallback(() => createAction('Expand'), [createAction])\n const onProofread = useCallback(() => createAction('Proofread'), [createAction])\n const onRephrase = useCallback(() => createAction('Rephrase'), [createAction])\n const onSimplify = useCallback(() => createAction('Simplify'), [createAction])\n const onSummarize = useCallback(() => createAction('Summarize'), [createAction])\n const onTranslate = useCallback(\n (data: unknown) => {\n // If the action is triggered directly via the button click,\n // it passes a React SyntheticEvent which cannot (and should not) be stringified.\n // We only want to pass data if it's the actual payload containing { locale }.\n const isEvent = data && typeof data === 'object' && 'nativeEvent' in data\n return createAction('Translate', isEvent ? undefined : data)\n },\n [createAction],\n )\n\n const handleOpenSettings = useCallback(() => {\n if (isConfigAllowed) {\n openDrawer(instructionId)\n }\n }, [isConfigAllowed, openDrawer, instructionId])\n\n const { ActiveComponent, Menu } = useMenu(\n {\n onCompose,\n onExpand,\n onProofread,\n onRephrase,\n onSettings: isConfigAllowed ? handleOpenSettings : undefined,\n onSimplify,\n onSummarize,\n onTranslate,\n },\n {\n isConfigAllowed,\n },\n )\n\n const { setValue } = useField<string>({\n path: pathFromContext,\n })\n\n const setIfValueIsLexicalState = useCallback((val: any) => {\n // Prevent setting incomplete states during streaming\n if (!val || typeof val !== 'object' || !('root' in val) || !lexicalEditor) {\n return\n }\n\n // Validate that the state is complete before setting\n // Check for common incomplete streaming states\n if (!val.root || typeof val.root !== 'object' || Object.keys(val.root).length === 0) {\n return\n }\n\n if (val.root.type !== 'root') {\n return\n }\n\n if (!val.root.children || !Array.isArray(val.root.children) || val.root.children.length === 0) {\n return\n }\n\n // Check for invalid child types (common streaming issue)\n const hasInvalidChildren = val.root.children.some(\n (child: any) => !child || !child.type || child.type === 'undefined' || child.type === '',\n )\n\n if (hasInvalidChildren) {\n return\n }\n\n // State looks valid, proceed\n setSafeLexicalState(JSON.stringify(val), lexicalEditor)\n\n // DO NOT PROVIDE lexicalEditor as a dependency, it freaks out and does not update the editor after first undo/redo - revisit\n }, [])\n\n const popupRender = useCallback(\n ({ close }: { close: () => void }) => {\n return <Menu isLoading={isProcessing || isLoading} onClose={close} />\n },\n [isProcessing, isLoading, Menu],\n )\n\n // Combine loading states to reduce re-renders\n const isAnyLoading = isProcessing || isLoading || isJobActive\n\n const memoizedPopup = useMemo(() => {\n return (\n <Popup\n button={<PluginIcon isLoading={isAnyLoading} />}\n render={popupRender}\n verticalAlign=\"bottom\"\n />\n )\n }, [popupRender, isAnyLoading])\n\n return (\n <label\n className={`payloadai-compose__actions ${styles.actions} ${forceVisible ? styles.actionsVisible : ''}`}\n onClick={(e) => e.preventDefault()}\n role=\"presentation\"\n >\n {memoizedPopup}\n <ActiveComponent\n isLoading={isProcessing || isLoading || isJobActive}\n loadingLabel={\n isJobActive\n ? jobStatus === 'running'\n ? `${t('ai-plugin:general:video' as any)} ${Math.max(0, Math.min(100, Math.round(jobProgress ?? 0)))}%`\n : jobStatus || t('ai-plugin:general:queued' as any)\n : undefined\n }\n stop={stop}\n />\n <div style={{ alignItems: 'center', display: 'flex', gap: '10px', marginLeft: 'auto' }}>\n <UndoRedoActions\n onChange={(val) => {\n setValue(val)\n setIfValueIsLexicalState(val)\n }}\n />\n </div>\n </label>\n )\n}\n"],"names":["useEditorConfigContext","Popup","useField","useTranslation","React","useCallback","useMemo","useState","useInstructions","setSafeLexicalState","PluginIcon","styles","useMenu","useActiveFieldTracking","useGenerate","UndoRedoActions","Compose","descriptionProps","forceVisible","instructionId","isConfigAllowed","pathFromContext","path","editor","lexicalEditor","openDrawer","t","isProcessing","setIsProcessing","generate","isJobActive","isLoading","jobProgress","jobStatus","stop","createAction","action","params","catch","reason","console","error","finally","onCompose","onExpand","onProofread","onRephrase","onSimplify","onSummarize","onTranslate","data","isEvent","undefined","handleOpenSettings","ActiveComponent","Menu","onSettings","setValue","setIfValueIsLexicalState","val","root","Object","keys","length","type","children","Array","isArray","hasInvalidChildren","some","child","JSON","stringify","popupRender","close","onClose","isAnyLoading","memoizedPopup","button","render","verticalAlign","label","className","actions","actionsVisible","onClick","e","preventDefault","role","loadingLabel","Math","max","min","round","div","style","alignItems","display","gap","marginLeft","onChange"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/Compose/Compose.tsx"],"sourcesContent":["'use client'\n\nimport type { ClientField } from 'payload'\nimport type { FC } from 'react'\n\nimport { useEditorConfigContext } from '@payloadcms/richtext-lexical/client'\nimport { Popup, useField, useTranslation } from '@payloadcms/ui'\nimport React, { useCallback, useMemo, useState } from 'react'\n\nimport type { PluginAITranslationKeys, PluginAITranslations } from '../../translations/index.js'\nimport type { ActionMenuItems } from '../../types.js'\n\nimport { useInstructions } from '../../providers/InstructionsProvider/useInstructions.js'\nimport { setSafeLexicalState } from '../../utilities/lexical/setSafeLexicalState.js'\nimport { PluginIcon } from '../Icons/Icons.js'\nimport styles from './compose.module.scss'\nimport { useMenu } from './hooks/menu/useMenu.js'\nimport { useActiveFieldTracking } from './hooks/useActiveFieldTracking.js'\nimport { useGenerate } from './hooks/useGenerate.js'\nimport { UndoRedoActions } from './UndoRedoActions.js'\n\nexport type ComposeProps = {\n descriptionProps?: {\n field: ClientField\n path: string\n schemaPath: string\n }\n forceVisible?: boolean\n instructionId: string\n isConfigAllowed: boolean\n}\n\nexport const Compose: FC<ComposeProps> = ({\n descriptionProps,\n forceVisible,\n instructionId,\n isConfigAllowed,\n}) => {\n const pathFromContext = descriptionProps?.path\n const { editor: lexicalEditor } = useEditorConfigContext()\n\n // Get global openDrawer from context\n const { openDrawer } = useInstructions()\n\n // Initialize global active-field tracking\n useActiveFieldTracking()\n\n const { t } = useTranslation<PluginAITranslations, PluginAITranslationKeys>()\n\n const [isProcessing, setIsProcessing] = useState<boolean>(false)\n const { generate, isJobActive, isLoading, jobProgress, jobStatus, stop } = useGenerate({\n instructionId,\n })\n\n // Single factory for all action callbacks, eliminating duplication\n const createAction = useCallback(\n (action: ActionMenuItems, params?: unknown) => {\n setIsProcessing(true)\n generate({ action, params })\n .catch((reason) => {\n console.error(`AI Plugin — ${action}:`, reason)\n })\n .finally(() => {\n setIsProcessing(false)\n })\n },\n [generate],\n )\n\n const onCompose = useCallback(() => createAction('Compose'), [createAction])\n const onExpand = useCallback(() => createAction('Expand'), [createAction])\n const onProofread = useCallback(() => createAction('Proofread'), [createAction])\n const onRephrase = useCallback(() => createAction('Rephrase'), [createAction])\n const onSimplify = useCallback(() => createAction('Simplify'), [createAction])\n const onSummarize = useCallback(() => createAction('Summarize'), [createAction])\n const onTranslate = useCallback(\n (data: unknown) => {\n // If the action is triggered directly via the button click,\n // it passes a React SyntheticEvent which cannot (and should not) be stringified.\n // We only want to pass data if it's the actual payload containing { locale }.\n const isEvent = data && typeof data === 'object' && 'nativeEvent' in data\n return createAction('Translate', isEvent ? undefined : data)\n },\n [createAction],\n )\n\n const handleOpenSettings = useCallback(() => {\n if (isConfigAllowed) {\n openDrawer(instructionId)\n }\n }, [isConfigAllowed, openDrawer, instructionId])\n\n const { ActiveComponent, Menu } = useMenu(\n {\n onCompose,\n onExpand,\n onProofread,\n onRephrase,\n onSettings: isConfigAllowed ? handleOpenSettings : undefined,\n onSimplify,\n onSummarize,\n onTranslate,\n },\n {\n isConfigAllowed,\n },\n )\n\n const { setValue } = useField<string>({\n path: pathFromContext,\n })\n\n const setIfValueIsLexicalState = useCallback((val: any) => {\n // Prevent setting incomplete states during streaming\n if (!val || typeof val !== 'object' || !('root' in val) || !lexicalEditor) {\n return\n }\n\n // Validate that the state is complete before setting\n // Check for common incomplete streaming states\n if (!val.root || typeof val.root !== 'object' || Object.keys(val.root).length === 0) {\n return\n }\n\n if (val.root.type !== 'root') {\n return\n }\n\n if (!val.root.children || !Array.isArray(val.root.children) || val.root.children.length === 0) {\n return\n }\n\n // Check for invalid child types (common streaming issue)\n const hasInvalidChildren = val.root.children.some(\n (child: any) => !child || !child.type || child.type === 'undefined' || child.type === '',\n )\n\n if (hasInvalidChildren) {\n return\n }\n\n // State looks valid, proceed\n setSafeLexicalState(JSON.stringify(val), lexicalEditor)\n\n // DO NOT PROVIDE lexicalEditor as a dependency, it freaks out and does not update the editor after first undo/redo - revisit\n }, [])\n\n const popupRender = useCallback(\n ({ close }: { close: () => void }) => {\n return <Menu isLoading={isProcessing || isLoading} onClose={close} />\n },\n [isProcessing, isLoading, Menu],\n )\n\n // Combine loading states to reduce re-renders\n const isAnyLoading = isProcessing || isLoading || isJobActive\n\n const memoizedPopup = useMemo(() => {\n return (\n <Popup\n button={<PluginIcon isLoading={isAnyLoading} />}\n render={popupRender}\n verticalAlign=\"bottom\"\n />\n )\n }, [popupRender, isAnyLoading])\n\n return (\n <label\n className={`payloadai-compose__actions ${styles.actions} ${forceVisible ? styles.actionsVisible : ''}`}\n onClick={(e) => e.preventDefault()}\n role=\"presentation\"\n >\n {memoizedPopup}\n <ActiveComponent\n isLoading={isProcessing || isLoading || isJobActive}\n loadingLabel={\n isJobActive\n ? jobStatus === 'running'\n ? `${t('ai-plugin:general:video' as any)} ${Math.max(0, Math.min(100, Math.round(jobProgress ?? 0)))}%`\n : jobStatus || t('ai-plugin:general:queued' as any)\n : undefined\n }\n stop={stop}\n />\n <div style={{ alignItems: 'center', display: 'flex', gap: '10px', marginLeft: 'auto' }}>\n <UndoRedoActions\n onChange={(val) => {\n setValue(val)\n setIfValueIsLexicalState(val)\n }}\n />\n </div>\n </label>\n )\n}\n"],"names":["useEditorConfigContext","Popup","useField","useTranslation","React","useCallback","useMemo","useState","useInstructions","setSafeLexicalState","PluginIcon","styles","useMenu","useActiveFieldTracking","useGenerate","UndoRedoActions","Compose","descriptionProps","forceVisible","instructionId","isConfigAllowed","pathFromContext","path","editor","lexicalEditor","openDrawer","t","isProcessing","setIsProcessing","generate","isJobActive","isLoading","jobProgress","jobStatus","stop","createAction","action","params","catch","reason","console","error","finally","onCompose","onExpand","onProofread","onRephrase","onSimplify","onSummarize","onTranslate","data","isEvent","undefined","handleOpenSettings","ActiveComponent","Menu","onSettings","setValue","setIfValueIsLexicalState","val","root","Object","keys","length","type","children","Array","isArray","hasInvalidChildren","some","child","JSON","stringify","popupRender","close","onClose","isAnyLoading","memoizedPopup","button","render","verticalAlign","label","className","actions","actionsVisible","onClick","e","preventDefault","role","loadingLabel","Math","max","min","round","div","style","alignItems","display","gap","marginLeft","onChange"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/ui/Compose/hooks/menu/Item.tsx"],"sourcesContent":["import { useTranslation } from '@payloadcms/ui'\nimport React, { memo } from 'react'\n\nimport type {
|
|
1
|
+
{"version":3,"sources":["../../../../../src/ui/Compose/hooks/menu/Item.tsx"],"sourcesContent":["import { useTranslation } from '@payloadcms/ui'\nimport React, { memo } from 'react'\n\nimport type { PluginAITranslationKeys, PluginAITranslations } from '../../../../translations/index.js'\nimport type { BaseItemProps } from './types.js'\n\nimport { ArrowIcon } from '../../../Icons/Icons.js'\nimport styles from './menu.module.scss'\n\nexport const Item: React.FC<BaseItemProps> = memo(\n ({ children, disabled, isActive, onClick, ...rest }) => (\n <span\n className={styles.generate_button + ' ' + (isActive ? styles.active : '')}\n data-disabled={disabled}\n onClick={\n !disabled && typeof onClick === 'function'\n ? (onClick as React.MouseEventHandler<HTMLSpanElement>)\n : undefined\n }\n onKeyDown={\n !disabled && typeof onClick === 'function'\n ? (onClick as React.KeyboardEventHandler<HTMLSpanElement>)\n : undefined\n }\n role=\"presentation\"\n {...rest}\n >\n {children}\n </span>\n ),\n)\n\nexport const createMenuItem = (\n IconComponent: React.ComponentType<{ size?: number }>,\n initialText: string,\n) =>\n memo(({ children, disabled, hideIcon, isMenu, onClick, ...rest }: BaseItemProps) => {\n const { t } = useTranslation<PluginAITranslations, PluginAITranslationKeys>()\n return (\n <Item disabled={disabled} onClick={onClick} {...rest}>\n {hideIcon || <IconComponent size={18} />}\n {children || (\n <span className={styles.text}>\n {t(`ai-plugin:actions:${initialText.toLowerCase()}` as any)}\n </span>\n )}\n {isMenu && <ArrowIcon size={18} />}\n </Item>\n )\n })\n"],"names":["useTranslation","React","memo","ArrowIcon","styles","Item","children","disabled","isActive","onClick","rest","span","className","generate_button","active","data-disabled","undefined","onKeyDown","role","createMenuItem","IconComponent","initialText","hideIcon","isMenu","t","size","text","toLowerCase"],"mappings":";AAAA,SAASA,cAAc,QAAQ,iBAAgB;AAC/C,OAAOC,SAASC,IAAI,QAAQ,QAAO;AAKnC,SAASC,SAAS,QAAQ,0BAAyB;AACnD,OAAOC,YAAY,qBAAoB;AAEvC,OAAO,MAAMC,qBAAgCH,KAC3C,CAAC,EAAEI,QAAQ,EAAEC,QAAQ,EAAEC,QAAQ,EAAEC,OAAO,EAAE,GAAGC,MAAM,iBACjD,KAACC;QACCC,WAAWR,OAAOS,eAAe,GAAG,MAAOL,CAAAA,WAAWJ,OAAOU,MAAM,GAAG,EAAC;QACvEC,iBAAeR;QACfE,SACE,CAACF,YAAY,OAAOE,YAAY,aAC3BA,UACDO;QAENC,WACE,CAACV,YAAY,OAAOE,YAAY,aAC3BA,UACDO;QAENE,MAAK;QACJ,GAAGR,IAAI;kBAEPJ;QAGN;AAED,OAAO,MAAMa,iBAAiB,CAC5BC,eACAC,4BAEAnB,KAAK,CAAC,EAAEI,QAAQ,EAAEC,QAAQ,EAAEe,QAAQ,EAAEC,MAAM,EAAEd,OAAO,EAAE,GAAGC,MAAqB;QAC7E,MAAM,EAAEc,CAAC,EAAE,GAAGxB;QACd,qBACE,MAACK;YAAKE,UAAUA;YAAUE,SAASA;YAAU,GAAGC,IAAI;;gBACjDY,0BAAY,KAACF;oBAAcK,MAAM;;gBACjCnB,0BACC,KAACK;oBAAKC,WAAWR,OAAOsB,IAAI;8BACzBF,EAAE,CAAC,kBAAkB,EAAEH,YAAYM,WAAW,GAAG,CAAC;;gBAGtDJ,wBAAU,KAACpB;oBAAUsB,MAAM;;;;IAGlC,GAAE"}
|
|
@@ -42,21 +42,29 @@ export const TranslateMenu = ({ onClick })=>{
|
|
|
42
42
|
onBlur: (e)=>{
|
|
43
43
|
// Only clear if focus moves outside the menu container
|
|
44
44
|
if (!e.currentTarget.contains(e.relatedTarget)) {
|
|
45
|
-
if (typeof window !== 'undefined')
|
|
45
|
+
if (typeof window !== 'undefined') {
|
|
46
|
+
window.__AI_MENU_INTERACTIVE = false;
|
|
47
|
+
}
|
|
46
48
|
}
|
|
47
49
|
},
|
|
48
50
|
onFocus: ()=>{
|
|
49
|
-
if (typeof window !== 'undefined')
|
|
51
|
+
if (typeof window !== 'undefined') {
|
|
52
|
+
window.__AI_MENU_INTERACTIVE = true;
|
|
53
|
+
}
|
|
50
54
|
},
|
|
51
55
|
onMouseEnter: ()=>{
|
|
52
56
|
if (closeTimeoutRef.current) {
|
|
53
57
|
clearTimeout(closeTimeoutRef.current);
|
|
54
58
|
closeTimeoutRef.current = null;
|
|
55
59
|
}
|
|
56
|
-
if (typeof window !== 'undefined')
|
|
60
|
+
if (typeof window !== 'undefined') {
|
|
61
|
+
window.__AI_MENU_INTERACTIVE = true;
|
|
62
|
+
}
|
|
57
63
|
},
|
|
58
64
|
onMouseLeave: ()=>{
|
|
59
|
-
if (typeof window !== 'undefined')
|
|
65
|
+
if (typeof window !== 'undefined') {
|
|
66
|
+
window.__AI_MENU_INTERACTIVE = false;
|
|
67
|
+
}
|
|
60
68
|
if (!inputFocus) {
|
|
61
69
|
closeTimeoutRef.current = setTimeout(()=>{
|
|
62
70
|
setShow(false);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/ui/Compose/hooks/menu/TranslateMenu.tsx"],"sourcesContent":["import { useTranslation } from '@payloadcms/ui'\nimport locales from 'locale-codes'\nimport React, { memo, useEffect, useRef, useState } from 'react'\n\nimport type { PluginAITranslationKeys, PluginAITranslations } from '../../../../translations/index.js'\n\nimport { useInstructions } from '../../../../providers/InstructionsProvider/useInstructions.js'\nimport { Item } from './Item.js'\nimport { Translate } from './items.js'\nimport styles from './menu.module.scss'\n\ndeclare global {\n interface Window {\n __AI_MENU_INTERACTIVE?: boolean\n }\n}\n\nexport const TranslateMenu = ({ onClick }: { onClick: (data: { locale: string }) => void }) => {\n const { t } = useTranslation<PluginAITranslations, PluginAITranslationKeys>()\n const [show, setShow] = useState(false)\n const closeTimeoutRef = useRef<NodeJS.Timeout | null>(null)\n\n const { enabledLanguages = [] } = useInstructions()\n\n let filteredLocales = locales.all.filter((a) => {\n return a.tag && a.location\n })\n\n if (enabledLanguages?.length) {\n filteredLocales = filteredLocales.filter((a) => enabledLanguages?.includes(a.tag))\n }\n\n const [languages, setLanguages] = useState(filteredLocales)\n const [inputFocus, setInputFocus] = useState(false)\n\n useEffect(() => {\n if (!show) {\n if (typeof window !== 'undefined') {\n window.__AI_MENU_INTERACTIVE = false\n }\n }\n return () => {\n if (closeTimeoutRef.current) {\n clearTimeout(closeTimeoutRef.current)\n }\n if (show && typeof window !== 'undefined') {\n window.__AI_MENU_INTERACTIVE = false\n }\n }\n }, [show])\n\n return (\n <div\n className={`${styles.menu} ai-interactive-menu`}\n data-ai-interactive=\"true\"\n onBlur={(e) => {\n // Only clear if focus moves outside the menu container\n if (!e.currentTarget.contains(e.relatedTarget as Node)) {\n if (typeof window !== 'undefined') window.__AI_MENU_INTERACTIVE = false\n }\n }}\n onFocus={() => {\n if (typeof window !== 'undefined') window.__AI_MENU_INTERACTIVE = true\n }}\n onMouseEnter={() => {\n if (closeTimeoutRef.current) {\n clearTimeout(closeTimeoutRef.current)\n closeTimeoutRef.current = null\n }\n if (typeof window !== 'undefined') window.__AI_MENU_INTERACTIVE = true\n }}\n onMouseLeave={() => {\n if (typeof window !== 'undefined') window.__AI_MENU_INTERACTIVE = false\n if (!inputFocus) {\n closeTimeoutRef.current = setTimeout(() => {\n setShow(false)\n }, 400)\n }\n }}\n >\n <Translate\n isActive={show}\n isMenu\n onClick={() => {\n setShow(!show)\n }}\n />\n <div className={styles.hoverMenu} data-show={show}>\n <div\n className={`${styles.menu} ${styles.subMenu}`}\n style={{\n background: 'var(--popup-bg)',\n // minHeight: '300px',\n }}\n >\n <Item\n onClick={() => {}}\n style={{\n background: 'transparent',\n padding: '0 0 5px 0',\n position: 'sticky',\n top: 0,\n }}\n >\n <input\n className={`${styles.menuInput} ai-interactive-menu`}\n data-ai-interactive=\"true\"\n onBlur={() => setInputFocus(false)}\n onChange={(event) => {\n const value = event.target.value\n setLanguages(\n filteredLocales.filter((l) => {\n const lowerCaseValue = value.toLowerCase()\n return (\n l.name.toLowerCase().startsWith(lowerCaseValue) ||\n (l.location && l.location.toLowerCase().startsWith(lowerCaseValue)) ||\n l.tag.toLowerCase().startsWith(lowerCaseValue)\n )\n }),\n )\n }}\n onFocus={() => setInputFocus(true)}\n placeholder={t('ai-plugin:general:search')}\n />\n </Item>\n {languages.map((locale) => {\n return (\n <Item\n className=\"ai-interactive-menu\"\n data-ai-interactive=\"true\"\n key={locale.tag}\n onClick={() => {\n onClick({ locale: locale.tag })\n }}\n >\n <span className={styles.ellipsis}>{`${locale.location} (${locale.tag})`}</span>\n </Item>\n )\n })}\n </div>\n </div>\n </div>\n )\n}\n\nexport const MemoizedTranslateMenu = memo(TranslateMenu)\n"],"names":["useTranslation","locales","React","memo","useEffect","useRef","useState","useInstructions","Item","Translate","styles","TranslateMenu","onClick","t","show","setShow","closeTimeoutRef","enabledLanguages","filteredLocales","all","filter","a","tag","location","length","includes","languages","setLanguages","inputFocus","setInputFocus","window","__AI_MENU_INTERACTIVE","current","clearTimeout","div","className","menu","data-ai-interactive","onBlur","e","currentTarget","contains","relatedTarget","onFocus","onMouseEnter","onMouseLeave","setTimeout","isActive","isMenu","hoverMenu","data-show","subMenu","style","background","padding","position","top","input","menuInput","onChange","event","value","target","l","lowerCaseValue","toLowerCase","name","startsWith","placeholder","map","locale","span","ellipsis","MemoizedTranslateMenu"],"mappings":";AAAA,SAASA,cAAc,QAAQ,iBAAgB;AAC/C,OAAOC,aAAa,eAAc;AAClC,OAAOC,SAASC,IAAI,EAAEC,SAAS,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,QAAO;AAIhE,SAASC,eAAe,QAAQ,gEAA+D;AAC/F,SAASC,IAAI,QAAQ,YAAW;AAChC,SAASC,SAAS,QAAQ,aAAY;AACtC,OAAOC,YAAY,qBAAoB;AAQvC,OAAO,MAAMC,gBAAgB,CAAC,EAAEC,OAAO,EAAmD;IACxF,MAAM,EAAEC,CAAC,EAAE,GAAGb;IACd,MAAM,CAACc,MAAMC,QAAQ,GAAGT,SAAS;IACjC,MAAMU,kBAAkBX,OAA8B;IAEtD,MAAM,EAAEY,mBAAmB,EAAE,EAAE,GAAGV;IAElC,IAAIW,kBAAkBjB,QAAQkB,GAAG,CAACC,MAAM,CAAC,CAACC;QACxC,OAAOA,EAAEC,GAAG,IAAID,EAAEE,QAAQ;IAC5B;IAEA,IAAIN,kBAAkBO,QAAQ;QAC5BN,kBAAkBA,gBAAgBE,MAAM,CAAC,CAACC,IAAMJ,kBAAkBQ,SAASJ,EAAEC,GAAG;IAClF;IAEA,MAAM,CAACI,WAAWC,aAAa,GAAGrB,SAASY;IAC3C,MAAM,CAACU,YAAYC,cAAc,GAAGvB,SAAS;IAE7CF,UAAU;QACR,IAAI,CAACU,MAAM;YACT,IAAI,OAAOgB,WAAW,aAAa;gBACjCA,OAAOC,qBAAqB,GAAG;YACjC;QACF;QACA,OAAO;YACL,IAAIf,gBAAgBgB,OAAO,EAAE;gBAC3BC,aAAajB,gBAAgBgB,OAAO;YACtC;YACA,IAAIlB,QAAQ,OAAOgB,WAAW,aAAa;gBACzCA,OAAOC,qBAAqB,GAAG;YACjC;QACF;IACF,GAAG;QAACjB;KAAK;IAET,qBACE,MAACoB;QACCC,WAAW,CAAC,EAAEzB,OAAO0B,IAAI,CAAC,oBAAoB,CAAC;QAC/CC,uBAAoB;QACpBC,QAAQ,CAACC;YACP,uDAAuD;YACvD,IAAI,CAACA,EAAEC,aAAa,CAACC,QAAQ,CAACF,EAAEG,aAAa,GAAW;gBACtD,IAAI,OAAOZ,WAAW,
|
|
1
|
+
{"version":3,"sources":["../../../../../src/ui/Compose/hooks/menu/TranslateMenu.tsx"],"sourcesContent":["import { useTranslation } from '@payloadcms/ui'\nimport locales from 'locale-codes'\nimport React, { memo, useEffect, useRef, useState } from 'react'\n\nimport type { PluginAITranslationKeys, PluginAITranslations } from '../../../../translations/index.js'\n\nimport { useInstructions } from '../../../../providers/InstructionsProvider/useInstructions.js'\nimport { Item } from './Item.js'\nimport { Translate } from './items.js'\nimport styles from './menu.module.scss'\n\ndeclare global {\n interface Window {\n __AI_MENU_INTERACTIVE?: boolean\n }\n}\n\nexport const TranslateMenu = ({ onClick }: { onClick: (data: { locale: string }) => void }) => {\n const { t } = useTranslation<PluginAITranslations, PluginAITranslationKeys>()\n const [show, setShow] = useState(false)\n const closeTimeoutRef = useRef<NodeJS.Timeout | null>(null)\n\n const { enabledLanguages = [] } = useInstructions()\n\n let filteredLocales = locales.all.filter((a) => {\n return a.tag && a.location\n })\n\n if (enabledLanguages?.length) {\n filteredLocales = filteredLocales.filter((a) => enabledLanguages?.includes(a.tag))\n }\n\n const [languages, setLanguages] = useState(filteredLocales)\n const [inputFocus, setInputFocus] = useState(false)\n\n useEffect(() => {\n if (!show) {\n if (typeof window !== 'undefined') {\n window.__AI_MENU_INTERACTIVE = false\n }\n }\n return () => {\n if (closeTimeoutRef.current) {\n clearTimeout(closeTimeoutRef.current)\n }\n if (show && typeof window !== 'undefined') {\n window.__AI_MENU_INTERACTIVE = false\n }\n }\n }, [show])\n\n return (\n <div\n className={`${styles.menu} ai-interactive-menu`}\n data-ai-interactive=\"true\"\n onBlur={(e) => {\n // Only clear if focus moves outside the menu container\n if (!e.currentTarget.contains(e.relatedTarget as Node)) {\n if (typeof window !== 'undefined') {window.__AI_MENU_INTERACTIVE = false}\n }\n }}\n onFocus={() => {\n if (typeof window !== 'undefined') {window.__AI_MENU_INTERACTIVE = true}\n }}\n onMouseEnter={() => {\n if (closeTimeoutRef.current) {\n clearTimeout(closeTimeoutRef.current)\n closeTimeoutRef.current = null\n }\n if (typeof window !== 'undefined') {window.__AI_MENU_INTERACTIVE = true}\n }}\n onMouseLeave={() => {\n if (typeof window !== 'undefined') {window.__AI_MENU_INTERACTIVE = false}\n if (!inputFocus) {\n closeTimeoutRef.current = setTimeout(() => {\n setShow(false)\n }, 400)\n }\n }}\n >\n <Translate\n isActive={show}\n isMenu\n onClick={() => {\n setShow(!show)\n }}\n />\n <div className={styles.hoverMenu} data-show={show}>\n <div\n className={`${styles.menu} ${styles.subMenu}`}\n style={{\n background: 'var(--popup-bg)',\n // minHeight: '300px',\n }}\n >\n <Item\n onClick={() => {}}\n style={{\n background: 'transparent',\n padding: '0 0 5px 0',\n position: 'sticky',\n top: 0,\n }}\n >\n <input\n className={`${styles.menuInput} ai-interactive-menu`}\n data-ai-interactive=\"true\"\n onBlur={() => setInputFocus(false)}\n onChange={(event) => {\n const value = event.target.value\n setLanguages(\n filteredLocales.filter((l) => {\n const lowerCaseValue = value.toLowerCase()\n return (\n l.name.toLowerCase().startsWith(lowerCaseValue) ||\n (l.location && l.location.toLowerCase().startsWith(lowerCaseValue)) ||\n l.tag.toLowerCase().startsWith(lowerCaseValue)\n )\n }),\n )\n }}\n onFocus={() => setInputFocus(true)}\n placeholder={t('ai-plugin:general:search')}\n />\n </Item>\n {languages.map((locale) => {\n return (\n <Item\n className=\"ai-interactive-menu\"\n data-ai-interactive=\"true\"\n key={locale.tag}\n onClick={() => {\n onClick({ locale: locale.tag })\n }}\n >\n <span className={styles.ellipsis}>{`${locale.location} (${locale.tag})`}</span>\n </Item>\n )\n })}\n </div>\n </div>\n </div>\n )\n}\n\nexport const MemoizedTranslateMenu = memo(TranslateMenu)\n"],"names":["useTranslation","locales","React","memo","useEffect","useRef","useState","useInstructions","Item","Translate","styles","TranslateMenu","onClick","t","show","setShow","closeTimeoutRef","enabledLanguages","filteredLocales","all","filter","a","tag","location","length","includes","languages","setLanguages","inputFocus","setInputFocus","window","__AI_MENU_INTERACTIVE","current","clearTimeout","div","className","menu","data-ai-interactive","onBlur","e","currentTarget","contains","relatedTarget","onFocus","onMouseEnter","onMouseLeave","setTimeout","isActive","isMenu","hoverMenu","data-show","subMenu","style","background","padding","position","top","input","menuInput","onChange","event","value","target","l","lowerCaseValue","toLowerCase","name","startsWith","placeholder","map","locale","span","ellipsis","MemoizedTranslateMenu"],"mappings":"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"}
|
|
@@ -36,22 +36,26 @@ export const TranslateMenu = ({ onClick }) => {
|
|
|
36
36
|
return (<div className={`${styles.menu} ai-interactive-menu`} data-ai-interactive="true" onBlur={(e) => {
|
|
37
37
|
// Only clear if focus moves outside the menu container
|
|
38
38
|
if (!e.currentTarget.contains(e.relatedTarget)) {
|
|
39
|
-
if (typeof window !== 'undefined')
|
|
39
|
+
if (typeof window !== 'undefined') {
|
|
40
40
|
window.__AI_MENU_INTERACTIVE = false;
|
|
41
|
+
}
|
|
41
42
|
}
|
|
42
43
|
}} onFocus={() => {
|
|
43
|
-
if (typeof window !== 'undefined')
|
|
44
|
+
if (typeof window !== 'undefined') {
|
|
44
45
|
window.__AI_MENU_INTERACTIVE = true;
|
|
46
|
+
}
|
|
45
47
|
}} onMouseEnter={() => {
|
|
46
48
|
if (closeTimeoutRef.current) {
|
|
47
49
|
clearTimeout(closeTimeoutRef.current);
|
|
48
50
|
closeTimeoutRef.current = null;
|
|
49
51
|
}
|
|
50
|
-
if (typeof window !== 'undefined')
|
|
52
|
+
if (typeof window !== 'undefined') {
|
|
51
53
|
window.__AI_MENU_INTERACTIVE = true;
|
|
54
|
+
}
|
|
52
55
|
}} onMouseLeave={() => {
|
|
53
|
-
if (typeof window !== 'undefined')
|
|
56
|
+
if (typeof window !== 'undefined') {
|
|
54
57
|
window.__AI_MENU_INTERACTIVE = false;
|
|
58
|
+
}
|
|
55
59
|
if (!inputFocus) {
|
|
56
60
|
closeTimeoutRef.current = setTimeout(() => {
|
|
57
61
|
setShow(false);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { useDocumentInfo, useForm } from '@payloadcms/ui';
|
|
3
|
-
import { useCallback, useEffect, useRef } from 'react';
|
|
4
3
|
import { getSiblingData } from 'payload/shared';
|
|
4
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
5
5
|
import { PLUGIN_NAME } from '../../../defaults.js';
|
|
6
6
|
import { useFieldProps } from '../../../providers/FieldProvider/useFieldProps.js';
|
|
7
7
|
const STORAGE_KEY = `${PLUGIN_NAME}-fields-history`;
|