@intlayer/design-system 9.0.0-canary.14 → 9.0.0-canary.16

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 (70) hide show
  1. package/dist/esm/api/hooks/analytics.mjs +71 -0
  2. package/dist/esm/api/hooks/analytics.mjs.map +1 -0
  3. package/dist/esm/api/index.mjs +5 -4
  4. package/dist/esm/api/useAuth/useOAuth2.mjs +1 -1
  5. package/dist/esm/api/useAuth/useSession.mjs +1 -1
  6. package/dist/esm/api/useIntlayerAPI.mjs +6 -1
  7. package/dist/esm/api/useIntlayerAPI.mjs.map +1 -1
  8. package/dist/esm/components/ContentEditor/ContentEditorTextArea.mjs +1 -1
  9. package/dist/esm/components/DictionaryFieldEditor/ContentEditor.mjs +2 -2
  10. package/dist/esm/components/DictionaryFieldEditor/ContentEditorView/TextEditor.mjs +26 -24
  11. package/dist/esm/components/DictionaryFieldEditor/ContentEditorView/TextEditor.mjs.map +1 -1
  12. package/dist/esm/components/DictionaryFieldEditor/DictionaryCreationForm/DictionaryCreationForm.mjs +1 -1
  13. package/dist/esm/components/DictionaryFieldEditor/DictionaryDetails/DictionaryDetailsForm.mjs +6 -6
  14. package/dist/esm/components/DictionaryFieldEditor/DictionaryFieldEditor.mjs +1 -1
  15. package/dist/esm/components/DictionaryFieldEditor/NavigationView/NavigationViewNode.mjs +1 -1
  16. package/dist/esm/components/DictionaryFieldEditor/SaveForm/SaveForm.mjs +2 -2
  17. package/dist/esm/components/DictionaryFieldEditor/StructureView/StructureView.mjs +1 -1
  18. package/dist/esm/components/Form/elements/OTPElement.mjs +1 -1
  19. package/dist/esm/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.mjs +1 -1
  20. package/dist/esm/components/MarkdownEditor/MarkdownEditor.mjs +2 -3
  21. package/dist/esm/components/MarkdownEditor/MarkdownEditor.mjs.map +1 -1
  22. package/dist/esm/components/MarkdownEditor/markdownEditor.content.mjs +118 -59
  23. package/dist/esm/components/MarkdownEditor/markdownEditor.content.mjs.map +1 -1
  24. package/dist/esm/components/MarkdownEditor/novel/components/editor.mjs.map +1 -1
  25. package/dist/esm/components/MarkdownEditor/novel/extensions/image-resizer.mjs +91 -37
  26. package/dist/esm/components/MarkdownEditor/novel/extensions/image-resizer.mjs.map +1 -1
  27. package/dist/esm/components/MarkdownEditor/novel/extensions/slash-command.mjs +49 -13
  28. package/dist/esm/components/MarkdownEditor/novel/extensions/slash-command.mjs.map +1 -1
  29. package/dist/esm/components/Modal/Modal.mjs +2 -2
  30. package/dist/esm/components/Navbar/MobileNavbar.mjs +1 -1
  31. package/dist/esm/components/Pagination/Pagination.mjs +1 -1
  32. package/dist/esm/components/RightDrawer/RightDrawer.mjs +3 -3
  33. package/dist/esm/components/Tab/Tab.mjs +1 -1
  34. package/dist/esm/hooks/index.mjs +8 -8
  35. package/dist/esm/routes.mjs +3 -1
  36. package/dist/esm/routes.mjs.map +1 -1
  37. package/dist/types/api/hooks/analytics.d.ts +28 -0
  38. package/dist/types/api/hooks/analytics.d.ts.map +1 -0
  39. package/dist/types/api/index.d.ts +3 -2
  40. package/dist/types/api/useIntlayerAPI.d.ts +4 -2
  41. package/dist/types/api/useIntlayerAPI.d.ts.map +1 -1
  42. package/dist/types/components/Badge/index.d.ts +1 -1
  43. package/dist/types/components/Button/Button.d.ts +5 -5
  44. package/dist/types/components/CollapsibleTable/CollapsibleTable.d.ts +2 -2
  45. package/dist/types/components/Command/index.d.ts +2 -2
  46. package/dist/types/components/Container/index.d.ts +5 -5
  47. package/dist/types/components/DictionaryFieldEditor/ContentEditorView/TextEditor.d.ts +5 -1
  48. package/dist/types/components/DictionaryFieldEditor/ContentEditorView/TextEditor.d.ts.map +1 -1
  49. package/dist/types/components/DictionaryFieldEditor/DictionaryCreationForm/useDictionaryFormSchema.d.ts +1 -1
  50. package/dist/types/components/Input/Checkbox.d.ts +1 -1
  51. package/dist/types/components/Input/Radio.d.ts +1 -1
  52. package/dist/types/components/Link/Link.d.ts +3 -3
  53. package/dist/types/components/MarkdownEditor/MarkdownEditor.d.ts.map +1 -1
  54. package/dist/types/components/MarkdownEditor/markdownEditor.content.d.ts +59 -0
  55. package/dist/types/components/MarkdownEditor/markdownEditor.content.d.ts.map +1 -1
  56. package/dist/types/components/MarkdownEditor/novel/components/editor.d.ts +5 -1
  57. package/dist/types/components/MarkdownEditor/novel/components/editor.d.ts.map +1 -1
  58. package/dist/types/components/MarkdownEditor/novel/extensions/image-resizer.d.ts +4 -0
  59. package/dist/types/components/MarkdownEditor/novel/extensions/image-resizer.d.ts.map +1 -1
  60. package/dist/types/components/MarkdownEditor/novel/extensions/slash-command.d.ts +4 -4
  61. package/dist/types/components/MarkdownEditor/novel/extensions/slash-command.d.ts.map +1 -1
  62. package/dist/types/components/Pagination/Pagination.d.ts +1 -1
  63. package/dist/types/components/SwitchSelector/SwitchSelector.d.ts +2 -2
  64. package/dist/types/components/SwitchSelector/VerticalSwitchSelector.d.ts +1 -1
  65. package/dist/types/components/TabSelector/TabSelector.d.ts +1 -1
  66. package/dist/types/components/Tag/index.d.ts +2 -2
  67. package/dist/types/routes.d.ts +3 -1
  68. package/dist/types/routes.d.ts.map +1 -1
  69. package/package.json +19 -21
  70. package/src/components/MarkdownEditor/markdown-editor.css +2 -8
