@ai-stack/payloadcms 3.2.20-beta → 3.2.21-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.
Files changed (63) hide show
  1. package/dist/ai/models/anthropic/index.js +9 -15
  2. package/dist/ai/models/anthropic/index.js.map +1 -1
  3. package/dist/ai/models/generateObject.d.ts +11 -0
  4. package/dist/ai/models/generateObject.js +22 -0
  5. package/dist/ai/models/generateObject.js.map +1 -0
  6. package/dist/ai/models/openai/index.js +19 -17
  7. package/dist/ai/models/openai/index.js.map +1 -1
  8. package/dist/collections/Instructions.js +2 -0
  9. package/dist/collections/Instructions.js.map +1 -1
  10. package/dist/endpoints/index.js +55 -6
  11. package/dist/endpoints/index.js.map +1 -1
  12. package/dist/fields/ComposeField/ComposeField.js +5 -3
  13. package/dist/fields/ComposeField/ComposeField.js.map +1 -1
  14. package/dist/fields/ComposeField/ComposeField.jsx +32 -0
  15. package/dist/fields/LexicalEditor/ComposeFeatureComponent.js +1 -1
  16. package/dist/fields/LexicalEditor/ComposeFeatureComponent.js.map +1 -1
  17. package/dist/fields/LexicalEditor/ComposeFeatureComponent.jsx +24 -0
  18. package/dist/fields/LexicalEditor/feature.client.jsx +21 -0
  19. package/dist/fields/PromptEditorField/PromptEditorField.jsx +42 -0
  20. package/dist/fields/SelectField/SelectField.jsx +38 -0
  21. package/dist/providers/FieldProvider/FieldProvider.d.ts +7 -4
  22. package/dist/providers/FieldProvider/FieldProvider.js +7 -6
  23. package/dist/providers/FieldProvider/FieldProvider.js.map +1 -1
  24. package/dist/providers/FieldProvider/FieldProvider.jsx +27 -0
  25. package/dist/providers/FieldProvider/useFieldProps.d.ts +1 -1
  26. package/dist/providers/FieldProvider/useFieldProps.js +2 -2
  27. package/dist/providers/FieldProvider/useFieldProps.js.map +1 -1
  28. package/dist/providers/InstructionsProvider/InstructionsProvider.jsx +45 -0
  29. package/dist/types.d.ts +4 -4
  30. package/dist/types.js.map +1 -1
  31. package/dist/ui/Compose/Compose.js +12 -81
  32. package/dist/ui/Compose/Compose.js.map +1 -1
  33. package/dist/ui/Compose/Compose.jsx +141 -0
  34. package/dist/ui/Compose/UndoRedoActions.jsx +34 -0
  35. package/dist/ui/Compose/compose.module.css +99 -12
  36. package/dist/ui/Compose/hooks/menu/Item.jsx +15 -0
  37. package/dist/ui/Compose/hooks/menu/TranslateMenu.jsx +58 -0
  38. package/dist/ui/Compose/hooks/menu/items.jsx +10 -0
  39. package/dist/ui/Compose/hooks/menu/useMenu.js +1 -1
  40. package/dist/ui/Compose/hooks/menu/useMenu.js.map +1 -1
  41. package/dist/ui/Compose/hooks/menu/useMenu.jsx +89 -0
  42. package/dist/ui/Compose/hooks/useActiveFieldTracking.d.ts +5 -0
  43. package/dist/ui/Compose/hooks/useActiveFieldTracking.js +148 -0
  44. package/dist/ui/Compose/hooks/useActiveFieldTracking.js.map +1 -0
  45. package/dist/ui/Compose/hooks/useGenerate.js +46 -79
  46. package/dist/ui/Compose/hooks/useGenerate.js.map +1 -1
  47. package/dist/ui/Icons/Icons.jsx +78 -0
  48. package/dist/ui/Icons/LottieAnimation.jsx +64 -0
  49. package/dist/utilities/extractPromptAttachments.d.ts +2 -2
  50. package/dist/utilities/extractPromptAttachments.js.map +1 -1
  51. package/dist/utilities/fieldToJsonSchema.d.ts +37 -0
  52. package/dist/utilities/fieldToJsonSchema.js +274 -0
  53. package/dist/utilities/fieldToJsonSchema.js.map +1 -0
  54. package/dist/utilities/getFieldBySchemaPath.d.ts +12 -1
  55. package/dist/utilities/getFieldBySchemaPath.js +63 -29
  56. package/dist/utilities/getFieldBySchemaPath.js.map +1 -1
  57. package/package.json +2 -1
  58. package/dist/ai/models/anthropic/generateRichText.d.ts +0 -1
  59. package/dist/ai/models/anthropic/generateRichText.js +0 -36
  60. package/dist/ai/models/anthropic/generateRichText.js.map +0 -1
  61. package/dist/ai/models/openai/generateRichText.d.ts +0 -1
  62. package/dist/ai/models/openai/generateRichText.js +0 -37
  63. package/dist/ai/models/openai/generateRichText.js.map +0 -1
