draftly 2.0.0 → 2.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.
@@ -1,7 +1,8 @@
1
1
  import { d as DraftlyPlugin, T as ThemeEnum, f as ThemeStyle, a as DecorationPlugin, D as DecorationContext, e as PluginContext } from '../draftly-BBL-AdOl.cjs';
2
2
  import { SyntaxNode } from '@lezer/common';
3
3
  import { Extension } from '@codemirror/state';
4
- import { KeyBinding } from '@codemirror/view';
4
+ import * as _codemirror_view from '@codemirror/view';
5
+ import { KeyBinding, EditorView } from '@codemirror/view';
5
6
  import { MarkdownConfig } from '@lezer/markdown';
6
7
  import * as _lezer_highlight from '@lezer/highlight';
7
8
  import { Highlighter } from '@lezer/highlight';
@@ -191,63 +192,97 @@ declare class ListPlugin extends DecorationPlugin {
191
192
  }): string | null;
192
193
  }
193
194
 
194
- type PreviewContextLike = {
195
+ interface PreviewContextLike {
195
196
  sliceDoc(from: number, to: number): string;
196
197
  sanitize(html: string): string;
197
- };
198
- /**
199
- * TablePlugin — Renders GFM markdown tables as styled widgets.
200
- *
201
- * Features:
202
- * - Rendered table widget with rounded borders, alternate row colors, cell borders
203
- * - Alignment support (`:---:`, `----:`, `:---`)
204
- * - Monospace raw markdown when cursor is inside the table
205
- * - Keyboard shortcuts for table creation, adding rows/columns
206
- * - Enter in last row/last cell: creates row, again removes it
207
- * - Auto-formats table markdown to align pipes
208
- */
198
+ }
209
199
  declare class TablePlugin extends DecorationPlugin {
210
200
  readonly name = "table";
211
- readonly version = "1.0.0";
201
+ readonly version = "2.0.0";
212
202
  decorationPriority: number;
213
203
  readonly requiredNodes: readonly ["Table", "TableHeader", "TableDelimiter", "TableRow", "TableCell"];
214
- /** Configuration stored from onRegister */
215
204
  private draftlyConfig;
205
+ private pendingNormalizationView;
206
+ private pendingPaddingView;
207
+ private pendingSelectionRepairView;
208
+ /** Stores the editor config for preview rendering and shared behavior. */
216
209
  onRegister(context: PluginContext): void;
210
+ /** Exposes the plugin theme used for editor and preview styling. */
217
211
  get theme(): (theme: ThemeEnum) => ThemeStyle;
212
+ /** Enables GFM table parsing for the editor and preview renderer. */
213
+ getMarkdownConfig(): MarkdownConfig;
214
+ /** Registers block wrappers and atomic ranges for the table UI. */
215
+ getExtensions(): Extension[];
216
+ /** Provides the table-specific keyboard shortcuts and navigation. */
218
217
  getKeymap(): KeyBinding[];
218
+ /** Builds the high-priority key bindings used inside tables. */
219
+ private buildTableKeymap;
220
+ /** Schedules an initial normalization pass once the view is ready. */
221
+ onViewReady(view: EditorView): void;
222
+ /** Re-schedules normalization after user-driven document changes. */
223
+ onViewUpdate(update: _codemirror_view.ViewUpdate): void;
224
+ /** Intercepts table-specific DOM key handling before browser defaults run. */
225
+ private handleDomKeydown;
226
+ /** Builds the visual table decorations for every parsed table block. */
219
227
  buildDecorations(ctx: DecorationContext): void;
220
- /**
221
- * Insert a new 3×3 table at cursor position
222
- */
228
+ /** Renders the full table node to semantic preview HTML. */
229
+ renderToHTML(node: SyntaxNode, _children: string, ctx: PreviewContextLike): Promise<string | null>;
230
+ /** Computes the block wrapper ranges used to group table lines. */
231
+ private computeBlockWrappers;
232
+ /** Computes atomic ranges for delimiters and inline break tags. */
233
+ private computeAtomicRanges;
234
+ /** Applies row, cell, and control decorations for a single table. */
235
+ private decorateTable;
236
+ /** Applies the visual cell decorations for a single table row line. */
237
+ private decorateLine;
238
+ /** Normalizes every parsed table block back into canonical markdown. */
239
+ private normalizeTables;
240
+ /** Defers table normalization until the current update cycle is finished. */
241
+ private scheduleNormalization;
242
+ /** Adds missing spacer lines above and below tables after edits. */
243
+ private ensureTablePadding;
244
+ /** Schedules a padding-only pass after the current update cycle finishes. */
245
+ private schedulePadding;
246
+ /** Repairs carets that land in hidden table markup instead of editable cell content. */
247
+ private ensureTableSelection;
248
+ /** Schedules table selection repair after the current update finishes. */
249
+ private scheduleSelectionRepair;
250
+ /** Rewrites a table block and restores the caret to a target cell position. */
251
+ private replaceTable;
252
+ /** Inserts an empty body row below the given logical row index. */
253
+ private insertRowBelow;
254
+ /** Inserts a starter table near the current cursor line. */
223
255
  private insertTable;
224
- /**
225
- * Add a new row below the current row (Mod-Enter)
226
- */
256
+ /** Adds a new empty body row to the active table. */
227
257
  private addRow;
228
- /**
229
- * Add a new column after the current column (Mod-Shift-Enter)
230
- */
258
+ /** Appends a row and keeps the caret in the requested column. */
259
+ private appendRow;
260
+ /** Inserts a new column after the current column. */
231
261
  private addColumn;
232
- /**
233
- * Handle Enter key inside a table.
234
- * - Last cell of last row: create a new row
235
- * - Empty last row: remove it and move cursor after table
236
- */
237
- private handleEnter;
238
- /**
239
- * Handle Tab key inside a table — move to next/previous cell
240
- */
262
+ /** Appends a new column at the far right of the table. */
263
+ private appendColumn;
264
+ /** Removes the current body row or clears the last remaining row. */
265
+ private removeRow;
266
+ /** Removes the current column when the table has more than one column. */
267
+ private removeColumn;
268
+ /** Moves to the next or previous logical cell with Tab navigation. */
241
269
  private handleTab;
242
- /**
243
- * Find the Table node at the cursor position
244
- */
270
+ /** Moves horizontally between adjacent cells when the caret hits an edge. */
271
+ private handleArrowHorizontal;
272
+ /** Moves vertically between rows while keeping the current column. */
273
+ private handleArrowVertical;
274
+ /** Advances downward on Enter and manages the trailing empty row behavior. */
275
+ private handleEnter;
276
+ /** Inserts a canonical `<br />` token inside the current table cell. */
277
+ private insertBreakTag;
278
+ /** Deletes a whole `<br />` token when backspace or delete hits it. */
279
+ private handleBreakDeletion;
280
+ /** Moves the current selection anchor into a target cell. */
281
+ private moveSelectionToCell;
282
+ /** Returns the table currently containing the editor cursor. */
245
283
  private getTableAtCursor;
246
- /**
247
- * Split a table line into cells (keeping the whitespace around content)
248
- */
249
- private splitLineToCells;
250
- renderToHTML(node: SyntaxNode, _children: string, _ctx: PreviewContextLike): Promise<string | null>;
284
+ /** Returns the active cell under the current selection head. */
285
+ private getCurrentCell;
251
286
  }
