@llui/markdown-editor 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__llui_deps.json +21 -0
- package/dist/editor.d.ts +24 -0
- package/dist/editor.d.ts.map +1 -1
- package/dist/editor.js +33 -4
- package/dist/editor.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/plugins/core.d.ts.map +1 -1
- package/dist/plugins/core.js +3 -40
- package/dist/plugins/core.js.map +1 -1
- package/dist/plugins/inline.d.ts +12 -0
- package/dist/plugins/inline.d.ts.map +1 -0
- package/dist/plugins/inline.js +59 -0
- package/dist/plugins/inline.js.map +1 -0
- package/dist/plugins/single-block.d.ts +29 -0
- package/dist/plugins/single-block.d.ts.map +1 -0
- package/dist/plugins/single-block.js +145 -0
- package/dist/plugins/single-block.js.map +1 -0
- package/dist/state.d.ts +23 -0
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +22 -0
- package/dist/state.js.map +1 -1
- package/dist/styles/editor.css +25 -0
- package/dist/surfaces/toolbar.d.ts +4 -1
- package/dist/surfaces/toolbar.d.ts.map +1 -1
- package/dist/surfaces/toolbar.js +21 -0
- package/dist/surfaces/toolbar.js.map +1 -1
- package/dist/transformers/gfm.d.ts +4 -0
- package/dist/transformers/gfm.d.ts.map +1 -1
- package/dist/transformers/gfm.js +15 -9
- package/dist/transformers/gfm.js.map +1 -1
- package/package.json +7 -7
package/dist/__llui_deps.json
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"index": 0,
|
|
11
11
|
"reads": [
|
|
12
12
|
"changeDebounceMs",
|
|
13
|
+
"collab",
|
|
13
14
|
"defaultValue",
|
|
14
15
|
"namespace",
|
|
15
16
|
"onChange",
|
|
@@ -154,6 +155,21 @@
|
|
|
154
155
|
}
|
|
155
156
|
]
|
|
156
157
|
},
|
|
158
|
+
"plugins/single-block#singleBlockPlugin": {
|
|
159
|
+
"helperLocalPaths": [],
|
|
160
|
+
"kind": "view-helper",
|
|
161
|
+
"viaParams": [
|
|
162
|
+
{
|
|
163
|
+
"index": 0,
|
|
164
|
+
"reads": [
|
|
165
|
+
"allowLineBreaks",
|
|
166
|
+
"formats",
|
|
167
|
+
"link"
|
|
168
|
+
],
|
|
169
|
+
"shape": "state-value"
|
|
170
|
+
}
|
|
171
|
+
]
|
|
172
|
+
},
|
|
157
173
|
"plugins/ui#definePluginUI": {
|
|
158
174
|
"helperLocalPaths": [],
|
|
159
175
|
"kind": "view-helper",
|
|
@@ -177,6 +193,7 @@
|
|
|
177
193
|
{
|
|
178
194
|
"index": 0,
|
|
179
195
|
"reads": [
|
|
196
|
+
"collab",
|
|
180
197
|
"readonly",
|
|
181
198
|
"value",
|
|
182
199
|
"value.length"
|
|
@@ -197,11 +214,14 @@
|
|
|
197
214
|
"index": 1,
|
|
198
215
|
"reads": [
|
|
199
216
|
"charCount",
|
|
217
|
+
"connected",
|
|
200
218
|
"format",
|
|
201
219
|
"id",
|
|
202
220
|
"overlay",
|
|
221
|
+
"peers",
|
|
203
222
|
"query",
|
|
204
223
|
"readonly",
|
|
224
|
+
"synced",
|
|
205
225
|
"type",
|
|
206
226
|
"value",
|
|
207
227
|
"wordCount",
|
|
@@ -237,6 +257,7 @@
|
|
|
237
257
|
"reads": [
|
|
238
258
|
"aria-label",
|
|
239
259
|
"blockSelect",
|
|
260
|
+
"collab",
|
|
240
261
|
"format",
|
|
241
262
|
"glyphs",
|
|
242
263
|
"groups",
|
package/dist/editor.d.ts
CHANGED
|
@@ -26,7 +26,31 @@ export interface EditorConfig {
|
|
|
26
26
|
onReady?: (editor: LexicalEditor) => void;
|
|
27
27
|
/** Render the built-in toolbar above the editor. Default false (minimal). */
|
|
28
28
|
toolbar?: boolean;
|
|
29
|
+
/** Enable collaborative editing. The editor hands you a markdown `seed` and
|
|
30
|
+
* status sinks; return a binding (build it with `yjsCollab` from
|
|
31
|
+
* `@llui/lexical-collab`, wiring your own provider). Mutually exclusive with
|
|
32
|
+
* `value` — the shared CRDT document, not a markdown signal, owns the content.
|
|
33
|
+
* `defaultValue` becomes the seed the bootstrapping peer writes. */
|
|
34
|
+
collab?: CollabFactory;
|
|
29
35
|
}
|
|
36
|
+
/** Disposer-returning binding the collab layer installs on the live editor.
|
|
37
|
+
* `@llui/lexical-collab`'s `YjsCollab` satisfies this structurally, so
|
|
38
|
+
* `@llui/markdown-editor` needs no Yjs dependency of its own. */
|
|
39
|
+
export interface CollabBinding {
|
|
40
|
+
register: (editor: LexicalEditor) => () => void;
|
|
41
|
+
}
|
|
42
|
+
/** Hooks the editor injects into the {@link CollabFactory}: a markdown `seed`
|
|
43
|
+
* (run once by the bootstrapping peer to fill an empty shared doc from
|
|
44
|
+
* `defaultValue`) plus status sinks the editor mirrors into `state.collab`.
|
|
45
|
+
* Spread straight into `yjsCollab({ id, provider, user, ...hooks })`. */
|
|
46
|
+
export interface CollabHooks {
|
|
47
|
+
seed: (editor: LexicalEditor) => void;
|
|
48
|
+
onStatus: (connected: boolean) => void;
|
|
49
|
+
onSync: (synced: boolean) => void;
|
|
50
|
+
onPeers: (count: number) => void;
|
|
51
|
+
}
|
|
52
|
+
/** Builds the collab binding from the editor-supplied hooks. */
|
|
53
|
+
export type CollabFactory = (hooks: CollabHooks) => CollabBinding;
|
|
30
54
|
/** Hooks the chrome layer (toolbar/menus) uses to compose around the editor. */
|
|
31
55
|
export interface EditorParts {
|
|
32
56
|
/** The merged, surface-filtered command items. */
|
package/dist/editor.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../src/editor.ts"],"names":[],"mappings":"AAMA,OAAO,EAA2B,KAAK,kBAAkB,EAAE,KAAK,aAAa,EAAE,MAAM,SAAS,CAAA;AAM9F,OAAO,EAAmC,KAAK,MAAM,EAAE,KAAK,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAUjG,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAKrE,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,SAAS,EAEd,KAAK,WAAW,EAChB,KAAK,WAAW,EACjB,MAAM,YAAY,CAAA;AAEnB,MAAM,WAAW,YAAY;IAC3B;2FACuF;IACvF,OAAO,CAAC,EAAE,SAAS,cAAc,EAAE,CAAA;IACnC,4CAA4C;IAC5C,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,wEAAwE;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;IACtB,4DAA4D;IAC5D,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,kBAAkB,CAAA;IAC1B,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;IACrC,uEAAuE;IACvE,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAA;IAC9C,mFAAmF;IACnF,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAA;IACzC,6EAA6E;IAC7E,OAAO,CAAC,EAAE,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../src/editor.ts"],"names":[],"mappings":"AAMA,OAAO,EAA2B,KAAK,kBAAkB,EAAE,KAAK,aAAa,EAAE,MAAM,SAAS,CAAA;AAM9F,OAAO,EAAmC,KAAK,MAAM,EAAE,KAAK,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAUjG,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAKrE,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,SAAS,EAEd,KAAK,WAAW,EAChB,KAAK,WAAW,EACjB,MAAM,YAAY,CAAA;AAEnB,MAAM,WAAW,YAAY;IAC3B;2FACuF;IACvF,OAAO,CAAC,EAAE,SAAS,cAAc,EAAE,CAAA;IACnC,4CAA4C;IAC5C,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,wEAAwE;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;IACtB,4DAA4D;IAC5D,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,kBAAkB,CAAA;IAC1B,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;IACrC,uEAAuE;IACvE,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAA;IAC9C,mFAAmF;IACnF,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAA;IACzC,6EAA6E;IAC7E,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;;wEAIoE;IACpE,MAAM,CAAC,EAAE,aAAa,CAAA;CACvB;AAED;;iEAEiE;AACjE,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,MAAM,IAAI,CAAA;CAChD;AAED;;;yEAGyE;AACzE,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAA;IACrC,QAAQ,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAA;IACjC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACjC;AAED,gEAAgE;AAChE,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,WAAW,KAAK,aAAa,CAAA;AAEjE,gFAAgF;AAChF,MAAM,WAAW,WAAW;IAC1B,kDAAkD;IAClD,KAAK,EAAE,SAAS,WAAW,EAAE,CAAA;IAC7B,2DAA2D;IAC3D,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,CAAA;CAC5B;AAOD;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,MAAM,GAAE,YAAiB,GACxB,kBAAkB,CAAC,WAAW,EAAE,SAAS,EAAE,YAAY,CAAC,CAwL1D"}
|
package/dist/editor.js
CHANGED
|
@@ -48,10 +48,20 @@ export function markdownEditor(config = {}) {
|
|
|
48
48
|
$setSelection(null);
|
|
49
49
|
}, { tag: PROGRAMMATIC_TAG }),
|
|
50
50
|
});
|
|
51
|
+
if (config.collab && config.value) {
|
|
52
|
+
throw new Error('markdownEditor: `collab` and `value` are mutually exclusive — in a collaborative ' +
|
|
53
|
+
'session the shared CRDT document owns the content, not a markdown signal. ' +
|
|
54
|
+
'Use `defaultValue` as the bootstrap seed instead.');
|
|
55
|
+
}
|
|
56
|
+
const collabEnabled = !!config.collab;
|
|
51
57
|
const seedValue = config.value ? config.value.peek() : (config.defaultValue ?? '');
|
|
52
58
|
// ── Composed TEA: core + plugin UI slices ──────────────────────────────────
|
|
53
59
|
const composedInit = () => {
|
|
54
|
-
const [core, effects] = init({
|
|
60
|
+
const [core, effects] = init({
|
|
61
|
+
value: seedValue,
|
|
62
|
+
readonly: config.readonly ?? false,
|
|
63
|
+
collab: collabEnabled,
|
|
64
|
+
});
|
|
55
65
|
const slices = {};
|
|
56
66
|
for (const { name, ui } of pluginUIs)
|
|
57
67
|
slices[name] = ui.init();
|
|
@@ -84,6 +94,19 @@ export function markdownEditor(config = {}) {
|
|
|
84
94
|
baseOnEffect(effect, api);
|
|
85
95
|
};
|
|
86
96
|
const view = ({ state, send, }) => {
|
|
97
|
+
// Build the collab binding (once, at mount) from the consumer's factory,
|
|
98
|
+
// injecting the markdown seed + status sinks that mirror into `state.collab`.
|
|
99
|
+
const collabBinding = config.collab
|
|
100
|
+
? config.collab({
|
|
101
|
+
seed: () => {
|
|
102
|
+
$convertFromMarkdownString(seedValue, transformers);
|
|
103
|
+
$setSelection(null);
|
|
104
|
+
},
|
|
105
|
+
onStatus: (connected) => send({ type: 'collabStatus', connected }),
|
|
106
|
+
onSync: (synced) => send({ type: 'collabSync', synced }),
|
|
107
|
+
onPeers: (peers) => send({ type: 'collabPeers', peers }),
|
|
108
|
+
})
|
|
109
|
+
: null;
|
|
87
110
|
const host = lexicalForeign({
|
|
88
111
|
namespace: config.namespace ?? 'llui-markdown',
|
|
89
112
|
theme: config.theme,
|
|
@@ -93,8 +116,12 @@ export function markdownEditor(config = {}) {
|
|
|
93
116
|
$convertFromMarkdownString(value, transformers);
|
|
94
117
|
$setSelection(null);
|
|
95
118
|
},
|
|
96
|
-
|
|
97
|
-
|
|
119
|
+
// In collab mode the shared CRDT owns the document: the local undo stack
|
|
120
|
+
// and the boot-time seed are disabled — the binding supplies a scoped undo
|
|
121
|
+
// manager and a sync-gated bootstrap instead.
|
|
122
|
+
...(collabBinding ? { history: false, seedMode: 'deferred' } : {}),
|
|
123
|
+
defaultValue: collabBinding || config.value ? undefined : (config.defaultValue ?? ''),
|
|
124
|
+
...(config.value && !collabBinding ? { value: config.value } : {}),
|
|
98
125
|
readonly: state.at('readonly'),
|
|
99
126
|
...(config.changeDebounceMs !== undefined
|
|
100
127
|
? { changeDebounceMs: config.changeDebounceMs }
|
|
@@ -103,6 +130,8 @@ export function markdownEditor(config = {}) {
|
|
|
103
130
|
const disposers = [registerMarkdownShortcuts(editor, transformers)];
|
|
104
131
|
if (decorators.length > 0)
|
|
105
132
|
disposers.push(registerDecoratorBridges(editor, decorators));
|
|
133
|
+
if (collabBinding)
|
|
134
|
+
disposers.push(collabBinding.register(editor));
|
|
106
135
|
return () => {
|
|
107
136
|
for (const dispose of disposers)
|
|
108
137
|
dispose();
|
|
@@ -140,7 +169,7 @@ export function markdownEditor(config = {}) {
|
|
|
140
169
|
return [host, ...pluginViews];
|
|
141
170
|
return [
|
|
142
171
|
div({ 'data-scope': 'md-editor', 'data-part': 'root' }, [
|
|
143
|
-
renderToolbar({ format: state.at('format'), send, items }),
|
|
172
|
+
renderToolbar({ format: state.at('format'), send, items, collab: state.at('collab') }),
|
|
144
173
|
div({ 'data-scope': 'md-editor', 'data-part': 'surface' }, [host]),
|
|
145
174
|
]),
|
|
146
175
|
...pluginViews,
|
package/dist/editor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor.js","sourceRoot":"","sources":["../src/editor.ts"],"names":[],"mappings":"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","sourcesContent":["// `markdownEditor(config)` — the high-level component. Lexical owns the live\n// document; this wires the foreign seam to the markdown transformer converters,\n// surfaces the format state for the chrome, routes command intents back to the\n// live editor through effects, and COMPOSES plugin UI extensions (each plugin's\n// state slice + reducer + view + effects) into the single component.\n\nimport { $getRoot, $setSelection, type EditorThemeClasses, type LexicalEditor } from 'lexical'\nimport {\n $convertFromMarkdownString,\n $convertToMarkdownString,\n registerMarkdownShortcuts,\n} from '@lexical/markdown'\nimport { component, div, type Renderable, type Signal, type SignalComponentDef } from '@llui/dom'\nimport {\n lexicalForeign,\n registerDecoratorBridges,\n PROGRAMMATIC_TAG,\n type DecoratorBridge,\n} from '@llui/lexical'\nimport { corePlugin } from './plugins/core.js'\nimport { linkPlugin } from './plugins/link.js'\nimport { toolbar as renderToolbar } from './surfaces/toolbar.js'\nimport type { CommandItem, MarkdownPlugin } from './plugins/types.js'\nimport type { PluginUI } from './plugins/ui.js'\nimport { buildTransformers } from './transformers/registry.js'\nimport { computeFormatState } from './format.js'\nimport { makeOnEffect } from './effects.js'\nimport {\n countWords,\n init,\n update,\n type EditorEffect,\n type EditorMsg,\n type EditorOutMsg,\n type EditorState,\n type FormatState,\n} from './state.js'\n\nexport interface EditorConfig {\n /** Plugins composing the feature set; order defines transformer precedence.\n * Defaults to `[corePlugin(), linkPlugin()]` so the minimal editor has GFM + links. */\n plugins?: readonly MarkdownPlugin[]\n /** Initial markdown (uncontrolled seed). */\n defaultValue?: string\n /** Controlled: the consumer owns this signal; the editor follows it. */\n value?: Signal<string>\n /** Debounced markdown-emission window (ms). Default 300. */\n changeDebounceMs?: number\n placeholder?: string\n readonly?: boolean\n /** Lexical theme class map. */\n theme?: EditorThemeClasses\n /** Editor namespace (instance isolation). */\n namespace?: string\n /** Outbound markdown (after debounce). */\n onChange?: (markdown: string) => void\n /** Outbound format surface (for chrome built outside this package). */\n onFormatChange?: (format: FormatState) => void\n /** Receives the live Lexical editor at mount (imperative access, collab hooks). */\n onReady?: (editor: LexicalEditor) => void\n /** Render the built-in toolbar above the editor. Default false (minimal). */\n toolbar?: boolean\n}\n\n/** Hooks the chrome layer (toolbar/menus) uses to compose around the editor. */\nexport interface EditorParts {\n /** The merged, surface-filtered command items. */\n items: readonly CommandItem[]\n /** Reactive format signal for `connect`-style toolbars. */\n format: Signal<FormatState>\n}\n\n/** Default plugin set when the consumer supplies none. */\nfunction defaultPlugins(): MarkdownPlugin[] {\n return [corePlugin(), linkPlugin()]\n}\n\n/**\n * Build the markdown editor component. Embed it with `mountApp(el, markdownEditor(...))`\n * or compose it inside a larger component.\n */\nexport function markdownEditor(\n config: EditorConfig = {},\n): SignalComponentDef<EditorState, EditorMsg, EditorEffect> {\n const plugins = config.plugins && config.plugins.length > 0 ? config.plugins : defaultPlugins()\n const transformers = buildTransformers(plugins)\n\n const items: CommandItem[] = plugins.flatMap((p) => p.items ?? [])\n const itemsById = new Map(items.map((i) => [i.id, i]))\n // Share the merged item list with plugins that want it (e.g. the slash menu).\n for (const plugin of plugins) plugin.onItems?.(items)\n const decorators: DecoratorBridge[] = plugins.flatMap((p) => p.decorators ?? [])\n const pluginUIs: Array<{ name: string; ui: PluginUI }> = plugins\n .filter((p): p is MarkdownPlugin & { ui: PluginUI } => p.ui !== undefined)\n .map((p) => ({ name: p.name, ui: p.ui }))\n const pluginUIByName = new Map(pluginUIs.map((p) => [p.name, p.ui]))\n\n // The live editor, captured at mount; effects dispatch through it.\n let editorRef: LexicalEditor | null = null\n const getEditor = (): LexicalEditor | null => editorRef\n\n const baseOnEffect = makeOnEffect(getEditor, itemsById, {\n onChange: config.onChange,\n onFormatChange: config.onFormatChange,\n applyValue: (editor, value) =>\n editor.update(\n () => {\n $convertFromMarkdownString(value, transformers)\n // Clear selection so the reconciler doesn't pull DOM focus into the\n // editor on an external push (e.g. typing in a bound source textarea).\n $setSelection(null)\n },\n { tag: PROGRAMMATIC_TAG },\n ),\n })\n\n const seedValue = config.value ? config.value.peek() : (config.defaultValue ?? '')\n\n // ── Composed TEA: core + plugin UI slices ──────────────────────────────────\n const composedInit = (): [EditorState, EditorEffect[]] => {\n const [core, effects] = init({ value: seedValue, readonly: config.readonly ?? false })\n const slices: Record<string, unknown> = {}\n for (const { name, ui } of pluginUIs) slices[name] = ui.init()\n return [{ ...core, plugins: slices }, effects]\n }\n\n const composedUpdate = (state: EditorState, msg: EditorMsg): [EditorState, EditorEffect[]] => {\n if (msg.type === 'plugin') {\n const ui = pluginUIByName.get(msg.name)\n if (!ui?.update) return [state, []]\n const result = ui.update(state.plugins[msg.name], msg.msg)\n const [slice, effects] = (Array.isArray(result) ? result : [result, []]) as [\n unknown,\n unknown[],\n ]\n return [\n { ...state, plugins: { ...state.plugins, [msg.name]: slice } },\n effects.map((effect) => ({ type: 'pluginEffect' as const, name: msg.name, effect })),\n ]\n }\n return update(state, msg)\n }\n\n const composedOnEffect = (\n effect: EditorEffect,\n api: { send: (msg: EditorMsg) => void; state: Signal<EditorState> },\n ): void => {\n if (effect.type === 'pluginEffect') {\n const ui = pluginUIByName.get(effect.name)\n ui?.onEffect?.(effect.effect, {\n editor: getEditor,\n send: (msg) => api.send({ type: 'plugin', name: effect.name, msg }),\n emit: (msg) => api.send(msg as EditorMsg),\n })\n return\n }\n baseOnEffect(effect, api)\n }\n\n const view = ({\n state,\n send,\n }: {\n state: Signal<EditorState>\n send: (msg: EditorMsg) => void\n }): Renderable => {\n const host = lexicalForeign<EditorOutMsg>({\n namespace: config.namespace ?? 'llui-markdown',\n theme: config.theme,\n plugins,\n serialize: (editor) =>\n editor.getEditorState().read(() => $convertToMarkdownString(transformers)),\n deserialize: (_editor, value) => {\n $convertFromMarkdownString(value, transformers)\n $setSelection(null)\n },\n defaultValue: config.value ? undefined : (config.defaultValue ?? ''),\n ...(config.value ? { value: config.value } : {}),\n readonly: state.at('readonly'),\n ...(config.changeDebounceMs !== undefined\n ? { changeDebounceMs: config.changeDebounceMs }\n : {}),\n register: (editor) => {\n const disposers = [registerMarkdownShortcuts(editor, transformers)]\n if (decorators.length > 0) disposers.push(registerDecoratorBridges(editor, decorators))\n return () => {\n for (const dispose of disposers) dispose()\n }\n },\n onReady: (editor) => {\n editorRef = editor\n if (config.placeholder) {\n editor.getRootElement()?.setAttribute('data-placeholder', config.placeholder)\n }\n config.onReady?.(editor)\n },\n onChange: (value) => send({ type: 'markdownChanged', value }),\n onSelectionChange: (ctx) => {\n const format = computeFormatState(ctx.editor, ctx)\n const text = ctx.editor.getEditorState().read(() => $getRoot().getTextContent())\n // Toggle an empty marker so CSS can show the placeholder.\n ctx.editor.getRootElement()?.setAttribute('data-empty', text === '' ? 'true' : 'false')\n send({ type: 'formatChanged', format, wordCount: countWords(text), charCount: text.length })\n },\n emit: (msg) => send(msg),\n })\n\n // Plugin view contributions (overlays/panels) — each gets its own slice + send.\n const pluginViews: Renderable = pluginUIs.flatMap(({ name, ui }) => {\n if (!ui.view) return []\n const rendered = ui.view({\n state: state.at(`plugins.${name}`),\n send: (msg) => send({ type: 'plugin', name, msg }),\n editor: getEditor,\n })\n return Array.isArray(rendered) ? rendered : [rendered]\n })\n\n if (!config.toolbar) return [host, ...pluginViews]\n return [\n div({ 'data-scope': 'md-editor', 'data-part': 'root' }, [\n renderToolbar({ format: state.at('format'), send, items }),\n div({ 'data-scope': 'md-editor', 'data-part': 'surface' }, [host]),\n ]),\n ...pluginViews,\n ]\n }\n\n return component<EditorState, EditorMsg, EditorEffect>({\n name: 'MarkdownEditor',\n init: composedInit,\n update: composedUpdate,\n view,\n onEffect: composedOnEffect,\n })\n}\n"]}
|
|
1
|
+
{"version":3,"file":"editor.js","sourceRoot":"","sources":["../src/editor.ts"],"names":[],"mappings":"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","sourcesContent":["// `markdownEditor(config)` — the high-level component. Lexical owns the live\n// document; this wires the foreign seam to the markdown transformer converters,\n// surfaces the format state for the chrome, routes command intents back to the\n// live editor through effects, and COMPOSES plugin UI extensions (each plugin's\n// state slice + reducer + view + effects) into the single component.\n\nimport { $getRoot, $setSelection, type EditorThemeClasses, type LexicalEditor } from 'lexical'\nimport {\n $convertFromMarkdownString,\n $convertToMarkdownString,\n registerMarkdownShortcuts,\n} from '@lexical/markdown'\nimport { component, div, type Renderable, type Signal, type SignalComponentDef } from '@llui/dom'\nimport {\n lexicalForeign,\n registerDecoratorBridges,\n PROGRAMMATIC_TAG,\n type DecoratorBridge,\n} from '@llui/lexical'\nimport { corePlugin } from './plugins/core.js'\nimport { linkPlugin } from './plugins/link.js'\nimport { toolbar as renderToolbar } from './surfaces/toolbar.js'\nimport type { CommandItem, MarkdownPlugin } from './plugins/types.js'\nimport type { PluginUI } from './plugins/ui.js'\nimport { buildTransformers } from './transformers/registry.js'\nimport { computeFormatState } from './format.js'\nimport { makeOnEffect } from './effects.js'\nimport {\n countWords,\n init,\n update,\n type EditorEffect,\n type EditorMsg,\n type EditorOutMsg,\n type EditorState,\n type FormatState,\n} from './state.js'\n\nexport interface EditorConfig {\n /** Plugins composing the feature set; order defines transformer precedence.\n * Defaults to `[corePlugin(), linkPlugin()]` so the minimal editor has GFM + links. */\n plugins?: readonly MarkdownPlugin[]\n /** Initial markdown (uncontrolled seed). */\n defaultValue?: string\n /** Controlled: the consumer owns this signal; the editor follows it. */\n value?: Signal<string>\n /** Debounced markdown-emission window (ms). Default 300. */\n changeDebounceMs?: number\n placeholder?: string\n readonly?: boolean\n /** Lexical theme class map. */\n theme?: EditorThemeClasses\n /** Editor namespace (instance isolation). */\n namespace?: string\n /** Outbound markdown (after debounce). */\n onChange?: (markdown: string) => void\n /** Outbound format surface (for chrome built outside this package). */\n onFormatChange?: (format: FormatState) => void\n /** Receives the live Lexical editor at mount (imperative access, collab hooks). */\n onReady?: (editor: LexicalEditor) => void\n /** Render the built-in toolbar above the editor. Default false (minimal). */\n toolbar?: boolean\n /** Enable collaborative editing. The editor hands you a markdown `seed` and\n * status sinks; return a binding (build it with `yjsCollab` from\n * `@llui/lexical-collab`, wiring your own provider). Mutually exclusive with\n * `value` — the shared CRDT document, not a markdown signal, owns the content.\n * `defaultValue` becomes the seed the bootstrapping peer writes. */\n collab?: CollabFactory\n}\n\n/** Disposer-returning binding the collab layer installs on the live editor.\n * `@llui/lexical-collab`'s `YjsCollab` satisfies this structurally, so\n * `@llui/markdown-editor` needs no Yjs dependency of its own. */\nexport interface CollabBinding {\n register: (editor: LexicalEditor) => () => void\n}\n\n/** Hooks the editor injects into the {@link CollabFactory}: a markdown `seed`\n * (run once by the bootstrapping peer to fill an empty shared doc from\n * `defaultValue`) plus status sinks the editor mirrors into `state.collab`.\n * Spread straight into `yjsCollab({ id, provider, user, ...hooks })`. */\nexport interface CollabHooks {\n seed: (editor: LexicalEditor) => void\n onStatus: (connected: boolean) => void\n onSync: (synced: boolean) => void\n onPeers: (count: number) => void\n}\n\n/** Builds the collab binding from the editor-supplied hooks. */\nexport type CollabFactory = (hooks: CollabHooks) => CollabBinding\n\n/** Hooks the chrome layer (toolbar/menus) uses to compose around the editor. */\nexport interface EditorParts {\n /** The merged, surface-filtered command items. */\n items: readonly CommandItem[]\n /** Reactive format signal for `connect`-style toolbars. */\n format: Signal<FormatState>\n}\n\n/** Default plugin set when the consumer supplies none. */\nfunction defaultPlugins(): MarkdownPlugin[] {\n return [corePlugin(), linkPlugin()]\n}\n\n/**\n * Build the markdown editor component. Embed it with `mountApp(el, markdownEditor(...))`\n * or compose it inside a larger component.\n */\nexport function markdownEditor(\n config: EditorConfig = {},\n): SignalComponentDef<EditorState, EditorMsg, EditorEffect> {\n const plugins = config.plugins && config.plugins.length > 0 ? config.plugins : defaultPlugins()\n const transformers = buildTransformers(plugins)\n\n const items: CommandItem[] = plugins.flatMap((p) => p.items ?? [])\n const itemsById = new Map(items.map((i) => [i.id, i]))\n // Share the merged item list with plugins that want it (e.g. the slash menu).\n for (const plugin of plugins) plugin.onItems?.(items)\n const decorators: DecoratorBridge[] = plugins.flatMap((p) => p.decorators ?? [])\n const pluginUIs: Array<{ name: string; ui: PluginUI }> = plugins\n .filter((p): p is MarkdownPlugin & { ui: PluginUI } => p.ui !== undefined)\n .map((p) => ({ name: p.name, ui: p.ui }))\n const pluginUIByName = new Map(pluginUIs.map((p) => [p.name, p.ui]))\n\n // The live editor, captured at mount; effects dispatch through it.\n let editorRef: LexicalEditor | null = null\n const getEditor = (): LexicalEditor | null => editorRef\n\n const baseOnEffect = makeOnEffect(getEditor, itemsById, {\n onChange: config.onChange,\n onFormatChange: config.onFormatChange,\n applyValue: (editor, value) =>\n editor.update(\n () => {\n $convertFromMarkdownString(value, transformers)\n // Clear selection so the reconciler doesn't pull DOM focus into the\n // editor on an external push (e.g. typing in a bound source textarea).\n $setSelection(null)\n },\n { tag: PROGRAMMATIC_TAG },\n ),\n })\n\n if (config.collab && config.value) {\n throw new Error(\n 'markdownEditor: `collab` and `value` are mutually exclusive — in a collaborative ' +\n 'session the shared CRDT document owns the content, not a markdown signal. ' +\n 'Use `defaultValue` as the bootstrap seed instead.',\n )\n }\n\n const collabEnabled = !!config.collab\n const seedValue = config.value ? config.value.peek() : (config.defaultValue ?? '')\n\n // ── Composed TEA: core + plugin UI slices ──────────────────────────────────\n const composedInit = (): [EditorState, EditorEffect[]] => {\n const [core, effects] = init({\n value: seedValue,\n readonly: config.readonly ?? false,\n collab: collabEnabled,\n })\n const slices: Record<string, unknown> = {}\n for (const { name, ui } of pluginUIs) slices[name] = ui.init()\n return [{ ...core, plugins: slices }, effects]\n }\n\n const composedUpdate = (state: EditorState, msg: EditorMsg): [EditorState, EditorEffect[]] => {\n if (msg.type === 'plugin') {\n const ui = pluginUIByName.get(msg.name)\n if (!ui?.update) return [state, []]\n const result = ui.update(state.plugins[msg.name], msg.msg)\n const [slice, effects] = (Array.isArray(result) ? result : [result, []]) as [\n unknown,\n unknown[],\n ]\n return [\n { ...state, plugins: { ...state.plugins, [msg.name]: slice } },\n effects.map((effect) => ({ type: 'pluginEffect' as const, name: msg.name, effect })),\n ]\n }\n return update(state, msg)\n }\n\n const composedOnEffect = (\n effect: EditorEffect,\n api: { send: (msg: EditorMsg) => void; state: Signal<EditorState> },\n ): void => {\n if (effect.type === 'pluginEffect') {\n const ui = pluginUIByName.get(effect.name)\n ui?.onEffect?.(effect.effect, {\n editor: getEditor,\n send: (msg) => api.send({ type: 'plugin', name: effect.name, msg }),\n emit: (msg) => api.send(msg as EditorMsg),\n })\n return\n }\n baseOnEffect(effect, api)\n }\n\n const view = ({\n state,\n send,\n }: {\n state: Signal<EditorState>\n send: (msg: EditorMsg) => void\n }): Renderable => {\n // Build the collab binding (once, at mount) from the consumer's factory,\n // injecting the markdown seed + status sinks that mirror into `state.collab`.\n const collabBinding: CollabBinding | null = config.collab\n ? config.collab({\n seed: () => {\n $convertFromMarkdownString(seedValue, transformers)\n $setSelection(null)\n },\n onStatus: (connected) => send({ type: 'collabStatus', connected }),\n onSync: (synced) => send({ type: 'collabSync', synced }),\n onPeers: (peers) => send({ type: 'collabPeers', peers }),\n })\n : null\n\n const host = lexicalForeign<EditorOutMsg>({\n namespace: config.namespace ?? 'llui-markdown',\n theme: config.theme,\n plugins,\n serialize: (editor) =>\n editor.getEditorState().read(() => $convertToMarkdownString(transformers)),\n deserialize: (_editor, value) => {\n $convertFromMarkdownString(value, transformers)\n $setSelection(null)\n },\n // In collab mode the shared CRDT owns the document: the local undo stack\n // and the boot-time seed are disabled — the binding supplies a scoped undo\n // manager and a sync-gated bootstrap instead.\n ...(collabBinding ? { history: false, seedMode: 'deferred' as const } : {}),\n defaultValue: collabBinding || config.value ? undefined : (config.defaultValue ?? ''),\n ...(config.value && !collabBinding ? { value: config.value } : {}),\n readonly: state.at('readonly'),\n ...(config.changeDebounceMs !== undefined\n ? { changeDebounceMs: config.changeDebounceMs }\n : {}),\n register: (editor) => {\n const disposers = [registerMarkdownShortcuts(editor, transformers)]\n if (decorators.length > 0) disposers.push(registerDecoratorBridges(editor, decorators))\n if (collabBinding) disposers.push(collabBinding.register(editor))\n return () => {\n for (const dispose of disposers) dispose()\n }\n },\n onReady: (editor) => {\n editorRef = editor\n if (config.placeholder) {\n editor.getRootElement()?.setAttribute('data-placeholder', config.placeholder)\n }\n config.onReady?.(editor)\n },\n onChange: (value) => send({ type: 'markdownChanged', value }),\n onSelectionChange: (ctx) => {\n const format = computeFormatState(ctx.editor, ctx)\n const text = ctx.editor.getEditorState().read(() => $getRoot().getTextContent())\n // Toggle an empty marker so CSS can show the placeholder.\n ctx.editor.getRootElement()?.setAttribute('data-empty', text === '' ? 'true' : 'false')\n send({ type: 'formatChanged', format, wordCount: countWords(text), charCount: text.length })\n },\n emit: (msg) => send(msg),\n })\n\n // Plugin view contributions (overlays/panels) — each gets its own slice + send.\n const pluginViews: Renderable = pluginUIs.flatMap(({ name, ui }) => {\n if (!ui.view) return []\n const rendered = ui.view({\n state: state.at(`plugins.${name}`),\n send: (msg) => send({ type: 'plugin', name, msg }),\n editor: getEditor,\n })\n return Array.isArray(rendered) ? rendered : [rendered]\n })\n\n if (!config.toolbar) return [host, ...pluginViews]\n return [\n div({ 'data-scope': 'md-editor', 'data-part': 'root' }, [\n renderToolbar({ format: state.at('format'), send, items, collab: state.at('collab') }),\n div({ 'data-scope': 'md-editor', 'data-part': 'surface' }, [host]),\n ]),\n ...pluginViews,\n ]\n }\n\n return component<EditorState, EditorMsg, EditorEffect>({\n name: 'MarkdownEditor',\n init: composedInit,\n update: composedUpdate,\n view,\n onEffect: composedOnEffect,\n })\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
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';
|
|
1
|
+
export { type EditorConfig, type EditorParts, type CollabBinding, type CollabHooks, type CollabFactory, markdownEditor, } from './editor.js';
|
|
2
|
+
export { type BlockType, type FormatState, type OverlayKind, type CollabStatus, type EditorState, type EditorMsg, type EditorOutMsg, type EditorEffect, type InitOptions, EMPTY_FORMAT, COLLAB_OFF, init, update, countWords, } from './state.js';
|
|
3
3
|
export { type ItemSurface, type CommandItem, type CommandContext, type MarkdownPlugin, } from './plugins/types.js';
|
|
4
4
|
export { type PluginUI, type PluginUISpec, type PluginViewArgs, type PluginEffectContext, definePluginUI, } from './plugins/ui.js';
|
|
5
5
|
export { type CorePluginOptions, corePlugin } from './plugins/core.js';
|
|
6
|
+
export { type InlineFormat, type SingleBlockPluginOptions, singleBlockPlugin, } from './plugins/single-block.js';
|
|
6
7
|
export { type LinkPluginOptions, linkPlugin } from './plugins/link.js';
|
|
7
8
|
export { type CalloutKind, type CalloutData, type CalloutPluginOptions, calloutPlugin, $insertCallout, } from './plugins/callout.js';
|
|
8
9
|
export { hrPlugin, $insertHorizontalRule } from './plugins/hr.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,cAAc,GACf,MAAM,aAAa,CAAA;AAEpB,OAAO,EACL,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,YAAY,EACZ,UAAU,EACV,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,EACL,KAAK,YAAY,EACjB,KAAK,wBAAwB,EAC7B,iBAAiB,GAClB,MAAM,2BAA2B,CAAA;AAClC,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
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
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';
|
|
2
|
+
export { markdownEditor, } from './editor.js';
|
|
3
|
+
export { EMPTY_FORMAT, COLLAB_OFF, init, update, countWords, } from './state.js';
|
|
4
4
|
export {} from './plugins/types.js';
|
|
5
5
|
export { definePluginUI, } from './plugins/ui.js';
|
|
6
6
|
export { corePlugin } from './plugins/core.js';
|
|
7
|
+
export { singleBlockPlugin, } from './plugins/single-block.js';
|
|
7
8
|
export { linkPlugin } from './plugins/link.js';
|
|
8
9
|
export { calloutPlugin, $insertCallout, } from './plugins/callout.js';
|
|
9
10
|
export { hrPlugin, $insertHorizontalRule } from './plugins/hr.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAEhF,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAEhF,OAAO,EAML,cAAc,GACf,MAAM,aAAa,CAAA;AAEpB,OAAO,EAUL,YAAY,EACZ,UAAU,EACV,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,EAGL,iBAAiB,GAClB,MAAM,2BAA2B,CAAA;AAClC,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 {\n type EditorConfig,\n type EditorParts,\n type CollabBinding,\n type CollabHooks,\n type CollabFactory,\n markdownEditor,\n} from './editor.js'\n\nexport {\n type BlockType,\n type FormatState,\n type OverlayKind,\n type CollabStatus,\n type EditorState,\n type EditorMsg,\n type EditorOutMsg,\n type EditorEffect,\n type InitOptions,\n EMPTY_FORMAT,\n COLLAB_OFF,\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 {\n type InlineFormat,\n type SingleBlockPluginOptions,\n singleBlockPlugin,\n} from './plugins/single-block.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"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/plugins/core.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/plugins/core.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAA+B,cAAc,EAAE,MAAM,YAAY,CAAA;AAmB7E,MAAM,WAAW,iBAAiB;IAChC,wCAAwC;IACxC,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,CAAA;CACnB;AAED,wBAAgB,UAAU,CAAC,KAAK,GAAE,iBAAsB,GAAG,cAAc,CAkIxE"}
|
package/dist/plugins/core.js
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
// The core plugin: the GFM superset of nodes, transformers, command items, and
|
|
2
2
|
// shortcuts. This is the default plugin when none are supplied, so the minimal
|
|
3
3
|
// `markdownEditor()` one-liner still has full keyboard formatting.
|
|
4
|
-
import { $createParagraphNode, $getSelection, $isRangeSelection,
|
|
4
|
+
import { $createParagraphNode, $getSelection, $isRangeSelection, REDO_COMMAND, UNDO_COMMAND, } from 'lexical';
|
|
5
5
|
import { mergeRegister } from '@lexical/utils';
|
|
6
6
|
import { $setBlocksType } from '@lexical/selection';
|
|
7
7
|
import { $createHeadingNode, $createQuoteNode } from '@lexical/rich-text';
|
|
8
8
|
import { $createCodeNode } from '@lexical/code-core';
|
|
9
9
|
import { INSERT_CHECK_LIST_COMMAND, INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND, registerCheckList, registerList, } from '@lexical/list';
|
|
10
|
+
import { inlineItems } from './inline.js';
|
|
10
11
|
import { GFM_NODES, GFM_TRANSFORMERS } from '../transformers/gfm.js';
|
|
11
12
|
const NOOP_CTX = { send: () => { } };
|
|
12
|
-
function inline(format) {
|
|
13
|
-
return (editor) => editor.dispatchCommand(FORMAT_TEXT_COMMAND, format);
|
|
14
|
-
}
|
|
15
13
|
/** Wrap a node-factory into an editor action that converts the selected blocks. */
|
|
16
14
|
function block(create) {
|
|
17
15
|
return (editor) => editor.update(() => {
|
|
@@ -25,42 +23,7 @@ function heading(tag) {
|
|
|
25
23
|
}
|
|
26
24
|
export function corePlugin(_opts = {}) {
|
|
27
25
|
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
|
-
},
|
|
26
|
+
...inlineItems(),
|
|
64
27
|
{
|
|
65
28
|
id: 'paragraph',
|
|
66
29
|
label: 'Text',
|
package/dist/plugins/core.js.map
CHANGED
|
@@ -1 +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"]}
|
|
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 REDO_COMMAND,\n UNDO_COMMAND,\n type ElementNode,\n type LexicalEditor,\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 { inlineItems } from './inline.js'\nimport { GFM_NODES, GFM_TRANSFORMERS } from '../transformers/gfm.js'\n\nconst NOOP_CTX: CommandContext = { send: () => {} }\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 ...inlineItems(),\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,12 @@
|
|
|
1
|
+
import { type LexicalEditor, type TextFormatType } from 'lexical';
|
|
2
|
+
import type { CommandItem } from './types.js';
|
|
3
|
+
/** An inline text-format surfaced as a toolbar command item. */
|
|
4
|
+
export type InlineFormat = 'bold' | 'italic' | 'strikethrough' | 'code';
|
|
5
|
+
/** The full inline-format set, in toolbar order. */
|
|
6
|
+
export declare const INLINE_FORMATS: readonly InlineFormat[];
|
|
7
|
+
/** Dispatch a text-format toggle on the live editor. */
|
|
8
|
+
export declare function inlineFormatCommand(format: TextFormatType): (editor: LexicalEditor) => void;
|
|
9
|
+
/** Build the inline `CommandItem`s for `formats` (default: all four), grouped
|
|
10
|
+
* under `'inline'`. Surfaces are left unset (item appears in every surface). */
|
|
11
|
+
export declare function inlineItems(formats?: readonly InlineFormat[]): CommandItem[];
|
|
12
|
+
//# sourceMappingURL=inline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inline.d.ts","sourceRoot":"","sources":["../../src/plugins/inline.ts"],"names":[],"mappings":"AAMA,OAAO,EAAuB,KAAK,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,SAAS,CAAA;AAEtF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE7C,gEAAgE;AAChE,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,QAAQ,GAAG,eAAe,GAAG,MAAM,CAAA;AAEvE,oDAAoD;AACpD,eAAO,MAAM,cAAc,EAAE,SAAS,YAAY,EAAgD,CAAA;AAyClG,wDAAwD;AACxD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,cAAc,GAAG,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAE3F;AAED;gFACgF;AAChF,wBAAgB,WAAW,CAAC,OAAO,GAAE,SAAS,YAAY,EAAmB,GAAG,WAAW,EAAE,CAa5F"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// Shared inline text-formatting building blocks: the bold / italic /
|
|
2
|
+
// strikethrough / code command items and the `FORMAT_TEXT_COMMAND` dispatcher.
|
|
3
|
+
// Both `corePlugin` (the full GFM superset) and `singleBlockPlugin` (inline-only)
|
|
4
|
+
// derive their inline surface from here, so the canonical inline-format set and
|
|
5
|
+
// its labels/icons/keywords live in exactly one place.
|
|
6
|
+
import { FORMAT_TEXT_COMMAND } from 'lexical';
|
|
7
|
+
/** The full inline-format set, in toolbar order. */
|
|
8
|
+
export const INLINE_FORMATS = ['bold', 'italic', 'strikethrough', 'code'];
|
|
9
|
+
const DEFS = {
|
|
10
|
+
bold: {
|
|
11
|
+
label: 'Bold',
|
|
12
|
+
icon: 'bold',
|
|
13
|
+
keywords: ['strong'],
|
|
14
|
+
format: 'bold',
|
|
15
|
+
isActive: (f) => f.bold,
|
|
16
|
+
},
|
|
17
|
+
italic: {
|
|
18
|
+
label: 'Italic',
|
|
19
|
+
icon: 'italic',
|
|
20
|
+
keywords: ['emphasis'],
|
|
21
|
+
format: 'italic',
|
|
22
|
+
isActive: (f) => f.italic,
|
|
23
|
+
},
|
|
24
|
+
strikethrough: {
|
|
25
|
+
label: 'Strikethrough',
|
|
26
|
+
icon: 'strikethrough',
|
|
27
|
+
keywords: ['strike', 'del'],
|
|
28
|
+
format: 'strikethrough',
|
|
29
|
+
isActive: (f) => f.strikethrough,
|
|
30
|
+
},
|
|
31
|
+
code: {
|
|
32
|
+
label: 'Inline code',
|
|
33
|
+
icon: 'code',
|
|
34
|
+
keywords: ['mono'],
|
|
35
|
+
format: 'code',
|
|
36
|
+
isActive: (f) => f.code,
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
/** Dispatch a text-format toggle on the live editor. */
|
|
40
|
+
export function inlineFormatCommand(format) {
|
|
41
|
+
return (editor) => editor.dispatchCommand(FORMAT_TEXT_COMMAND, format);
|
|
42
|
+
}
|
|
43
|
+
/** Build the inline `CommandItem`s for `formats` (default: all four), grouped
|
|
44
|
+
* under `'inline'`. Surfaces are left unset (item appears in every surface). */
|
|
45
|
+
export function inlineItems(formats = INLINE_FORMATS) {
|
|
46
|
+
return formats.map((id) => {
|
|
47
|
+
const def = DEFS[id];
|
|
48
|
+
return {
|
|
49
|
+
id,
|
|
50
|
+
label: def.label,
|
|
51
|
+
icon: def.icon,
|
|
52
|
+
group: 'inline',
|
|
53
|
+
keywords: def.keywords,
|
|
54
|
+
run: inlineFormatCommand(def.format),
|
|
55
|
+
isActive: def.isActive,
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=inline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inline.js","sourceRoot":"","sources":["../../src/plugins/inline.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,+EAA+E;AAC/E,kFAAkF;AAClF,gFAAgF;AAChF,uDAAuD;AAEvD,OAAO,EAAE,mBAAmB,EAA2C,MAAM,SAAS,CAAA;AAOtF,oDAAoD;AACpD,MAAM,CAAC,MAAM,cAAc,GAA4B,CAAC,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,CAAC,CAAA;AAUlG,MAAM,IAAI,GAA0C;IAClD,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM;QACb,IAAI,EAAE,MAAM;QACZ,QAAQ,EAAE,CAAC,QAAQ,CAAC;QACpB,MAAM,EAAE,MAAM;QACd,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI;KACxB;IACD,MAAM,EAAE;QACN,KAAK,EAAE,QAAQ;QACf,IAAI,EAAE,QAAQ;QACd,QAAQ,EAAE,CAAC,UAAU,CAAC;QACtB,MAAM,EAAE,QAAQ;QAChB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM;KAC1B;IACD,aAAa,EAAE;QACb,KAAK,EAAE,eAAe;QACtB,IAAI,EAAE,eAAe;QACrB,QAAQ,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC;QAC3B,MAAM,EAAE,eAAe;QACvB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa;KACjC;IACD,IAAI,EAAE;QACJ,KAAK,EAAE,aAAa;QACpB,IAAI,EAAE,MAAM;QACZ,QAAQ,EAAE,CAAC,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM;QACd,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI;KACxB;CACF,CAAA;AAED,wDAAwD;AACxD,MAAM,UAAU,mBAAmB,CAAC,MAAsB;IACxD,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,eAAe,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAA;AACxE,CAAC;AAED;gFACgF;AAChF,MAAM,UAAU,WAAW,CAAC,UAAmC,cAAc;IAC3E,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE;QACxB,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,CAAA;QACpB,OAAO;YACL,EAAE;YACF,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,KAAK,EAAE,QAAQ;YACf,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,GAAG,EAAE,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC;YACpC,QAAQ,EAAE,GAAG,CAAC,QAAQ;SACvB,CAAA;IACH,CAAC,CAAC,CAAA;AACJ,CAAC","sourcesContent":["// Shared inline text-formatting building blocks: the bold / italic /\n// strikethrough / code command items and the `FORMAT_TEXT_COMMAND` dispatcher.\n// Both `corePlugin` (the full GFM superset) and `singleBlockPlugin` (inline-only)\n// derive their inline surface from here, so the canonical inline-format set and\n// its labels/icons/keywords live in exactly one place.\n\nimport { FORMAT_TEXT_COMMAND, type LexicalEditor, type TextFormatType } from 'lexical'\nimport type { FormatState } from '../state.js'\nimport type { CommandItem } from './types.js'\n\n/** An inline text-format surfaced as a toolbar command item. */\nexport type InlineFormat = 'bold' | 'italic' | 'strikethrough' | 'code'\n\n/** The full inline-format set, in toolbar order. */\nexport const INLINE_FORMATS: readonly InlineFormat[] = ['bold', 'italic', 'strikethrough', 'code']\n\ninterface InlineFormatDef {\n label: string\n icon: string\n keywords: readonly string[]\n format: TextFormatType\n isActive: (f: FormatState) => boolean\n}\n\nconst DEFS: Record<InlineFormat, InlineFormatDef> = {\n bold: {\n label: 'Bold',\n icon: 'bold',\n keywords: ['strong'],\n format: 'bold',\n isActive: (f) => f.bold,\n },\n italic: {\n label: 'Italic',\n icon: 'italic',\n keywords: ['emphasis'],\n format: 'italic',\n isActive: (f) => f.italic,\n },\n strikethrough: {\n label: 'Strikethrough',\n icon: 'strikethrough',\n keywords: ['strike', 'del'],\n format: 'strikethrough',\n isActive: (f) => f.strikethrough,\n },\n code: {\n label: 'Inline code',\n icon: 'code',\n keywords: ['mono'],\n format: 'code',\n isActive: (f) => f.code,\n },\n}\n\n/** Dispatch a text-format toggle on the live editor. */\nexport function inlineFormatCommand(format: TextFormatType): (editor: LexicalEditor) => void {\n return (editor) => editor.dispatchCommand(FORMAT_TEXT_COMMAND, format)\n}\n\n/** Build the inline `CommandItem`s for `formats` (default: all four), grouped\n * under `'inline'`. Surfaces are left unset (item appears in every surface). */\nexport function inlineItems(formats: readonly InlineFormat[] = INLINE_FORMATS): CommandItem[] {\n return formats.map((id) => {\n const def = DEFS[id]\n return {\n id,\n label: def.label,\n icon: def.icon,\n group: 'inline',\n keywords: def.keywords,\n run: inlineFormatCommand(def.format),\n isActive: def.isActive,\n }\n })\n}\n"]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { MarkdownPlugin } from './types.js';
|
|
2
|
+
import { type InlineFormat } from './inline.js';
|
|
3
|
+
export type { InlineFormat };
|
|
4
|
+
declare global {
|
|
5
|
+
interface ImportMeta {
|
|
6
|
+
env?: {
|
|
7
|
+
DEV?: boolean;
|
|
8
|
+
MODE?: string;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export interface SingleBlockPluginOptions {
|
|
13
|
+
/** Inline formats surfaced as toolbar items.
|
|
14
|
+
* Default `['bold', 'italic', 'strikethrough', 'code']`. NOTE: this limits the
|
|
15
|
+
* toolbar buttons only — markdown syntax (`*x*`) and Ctrl/⌘ shortcuts still
|
|
16
|
+
* apply every inline format, and all inline markdown round-trips regardless. */
|
|
17
|
+
formats?: readonly InlineFormat[];
|
|
18
|
+
/** Allow soft line breaks within the single paragraph. When `false` (default)
|
|
19
|
+
* Enter is inert and pasted/seeded line breaks collapse to spaces — a strict
|
|
20
|
+
* single-line field. When `true`, Enter inserts a `\n` and merged lines are
|
|
21
|
+
* joined with a line break instead of a space. A new paragraph is never made. */
|
|
22
|
+
allowLineBreaks?: boolean;
|
|
23
|
+
/** Register `LinkNode` + the markdown link transformer so inline links
|
|
24
|
+
* round-trip. Default `false`. Compose with `linkPlugin()` for the toolbar
|
|
25
|
+
* button + insert dialog. */
|
|
26
|
+
link?: boolean;
|
|
27
|
+
}
|
|
28
|
+
export declare function singleBlockPlugin(opts?: SingleBlockPluginOptions): MarkdownPlugin;
|
|
29
|
+
//# sourceMappingURL=single-block.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"single-block.d.ts","sourceRoot":"","sources":["../../src/plugins/single-block.ts"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAAe,cAAc,EAAE,MAAM,YAAY,CAAA;AAC7D,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,aAAa,CAAA;AAG5D,YAAY,EAAE,YAAY,EAAE,CAAA;AAK5B,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,UAAU;QAClB,GAAG,CAAC,EAAE;YAAE,GAAG,CAAC,EAAE,OAAO,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KACvC;CACF;AAED,MAAM,WAAW,wBAAwB;IACvC;;;oFAGgF;IAChF,OAAO,CAAC,EAAE,SAAS,YAAY,EAAE,CAAA;IACjC;;;qFAGiF;IACjF,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB;;iCAE6B;IAC7B,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAuED,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,wBAA6B,GAAG,cAAc,CAqDrF"}
|