payload-intl 1.4.6 → 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.
@@ -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;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,YAAY,EACZ,IAAI,GACL,EAAE,oBAAoB,GAAG,kBAAkB,2CAgC3C"}
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"}
@@ -4,27 +4,59 @@ import { useField } from '@payloadcms/ui';
4
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
  });
14
- const lastPushedRef = useRef(value);
37
+ const lastSyncedRef = useRef(stableStringify(value));
15
38
  const form = useForm({
16
- values: value,
39
+ defaultValues: value ?? {},
17
40
  reValidateMode: 'onBlur'
18
41
  });
19
- // When form values change, push back to Payload's field.
20
- // Guard against the circular loop: Payload value useForm syncs → watch
21
- // fires → setValue → Payload value changes → repeat. Only call setValue
22
- // when the form produced genuinely new data.
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.
23
55
  useEffect(()=>{
24
56
  const subscription = form.watch((formValues)=>{
25
- const json = JSON.stringify(formValues);
26
- if (json !== JSON.stringify(lastPushedRef.current)) {
27
- lastPushedRef.current = formValues;
57
+ const serialized = stableStringify(formValues);
58
+ if (serialized !== lastSyncedRef.current) {
59
+ lastSyncedRef.current = serialized;
28
60
  setValue(formValues);
29
61
  }
30
62
  });
@@ -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, 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 * 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 const lastPushedRef = useRef(value);\n\n const form = useForm<Messages>({\n values: value,\n reValidateMode: 'onBlur',\n });\n\n // When form values change, push back to Payload's field.\n // Guard against the circular loop: Payload value useForm syncs watch\n // fires setValue Payload value changes repeat. Only call setValue\n // when the form produced genuinely new data.\n useEffect(() => {\n const subscription = form.watch((formValues) => {\n const json = JSON.stringify(formValues);\n if (json !== JSON.stringify(lastPushedRef.current)) {\n lastPushedRef.current = formValues as Messages;\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","MessagesField","schema","hiddenGroups","path","value","setValue","lastPushedRef","form","values","reValidateMode","subscription","watch","formValues","json","JSON","stringify","current","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;;;CAGC,GACD,OAAO,SAASC,cAAc,EAC5BC,MAAM,EACNC,YAAY,EACZC,IAAI,EACsC;IAC1C,MAAM,EAAEC,KAAK,EAAEC,QAAQ,EAAE,GAAGV,SAAmB;QAAEQ;IAAK;IACtD,MAAMG,gBAAgBT,OAAOO;IAE7B,MAAMG,OAAOT,QAAkB;QAC7BU,QAAQJ;QACRK,gBAAgB;IAClB;IAEA,yDAAyD;IACzD,yEAAyE;IACzE,wEAAwE;IACxE,6CAA6C;IAC7Cb,UAAU;QACR,MAAMc,eAAeH,KAAKI,KAAK,CAAC,CAACC;YAC/B,MAAMC,OAAOC,KAAKC,SAAS,CAACH;YAC5B,IAAIC,SAASC,KAAKC,SAAS,CAACT,cAAcU,OAAO,GAAG;gBAClDV,cAAcU,OAAO,GAAGJ;gBACxBP,SAASO;YACX;QACF;QACA,OAAO,IAAMF,aAAaO,WAAW;IACvC,GAAG;QAACV;QAAMF;KAAS;IAEnB,qBACE,KAACN;QACCmB,SAASX,KAAKW,OAAO;QACrBhB,cAAcA;QACdC,MAAK;QACLF,QAAQA;;AAGd"}
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"}
@@ -89,6 +89,7 @@ export function MessageInput({ value, variables, onChange, onBlur, multiline, er
89
89
  value: value
90
90
  }),
91
91
  /*#__PURE__*/ _jsx(OnChangePlugin, {
92
+ ignoreSelectionChange: true,
92
93
  onChange: handleChange
93
94
  }),
94
95
  /*#__PURE__*/ _jsx(HistoryPlugin, {}),
@@ -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":"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"}
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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "payload-intl",
3
- "version": "1.4.6",
3
+ "version": "1.4.7",
4
4
  "description": "Payload Plugin for I18N using ICU Messages",
5
5
  "keywords": [
6
6
  "payload",