payload-intl 1.2.1 → 1.2.3

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 (164) hide show
  1. package/LICENSE +21 -0
  2. package/dist/components/MessageFormField.d.ts +15 -0
  3. package/dist/components/MessageFormField.d.ts.map +1 -0
  4. package/dist/components/{MessageController.js → MessageFormField.js} +5 -3
  5. package/dist/components/MessageFormField.js.map +1 -0
  6. package/dist/components/MessagesForm.d.ts +3 -1
  7. package/dist/components/MessagesForm.d.ts.map +1 -1
  8. package/dist/components/MessagesForm.js +25 -36
  9. package/dist/components/MessagesForm.js.map +1 -1
  10. package/dist/components/{MessageFormContext.d.ts → MessagesFormProvider.d.ts} +6 -2
  11. package/dist/components/MessagesFormProvider.d.ts.map +1 -0
  12. package/dist/components/{MessageFormContext.js → MessagesFormProvider.js} +8 -4
  13. package/dist/components/MessagesFormProvider.js.map +1 -0
  14. package/dist/components/MessagesLink.js +5 -2
  15. package/dist/components/MessagesLink.js.map +1 -1
  16. package/dist/components/MessagesView.d.ts +1 -1
  17. package/dist/components/MessagesView.d.ts.map +1 -1
  18. package/dist/components/MessagesView.js +13 -4
  19. package/dist/components/MessagesView.js.map +1 -1
  20. package/dist/components/actions/CopyMessages.d.ts +2 -0
  21. package/dist/components/actions/CopyMessages.d.ts.map +1 -0
  22. package/dist/components/actions/{Move.js → CopyMessages.js} +6 -6
  23. package/dist/components/actions/CopyMessages.js.map +1 -0
  24. package/dist/components/actions/JsonImport.d.ts +4 -1
  25. package/dist/components/actions/JsonImport.d.ts.map +1 -1
  26. package/dist/components/actions/JsonImport.js +7 -25
  27. package/dist/components/actions/JsonImport.js.map +1 -1
  28. package/dist/components/hooks/useHtmlLexicalAdapter.d.ts +12 -0
  29. package/dist/components/hooks/useHtmlLexicalAdapter.d.ts.map +1 -0
  30. package/dist/components/hooks/useHtmlLexicalAdapter.js +63 -0
  31. package/dist/components/hooks/useHtmlLexicalAdapter.js.map +1 -0
  32. package/dist/components/hooks/useMessagesFormSubmit.d.ts +11 -0
  33. package/dist/components/hooks/useMessagesFormSubmit.d.ts.map +1 -0
  34. package/dist/components/hooks/useMessagesFormSubmit.js +44 -0
  35. package/dist/components/hooks/useMessagesFormSubmit.js.map +1 -0
  36. package/dist/components/inputs/FieldWrapper.d.ts +9 -0
  37. package/dist/components/inputs/FieldWrapper.d.ts.map +1 -0
  38. package/dist/components/inputs/FieldWrapper.js +24 -0
  39. package/dist/components/inputs/FieldWrapper.js.map +1 -0
  40. package/dist/components/inputs/{InputWrapper.module.css → FieldWrapper.module.css} +2 -12
  41. package/dist/components/inputs/LexicalInput.d.ts +2 -13
  42. package/dist/components/inputs/LexicalInput.d.ts.map +1 -1
  43. package/dist/components/inputs/LexicalInput.js +4 -63
  44. package/dist/components/inputs/LexicalInput.js.map +1 -1
  45. package/dist/components/inputs/MessageInput.d.ts +6 -3
  46. package/dist/components/inputs/MessageInput.d.ts.map +1 -1
  47. package/dist/components/inputs/MessageInput.js +47 -43
  48. package/dist/components/inputs/MessageInput.js.map +1 -1
  49. package/dist/components/inputs/MessageInput.module.css +23 -4
  50. package/dist/components/inputs/ReferencePopover.d.ts +7 -0
  51. package/dist/components/inputs/ReferencePopover.d.ts.map +1 -0
  52. package/dist/components/inputs/ReferencePopover.js +42 -0
  53. package/dist/components/inputs/ReferencePopover.js.map +1 -0
  54. package/dist/components/inputs/ReferencePopover.module.css +70 -0
  55. package/dist/components/inputs/SingleLinePlugin.d.ts +2 -0
  56. package/dist/components/inputs/SingleLinePlugin.d.ts.map +1 -0
  57. package/dist/components/inputs/SingleLinePlugin.js +24 -0
  58. package/dist/components/inputs/SingleLinePlugin.js.map +1 -0
  59. package/dist/components/inputs/variables/VariableChip.d.ts.map +1 -1
  60. package/dist/components/inputs/variables/VariableChip.js +31 -32
  61. package/dist/components/inputs/variables/VariableChip.js.map +1 -1
  62. package/dist/components/inputs/variables/VariableChip.module.css +3 -3
  63. package/dist/components/inputs/variables/VariableSuggestion.d.ts +4 -0
  64. package/dist/components/inputs/variables/VariableSuggestion.d.ts.map +1 -0
  65. package/dist/components/inputs/variables/VariableSuggestion.js +24 -0
  66. package/dist/components/inputs/variables/VariableSuggestion.js.map +1 -0
  67. package/dist/components/inputs/variables/editors/PluralVariableEditor.d.ts.map +1 -1
  68. package/dist/components/inputs/variables/editors/PluralVariableEditor.js +62 -60
  69. package/dist/components/inputs/variables/editors/PluralVariableEditor.js.map +1 -1
  70. package/dist/components/inputs/variables/editors/PluralVariableEditor.module.css +4 -4
  71. package/dist/components/inputs/variables/editors/TemporalVariableEditor.d.ts +11 -0
  72. package/dist/components/inputs/variables/editors/TemporalVariableEditor.d.ts.map +1 -0
  73. package/dist/components/inputs/variables/editors/{DateVariableEditor.js → TemporalVariableEditor.js} +3 -3
  74. package/dist/components/inputs/variables/editors/TemporalVariableEditor.js.map +1 -0
  75. package/dist/components/inputs/variables/pickers/NumericVariableEditor.d.ts +7 -0
  76. package/dist/components/inputs/variables/pickers/{NumericVariablePicker.d.ts.map → NumericVariableEditor.d.ts.map} +1 -1
  77. package/dist/components/inputs/variables/pickers/{NumericVariablePicker.js → NumericVariableEditor.js} +15 -9
  78. package/dist/components/inputs/variables/pickers/NumericVariableEditor.js.map +1 -0
  79. package/dist/components/inputs/variables/pickers/{NumericVariablePicker.module.css → NumericVariableEditor.module.css} +3 -3
  80. package/dist/components/inputs/variables/pickers/TemporalVariablePicker.d.ts +7 -0
  81. package/dist/components/inputs/variables/pickers/TemporalVariablePicker.d.ts.map +1 -0
  82. package/dist/components/inputs/variables/pickers/TemporalVariablePicker.js +57 -0
  83. package/dist/components/inputs/variables/pickers/TemporalVariablePicker.js.map +1 -0
  84. package/dist/components/inputs/variables/pickers/{TemporalElementEditor.module.css → TemporalVariablePicker.module.css} +3 -3
  85. package/dist/components/layout/GroupStatusDot.d.ts +6 -0
  86. package/dist/components/layout/GroupStatusDot.d.ts.map +1 -0
  87. package/dist/components/layout/GroupStatusDot.js +24 -0
  88. package/dist/components/layout/GroupStatusDot.js.map +1 -0
  89. package/dist/components/layout/MessageField.d.ts +2 -1
  90. package/dist/components/layout/MessageField.d.ts.map +1 -1
  91. package/dist/components/layout/MessageField.js +52 -33
  92. package/dist/components/layout/MessageField.js.map +1 -1
  93. package/dist/components/layout/MessageField.module.css +21 -10
  94. package/dist/components/layout/MessagesTabs.d.ts.map +1 -1
  95. package/dist/components/layout/MessagesTabs.js +3 -5
  96. package/dist/components/layout/MessagesTabs.js.map +1 -1
  97. package/dist/components/layout/MessagesTree.d.ts +1 -1
  98. package/dist/components/layout/MessagesTree.d.ts.map +1 -1
  99. package/dist/components/layout/MessagesTree.js +33 -43
  100. package/dist/components/layout/MessagesTree.js.map +1 -1
  101. package/dist/components/layout/MessagesTree.module.css +10 -5
  102. package/dist/components/layout/StatusDot.d.ts +7 -0
  103. package/dist/components/layout/StatusDot.d.ts.map +1 -0
  104. package/dist/components/layout/StatusDot.js +12 -0
  105. package/dist/components/layout/StatusDot.js.map +1 -0
  106. package/dist/components/layout/StatusDot.module.css +16 -0
  107. package/dist/const.d.ts +2 -2
  108. package/dist/const.js +1 -1
  109. package/dist/entities.js +1 -1
  110. package/dist/internals/index.d.ts.map +1 -0
  111. package/dist/internals/index.js.map +1 -0
  112. package/dist/internals/procedure.d.ts.map +1 -0
  113. package/dist/internals/procedure.js.map +1 -0
  114. package/dist/internals/urls.d.ts.map +1 -0
  115. package/dist/internals/urls.js.map +1 -0
  116. package/dist/internals/utils.d.ts.map +1 -0
  117. package/dist/internals/utils.js.map +1 -0
  118. package/dist/utils/sanitize.d.ts +7 -6
  119. package/dist/utils/sanitize.d.ts.map +1 -1
  120. package/dist/utils/sanitize.js +11 -8
  121. package/dist/utils/sanitize.js.map +1 -1
  122. package/package.json +29 -28
  123. package/dist/_common/index.d.ts.map +0 -1
  124. package/dist/_common/index.js.map +0 -1
  125. package/dist/_common/procedure.d.ts.map +0 -1
  126. package/dist/_common/procedure.js.map +0 -1
  127. package/dist/_common/urls.d.ts.map +0 -1
  128. package/dist/_common/urls.js.map +0 -1
  129. package/dist/_common/utils.d.ts.map +0 -1
  130. package/dist/_common/utils.js.map +0 -1
  131. package/dist/components/MessageController.d.ts +0 -13
  132. package/dist/components/MessageController.d.ts.map +0 -1
  133. package/dist/components/MessageController.js.map +0 -1
  134. package/dist/components/MessageFormContext.d.ts.map +0 -1
  135. package/dist/components/MessageFormContext.js.map +0 -1
  136. package/dist/components/actions/Move.d.ts +0 -2
  137. package/dist/components/actions/Move.d.ts.map +0 -1
  138. package/dist/components/actions/Move.js.map +0 -1
  139. package/dist/components/inputs/InputWrapper.d.ts +0 -8
  140. package/dist/components/inputs/InputWrapper.d.ts.map +0 -1
  141. package/dist/components/inputs/InputWrapper.js +0 -34
  142. package/dist/components/inputs/InputWrapper.js.map +0 -1
  143. package/dist/components/inputs/variables/editors/DateVariableEditor.d.ts +0 -10
  144. package/dist/components/inputs/variables/editors/DateVariableEditor.d.ts.map +0 -1
  145. package/dist/components/inputs/variables/editors/DateVariableEditor.js.map +0 -1
  146. package/dist/components/inputs/variables/editors/TimeVariableEditor.d.ts +0 -10
  147. package/dist/components/inputs/variables/editors/TimeVariableEditor.d.ts.map +0 -1
  148. package/dist/components/inputs/variables/editors/TimeVariableEditor.js +0 -15
  149. package/dist/components/inputs/variables/editors/TimeVariableEditor.js.map +0 -1
  150. package/dist/components/inputs/variables/pickers/NumericVariablePicker.d.ts +0 -7
  151. package/dist/components/inputs/variables/pickers/NumericVariablePicker.js.map +0 -1
  152. package/dist/components/inputs/variables/pickers/TemporalElementEditor.d.ts +0 -7
  153. package/dist/components/inputs/variables/pickers/TemporalElementEditor.d.ts.map +0 -1
  154. package/dist/components/inputs/variables/pickers/TemporalElementEditor.js +0 -58
  155. package/dist/components/inputs/variables/pickers/TemporalElementEditor.js.map +0 -1
  156. /package/dist/components/actions/{Move.module.css → CopyMessages.module.css} +0 -0
  157. /package/dist/{_common → internals}/index.d.ts +0 -0
  158. /package/dist/{_common → internals}/index.js +0 -0
  159. /package/dist/{_common → internals}/procedure.d.ts +0 -0
  160. /package/dist/{_common → internals}/procedure.js +0 -0
  161. /package/dist/{_common → internals}/urls.d.ts +0 -0
  162. /package/dist/{_common → internals}/urls.js +0 -0
  163. /package/dist/{_common → internals}/utils.d.ts +0 -0
  164. /package/dist/{_common → internals}/utils.js +0 -0