252
287
 
253
288
  /**
@@ -1,7 +1,8 @@
1
1
  import { d as DraftlyPlugin, T as ThemeEnum, f as ThemeStyle, a as DecorationPlugin, D as DecorationContext, e as PluginContext } from '../draftly-BBL-AdOl.js';
2
2
  import { SyntaxNode } from '@lezer/common';
3
3
  import { Extension } from '@codemirror/state';
4
- import { KeyBinding } from '@codemirror/view';
4
+ import * as _codemirror_view from '@codemirror/view';
5
+ import { KeyBinding, EditorView } from '@codemirror/view';
5
6
  import { MarkdownConfig } from '@lezer/markdown';
6
7
  import * as _lezer_highlight from '@lezer/highlight';
7
8
  import { Highlighter } from '@lezer/highlight';
@@ -191,63 +192,97 @@ declare class ListPlugin extends DecorationPlugin {
191
192
  }): string | null;
192
193
  }
193
194
 
194
- type PreviewContextLike = {
195
+ interface PreviewContextLike {
195
196
  sliceDoc(from: number, to: number): string;
196
197
  sanitize(html: string): string;
197
- };
198
- /**
199
- * TablePlugin — Renders GFM markdown tables as styled widgets.
200
- *
201
- * Features:
202
- * - Rendered table widget with rounded borders, alternate row colors, cell borders
203
- * - Alignment support (`:---:`, `----:`, `:---`)
204
- * - Monospace raw markdown when cursor is inside the table
205
- * - Keyboard shortcuts for table creation, adding rows/columns
206
- * - Enter in last row/last cell: creates row, again removes it
207
- * - Auto-formats table markdown to align pipes
208
- */
198
+ }
209
199
  declare class TablePlugin extends DecorationPlugin {
210
200
  readonly name = "table";
211
- readonly version = "1.0.0";
201
+ readonly version = "2.0.0";
212
202
  decorationPriority: number;
213
203
  readonly requiredNodes: readonly ["Table", "TableHeader", "TableDelimiter", "TableRow", "TableCell"];
214
- /** Configuration stored from onRegister */
215
204
  private draftlyConfig;
205
+ private pendingNormalizationView;
206
+ private pendingPaddingView;
207
+ private pendingSelectionRepairView;
208
+ /** Stores the editor config for preview rendering and shared behavior. */
216
209
  onRegister(context: PluginContext): void;
210
+ /** Exposes the plugin theme used for editor and preview styling. */
217
211
  get theme(): (theme: ThemeEnum) => ThemeStyle;
212
+ /** Enables GFM table parsing for the editor and preview renderer. */
213
+ getMarkdownConfig(): MarkdownConfig;
214
+ /** Registers block wrappers and atomic ranges for the table UI. */
215
+ getExtensions(): Extension[];
216
+ /** Provides the table-specific keyboard shortcuts and navigation. */
218
217
  getKeymap(): KeyBinding[];
218
+ /** Builds the high-priority key bindings used inside tables. */
219
+ private buildTableKeymap;
220
+ /** Schedules an initial normalization pass once the view is ready. */
221
+ onViewReady(view: EditorView): void;
222
+ /** Re-schedules normalization after user-driven document changes. */
223
+ onViewUpdate(update: _codemirror_view.ViewUpdate): void;
224
+ /** Intercepts table-specific DOM key handling before browser defaults run. */
225
+ private handleDomKeydown;
226
+ /** Builds the visual table decorations for every parsed table block. */
219
227
  buildDecorations(ctx: DecorationContext): void;
220
- /**
221
- * Insert a new 3×3 table at cursor position
222
- */
228
+ /** Renders the full table node to semantic preview HTML. */
229
+ renderToHTML(node: SyntaxNode, _children: string, ctx: PreviewContextLike): Promise<string | null>;
230
+ /** Computes the block wrapper ranges used to group table lines. */
231
+ private computeBlockWrappers;
232
+ /** Computes atomic ranges for delimiters and inline break tags. */
233
+ private computeAtomicRanges;
234
+ /** Applies row, cell, and control decorations for a single table. */
235
+ private decorateTable;
236
+ /** Applies the visual cell decorations for a single table row line. */
237
+ private decorateLine;
238
+ /** Normalizes every parsed table block back into canonical markdown. */
239
+ private normalizeTables;
240
+ /** Defers table normalization until the current update cycle is finished. */
241
+ private scheduleNormalization;
242
+ /** Adds missing spacer lines above and below tables after edits. */
243
+ private ensureTablePadding;
244
+ /** Schedules a padding-only pass after the current update cycle finishes. */
245
+ private schedulePadding;
246
+ /** Repairs carets that land in hidden table markup instead of editable cell content. */
247
+ private ensureTableSelection;
248
+ /** Schedules table selection repair after the current update finishes. */
249
+ private scheduleSelectionRepair;
250
+ /** Rewrites a table block and restores the caret to a target cell position. */
251
+ private replaceTable;
252
+ /** Inserts an empty body row below the given logical row index. */
253
+ private insertRowBelow;
254
+ /** Inserts a starter table near the current cursor line. */
223
255
  private insertTable;
224
- /**
225
- * Add a new row below the current row (Mod-Enter)
226
- */
256
+ /** Adds a new empty body row to the active table. */
227
257
  private addRow;
228
- /**
229
- * Add a new column after the current column (Mod-Shift-Enter)
230
- */
258
+ /** Appends a row and keeps the caret in the requested column. */
259
+ private appendRow;
260
+ /** Inserts a new column after the current column. */
231
261
  private addColumn;
232
- /**
233
- * Handle Enter key inside a table.
234
- * - Last cell of last row: create a new row
235
- * - Empty last row: remove it and move cursor after table
236
- */
237
- private handleEnter;
238
- /**
239
- * Handle Tab key inside a table — move to next/previous cell
240
- */
262
+ /** Appends a new column at the far right of the table. */
263
+ private appendColumn;
264
+ /** Removes the current body row or clears the last remaining row. */
265
+ private removeRow;
266
+ /** Removes the current column when the table has more than one column. */
267
+ private removeColumn;
268
+ /** Moves to the next or previous logical cell with Tab navigation. */
241
269
  private handleTab;
242
- /**
243
- * Find the Table node at the cursor position
244
- */
270
+ /** Moves horizontally between adjacent cells when the caret hits an edge. */
271
+ private handleArrowHorizontal;
272
+ /** Moves vertically between rows while keeping the current column. */
273
+ private handleArrowVertical;
274
+ /** Advances downward on Enter and manages the trailing empty row behavior. */
275
+ private handleEnter;
276
+ /** Inserts a canonical `<br />` token inside the current table cell. */
277
+ private insertBreakTag;
278
+ /** Deletes a whole `<br />` token when backspace or delete hits it. */
279
+ private handleBreakDeletion;
280
+ /** Moves the current selection anchor into a target cell. */
281
+ private moveSelectionToCell;
282
+ /** Returns the table currently containing the editor cursor. */
245
283
  private getTableAtCursor;
246
- /**
247
- * Split a table line into cells (keeping the whitespace around content)
248
- */
249
- private splitLineToCells;
250
- renderToHTML(node: SyntaxNode, _children: string, _ctx: PreviewContextLike): Promise<string | null>;
284
+ /** Returns the active cell under the current selection head. */
285
+ private getCurrentCell;
251
286
  }
