@llui/markdown-editor 0.2.5 → 0.2.6
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../src/plugins/image.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../src/plugins/image.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAgFhD,MAAM,WAAW,kBAAkB;IACjC;kDAC8C;IAC9C,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;CACzC;AAED,wBAAgB,WAAW,CAAC,IAAI,GAAE,kBAAuB,GAAG,cAAc,CA2HzE"}
|
package/dist/plugins/image.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image.js","sourceRoot":"","sources":["../../src/plugins/image.ts"],"names":[],"mappings":"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","sourcesContent":["// Image plugin — a block image rendered via the decorator bridge, round-tripping\n// to `` markdown, inserted through a plugin-UI dialog (URL + alt, with\n// optional file upload). Exercises decorator rendering + a transformer + the\n// plugin-UI extension all at once.\n\nimport {\n $getSelection,\n $setSelection,\n type BaseSelection,\n type ElementNode,\n type LexicalNode,\n} from 'lexical'\nimport { $insertNodeToNearestRoot } from '@lexical/utils'\nimport type { ElementTransformer } from '@lexical/markdown'\nimport {\n $createLLuiDecoratorNode,\n $isLLuiDecoratorNode,\n LLuiDecoratorNode,\n decoratorBridge,\n} from '@llui/lexical'\nimport { button, component, div, img, input, text, type Signal } from '@llui/dom'\nimport {\n connect as connectDialog,\n overlay as overlayDialog,\n type DialogMsg,\n} from '@llui/components/dialog'\nimport { definePluginUI } from './ui.js'\nimport type { MarkdownPlugin } from './types.js'\n\nconst BRIDGE_TYPE = 'image'\n\ninterface ImageData {\n src: string\n alt: string\n}\n\nfunction isImageData(value: unknown): value is ImageData {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as ImageData).src === 'string' &&\n typeof (value as ImageData).alt === 'string'\n )\n}\n\nconst imageBridge = decoratorBridge<ImageData, ImageData, { type: 'noop' }, never>(\n BRIDGE_TYPE,\n (data) =>\n component<ImageData, { type: 'noop' }, never>({\n name: 'Image',\n init: () => ({ src: data.src, alt: data.alt }),\n update: (state) => state,\n view: ({ state }) => [\n div({ 'data-scope': 'md-image', 'data-part': 'root', contenteditable: 'false' }, [\n img({ src: state.at('src') as Signal<string>, alt: state.at('alt') as Signal<string> }),\n ]),\n ],\n }),\n)\n\nconst IMAGE_TRANSFORMER: ElementTransformer = {\n dependencies: [LLuiDecoratorNode],\n export: (node: LexicalNode): string | null => {\n if (!$isLLuiDecoratorNode(node) || node.getBridgeType() !== BRIDGE_TYPE) return null\n const data = node.getData()\n return isImageData(data) ? `` : null\n },\n regExp: /^!\\[([^\\]]*)\\]\\(([^)]+)\\)$/,\n replace: (parentNode: ElementNode, _children, match): void => {\n parentNode.replace(\n $createLLuiDecoratorNode(BRIDGE_TYPE, { alt: match[1] ?? '', src: match[2] ?? '' }),\n )\n },\n type: 'element',\n}\n\ninterface ImageState {\n dialog: { open: boolean }\n src: string\n alt: string\n}\n\ntype ImageMsg =\n | { type: 'open' }\n | { type: 'setSrc'; src: string }\n | { type: 'setAlt'; alt: string }\n | { type: 'submit' }\n | { type: 'dialog'; msg: DialogMsg }\n\ntype ImageEffect = { type: 'begin' } | { type: 'insert'; src: string; alt: string }\n\nfunction dialogOpen(msg: DialogMsg, current: boolean): boolean {\n switch (msg.type) {\n case 'open':\n return true\n case 'close':\n return false\n case 'toggle':\n return !current\n case 'setOpen':\n return msg.open\n }\n}\n\nexport interface ImagePluginOptions {\n /** Upload a chosen file and resolve to its URL. When omitted, the file picker\n * is hidden and only URL entry is offered. */\n upload?: (file: File) => Promise<string>\n}\n\nexport function imagePlugin(opts: ImagePluginOptions = {}): MarkdownPlugin {\n let savedSelection: BaseSelection | null = null\n\n return {\n name: 'image',\n nodes: [LLuiDecoratorNode],\n decorators: [imageBridge],\n transformers: [IMAGE_TRANSFORMER],\n items: [\n {\n id: 'image',\n label: 'Image',\n icon: 'image',\n group: 'insert',\n keywords: ['img', 'picture', 'photo'],\n run: (_editor, ctx) => ctx.send({ type: 'plugin', name: 'image', msg: { type: 'open' } }),\n surfaces: ['toolbar', 'slash', 'context'],\n },\n ],\n ui: definePluginUI<ImageState, ImageMsg, ImageEffect>({\n init: () => ({ dialog: { open: false }, src: '', alt: '' }),\n update: (state, msg) => {\n switch (msg.type) {\n case 'open':\n return [{ dialog: { open: true }, src: '', alt: '' }, [{ type: 'begin' }]]\n case 'setSrc':\n return { ...state, src: msg.src }\n case 'setAlt':\n return { ...state, alt: msg.alt }\n case 'submit':\n return [\n { ...state, dialog: { open: false } },\n [{ type: 'insert', src: state.src, alt: state.alt }],\n ]\n case 'dialog': {\n const open = dialogOpen(msg.msg, state.dialog.open)\n return open === state.dialog.open ? state : { ...state, dialog: { open } }\n }\n }\n },\n view: ({ state, send }) => {\n const dialogSend = (msg: DialogMsg): void => send({ type: 'dialog', msg })\n const parts = connectDialog(state.at('dialog'), dialogSend, {\n id: 'md-image-dialog',\n closeLabel: 'Cancel',\n })\n return [\n overlayDialog({\n state: state.at('dialog'),\n send: dialogSend,\n parts,\n content: () => [\n div({ ...parts.content, 'data-md-link': 'box' }, [\n div({ ...parts.title, 'data-md-link': 'title' }, [text('Insert image')]),\n input({\n 'data-md-link': 'input',\n type: 'url',\n placeholder: 'https://example.com/image.png',\n value: state.at('src') as Signal<string>,\n onInput: (e: Event) =>\n send({ type: 'setSrc', src: (e.target as HTMLInputElement).value }),\n }),\n input({\n 'data-md-link': 'input',\n 'data-md-image': 'alt',\n type: 'text',\n placeholder: 'Alt text (description)',\n value: state.at('alt') as Signal<string>,\n onInput: (e: Event) =>\n send({ type: 'setAlt', alt: (e.target as HTMLInputElement).value }),\n }),\n ...(opts.upload\n ? [\n input({\n 'data-md-image': 'file',\n type: 'file',\n accept: 'image/*',\n onChange: (e: Event) => {\n const file = (e.target as HTMLInputElement).files?.[0]\n if (file && opts.upload) {\n void opts.upload(file).then((src) => send({ type: 'setSrc', src }))\n }\n },\n }),\n ]\n : []),\n div({ 'data-md-link': 'actions' }, [\n button({ ...parts.closeTrigger, 'data-md-link': 'cancel' }, [text('Cancel')]),\n button(\n {\n type: 'button',\n 'data-md-link': 'apply',\n onClick: () => send({ type: 'submit' }),\n },\n [text('Insert')],\n ),\n ]),\n ]),\n ],\n }),\n ]\n },\n onEffect: (effect, ctx) => {\n const editor = ctx.editor()\n if (!editor) return\n if (effect.type === 'begin') {\n savedSelection = editor.getEditorState().read(() => {\n const selection = $getSelection()\n return selection ? selection.clone() : null\n })\n return\n }\n if (effect.src.trim() === '') return\n editor.update(() => {\n if (savedSelection) $setSelection(savedSelection.clone())\n $insertNodeToNearestRoot(\n $createLLuiDecoratorNode(BRIDGE_TYPE, { src: effect.src.trim(), alt: effect.alt }),\n )\n })\n savedSelection = null\n },\n }),\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"image.js","sourceRoot":"","sources":["../../src/plugins/image.ts"],"names":[],"mappings":"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","sourcesContent":["// Image plugin — a block image rendered via the decorator bridge, round-tripping\n// to `` markdown, inserted through a plugin-UI dialog (URL + alt, with\n// optional file upload). Exercises decorator rendering + a transformer + the\n// plugin-UI extension all at once.\n\nimport {\n $getSelection,\n $setSelection,\n type BaseSelection,\n type ElementNode,\n type LexicalNode,\n} from 'lexical'\nimport { $insertNodeToNearestRoot } from '@lexical/utils'\nimport type { ElementTransformer } from '@lexical/markdown'\nimport {\n $createLLuiDecoratorNode,\n $isLLuiDecoratorNode,\n LLuiDecoratorNode,\n decoratorBridge,\n} from '@llui/lexical'\nimport { button, component, div, img, input, text, type Signal } from '@llui/dom'\nimport {\n connect as connectDialog,\n overlay as overlayDialog,\n type DialogMsg,\n} from '@llui/components/dialog'\nimport { definePluginUI } from './ui.js'\nimport type { MarkdownPlugin } from './types.js'\n\nconst BRIDGE_TYPE = 'image'\n\ninterface ImageData {\n src: string\n alt: string\n}\n\nfunction isImageData(value: unknown): value is ImageData {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as ImageData).src === 'string' &&\n typeof (value as ImageData).alt === 'string'\n )\n}\n\nconst imageBridge = decoratorBridge<ImageData, ImageData, { type: 'noop' }, never>(\n BRIDGE_TYPE,\n (data) =>\n component<ImageData, { type: 'noop' }, never>({\n name: 'Image',\n init: () => ({ src: data.src, alt: data.alt }),\n update: (state) => state,\n view: ({ state }) => [\n div({ 'data-scope': 'md-image', 'data-part': 'root', contenteditable: 'false' }, [\n img({ src: state.at('src') as Signal<string>, alt: state.at('alt') as Signal<string> }),\n ]),\n ],\n }),\n)\n\nconst IMAGE_TRANSFORMER: ElementTransformer = {\n dependencies: [LLuiDecoratorNode],\n export: (node: LexicalNode): string | null => {\n if (!$isLLuiDecoratorNode(node) || node.getBridgeType() !== BRIDGE_TYPE) return null\n const data = node.getData()\n return isImageData(data) ? `` : null\n },\n regExp: /^!\\[([^\\]]*)\\]\\(([^)]+)\\)$/,\n replace: (parentNode: ElementNode, _children, match): void => {\n parentNode.replace(\n $createLLuiDecoratorNode(BRIDGE_TYPE, { alt: match[1] ?? '', src: match[2] ?? '' }),\n )\n },\n type: 'element',\n}\n\ninterface ImageState {\n dialog: { open: boolean }\n src: string\n alt: string\n}\n\ntype ImageMsg =\n | { type: 'open' }\n | { type: 'setSrc'; src: string }\n | { type: 'setAlt'; alt: string }\n | { type: 'submit' }\n | { type: 'dialog'; msg: DialogMsg }\n\ntype ImageEffect = { type: 'begin' } | { type: 'insert'; src: string; alt: string }\n\nfunction dialogOpen(msg: DialogMsg, current: boolean): boolean {\n switch (msg.type) {\n case 'open':\n return true\n case 'close':\n return false\n case 'toggle':\n return !current\n case 'setOpen':\n return msg.open\n case 'animationEnd':\n case 'transitionEnd':\n return current\n }\n}\n\nexport interface ImagePluginOptions {\n /** Upload a chosen file and resolve to its URL. When omitted, the file picker\n * is hidden and only URL entry is offered. */\n upload?: (file: File) => Promise<string>\n}\n\nexport function imagePlugin(opts: ImagePluginOptions = {}): MarkdownPlugin {\n let savedSelection: BaseSelection | null = null\n\n return {\n name: 'image',\n nodes: [LLuiDecoratorNode],\n decorators: [imageBridge],\n transformers: [IMAGE_TRANSFORMER],\n items: [\n {\n id: 'image',\n label: 'Image',\n icon: 'image',\n group: 'insert',\n keywords: ['img', 'picture', 'photo'],\n run: (_editor, ctx) => ctx.send({ type: 'plugin', name: 'image', msg: { type: 'open' } }),\n surfaces: ['toolbar', 'slash', 'context'],\n },\n ],\n ui: definePluginUI<ImageState, ImageMsg, ImageEffect>({\n init: () => ({ dialog: { open: false }, src: '', alt: '' }),\n update: (state, msg) => {\n switch (msg.type) {\n case 'open':\n return [{ dialog: { open: true }, src: '', alt: '' }, [{ type: 'begin' }]]\n case 'setSrc':\n return { ...state, src: msg.src }\n case 'setAlt':\n return { ...state, alt: msg.alt }\n case 'submit':\n return [\n { ...state, dialog: { open: false } },\n [{ type: 'insert', src: state.src, alt: state.alt }],\n ]\n case 'dialog': {\n const open = dialogOpen(msg.msg, state.dialog.open)\n return open === state.dialog.open ? state : { ...state, dialog: { open } }\n }\n }\n },\n view: ({ state, send }) => {\n const dialogSend = (msg: DialogMsg): void => send({ type: 'dialog', msg })\n const parts = connectDialog(state.at('dialog'), dialogSend, {\n id: 'md-image-dialog',\n closeLabel: 'Cancel',\n })\n return [\n overlayDialog({\n state: state.at('dialog'),\n send: dialogSend,\n parts,\n content: () => [\n div({ ...parts.content, 'data-md-link': 'box' }, [\n div({ ...parts.title, 'data-md-link': 'title' }, [text('Insert image')]),\n input({\n 'data-md-link': 'input',\n type: 'url',\n placeholder: 'https://example.com/image.png',\n value: state.at('src') as Signal<string>,\n onInput: (e: Event) =>\n send({ type: 'setSrc', src: (e.target as HTMLInputElement).value }),\n }),\n input({\n 'data-md-link': 'input',\n 'data-md-image': 'alt',\n type: 'text',\n placeholder: 'Alt text (description)',\n value: state.at('alt') as Signal<string>,\n onInput: (e: Event) =>\n send({ type: 'setAlt', alt: (e.target as HTMLInputElement).value }),\n }),\n ...(opts.upload\n ? [\n input({\n 'data-md-image': 'file',\n type: 'file',\n accept: 'image/*',\n onChange: (e: Event) => {\n const file = (e.target as HTMLInputElement).files?.[0]\n if (file && opts.upload) {\n void opts.upload(file).then((src) => send({ type: 'setSrc', src }))\n }\n },\n }),\n ]\n : []),\n div({ 'data-md-link': 'actions' }, [\n button({ ...parts.closeTrigger, 'data-md-link': 'cancel' }, [text('Cancel')]),\n button(\n {\n type: 'button',\n 'data-md-link': 'apply',\n onClick: () => send({ type: 'submit' }),\n },\n [text('Insert')],\n ),\n ]),\n ]),\n ],\n }),\n ]\n },\n onEffect: (effect, ctx) => {\n const editor = ctx.editor()\n if (!editor) return\n if (effect.type === 'begin') {\n savedSelection = editor.getEditorState().read(() => {\n const selection = $getSelection()\n return selection ? selection.clone() : null\n })\n return\n }\n if (effect.src.trim() === '') return\n editor.update(() => {\n if (savedSelection) $setSelection(savedSelection.clone())\n $insertNodeToNearestRoot(\n $createLLuiDecoratorNode(BRIDGE_TYPE, { src: effect.src.trim(), alt: effect.alt }),\n )\n })\n savedSelection = null\n },\n }),\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../src/plugins/link.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAe,cAAc,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../src/plugins/link.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAe,cAAc,EAAE,MAAM,YAAY,CAAA;AA4C7D,MAAM,WAAW,iBAAiB;IAChC,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,wBAAgB,UAAU,CAAC,IAAI,GAAE,iBAAsB,GAAG,cAAc,CAkEvE"}
|
package/dist/plugins/link.js
CHANGED
package/dist/plugins/link.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link.js","sourceRoot":"","sources":["../../src/plugins/link.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,gFAAgF;AAChF,iFAAiF;AACjF,8EAA8E;AAE9E,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,aAAa,GAGd,MAAM,SAAS,CAAA;AAChB,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAA;AACpD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAExD,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAGxC,MAAM,MAAM,GAAG,MAAM,CAAA;AAgBrB,+EAA+E;AAC/E,SAAS,WAAW,CAAC,MAAqB;IACxC,OAAO,MAAM,CAAC,cAAc,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;QACvC,MAAM,SAAS,GAAG,aAAa,EAAE,CAAA;QACjC,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC;YAAE,OAAO,EAAE,CAAA;QAC5C,MAAM,IAAI,GAAG,mBAAmB,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAA;QACzF,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IAC/C,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,GAAc,EAAE,OAAgB;IAClD,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;QACjB,KAAK,MAAM;YACT,OAAO,IAAI,CAAA;QACb,KAAK,OAAO;YACV,OAAO,KAAK,CAAA;QACd,KAAK,QAAQ;YACX,OAAO,CAAC,OAAO,CAAA;QACjB,KAAK,SAAS;YACZ,OAAO,GAAG,CAAC,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"link.js","sourceRoot":"","sources":["../../src/plugins/link.ts"],"names":[],"mappings":"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","sourcesContent":["// The link plugin — a stateful, UI-bearing feature built entirely as a plugin\n// (no core editor changes). It owns its dialog state, its view (the modal), and\n// its effects (save/restore selection + toggle the link). This is the proof that\n// the plugin-UI extension makes such features pluggable rather than built-in.\n\nimport {\n $getSelection,\n $isRangeSelection,\n $setSelection,\n type BaseSelection,\n type LexicalEditor,\n} from 'lexical'\nimport { $findMatchingParent } from '@lexical/utils'\nimport { $isLinkNode, $toggleLink } from '@lexical/link'\nimport type { DialogMsg, DialogState } from '@llui/components/dialog'\nimport { linkDialog } from '../surfaces/link-dialog.js'\nimport { definePluginUI } from './ui.js'\nimport type { CommandItem, MarkdownPlugin } from './types.js'\n\nconst PLUGIN = 'link'\n\ninterface LinkState {\n dialog: DialogState\n url: string\n}\n\ntype LinkMsg =\n | { type: 'open' }\n | { type: 'show'; url: string }\n | { type: 'setUrl'; url: string }\n | { type: 'submit' }\n | { type: 'dialog'; msg: DialogMsg }\n\ntype LinkEffect = { type: 'begin' } | { type: 'commit'; url: string }\n\n/** Read the URL of the link wrapping the current selection (empty if none). */\nfunction readLinkUrl(editor: LexicalEditor): string {\n return editor.getEditorState().read(() => {\n const selection = $getSelection()\n if (!$isRangeSelection(selection)) return ''\n const link = $findMatchingParent(selection.anchor.getNode(), (node) => $isLinkNode(node))\n return $isLinkNode(link) ? link.getURL() : ''\n })\n}\n\nfunction dialogOpen(msg: DialogMsg, current: boolean): boolean {\n switch (msg.type) {\n case 'open':\n return true\n case 'close':\n return false\n case 'toggle':\n return !current\n case 'setOpen':\n return msg.open\n case 'animationEnd':\n case 'transitionEnd':\n return current\n }\n}\n\nexport interface LinkPluginOptions {\n /** Default URL pre-filled when there's no existing link (default ''). */\n defaultUrl?: string\n}\n\nexport function linkPlugin(opts: LinkPluginOptions = {}): MarkdownPlugin {\n // Selection saved when the dialog opens (the modal steals focus/selection),\n // restored on commit. Encapsulated in the plugin instance — not the core editor.\n let savedSelection: BaseSelection | null = null\n\n const item: CommandItem = {\n id: 'link',\n label: 'Link',\n icon: 'link',\n group: 'inline',\n keywords: ['url', 'href'],\n run: (_editor, ctx) => ctx.send({ type: 'plugin', name: PLUGIN, msg: { type: 'open' } }),\n isActive: (f) => f.link,\n surfaces: ['toolbar', 'floating', 'context'],\n }\n\n return {\n name: PLUGIN,\n items: [item],\n ui: definePluginUI<LinkState, LinkMsg, LinkEffect>({\n init: () => ({ dialog: { open: false }, url: opts.defaultUrl ?? '' }),\n update: (state, msg) => {\n switch (msg.type) {\n case 'open':\n return [state, [{ type: 'begin' }]]\n case 'show':\n return { dialog: { open: true }, url: msg.url }\n case 'setUrl':\n return { ...state, url: msg.url }\n case 'submit':\n return [{ ...state, dialog: { open: false } }, [{ type: 'commit', url: state.url }]]\n case 'dialog': {\n const open = dialogOpen(msg.msg, state.dialog.open)\n return open === state.dialog.open ? state : { ...state, dialog: { open } }\n }\n }\n },\n view: ({ state, send }) => [\n linkDialog({\n dialog: state.at('dialog'),\n url: state.at('url'),\n onInput: (url) => send({ type: 'setUrl', url }),\n onSubmit: () => send({ type: 'submit' }),\n onDialog: (msg) => send({ type: 'dialog', msg }),\n }),\n ],\n onEffect: (effect, ctx) => {\n const editor = ctx.editor()\n if (!editor) return\n if (effect.type === 'begin') {\n savedSelection = editor.getEditorState().read(() => {\n const selection = $getSelection()\n return selection ? selection.clone() : null\n })\n ctx.send({ type: 'show', url: readLinkUrl(editor) })\n return\n }\n const url = effect.url.trim()\n editor.update(() => {\n if (savedSelection) $setSelection(savedSelection.clone())\n $toggleLink(url === '' ? null : url)\n })\n savedSelection = null\n },\n }),\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@llui/markdown-editor",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -24,9 +24,9 @@
|
|
|
24
24
|
"./styles/editor.css": "./dist/styles/editor.css"
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
|
-
"@llui/dom": "^0.11.
|
|
28
|
-
"@llui/lexical": "^0.2.
|
|
29
|
-
"@llui/components": "^0.11.
|
|
27
|
+
"@llui/dom": "^0.11.3",
|
|
28
|
+
"@llui/lexical": "^0.2.4",
|
|
29
|
+
"@llui/components": "^0.11.7",
|
|
30
30
|
"lexical": "^0.45.0",
|
|
31
31
|
"@lexical/markdown": "^0.45.0",
|
|
32
32
|
"@lexical/rich-text": "^0.45.0",
|
|
@@ -50,9 +50,9 @@
|
|
|
50
50
|
"typescript": "^6.0.0",
|
|
51
51
|
"vitest": "^4.1.2",
|
|
52
52
|
"@lexical/code-core": "^0.45.0",
|
|
53
|
-
"@llui/dom": "0.11.
|
|
54
|
-
"@llui/
|
|
55
|
-
"@llui/
|
|
53
|
+
"@llui/dom": "0.11.3",
|
|
54
|
+
"@llui/components": "0.11.7",
|
|
55
|
+
"@llui/lexical": "0.2.4"
|
|
56
56
|
},
|
|
57
57
|
"sideEffects": [
|
|
58
58
|
"./dist/styles/editor.css"
|