@llui/markdown-editor 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/__llui_deps.json +252 -0
- package/dist/editor.d.ts +42 -0
- package/dist/editor.d.ts.map +1 -0
- package/dist/editor.js +157 -0
- package/dist/editor.js.map +1 -0
- package/dist/effects.d.ts +17 -0
- package/dist/effects.d.ts.map +1 -0
- package/dist/effects.js +33 -0
- package/dist/effects.js.map +1 -0
- package/dist/format.d.ts +6 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +51 -0
- package/dist/format.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/plugins/callout.d.ts +15 -0
- package/dist/plugins/callout.d.ts.map +1 -0
- package/dist/plugins/callout.js +151 -0
- package/dist/plugins/callout.js.map +1 -0
- package/dist/plugins/context-menu.d.ts +3 -0
- package/dist/plugins/context-menu.d.ts.map +1 -0
- package/dist/plugins/context-menu.js +93 -0
- package/dist/plugins/context-menu.js.map +1 -0
- package/dist/plugins/core.d.ts +7 -0
- package/dist/plugins/core.d.ts.map +1 -0
- package/dist/plugins/core.js +189 -0
- package/dist/plugins/core.js.map +1 -0
- package/dist/plugins/emoji.d.ts +9 -0
- package/dist/plugins/emoji.d.ts.map +1 -0
- package/dist/plugins/emoji.js +50 -0
- package/dist/plugins/emoji.js.map +1 -0
- package/dist/plugins/floating-toolbar.d.ts +3 -0
- package/dist/plugins/floating-toolbar.d.ts.map +1 -0
- package/dist/plugins/floating-toolbar.js +137 -0
- package/dist/plugins/floating-toolbar.js.map +1 -0
- package/dist/plugins/hr.d.ts +5 -0
- package/dist/plugins/hr.d.ts.map +1 -0
- package/dist/plugins/hr.js +46 -0
- package/dist/plugins/hr.js.map +1 -0
- package/dist/plugins/image.d.ts +8 -0
- package/dist/plugins/image.d.ts.map +1 -0
- package/dist/plugins/image.js +173 -0
- package/dist/plugins/image.js.map +1 -0
- package/dist/plugins/link.d.ts +7 -0
- package/dist/plugins/link.d.ts.map +1 -0
- package/dist/plugins/link.js +100 -0
- package/dist/plugins/link.js.map +1 -0
- package/dist/plugins/math.d.ts +8 -0
- package/dist/plugins/math.d.ts.map +1 -0
- package/dist/plugins/math.js +81 -0
- package/dist/plugins/math.js.map +1 -0
- package/dist/plugins/mention.d.ts +11 -0
- package/dist/plugins/mention.d.ts.map +1 -0
- package/dist/plugins/mention.js +163 -0
- package/dist/plugins/mention.js.map +1 -0
- package/dist/plugins/mermaid.d.ts +8 -0
- package/dist/plugins/mermaid.d.ts.map +1 -0
- package/dist/plugins/mermaid.js +92 -0
- package/dist/plugins/mermaid.js.map +1 -0
- package/dist/plugins/overlay.d.ts +46 -0
- package/dist/plugins/overlay.d.ts.map +1 -0
- package/dist/plugins/overlay.js +83 -0
- package/dist/plugins/overlay.js.map +1 -0
- package/dist/plugins/slash.d.ts +3 -0
- package/dist/plugins/slash.d.ts.map +1 -0
- package/dist/plugins/slash.js +167 -0
- package/dist/plugins/slash.js.map +1 -0
- package/dist/plugins/table.d.ts +3 -0
- package/dist/plugins/table.d.ts.map +1 -0
- package/dist/plugins/table.js +227 -0
- package/dist/plugins/table.js.map +1 -0
- package/dist/plugins/types.d.ts +44 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/plugins/types.js +4 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/plugins/ui.d.ts +44 -0
- package/dist/plugins/ui.d.ts.map +1 -0
- package/dist/plugins/ui.js +34 -0
- package/dist/plugins/ui.js.map +1 -0
- package/dist/state.d.ts +105 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +100 -0
- package/dist/state.js.map +1 -0
- package/dist/styles/editor.css +517 -0
- package/dist/surfaces/link-dialog.d.ts +19 -0
- package/dist/surfaces/link-dialog.d.ts.map +1 -0
- package/dist/surfaces/link-dialog.js +45 -0
- package/dist/surfaces/link-dialog.js.map +1 -0
- package/dist/surfaces/toolbar.d.ts +48 -0
- package/dist/surfaces/toolbar.d.ts.map +1 -0
- package/dist/surfaces/toolbar.js +134 -0
- package/dist/surfaces/toolbar.js.map +1 -0
- package/dist/transformers/gfm.d.ts +7 -0
- package/dist/transformers/gfm.d.ts.map +1 -0
- package/dist/transformers/gfm.js +41 -0
- package/dist/transformers/gfm.js.map +1 -0
- package/dist/transformers/registry.d.ts +9 -0
- package/dist/transformers/registry.d.ts.map +1 -0
- package/dist/transformers/registry.js +43 -0
- package/dist/transformers/registry.js.map +1 -0
- package/package.json +89 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export { type EditorConfig, type EditorParts, markdownEditor } from './editor.js';
|
|
2
|
+
export { type BlockType, type FormatState, type OverlayKind, type EditorState, type EditorMsg, type EditorOutMsg, type EditorEffect, type InitOptions, EMPTY_FORMAT, init, update, countWords, } from './state.js';
|
|
3
|
+
export { type ItemSurface, type CommandItem, type CommandContext, type MarkdownPlugin, } from './plugins/types.js';
|
|
4
|
+
export { type PluginUI, type PluginUISpec, type PluginViewArgs, type PluginEffectContext, definePluginUI, } from './plugins/ui.js';
|
|
5
|
+
export { type CorePluginOptions, corePlugin } from './plugins/core.js';
|
|
6
|
+
export { type LinkPluginOptions, linkPlugin } from './plugins/link.js';
|
|
7
|
+
export { type CalloutKind, type CalloutData, type CalloutPluginOptions, calloutPlugin, $insertCallout, } from './plugins/callout.js';
|
|
8
|
+
export { hrPlugin, $insertHorizontalRule } from './plugins/hr.js';
|
|
9
|
+
export { slashPlugin } from './plugins/slash.js';
|
|
10
|
+
export { contextMenuPlugin } from './plugins/context-menu.js';
|
|
11
|
+
export { floatingToolbarPlugin } from './plugins/floating-toolbar.js';
|
|
12
|
+
export { type MathPluginOptions, mathPlugin } from './plugins/math.js';
|
|
13
|
+
export { type MermaidPluginOptions, mermaidPlugin } from './plugins/mermaid.js';
|
|
14
|
+
export { type Mention, type MentionPluginOptions, mentionPlugin } from './plugins/mention.js';
|
|
15
|
+
export { type EmojiPluginOptions, DEFAULT_EMOJI, emojiPlugin } from './plugins/emoji.js';
|
|
16
|
+
export { type ImagePluginOptions, imagePlugin } from './plugins/image.js';
|
|
17
|
+
export { tablePlugin } from './plugins/table.js';
|
|
18
|
+
export { GFM_NODES, GFM_TRANSFORMERS } from './transformers/gfm.js';
|
|
19
|
+
export { buildTransformers, orderTransformers } from './transformers/registry.js';
|
|
20
|
+
export { computeFormatState } from './format.js';
|
|
21
|
+
export { type ToolbarItemParts, type ToolbarParts, type ToolbarOptions, DEFAULT_GLYPHS, connectToolbar, toolbar, } from './surfaces/toolbar.js';
|
|
22
|
+
export { type LinkDialogOptions, linkDialog } from './surfaces/link-dialog.js';
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAEjF,OAAO,EACL,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,YAAY,EACZ,IAAI,EACJ,MAAM,EACN,UAAU,GACX,MAAM,YAAY,CAAA;AAEnB,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,cAAc,GACpB,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,cAAc,GACf,MAAM,iBAAiB,CAAA;AAExB,OAAO,EAAE,KAAK,iBAAiB,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACtE,OAAO,EAAE,KAAK,iBAAiB,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACtE,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,oBAAoB,EACzB,aAAa,EACb,cAAc,GACf,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,QAAQ,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAA;AACrE,OAAO,EAAE,KAAK,iBAAiB,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACtE,OAAO,EAAE,KAAK,oBAAoB,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAC/E,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,oBAAoB,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAC7F,OAAO,EAAE,KAAK,kBAAkB,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACxF,OAAO,EAAE,KAAK,kBAAkB,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAEhD,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACnE,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAEjF,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAEhD,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,cAAc,EACd,cAAc,EACd,OAAO,GACR,MAAM,uBAAuB,CAAA;AAE9B,OAAO,EAAE,KAAK,iBAAiB,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// `@llui/markdown-editor` — WYSIWYG Markdown editor for LLui, built on Lexical.
|
|
2
|
+
export { markdownEditor } from './editor.js';
|
|
3
|
+
export { EMPTY_FORMAT, init, update, countWords, } from './state.js';
|
|
4
|
+
export {} from './plugins/types.js';
|
|
5
|
+
export { definePluginUI, } from './plugins/ui.js';
|
|
6
|
+
export { corePlugin } from './plugins/core.js';
|
|
7
|
+
export { linkPlugin } from './plugins/link.js';
|
|
8
|
+
export { calloutPlugin, $insertCallout, } from './plugins/callout.js';
|
|
9
|
+
export { hrPlugin, $insertHorizontalRule } from './plugins/hr.js';
|
|
10
|
+
export { slashPlugin } from './plugins/slash.js';
|
|
11
|
+
export { contextMenuPlugin } from './plugins/context-menu.js';
|
|
12
|
+
export { floatingToolbarPlugin } from './plugins/floating-toolbar.js';
|
|
13
|
+
export { mathPlugin } from './plugins/math.js';
|
|
14
|
+
export { mermaidPlugin } from './plugins/mermaid.js';
|
|
15
|
+
export { mentionPlugin } from './plugins/mention.js';
|
|
16
|
+
export { DEFAULT_EMOJI, emojiPlugin } from './plugins/emoji.js';
|
|
17
|
+
export { imagePlugin } from './plugins/image.js';
|
|
18
|
+
export { tablePlugin } from './plugins/table.js';
|
|
19
|
+
export { GFM_NODES, GFM_TRANSFORMERS } from './transformers/gfm.js';
|
|
20
|
+
export { buildTransformers, orderTransformers } from './transformers/registry.js';
|
|
21
|
+
export { computeFormatState } from './format.js';
|
|
22
|
+
export { DEFAULT_GLYPHS, connectToolbar, toolbar, } from './surfaces/toolbar.js';
|
|
23
|
+
export { linkDialog } from './surfaces/link-dialog.js';
|
|
24
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAEhF,OAAO,EAAuC,cAAc,EAAE,MAAM,aAAa,CAAA;AAEjF,OAAO,EASL,YAAY,EACZ,IAAI,EACJ,MAAM,EACN,UAAU,GACX,MAAM,YAAY,CAAA;AAEnB,OAAO,EAKN,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EAKL,cAAc,GACf,MAAM,iBAAiB,CAAA;AAExB,OAAO,EAA0B,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACtE,OAAO,EAA0B,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACtE,OAAO,EAIL,aAAa,EACb,cAAc,GACf,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,QAAQ,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAA;AACrE,OAAO,EAA0B,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACtE,OAAO,EAA6B,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAC/E,OAAO,EAA2C,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAC7F,OAAO,EAA2B,aAAa,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACxF,OAAO,EAA2B,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAEhD,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACnE,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAEjF,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAEhD,OAAO,EAIL,cAAc,EACd,cAAc,EACd,OAAO,GACR,MAAM,uBAAuB,CAAA;AAE9B,OAAO,EAA0B,UAAU,EAAE,MAAM,2BAA2B,CAAA","sourcesContent":["// `@llui/markdown-editor` — WYSIWYG Markdown editor for LLui, built on Lexical.\n\nexport { type EditorConfig, type EditorParts, markdownEditor } from './editor.js'\n\nexport {\n type BlockType,\n type FormatState,\n type OverlayKind,\n type EditorState,\n type EditorMsg,\n type EditorOutMsg,\n type EditorEffect,\n type InitOptions,\n EMPTY_FORMAT,\n init,\n update,\n countWords,\n} from './state.js'\n\nexport {\n type ItemSurface,\n type CommandItem,\n type CommandContext,\n type MarkdownPlugin,\n} from './plugins/types.js'\n\nexport {\n type PluginUI,\n type PluginUISpec,\n type PluginViewArgs,\n type PluginEffectContext,\n definePluginUI,\n} from './plugins/ui.js'\n\nexport { type CorePluginOptions, corePlugin } from './plugins/core.js'\nexport { type LinkPluginOptions, linkPlugin } from './plugins/link.js'\nexport {\n type CalloutKind,\n type CalloutData,\n type CalloutPluginOptions,\n calloutPlugin,\n $insertCallout,\n} from './plugins/callout.js'\nexport { hrPlugin, $insertHorizontalRule } from './plugins/hr.js'\nexport { slashPlugin } from './plugins/slash.js'\nexport { contextMenuPlugin } from './plugins/context-menu.js'\nexport { floatingToolbarPlugin } from './plugins/floating-toolbar.js'\nexport { type MathPluginOptions, mathPlugin } from './plugins/math.js'\nexport { type MermaidPluginOptions, mermaidPlugin } from './plugins/mermaid.js'\nexport { type Mention, type MentionPluginOptions, mentionPlugin } from './plugins/mention.js'\nexport { type EmojiPluginOptions, DEFAULT_EMOJI, emojiPlugin } from './plugins/emoji.js'\nexport { type ImagePluginOptions, imagePlugin } from './plugins/image.js'\nexport { tablePlugin } from './plugins/table.js'\n\nexport { GFM_NODES, GFM_TRANSFORMERS } from './transformers/gfm.js'\nexport { buildTransformers, orderTransformers } from './transformers/registry.js'\n\nexport { computeFormatState } from './format.js'\n\nexport {\n type ToolbarItemParts,\n type ToolbarParts,\n type ToolbarOptions,\n DEFAULT_GLYPHS,\n connectToolbar,\n toolbar,\n} from './surfaces/toolbar.js'\n\nexport { type LinkDialogOptions, linkDialog } from './surfaces/link-dialog.js'\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { LLuiDecoratorNode } from '@llui/lexical';
|
|
2
|
+
import type { MarkdownPlugin } from './types.js';
|
|
3
|
+
export type CalloutKind = 'note' | 'tip' | 'warning' | 'danger';
|
|
4
|
+
export interface CalloutData {
|
|
5
|
+
kind: CalloutKind;
|
|
6
|
+
text: string;
|
|
7
|
+
}
|
|
8
|
+
/** Insert a fresh callout at the current selection; returns the created node. */
|
|
9
|
+
export declare function $insertCallout(kind?: CalloutKind, textValue?: string): LLuiDecoratorNode;
|
|
10
|
+
export interface CalloutPluginOptions {
|
|
11
|
+
/** Default kind for the toolbar/slash insert action. */
|
|
12
|
+
defaultKind?: CalloutKind;
|
|
13
|
+
}
|
|
14
|
+
export declare function calloutPlugin(opts?: CalloutPluginOptions): MarkdownPlugin;
|
|
15
|
+
//# sourceMappingURL=callout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callout.d.ts","sourceRoot":"","sources":["../../src/plugins/callout.ts"],"names":[],"mappings":"AAQA,OAAO,EAGL,iBAAiB,EAElB,MAAM,eAAe,CAAA;AAEtB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhD,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,GAAG,QAAQ,CAAA;AAE/D,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,WAAW,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;CACb;AA8GD,iFAAiF;AACjF,wBAAgB,cAAc,CAC5B,IAAI,GAAE,WAAoB,EAC1B,SAAS,SAAgB,GACxB,iBAAiB,CAEnB;AAyBD,MAAM,WAAW,oBAAoB;IACnC,wDAAwD;IACxD,WAAW,CAAC,EAAE,WAAW,CAAA;CAC1B;AAED,wBAAgB,aAAa,CAAC,IAAI,GAAE,oBAAyB,GAAG,cAAc,CA0B7E"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// Callout (admonition) plugin — the custom-rendering showcase. A callout is a
|
|
2
|
+
// block decorator: it stores `{ kind, text }`, renders an LLui sub-view (its own
|
|
3
|
+
// TEA loop) with a clickable kind badge, and round-trips to `:::kind text`
|
|
4
|
+
// markdown via a contributed element transformer.
|
|
5
|
+
import {} from 'lexical';
|
|
6
|
+
import { $insertNodeToNearestRoot } from '@lexical/utils';
|
|
7
|
+
import { $createLLuiDecoratorNode, $isLLuiDecoratorNode, LLuiDecoratorNode, decoratorBridge, } from '@llui/lexical';
|
|
8
|
+
import { button, component, div, span, text } from '@llui/dom';
|
|
9
|
+
const KIND_CYCLE = ['note', 'tip', 'warning', 'danger'];
|
|
10
|
+
const KIND_LABEL = {
|
|
11
|
+
note: 'Note',
|
|
12
|
+
tip: 'Tip',
|
|
13
|
+
warning: 'Warning',
|
|
14
|
+
danger: 'Danger',
|
|
15
|
+
};
|
|
16
|
+
const BRIDGE_TYPE = 'callout';
|
|
17
|
+
function nextKind(kind) {
|
|
18
|
+
const idx = KIND_CYCLE.indexOf(kind);
|
|
19
|
+
return KIND_CYCLE[(idx + 1) % KIND_CYCLE.length];
|
|
20
|
+
}
|
|
21
|
+
function isCalloutData(value) {
|
|
22
|
+
return (typeof value === 'object' &&
|
|
23
|
+
value !== null &&
|
|
24
|
+
typeof value.kind === 'string' &&
|
|
25
|
+
typeof value.text === 'string');
|
|
26
|
+
}
|
|
27
|
+
// Keep keyboard/input/paste events from bubbling to the outer Lexical editor so
|
|
28
|
+
// the nested editable text island edits natively without Lexical intercepting.
|
|
29
|
+
const stop = (e) => e.stopPropagation();
|
|
30
|
+
/** The LLui sub-view rendered inside a callout DecoratorNode. The badge cycles
|
|
31
|
+
* the kind; the text is an editable island that persists into the Lexical node
|
|
32
|
+
* on blur (both round-trip to markdown). */
|
|
33
|
+
const calloutBridge = decoratorBridge(BRIDGE_TYPE, (data, api) => component({
|
|
34
|
+
name: 'Callout',
|
|
35
|
+
init: () => ({ kind: data.kind, text: data.text }),
|
|
36
|
+
update: (state, msg) => {
|
|
37
|
+
if (msg.type === 'cycle') {
|
|
38
|
+
const kind = nextKind(state.kind);
|
|
39
|
+
api.update({ kind, text: state.text });
|
|
40
|
+
return { ...state, kind };
|
|
41
|
+
}
|
|
42
|
+
if (msg.type === 'commitText') {
|
|
43
|
+
if (msg.text === state.text)
|
|
44
|
+
return state;
|
|
45
|
+
api.update({ kind: state.kind, text: msg.text });
|
|
46
|
+
return { ...state, text: msg.text };
|
|
47
|
+
}
|
|
48
|
+
return state;
|
|
49
|
+
},
|
|
50
|
+
view: ({ state, send }) => [
|
|
51
|
+
div({
|
|
52
|
+
'data-scope': 'md-callout',
|
|
53
|
+
'data-part': 'root',
|
|
54
|
+
'data-kind': state.at('kind'),
|
|
55
|
+
contenteditable: 'false',
|
|
56
|
+
onKeyDown: stop,
|
|
57
|
+
onBeforeInput: stop,
|
|
58
|
+
onPaste: stop,
|
|
59
|
+
}, [
|
|
60
|
+
button({
|
|
61
|
+
type: 'button',
|
|
62
|
+
'data-part': 'badge',
|
|
63
|
+
'aria-label': 'Change callout kind',
|
|
64
|
+
onClick: () => send({ type: 'cycle' }),
|
|
65
|
+
}, [text(state.at('kind').map((k) => KIND_LABEL[k]))]),
|
|
66
|
+
span({
|
|
67
|
+
'data-part': 'text',
|
|
68
|
+
contenteditable: 'true',
|
|
69
|
+
role: 'textbox',
|
|
70
|
+
'aria-label': 'Callout text',
|
|
71
|
+
onBlur: (e) => send({ type: 'commitText', text: e.target.textContent ?? '' }),
|
|
72
|
+
}, [text(state.at('text'))]),
|
|
73
|
+
]),
|
|
74
|
+
],
|
|
75
|
+
}));
|
|
76
|
+
/** `:::kind text` element transformer (single-line admonition). */
|
|
77
|
+
const CALLOUT_TRANSFORMER = {
|
|
78
|
+
dependencies: [LLuiDecoratorNode],
|
|
79
|
+
export: (node) => {
|
|
80
|
+
if (!$isLLuiDecoratorNode(node) || node.getBridgeType() !== BRIDGE_TYPE)
|
|
81
|
+
return null;
|
|
82
|
+
const data = node.getData();
|
|
83
|
+
if (!isCalloutData(data))
|
|
84
|
+
return null;
|
|
85
|
+
return `:::${data.kind} ${data.text}`;
|
|
86
|
+
},
|
|
87
|
+
regExp: /^:::(note|tip|warning|danger)[ \t]+(.+)$/,
|
|
88
|
+
replace: (parentNode, _children, match) => {
|
|
89
|
+
const kind = match[1];
|
|
90
|
+
const callout = $createLLuiDecoratorNode(BRIDGE_TYPE, { kind, text: match[2] ?? '' });
|
|
91
|
+
parentNode.replace(callout);
|
|
92
|
+
},
|
|
93
|
+
type: 'element',
|
|
94
|
+
};
|
|
95
|
+
/** Insert a fresh callout at the current selection; returns the created node. */
|
|
96
|
+
export function $insertCallout(kind = 'note', textValue = 'New callout') {
|
|
97
|
+
return $insertNodeToNearestRoot($createLLuiDecoratorNode(BRIDGE_TYPE, { kind, text: textValue }));
|
|
98
|
+
}
|
|
99
|
+
/** Move focus into a callout's editable text island once it has decorated, and
|
|
100
|
+
* select its placeholder text so the next keystroke replaces it. */
|
|
101
|
+
function focusCalloutText(editor, key, attempt = 0) {
|
|
102
|
+
if (typeof requestAnimationFrame !== 'function')
|
|
103
|
+
return;
|
|
104
|
+
requestAnimationFrame(() => {
|
|
105
|
+
const span = editor.getElementByKey(key)?.querySelector('[data-part="text"]');
|
|
106
|
+
if (span instanceof HTMLElement) {
|
|
107
|
+
span.focus();
|
|
108
|
+
try {
|
|
109
|
+
const range = document.createRange();
|
|
110
|
+
range.selectNodeContents(span);
|
|
111
|
+
const sel = window.getSelection();
|
|
112
|
+
sel?.removeAllRanges();
|
|
113
|
+
sel?.addRange(range);
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
/* selection API unavailable */
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else if (attempt < 3) {
|
|
120
|
+
focusCalloutText(editor, key, attempt + 1);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
export function calloutPlugin(opts = {}) {
|
|
125
|
+
const defaultKind = opts.defaultKind ?? 'note';
|
|
126
|
+
return {
|
|
127
|
+
name: 'callout',
|
|
128
|
+
nodes: [LLuiDecoratorNode],
|
|
129
|
+
decorators: [calloutBridge],
|
|
130
|
+
transformers: [CALLOUT_TRANSFORMER],
|
|
131
|
+
items: [
|
|
132
|
+
{
|
|
133
|
+
id: 'callout',
|
|
134
|
+
label: 'Callout',
|
|
135
|
+
icon: 'callout',
|
|
136
|
+
group: 'insert',
|
|
137
|
+
keywords: ['note', 'admonition', 'aside', 'tip', 'warning'],
|
|
138
|
+
run: (editor) => {
|
|
139
|
+
let key = '';
|
|
140
|
+
editor.update(() => {
|
|
141
|
+
key = $insertCallout(defaultKind).getKey();
|
|
142
|
+
});
|
|
143
|
+
// Land the caret inside the new callout's text, not after the block.
|
|
144
|
+
focusCalloutText(editor, key);
|
|
145
|
+
},
|
|
146
|
+
surfaces: ['toolbar', 'slash', 'context'],
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=callout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callout.js","sourceRoot":"","sources":["../../src/plugins/callout.ts"],"names":[],"mappings":"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","sourcesContent":["// Callout (admonition) plugin — the custom-rendering showcase. A callout is a\n// block decorator: it stores `{ kind, text }`, renders an LLui sub-view (its own\n// TEA loop) with a clickable kind badge, and round-trips to `:::kind text`\n// markdown via a contributed element transformer.\n\nimport { type ElementNode, type LexicalEditor, type LexicalNode } 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, span, text, type Signal } from '@llui/dom'\nimport type { MarkdownPlugin } from './types.js'\n\nexport type CalloutKind = 'note' | 'tip' | 'warning' | 'danger'\n\nexport interface CalloutData {\n kind: CalloutKind\n text: string\n}\n\nconst KIND_CYCLE: readonly CalloutKind[] = ['note', 'tip', 'warning', 'danger']\nconst KIND_LABEL: Readonly<Record<CalloutKind, string>> = {\n note: 'Note',\n tip: 'Tip',\n warning: 'Warning',\n danger: 'Danger',\n}\n\nconst BRIDGE_TYPE = 'callout'\n\nfunction nextKind(kind: CalloutKind): CalloutKind {\n const idx = KIND_CYCLE.indexOf(kind)\n return KIND_CYCLE[(idx + 1) % KIND_CYCLE.length]!\n}\n\nfunction isCalloutData(value: unknown): value is CalloutData {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as CalloutData).kind === 'string' &&\n typeof (value as CalloutData).text === 'string'\n )\n}\n\ntype CalloutMsg = { type: 'cycle' } | { type: 'commitText'; text: string }\n\n// Keep keyboard/input/paste events from bubbling to the outer Lexical editor so\n// the nested editable text island edits natively without Lexical intercepting.\nconst stop = (e: Event): void => e.stopPropagation()\n\n/** The LLui sub-view rendered inside a callout DecoratorNode. The badge cycles\n * the kind; the text is an editable island that persists into the Lexical node\n * on blur (both round-trip to markdown). */\nconst calloutBridge = decoratorBridge<CalloutData, CalloutData, CalloutMsg, never>(\n BRIDGE_TYPE,\n (data, api) =>\n component<CalloutData, CalloutMsg, never>({\n name: 'Callout',\n init: () => ({ kind: data.kind, text: data.text }),\n update: (state, msg) => {\n if (msg.type === 'cycle') {\n const kind = nextKind(state.kind)\n api.update({ kind, text: state.text })\n return { ...state, kind }\n }\n if (msg.type === 'commitText') {\n if (msg.text === state.text) return state\n api.update({ kind: state.kind, text: msg.text })\n return { ...state, text: msg.text }\n }\n return state\n },\n view: ({ state, send }) => [\n div(\n {\n 'data-scope': 'md-callout',\n 'data-part': 'root',\n 'data-kind': state.at('kind') as Signal<string>,\n contenteditable: 'false',\n onKeyDown: stop,\n onBeforeInput: stop,\n onPaste: stop,\n },\n [\n button(\n {\n type: 'button',\n 'data-part': 'badge',\n 'aria-label': 'Change callout kind',\n onClick: () => send({ type: 'cycle' }),\n },\n [text(state.at('kind').map((k) => KIND_LABEL[k]))],\n ),\n span(\n {\n 'data-part': 'text',\n contenteditable: 'true',\n role: 'textbox',\n 'aria-label': 'Callout text',\n onBlur: (e: FocusEvent) =>\n send({ type: 'commitText', text: (e.target as HTMLElement).textContent ?? '' }),\n },\n [text(state.at('text') as Signal<string>)],\n ),\n ],\n ),\n ],\n }),\n)\n\n/** `:::kind text` element transformer (single-line admonition). */\nconst CALLOUT_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 if (!isCalloutData(data)) return null\n return `:::${data.kind} ${data.text}`\n },\n regExp: /^:::(note|tip|warning|danger)[ \\t]+(.+)$/,\n replace: (parentNode: ElementNode, _children, match): void => {\n const kind = match[1] as CalloutKind\n const callout = $createLLuiDecoratorNode(BRIDGE_TYPE, { kind, text: match[2] ?? '' })\n parentNode.replace(callout)\n },\n type: 'element',\n}\n\n/** Insert a fresh callout at the current selection; returns the created node. */\nexport function $insertCallout(\n kind: CalloutKind = 'note',\n textValue = 'New callout',\n): LLuiDecoratorNode {\n return $insertNodeToNearestRoot($createLLuiDecoratorNode(BRIDGE_TYPE, { kind, text: textValue }))\n}\n\n/** Move focus into a callout's editable text island once it has decorated, and\n * select its placeholder text so the next keystroke replaces it. */\nfunction focusCalloutText(editor: LexicalEditor, key: string, attempt = 0): void {\n if (typeof requestAnimationFrame !== 'function') return\n requestAnimationFrame(() => {\n const span = editor.getElementByKey(key)?.querySelector('[data-part=\"text\"]')\n if (span instanceof HTMLElement) {\n span.focus()\n try {\n const range = document.createRange()\n range.selectNodeContents(span)\n const sel = window.getSelection()\n sel?.removeAllRanges()\n sel?.addRange(range)\n } catch {\n /* selection API unavailable */\n }\n } else if (attempt < 3) {\n focusCalloutText(editor, key, attempt + 1)\n }\n })\n}\n\nexport interface CalloutPluginOptions {\n /** Default kind for the toolbar/slash insert action. */\n defaultKind?: CalloutKind\n}\n\nexport function calloutPlugin(opts: CalloutPluginOptions = {}): MarkdownPlugin {\n const defaultKind = opts.defaultKind ?? 'note'\n return {\n name: 'callout',\n nodes: [LLuiDecoratorNode],\n decorators: [calloutBridge],\n transformers: [CALLOUT_TRANSFORMER],\n items: [\n {\n id: 'callout',\n label: 'Callout',\n icon: 'callout',\n group: 'insert',\n keywords: ['note', 'admonition', 'aside', 'tip', 'warning'],\n run: (editor) => {\n let key = ''\n editor.update(() => {\n key = $insertCallout(defaultKind).getKey()\n })\n // Land the caret inside the new callout's text, not after the block.\n focusCalloutText(editor, key)\n },\n surfaces: ['toolbar', 'slash', 'context'],\n },\n ],\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-menu.d.ts","sourceRoot":"","sources":["../../src/plugins/context-menu.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAe,cAAc,EAAE,MAAM,YAAY,CAAA;AAqB7D,wBAAgB,iBAAiB,IAAI,cAAc,CAyFlD"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// Right-click context menu — a plugin-UI overlay. `register` installs a
|
|
2
|
+
// `contextmenu` listener on the editor root and opens the menu at the pointer;
|
|
3
|
+
// the plugin-UI renders the menu and runs the chosen command.
|
|
4
|
+
import { div, each, text } from '@llui/dom';
|
|
5
|
+
import { definePluginUI } from './ui.js';
|
|
6
|
+
import { OVERLAY_Z, hideOverlay, overlayRoot } from './overlay.js';
|
|
7
|
+
export function contextMenuPlugin() {
|
|
8
|
+
let contextItems = [];
|
|
9
|
+
return {
|
|
10
|
+
name: 'contextMenu',
|
|
11
|
+
onItems: (items) => {
|
|
12
|
+
// Curated: only items that explicitly opt into the context menu (insert
|
|
13
|
+
// actions, links, history). Inline formatting lives in the floating bar.
|
|
14
|
+
contextItems = items.filter((i) => i.surfaces?.includes('context') ?? false);
|
|
15
|
+
},
|
|
16
|
+
register: (editor, ctx) => {
|
|
17
|
+
const onContext = (e) => {
|
|
18
|
+
const me = e;
|
|
19
|
+
e.preventDefault();
|
|
20
|
+
ctx.emit({
|
|
21
|
+
type: 'plugin',
|
|
22
|
+
name: 'contextMenu',
|
|
23
|
+
msg: {
|
|
24
|
+
type: 'open',
|
|
25
|
+
x: me.clientX,
|
|
26
|
+
y: me.clientY,
|
|
27
|
+
items: contextItems.map((i) => ({ id: i.id, label: i.label })),
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
const root = editor.getRootElement();
|
|
32
|
+
root?.addEventListener('contextmenu', onContext);
|
|
33
|
+
return () => {
|
|
34
|
+
editor.getRootElement()?.removeEventListener('contextmenu', onContext);
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
ui: definePluginUI({
|
|
38
|
+
init: () => ({ open: false, x: 0, y: 0, items: [] }),
|
|
39
|
+
update: (state, msg) => {
|
|
40
|
+
switch (msg.type) {
|
|
41
|
+
case 'open':
|
|
42
|
+
return { open: msg.items.length > 0, x: msg.x, y: msg.y, items: msg.items };
|
|
43
|
+
case 'close':
|
|
44
|
+
return hideOverlay(state);
|
|
45
|
+
case 'choose': {
|
|
46
|
+
const item = state.items[msg.index];
|
|
47
|
+
if (!item)
|
|
48
|
+
return hideOverlay(state);
|
|
49
|
+
return [{ ...state, open: false }, [{ type: 'run', id: item.id }]];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
onEffect: (effect, ctx) => {
|
|
54
|
+
ctx.emit({ type: 'runCommand', id: effect.id });
|
|
55
|
+
},
|
|
56
|
+
view: ({ state, send }) => overlayRoot({
|
|
57
|
+
open: state.at('open'),
|
|
58
|
+
x: state.at('x'),
|
|
59
|
+
y: state.at('y'),
|
|
60
|
+
zIndex: OVERLAY_Z.contextMenu,
|
|
61
|
+
attrs: { 'data-scope': 'md-context', 'data-part': 'root' },
|
|
62
|
+
// Backdrop closes the menu on any outside interaction.
|
|
63
|
+
before: () => [
|
|
64
|
+
div({
|
|
65
|
+
'data-scope': 'md-context',
|
|
66
|
+
'data-part': 'backdrop',
|
|
67
|
+
onMouseDown: () => send({ type: 'close' }),
|
|
68
|
+
onContextMenu: (e) => {
|
|
69
|
+
e.preventDefault();
|
|
70
|
+
send({ type: 'close' });
|
|
71
|
+
},
|
|
72
|
+
}),
|
|
73
|
+
],
|
|
74
|
+
children: () => [
|
|
75
|
+
each(state.at('items'), {
|
|
76
|
+
key: (it) => it.id,
|
|
77
|
+
render: (item, index) => [
|
|
78
|
+
div({
|
|
79
|
+
'data-scope': 'md-context',
|
|
80
|
+
'data-part': 'option',
|
|
81
|
+
onMouseDown: (e) => {
|
|
82
|
+
e.preventDefault();
|
|
83
|
+
send({ type: 'choose', index: index.peek() });
|
|
84
|
+
},
|
|
85
|
+
}, [text(item.map((it) => it.label))]),
|
|
86
|
+
],
|
|
87
|
+
}),
|
|
88
|
+
],
|
|
89
|
+
}),
|
|
90
|
+
}),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=context-menu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-menu.js","sourceRoot":"","sources":["../../src/plugins/context-menu.ts"],"names":[],"mappings":"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","sourcesContent":["// Right-click context menu — a plugin-UI overlay. `register` installs a\n// `contextmenu` listener on the editor root and opens the menu at the pointer;\n// the plugin-UI renders the menu and runs the chosen command.\n\nimport { div, each, text, type Signal } from '@llui/dom'\nimport { definePluginUI } from './ui.js'\nimport { OVERLAY_Z, hideOverlay, overlayRoot } from './overlay.js'\nimport type { CommandItem, MarkdownPlugin } from './types.js'\n\ninterface MenuItem {\n id: string\n label: string\n}\n\ninterface ContextState {\n open: boolean\n x: number\n y: number\n items: MenuItem[]\n}\n\ntype ContextMsg =\n | { type: 'open'; x: number; y: number; items: MenuItem[] }\n | { type: 'close' }\n | { type: 'choose'; index: number }\n\ntype ContextEffect = { type: 'run'; id: string }\n\nexport function contextMenuPlugin(): MarkdownPlugin {\n let contextItems: CommandItem[] = []\n\n return {\n name: 'contextMenu',\n onItems: (items) => {\n // Curated: only items that explicitly opt into the context menu (insert\n // actions, links, history). Inline formatting lives in the floating bar.\n contextItems = items.filter((i) => i.surfaces?.includes('context') ?? false)\n },\n register: (editor, ctx) => {\n const onContext = (e: Event): void => {\n const me = e as MouseEvent\n e.preventDefault()\n ctx.emit({\n type: 'plugin',\n name: 'contextMenu',\n msg: {\n type: 'open',\n x: me.clientX,\n y: me.clientY,\n items: contextItems.map((i) => ({ id: i.id, label: i.label })),\n },\n })\n }\n const root = editor.getRootElement()\n root?.addEventListener('contextmenu', onContext)\n return () => {\n editor.getRootElement()?.removeEventListener('contextmenu', onContext)\n }\n },\n ui: definePluginUI<ContextState, ContextMsg, ContextEffect>({\n init: () => ({ open: false, x: 0, y: 0, items: [] }),\n update: (state, msg) => {\n switch (msg.type) {\n case 'open':\n return { open: msg.items.length > 0, x: msg.x, y: msg.y, items: msg.items }\n case 'close':\n return hideOverlay(state)\n case 'choose': {\n const item = state.items[msg.index]\n if (!item) return hideOverlay(state)\n return [{ ...state, open: false }, [{ type: 'run', id: item.id }]]\n }\n }\n },\n onEffect: (effect, ctx) => {\n ctx.emit({ type: 'runCommand', id: effect.id })\n },\n view: ({ state, send }) =>\n overlayRoot({\n open: state.at('open'),\n x: state.at('x'),\n y: state.at('y'),\n zIndex: OVERLAY_Z.contextMenu,\n attrs: { 'data-scope': 'md-context', 'data-part': 'root' },\n // Backdrop closes the menu on any outside interaction.\n before: () => [\n div({\n 'data-scope': 'md-context',\n 'data-part': 'backdrop',\n onMouseDown: () => send({ type: 'close' }),\n onContextMenu: (e: Event) => {\n e.preventDefault()\n send({ type: 'close' })\n },\n }),\n ],\n children: () => [\n each(state.at('items') as Signal<MenuItem[]>, {\n key: (it) => it.id,\n render: (item, index) => [\n div(\n {\n 'data-scope': 'md-context',\n 'data-part': 'option',\n onMouseDown: (e: MouseEvent) => {\n e.preventDefault()\n send({ type: 'choose', index: index.peek() })\n },\n },\n [text(item.map((it) => it.label))],\n ),\n ],\n }),\n ],\n }),\n }),\n }\n}\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { MarkdownPlugin } from './types.js';
|
|
2
|
+
export interface CorePluginOptions {
|
|
3
|
+
/** Reserved for future core options. */
|
|
4
|
+
readonly _?: never;
|
|
5
|
+
}
|
|
6
|
+
export declare function corePlugin(_opts?: CorePluginOptions): MarkdownPlugin;
|
|
7
|
+
//# sourceMappingURL=core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/plugins/core.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAA+B,cAAc,EAAE,MAAM,YAAY,CAAA;AAsB7E,MAAM,WAAW,iBAAiB;IAChC,wCAAwC;IACxC,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,CAAA;CACnB;AAED,wBAAgB,UAAU,CAAC,KAAK,GAAE,iBAAsB,GAAG,cAAc,CAqKxE"}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
// The core plugin: the GFM superset of nodes, transformers, command items, and
|
|
2
|
+
// shortcuts. This is the default plugin when none are supplied, so the minimal
|
|
3
|
+
// `markdownEditor()` one-liner still has full keyboard formatting.
|
|
4
|
+
import { $createParagraphNode, $getSelection, $isRangeSelection, FORMAT_TEXT_COMMAND, REDO_COMMAND, UNDO_COMMAND, } from 'lexical';
|
|
5
|
+
import { mergeRegister } from '@lexical/utils';
|
|
6
|
+
import { $setBlocksType } from '@lexical/selection';
|
|
7
|
+
import { $createHeadingNode, $createQuoteNode } from '@lexical/rich-text';
|
|
8
|
+
import { $createCodeNode } from '@lexical/code-core';
|
|
9
|
+
import { INSERT_CHECK_LIST_COMMAND, INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND, registerCheckList, registerList, } from '@lexical/list';
|
|
10
|
+
import { GFM_NODES, GFM_TRANSFORMERS } from '../transformers/gfm.js';
|
|
11
|
+
const NOOP_CTX = { send: () => { } };
|
|
12
|
+
function inline(format) {
|
|
13
|
+
return (editor) => editor.dispatchCommand(FORMAT_TEXT_COMMAND, format);
|
|
14
|
+
}
|
|
15
|
+
/** Wrap a node-factory into an editor action that converts the selected blocks. */
|
|
16
|
+
function block(create) {
|
|
17
|
+
return (editor) => editor.update(() => {
|
|
18
|
+
const selection = $getSelection();
|
|
19
|
+
if ($isRangeSelection(selection))
|
|
20
|
+
$setBlocksType(selection, create);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function heading(tag) {
|
|
24
|
+
return block(() => $createHeadingNode(tag));
|
|
25
|
+
}
|
|
26
|
+
export function corePlugin(_opts = {}) {
|
|
27
|
+
const items = [
|
|
28
|
+
{
|
|
29
|
+
id: 'bold',
|
|
30
|
+
label: 'Bold',
|
|
31
|
+
icon: 'bold',
|
|
32
|
+
group: 'inline',
|
|
33
|
+
keywords: ['strong'],
|
|
34
|
+
run: inline('bold'),
|
|
35
|
+
isActive: (f) => f.bold,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: 'italic',
|
|
39
|
+
label: 'Italic',
|
|
40
|
+
icon: 'italic',
|
|
41
|
+
group: 'inline',
|
|
42
|
+
keywords: ['emphasis'],
|
|
43
|
+
run: inline('italic'),
|
|
44
|
+
isActive: (f) => f.italic,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: 'strikethrough',
|
|
48
|
+
label: 'Strikethrough',
|
|
49
|
+
icon: 'strikethrough',
|
|
50
|
+
group: 'inline',
|
|
51
|
+
keywords: ['strike', 'del'],
|
|
52
|
+
run: inline('strikethrough'),
|
|
53
|
+
isActive: (f) => f.strikethrough,
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: 'code',
|
|
57
|
+
label: 'Inline code',
|
|
58
|
+
icon: 'code',
|
|
59
|
+
group: 'inline',
|
|
60
|
+
keywords: ['mono'],
|
|
61
|
+
run: inline('code'),
|
|
62
|
+
isActive: (f) => f.code,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: 'paragraph',
|
|
66
|
+
label: 'Text',
|
|
67
|
+
icon: 'paragraph',
|
|
68
|
+
group: 'block',
|
|
69
|
+
keywords: ['body', 'normal'],
|
|
70
|
+
run: block(() => $createParagraphNode()),
|
|
71
|
+
isActive: (f) => f.blockType === 'paragraph',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
id: 'h1',
|
|
75
|
+
label: 'Heading 1',
|
|
76
|
+
icon: 'h1',
|
|
77
|
+
group: 'block',
|
|
78
|
+
keywords: ['title'],
|
|
79
|
+
run: heading('h1'),
|
|
80
|
+
isActive: (f) => f.blockType === 'h1',
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
id: 'h2',
|
|
84
|
+
label: 'Heading 2',
|
|
85
|
+
icon: 'h2',
|
|
86
|
+
group: 'block',
|
|
87
|
+
run: heading('h2'),
|
|
88
|
+
isActive: (f) => f.blockType === 'h2',
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
id: 'h3',
|
|
92
|
+
label: 'Heading 3',
|
|
93
|
+
icon: 'h3',
|
|
94
|
+
group: 'block',
|
|
95
|
+
run: heading('h3'),
|
|
96
|
+
isActive: (f) => f.blockType === 'h3',
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
id: 'quote',
|
|
100
|
+
label: 'Quote',
|
|
101
|
+
icon: 'quote',
|
|
102
|
+
group: 'block',
|
|
103
|
+
keywords: ['blockquote'],
|
|
104
|
+
run: block(() => $createQuoteNode()),
|
|
105
|
+
isActive: (f) => f.blockType === 'quote',
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
id: 'codeBlock',
|
|
109
|
+
label: 'Code block',
|
|
110
|
+
icon: 'code-block',
|
|
111
|
+
group: 'block',
|
|
112
|
+
keywords: ['fence', 'pre'],
|
|
113
|
+
run: block(() => $createCodeNode()),
|
|
114
|
+
isActive: (f) => f.blockType === 'code',
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
id: 'bulletList',
|
|
118
|
+
label: 'Bulleted list',
|
|
119
|
+
icon: 'list-bullet',
|
|
120
|
+
group: 'list',
|
|
121
|
+
keywords: ['unordered', 'ul'],
|
|
122
|
+
run: (e) => e.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined),
|
|
123
|
+
isActive: (f) => f.blockType === 'bullet',
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
id: 'numberList',
|
|
127
|
+
label: 'Numbered list',
|
|
128
|
+
icon: 'list-number',
|
|
129
|
+
group: 'list',
|
|
130
|
+
keywords: ['ordered', 'ol'],
|
|
131
|
+
run: (e) => e.dispatchCommand(INSERT_ORDERED_LIST_COMMAND, undefined),
|
|
132
|
+
isActive: (f) => f.blockType === 'number',
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
id: 'checkList',
|
|
136
|
+
label: 'Task list',
|
|
137
|
+
icon: 'list-check',
|
|
138
|
+
group: 'list',
|
|
139
|
+
keywords: ['todo', 'checkbox'],
|
|
140
|
+
run: (e) => e.dispatchCommand(INSERT_CHECK_LIST_COMMAND, undefined),
|
|
141
|
+
isActive: (f) => f.blockType === 'check',
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
id: 'undo',
|
|
145
|
+
label: 'Undo',
|
|
146
|
+
icon: 'undo',
|
|
147
|
+
group: 'history',
|
|
148
|
+
run: (e) => e.dispatchCommand(UNDO_COMMAND, undefined),
|
|
149
|
+
isDisabled: (f) => !f.canUndo,
|
|
150
|
+
surfaces: ['toolbar', 'context'],
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
id: 'redo',
|
|
154
|
+
label: 'Redo',
|
|
155
|
+
icon: 'redo',
|
|
156
|
+
group: 'history',
|
|
157
|
+
run: (e) => e.dispatchCommand(REDO_COMMAND, undefined),
|
|
158
|
+
isDisabled: (f) => !f.canRedo,
|
|
159
|
+
surfaces: ['toolbar', 'context'],
|
|
160
|
+
},
|
|
161
|
+
];
|
|
162
|
+
const byId = new Map(items.map((i) => [i.id, i]));
|
|
163
|
+
const shortcut = (id) => (editor) => {
|
|
164
|
+
const item = byId.get(id);
|
|
165
|
+
if (!item)
|
|
166
|
+
return false;
|
|
167
|
+
item.run(editor, NOOP_CTX);
|
|
168
|
+
return true;
|
|
169
|
+
};
|
|
170
|
+
return {
|
|
171
|
+
name: 'core',
|
|
172
|
+
nodes: GFM_NODES,
|
|
173
|
+
transformers: GFM_TRANSFORMERS,
|
|
174
|
+
items,
|
|
175
|
+
// registerList wires list commands/indentation; registerCheckList adds the
|
|
176
|
+
// click-to-toggle on task items. (Linking is handled by the editor's link
|
|
177
|
+
// dialog via $toggleLink — see commitLink in editor.ts.)
|
|
178
|
+
register: (editor) => mergeRegister(registerList(editor), registerCheckList(editor)),
|
|
179
|
+
shortcuts: [
|
|
180
|
+
{ combo: 'Mod-Alt-1', run: shortcut('h1') },
|
|
181
|
+
{ combo: 'Mod-Alt-2', run: shortcut('h2') },
|
|
182
|
+
{ combo: 'Mod-Alt-3', run: shortcut('h3') },
|
|
183
|
+
{ combo: 'Mod-Shift-7', run: shortcut('numberList') },
|
|
184
|
+
{ combo: 'Mod-Shift-8', run: shortcut('bulletList') },
|
|
185
|
+
{ combo: 'Mod-Shift-9', run: shortcut('quote') },
|
|
186
|
+
],
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.js","sourceRoot":"","sources":["../../src/plugins/core.ts"],"names":[],"mappings":"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","sourcesContent":["// The core plugin: the GFM superset of nodes, transformers, command items, and\n// shortcuts. This is the default plugin when none are supplied, so the minimal\n// `markdownEditor()` one-liner still has full keyboard formatting.\n\nimport {\n $createParagraphNode,\n $getSelection,\n $isRangeSelection,\n FORMAT_TEXT_COMMAND,\n REDO_COMMAND,\n UNDO_COMMAND,\n type ElementNode,\n type LexicalEditor,\n type TextFormatType,\n} from 'lexical'\nimport { mergeRegister } from '@lexical/utils'\nimport { $setBlocksType } from '@lexical/selection'\nimport { $createHeadingNode, $createQuoteNode, type HeadingTagType } from '@lexical/rich-text'\nimport { $createCodeNode } from '@lexical/code-core'\nimport {\n INSERT_CHECK_LIST_COMMAND,\n INSERT_ORDERED_LIST_COMMAND,\n INSERT_UNORDERED_LIST_COMMAND,\n registerCheckList,\n registerList,\n} from '@lexical/list'\nimport type { CommandContext, CommandItem, MarkdownPlugin } from './types.js'\nimport { GFM_NODES, GFM_TRANSFORMERS } from '../transformers/gfm.js'\n\nconst NOOP_CTX: CommandContext = { send: () => {} }\n\nfunction inline(format: TextFormatType): (editor: LexicalEditor) => void {\n return (editor) => editor.dispatchCommand(FORMAT_TEXT_COMMAND, format)\n}\n\n/** Wrap a node-factory into an editor action that converts the selected blocks. */\nfunction block(create: () => ElementNode): (editor: LexicalEditor) => void {\n return (editor) =>\n editor.update(() => {\n const selection = $getSelection()\n if ($isRangeSelection(selection)) $setBlocksType(selection, create)\n })\n}\n\nfunction heading(tag: HeadingTagType): (editor: LexicalEditor) => void {\n return block(() => $createHeadingNode(tag))\n}\n\nexport interface CorePluginOptions {\n /** Reserved for future core options. */\n readonly _?: never\n}\n\nexport function corePlugin(_opts: CorePluginOptions = {}): MarkdownPlugin {\n const items: CommandItem[] = [\n {\n id: 'bold',\n label: 'Bold',\n icon: 'bold',\n group: 'inline',\n keywords: ['strong'],\n run: inline('bold'),\n isActive: (f) => f.bold,\n },\n {\n id: 'italic',\n label: 'Italic',\n icon: 'italic',\n group: 'inline',\n keywords: ['emphasis'],\n run: inline('italic'),\n isActive: (f) => f.italic,\n },\n {\n id: 'strikethrough',\n label: 'Strikethrough',\n icon: 'strikethrough',\n group: 'inline',\n keywords: ['strike', 'del'],\n run: inline('strikethrough'),\n isActive: (f) => f.strikethrough,\n },\n {\n id: 'code',\n label: 'Inline code',\n icon: 'code',\n group: 'inline',\n keywords: ['mono'],\n run: inline('code'),\n isActive: (f) => f.code,\n },\n {\n id: 'paragraph',\n label: 'Text',\n icon: 'paragraph',\n group: 'block',\n keywords: ['body', 'normal'],\n run: block(() => $createParagraphNode()),\n isActive: (f) => f.blockType === 'paragraph',\n },\n {\n id: 'h1',\n label: 'Heading 1',\n icon: 'h1',\n group: 'block',\n keywords: ['title'],\n run: heading('h1'),\n isActive: (f) => f.blockType === 'h1',\n },\n {\n id: 'h2',\n label: 'Heading 2',\n icon: 'h2',\n group: 'block',\n run: heading('h2'),\n isActive: (f) => f.blockType === 'h2',\n },\n {\n id: 'h3',\n label: 'Heading 3',\n icon: 'h3',\n group: 'block',\n run: heading('h3'),\n isActive: (f) => f.blockType === 'h3',\n },\n {\n id: 'quote',\n label: 'Quote',\n icon: 'quote',\n group: 'block',\n keywords: ['blockquote'],\n run: block(() => $createQuoteNode()),\n isActive: (f) => f.blockType === 'quote',\n },\n {\n id: 'codeBlock',\n label: 'Code block',\n icon: 'code-block',\n group: 'block',\n keywords: ['fence', 'pre'],\n run: block(() => $createCodeNode()),\n isActive: (f) => f.blockType === 'code',\n },\n {\n id: 'bulletList',\n label: 'Bulleted list',\n icon: 'list-bullet',\n group: 'list',\n keywords: ['unordered', 'ul'],\n run: (e) => e.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined),\n isActive: (f) => f.blockType === 'bullet',\n },\n {\n id: 'numberList',\n label: 'Numbered list',\n icon: 'list-number',\n group: 'list',\n keywords: ['ordered', 'ol'],\n run: (e) => e.dispatchCommand(INSERT_ORDERED_LIST_COMMAND, undefined),\n isActive: (f) => f.blockType === 'number',\n },\n {\n id: 'checkList',\n label: 'Task list',\n icon: 'list-check',\n group: 'list',\n keywords: ['todo', 'checkbox'],\n run: (e) => e.dispatchCommand(INSERT_CHECK_LIST_COMMAND, undefined),\n isActive: (f) => f.blockType === 'check',\n },\n {\n id: 'undo',\n label: 'Undo',\n icon: 'undo',\n group: 'history',\n run: (e) => e.dispatchCommand(UNDO_COMMAND, undefined),\n isDisabled: (f) => !f.canUndo,\n surfaces: ['toolbar', 'context'],\n },\n {\n id: 'redo',\n label: 'Redo',\n icon: 'redo',\n group: 'history',\n run: (e) => e.dispatchCommand(REDO_COMMAND, undefined),\n isDisabled: (f) => !f.canRedo,\n surfaces: ['toolbar', 'context'],\n },\n ]\n\n const byId = new Map(items.map((i) => [i.id, i]))\n const shortcut =\n (id: string) =>\n (editor: LexicalEditor): boolean => {\n const item = byId.get(id)\n if (!item) return false\n item.run(editor, NOOP_CTX)\n return true\n }\n\n return {\n name: 'core',\n nodes: GFM_NODES,\n transformers: GFM_TRANSFORMERS,\n items,\n // registerList wires list commands/indentation; registerCheckList adds the\n // click-to-toggle on task items. (Linking is handled by the editor's link\n // dialog via $toggleLink — see commitLink in editor.ts.)\n register: (editor) => mergeRegister(registerList(editor), registerCheckList(editor)),\n shortcuts: [\n { combo: 'Mod-Alt-1', run: shortcut('h1') },\n { combo: 'Mod-Alt-2', run: shortcut('h2') },\n { combo: 'Mod-Alt-3', run: shortcut('h3') },\n { combo: 'Mod-Shift-7', run: shortcut('numberList') },\n { combo: 'Mod-Shift-8', run: shortcut('bulletList') },\n { combo: 'Mod-Shift-9', run: shortcut('quote') },\n ],\n }\n}\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { MarkdownPlugin } from './types.js';
|
|
2
|
+
/** A small default shortcode → emoji map. Extend via `emojiPlugin({ emoji })`. */
|
|
3
|
+
export declare const DEFAULT_EMOJI: Readonly<Record<string, string>>;
|
|
4
|
+
export interface EmojiPluginOptions {
|
|
5
|
+
/** Extra/override shortcode → emoji entries (merged over the defaults). */
|
|
6
|
+
emoji?: Readonly<Record<string, string>>;
|
|
7
|
+
}
|
|
8
|
+
export declare function emojiPlugin(opts?: EmojiPluginOptions): MarkdownPlugin;
|
|
9
|
+
//# sourceMappingURL=emoji.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emoji.d.ts","sourceRoot":"","sources":["../../src/plugins/emoji.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhD,kFAAkF;AAClF,eAAO,MAAM,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAqB1D,CAAA;AAkBD,MAAM,WAAW,kBAAkB;IACjC,2EAA2E;IAC3E,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CACzC;AAED,wBAAgB,WAAW,CAAC,IAAI,GAAE,kBAAuB,GAAG,cAAc,CAMzE"}
|