252
287
 
253
288
  /**
@@ -1,7 +1,7 @@
1
- export { CodePlugin, EmojiPlugin, HRPlugin, HTMLPlugin, HeadingPlugin, ImagePlugin, InlinePlugin, LinkPlugin, ListPlugin, MathPlugin, MermaidPlugin, ParagraphPlugin, QuotePlugin, TablePlugin, allPlugins, essentialPlugins } from '../chunk-L2XSK57Y.js';
2
- import '../chunk-ZUI3GI3W.js';
1
+ export { CodePlugin, EmojiPlugin, HRPlugin, HTMLPlugin, HeadingPlugin, ImagePlugin, InlinePlugin, LinkPlugin, ListPlugin, MathPlugin, MermaidPlugin, ParagraphPlugin, QuotePlugin, TablePlugin, allPlugins, essentialPlugins } from '../chunk-NRPI5O6Y.js';
2
+ import '../chunk-UCHBDJ4R.js';
3
3
  import '../chunk-JF3WXXMJ.js';
4
4
  import '../chunk-I563H35S.js';
5
- import '../chunk-EEHILRG5.js';
5
+ import '../chunk-TD3L5C45.js';
6
6
  //# sourceMappingURL=index.js.map
7
7
  //# sourceMappingURL=index.js.map
@@ -2,7 +2,7 @@
2
2
 
3
3
  var chunk5MC4T7JH_cjs = require('../chunk-5MC4T7JH.cjs');
4
4
  var chunkCLW73JRX_cjs = require('../chunk-CLW73JRX.cjs');
5
- require('../chunk-TBVZEK2H.cjs');
5
+ require('../chunk-W75QUUQC.cjs');
6
6
 
7
7
 
8
8
 
@@ -1,5 +1,5 @@
1
1
  export { generateCSS, preview } from '../chunk-IAXF4SJL.js';
2
2
  export { PreviewRenderer, defaultRenderers, escapeHtml, generateSyntaxThemeCSS } from '../chunk-I563H35S.js';
3
- import '../chunk-EEHILRG5.js';
3
+ import '../chunk-TD3L5C45.js';
4
4
  //# sourceMappingURL=index.js.map
5
5
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "draftly",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Core library for draftly",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -114,33 +114,35 @@ export function draftly(config: DraftlyConfig = {}): Extension[] {
114
114
  // Create plugin context for lifecycle methods
115
115
  const pluginContext: PluginContext = { config };
116
116
 
117
- // Process each plugin
118
- for (const plugin of allPlugins) {
119
- // Call onRegister lifecycle hook
120
- plugin.onRegister(pluginContext);
121
-
122
- // Collect extensions via class method
123
- const exts = plugin.getExtensions();
124
- if (exts.length > 0) {
125
- pluginExtensions.push(...exts);
126
- }
127
-
128
- // Collect keymaps via class method
129
- const keys = plugin.getKeymap();
130
- if (keys.length > 0) {
131
- pluginKeymaps.push(...keys);
132
- }
133
-
134
- // Collect theme via class method
135
- const theme = plugin.theme;
136
- if (baseStyles && theme && typeof theme === "function") {
137
- pluginExtensions.push(EditorView.theme(theme(configTheme)));
138
- }
139
-
140
- // Collect markdown parser extensions via class method
141
- const md = plugin.getMarkdownConfig();
142
- if (md) {
143
- markdownExtensions.push(md);
117
+ if (!disableViewPlugin) {
118
+ // Process each plugin
119
+ for (const plugin of allPlugins) {
120
+ // Call onRegister lifecycle hook
121
+ plugin.onRegister(pluginContext);
122
+
123
+ // Collect extensions via class method
124
+ const exts = plugin.getExtensions();
125
+ if (exts.length > 0) {
126
+ pluginExtensions.push(...exts);
127
+ }
128
+
129
+ // Collect keymaps via class method
130
+ const keys = plugin.getKeymap();
131
+ if (keys.length > 0) {
132
+ pluginKeymaps.push(...keys);
133
+ }
134
+
135
+ // Collect theme via class method
136
+ const theme = plugin.theme;
137
+ if (baseStyles && theme && typeof theme === "function") {
138
+ pluginExtensions.push(EditorView.theme(theme(configTheme)));
139
+ }
140
+
141
+ // Collect markdown parser extensions via class method
142
+ const md = plugin.getMarkdownConfig();
143
+ if (md) {
144
+ markdownExtensions.push(md);
145
+ }
144
146
  }
145
147
  }
146
148
 
@@ -80,18 +80,20 @@ export function createTheme({
80
80
  export function flattenThemeStyles(themeStyles: ThemeStyle, parentSelector?: string): ThemeStyle {
81
81
  const flattened: ThemeStyle = {};
82
82
 
83
- for (const [selector, styles] of Object.entries(themeStyles)) {
84
- if (typeof styles === "object" && !Array.isArray(styles)) {
85
- // Flatten nested styles
86
- const fullSelector = fixSelector(parentSelector ? `${parentSelector} ${selector}` : selector);
87
- const nestedStyles = flattenThemeStyles(styles as ThemeStyle, fullSelector);
88
- Object.assign(flattened, nestedStyles);
89
- } else {
90
- // Add styles to the flattened object
91
- if (parentSelector) {
92
- flattened[parentSelector] = { ...flattened[parentSelector], [selector]: styles };
83
+ for (const [selectors, styles] of Object.entries(themeStyles)) {
84
+ for (const selector of selectors.split(",")) {
85
+ if (typeof styles === "object" && !Array.isArray(styles)) {
86
+ // Flatten nested styles
87
+ const fullSelector = fixSelector(parentSelector ? `${parentSelector} ${selector}` : selector);
88
+ const nestedStyles = flattenThemeStyles(styles as ThemeStyle, fullSelector);
89
+ Object.assign(flattened, nestedStyles);
93
90
  } else {
94
- flattened[selector] = styles as StyleSpec;
91
+ // Add styles to the flattened object
92
+ if (parentSelector) {
93
+ flattened[parentSelector] = { ...flattened[parentSelector], [selector]: styles };
94
+ } else {
95
+ flattened[selector] = styles as StyleSpec;
96
+ }
95
97
  }
96
98
  }
97
99
  }