@@ -1,16 +1,16 @@
1
1
  'use client';
2
2
 
3
3
  import { cn } from "../../../utils/cn.mjs";
4
- import { Loader } from "../../Loader/index.mjs";
5
- import { Button } from "../../Button/Button.mjs";
6
- import { Container } from "../../Container/index.mjs";
7
- import { Checkbox } from "../../Input/Checkbox.mjs";
8
- import { Input } from "../../Input/Input.mjs";
9
4
  import { useSession } from "../../../api/useAuth/useSession.mjs";
10
5
  import { useAuditContentDeclarationMetadata } from "../../../api/hooks/ai.mjs";
11
6
  import { useGetDictionaries } from "../../../api/hooks/dictionary.mjs";
12
7
  import { useGetProjects } from "../../../api/hooks/project.mjs";
13
8
  import { useGetTags } from "../../../api/hooks/tag.mjs";
9
+ import { Loader } from "../../Loader/index.mjs";
10
+ import { Button } from "../../Button/Button.mjs";
11
+ import { Container } from "../../Container/index.mjs";
12
+ import { Checkbox } from "../../Input/Checkbox.mjs";
13
+ import { Input } from "../../Input/Input.mjs";
14
14
  import { MultiSelect } from "../../Select/Multiselect.mjs";
15
15
  import { Select } from "../../Select/Select.mjs";
16
16
  import { Pagination } from "../../Pagination/Pagination.mjs";
@@ -30,8 +30,8 @@ import { useDictionaryDetailsSchema } from "./useDictionaryDetailsSchema.mjs";
30
30
  import { useEffect, useMemo, useState } from "react";
31
31
  import { WandSparkles } from "lucide-react";
32
32
  import { jsx, jsxs } from "react/jsx-runtime";
33
- import { useIntlayer } from "react-intlayer";
34
33
  import { useEditedContent } from "@intlayer/editor-react";
34
+ import { useIntlayer } from "react-intlayer";
35
35
  import { useWatch } from "react-hook-form";
36
36
  import { AnimatePresence, motion } from "framer-motion";
37
37
 
@@ -13,8 +13,8 @@ import { StructureEditor } from "./StructureEditor.mjs";
13
13
  import { useEffect, useState } from "react";
14
14
  import { ArrowLeft } from "lucide-react";
15
15
  import { jsx, jsxs } from "react/jsx-runtime";
