@rcarls/rc-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.
@@ -0,0 +1,5 @@
1
+ import "@rcarls/rc-textarea/define";
2
+ import { R as o, a as t } from "./rc-editor-toolbar-B74gMsna.js";
3
+ customElements.get("rc-editor-toolbar") ?? customElements.define("rc-editor-toolbar", o);
4
+ customElements.get("rc-markdown-editor") ?? customElements.define("rc-markdown-editor", t);
5
+ //# sourceMappingURL=rc-markdown-editor-define.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rc-markdown-editor-define.js","sources":["../src/define.ts"],"sourcesContent":["import '@rcarls/rc-textarea/define';\n\nimport { RcEditorToolbar } from './rc-editor-toolbar.ts';\nimport { RcMarkdownEditor } from './rc-markdown-editor.ts';\n\ncustomElements.get('rc-editor-toolbar') ?? customElements.define('rc-editor-toolbar', RcEditorToolbar);\ncustomElements.get('rc-markdown-editor') ?? customElements.define('rc-markdown-editor', RcMarkdownEditor);\n"],"names":["RcEditorToolbar","RcMarkdownEditor"],"mappings":";;AAKA,eAAe,IAAI,mBAAmB,KAAO,eAAe,OAAO,qBAAuBA,CAAe;AACzG,eAAe,IAAI,oBAAoB,KAAM,eAAe,OAAO,sBAAuBC,CAAgB;"}
@@ -0,0 +1,6 @@
1
+ import { R as a, a as d } from "./rc-editor-toolbar-B74gMsna.js";
2
+ export {
3
+ a as RcEditorToolbar,
4
+ d as RcMarkdownEditor
5
+ };
6
+ //# sourceMappingURL=rc-markdown-editor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rc-markdown-editor.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
@@ -0,0 +1,8 @@
1
+ import { Decoration } from '@rcarls/rc-textarea';
2
+ import { ActiveFormats } from './types.ts';
3
+ /**
4
+ * Derives active inline and block formats from the decoration array at a given
5
+ * selection range in the markdown source editor. Used for toolbar state sync in
6
+ * source mode.
7
+ */
8
+ export declare function getFormatsFromDecorations(decorations: readonly Decoration[], start: number, end: number): Omit<ActiveFormats, 'codeLanguage'>;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Bootstrap Icons v1.x (MIT) used for `<rc-editor-toolbar>`.
3
+ * Icons source: https://icons.getbootstrap.com/
4
+ * License: MIT — https://github.com/twbs/icons/blob/main/LICENSE
5
+ *
6
+ * All icons use `currentColor` so they inherit button text colour,
7
+ * including forced-colours mode. ViewBox is 0 0 16 16; rendered at
8
+ * 1em so they scale with the button's font-size.
9
+ */
10
+ export declare const icons: {
11
+ bold: import('lit').TemplateResult<2>;
12
+ italic: import('lit').TemplateResult<2>;
13
+ underline: import('lit').TemplateResult<2>;
14
+ strikethrough: import('lit').TemplateResult<2>;
15
+ code: import('lit').TemplateResult<2>;
16
+ link: import('lit').TemplateResult<2>;
17
+ blockquote: import('lit').TemplateResult<2>;
18
+ bulletList: import('lit').TemplateResult<2>;
19
+ orderedList: import('lit').TemplateResult<2>;
20
+ codeBlock: import('lit').TemplateResult<2>;
21
+ source: import('lit').TemplateResult<2>;
22
+ };
@@ -0,0 +1,3 @@
1
+ export { RcMarkdownEditor } from './rc-markdown-editor.ts';
2
+ export { RcEditorToolbar } from './rc-editor-toolbar.ts';
3
+ export type { EditorToolbarAction, EditorToolbarActionDetail, ActiveFormats, EditorMode, HeadingLevel, } from './types.ts';
@@ -0,0 +1,44 @@
1
+ import { LitElement } from 'lit';
2
+ import { HeadingLevel } from './types.ts';
3
+ /**
4
+ * Formatting toolbar for `<rc-markdown-editor>`. Renders into its own light DOM
5
+ * so the parent shadow stylesheet can reach `rc-editor-toolbar button` directly.
6
+ *
7
+ * Active-format properties are set by the parent editor and reflected as
8
+ * `aria-pressed` on the corresponding buttons. Heading level is shown via a
9
+ * `<select>`. Code-block language is shown via a `<input>` when active.
10
+ *
11
+ * @fires rc-toolbar-action - When a formatting button or select is activated.
12
+ */
13
+ export declare class RcEditorToolbar extends LitElement {
14
+ /** `aria-label` applied to the `[role="toolbar"]` container. */
15
+ label: string;
16
+ activeBold: boolean;
17
+ activeItalic: boolean;
18
+ activeUnderline: boolean;
19
+ activeStrikethrough: boolean;
20
+ activeCode: boolean;
21
+ activeHeading: HeadingLevel | null;
22
+ activeBlockquote: boolean;
23
+ activeBulletList: boolean;
24
+ activeOrderedList: boolean;
25
+ activeCodeBlock: boolean;
26
+ /**
27
+ * Language of the code block at the cursor. `null` means not in a code block
28
+ * (hides the language input). `''` means no language is set.
29
+ */
30
+ codeLanguage: string | null;
31
+ /** Whether the editor is in source mode. */
32
+ sourceMode: boolean;
33
+ /** Tracks the in-progress language input value before commit. */
34
+ private _langInputValue;
35
+ createRenderRoot(): this;
36
+ updated(changed: Map<string, unknown>): void;
37
+ private _dispatch;
38
+ private _onClick;
39
+ private _onHeadingChange;
40
+ private _onLangInput;
41
+ private _onLangCommit;
42
+ private _onLangKeyDown;
43
+ render(): import('lit').TemplateResult<1>;
44
+ }
@@ -0,0 +1,98 @@
1
+ import { LitElement } from 'lit';
2
+ /**
3
+ * Markdown-backed rich-text editor with two first-class modes:
4
+ *
5
+ * - **Rich mode (default)**: A `contenteditable` div shows micromark-rendered
6
+ * HTML. DOM mutations are converted back to markdown via turndown and
7
+ * written to the backing `<textarea>` for form participation.
8
+ * - **Source mode**: An `<rc-textarea>` instance shows the markdown source
9
+ * with live decorations. Toggle via `source-mode` attribute or Ctrl+Shift+S.
10
+ *
11
+ * Consumer markup follows the same progressive-enhancement contract as
12
+ * `<rc-textarea>`:
13
+ *
14
+ * ```html
15
+ * <rc-markdown-editor>
16
+ * <label for="body">Content</label>
17
+ * <textarea id="body" name="body"></textarea>
18
+ * </rc-markdown-editor>
19
+ * ```
20
+ *
21
+ * @fires rc-change - Value changed. Detail: `{ value: string }`.
22
+ * @fires rc-mode-change - Mode toggled. Detail: `{ mode: EditorMode }`.
23
+ * @fires rc-formatting-change - Active formats at cursor changed. Detail: `ActiveFormats`.
24
+ *
25
+ * @attr {boolean} toolbar - Show the formatting toolbar (default: true).
26
+ * @attr {boolean} source-mode - Controlled: show the markdown source editor.
27
+ * @attr {boolean} default-source-mode - Uncontrolled initial source-mode state.
28
+ * @attr {boolean} read-only - Make the editor read-only.
29
+ */
30
+ export declare class RcMarkdownEditor extends LitElement {
31
+ static styles: import('lit').CSSResult;
32
+ private _value;
33
+ private _defaultValue;
34
+ private _valueInitialized;
35
+ get defaultValue(): string;
36
+ set defaultValue(v: string);
37
+ get value(): string;
38
+ set value(v: string);
39
+ private _sourceMode;
40
+ private _defaultSourceMode;
41
+ private _sourceModeInitialized;
42
+ get defaultSourceMode(): boolean;
43
+ set defaultSourceMode(v: boolean);
44
+ get sourceMode(): boolean;
45
+ set sourceMode(v: boolean);
46
+ /** Show the formatting toolbar. */
47
+ toolbar: boolean;
48
+ /** Make the editor read-only. */
49
+ readOnly: boolean;
50
+ private _richView;
51
+ private _sourceEditor;
52
+ private _toolbarEl?;
53
+ private _observer;
54
+ private _savedRichRange;
55
+ private _activeFormats;
56
+ private _syncTimer;
57
+ private _pluginApi;
58
+ private _ignoreRichMutations;
59
+ private _richViewRendered;
60
+ private _skipNextModeSwitch;
61
+ connectedCallback(): void;
62
+ disconnectedCallback(): void;
63
+ firstUpdated(): void;
64
+ updated(changed: Map<string, unknown>): void;
65
+ render(): import('lit').TemplateResult<1>;
66
+ private _setRichViewContent;
67
+ private _renderMarkdown;
68
+ private _scheduleMarkdownSync;
69
+ private _syncMarkdownFromRichView;
70
+ private _switchToSource;
71
+ private _switchToRich;
72
+ private _cachedTree;
73
+ private _setupSourcePlugin;
74
+ private _getCodeBlockLanguage;
75
+ private _onSourceChange;
76
+ private _onToolbarAction;
77
+ private _applyRichFormat;
78
+ private _applySourceFormat;
79
+ /** Sets the heading level on the cursor's line in source mode. null = paragraph. */
80
+ private _setSourceHeadingLevel;
81
+ /** Updates the language of the code block at the cursor in source mode. */
82
+ private _setSourceCodeBlockLanguage;
83
+ /** Updates the data-lang attribute on the <pre> at the cursor in rich mode. */
84
+ private _setRichCodeBlockLanguage;
85
+ /** Toggles a line prefix (e.g. `'# '`, `'> '`, `'- '`) on the cursor's line. */
86
+ private _toggleLinePrefix;
87
+ /** Wraps the current selection (or cursor line) with a fenced code block. */
88
+ private _toggleSourceCodeFence;
89
+ private _wrapRichSelection;
90
+ private _toggleRichCodeBlock;
91
+ private _onKeyDown;
92
+ private _onSelectionChange;
93
+ private _pushToolbarState;
94
+ private _syncNativeTextarea;
95
+ private _connectLabel;
96
+ private _dispatchChange;
97
+ private _dispatchModeChange;
98
+ }
@@ -0,0 +1 @@
1
+ export declare const rmeStyles: import('lit').CSSResult;
@@ -0,0 +1,42 @@
1
+ /** Actions dispatched by `<rc-editor-toolbar>` via the `rc-toolbar-action` event. */
2
+ export type EditorToolbarAction = 'bold' | 'italic' | 'underline' | 'strikethrough' | 'code' | 'link' | 'heading' | 'blockquote' | 'bullet-list' | 'ordered-list' | 'code-block' | 'code-block-language' | 'source';
3
+ /** Detail payload carried by `rc-toolbar-action` custom events. */
4
+ export interface EditorToolbarActionDetail {
5
+ action: EditorToolbarAction;
6
+ /** Heading level for `action === 'heading'`; null means paragraph. */
7
+ headingLevel?: HeadingLevel | null;
8
+ /** Language string for `action === 'code-block-language'`. */
9
+ codeLanguage?: string;
10
+ }
11
+ /** Heading level active at the current cursor position. */
12
+ export type HeadingLevel = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
13
+ /** Inline and block formatting state at the current cursor position or selection. */
14
+ export interface ActiveFormats {
15
+ bold?: boolean;
16
+ italic?: boolean;
17
+ underline?: boolean;
18
+ strikethrough?: boolean;
19
+ code?: boolean;
20
+ link?: boolean;
21
+ heading?: HeadingLevel | null;
22
+ blockquote?: boolean;
23
+ bulletList?: boolean;
24
+ orderedList?: boolean;
25
+ codeBlock?: boolean;
26
+ /** Language of the code block at the cursor, or null if none / not in a code block. */
27
+ codeLanguage?: string | null;
28
+ }
29
+ /** Editor display mode. */
30
+ export type EditorMode = 'rich' | 'source';
31
+ declare global {
32
+ interface HTMLElementEventMap {
33
+ 'rc-toolbar-action': CustomEvent<EditorToolbarActionDetail>;
34
+ 'rc-change': CustomEvent<{
35
+ value: string;
36
+ }>;
37
+ 'rc-mode-change': CustomEvent<{
38
+ mode: EditorMode;
39
+ }>;
40
+ 'rc-formatting-change': CustomEvent<ActiveFormats>;
41
+ }
42
+ }
package/package.json ADDED
@@ -0,0 +1,75 @@
1
+ {
2
+ "name": "@rcarls/rc-markdown-editor",
3
+ "publishConfig": {
4
+ "access": "public"
5
+ },
6
+ "version": "0.1.0",
7
+ "description": "Headless markdown editor web component extending rc-textarea, built with Lit",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/richardcarls/rc-webcomponents.git",
11
+ "directory": "packages/rc-markdown-editor"
12
+ },
13
+ "homepage": "https://github.com/richardcarls/rc-webcomponents#readme",
14
+ "license": "MIT",
15
+ "type": "module",
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "module": "./dist/rc-markdown-editor.js",
20
+ "exports": {
21
+ ".": {
22
+ "import": {
23
+ "types": "./dist/types/packages/rc-markdown-editor/src/index.d.ts",
24
+ "default": "./dist/rc-markdown-editor.js"
25
+ }
26
+ },
27
+ "./define": {
28
+ "import": {
29
+ "types": "./dist/types/packages/rc-markdown-editor/src/define.d.ts",
30
+ "default": "./dist/rc-markdown-editor-define.js"
31
+ }
32
+ }
33
+ },
34
+ "types": "./dist/types/packages/rc-markdown-editor/src/index.d.ts",
35
+ "sideEffects": [
36
+ "./dist/rc-markdown-editor-define.js"
37
+ ],
38
+ "customElements": "dist/custom-elements.json",
39
+ "scripts": {
40
+ "dev": "vite",
41
+ "build": "tsc && vite build && cem analyze",
42
+ "cem:analyze": "cem analyze",
43
+ "preview": "vite preview",
44
+ "test:browser": "vitest",
45
+ "test:browser:chrome": "vitest --project=chromium",
46
+ "test:browser:firefox": "vitest --project=firefox",
47
+ "yalc:publish": "yalc publish --push"
48
+ },
49
+ "dependencies": {
50
+ "@rcarls/rc-textarea": "workspace:^"
51
+ },
52
+ "devDependencies": {
53
+ "@custom-elements-manifest/analyzer": "0.11.0",
54
+ "@guanghechen/rollup-plugin-copy": "^6.0.9",
55
+ "@types/turndown": "^5.0.5",
56
+ "@vitest/browser-playwright": "4.1.5",
57
+ "lit": "^3.0.0",
58
+ "mdast-util-from-markdown": "^2.0.2",
59
+ "mdast-util-gfm-strikethrough": "^2.0.0",
60
+ "micromark": "^4.0.2",
61
+ "micromark-extension-gfm-strikethrough": "^2.0.0",
62
+ "playwright": "^1.56.0",
63
+ "rollup": "^4.60.2",
64
+ "turndown": "^7.2.0",
65
+ "typescript": "~5.9.3",
66
+ "unist-util-visit": "^5.0.0",
67
+ "vite": "^7.1.7",
68
+ "vite-plugin-dts": "^4.5.4",
69
+ "vitest": "^4.0.6",
70
+ "vitest-browser-lit": "^1.0.1"
71
+ },
72
+ "peerDependencies": {
73
+ "lit": "^3.0.0"
74
+ }
75
+ }