@@ -0,0 +1,89 @@
1
+ 'use client';
2
+ import { useField } from '@payloadcms/ui';
3
+ import React, { useEffect, useMemo, useState } from 'react';
4
+ import { useFieldProps } from '../../../../providers/FieldProvider/useFieldProps.js';
5
+ import { Compose, Proofread, Rephrase } from './items.js';
6
+ import { menuItemsMap } from './itemsMap.js';
7
+ import styles from './menu.module.scss';
8
+ const getActiveComponent = (ac) => {
9
+ switch (ac) {
10
+ case 'Compose':
11
+ return Compose;
12
+ case 'Proofread':
13
+ return Proofread;
14
+ case 'Rephrase':
15
+ return Rephrase;
16
+ default:
17
+ return Rephrase;
18
+ }
19
+ };
20
+ export const useMenu = (menuEvents, options) => {
21
+ const { field: { type: fieldType } = {}, path: pathFromContext } = useFieldProps();
22
+ const field = useField({ path: pathFromContext ?? '' });
23
+ const [activeComponent, setActiveComponent] = useState('Rephrase');
24
+ const { initialValue, value } = field;
25
+ useEffect(() => {
26
+ if (!value) {
27
+ setActiveComponent('Compose');
28
+ return;
29
+ }
30
+ if (menuItemsMap.some((i) => i.excludedFor?.includes(fieldType ?? ''))) {
31
+ setActiveComponent('Compose');
32
+ return;
33
+ }
34
+ if (typeof value === 'string' && value !== initialValue) {
35
+ setActiveComponent('Proofread');
36
+ }
37
+ else {
38
+ setActiveComponent('Rephrase');
39
+ }
40
+ }, [initialValue, value, fieldType]);
41
+ const MemoizedActiveComponent = useMemo(() => {
42
+ return ({ isLoading, stop }) => {
43
+ const ActiveComponent = getActiveComponent(activeComponent);
44
+ const activeItem = menuItemsMap.find((i) => i.name === activeComponent);
45
+ return (<ActiveComponent hideIcon onClick={(data) => {
46
+ if (!isLoading) {
47
+ const trigger = menuEvents[`on${activeComponent}`];
48
+ if (typeof trigger === 'function') {
49
+ trigger(data);
50
+ }
51
+ else {
52
+ console.error('No trigger found for', activeComponent);
53
+ }
54
+ }
55
+ else {
56
+ stop();
57
+ }
58
+ }} title={isLoading ? 'Click to stop' : activeItem.name}>
59
+ {isLoading && activeItem.loadingText}
60
+ </ActiveComponent>);
61
+ };
62
+ }, [activeComponent, menuEvents]);
63
+ const filteredMenuItems = useMemo(() => menuItemsMap.filter((i) => {
64
+ if (i.name === 'Settings' && !options.isConfigAllowed) {
65
+ return false;
66
+ } // Disable settings if a user role is not permitted
67
+ return i.name !== activeComponent && !i.excludedFor?.includes(fieldType ?? '');
68
+ }), [activeComponent, fieldType, options.isConfigAllowed]);
69
+ const MemoizedMenu = useMemo(() => {
70
+ return ({ isLoading, onClose }) => (<div className={styles.menu}>
71
+ {filteredMenuItems.map((i) => {
72
+ const Action = i.component;
73
+ return (<Action disabled={isLoading} key={i.name} onClick={(data) => {
74
+ if (i.name !== 'Settings') {
75
+ setActiveComponent(i.name);
76
+ }
77
+ menuEvents[`on${i.name}`]?.(data);
78
+ onClose();
79
+ }}>
80
+ {isLoading && i.loadingText}
81
+ </Action>);
82
+ })}
83
+ </div>);
84
+ }, [filteredMenuItems, menuEvents]);
85
+ return {
86
+ ActiveComponent: MemoizedActiveComponent,
87
+ Menu: MemoizedMenu,
88
+ };
89
+ };
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Initialize document-level listeners to track the active field container.
3
+ * When a container is active, it receives the 'ai-plugin-active' class.
4
+ */
5
+ export declare const useActiveFieldTracking: () => void;
@@ -0,0 +1,148 @@
1
+ 'use client';
2
+ import { useEffect } from 'react';
3
+ let currentContainer = null;
4
+ /**
5
+ * Safely escape CSS selector values
6
+ */ const cssEscape = (value)=>{
7
+ if (typeof CSS !== 'undefined' && typeof CSS.escape === 'function') {
8
+ return CSS.escape(value);
9
+ }
10
+ return value.replace(/([ #;?%&,.+*~':"!^$[\]()=>|/@])/g, '\\$1');
11
+ };
12
+ /**
13
+ * Find container from React Select dropdown elements
14
+ */ const findContainerFromReactSelect = (target)=>{
15
+ const listbox = target.closest('[role="listbox"]');
16
+ if (!listbox?.id) {
17
+ return null;
18
+ }
19
+ const id = cssEscape(listbox.id);
20
+ const selector = `[aria-controls="${id}"], [aria-owns="${id}"]`;
21
+ const control = document.querySelector(selector);
22
+ return control?.closest('.field-type') ?? null;
23
+ };
24
+ /**
25
+ * Resolve the .field-type container for a given event target
26
+ */ const resolveContainerFromTarget = (target)=>{
27
+ if (!(target instanceof HTMLElement)) {
28
+ return null;
29
+ }
30
+ // Check for direct parent first
31
+ const direct = target.closest('.field-type');
32
+ if (direct) {
33
+ return direct;
34
+ }
35
+ // Fall back to React Select logic
36
+ return findContainerFromReactSelect(target);
37
+ };
38
+ /**
39
+ * Update the active container and toggle CSS class
40
+ */ const setActiveContainer = (next)=>{
41
+ if (currentContainer === next) {
42
+ return;
43
+ }
44
+ currentContainer?.classList.remove('ai-plugin-active');
45
+ next?.classList.add('ai-plugin-active');
46
+ currentContainer = next;
47
+ };
48
+ const isInteractiveElement = (element)=>{
49
+ const tagName = element.tagName.toLowerCase();
50
+ const interactiveTags = [
51
+ 'input',
52
+ 'textarea',
53
+ 'select',
54
+ 'button'
55
+ ];
56
+ if (interactiveTags.includes(tagName)) {
57
+ return true;
58
+ }
59
+ // Check for contenteditable
60
+ if (element.isContentEditable) {
61
+ return true;
62
+ }
63
+ // Check for elements with role="textbox" or role="combobox" (React Select)
64
+ const role = element.getAttribute('role');
65
+ if (role && [
66
+ 'combobox',
67
+ 'listbox',
68
+ 'searchbox',
69
+ 'textbox'
70
+ ].includes(role)) {
71
+ return true;
72
+ }
73
+ return false;
74
+ };
75
+ /**
76
+ * Handle focus events - only activate if focus is on an interactive element within .field-type
77
+ */ const onFocusIn = (e)=>{
78
+ const target = e.target;
79
+ if (!(target instanceof HTMLElement)) {
80
+ return;
81
+ }
82
+ // Only activate if the focused element is actually interactive
83
+ if (!isInteractiveElement(target)) {
84
+ return;
85
+ }
86
+ const container = resolveContainerFromTarget(target);
87
+ // Only update if we found a new container
88
+ if (container) {
89
+ setActiveContainer(container);
90
+ }
91
+ };
92
+ /**
93
+ * Handle pointer/mouse events - only switch when clicking a different .field-type
94
+ */ const onPointerDown = (e)=>{
95
+ const target = e.target;
96
+ if (!(target instanceof HTMLElement)) {
97
+ return;
98
+ }
99
+ const container = resolveContainerFromTarget(target);
100
+ // Only update if we found a container (keeps last active if clicking elsewhere)
101
+ if (container) {
102
+ setActiveContainer(container);
103
+ }
104
+ };
105
+ /**
106
+ * Handle keyboard navigation (Tab key)
107
+ */ const onKeyDown = (e)=>{
108
+ if (e.key !== 'Tab') {
109
+ return;
110
+ }
111
+ requestAnimationFrame(()=>{
112
+ const container = resolveContainerFromTarget(document.activeElement);
113
+ setActiveContainer(container);
114
+ });
115
+ };
116
+ /**
117
+ * Initialize document-level listeners to track the active field container.
118
+ * When a container is active, it receives the 'ai-plugin-active' class.
119
+ */ export const useActiveFieldTracking = ()=>{
120
+ useEffect(()=>{
121
+ if (typeof window === 'undefined') {
122
+ return;
123
+ }
124
+ const pluginWindow = window;
125
+ // Track number of mounted users of the hook
126
+ pluginWindow.__aiComposeTrackingCount = (pluginWindow.__aiComposeTrackingCount ?? 0) + 1;
127
+ // Initialize listeners only once
128
+ if (!pluginWindow.__aiComposeTracking) {
129
+ document.addEventListener('focusin', onFocusIn, true);
130
+ document.addEventListener('pointerdown', onPointerDown, true);
131
+ document.addEventListener('keydown', onKeyDown, true);
132
+ pluginWindow.__aiComposeTracking = true;
133
+ }
134
+ return ()=>{
135
+ // Decrement and cleanup when the last user unmounts
136
+ pluginWindow.__aiComposeTrackingCount = (pluginWindow.__aiComposeTrackingCount ?? 1) - 1;
137
+ if ((pluginWindow.__aiComposeTrackingCount ?? 0) <= 0) {
138
+ document.removeEventListener('focusin', onFocusIn, true);
139
+ document.removeEventListener('pointerdown', onPointerDown, true);
140
+ document.removeEventListener('keydown', onKeyDown, true);
141
+ pluginWindow.__aiComposeTracking = false;
142
+ pluginWindow.__aiComposeTrackingCount = 0;
143
+ }
144
+ };
145
+ }, []);
146
+ };
147
+
148
+ //# sourceMappingURL=useActiveFieldTracking.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/ui/Compose/hooks/useActiveFieldTracking.ts"],"sourcesContent":["'use client'\n\nimport { useEffect } from 'react'\n\nlet currentContainer: HTMLElement | null = null\n\n/**\n * Safely escape CSS selector values\n */\nconst cssEscape = (value: string): string => {\n if (typeof CSS !== 'undefined' && typeof CSS.escape === 'function') {\n return CSS.escape(value)\n }\n return value.replace(/([ #;?%&,.+*~':\"!^$[\\]()=>|/@])/g, '\\\\$1')\n}\n\n/**\n * Find container from React Select dropdown elements\n */\nconst findContainerFromReactSelect = (target: HTMLElement): HTMLElement | null => {\n const listbox = target.closest<HTMLElement>('[role=\"listbox\"]')\n if (!listbox?.id) {\n return null\n }\n\n const id = cssEscape(listbox.id)\n const selector = `[aria-controls=\"${id}\"], [aria-owns=\"${id}\"]`\n const control = document.querySelector<HTMLElement>(selector)\n\n return control?.closest<HTMLElement>('.field-type') ?? null\n}\n\n/**\n * Resolve the .field-type container for a given event target\n */\nconst resolveContainerFromTarget = (target: EventTarget | null): HTMLElement | null => {\n if (!(target instanceof HTMLElement)) {\n return null\n }\n\n // Check for direct parent first\n const direct = target.closest<HTMLElement>('.field-type')\n if (direct) {\n return direct\n }\n\n // Fall back to React Select logic\n return findContainerFromReactSelect(target)\n}\n\n/**\n * Update the active container and toggle CSS class\n */\nconst setActiveContainer = (next: HTMLElement | null): void => {\n if (currentContainer === next) {\n return\n }\n\n currentContainer?.classList.remove('ai-plugin-active')\n next?.classList.add('ai-plugin-active')\n currentContainer = next\n}\n\nconst isInteractiveElement = (element: HTMLElement): boolean => {\n const tagName = element.tagName.toLowerCase()\n const interactiveTags = ['input', 'textarea', 'select', 'button']\n\n if (interactiveTags.includes(tagName)) {\n return true\n }\n\n // Check for contenteditable\n if (element.isContentEditable) {\n return true\n }\n\n // Check for elements with role=\"textbox\" or role=\"combobox\" (React Select)\n const role = element.getAttribute('role')\n if (role && ['combobox', 'listbox', 'searchbox', 'textbox'].includes(role)) {\n return true\n }\n\n return false\n}\n\n/**\n * Handle focus events - only activate if focus is on an interactive element within .field-type\n */\nconst onFocusIn = (e: FocusEvent): void => {\n const target = e.target\n if (!(target instanceof HTMLElement)) {\n return\n }\n\n // Only activate if the focused element is actually interactive\n if (!isInteractiveElement(target)) {\n return\n }\n\n const container = resolveContainerFromTarget(target)\n // Only update if we found a new container\n if (container) {\n setActiveContainer(container)\n }\n}\n\n/**\n * Handle pointer/mouse events - only switch when clicking a different .field-type\n */\nconst onPointerDown = (e: PointerEvent): void => {\n const target = e.target\n if (!(target instanceof HTMLElement)) {\n return\n }\n\n const container = resolveContainerFromTarget(target)\n\n // Only update if we found a container (keeps last active if clicking elsewhere)\n if (container) {\n setActiveContainer(container)\n }\n}\n\n/**\n * Handle keyboard navigation (Tab key)\n */\nconst onKeyDown = (e: KeyboardEvent): void => {\n if (e.key !== 'Tab') {\n return\n }\n\n requestAnimationFrame(() => {\n const container = resolveContainerFromTarget(document.activeElement)\n setActiveContainer(container)\n })\n}\n\n/**\n * Initialize document-level listeners to track the active field container.\n * When a container is active, it receives the 'ai-plugin-active' class.\n */\nexport const useActiveFieldTracking = (): void => {\n useEffect(() => {\n if (typeof window === 'undefined') {\n return\n }\n\n const pluginWindow = window as {\n __aiComposeTracking?: boolean\n __aiComposeTrackingCount?: number\n } & Window\n\n // Track number of mounted users of the hook\n pluginWindow.__aiComposeTrackingCount = (pluginWindow.__aiComposeTrackingCount ?? 0) + 1\n\n // Initialize listeners only once\n if (!pluginWindow.__aiComposeTracking) {\n document.addEventListener('focusin', onFocusIn, true)\n document.addEventListener('pointerdown', onPointerDown, true)\n document.addEventListener('keydown', onKeyDown, true)\n pluginWindow.__aiComposeTracking = true\n }\n\n return () => {\n // Decrement and cleanup when the last user unmounts\n pluginWindow.__aiComposeTrackingCount = (pluginWindow.__aiComposeTrackingCount ?? 1) - 1\n if ((pluginWindow.__aiComposeTrackingCount ?? 0) <= 0) {\n document.removeEventListener('focusin', onFocusIn, true)\n document.removeEventListener('pointerdown', onPointerDown, true)\n document.removeEventListener('keydown', onKeyDown, true)\n pluginWindow.__aiComposeTracking = false\n pluginWindow.__aiComposeTrackingCount = 0\n }\n }\n }, [])\n}\n"],"names":["useEffect","currentContainer","cssEscape","value","CSS","escape","replace","findContainerFromReactSelect","target","listbox","closest","id","selector","control","document","querySelector","resolveContainerFromTarget","HTMLElement","direct","setActiveContainer","next","classList","remove","add","isInteractiveElement","element","tagName","toLowerCase","interactiveTags","includes","isContentEditable","role","getAttribute","onFocusIn","e","container","onPointerDown","onKeyDown","key","requestAnimationFrame","activeElement","useActiveFieldTracking","window","pluginWindow","__aiComposeTrackingCount","__aiComposeTracking","addEventListener","removeEventListener"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { useCompletion, experimental_useObject as useObject } from '@ai-sdk/react';
1
+ import { experimental_useObject as useObject } from '@ai-sdk/react';
2
2
  import { useEditorConfigContext } from '@payloadcms/richtext-lexical/client';
3
3
  import { toast, useConfig, useDocumentInfo, useField, useForm, useLocale } from '@payloadcms/ui';
4
4
  import { jsonSchema } from 'ai';
@@ -6,6 +6,7 @@ import { useCallback, useEffect, useMemo, useRef } from 'react';
6
6
  import { PLUGIN_API_ENDPOINT_GENERATE, PLUGIN_API_ENDPOINT_GENERATE_UPLOAD, PLUGIN_INSTRUCTIONS_TABLE, PLUGIN_NAME } from '../../../defaults.js';
7
7
  import { useFieldProps } from '../../../providers/FieldProvider/useFieldProps.js';
8
8
  import { editorSchemaValidator } from '../../../utilities/editorSchemaValidator.js';
9
+ import { fieldToJsonSchema } from '../../../utilities/fieldToJsonSchema.js';
9
10
  import { setSafeLexicalState } from '../../../utilities/setSafeLexicalState.js';
10
11
  import { useHistory } from './useHistory.js';
11
12
  export const useGenerate = ({ instructionId })=>{
@@ -17,7 +18,7 @@ export const useGenerate = ({ instructionId })=>{
17
18
  }, [
18
19
  instructionId
19
20
  ]);
20
- const { type, path: pathFromContext } = useFieldProps();
21
+ const { field, path: pathFromContext } = useFieldProps();
21
22
  const editorConfigContext = useEditorConfigContext();
22
23
  const { editor } = editorConfigContext;
23
24
  const { config } = useConfig();
@@ -56,6 +57,24 @@ export const useGenerate = ({ instructionId })=>{
56
57
  }), [
57
58
  memoizedValidator
58
59
  ]);
60
+ // Active JSON schema for useObject based on field type
61
+ const activeSchema = useMemo(()=>{
62
+ const f = field;
63
+ const fieldType = f?.type;
64
+ if (fieldType === 'richText') {
65
+ return memoizedSchema;
66
+ }
67
+ if (f && f.name && fieldType) {
68
+ const schemaJson = fieldToJsonSchema(f);
69
+ if (schemaJson && Object.keys(schemaJson).length > 0) {
70
+ return jsonSchema(schemaJson);
71
+ }
72
+ }
73
+ return undefined;
74
+ }, [
75
+ field,
76
+ memoizedSchema
77
+ ]);
59
78
  const { isLoading: loadingObject, object, stop: objectStop, submit } = useObject({
60
79
  api: `/api${PLUGIN_API_ENDPOINT_GENERATE}`,
61
80
  onError: (error)=>{
@@ -63,50 +82,35 @@ export const useGenerate = ({ instructionId })=>{
63
82
  console.error('Error generating object:', error);
64
83
  },
65
84
  onFinish: (result)=>{
66
- if (result.object) {
67
- setHistory(result.object);
68
- setValue(result.object);
85
+ if (result.object && field) {
86
+ if (field.type === 'richText') {
87
+ setHistory(result.object);
88
+ setValue(result.object);
89
+ } else if ('name' in field) {
90
+ setHistory(result.object[field.name]);
91
+ setValue(result.object[field.name]);
92
+ }
69
93
  } else {
70
- console.log('onFinish: result ', result);
94
+ console.log('onFinish: result, field ', result, field);
71
95
  }
72
96
  },
73
- schema: memoizedSchema
97
+ schema: activeSchema
74
98
  });
75
99
  useEffect(()=>{
76
100
  if (!object) {
77
101
  return;
78
102
  }
79
103
  requestAnimationFrame(()=>{
80
- // TODO: Temporary disabled pre validation, sometimes it fails to validate
81
- // const validateObject = await memoizedSchema?.validate?.(object)
82
- // if (validateObject?.success) {
83
- setSafeLexicalState(object, editor);
84
- // }
104
+ if (field?.type === 'richText') {
105
+ setSafeLexicalState(object, editor);
106
+ } else if (field && 'name' in field && object[field.name]) {
107
+ setValue(object[field.name]);
108
+ }
85
109
  });
86
110
  }, [
87
111
  object,
88
- editor
89
- ]);
90
- const { complete, completion, isLoading: loadingCompletion, stop: completionStop } = useCompletion({
91
- api: `${serverURL}${api}${PLUGIN_API_ENDPOINT_GENERATE}`,
92
- onError: (error)=>{
93
- toast.error(`Failed to generate: ${error.message}`);
94
- console.error('Error generating text:', error);
95
- },
96
- onFinish: (prompt, result)=>{
97
- setHistory(result);
98
- },
99
- streamProtocol: 'data'
100
- });
101
- useEffect(()=>{
102
- if (!completion) {
103
- return;
104
- }
105
- requestAnimationFrame(()=>{
106
- setValue(completion);
107
- });
108
- }, [
109
- completion
112
+ editor,
113
+ field
110
114
  ]);
111
115
  const streamObject = useCallback(({ action = 'Compose', params })=>{
112
116
  const doc = getData();
@@ -130,31 +134,6 @@ export const useGenerate = ({ instructionId })=>{
130
134
  instructionIdRef,
131
135
  documentId
132
136
  ]);
133
- const streamText = useCallback(async ({ action = 'Compose', params })=>{
134
- const doc = getData();
135
- const currentInstructionId = instructionIdRef.current;
136
- const options = {
137
- action,
138
- actionParams: params,
139
- instructionId: currentInstructionId
140
- };
141
- await complete('', {
142
- body: {
143
- doc: {
144
- ...doc,
145
- id: documentId
146
- },
147
- locale: localFromContext?.code,
148
- options
149
- }
150
- });
151
- }, [
152
- getData,
153
- localFromContext?.code,
154
- instructionIdRef,
155
- complete,
156
- documentId
157
- ]);
158
137
  const generateUpload = useCallback(async ()=>{
159
138
  const doc = getData();
160
139
  const currentInstructionId = instructionIdRef.current;
@@ -201,39 +180,27 @@ export const useGenerate = ({ instructionId })=>{
201
180
  collectionSlug
202
181
  ]);
203
182
  const generate = useCallback(async (options)=>{
204
- if (type === 'richText') {
205
- return streamObject(options ?? {
206
- action: 'Compose'
207
- });
208
- }
209
- if ([
210
- 'text',
211
- 'textarea'
212
- ].includes(type ?? '') && type) {
213
- return streamText(options ?? {
214
- action: 'Compose'
215
- });
216
- }
217
- if (type === 'upload') {
183
+ if (field?.type === 'upload') {
218
184
  return generateUpload();
219
185
  }
186
+ // All supported types use structured object generation when schema is provided server-side
187
+ return streamObject(options ?? {
188
+ action: 'Compose'
189
+ });
220
190
  }, [
221
191
  generateUpload,
222
192
  streamObject,
223
- streamText,
224
- type
193
+ field
225
194
  ]);
226
195
  const stop = useCallback(()=>{
227
196
  console.log('Stopping...');
228
197
  objectStop();
229
- completionStop();
230
198
  }, [
231
- objectStop,
232
- completionStop
199
+ objectStop
233
200
  ]);
234
201
  return {
235
202
  generate,
236
- isLoading: loadingCompletion || loadingObject,
203
+ isLoading: loadingObject,
237
204
  stop
238
205
  };
239
206
  };
@@ -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
+ };