16
- import { useIntlayer } from "react-intlayer";
17
16
  import { useConfiguration, useDictionariesRecordActions, useFocusUnmergedDictionary } from "@intlayer/editor-react";
17
+ import { useIntlayer } from "react-intlayer";
18
18
 
19
19
  //#region src/components/DictionaryFieldEditor/DictionaryFieldEditor.tsx
20
20
  const DictionaryFieldEditor = ({ dictionary, onClickDictionaryList, isDarkMode, mode, onDelete, onSave, showReturnButton = true, rightContent }) => {
@@ -5,8 +5,8 @@ import { getIsEditableSection } from "../getIsEditableSection.mjs";
5
5
  import { useState } from "react";
6
6
  import { ChevronRight, Plus } from "lucide-react";
7
7
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
- import { useIntlayer } from "react-intlayer";
9
8
  import { useEditedContentActions, useEditorLocale, useFocusUnmergedDictionary } from "@intlayer/editor-react";
9
+ import { useIntlayer } from "react-intlayer";
10
10
  import { getContentNodeByKeyPath, getEmptyNode, getNodeType } from "@intlayer/core/dictionaryManipulator";
11
11
  import * as NodeTypes from "@intlayer/types/nodeType";
12
12
  import { isSameKeyPath } from "@intlayer/core/utils";
@@ -1,17 +1,17 @@
1
1
  'use client';
2
2
 
3
3
  import { cn } from "../../../utils/cn.mjs";
4
- import { Button } from "../../Button/Button.mjs";
5
4
  import { useSession } from "../../../api/useAuth/useSession.mjs";
6
5
  import { useAuth } from "../../../api/useAuth/useAuth.mjs";
7
6
  import { useDeleteDictionary, usePushDictionaries } from "../../../api/hooks/dictionary.mjs";
8
7
  import { useWriteDictionary } from "../../../api/hooks/editor.mjs";
8
+ import { Button } from "../../Button/Button.mjs";
9
9
  import { Modal } from "../../Modal/Modal.mjs";
10
10
  import { useState } from "react";
11
11
  import { ArrowUpFromLine, Download, RotateCcw, Save, Trash } from "lucide-react";
12
12
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
13
- import { useIntlayer } from "react-intlayer";
14
13
  import { useDictionariesRecordActions, useEditedContent } from "@intlayer/editor-react";
14
+ import { useIntlayer } from "react-intlayer";
15
15
 
16
16
  //#region src/components/DictionaryFieldEditor/SaveForm/SaveForm.tsx
17
17
  const SaveForm = ({ dictionary, mode, className, onDelete, onSave, ...props }) => {
@@ -6,8 +6,8 @@ import { EditableFieldInput } from "../../EditableField/EditableFieldInput.mjs";
6
6
  import { NodeTypeSelector } from "../NodeTypeSelector.mjs";
7
7
  import { Plus, Trash } from "lucide-react";
8
8
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
- import { useIntlayer } from "react-intlayer";
10
9
  import { useConfiguration, useEditedContentActions, useFocusUnmergedDictionary } from "@intlayer/editor-react";
10
+ import { useIntlayer } from "react-intlayer";
11
11
  import { getDefaultNode, getNodeChildren, getNodeType } from "@intlayer/core/dictionaryManipulator";
12
12
  import * as NodeTypes from "@intlayer/types/nodeType";
13
13
  import { isSameKeyPath } from "@intlayer/core/utils";
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
 
3
- import { InputIndicator, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot } from "../../Input/OTPInput.mjs";
4
3
  import { useItemSelector } from "../../../hooks/useItemSelector.mjs";
4
+ import { InputIndicator, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot } from "../../Input/OTPInput.mjs";
5
5
  import { FormField, useFormField } from "../FormField.mjs";
6
6
  import { FormItemLayout } from "../layout/FormItemLayout.mjs";
7
7
  import { useEffect, useRef } from "react";
@@ -1,11 +1,11 @@
1
1
  'use client';
2
2
 
3
+ import { usePersistedStore } from "../../hooks/usePersistedStore.mjs";
3
4
  import { Button } from "../Button/Button.mjs";
4
5
  import { Container } from "../Container/index.mjs";
5
6
  import { DropDown } from "../DropDown/index.mjs";
6
7
  import { Input } from "../Input/Input.mjs";
7
8
  import { SwitchSelector } from "../SwitchSelector/SwitchSelector.mjs";
8
- import { usePersistedStore } from "../../hooks/usePersistedStore.mjs";
9
9
  import { useLocaleSwitcherContent } from "./LocaleSwitcherContentContext.mjs";
10
10
  import { useMemo, useRef, useState } from "react";
11
11
  import { Check, Globe, MoveVertical } from "lucide-react";
@@ -46,7 +46,6 @@ const MarkdownEditor = ({ defaultValue, onChange, editable = true, enableAI = tr
46
46
  suggestionItems: items
47
47
  };
48
48
  }, [uploadFn, content]);
49
- const initialContent = defaultValue ?? "";
50
49
  const handleUpdate = ({ editor }) => {
51
50
  onChange?.(editor.storage.markdown.getMarkdown());
52
51
  };
@@ -64,7 +63,7 @@ const MarkdownEditor = ({ defaultValue, onChange, editable = true, enableAI = tr
64
63
  children: /* @__PURE__ */ jsx(EditorRoot, { children: /* @__PURE__ */ jsxs(EditorContent, {
65
64
  immediatelyRender: false,
66
65
  editable,
67
- initialContent,
66
+ initialContent: defaultValue ?? "",
68
67
  extensions,
69
68
  className: cn("min-h-[350px] w-full max-w-full", className),
70
69
  editorProps: {
@@ -76,7 +75,7 @@ const MarkdownEditor = ({ defaultValue, onChange, editable = true, enableAI = tr
76
75
  onUpdate: handleUpdate,
77
76
  slotAfter: /* @__PURE__ */ jsx(ImageResizer, {}),
78
77
  children: [/* @__PURE__ */ jsxs(EditorCommand, {
79
- className: "z-50 h-auto max-h-[330px] overflow-y-auto px-1 py-2 shadow-md transition-all",
78
+ className: "z-50 h-auto max-h-[330px] overflow-y-auto rounded-lg border border-neutral/20 bg-card px-1 py-2 text-text shadow-xl transition-all",
80
79
  children: [/* @__PURE__ */ jsx(EditorCommandEmpty, {
81
80
  className: "px-2 text-muted-foreground",
82
81
  children: content.noResults.value
@@ -1 +1 @@
1
- {"version":3,"file":"MarkdownEditor.mjs","names":[],"sources":["../../../../src/components/MarkdownEditor/MarkdownEditor.tsx"],"sourcesContent":["'use client';\n\nimport { cn } from '@utils/cn';\nimport { type FC, useMemo, useState } from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { defaultExtensions } from './extensions';\nimport { GenerativeMenuSwitch } from './generative/GenerativeMenuSwitch';\nimport {\n type CreateEditorUploadFnOptions,\n createEditorUploadFn,\n} from './imageUpload';\nimport {\n EditorBubble,\n EditorCommand,\n EditorCommandEmpty,\n EditorCommandItem,\n EditorCommandList,\n EditorContent,\n type EditorInstance,\n EditorRoot,\n handleCommandNavigation,\n handleImageDrop,\n handleImagePaste,\n ImageResizer,\n type JSONContent,\n} from './novel';\nimport { ColorSelector } from './selectors/ColorSelector';\nimport { LinkSelector } from './selectors/LinkSelector';\nimport { NodeSelector } from './selectors/NodeSelector';\nimport { TextButtons } from './selectors/TextButtons';\nimport { createSlashCommand } from './slashCommand';\n\nconst Divider = () => <div className=\"h-full w-px shrink-0 bg-border\" />;\n\nexport type MarkdownEditorProps = {\n /** Initial markdown value. */\n defaultValue?: string;\n /** Called with the serialized markdown on every change. */\n onChange?: (markdown: string) => void;\n /** Whether the document can be edited. Defaults to `true`. */\n editable?: boolean;\n /** Enables the AI bubble menu (\"Ask AI\"). Defaults to `true`. */\n enableAI?: boolean;\n /**\n * Custom image uploader. When omitted, images are embedded inline as base64\n * data URLs (no backend required).\n */\n uploadImage?: CreateEditorUploadFnOptions['uploadImage'];\n /** Maximum allowed image size in megabytes. Defaults to `20`. */\n maxImageSizeMb?: number;\n /** Class applied to the editor surface. */\n className?: string;\n};\n\n/**\n * Notion-style WYSIWYG markdown editor built on Novel / Tiptap.\n *\n * Features a slash command menu, a formatting bubble menu (node / link / color\n * / inline marks), image upload (drop / paste / slash), and an optional\n * AI assistant wired to the Intlayer AI backend.\n *\n * The value contract is markdown: pass `defaultValue` as a markdown string and\n * read changes from `onChange`.\n */\nexport const MarkdownEditor: FC<MarkdownEditorProps> = ({\n defaultValue,\n onChange,\n editable = true,\n enableAI = true,\n uploadImage,\n maxImageSizeMb,\n className,\n}) => {\n const [openAI, setOpenAI] = useState(false);\n const content = useIntlayer('markdown-editor');\n\n const uploadFn = useMemo(\n () => createEditorUploadFn({ uploadImage, maxSizeMb: maxImageSizeMb }),\n [uploadImage, maxImageSizeMb]\n );\n\n const { extensions, suggestionItems } = useMemo(() => {\n const { slashCommand, suggestionItems: items } = createSlashCommand(\n uploadFn,\n content\n );\n\n return {\n extensions: [...defaultExtensions, slashCommand],\n suggestionItems: items,\n };\n }, [uploadFn, content]);\n\n const initialContent = (defaultValue ?? '') as unknown as JSONContent;\n\n const handleUpdate = ({ editor }: { editor: EditorInstance }) => {\n onChange?.(editor.storage.markdown.getMarkdown() as string);\n };\n\n const toolbar = (\n <>\n <NodeSelector />\n <Divider />\n <LinkSelector />\n <Divider />\n <TextButtons />\n <Divider />\n <ColorSelector />\n </>\n );\n\n return (\n <div className=\"relative w-full\">\n <EditorRoot>\n <EditorContent\n immediatelyRender={false}\n editable={editable}\n initialContent={initialContent}\n extensions={extensions}\n className={cn('min-h-[350px] w-full max-w-full', className)}\n editorProps={{\n handleDOMEvents: {\n keydown: (_view, event) => handleCommandNavigation(event),\n },\n handlePaste: (view, event) =>\n handleImagePaste(view, event, uploadFn),\n handleDrop: (view, event, _slice, moved) =>\n handleImageDrop(view, event, moved, uploadFn),\n attributes: {\n // Content typography (headings, lists, spacing) is defined in\n // `markdown-editor.css`, scoped to `.ProseMirror` — this project\n // has no Tailwind `prose` plugin.\n class: 'max-w-full pl-6 focus:outline-none',\n },\n }}\n onUpdate={handleUpdate}\n slotAfter={<ImageResizer />}\n >\n <EditorCommand className=\"z-50 h-auto max-h-[330px] overflow-y-auto px-1 py-2 shadow-md transition-all\">\n <EditorCommandEmpty className=\"px-2 text-muted-foreground\">\n {content.noResults.value}\n </EditorCommandEmpty>\n <EditorCommandList>\n {suggestionItems.map((item) => (\n <EditorCommandItem\n value={item.title}\n onCommand={(val) => item.command?.(val)}\n className=\"flex w-full items-center space-x-2 rounded-md px-2 py-1 text-left text-sm hover:bg-accent aria-selected:bg-accent\"\n key={item.title}\n >\n <div className=\"flex size-10 items-center justify-center rounded-md border border-card bg-background\">\n {item.icon}\n </div>\n <div>\n <p className=\"font-medium\">{item.title}</p>\n <p className=\"text-muted-foreground text-xs\">\n {item.description}\n </p>\n </div>\n </EditorCommandItem>\n ))}\n </EditorCommandList>\n </EditorCommand>\n\n {enableAI ? (\n <GenerativeMenuSwitch open={openAI} onOpenChange={setOpenAI}>\n {toolbar}\n </GenerativeMenuSwitch>\n ) : (\n <EditorBubble\n options={{ placement: 'top' }}\n className=\"flex w-fit max-w-[90vw] rounded-lg border-[1.3px] border-neutral/20 bg-card/95 text-text shadow-xl backdrop-blur [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-xl\"\n >\n {toolbar}\n </EditorBubble>\n )}\n </EditorContent>\n </EditorRoot>\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAgCA,MAAM,gBAAgB,oBAAC,OAAD,EAAK,WAAU,kCAAmC;;;;;;;;;;;AAgCxE,MAAa,kBAA2C,EACtD,cACA,UACA,WAAW,MACX,WAAW,MACX,aACA,gBACA,gBACI;CACJ,MAAM,CAAC,QAAQ,aAAa,SAAS,MAAM;CAC3C,MAAM,UAAU,YAAY,kBAAkB;CAE9C,MAAM,WAAW,cACT,qBAAqB;EAAE;EAAa,WAAW;EAAgB,CAAC,EACtE,CAAC,aAAa,eAAe,CAC9B;CAED,MAAM,EAAE,YAAY,oBAAoB,cAAc;EACpD,MAAM,EAAE,cAAc,iBAAiB,UAAU,mBAC/C,UACA,QACD;AAED,SAAO;GACL,YAAY,CAAC,GAAG,mBAAmB,aAAa;GAChD,iBAAiB;GAClB;IACA,CAAC,UAAU,QAAQ,CAAC;CAEvB,MAAM,iBAAkB,gBAAgB;CAExC,MAAM,gBAAgB,EAAE,aAAyC;AAC/D,aAAW,OAAO,QAAQ,SAAS,aAAa,CAAW;;CAG7D,MAAM,UACJ;EACE,oBAAC,cAAD,EAAgB;EAChB,oBAAC,SAAD,EAAW;EACX,oBAAC,cAAD,EAAgB;EAChB,oBAAC,SAAD,EAAW;EACX,oBAAC,aAAD,EAAe;EACf,oBAAC,SAAD,EAAW;EACX,oBAAC,eAAD,EAAiB;EAChB;AAGL,QACE,oBAAC,OAAD;EAAK,WAAU;YACb,oBAAC,YAAD,YACE,qBAAC,eAAD;GACE,mBAAmB;GACT;GACM;GACJ;GACZ,WAAW,GAAG,mCAAmC,UAAU;GAC3D,aAAa;IACX,iBAAiB,EACf,UAAU,OAAO,UAAU,wBAAwB,MAAM,EAC1D;IACD,cAAc,MAAM,UAClB,iBAAiB,MAAM,OAAO,SAAS;IACzC,aAAa,MAAM,OAAO,QAAQ,UAChC,gBAAgB,MAAM,OAAO,OAAO,SAAS;IAC/C,YAAY,EAIV,OAAO,sCACR;IACF;GACD,UAAU;GACV,WAAW,oBAAC,cAAD,EAAgB;aAtB7B,CAwBE,qBAAC,eAAD;IAAe,WAAU;cAAzB,CACE,oBAAC,oBAAD;KAAoB,WAAU;eAC3B,QAAQ,UAAU;KACA,GACrB,oBAAC,mBAAD,YACG,gBAAgB,KAAK,SACpB,qBAAC,mBAAD;KACE,OAAO,KAAK;KACZ,YAAY,QAAQ,KAAK,UAAU,IAAI;KACvC,WAAU;eAHZ,CAME,oBAAC,OAAD;MAAK,WAAU;gBACZ,KAAK;MACF,GACN,qBAAC,OAAD,aACE,oBAAC,KAAD;MAAG,WAAU;gBAAe,KAAK;MAAU,GAC3C,oBAAC,KAAD;MAAG,WAAU;gBACV,KAAK;MACJ,EACA,IACY;OAXb,KAAK,MAWQ,CACpB,EACgB,EACN;OAEf,WACC,oBAAC,sBAAD;IAAsB,MAAM;IAAQ,cAAc;cAC/C;IACoB,IAEvB,oBAAC,cAAD;IACE,SAAS,EAAE,WAAW,OAAO;IAC7B,WAAU;cAET;IACY,EAEH;MACL;EACT"}
1
+ {"version":3,"file":"MarkdownEditor.mjs","names":[],"sources":["../../../../src/components/MarkdownEditor/MarkdownEditor.tsx"],"sourcesContent":["'use client';\n\nimport { cn } from '@utils/cn';\nimport { type FC, useMemo, useState } from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { defaultExtensions } from './extensions';\nimport { GenerativeMenuSwitch } from './generative/GenerativeMenuSwitch';\nimport {\n type CreateEditorUploadFnOptions,\n createEditorUploadFn,\n} from './imageUpload';\nimport {\n EditorBubble,\n EditorCommand,\n EditorCommandEmpty,\n EditorCommandItem,\n EditorCommandList,\n EditorContent,\n type EditorInstance,\n EditorRoot,\n handleCommandNavigation,\n handleImageDrop,\n handleImagePaste,\n ImageResizer,\n} from './novel';\nimport { ColorSelector } from './selectors/ColorSelector';\nimport { LinkSelector } from './selectors/LinkSelector';\nimport { NodeSelector } from './selectors/NodeSelector';\nimport { TextButtons } from './selectors/TextButtons';\nimport { createSlashCommand } from './slashCommand';\n\nconst Divider = () => <div className=\"h-full w-px shrink-0 bg-border\" />;\n\nexport type MarkdownEditorProps = {\n /** Initial markdown value. */\n defaultValue?: string;\n /** Called with the serialized markdown on every change. */\n onChange?: (markdown: string) => void;\n /** Whether the document can be edited. Defaults to `true`. */\n editable?: boolean;\n /** Enables the AI bubble menu (\"Ask AI\"). Defaults to `true`. */\n enableAI?: boolean;\n /**\n * Custom image uploader. When omitted, images are embedded inline as base64\n * data URLs (no backend required).\n */\n uploadImage?: CreateEditorUploadFnOptions['uploadImage'];\n /** Maximum allowed image size in megabytes. Defaults to `20`. */\n maxImageSizeMb?: number;\n /** Class applied to the editor surface. */\n className?: string;\n};\n\n/**\n * Notion-style WYSIWYG markdown editor built on Novel / Tiptap.\n *\n * Features a slash command menu, a formatting bubble menu (node / link / color\n * / inline marks), image upload (drop / paste / slash), and an optional\n * AI assistant wired to the Intlayer AI backend.\n *\n * The value contract is markdown: pass `defaultValue` as a markdown string and\n * read changes from `onChange`.\n */\nexport const MarkdownEditor: FC<MarkdownEditorProps> = ({\n defaultValue,\n onChange,\n editable = true,\n enableAI = true,\n uploadImage,\n maxImageSizeMb,\n className,\n}) => {\n const [openAI, setOpenAI] = useState(false);\n const content = useIntlayer('markdown-editor');\n\n const uploadFn = useMemo(\n () => createEditorUploadFn({ uploadImage, maxSizeMb: maxImageSizeMb }),\n [uploadImage, maxImageSizeMb]\n );\n\n const { extensions, suggestionItems } = useMemo(() => {\n const { slashCommand, suggestionItems: items } = createSlashCommand(\n uploadFn,\n content\n );\n\n return {\n extensions: [...defaultExtensions, slashCommand],\n suggestionItems: items,\n };\n }, [uploadFn, content]);\n\n const handleUpdate = ({ editor }: { editor: EditorInstance }) => {\n onChange?.(editor.storage.markdown.getMarkdown() as string);\n };\n\n const toolbar = (\n <>\n <NodeSelector />\n <Divider />\n <LinkSelector />\n <Divider />\n <TextButtons />\n <Divider />\n <ColorSelector />\n </>\n );\n\n return (\n <div className=\"relative w-full\">\n <EditorRoot>\n <EditorContent\n immediatelyRender={false}\n editable={editable}\n initialContent={defaultValue ?? ''}\n extensions={extensions}\n className={cn('min-h-[350px] w-full max-w-full', className)}\n editorProps={{\n handleDOMEvents: {\n keydown: (_view, event) => handleCommandNavigation(event),\n },\n handlePaste: (view, event) =>\n handleImagePaste(view, event, uploadFn),\n handleDrop: (view, event, _slice, moved) =>\n handleImageDrop(view, event, moved, uploadFn),\n attributes: {\n // Content typography (headings, lists, spacing) is defined in\n // `markdown-editor.css`, scoped to `.ProseMirror` — this project\n // has no Tailwind `prose` plugin.\n class: 'max-w-full pl-6 focus:outline-none',\n },\n }}\n onUpdate={handleUpdate}\n slotAfter={<ImageResizer />}\n >\n <EditorCommand className=\"z-50 h-auto max-h-[330px] overflow-y-auto rounded-lg border border-neutral/20 bg-card px-1 py-2 text-text shadow-xl transition-all\">\n <EditorCommandEmpty className=\"px-2 text-muted-foreground\">\n {content.noResults.value}\n </EditorCommandEmpty>\n <EditorCommandList>\n {suggestionItems.map((item) => (\n <EditorCommandItem\n value={item.title}\n onCommand={(val) => item.command?.(val)}\n className=\"flex w-full items-center space-x-2 rounded-md px-2 py-1 text-left text-sm hover:bg-accent aria-selected:bg-accent\"\n key={item.title}\n >\n <div className=\"flex size-10 items-center justify-center rounded-md border border-card bg-background\">\n {item.icon}\n </div>\n <div>\n <p className=\"font-medium\">{item.title}</p>\n <p className=\"text-muted-foreground text-xs\">\n {item.description}\n </p>\n </div>\n </EditorCommandItem>\n ))}\n </EditorCommandList>\n </EditorCommand>\n\n {enableAI ? (\n <GenerativeMenuSwitch open={openAI} onOpenChange={setOpenAI}>\n {toolbar}\n </GenerativeMenuSwitch>\n ) : (\n <EditorBubble\n options={{ placement: 'top' }}\n className=\"flex w-fit max-w-[90vw] rounded-lg border-[1.3px] border-neutral/20 bg-card/95 text-text shadow-xl backdrop-blur [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-xl\"\n >\n {toolbar}\n </EditorBubble>\n )}\n </EditorContent>\n </EditorRoot>\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AA+BA,MAAM,gBAAgB,oBAAC,OAAD,EAAK,WAAU,kCAAmC;;;;;;;;;;;AAgCxE,MAAa,kBAA2C,EACtD,cACA,UACA,WAAW,MACX,WAAW,MACX,aACA,gBACA,gBACI;CACJ,MAAM,CAAC,QAAQ,aAAa,SAAS,MAAM;CAC3C,MAAM,UAAU,YAAY,kBAAkB;CAE9C,MAAM,WAAW,cACT,qBAAqB;EAAE;EAAa,WAAW;EAAgB,CAAC,EACtE,CAAC,aAAa,eAAe,CAC9B;CAED,MAAM,EAAE,YAAY,oBAAoB,cAAc;EACpD,MAAM,EAAE,cAAc,iBAAiB,UAAU,mBAC/C,UACA,QACD;AAED,SAAO;GACL,YAAY,CAAC,GAAG,mBAAmB,aAAa;GAChD,iBAAiB;GAClB;IACA,CAAC,UAAU,QAAQ,CAAC;CAEvB,MAAM,gBAAgB,EAAE,aAAyC;AAC/D,aAAW,OAAO,QAAQ,SAAS,aAAa,CAAW;;CAG7D,MAAM,UACJ;EACE,oBAAC,cAAD,EAAgB;EAChB,oBAAC,SAAD,EAAW;EACX,oBAAC,cAAD,EAAgB;EAChB,oBAAC,SAAD,EAAW;EACX,oBAAC,aAAD,EAAe;EACf,oBAAC,SAAD,EAAW;EACX,oBAAC,eAAD,EAAiB;EAChB;AAGL,QACE,oBAAC,OAAD;EAAK,WAAU;YACb,oBAAC,YAAD,YACE,qBAAC,eAAD;GACE,mBAAmB;GACT;GACV,gBAAgB,gBAAgB;GACpB;GACZ,WAAW,GAAG,mCAAmC,UAAU;GAC3D,aAAa;IACX,iBAAiB,EACf,UAAU,OAAO,UAAU,wBAAwB,MAAM,EAC1D;IACD,cAAc,MAAM,UAClB,iBAAiB,MAAM,OAAO,SAAS;IACzC,aAAa,MAAM,OAAO,QAAQ,UAChC,gBAAgB,MAAM,OAAO,OAAO,SAAS;IAC/C,YAAY,EAIV,OAAO,sCACR;IACF;GACD,UAAU;GACV,WAAW,oBAAC,cAAD,EAAgB;aAtB7B,CAwBE,qBAAC,eAAD;IAAe,WAAU;cAAzB,CACE,oBAAC,oBAAD;KAAoB,WAAU;eAC3B,QAAQ,UAAU;KACA,GACrB,oBAAC,mBAAD,YACG,gBAAgB,KAAK,SACpB,qBAAC,mBAAD;KACE,OAAO,KAAK;KACZ,YAAY,QAAQ,KAAK,UAAU,IAAI;KACvC,WAAU;eAHZ,CAME,oBAAC,OAAD;MAAK,WAAU;gBACZ,KAAK;MACF,GACN,qBAAC,OAAD,aACE,oBAAC,KAAD;MAAG,WAAU;gBAAe,KAAK;MAAU,GAC3C,oBAAC,KAAD;MAAG,WAAU;gBACV,KAAK;MACJ,EACA,IACY;OAXb,KAAK,MAWQ,CACpB,EACgB,EACN;OAEf,WACC,oBAAC,sBAAD;IAAsB,MAAM;IAAQ,cAAc;cAC/C;IACoB,IAEvB,oBAAC,cAAD;IACE,SAAS,EAAE,WAAW,OAAO;IAC7B,WAAU;cAET;IACY,EAEH;MACL;EACT"}