@@ -0,0 +1,63 @@
1
+ import { defaultEditorConfig, defaultEditorFeatures } from '@payloadcms/richtext-lexical';
2
+ import { buildDefaultEditorState, getEnabledNodes, sanitizeClientEditorConfig } from '@payloadcms/richtext-lexical/client';
3
+ import { $getRoot } from '@payloadcms/richtext-lexical/lexical';
4
+ import { createHeadlessEditor } from '@payloadcms/richtext-lexical/lexical/headless';
5
+ import { $generateHtmlFromNodes, $generateNodesFromDOM } from '@payloadcms/richtext-lexical/lexical/html';
6
+ import { useCallback, useMemo, useRef } from 'react';
7
+ const EMPTY_STATE = buildDefaultEditorState({});
8
+ export function useHtmlLexicalAdapter({ html, onChange }) {
9
+ // 1. Maintain a persistent headless editor for conversion
10
+ const headlessEditor = useRef(createHeadlessEditor({
11
+ nodes: getEnabledNodes({
12
+ editorConfig: sanitizeClientEditorConfig(// @ts-expect-error - FIXME
13
+ defaultEditorFeatures, defaultEditorConfig)
14
+ })
15
+ }));
16
+ // 2. HTML -> SerializedState
17
+ const getSerializedState = useCallback((htmlString)=>{
18
+ const editor = headlessEditor.current;
19
+ editor.update(()=>{
20
+ const parser = new DOMParser();
21
+ const dom = parser.parseFromString(htmlString, 'text/html');
22
+ const nodes = $generateNodesFromDOM(editor, dom);
23
+ const root = $getRoot();
24
+ root.clear().append(...nodes);
25
+ }, {
26
+ discrete: true
27
+ });
28
+ return editor.getEditorState().toJSON();
29
+ }, []);
30
+ // 3. Memoize the initial value to prevent unnecessary re-renders
31
+ const value = useMemo(()=>{
32
+ const serializedState = getSerializedState(html);
33
+ if (serializedState.root.children.length === 0) {
34
+ return EMPTY_STATE;
35
+ }
36
+ return serializedState;
37
+ }, [
38
+ html,
39
+ getSerializedState
40
+ ]);
41
+ // 4. SerializedState -> HTML
42
+ const setValue = useCallback((serializedState)=>{
43
+ const editor = headlessEditor.current;
44
+ // Update headless editor to match the incoming state
45
+ editor.setEditorState(editor.parseEditorState(serializedState));
46
+ // Generate HTML and broadcast if it has changed
47
+ editor.read(()=>{
48
+ const newHtml = $generateHtmlFromNodes(editor);
49
+ if (newHtml !== html) {
50
+ onChange(newHtml);
51
+ }
52
+ });
53
+ }, [
54
+ html,
55
+ onChange
56
+ ]);
57
+ return {
58
+ value: value,
59
+ setValue
60
+ };
61
+ }
62
+
63
+ //# sourceMappingURL=useHtmlLexicalAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/hooks/useHtmlLexicalAdapter.ts"],"sourcesContent":["import type {\n DefaultNodeTypes,\n TypedEditorState,\n} from '@payloadcms/richtext-lexical';\nimport {\n defaultEditorConfig,\n defaultEditorFeatures,\n} from '@payloadcms/richtext-lexical';\nimport {\n buildDefaultEditorState,\n getEnabledNodes,\n sanitizeClientEditorConfig,\n} from '@payloadcms/richtext-lexical/client';\nimport type { SerializedEditorState } from '@payloadcms/richtext-lexical/lexical';\nimport { $getRoot } from '@payloadcms/richtext-lexical/lexical';\nimport { createHeadlessEditor } from '@payloadcms/richtext-lexical/lexical/headless';\nimport {\n $generateHtmlFromNodes,\n $generateNodesFromDOM,\n} from '@payloadcms/richtext-lexical/lexical/html';\nimport { useCallback, useMemo, useRef } from 'react';\n\nconst EMPTY_STATE = buildDefaultEditorState({});\n\ninterface UseHtmlLexicalAdapterProps {\n html: string;\n onChange: (html: string) => void;\n}\n\nexport function useHtmlLexicalAdapter({\n html,\n onChange,\n}: UseHtmlLexicalAdapterProps) {\n // 1. Maintain a persistent headless editor for conversion\n const headlessEditor = useRef(\n createHeadlessEditor({\n nodes: getEnabledNodes({\n editorConfig: sanitizeClientEditorConfig(\n // @ts-expect-error - FIXME\n defaultEditorFeatures,\n defaultEditorConfig,\n ),\n }),\n }),\n );\n\n // 2. HTML -> SerializedState\n const getSerializedState = useCallback(\n (htmlString: string): SerializedEditorState => {\n const editor = headlessEditor.current;\n editor.update(\n () => {\n const parser = new DOMParser();\n const dom = parser.parseFromString(htmlString, 'text/html');\n const nodes = $generateNodesFromDOM(editor, dom);\n\n const root = $getRoot();\n root.clear().append(...nodes);\n },\n { discrete: true },\n );\n\n return editor.getEditorState().toJSON();\n },\n [],\n );\n\n // 3. Memoize the initial value to prevent unnecessary re-renders\n const value = useMemo(() => {\n const serializedState = getSerializedState(html);\n\n if (serializedState.root.children.length === 0) {\n return EMPTY_STATE;\n }\n\n return serializedState;\n }, [html, getSerializedState]);\n\n // 4. SerializedState -> HTML\n const setValue = useCallback(\n (serializedState: SerializedEditorState) => {\n const editor = headlessEditor.current;\n\n // Update headless editor to match the incoming state\n editor.setEditorState(editor.parseEditorState(serializedState));\n\n // Generate HTML and broadcast if it has changed\n editor.read(() => {\n const newHtml = $generateHtmlFromNodes(editor);\n if (newHtml !== html) {\n onChange(newHtml);\n }\n });\n },\n [html, onChange],\n );\n\n return { value: value as TypedEditorState<DefaultNodeTypes>, setValue };\n}\n"],"names":["defaultEditorConfig","defaultEditorFeatures","buildDefaultEditorState","getEnabledNodes","sanitizeClientEditorConfig","$getRoot","createHeadlessEditor","$generateHtmlFromNodes","$generateNodesFromDOM","useCallback","useMemo","useRef","EMPTY_STATE","useHtmlLexicalAdapter","html","onChange","headlessEditor","nodes","editorConfig","getSerializedState","htmlString","editor","current","update","parser","DOMParser","dom","parseFromString","root","clear","append","discrete","getEditorState","toJSON","value","serializedState","children","length","setValue","setEditorState","parseEditorState","read","newHtml"],"mappings":"AAIA,SACEA,mBAAmB,EACnBC,qBAAqB,QAChB,+BAA+B;AACtC,SACEC,uBAAuB,EACvBC,eAAe,EACfC,0BAA0B,QACrB,sCAAsC;AAE7C,SAASC,QAAQ,QAAQ,uCAAuC;AAChE,SAASC,oBAAoB,QAAQ,gDAAgD;AACrF,SACEC,sBAAsB,EACtBC,qBAAqB,QAChB,4CAA4C;AACnD,SAASC,WAAW,EAAEC,OAAO,EAAEC,MAAM,QAAQ,QAAQ;AAErD,MAAMC,cAAcV,wBAAwB,CAAC;AAO7C,OAAO,SAASW,sBAAsB,EACpCC,IAAI,EACJC,QAAQ,EACmB;IAC3B,0DAA0D;IAC1D,MAAMC,iBAAiBL,OACrBL,qBAAqB;QACnBW,OAAOd,gBAAgB;YACrBe,cAAcd,2BACZ,2BAA2B;YAC3BH,uBACAD;QAEJ;IACF;IAGF,6BAA6B;IAC7B,MAAMmB,qBAAqBV,YACzB,CAACW;QACC,MAAMC,SAASL,eAAeM,OAAO;QACrCD,OAAOE,MAAM,CACX;YACE,MAAMC,SAAS,IAAIC;YACnB,MAAMC,MAAMF,OAAOG,eAAe,CAACP,YAAY;YAC/C,MAAMH,QAAQT,sBAAsBa,QAAQK;YAE5C,MAAME,OAAOvB;YACbuB,KAAKC,KAAK,GAAGC,MAAM,IAAIb;QACzB,GACA;YAAEc,UAAU;QAAK;QAGnB,OAAOV,OAAOW,cAAc,GAAGC,MAAM;IACvC,GACA,EAAE;IAGJ,iEAAiE;IACjE,MAAMC,QAAQxB,QAAQ;QACpB,MAAMyB,kBAAkBhB,mBAAmBL;QAE3C,IAAIqB,gBAAgBP,IAAI,CAACQ,QAAQ,CAACC,MAAM,KAAK,GAAG;YAC9C,OAAOzB;QACT;QAEA,OAAOuB;IACT,GAAG;QAACrB;QAAMK;KAAmB;IAE7B,6BAA6B;IAC7B,MAAMmB,WAAW7B,YACf,CAAC0B;QACC,MAAMd,SAASL,eAAeM,OAAO;QAErC,qDAAqD;QACrDD,OAAOkB,cAAc,CAAClB,OAAOmB,gBAAgB,CAACL;QAE9C,gDAAgD;QAChDd,OAAOoB,IAAI,CAAC;YACV,MAAMC,UAAUnC,uBAAuBc;YACvC,IAAIqB,YAAY5B,MAAM;gBACpBC,SAAS2B;YACX;QACF;IACF,GACA;QAAC5B;QAAMC;KAAS;IAGlB,OAAO;QAAEmB,OAAOA;QAA6CI;IAAS;AACxE"}
@@ -0,0 +1,11 @@
1
+ import type { UseFormReturn } from 'react-hook-form';
2
+ import type { FormValues } from '../../components/MessagesFormProvider';
3
+ import type { DeepPartial, Messages, Translations } from '../../types';
4
+ interface UseMessagesFormSubmitOptions {
5
+ endpointUrl: string;
6
+ defaultValues: Translations<DeepPartial<Messages>>;
7
+ form: UseFormReturn<FormValues>;
8
+ }
9
+ export declare function useMessagesFormSubmit({ endpointUrl, defaultValues, form, }: UseMessagesFormSubmitOptions): (currentValues: FormValues) => Promise<void>;
10
+ export {};
11
+ //# sourceMappingURL=useMessagesFormSubmit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMessagesFormSubmit.d.ts","sourceRoot":"","sources":["../../../src/components/hooks/useMessagesFormSubmit.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAGnE,UAAU,4BAA4B;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,YAAY,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC;IACnD,IAAI,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;CACjC;AAED,wBAAgB,qBAAqB,CAAC,EACpC,WAAW,EACX,aAAa,EACb,IAAI,GACL,EAAE,4BAA4B,mBAGc,UAAU,mBAyCtD"}
@@ -0,0 +1,44 @@
1
+ import { toast, useDocumentEvents } from '@payloadcms/ui';
2
+ import { isEqual } from 'lodash-es';
3
+ import { getErrorMessage } from '../../utils/error-handling';
4
+ export function useMessagesFormSubmit({ endpointUrl, defaultValues, form }) {
5
+ const { reportUpdate } = useDocumentEvents();
6
+ const handleSubmit = async (currentValues)=>{
7
+ const toastId = toast.loading('Saving...');
8
+ const changes = Object.entries(currentValues).reduce((acc, [locale, value])=>{
9
+ const hasChanged = !isEqual(value, defaultValues[locale]);
10
+ if (!hasChanged) return acc;
11
+ acc[locale] = value;
12
+ return acc;
13
+ }, {});
14
+ try {
15
+ const response = await fetch(endpointUrl, {
16
+ method: 'PUT',
17
+ headers: {
18
+ 'Content-Type': 'application/json'
19
+ },
20
+ body: JSON.stringify(changes)
21
+ });
22
+ if (!response.ok) {
23
+ const error = await getErrorMessage(response);
24
+ throw new Error(error);
25
+ }
26
+ form.reset(currentValues);
27
+ reportUpdate({
28
+ entitySlug: 'messages',
29
+ operation: 'update',
30
+ updatedAt: new Date().toISOString()
31
+ });
32
+ toast.success('Saved', {
33
+ id: toastId
34
+ });
35
+ } catch (error) {
36
+ toast.error(`Failed to save: ${error instanceof Error ? error.message : 'Unknown error'}`, {
37
+ id: toastId
38
+ });
39
+ }
40
+ };
41
+ return handleSubmit;
42
+ }
43
+
44
+ //# sourceMappingURL=useMessagesFormSubmit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/hooks/useMessagesFormSubmit.ts"],"sourcesContent":["import { toast, useDocumentEvents } from '@payloadcms/ui';\nimport { isEqual } from 'lodash-es';\nimport type { UseFormReturn } from 'react-hook-form';\nimport type { FormValues } from '@/components/MessagesFormProvider';\nimport type { DeepPartial, Messages, Translations } from '@/types';\nimport { getErrorMessage } from '@/utils/error-handling';\n\ninterface UseMessagesFormSubmitOptions {\n endpointUrl: string;\n defaultValues: Translations<DeepPartial<Messages>>;\n form: UseFormReturn<FormValues>;\n}\n\nexport function useMessagesFormSubmit({\n endpointUrl,\n defaultValues,\n form,\n}: UseMessagesFormSubmitOptions) {\n const { reportUpdate } = useDocumentEvents();\n\n const handleSubmit = async (currentValues: FormValues) => {\n const toastId = toast.loading('Saving...');\n const changes = Object.entries(currentValues).reduce<\n Translations<Messages>\n >((acc, [locale, value]) => {\n const hasChanged = !isEqual(value, defaultValues[locale]);\n if (!hasChanged) return acc;\n acc[locale] = value;\n return acc;\n }, {});\n\n try {\n const response = await fetch(endpointUrl, {\n method: 'PUT',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(changes),\n });\n\n if (!response.ok) {\n const error = await getErrorMessage(response);\n throw new Error(error);\n }\n\n form.reset(currentValues);\n reportUpdate({\n entitySlug: 'messages',\n operation: 'update',\n updatedAt: new Date().toISOString(),\n });\n toast.success('Saved', { id: toastId });\n } catch (error) {\n toast.error(\n `Failed to save: ${error instanceof Error ? error.message : 'Unknown error'}`,\n { id: toastId },\n );\n }\n };\n\n return handleSubmit;\n}\n"],"names":["toast","useDocumentEvents","isEqual","getErrorMessage","useMessagesFormSubmit","endpointUrl","defaultValues","form","reportUpdate","handleSubmit","currentValues","toastId","loading","changes","Object","entries","reduce","acc","locale","value","hasChanged","response","fetch","method","headers","body","JSON","stringify","ok","error","Error","reset","entitySlug","operation","updatedAt","Date","toISOString","success","id","message"],"mappings":"AAAA,SAASA,KAAK,EAAEC,iBAAiB,QAAQ,iBAAiB;AAC1D,SAASC,OAAO,QAAQ,YAAY;AAIpC,SAASC,eAAe,QAAQ,yBAAyB;AAQzD,OAAO,SAASC,sBAAsB,EACpCC,WAAW,EACXC,aAAa,EACbC,IAAI,EACyB;IAC7B,MAAM,EAAEC,YAAY,EAAE,GAAGP;IAEzB,MAAMQ,eAAe,OAAOC;QAC1B,MAAMC,UAAUX,MAAMY,OAAO,CAAC;QAC9B,MAAMC,UAAUC,OAAOC,OAAO,CAACL,eAAeM,MAAM,CAElD,CAACC,KAAK,CAACC,QAAQC,MAAM;YACrB,MAAMC,aAAa,CAAClB,QAAQiB,OAAOb,aAAa,CAACY,OAAO;YACxD,IAAI,CAACE,YAAY,OAAOH;YACxBA,GAAG,CAACC,OAAO,GAAGC;YACd,OAAOF;QACT,GAAG,CAAC;QAEJ,IAAI;YACF,MAAMI,WAAW,MAAMC,MAAMjB,aAAa;gBACxCkB,QAAQ;gBACRC,SAAS;oBACP,gBAAgB;gBAClB;gBACAC,MAAMC,KAAKC,SAAS,CAACd;YACvB;YAEA,IAAI,CAACQ,SAASO,EAAE,EAAE;gBAChB,MAAMC,QAAQ,MAAM1B,gBAAgBkB;gBACpC,MAAM,IAAIS,MAAMD;YAClB;YAEAtB,KAAKwB,KAAK,CAACrB;YACXF,aAAa;gBACXwB,YAAY;gBACZC,WAAW;gBACXC,WAAW,IAAIC,OAAOC,WAAW;YACnC;YACApC,MAAMqC,OAAO,CAAC,SAAS;gBAAEC,IAAI3B;YAAQ;QACvC,EAAE,OAAOkB,OAAO;YACd7B,MAAM6B,KAAK,CACT,CAAC,gBAAgB,EAAEA,iBAAiBC,QAAQD,MAAMU,OAAO,GAAG,iBAAiB,EAC7E;gBAAED,IAAI3B;YAAQ;QAElB;IACF;IAEA,OAAOF;AACT"}
@@ -0,0 +1,9 @@
1
+ import type { FieldError } from 'react-hook-form';
2
+ export interface FieldWrapperProps {
3
+ label?: string;
4
+ error: FieldError | undefined;
5
+ className?: string;
6
+ reference?: string;
7
+ }
8
+ export declare function FieldWrapper({ label, error, reference, className, children, }: React.PropsWithChildren<FieldWrapperProps>): import("react/jsx-runtime").JSX.Element;
9
+ //# sourceMappingURL=FieldWrapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FieldWrapper.d.ts","sourceRoot":"","sources":["../../../src/components/inputs/FieldWrapper.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAKlD,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,UAAU,GAAG,SAAS,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,KAAK,EACL,SAAS,EACT,SAAS,EACT,QAAQ,GACT,EAAE,KAAK,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,2CAa5C"}
@@ -0,0 +1,24 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import clsx from 'clsx';
3
+ import styles from './FieldWrapper.module.css';
4
+ import { ReferencePopover } from './ReferencePopover';
5
+ export function FieldWrapper({ label, error, reference, className, children }) {
6
+ return /*#__PURE__*/ _jsxs("div", {
7
+ className: clsx(styles.wrapper, className),
8
+ children: [
9
+ /*#__PURE__*/ _jsx(ReferencePopover, {
10
+ reference: reference,
11
+ children: /*#__PURE__*/ _jsx("fieldset", {
12
+ className: clsx(styles.fieldset, error && styles.fieldsetError),
13
+ children: children
14
+ })
15
+ }),
16
+ error?.message && /*#__PURE__*/ _jsx("p", {
17
+ className: styles.errorMessage,
18
+ children: error.message
19
+ })
20
+ ]
21
+ });
22
+ }
23
+
24
+ //# sourceMappingURL=FieldWrapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/inputs/FieldWrapper.tsx"],"sourcesContent":["import { FieldLabel } from '@payloadcms/ui';\nimport clsx from 'clsx';\nimport type { FieldError } from 'react-hook-form';\n\nimport styles from './FieldWrapper.module.css';\nimport { ReferencePopover } from './ReferencePopover';\n\nexport interface FieldWrapperProps {\n label?: string;\n error: FieldError | undefined;\n className?: string;\n reference?: string;\n}\n\nexport function FieldWrapper({\n label,\n error,\n reference,\n className,\n children,\n}: React.PropsWithChildren<FieldWrapperProps>) {\n return (\n <div className={clsx(styles.wrapper, className)}>\n <ReferencePopover reference={reference}>\n <fieldset\n className={clsx(styles.fieldset, error && styles.fieldsetError)}\n >\n {children}\n </fieldset>\n </ReferencePopover>\n {error?.message && <p className={styles.errorMessage}>{error.message}</p>}\n </div>\n );\n}\n"],"names":["clsx","styles","ReferencePopover","FieldWrapper","label","error","reference","className","children","div","wrapper","fieldset","fieldsetError","message","p","errorMessage"],"mappings":";AACA,OAAOA,UAAU,OAAO;AAGxB,OAAOC,YAAY,4BAA4B;AAC/C,SAASC,gBAAgB,QAAQ,qBAAqB;AAStD,OAAO,SAASC,aAAa,EAC3BC,KAAK,EACLC,KAAK,EACLC,SAAS,EACTC,SAAS,EACTC,QAAQ,EACmC;IAC3C,qBACE,MAACC;QAAIF,WAAWP,KAAKC,OAAOS,OAAO,EAAEH;;0BACnC,KAACL;gBAAiBI,WAAWA;0BAC3B,cAAA,KAACK;oBACCJ,WAAWP,KAAKC,OAAOU,QAAQ,EAAEN,SAASJ,OAAOW,aAAa;8BAE7DJ;;;YAGJH,OAAOQ,yBAAW,KAACC;gBAAEP,WAAWN,OAAOc,YAAY;0BAAGV,MAAMQ,OAAO;;;;AAG1E"}
@@ -8,22 +8,12 @@
8
8
 
