payload-intl 1.4.5 → 1.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/MessagesField.d.ts +4 -0
- package/dist/components/MessagesField.d.ts.map +1 -1
- package/dist/components/MessagesField.js +44 -4
- package/dist/components/MessagesField.js.map +1 -1
- package/dist/components/input/MessageInput.js +1 -0
- package/dist/components/input/MessageInput.js.map +1 -1
- package/package.json +1 -1
|
@@ -7,6 +7,10 @@ export interface MessagesFieldProps {
|
|
|
7
7
|
/**
|
|
8
8
|
* Payload JSON field client component that bridges the virtual `_intlMessages`
|
|
9
9
|
* field with the existing MessagesFormProvider / MessagesTree component tree.
|
|
10
|
+
*
|
|
11
|
+
* Uses `defaultValues` (uncontrolled) instead of `values` (controlled) to
|
|
12
|
+
* prevent react-hook-form's automatic value sync from creating an infinite
|
|
13
|
+
* re-render loop with Payload's form state.
|
|
10
14
|
*/
|
|
11
15
|
export declare function MessagesField({ schema, hiddenGroups, path, }: JSONFieldClientProps & MessagesFieldProps): import("react/jsx-runtime").JSX.Element;
|
|
12
16
|
//# sourceMappingURL=MessagesField.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessagesField.d.ts","sourceRoot":"","sources":["../../src/components/MessagesField.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAGpD,OAAO,KAAK,EAAY,cAAc,EAAE,MAAM,SAAS,CAAC;AAGxD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CAClC;
|
|
1
|
+
{"version":3,"file":"MessagesField.d.ts","sourceRoot":"","sources":["../../src/components/MessagesField.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAGpD,OAAO,KAAK,EAAY,cAAc,EAAE,MAAM,SAAS,CAAC;AAGxD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CAClC;AAuBD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,YAAY,EACZ,IAAI,GACL,EAAE,oBAAoB,GAAG,kBAAkB,2CAuC3C"}
|
|
@@ -1,24 +1,64 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { useField } from '@payloadcms/ui';
|
|
4
|
-
import { useEffect } from 'react';
|
|
4
|
+
import { useEffect, useRef } from 'react';
|
|
5
5
|
import { useForm } from 'react-hook-form';
|
|
6
6
|
import { MessagesTree } from './layout/MessagesTree';
|
|
7
|
+
/**
|
|
8
|
+
* Order-independent JSON serialization that strips `undefined` values.
|
|
9
|
+
* Prevents false-positive mismatches caused by key insertion order
|
|
10
|
+
* differences between react-hook-form's internal state and the value
|
|
11
|
+
* returned by Payload's useField.
|
|
12
|
+
*/ function stableStringify(value) {
|
|
13
|
+
return JSON.stringify(value, (_key, val)=>{
|
|
14
|
+
if (val && typeof val === 'object' && !Array.isArray(val)) {
|
|
15
|
+
const sorted = {};
|
|
16
|
+
for (const k of Object.keys(val).sort()){
|
|
17
|
+
if (val[k] !== undefined) {
|
|
18
|
+
sorted[k] = val[k];
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return sorted;
|
|
22
|
+
}
|
|
23
|
+
return val;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
7
26
|
/**
|
|
8
27
|
* Payload JSON field client component that bridges the virtual `_intlMessages`
|
|
9
28
|
* field with the existing MessagesFormProvider / MessagesTree component tree.
|
|
29
|
+
*
|
|
30
|
+
* Uses `defaultValues` (uncontrolled) instead of `values` (controlled) to
|
|
31
|
+
* prevent react-hook-form's automatic value sync from creating an infinite
|
|
32
|
+
* re-render loop with Payload's form state.
|
|
10
33
|
*/ export function MessagesField({ schema, hiddenGroups, path }) {
|
|
11
34
|
const { value, setValue } = useField({
|
|
12
35
|
path
|
|
13
36
|
});
|
|
37
|
+
const lastSyncedRef = useRef(stableStringify(value));
|
|
14
38
|
const form = useForm({
|
|
15
|
-
|
|
39
|
+
defaultValues: value ?? {},
|
|
16
40
|
reValidateMode: 'onBlur'
|
|
17
41
|
});
|
|
18
|
-
//
|
|
42
|
+
// Payload → RHF: reset form only when value changes from an external source
|
|
43
|
+
// (locale switch, draft save, etc.), not from our own setValue echo.
|
|
44
|
+
useEffect(()=>{
|
|
45
|
+
const serialized = stableStringify(value);
|
|
46
|
+
if (serialized !== lastSyncedRef.current) {
|
|
47
|
+
lastSyncedRef.current = serialized;
|
|
48
|
+
form.reset(value ?? {});
|
|
49
|
+
}
|
|
50
|
+
}, [
|
|
51
|
+
value,
|
|
52
|
+
form
|
|
53
|
+
]);
|
|
54
|
+
// RHF → Payload: push user edits back to Payload's form state.
|
|
19
55
|
useEffect(()=>{
|
|
20
56
|
const subscription = form.watch((formValues)=>{
|
|
21
|
-
|
|
57
|
+
const serialized = stableStringify(formValues);
|
|
58
|
+
if (serialized !== lastSyncedRef.current) {
|
|
59
|
+
lastSyncedRef.current = serialized;
|
|
60
|
+
setValue(formValues);
|
|
61
|
+
}
|
|
22
62
|
});
|
|
23
63
|
return ()=>subscription.unsubscribe();
|
|
24
64
|
}, [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/MessagesField.tsx"],"sourcesContent":["'use client';\n\nimport { useField } from '@payloadcms/ui';\nimport type { JSONFieldClientProps } from 'payload';\nimport { useEffect } from 'react';\nimport { useForm } from 'react-hook-form';\nimport type { Messages, MessagesSchema } from '@/types';\nimport { MessagesTree } from './layout/MessagesTree';\n\nexport interface MessagesFieldProps {\n readonly schema: MessagesSchema;\n readonly hiddenGroups?: string[];\n}\n\n/**\n * Payload JSON field client component that bridges the virtual `_intlMessages`\n * field with the existing MessagesFormProvider / MessagesTree component tree.\n */\nexport function MessagesField({\n schema,\n hiddenGroups,\n path,\n}: JSONFieldClientProps & MessagesFieldProps) {\n const { value, setValue } = useField<Messages>({ path });\n\n const form = useForm<Messages>({\n
|
|
1
|
+
{"version":3,"sources":["../../src/components/MessagesField.tsx"],"sourcesContent":["'use client';\n\nimport { useField } from '@payloadcms/ui';\nimport type { JSONFieldClientProps } from 'payload';\nimport { useEffect, useRef } from 'react';\nimport { useForm } from 'react-hook-form';\nimport type { Messages, MessagesSchema } from '@/types';\nimport { MessagesTree } from './layout/MessagesTree';\n\nexport interface MessagesFieldProps {\n readonly schema: MessagesSchema;\n readonly hiddenGroups?: string[];\n}\n\n/**\n * Order-independent JSON serialization that strips `undefined` values.\n * Prevents false-positive mismatches caused by key insertion order\n * differences between react-hook-form's internal state and the value\n * returned by Payload's useField.\n */\nfunction stableStringify(value: unknown): string {\n return JSON.stringify(value, (_key, val: unknown) => {\n if (val && typeof val === 'object' && !Array.isArray(val)) {\n const sorted: Record<string, unknown> = {};\n for (const k of Object.keys(val as Record<string, unknown>).sort()) {\n if ((val as Record<string, unknown>)[k] !== undefined) {\n sorted[k] = (val as Record<string, unknown>)[k];\n }\n }\n return sorted;\n }\n return val;\n });\n}\n\n/**\n * Payload JSON field client component that bridges the virtual `_intlMessages`\n * field with the existing MessagesFormProvider / MessagesTree component tree.\n *\n * Uses `defaultValues` (uncontrolled) instead of `values` (controlled) to\n * prevent react-hook-form's automatic value sync from creating an infinite\n * re-render loop with Payload's form state.\n */\nexport function MessagesField({\n schema,\n hiddenGroups,\n path,\n}: JSONFieldClientProps & MessagesFieldProps) {\n const { value, setValue } = useField<Messages>({ path });\n const lastSyncedRef = useRef(stableStringify(value));\n\n const form = useForm<Messages>({\n defaultValues: value ?? {},\n reValidateMode: 'onBlur',\n });\n\n // Payload → RHF: reset form only when value changes from an external source\n // (locale switch, draft save, etc.), not from our own setValue echo.\n useEffect(() => {\n const serialized = stableStringify(value);\n if (serialized !== lastSyncedRef.current) {\n lastSyncedRef.current = serialized;\n form.reset(value ?? {});\n }\n }, [value, form]);\n\n // RHF → Payload: push user edits back to Payload's form state.\n useEffect(() => {\n const subscription = form.watch((formValues) => {\n const serialized = stableStringify(formValues);\n if (serialized !== lastSyncedRef.current) {\n lastSyncedRef.current = serialized;\n setValue(formValues);\n }\n });\n return () => subscription.unsubscribe();\n }, [form, setValue]);\n\n return (\n <MessagesTree\n control={form.control}\n hiddenGroups={hiddenGroups}\n path=\"\"\n schema={schema}\n />\n );\n}\n"],"names":["useField","useEffect","useRef","useForm","MessagesTree","stableStringify","value","JSON","stringify","_key","val","Array","isArray","sorted","k","Object","keys","sort","undefined","MessagesField","schema","hiddenGroups","path","setValue","lastSyncedRef","form","defaultValues","reValidateMode","serialized","current","reset","subscription","watch","formValues","unsubscribe","control"],"mappings":"AAAA;;AAEA,SAASA,QAAQ,QAAQ,iBAAiB;AAE1C,SAASC,SAAS,EAAEC,MAAM,QAAQ,QAAQ;AAC1C,SAASC,OAAO,QAAQ,kBAAkB;AAE1C,SAASC,YAAY,QAAQ,wBAAwB;AAOrD;;;;;CAKC,GACD,SAASC,gBAAgBC,KAAc;IACrC,OAAOC,KAAKC,SAAS,CAACF,OAAO,CAACG,MAAMC;QAClC,IAAIA,OAAO,OAAOA,QAAQ,YAAY,CAACC,MAAMC,OAAO,CAACF,MAAM;YACzD,MAAMG,SAAkC,CAAC;YACzC,KAAK,MAAMC,KAAKC,OAAOC,IAAI,CAACN,KAAgCO,IAAI,GAAI;gBAClE,IAAI,AAACP,GAA+B,CAACI,EAAE,KAAKI,WAAW;oBACrDL,MAAM,CAACC,EAAE,GAAG,AAACJ,GAA+B,CAACI,EAAE;gBACjD;YACF;YACA,OAAOD;QACT;QACA,OAAOH;IACT;AACF;AAEA;;;;;;;CAOC,GACD,OAAO,SAASS,cAAc,EAC5BC,MAAM,EACNC,YAAY,EACZC,IAAI,EACsC;IAC1C,MAAM,EAAEhB,KAAK,EAAEiB,QAAQ,EAAE,GAAGvB,SAAmB;QAAEsB;IAAK;IACtD,MAAME,gBAAgBtB,OAAOG,gBAAgBC;IAE7C,MAAMmB,OAAOtB,QAAkB;QAC7BuB,eAAepB,SAAS,CAAC;QACzBqB,gBAAgB;IAClB;IAEA,4EAA4E;IAC5E,qEAAqE;IACrE1B,UAAU;QACR,MAAM2B,aAAavB,gBAAgBC;QACnC,IAAIsB,eAAeJ,cAAcK,OAAO,EAAE;YACxCL,cAAcK,OAAO,GAAGD;YACxBH,KAAKK,KAAK,CAACxB,SAAS,CAAC;QACvB;IACF,GAAG;QAACA;QAAOmB;KAAK;IAEhB,+DAA+D;IAC/DxB,UAAU;QACR,MAAM8B,eAAeN,KAAKO,KAAK,CAAC,CAACC;YAC/B,MAAML,aAAavB,gBAAgB4B;YACnC,IAAIL,eAAeJ,cAAcK,OAAO,EAAE;gBACxCL,cAAcK,OAAO,GAAGD;gBACxBL,SAASU;YACX;QACF;QACA,OAAO,IAAMF,aAAaG,WAAW;IACvC,GAAG;QAACT;QAAMF;KAAS;IAEnB,qBACE,KAACnB;QACC+B,SAASV,KAAKU,OAAO;QACrBd,cAAcA;QACdC,MAAK;QACLF,QAAQA;;AAGd"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/input/MessageInput.tsx"],"sourcesContent":["'use client';\n\nimport type { EditorState } from '@payloadcms/richtext-lexical/lexical';\nimport { $getRoot } from '@payloadcms/richtext-lexical/lexical';\nimport { LexicalComposer } from '@payloadcms/richtext-lexical/lexical/react/LexicalComposer';\nimport { useLexicalComposerContext } from '@payloadcms/richtext-lexical/lexical/react/LexicalComposerContext';\nimport { ContentEditable } from '@payloadcms/richtext-lexical/lexical/react/LexicalContentEditable';\nimport { LexicalErrorBoundary } from '@payloadcms/richtext-lexical/lexical/react/LexicalErrorBoundary';\nimport { HistoryPlugin } from '@payloadcms/richtext-lexical/lexical/react/LexicalHistoryPlugin';\nimport { OnChangePlugin } from '@payloadcms/richtext-lexical/lexical/react/LexicalOnChangePlugin';\nimport { PlainTextPlugin } from '@payloadcms/richtext-lexical/lexical/react/LexicalPlainTextPlugin';\nimport {\n BeautifulMentionNode,\n BeautifulMentionsPlugin,\n} from 'lexical-beautiful-mentions';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { formatVariableLabel } from '@/components/input/utils';\nimport {\n isTagElement,\n parseIcuToLexicalState,\n serializeICUMessage,\n} from '@/icu';\nimport type { TemplateVariable } from '@/types';\n\nimport styles from './MessageInput.module.css';\nimport { SingleLinePlugin } from './SingleLinePlugin';\nimport { VariableMentionNode } from './variables/VariableNode';\nimport { MentionMenu, MentionMenuItem } from './variables/VariableSuggestion';\n\nfunction SyncValuePlugin({ value }: { value: string }) {\n const [editor] = useLexicalComposerContext();\n\n useEffect(() => {\n const currentText = editor\n .getEditorState()\n .read(() => $getRoot().getTextContent());\n if (value !== currentText) {\n queueMicrotask(() => {\n const newState = editor.parseEditorState(\n JSON.stringify(parseIcuToLexicalState(value)),\n );\n editor.setEditorState(newState);\n });\n }\n }, [value, editor]);\n\n return null;\n}\n\nexport interface MessageInputProps {\n value: string;\n variables: TemplateVariable[];\n onChange: (value: string) => void;\n onBlur: () => void;\n readOnly?: boolean;\n multiline?: boolean;\n error?: boolean;\n}\n\nexport function MessageInput({\n value,\n variables,\n onChange,\n onBlur,\n multiline,\n error,\n}: MessageInputProps) {\n const handleChange = useCallback(\n (editorState: EditorState) => {\n editorState.read(() => {\n onChange($getRoot().getTextContent());\n });\n },\n [onChange],\n );\n\n const mentionItems = useMemo(() => {\n const toItem = (v: TemplateVariable) => ({\n value: v.value,\n label: formatVariableLabel(v),\n icu: serializeICUMessage([v]),\n });\n\n return {\n '@': variables.map(toItem),\n '{': variables.filter((v) => !isTagElement(v)).map(toItem),\n '<': variables.filter((v) => isTagElement(v)).map(toItem),\n };\n }, [variables]);\n\n const [initialConfig] = useState(() => ({\n namespace: 'ICUMessageEditor',\n nodes: [\n VariableMentionNode,\n {\n replace: BeautifulMentionNode,\n with: (node: BeautifulMentionNode) =>\n new VariableMentionNode(\n node.getTrigger(),\n node.getValue(),\n node.getData(),\n ),\n withKlass: VariableMentionNode,\n },\n ],\n editorState: JSON.stringify(parseIcuToLexicalState(value)),\n editable: true,\n onError: console.error,\n }));\n\n return (\n <LexicalComposer initialConfig={initialConfig}>\n <div className={styles.editor} data-multiline={multiline}>\n <PlainTextPlugin\n contentEditable={\n <ContentEditable\n className={styles.contentEditable}\n data-error={error}\n onBlur={onBlur}\n />\n }\n ErrorBoundary={LexicalErrorBoundary}\n />\n {multiline && <SingleLinePlugin />}\n <SyncValuePlugin value={value} />\n <OnChangePlugin onChange={handleChange} />\n <HistoryPlugin />\n\n <BeautifulMentionsPlugin\n items={mentionItems}\n menuAnchorClassName={styles.menuAnchor}\n menuComponent={MentionMenu}\n menuItemComponent={MentionMenuItem}\n />\n </div>\n </LexicalComposer>\n );\n}\n"],"names":["$getRoot","LexicalComposer","useLexicalComposerContext","ContentEditable","LexicalErrorBoundary","HistoryPlugin","OnChangePlugin","PlainTextPlugin","BeautifulMentionNode","BeautifulMentionsPlugin","useCallback","useEffect","useMemo","useState","formatVariableLabel","isTagElement","parseIcuToLexicalState","serializeICUMessage","styles","SingleLinePlugin","VariableMentionNode","MentionMenu","MentionMenuItem","SyncValuePlugin","value","editor","currentText","getEditorState","read","getTextContent","queueMicrotask","newState","parseEditorState","JSON","stringify","setEditorState","MessageInput","variables","onChange","onBlur","multiline","error","handleChange","editorState","mentionItems","toItem","v","label","icu","map","filter","initialConfig","namespace","nodes","replace","with","node","getTrigger","getValue","getData","withKlass","editable","onError","console","div","className","data-multiline","contentEditable","data-error","ErrorBoundary","items","menuAnchorClassName","menuAnchor","menuComponent","menuItemComponent"],"mappings":"AAAA;;AAGA,SAASA,QAAQ,QAAQ,uCAAuC;AAChE,SAASC,eAAe,QAAQ,6DAA6D;AAC7F,SAASC,yBAAyB,QAAQ,oEAAoE;AAC9G,SAASC,eAAe,QAAQ,oEAAoE;AACpG,SAASC,oBAAoB,QAAQ,kEAAkE;AACvG,SAASC,aAAa,QAAQ,kEAAkE;AAChG,SAASC,cAAc,QAAQ,mEAAmE;AAClG,SAASC,eAAe,QAAQ,oEAAoE;AACpG,SACEC,oBAAoB,EACpBC,uBAAuB,QAClB,6BAA6B;AACpC,SAASC,WAAW,EAAEC,SAAS,EAAEC,OAAO,EAAEC,QAAQ,QAAQ,QAAQ;AAClE,SAASC,mBAAmB,QAAQ,2BAA2B;AAC/D,SACEC,YAAY,EACZC,sBAAsB,EACtBC,mBAAmB,QACd,QAAQ;AAGf,OAAOC,YAAY,4BAA4B;AAC/C,SAASC,gBAAgB,QAAQ,qBAAqB;AACtD,SAASC,mBAAmB,QAAQ,2BAA2B;AAC/D,SAASC,WAAW,EAAEC,eAAe,QAAQ,iCAAiC;AAE9E,SAASC,gBAAgB,EAAEC,KAAK,EAAqB;IACnD,MAAM,CAACC,OAAO,GAAGvB;IAEjBS,UAAU;QACR,MAAMe,cAAcD,OACjBE,cAAc,GACdC,IAAI,CAAC,IAAM5B,WAAW6B,cAAc;QACvC,IAAIL,UAAUE,aAAa;YACzBI,eAAe;gBACb,MAAMC,WAAWN,OAAOO,gBAAgB,CACtCC,KAAKC,SAAS,CAAClB,uBAAuBQ;gBAExCC,OAAOU,cAAc,CAACJ;YACxB;QACF;IACF,GAAG;QAACP;QAAOC;KAAO;IAElB,OAAO;AACT;AAYA,OAAO,SAASW,aAAa,EAC3BZ,KAAK,EACLa,SAAS,EACTC,QAAQ,EACRC,MAAM,EACNC,SAAS,EACTC,KAAK,EACa;IAClB,MAAMC,eAAehC,YACnB,CAACiC;QACCA,YAAYf,IAAI,CAAC;YACfU,SAAStC,WAAW6B,cAAc;QACpC;IACF,GACA;QAACS;KAAS;IAGZ,MAAMM,eAAehC,QAAQ;QAC3B,MAAMiC,SAAS,CAACC,IAAyB,CAAA;gBACvCtB,OAAOsB,EAAEtB,KAAK;gBACduB,OAAOjC,oBAAoBgC;gBAC3BE,KAAK/B,oBAAoB;oBAAC6B;iBAAE;YAC9B,CAAA;QAEA,OAAO;YACL,KAAKT,UAAUY,GAAG,CAACJ;YACnB,KAAKR,UAAUa,MAAM,CAAC,CAACJ,IAAM,CAAC/B,aAAa+B,IAAIG,GAAG,CAACJ;YACnD,KAAKR,UAAUa,MAAM,CAAC,CAACJ,IAAM/B,aAAa+B,IAAIG,GAAG,CAACJ;QACpD;IACF,GAAG;QAACR;KAAU;IAEd,MAAM,CAACc,cAAc,GAAGtC,SAAS,IAAO,CAAA;YACtCuC,WAAW;YACXC,OAAO;gBACLjC;gBACA;oBACEkC,SAAS9C;oBACT+C,MAAM,CAACC,OACL,IAAIpC,oBACFoC,KAAKC,UAAU,IACfD,KAAKE,QAAQ,IACbF,KAAKG,OAAO;oBAEhBC,WAAWxC;gBACb;aACD;YACDuB,aAAaV,KAAKC,SAAS,CAAClB,uBAAuBQ;YACnDqC,UAAU;YACVC,SAASC,QAAQtB,KAAK;QACxB,CAAA;IAEA,qBACE,KAACxC;QAAgBkD,eAAeA;kBAC9B,cAAA,MAACa;YAAIC,WAAW/C,OAAOO,MAAM;YAAEyC,kBAAgB1B;;8BAC7C,KAACjC;oBACC4D,+BACE,KAAChE;wBACC8D,WAAW/C,OAAOiD,eAAe;wBACjCC,cAAY3B;wBACZF,QAAQA;;oBAGZ8B,eAAejE;;gBAEhBoC,2BAAa,KAACrB;8BACf,KAACI;oBAAgBC,OAAOA;;8BACxB,KAAClB;
|
|
1
|
+
{"version":3,"sources":["../../../src/components/input/MessageInput.tsx"],"sourcesContent":["'use client';\n\nimport type { EditorState } from '@payloadcms/richtext-lexical/lexical';\nimport { $getRoot } from '@payloadcms/richtext-lexical/lexical';\nimport { LexicalComposer } from '@payloadcms/richtext-lexical/lexical/react/LexicalComposer';\nimport { useLexicalComposerContext } from '@payloadcms/richtext-lexical/lexical/react/LexicalComposerContext';\nimport { ContentEditable } from '@payloadcms/richtext-lexical/lexical/react/LexicalContentEditable';\nimport { LexicalErrorBoundary } from '@payloadcms/richtext-lexical/lexical/react/LexicalErrorBoundary';\nimport { HistoryPlugin } from '@payloadcms/richtext-lexical/lexical/react/LexicalHistoryPlugin';\nimport { OnChangePlugin } from '@payloadcms/richtext-lexical/lexical/react/LexicalOnChangePlugin';\nimport { PlainTextPlugin } from '@payloadcms/richtext-lexical/lexical/react/LexicalPlainTextPlugin';\nimport {\n BeautifulMentionNode,\n BeautifulMentionsPlugin,\n} from 'lexical-beautiful-mentions';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { formatVariableLabel } from '@/components/input/utils';\nimport {\n isTagElement,\n parseIcuToLexicalState,\n serializeICUMessage,\n} from '@/icu';\nimport type { TemplateVariable } from '@/types';\n\nimport styles from './MessageInput.module.css';\nimport { SingleLinePlugin } from './SingleLinePlugin';\nimport { VariableMentionNode } from './variables/VariableNode';\nimport { MentionMenu, MentionMenuItem } from './variables/VariableSuggestion';\n\nfunction SyncValuePlugin({ value }: { value: string }) {\n const [editor] = useLexicalComposerContext();\n\n useEffect(() => {\n const currentText = editor\n .getEditorState()\n .read(() => $getRoot().getTextContent());\n if (value !== currentText) {\n queueMicrotask(() => {\n const newState = editor.parseEditorState(\n JSON.stringify(parseIcuToLexicalState(value)),\n );\n editor.setEditorState(newState);\n });\n }\n }, [value, editor]);\n\n return null;\n}\n\nexport interface MessageInputProps {\n value: string;\n variables: TemplateVariable[];\n onChange: (value: string) => void;\n onBlur: () => void;\n readOnly?: boolean;\n multiline?: boolean;\n error?: boolean;\n}\n\nexport function MessageInput({\n value,\n variables,\n onChange,\n onBlur,\n multiline,\n error,\n}: MessageInputProps) {\n const handleChange = useCallback(\n (editorState: EditorState) => {\n editorState.read(() => {\n onChange($getRoot().getTextContent());\n });\n },\n [onChange],\n );\n\n const mentionItems = useMemo(() => {\n const toItem = (v: TemplateVariable) => ({\n value: v.value,\n label: formatVariableLabel(v),\n icu: serializeICUMessage([v]),\n });\n\n return {\n '@': variables.map(toItem),\n '{': variables.filter((v) => !isTagElement(v)).map(toItem),\n '<': variables.filter((v) => isTagElement(v)).map(toItem),\n };\n }, [variables]);\n\n const [initialConfig] = useState(() => ({\n namespace: 'ICUMessageEditor',\n nodes: [\n VariableMentionNode,\n {\n replace: BeautifulMentionNode,\n with: (node: BeautifulMentionNode) =>\n new VariableMentionNode(\n node.getTrigger(),\n node.getValue(),\n node.getData(),\n ),\n withKlass: VariableMentionNode,\n },\n ],\n editorState: JSON.stringify(parseIcuToLexicalState(value)),\n editable: true,\n onError: console.error,\n }));\n\n return (\n <LexicalComposer initialConfig={initialConfig}>\n <div className={styles.editor} data-multiline={multiline}>\n <PlainTextPlugin\n contentEditable={\n <ContentEditable\n className={styles.contentEditable}\n data-error={error}\n onBlur={onBlur}\n />\n }\n ErrorBoundary={LexicalErrorBoundary}\n />\n {multiline && <SingleLinePlugin />}\n <SyncValuePlugin value={value} />\n <OnChangePlugin ignoreSelectionChange onChange={handleChange} />\n <HistoryPlugin />\n\n <BeautifulMentionsPlugin\n items={mentionItems}\n menuAnchorClassName={styles.menuAnchor}\n menuComponent={MentionMenu}\n menuItemComponent={MentionMenuItem}\n />\n </div>\n </LexicalComposer>\n );\n}\n"],"names":["$getRoot","LexicalComposer","useLexicalComposerContext","ContentEditable","LexicalErrorBoundary","HistoryPlugin","OnChangePlugin","PlainTextPlugin","BeautifulMentionNode","BeautifulMentionsPlugin","useCallback","useEffect","useMemo","useState","formatVariableLabel","isTagElement","parseIcuToLexicalState","serializeICUMessage","styles","SingleLinePlugin","VariableMentionNode","MentionMenu","MentionMenuItem","SyncValuePlugin","value","editor","currentText","getEditorState","read","getTextContent","queueMicrotask","newState","parseEditorState","JSON","stringify","setEditorState","MessageInput","variables","onChange","onBlur","multiline","error","handleChange","editorState","mentionItems","toItem","v","label","icu","map","filter","initialConfig","namespace","nodes","replace","with","node","getTrigger","getValue","getData","withKlass","editable","onError","console","div","className","data-multiline","contentEditable","data-error","ErrorBoundary","ignoreSelectionChange","items","menuAnchorClassName","menuAnchor","menuComponent","menuItemComponent"],"mappings":"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"}
|