9
9
  .fieldset {
10
10
  margin-inline: 0;
11
+ padding: 0;
12
+ border: none;
11
13
  flex: 1;
12
- border-radius: var(--style-radius-m);
13
- overflow: visible;
14
- }
15
-
16
- .fieldset:focus-within {
17
- border-color: var(--theme-elevation-400);
18
- }
19
-
20
- .fieldsetError {
21
- border: 1px solid var(--theme-error-400);
22
- background-color: var(--theme-error-100);
23
14
  }
24
15
 
25
16
  .legend {
26
- margin-left: -0.5rem;
27
17
  padding-inline: 0.375rem;
28
18
  font-size: var(--font-size-base);
29
19
  }
@@ -1,20 +1,9 @@
1
- import type { DefaultNodeTypes, TypedEditorState } from '@payloadcms/richtext-lexical';
2
- import type { SerializedEditorState } from '@payloadcms/richtext-lexical/lexical';
3
- import type { InputWrapperProps } from './InputWrapper';
4
- export interface LexicalInputProps extends InputWrapperProps {
1
+ import type { FieldWrapperProps } from './FieldWrapper';
2
+ export interface LexicalInputProps extends FieldWrapperProps {
5
3
  lang: string;
6
4
  value: string;
7
5
  onChange: (value: string) => void;
8
6
  onBlur: () => void;
9
7
  }
10
8
  export declare function LexicalInput({ error, label, value, onChange, className, }: LexicalInputProps): React.ReactNode;
11
- interface UseHtmlLexicalAdapterProps {
12
- html: string;
13
- onChange: (html: string) => void;
14
- }
15
- export declare function useHtmlLexicalAdapter({ html, onChange, }: UseHtmlLexicalAdapterProps): {
16
- value: TypedEditorState<DefaultNodeTypes>;
17
- setValue: (serializedState: SerializedEditorState) => void;
18
- };
19
- export {};
20
9
  //# sourceMappingURL=LexicalInput.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"LexicalInput.d.ts","sourceRoot":"","sources":["../../../src/components/inputs/LexicalInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,gBAAgB,EACjB,MAAM,8BAA8B,CAAC;AAWtC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AASlF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGxD,MAAM,WAAW,iBAAkB,SAAQ,iBAAiB;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAED,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,KAAK,EACL,KAAK,EACL,QAAQ,EACR,SAAS,GACV,EAAE,iBAAiB,GAAG,KAAK,CAAC,SAAS,CAoBrC;AAID,UAAU,0BAA0B;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAED,wBAAgB,qBAAqB,CAAC,EACpC,IAAI,EACJ,QAAQ,GACT,EAAE,0BAA0B;WAiEF,gBAAgB,CAAC,gBAAgB,CAAC;gCAjBvC,qBAAqB;EAkB1C"}
1
+ {"version":3,"file":"LexicalInput.d.ts","sourceRoot":"","sources":["../../../src/components/inputs/LexicalInput.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGxD,MAAM,WAAW,iBAAkB,SAAQ,iBAAiB;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAED,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,KAAK,EACL,KAAK,EACL,QAAQ,EACR,SAAS,GACV,EAAE,iBAAiB,GAAG,KAAK,CAAC,SAAS,CAoBrC"}
@@ -1,17 +1,13 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { defaultEditorConfig, defaultEditorFeatures } from '@payloadcms/richtext-lexical';
3
- import { buildDefaultEditorState, getEnabledNodes, RenderLexical, sanitizeClientEditorConfig } from '@payloadcms/richtext-lexical/client';
4
- import { $getRoot } from '@payloadcms/richtext-lexical/lexical';
5
- import { createHeadlessEditor } from '@payloadcms/richtext-lexical/lexical/headless';
6
- import { $generateHtmlFromNodes, $generateNodesFromDOM } from '@payloadcms/richtext-lexical/lexical/html';
7
- import { useCallback, useMemo, useRef } from 'react';
8
- import { InputWrapper } from './InputWrapper';
2
+ import { RenderLexical } from '@payloadcms/richtext-lexical/client';
3
+ import { useHtmlLexicalAdapter } from '../hooks/useHtmlLexicalAdapter';
4
+ import { FieldWrapper } from './FieldWrapper';
9
5
  export function LexicalInput({ error, label, value, onChange, className }) {
10
6
  const editor = useHtmlLexicalAdapter({
11
7
  html: value,
12
8
  onChange
13
9
  });
14
- return /*#__PURE__*/ _jsx(InputWrapper, {
10
+ return /*#__PURE__*/ _jsx(FieldWrapper, {
15
11
  className: className,
16
12
  error: error,
17
13
  label: label,
@@ -27,60 +23,5 @@ export function LexicalInput({ error, label, value, onChange, className }) {
27
23
  })
28
24
  });
29
25
  }
30
- const EMPTY_STATE = buildDefaultEditorState({});
31
- export function useHtmlLexicalAdapter({ html, onChange }) {
32
- // 1. Maintain a persistent headless editor for conversion
33
- const headlessEditor = useRef(createHeadlessEditor({
34
- nodes: getEnabledNodes({
35
- editorConfig: sanitizeClientEditorConfig(// @ts-expect-error - FIXME
36
- defaultEditorFeatures, defaultEditorConfig)
37
- })
38
- }));
39
- // 2. HTML -> SerializedState
40
- const getSerializedState = useCallback((htmlString)=>{
41
- const editor = headlessEditor.current;
42
- editor.update(()=>{
43
- const parser = new DOMParser();
44
- const dom = parser.parseFromString(htmlString, 'text/html');
45
- const nodes = $generateNodesFromDOM(editor, dom);
46
- const root = $getRoot();
47
- root.clear().append(...nodes);
48
- }, {
49
- discrete: true
50
- });
51
- return editor.getEditorState().toJSON();
52
- }, []);
53
- // 3. Memoize the initial value to prevent unnecessary re-renders
54
- const value = useMemo(()=>{
55
- const serializedState = getSerializedState(html);
56
- if (serializedState.root.children.length === 0) {
57
- return EMPTY_STATE;
58
- }
59
- return serializedState;
60
- }, [
61
- html,
62
- getSerializedState
63
- ]);
64
- // 4. SerializedState -> HTML
65
- const setValue = useCallback((serializedState)=>{
66
- const editor = headlessEditor.current;
67
- // Update headless editor to match the incoming state
68
- editor.setEditorState(editor.parseEditorState(serializedState));
69
- // Generate HTML and broadcast if it has changed
70
- editor.read(()=>{
71
- const newHtml = $generateHtmlFromNodes(editor);
72
- if (newHtml !== html) {
73
- onChange(newHtml);
74
- }
75
- });
76
- }, [
77
- html,
78
- onChange
79
- ]);
80
- return {
81
- value: value,
82
- setValue
83
- };
84
- }
85
26
 
86
27
  //# sourceMappingURL=LexicalInput.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/inputs/LexicalInput.tsx"],"sourcesContent":["import type {\n DefaultNodeTypes,\n TypedEditorState,\n} from '@payloadcms/richtext-lexical';\nimport {\n defaultEditorConfig,\n defaultEditorFeatures,\n} from '@payloadcms/richtext-lexical';\nimport {\n buildDefaultEditorState,\n getEnabledNodes,\n RenderLexical,\n sanitizeClientEditorConfig,\n} from '@payloadcms/richtext-lexical/client';\nimport type { SerializedEditorState } from '@payloadcms/richtext-lexical/lexical';\nimport { $getRoot } from '@payloadcms/richtext-lexical/lexical';\nimport { createHeadlessEditor } from '@payloadcms/richtext-lexical/lexical/headless';\nimport {\n $generateHtmlFromNodes,\n $generateNodesFromDOM,\n} from '@payloadcms/richtext-lexical/lexical/html';\nimport { useCallback, useMemo, useRef } from 'react';\n\nimport type { InputWrapperProps } from './InputWrapper';\nimport { InputWrapper } from './InputWrapper';\n\nexport interface LexicalInputProps extends InputWrapperProps {\n lang: string;\n value: string;\n onChange: (value: string) => void;\n onBlur: () => void;\n}\n\nexport function LexicalInput({\n error,\n label,\n value,\n onChange,\n className,\n}: LexicalInputProps): React.ReactNode {\n const editor = useHtmlLexicalAdapter({\n html: value,\n onChange,\n });\n\n return (\n <InputWrapper className={className} error={error} label={label}>\n <RenderLexical\n field={{\n name: 'myCustomEditor',\n label: false,\n type: 'richText',\n }}\n schemaPath=\"global.intl-plugin.editorTemplate\"\n setValue={(val) => editor.setValue(val as SerializedEditorState)}\n value={editor.value}\n />\n </InputWrapper>\n );\n}\n\nconst EMPTY_STATE = buildDefaultEditorState({});\n\ninterface UseHtmlLexicalAdapterProps {\n html: string;\n onChange: (html: string) => void;\n}\n\nexport function useHtmlLexicalAdapter({\n html,\n onChange,\n}: UseHtmlLexicalAdapterProps) {\n // 1. Maintain a persistent headless editor for conversion\n const headlessEditor = useRef(\n createHeadlessEditor({\n nodes: getEnabledNodes({\n editorConfig: sanitizeClientEditorConfig(\n // @ts-expect-error - FIXME\n defaultEditorFeatures,\n defaultEditorConfig,\n ),\n }),\n }),\n );\n\n // 2. HTML -> SerializedState\n const getSerializedState = useCallback(\n (htmlString: string): SerializedEditorState => {\n const editor = headlessEditor.current;\n editor.update(\n () => {\n const parser = new DOMParser();\n const dom = parser.parseFromString(htmlString, 'text/html');\n const nodes = $generateNodesFromDOM(editor, dom);\n\n const root = $getRoot();\n root.clear().append(...nodes);\n },\n { discrete: true },\n );\n\n return editor.getEditorState().toJSON();\n },\n [],\n );\n\n // 3. Memoize the initial value to prevent unnecessary re-renders\n const value = useMemo(() => {\n const serializedState = getSerializedState(html);\n\n if (serializedState.root.children.length === 0) {\n return EMPTY_STATE;\n }\n\n return serializedState;\n }, [html, getSerializedState]);\n\n // 4. SerializedState -> HTML\n const setValue = useCallback(\n (serializedState: SerializedEditorState) => {\n const editor = headlessEditor.current;\n\n // Update headless editor to match the incoming state\n editor.setEditorState(editor.parseEditorState(serializedState));\n\n // Generate HTML and broadcast if it has changed\n editor.read(() => {\n const newHtml = $generateHtmlFromNodes(editor);\n if (newHtml !== html) {\n onChange(newHtml);\n }\n });\n },\n [html, onChange],\n );\n\n return { value: value as TypedEditorState<DefaultNodeTypes>, setValue };\n}\n"],"names":["defaultEditorConfig","defaultEditorFeatures","buildDefaultEditorState","getEnabledNodes","RenderLexical","sanitizeClientEditorConfig","$getRoot","createHeadlessEditor","$generateHtmlFromNodes","$generateNodesFromDOM","useCallback","useMemo","useRef","InputWrapper","LexicalInput","error","label","value","onChange","className","editor","useHtmlLexicalAdapter","html","field","name","type","schemaPath","setValue","val","EMPTY_STATE","headlessEditor","nodes","editorConfig","getSerializedState","htmlString","current","update","parser","DOMParser","dom","parseFromString","root","clear","append","discrete","getEditorState","toJSON","serializedState","children","length","setEditorState","parseEditorState","read","newHtml"],"mappings":";AAIA,SACEA,mBAAmB,EACnBC,qBAAqB,QAChB,+BAA+B;AACtC,SACEC,uBAAuB,EACvBC,eAAe,EACfC,aAAa,EACbC,0BAA0B,QACrB,sCAAsC;AAE7C,SAASC,QAAQ,QAAQ,uCAAuC;AAChE,SAASC,oBAAoB,QAAQ,gDAAgD;AACrF,SACEC,sBAAsB,EACtBC,qBAAqB,QAChB,4CAA4C;AACnD,SAASC,WAAW,EAAEC,OAAO,EAAEC,MAAM,QAAQ,QAAQ;AAGrD,SAASC,YAAY,QAAQ,iBAAiB;AAS9C,OAAO,SAASC,aAAa,EAC3BC,KAAK,EACLC,KAAK,EACLC,KAAK,EACLC,QAAQ,EACRC,SAAS,EACS;IAClB,MAAMC,SAASC,sBAAsB;QACnCC,MAAML;QACNC;IACF;IAEA,qBACE,KAACL;QAAaM,WAAWA;QAAWJ,OAAOA;QAAOC,OAAOA;kBACvD,cAAA,KAACZ;YACCmB,OAAO;gBACLC,MAAM;gBACNR,OAAO;gBACPS,MAAM;YACR;YACAC,YAAW;YACXC,UAAU,CAACC,MAAQR,OAAOO,QAAQ,CAACC;YACnCX,OAAOG,OAAOH,KAAK;;;AAI3B;AAEA,MAAMY,cAAc3B,wBAAwB,CAAC;AAO7C,OAAO,SAASmB,sBAAsB,EACpCC,IAAI,EACJJ,QAAQ,EACmB;IAC3B,0DAA0D;IAC1D,MAAMY,iBAAiBlB,OACrBL,qBAAqB;QACnBwB,OAAO5B,gBAAgB;YACrB6B,cAAc3B,2BACZ,2BAA2B;YAC3BJ,uBACAD;QAEJ;IACF;IAGF,6BAA6B;IAC7B,MAAMiC,qBAAqBvB,YACzB,CAACwB;QACC,MAAMd,SAASU,eAAeK,OAAO;QACrCf,OAAOgB,MAAM,CACX;YACE,MAAMC,SAAS,IAAIC;YACnB,MAAMC,MAAMF,OAAOG,eAAe,CAACN,YAAY;YAC/C,MAAMH,QAAQtB,sBAAsBW,QAAQmB;YAE5C,MAAME,OAAOnC;YACbmC,KAAKC,KAAK,GAAGC,MAAM,IAAIZ;QACzB,GACA;YAAEa,UAAU;QAAK;QAGnB,OAAOxB,OAAOyB,cAAc,GAAGC,MAAM;IACvC,GACA,EAAE;IAGJ,iEAAiE;IACjE,MAAM7B,QAAQN,QAAQ;QACpB,MAAMoC,kBAAkBd,mBAAmBX;QAE3C,IAAIyB,gBAAgBN,IAAI,CAACO,QAAQ,CAACC,MAAM,KAAK,GAAG;YAC9C,OAAOpB;QACT;QAEA,OAAOkB;IACT,GAAG;QAACzB;QAAMW;KAAmB;IAE7B,6BAA6B;IAC7B,MAAMN,WAAWjB,YACf,CAACqC;QACC,MAAM3B,SAASU,eAAeK,OAAO;QAErC,qDAAqD;QACrDf,OAAO8B,cAAc,CAAC9B,OAAO+B,gBAAgB,CAACJ;QAE9C,gDAAgD;QAChD3B,OAAOgC,IAAI,CAAC;YACV,MAAMC,UAAU7C,uBAAuBY;YACvC,IAAIiC,YAAY/B,MAAM;gBACpBJ,SAASmC;YACX;QACF;IACF,GACA;QAAC/B;QAAMJ;KAAS;IAGlB,OAAO;QAAED,OAAOA;QAA6CU;IAAS;AACxE"}
1
+ {"version":3,"sources":["../../../src/components/inputs/LexicalInput.tsx"],"sourcesContent":["import { RenderLexical } from '@payloadcms/richtext-lexical/client';\nimport type { SerializedEditorState } from '@payloadcms/richtext-lexical/lexical';\nimport { useHtmlLexicalAdapter } from '../hooks/useHtmlLexicalAdapter';\nimport type { FieldWrapperProps } from './FieldWrapper';\nimport { FieldWrapper } from './FieldWrapper';\n\nexport interface LexicalInputProps extends FieldWrapperProps {\n lang: string;\n value: string;\n onChange: (value: string) => void;\n onBlur: () => void;\n}\n\nexport function LexicalInput({\n error,\n label,\n value,\n onChange,\n className,\n}: LexicalInputProps): React.ReactNode {\n const editor = useHtmlLexicalAdapter({\n html: value,\n onChange,\n });\n\n return (\n <FieldWrapper className={className} error={error} label={label}>\n <RenderLexical\n field={{\n name: 'myCustomEditor',\n label: false,\n type: 'richText',\n }}\n schemaPath=\"global.intl-plugin.editorTemplate\"\n setValue={(val) => editor.setValue(val as SerializedEditorState)}\n value={editor.value}\n />\n </FieldWrapper>\n );\n}\n"],"names":["RenderLexical","useHtmlLexicalAdapter","FieldWrapper","LexicalInput","error","label","value","onChange","className","editor","html","field","name","type","schemaPath","setValue","val"],"mappings":";AAAA,SAASA,aAAa,QAAQ,sCAAsC;AAEpE,SAASC,qBAAqB,QAAQ,iCAAiC;AAEvE,SAASC,YAAY,QAAQ,iBAAiB;AAS9C,OAAO,SAASC,aAAa,EAC3BC,KAAK,EACLC,KAAK,EACLC,KAAK,EACLC,QAAQ,EACRC,SAAS,EACS;IAClB,MAAMC,SAASR,sBAAsB;QACnCS,MAAMJ;QACNC;IACF;IAEA,qBACE,KAACL;QAAaM,WAAWA;QAAWJ,OAAOA;QAAOC,OAAOA;kBACvD,cAAA,KAACL;YACCW,OAAO;gBACLC,MAAM;gBACNP,OAAO;gBACPQ,MAAM;YACR;YACAC,YAAW;YACXC,UAAU,CAACC,MAAQP,OAAOM,QAAQ,CAACC;YACnCV,OAAOG,OAAOH,KAAK;;;AAI3B"}
@@ -1,11 +1,14 @@
1
1
  import type { TemplateVariable } from '../../types';
2
- import type { InputWrapperProps } from './InputWrapper';
3
- export interface MessageInputProps extends InputWrapperProps {
2
+ import type { FieldWrapperProps } from './FieldWrapper';
3
+ export interface MessageInputProps extends FieldWrapperProps {
4
4
  value: string;
5
5
  lang: string;
6
6
  variables: TemplateVariable[];
7
7
  onChange: (value: string) => void;
8
8
  onBlur: () => void;
9
+ readOnly?: boolean;
10
+ multiline?: boolean;
11
+ reference?: string;
9
12
  }
10
- export declare function MessageInput({ label, value, lang, error, variables, onChange, onBlur, className, }: MessageInputProps): import("react/jsx-runtime").JSX.Element;
13
+ export declare function MessageInput({ label, value, lang, error, variables, onChange, onBlur, className, multiline, reference, }: MessageInputProps): import("react/jsx-runtime").JSX.Element;
11
14
  //# sourceMappingURL=MessageInput.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MessageInput.d.ts","sourceRoot":"","sources":["../../../src/components/inputs/MessageInput.tsx"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAShD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAMxD,MAAM,WAAW,iBAAkB,SAAQ,iBAAiB;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAC9B,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAsCD,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,KAAK,EACL,IAAI,EACJ,KAAK,EACL,SAAS,EACT,QAAQ,EACR,MAAM,EACN,SAAS,GACV,EAAE,iBAAiB,2CAiEnB"}
1
+ {"version":3,"file":"MessageInput.d.ts","sourceRoot":"","sources":["../../../src/components/inputs/MessageInput.tsx"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAShD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AA2BxD,MAAM,WAAW,iBAAkB,SAAQ,iBAAiB;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAC9B,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,KAAK,EACL,IAAI,EACJ,KAAK,EACL,SAAS,EACT,QAAQ,EACR,MAAM,EACN,SAAS,EACT,SAAS,EACT,SAAS,GACV,EAAE,iBAAiB,2CAuFnB"}
@@ -2,44 +2,40 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { $getRoot } from '@payloadcms/richtext-lexical/lexical';
4
4
  import { LexicalComposer } from '@payloadcms/richtext-lexical/lexical/react/LexicalComposer';
5
+ import { useLexicalComposerContext } from '@payloadcms/richtext-lexical/lexical/react/LexicalComposerContext';
5
6
  import { ContentEditable } from '@payloadcms/richtext-lexical/lexical/react/LexicalContentEditable';
6
7
  import { LexicalErrorBoundary } from '@payloadcms/richtext-lexical/lexical/react/LexicalErrorBoundary';
7
8
  import { HistoryPlugin } from '@payloadcms/richtext-lexical/lexical/react/LexicalHistoryPlugin';
8
9
  import { OnChangePlugin } from '@payloadcms/richtext-lexical/lexical/react/LexicalOnChangePlugin';
9
10
  import { PlainTextPlugin } from '@payloadcms/richtext-lexical/lexical/react/LexicalPlainTextPlugin';
11
+ import clsx from 'clsx';
10
12
  import { BeautifulMentionNode, BeautifulMentionsPlugin } from 'lexical-beautiful-mentions';
11
- import { forwardRef, useCallback, useMemo } from 'react';
13
+ import { useCallback, useEffect, useMemo } from 'react';
12
14
  import { formatVariableLabel } from '../../utils/format';
13
15
  import { isTagElement } from '../../utils/guards';
14
16
  import { parseIcuToLexicalState, serializeICUMessage } from '../../utils/icu-tranform';
15
- import { InputWrapper } from './InputWrapper';
17
+ import { FieldWrapper } from './FieldWrapper';
16
18
  import styles from './MessageInput.module.css';
19
+ import { SingleLinePlugin } from './SingleLinePlugin';
17
20
  import { VariableMentionNode } from './variables/VariableNode';
18
- import suggestionStyles from './variables/VariableSuggestion.module.css';
19
- const MentionMenu = /*#__PURE__*/ forwardRef(({ loading: _, ...props }, ref)=>/*#__PURE__*/ _jsx("ul", {
20
- ...props,
21
- className: suggestionStyles.list,
22
- ref: ref
23
- }));
24
- const MentionMenuItem = /*#__PURE__*/ forwardRef((props, ref)=>/*#__PURE__*/ _jsx("li", {
25
- "aria-selected": props.selected,
26
- className: [
27
- suggestionStyles.item,
28
- props.selected ? suggestionStyles.itemSelected : undefined
29
- ].filter(Boolean).join(' '),
30
- onClick: props.onClick,
31
- onKeyDown: props.onKeyDown,
32
- onMouseDown: props.onMouseDown,
33
- onMouseEnter: props.onMouseEnter,
34
- ref: ref,
35
- // biome-ignore lint/a11y/noNoninteractiveElementToInteractiveRole: standard WAI-ARIA listbox/option pattern
36
- role: "option",
37
- tabIndex: -1,
38
- children: typeof props.item.data?.label === 'string' ? props.item.data.label : props.item.displayValue
39
- }));
40
- // TODO add variable editor (style, options, etc)
41
- // TODO add tooltip to show all variables
42
- export function MessageInput({ label, value, lang, error, variables, onChange, onBlur, className }) {
21
+ import { MentionMenu, MentionMenuItem } from './variables/VariableSuggestion';
22
+ function SyncValuePlugin({ value }) {
23
+ const [editor] = useLexicalComposerContext();
24
+ useEffect(()=>{
25
+ const currentText = editor.getEditorState().read(()=>$getRoot().getTextContent());
26
+ if (value !== currentText) {
27
+ queueMicrotask(()=>{
28
+ const newState = editor.parseEditorState(JSON.stringify(parseIcuToLexicalState(value)));
29
+ editor.setEditorState(newState);
30
+ });
31
+ }
32
+ }, [
33
+ value,
34
+ editor
35
+ ]);
36
+ return null;
37
+ }
38
+ export function MessageInput({ label, value, lang, error, variables, onChange, onBlur, className, multiline, reference }) {
43
39
  const handleChange = useCallback((editorState)=>{
44
40
  editorState.read(()=>{
45
41
  onChange($getRoot().getTextContent());
@@ -63,35 +59,43 @@ export function MessageInput({ label, value, lang, error, variables, onChange, o
63
59
  }, [
64
60
  variables
65
61
  ]);
66
- const initialConfig = {
67
- namespace: 'ICUMessageEditor',
68
- nodes: [
69
- VariableMentionNode,
70
- {
71
- replace: BeautifulMentionNode,
72
- with: (node)=>new VariableMentionNode(node.getTrigger(), node.getValue(), node.getData())
73
- }
74
- ],
75
- editorState: JSON.stringify(parseIcuToLexicalState(value)),
76
- onError: console.error
77
- };
78
- return /*#__PURE__*/ _jsx(InputWrapper, {
62
+ // biome-ignore lint/correctness/useExhaustiveDependencies: LexicalComposer only reads initialConfig on mount
63
+ const initialConfig = useMemo(()=>({
64
+ namespace: 'ICUMessageEditor',
65
+ nodes: [
66
+ VariableMentionNode,
67
+ {
68
+ replace: BeautifulMentionNode,
69
+ with: (node)=>new VariableMentionNode(node.getTrigger(), node.getValue(), node.getData()),
70
+ withKlass: VariableMentionNode
71
+ }
72
+ ],
73
+ editorState: JSON.stringify(parseIcuToLexicalState(value)),
74
+ editable: true,
75
+ onError: console.error
76
+ }), []);
77
+ return /*#__PURE__*/ _jsx(FieldWrapper, {
79
78
  className: className,
80
79
  error: error,
81
80
  label: label,
81
+ reference: reference,
82
82
  children: /*#__PURE__*/ _jsx(LexicalComposer, {
83
83
  initialConfig: initialConfig,
84
84
  children: /*#__PURE__*/ _jsxs("div", {
85
- className: styles.editor,
85
+ className: clsx(styles.editor, multiline && styles.multiline),
86
86
  lang: lang,
87
- onBlur: onBlur,
88
87
  children: [
89
88
  /*#__PURE__*/ _jsx(PlainTextPlugin, {
90
89
  contentEditable: /*#__PURE__*/ _jsx(ContentEditable, {
91
- className: styles.contentEditable
90
+ className: clsx(styles.contentEditable, error && styles.contentEditableError),
91
+ onBlur: onBlur
92
92
  }),
93
93
  ErrorBoundary: LexicalErrorBoundary
94
94
  }),
95
+ multiline && /*#__PURE__*/ _jsx(SingleLinePlugin, {}),
96
+ /*#__PURE__*/ _jsx(SyncValuePlugin, {
97
+ value: value
98
+ }),
95
99
  /*#__PURE__*/ _jsx(OnChangePlugin, {
96
100
  onChange: handleChange
97
101
  }),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/inputs/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 { 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 type BeautifulMentionsMenuItemProps,\n type BeautifulMentionsMenuProps,\n BeautifulMentionsPlugin,\n} from 'lexical-beautiful-mentions';\nimport { forwardRef, useCallback, useMemo } from 'react';\nimport type { TemplateVariable } from '@/types';\n\nimport { formatVariableLabel } from '@/utils/format';\nimport { isTagElement } from '@/utils/guards';\nimport {\n parseIcuToLexicalState,\n serializeICUMessage,\n} from '@/utils/icu-tranform';\n\nimport type { InputWrapperProps } from './InputWrapper';\nimport { InputWrapper } from './InputWrapper';\nimport styles from './MessageInput.module.css';\nimport { VariableMentionNode } from './variables/VariableNode';\nimport suggestionStyles from './variables/VariableSuggestion.module.css';\n\nexport interface MessageInputProps extends InputWrapperProps {\n value: string;\n lang: string;\n variables: TemplateVariable[];\n onChange: (value: string) => void;\n onBlur: () => void;\n}\n\nconst MentionMenu = forwardRef<HTMLUListElement, BeautifulMentionsMenuProps>(\n ({ loading: _, ...props }, ref) => (\n <ul {...props} className={suggestionStyles.list} ref={ref} />\n ),\n);\n\nconst MentionMenuItem = forwardRef<\n HTMLLIElement,\n BeautifulMentionsMenuItemProps\n>((props, ref) => (\n <li\n aria-selected={props.selected}\n className={[\n suggestionStyles.item,\n props.selected ? suggestionStyles.itemSelected : undefined,\n ]\n .filter(Boolean)\n .join(' ')}\n onClick={props.onClick}\n onKeyDown={props.onKeyDown}\n onMouseDown={props.onMouseDown}\n onMouseEnter={props.onMouseEnter}\n ref={ref}\n // biome-ignore lint/a11y/noNoninteractiveElementToInteractiveRole: standard WAI-ARIA listbox/option pattern\n role=\"option\"\n tabIndex={-1}\n >\n {typeof props.item.data?.label === 'string'\n ? props.item.data.label\n : props.item.displayValue}\n </li>\n));\n\n// TODO add variable editor (style, options, etc)\n// TODO add tooltip to show all variables\n\nexport function MessageInput({\n label,\n value,\n lang,\n error,\n variables,\n onChange,\n onBlur,\n className,\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 = {\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 },\n ],\n editorState: JSON.stringify(parseIcuToLexicalState(value)),\n onError: console.error,\n };\n\n return (\n <InputWrapper className={className} error={error} label={label}>\n <LexicalComposer initialConfig={initialConfig}>\n {/* biome-ignore lint/a11y/noStaticElementInteractions: onBlur captures focus-leave from the Lexical contentEditable */}\n <div className={styles.editor} lang={lang} onBlur={onBlur}>\n <PlainTextPlugin\n contentEditable={\n <ContentEditable className={styles.contentEditable} />\n }\n ErrorBoundary={LexicalErrorBoundary}\n />\n <OnChangePlugin onChange={handleChange} />\n <HistoryPlugin />\n <BeautifulMentionsPlugin\n items={mentionItems}\n menuAnchorClassName={styles.menuAnchor}\n menuComponent={MentionMenu}\n menuItemComponent={MentionMenuItem}\n />\n </div>\n </LexicalComposer>\n </InputWrapper>\n );\n}\n"],"names":["$getRoot","LexicalComposer","ContentEditable","LexicalErrorBoundary","HistoryPlugin","OnChangePlugin","PlainTextPlugin","BeautifulMentionNode","BeautifulMentionsPlugin","forwardRef","useCallback","useMemo","formatVariableLabel","isTagElement","parseIcuToLexicalState","serializeICUMessage","InputWrapper","styles","VariableMentionNode","suggestionStyles","MentionMenu","loading","_","props","ref","ul","className","list","MentionMenuItem","li","aria-selected","selected","item","itemSelected","undefined","filter","Boolean","join","onClick","onKeyDown","onMouseDown","onMouseEnter","role","tabIndex","data","label","displayValue","MessageInput","value","lang","error","variables","onChange","onBlur","handleChange","editorState","read","getTextContent","mentionItems","toItem","v","icu","map","initialConfig","namespace","nodes","replace","with","node","getTrigger","getValue","getData","JSON","stringify","onError","console","div","editor","contentEditable","ErrorBoundary","items","menuAnchorClassName","menuAnchor","menuComponent","menuItemComponent"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/components/inputs/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 clsx from 'clsx';\nimport {\n BeautifulMentionNode,\n BeautifulMentionsPlugin,\n} from 'lexical-beautiful-mentions';\nimport { useCallback, useEffect, useMemo } from 'react';\nimport type { TemplateVariable } from '@/types';\n\nimport { formatVariableLabel } from '@/utils/format';\nimport { isTagElement } from '@/utils/guards';\nimport {\n parseIcuToLexicalState,\n serializeICUMessage,\n} from '@/utils/icu-tranform';\n\nimport type { FieldWrapperProps } from './FieldWrapper';\nimport { FieldWrapper } from './FieldWrapper';\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 extends FieldWrapperProps {\n value: string;\n lang: string;\n variables: TemplateVariable[];\n onChange: (value: string) => void;\n onBlur: () => void;\n readOnly?: boolean;\n multiline?: boolean;\n reference?: string;\n}\n\nexport function MessageInput({\n label,\n value,\n lang,\n error,\n variables,\n onChange,\n onBlur,\n className,\n multiline,\n reference,\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 // biome-ignore lint/correctness/useExhaustiveDependencies: LexicalComposer only reads initialConfig on mount\n const initialConfig = useMemo(\n () => ({\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 );\n\n return (\n <FieldWrapper\n className={className}\n error={error}\n label={label}\n reference={reference}\n >\n <LexicalComposer initialConfig={initialConfig}>\n <div\n className={clsx(styles.editor, multiline && styles.multiline)}\n lang={lang}\n >\n <PlainTextPlugin\n contentEditable={\n <ContentEditable\n className={clsx(\n styles.contentEditable,\n error && styles.contentEditableError,\n )}\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 </FieldWrapper>\n );\n}\n"],"names":["$getRoot","LexicalComposer","useLexicalComposerContext","ContentEditable","LexicalErrorBoundary","HistoryPlugin","OnChangePlugin","PlainTextPlugin","clsx","BeautifulMentionNode","BeautifulMentionsPlugin","useCallback","useEffect","useMemo","formatVariableLabel","isTagElement","parseIcuToLexicalState","serializeICUMessage","FieldWrapper","styles","SingleLinePlugin","VariableMentionNode","MentionMenu","MentionMenuItem","SyncValuePlugin","value","editor","currentText","getEditorState","read","getTextContent","queueMicrotask","newState","parseEditorState","JSON","stringify","setEditorState","MessageInput","label","lang","error","variables","onChange","onBlur","className","multiline","reference","handleChange","editorState","mentionItems","toItem","v","icu","map","filter","initialConfig","namespace","nodes","replace","with","node","getTrigger","getValue","getData","withKlass","editable","onError","console","div","contentEditable","contentEditableError","ErrorBoundary","items","menuAnchorClassName","menuAnchor","menuComponent","menuItemComponent"],"mappings":"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"}
@@ -1,25 +1,44 @@
1
1
  .editor {
2
2
  position: relative;
3
+ display: grid;
4
+ align-items: center;
3
5
  min-height: 2rem;
4
6
  font-size: var(--font-size-large);
5
7
  }
6
8
 
9
+ .readOnly {
10
+ opacity: 0.7;
11
+ cursor: default;
12
+ }
13
+
14
+ .multiline {
15
+ min-height: 4rem;
16
+ }
17
+
7
18
  .menuAnchor {
8
19
  z-index: 50;
9
20
  }
10
21
 
11
22
  .contentEditable {
12
23
  outline: none;
24
+ border-radius: var(--style-radius-m);
25
+ background-color: var(--theme-elevation-0);
26
+ border: 1px solid var(--theme-elevation-300);
27
+ padding-block: 0.25rem;
28
+ padding-inline: 0.75rem;
29
+ height: 100%;
13
30
  }
14
31
 
15
32
  .contentEditable:focus {
16
33
  outline: none;
34
+ border-color: var(--theme-elevation-600);
17
35
  }
18
36
 
19
- .contentEditable > :first-child {
20
- margin-top: 0;
37
+ .contentEditableError {
38
+ border-color: var(--theme-error-400);
39
+ background-color: var(--theme-error-100);
21
40
  }
22
41
 
23
- .contentEditable > :last-child {
24
- margin-bottom: 0;
42
+ .contentEditable p {
43
+ margin: 0;
25
44
  }