@domenico-esposito/react-native-markdown-editor 0.1.1

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.
Files changed (76) hide show
  1. package/.eslintrc.js +5 -0
  2. package/README.md +265 -0
  3. package/build/MarkdownRenderer.d.ts +12 -0
  4. package/build/MarkdownRenderer.d.ts.map +1 -0
  5. package/build/MarkdownRenderer.js +165 -0
  6. package/build/MarkdownRenderer.js.map +1 -0
  7. package/build/MarkdownTextInput.d.ts +10 -0
  8. package/build/MarkdownTextInput.d.ts.map +1 -0
  9. package/build/MarkdownTextInput.js +233 -0
  10. package/build/MarkdownTextInput.js.map +1 -0
  11. package/build/MarkdownToolbar.d.ts +11 -0
  12. package/build/MarkdownToolbar.d.ts.map +1 -0
  13. package/build/MarkdownToolbar.js +98 -0
  14. package/build/MarkdownToolbar.js.map +1 -0
  15. package/build/index.d.ts +14 -0
  16. package/build/index.d.ts.map +1 -0
  17. package/build/index.js +11 -0
  18. package/build/index.js.map +1 -0
  19. package/build/markdownCore.types.d.ts +321 -0
  20. package/build/markdownCore.types.d.ts.map +1 -0
  21. package/build/markdownCore.types.js +2 -0
  22. package/build/markdownCore.types.js.map +1 -0
  23. package/build/markdownHighlight.d.ts +31 -0
  24. package/build/markdownHighlight.d.ts.map +1 -0
  25. package/build/markdownHighlight.js +378 -0
  26. package/build/markdownHighlight.js.map +1 -0
  27. package/build/markdownHighlight.types.d.ts +48 -0
  28. package/build/markdownHighlight.types.d.ts.map +1 -0
  29. package/build/markdownHighlight.types.js +9 -0
  30. package/build/markdownHighlight.types.js.map +1 -0
  31. package/build/markdownParser.d.ts +16 -0
  32. package/build/markdownParser.d.ts.map +1 -0
  33. package/build/markdownParser.js +309 -0
  34. package/build/markdownParser.js.map +1 -0
  35. package/build/markdownRendererDefaults.d.ts +113 -0
  36. package/build/markdownRendererDefaults.d.ts.map +1 -0
  37. package/build/markdownRendererDefaults.js +174 -0
  38. package/build/markdownRendererDefaults.js.map +1 -0
  39. package/build/markdownSegment.types.d.ts +22 -0
  40. package/build/markdownSegment.types.d.ts.map +1 -0
  41. package/build/markdownSegment.types.js +2 -0
  42. package/build/markdownSegment.types.js.map +1 -0
  43. package/build/markdownSegmentDefaults.d.ts +43 -0
  44. package/build/markdownSegmentDefaults.d.ts.map +1 -0
  45. package/build/markdownSegmentDefaults.js +176 -0
  46. package/build/markdownSegmentDefaults.js.map +1 -0
  47. package/build/markdownSyntaxUtils.d.ts +58 -0
  48. package/build/markdownSyntaxUtils.d.ts.map +1 -0
  49. package/build/markdownSyntaxUtils.js +98 -0
  50. package/build/markdownSyntaxUtils.js.map +1 -0
  51. package/build/markdownToolbarActions.d.ts +12 -0
  52. package/build/markdownToolbarActions.d.ts.map +1 -0
  53. package/build/markdownToolbarActions.js +212 -0
  54. package/build/markdownToolbarActions.js.map +1 -0
  55. package/build/useMarkdownEditor.d.ts +10 -0
  56. package/build/useMarkdownEditor.d.ts.map +1 -0
  57. package/build/useMarkdownEditor.js +219 -0
  58. package/build/useMarkdownEditor.js.map +1 -0
  59. package/jest.config.js +10 -0
  60. package/package.json +45 -0
  61. package/src/MarkdownRenderer.tsx +240 -0
  62. package/src/MarkdownTextInput.tsx +263 -0
  63. package/src/MarkdownToolbar.tsx +126 -0
  64. package/src/index.ts +31 -0
  65. package/src/markdownCore.types.ts +405 -0
  66. package/src/markdownHighlight.ts +413 -0
  67. package/src/markdownHighlight.types.ts +75 -0
  68. package/src/markdownParser.ts +345 -0
  69. package/src/markdownRendererDefaults.tsx +207 -0
  70. package/src/markdownSegment.types.ts +24 -0
  71. package/src/markdownSegmentDefaults.tsx +208 -0
  72. package/src/markdownSyntaxUtils.ts +139 -0
  73. package/src/markdownToolbarActions.ts +296 -0
  74. package/src/useMarkdownEditor.ts +265 -0
  75. package/tsconfig.json +9 -0
  76. package/tsconfig.test.json +8 -0
@@ -0,0 +1,378 @@
1
+ /**
2
+ * Syntax highlighting module for the live preview editor.
3
+ * Converts raw markdown text into an array of semantic segments,
4
+ * preserving markdown delimiters as visible elements.
5
+ *
6
+ * Unlike the parser in markdownParser.ts (which produces an AST for rendering),
7
+ * this module produces flat {text, type, meta?} segments optimized to be
8
+ * rendered as children of a TextInput.
9
+ *
10
+ * Complexity: O(n) where n is text length.
11
+ */
12
+ import { findUnescapedToken, parseImageSourceAndTitle, isEscaped, isMarkdownFeatureEnabled, isHeadingLevelEnabled } from './markdownSyntaxUtils';
13
+ // ---------------------------------------------------------------------------
14
+ // Regex patterns for block recognition
15
+ // ---------------------------------------------------------------------------
16
+ const HEADING_RE = /^(#{1,6})\s+(.*)/;
17
+ const BLOCKQUOTE_RE = /^(>\s?)(.*)/;
18
+ const HORIZONTAL_RULE_RE = /^ {0,3}([-*_])[ \t]*(?:\1[ \t]*){2,}$/;
19
+ const UNORDERED_LIST_RE = /^(\s*[-*+]\s+)(.*)/;
20
+ const ORDERED_LIST_RE = /^(\s*\d+\.\s+)(.*)/;
21
+ const CODE_FENCE_RE = /^```/;
22
+ // ---------------------------------------------------------------------------
23
+ // Public API
24
+ // ---------------------------------------------------------------------------
25
+ /**
26
+ * Converts markdown text into an array of semantic segments.
27
+ *
28
+ * Parsing happens line by line:
29
+ * 1. Identifies block type (heading, list, quote, code block)
30
+ * 2. Tags block markers (e.g. #, >, -) with dedicated segment types
31
+ * 3. Analyzes inline content (bold, italic, code, link)
32
+ * 4. Produces semantic segments rendered via segment components
33
+ *
34
+ * @param markdown - Raw markdown text
35
+ * @param features - Optional list of enabled features. When provided,
36
+ * only the corresponding syntax is highlighted; disabled
37
+ * syntax is treated as plain text.
38
+ * @returns Array of semantic segments
39
+ */
40
+ export function highlightMarkdown(markdown, features) {
41
+ const lines = markdown.split('\n');
42
+ const segments = [];
43
+ let inCodeBlock = false;
44
+ let prevLineMeta;
45
+ for (let i = 0; i < lines.length; i++) {
46
+ if (i > 0) {
47
+ // Newline inherits previous heading context so Android renders
48
+ // the line break with the heading's larger lineHeight.
49
+ if (prevLineMeta?.lineContext === 'heading') {
50
+ segments.push({ text: '\n', type: 'heading', meta: prevLineMeta });
51
+ }
52
+ else {
53
+ segments.push({ text: '\n', type: 'text' });
54
+ }
55
+ }
56
+ prevLineMeta = undefined;
57
+ const line = lines[i] ?? '';
58
+ // Code fence: open/close code blocks
59
+ if (isMarkdownFeatureEnabled(features, 'codeBlock') && CODE_FENCE_RE.test(line)) {
60
+ segments.push({
61
+ text: line,
62
+ type: 'delimiter',
63
+ meta: { lineContext: 'codeFence' },
64
+ });
65
+ inCodeBlock = !inCodeBlock;
66
+ continue;
67
+ }
68
+ // Inside a code block
69
+ if (inCodeBlock) {
70
+ segments.push({
71
+ text: line,
72
+ type: 'codeBlock',
73
+ });
74
+ continue;
75
+ }
76
+ // Heading: # Title
77
+ const headingMatch = line.match(HEADING_RE);
78
+ if (headingMatch && !isEscaped(line, 0) && isHeadingLevelEnabled(features, headingMatch[1].length)) {
79
+ const level = headingMatch[1].length;
80
+ const headingMeta = { lineContext: 'heading', headingLevel: String(level) };
81
+ prevLineMeta = headingMeta;
82
+ segments.push({
83
+ text: `${headingMatch[1]} `,
84
+ type: 'delimiter',
85
+ meta: headingMeta,
86
+ });
87
+ appendInlineSegments(segments, headingMatch[2] ?? '', {
88
+ baseTextType: 'heading',
89
+ meta: headingMeta,
90
+ features,
91
+ });
92
+ continue;
93
+ }
94
+ // Horizontal rule: ---, ***, ___
95
+ if (isMarkdownFeatureEnabled(features, 'divider') && HORIZONTAL_RULE_RE.test(line)) {
96
+ segments.push({
97
+ text: line,
98
+ type: 'horizontalRule',
99
+ });
100
+ continue;
101
+ }
102
+ // Blockquote: > quote
103
+ if (isMarkdownFeatureEnabled(features, 'quote')) {
104
+ const quoteMatch = line.match(BLOCKQUOTE_RE);
105
+ if (quoteMatch) {
106
+ const quoteMeta = { lineContext: 'quote' };
107
+ segments.push({
108
+ text: quoteMatch[1] ?? '',
109
+ type: 'quoteMarker',
110
+ meta: quoteMeta,
111
+ });
112
+ appendInlineSegments(segments, quoteMatch[2] ?? '', {
113
+ baseTextType: 'quote',
114
+ meta: quoteMeta,
115
+ features,
116
+ });
117
+ continue;
118
+ }
119
+ }
120
+ // Unordered list: - item
121
+ if (isMarkdownFeatureEnabled(features, 'unorderedList')) {
122
+ const ulMatch = line.match(UNORDERED_LIST_RE);
123
+ if (ulMatch) {
124
+ segments.push({
125
+ text: ulMatch[1] ?? '',
126
+ type: 'listMarker',
127
+ });
128
+ appendInlineSegments(segments, ulMatch[2] ?? '', { features });
129
+ continue;
130
+ }
131
+ }
132
+ // Ordered list: 1. item
133
+ if (isMarkdownFeatureEnabled(features, 'orderedList')) {
134
+ const olMatch = line.match(ORDERED_LIST_RE);
135
+ if (olMatch) {
136
+ segments.push({
137
+ text: olMatch[1] ?? '',
138
+ type: 'listMarker',
139
+ });
140
+ appendInlineSegments(segments, olMatch[2] ?? '', { features });
141
+ continue;
142
+ }
143
+ }
144
+ // Simple text line: inline parsing only
145
+ appendInlineSegments(segments, line, { features });
146
+ }
147
+ return segments;
148
+ }
149
+ // ---------------------------------------------------------------------------
150
+ // Segment composition functions
151
+ // ---------------------------------------------------------------------------
152
+ /**
153
+ * Analyzes inline text and adds semantic segments to the array.
154
+ */
155
+ function appendInlineSegments(segments, text, options = {}) {
156
+ const inlineSegs = parseInlineHighlight(text, undefined, options.features);
157
+ for (const seg of inlineSegs) {
158
+ const type = resolveInlineSegmentType(seg, options.baseTextType ?? 'text');
159
+ const mergedMeta = options.meta || seg.meta ? { ...(options.meta ?? {}), ...(seg.meta ?? {}) } : undefined;
160
+ segments.push({
161
+ text: seg.text,
162
+ type,
163
+ ...(mergedMeta ? { meta: mergedMeta } : {}),
164
+ });
165
+ }
166
+ }
167
+ /**
168
+ * Maps a raw inline segment to its public semantic HighlightSegmentType.
169
+ */
170
+ function resolveInlineSegmentType(seg, baseTextType) {
171
+ switch (seg.type) {
172
+ case 'delimiter':
173
+ return 'delimiter';
174
+ case 'code':
175
+ return 'code';
176
+ case 'link-label':
177
+ return 'link';
178
+ case 'link-url':
179
+ return 'linkUrl';
180
+ case 'image-alt':
181
+ return 'image';
182
+ case 'text':
183
+ default:
184
+ if (seg.bold)
185
+ return 'bold';
186
+ if (seg.italic)
187
+ return 'italic';
188
+ if (seg.strikethrough)
189
+ return 'strikethrough';
190
+ return baseTextType;
191
+ }
192
+ }
193
+ // ---------------------------------------------------------------------------
194
+ // Inline parser
195
+ // ---------------------------------------------------------------------------
196
+ /**
197
+ * Inline parser that preserves markdown delimiters and tracks
198
+ * formatting context (bold, italic) recursively.
199
+ *
200
+ * Unlike parseMarkdownInline in markdownParser.ts:
201
+ * - Delimiters (**, _, `, etc.) are kept as 'delimiter' segments
202
+ * - Bold/italic context is propagated to nested levels
203
+ * - Produces flat segments (not a tree) for direct rendering
204
+ *
205
+ * @param content - Inline text to analyze
206
+ * @param context - Formatting context inherited from upper level
207
+ */
208
+ function parseInlineHighlight(content, context = { bold: false, italic: false, strikethrough: false }, features) {
209
+ const segments = [];
210
+ let cursor = 0;
211
+ /**
212
+ * Adds text to segments array, merging adjacent segments
213
+ * of same type to reduce number of Text nodes in rendering.
214
+ */
215
+ const appendText = (value, type = 'text') => {
216
+ if (!value)
217
+ return;
218
+ const last = segments[segments.length - 1];
219
+ // Merge only if type and formatting context match
220
+ if (last && last.type === type && last.bold === context.bold && last.italic === context.italic && last.strikethrough === context.strikethrough) {
221
+ last.text += value;
222
+ return;
223
+ }
224
+ segments.push({
225
+ text: value,
226
+ type,
227
+ bold: context.bold,
228
+ italic: context.italic,
229
+ strikethrough: context.strikethrough,
230
+ });
231
+ };
232
+ while (cursor < content.length) {
233
+ // Escape: \* → * literal
234
+ if (content[cursor] === '\\' && cursor + 1 < content.length) {
235
+ // Keep the backslash visible as a delimiter to preserve character count
236
+ // parity with the input value (required for correct cursor positioning).
237
+ segments.push({ text: '\\', type: 'delimiter', bold: false, italic: false, strikethrough: false });
238
+ appendText(content[cursor + 1] ?? '');
239
+ cursor += 2;
240
+ continue;
241
+ }
242
+ // Inline code: `code`
243
+ if (isMarkdownFeatureEnabled(features, 'code') && content[cursor] === '`') {
244
+ const closeIdx = findUnescapedToken(content, '`', cursor + 1);
245
+ if (closeIdx !== -1) {
246
+ // Backticks are delimiters, content is code
247
+ segments.push({ text: '`', type: 'delimiter', bold: false, italic: false, strikethrough: false });
248
+ segments.push({
249
+ text: content.slice(cursor + 1, closeIdx),
250
+ type: 'code',
251
+ bold: false,
252
+ italic: false,
253
+ strikethrough: false,
254
+ });
255
+ segments.push({ text: '`', type: 'delimiter', bold: false, italic: false, strikethrough: false });
256
+ cursor = closeIdx + 1;
257
+ continue;
258
+ }
259
+ }
260
+ // Bold: **text** or __text__
261
+ if (isMarkdownFeatureEnabled(features, 'bold') && (content.startsWith('**', cursor) || content.startsWith('__', cursor))) {
262
+ const marker = content.slice(cursor, cursor + 2);
263
+ const closeIdx = findUnescapedToken(content, marker, cursor + 2);
264
+ if (closeIdx !== -1) {
265
+ segments.push({ text: marker, type: 'delimiter', bold: false, italic: false, strikethrough: false });
266
+ // Recursion with bold context active: inner content
267
+ // inherits italic state from upper level
268
+ const inner = parseInlineHighlight(content.slice(cursor + 2, closeIdx), { ...context, bold: true }, features);
269
+ segments.push(...inner);
270
+ segments.push({ text: marker, type: 'delimiter', bold: false, italic: false, strikethrough: false });
271
+ cursor = closeIdx + 2;
272
+ continue;
273
+ }
274
+ }
275
+ // Strikethrough: ~~text~~
276
+ if (isMarkdownFeatureEnabled(features, 'strikethrough') && content.startsWith('~~', cursor)) {
277
+ const closeIdx = findUnescapedToken(content, '~~', cursor + 2);
278
+ if (closeIdx !== -1) {
279
+ segments.push({ text: '~~', type: 'delimiter', bold: false, italic: false, strikethrough: false });
280
+ const inner = parseInlineHighlight(content.slice(cursor + 2, closeIdx), { ...context, strikethrough: true }, features);
281
+ segments.push(...inner);
282
+ segments.push({ text: '~~', type: 'delimiter', bold: false, italic: false, strikethrough: false });
283
+ cursor = closeIdx + 2;
284
+ continue;
285
+ }
286
+ }
287
+ // Italic: *text* or _text_
288
+ if (isMarkdownFeatureEnabled(features, 'italic') && (content[cursor] === '*' || content[cursor] === '_')) {
289
+ const marker = content[cursor];
290
+ const closeIdx = findUnescapedToken(content, marker, cursor + 1);
291
+ if (closeIdx !== -1) {
292
+ segments.push({ text: marker, type: 'delimiter', bold: false, italic: false, strikethrough: false });
293
+ // Recursion with italic context active: inner content
294
+ // inherits bold state from upper level
295
+ const inner = parseInlineHighlight(content.slice(cursor + 1, closeIdx), { ...context, italic: true }, features);
296
+ segments.push(...inner);
297
+ segments.push({ text: marker, type: 'delimiter', bold: false, italic: false, strikethrough: false });
298
+ cursor = closeIdx + 1;
299
+ continue;
300
+ }
301
+ }
302
+ // Image: ![alt](url) or ![alt](url "title")
303
+ if (content[cursor] === '!' && content[cursor + 1] === '[') {
304
+ if (isMarkdownFeatureEnabled(features, 'image')) {
305
+ const altClose = findUnescapedToken(content, ']', cursor + 2);
306
+ if (altClose !== -1 && content[altClose + 1] === '(') {
307
+ const srcClose = findUnescapedToken(content, ')', altClose + 2);
308
+ if (srcClose !== -1) {
309
+ const fullText = content.slice(cursor, srcClose + 1);
310
+ const alt = content.slice(cursor + 2, altClose);
311
+ const rawUrl = content.slice(altClose + 2, srcClose).trim();
312
+ const { src, title } = parseImageSourceAndTitle(rawUrl, { unescapeSrc: false });
313
+ segments.push({
314
+ text: fullText,
315
+ type: 'image-alt',
316
+ bold: context.bold,
317
+ italic: context.italic,
318
+ strikethrough: context.strikethrough,
319
+ meta: { src, alt, ...(title ? { title } : {}) },
320
+ });
321
+ cursor = srcClose + 1;
322
+ continue;
323
+ }
324
+ }
325
+ }
326
+ else {
327
+ // Image disabled: consume "!" as plain text and skip ahead so
328
+ // the link parser does not pick up "[alt](url)" as a link.
329
+ const altClose = findUnescapedToken(content, ']', cursor + 2);
330
+ if (altClose !== -1 && content[altClose + 1] === '(') {
331
+ const srcClose = findUnescapedToken(content, ')', altClose + 2);
332
+ if (srcClose !== -1) {
333
+ appendText(content.slice(cursor, srcClose + 1));
334
+ cursor = srcClose + 1;
335
+ continue;
336
+ }
337
+ }
338
+ appendText('!');
339
+ cursor += 1;
340
+ continue;
341
+ }
342
+ }
343
+ // Link: [label](url)
344
+ if (content[cursor] === '[') {
345
+ const labelClose = findUnescapedToken(content, ']', cursor + 1);
346
+ if (labelClose !== -1 && content[labelClose + 1] === '(') {
347
+ const hrefClose = findUnescapedToken(content, ')', labelClose + 2);
348
+ if (hrefClose !== -1) {
349
+ // Delimiters [] and () are tagged separately from label/url
350
+ segments.push({ text: '[', type: 'delimiter', bold: context.bold, italic: context.italic, strikethrough: context.strikethrough });
351
+ segments.push({
352
+ text: content.slice(cursor + 1, labelClose),
353
+ type: 'link-label',
354
+ bold: context.bold,
355
+ italic: context.italic,
356
+ strikethrough: context.strikethrough,
357
+ });
358
+ segments.push({ text: '](', type: 'delimiter', bold: context.bold, italic: context.italic, strikethrough: context.strikethrough });
359
+ segments.push({
360
+ text: content.slice(labelClose + 2, hrefClose),
361
+ type: 'link-url',
362
+ bold: context.bold,
363
+ italic: context.italic,
364
+ strikethrough: context.strikethrough,
365
+ });
366
+ segments.push({ text: ')', type: 'delimiter', bold: context.bold, italic: context.italic, strikethrough: context.strikethrough });
367
+ cursor = hrefClose + 1;
368
+ continue;
369
+ }
370
+ }
371
+ }
372
+ // Simple text character
373
+ appendText(content[cursor] ?? '');
374
+ cursor += 1;
375
+ }
376
+ return segments;
377
+ }
378
+ //# sourceMappingURL=markdownHighlight.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdownHighlight.js","sourceRoot":"","sources":["../src/markdownHighlight.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Syntax highlighting module for the live preview editor.\n * Converts raw markdown text into an array of semantic segments,\n * preserving markdown delimiters as visible elements.\n *\n * Unlike the parser in markdownParser.ts (which produces an AST for rendering),\n * this module produces flat {text, type, meta?} segments optimized to be\n * rendered as children of a TextInput.\n *\n * Complexity: O(n) where n is text length.\n */\n\nimport { findUnescapedToken, parseImageSourceAndTitle, isEscaped, isMarkdownFeatureEnabled, isHeadingLevelEnabled } from './markdownSyntaxUtils';\nimport type { HighlightSegmentType, HighlightSegment, InlineSegmentType, InlineContext, RawInlineSegment } from './markdownHighlight.types';\nimport type { MarkdownToolbarAction } from './markdownCore.types';\n\nexport type { HighlightSegmentType, HighlightSegment } from './markdownHighlight.types';\n\n// ---------------------------------------------------------------------------\n// Regex patterns for block recognition\n// ---------------------------------------------------------------------------\n\nconst HEADING_RE = /^(#{1,6})\\s+(.*)/;\nconst BLOCKQUOTE_RE = /^(>\\s?)(.*)/;\nconst HORIZONTAL_RULE_RE = /^ {0,3}([-*_])[ \\t]*(?:\\1[ \\t]*){2,}$/;\nconst UNORDERED_LIST_RE = /^(\\s*[-*+]\\s+)(.*)/;\nconst ORDERED_LIST_RE = /^(\\s*\\d+\\.\\s+)(.*)/;\nconst CODE_FENCE_RE = /^```/;\n\ntype AppendInlineOptions = {\n\tbaseTextType?: Extract<HighlightSegmentType, 'text' | 'heading' | 'quote'>;\n\tmeta?: Record<string, string>;\n\tfeatures?: MarkdownToolbarAction[];\n};\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Converts markdown text into an array of semantic segments.\n *\n * Parsing happens line by line:\n * 1. Identifies block type (heading, list, quote, code block)\n * 2. Tags block markers (e.g. #, >, -) with dedicated segment types\n * 3. Analyzes inline content (bold, italic, code, link)\n * 4. Produces semantic segments rendered via segment components\n *\n * @param markdown - Raw markdown text\n * @param features - Optional list of enabled features. When provided,\n * only the corresponding syntax is highlighted; disabled\n * syntax is treated as plain text.\n * @returns Array of semantic segments\n */\nexport function highlightMarkdown(markdown: string, features?: MarkdownToolbarAction[]): HighlightSegment[] {\n\tconst lines = markdown.split('\\n');\n\tconst segments: HighlightSegment[] = [];\n\n\tlet inCodeBlock = false;\n\tlet prevLineMeta: Record<string, string> | undefined;\n\n\tfor (let i = 0; i < lines.length; i++) {\n\t\tif (i > 0) {\n\t\t\t// Newline inherits previous heading context so Android renders\n\t\t\t// the line break with the heading's larger lineHeight.\n\t\t\tif (prevLineMeta?.lineContext === 'heading') {\n\t\t\t\tsegments.push({ text: '\\n', type: 'heading', meta: prevLineMeta });\n\t\t\t} else {\n\t\t\t\tsegments.push({ text: '\\n', type: 'text' });\n\t\t\t}\n\t\t}\n\t\tprevLineMeta = undefined;\n\n\t\tconst line = lines[i] ?? '';\n\n\t\t// Code fence: open/close code blocks\n\t\tif (isMarkdownFeatureEnabled(features, 'codeBlock') && CODE_FENCE_RE.test(line)) {\n\t\t\tsegments.push({\n\t\t\t\ttext: line,\n\t\t\t\ttype: 'delimiter',\n\t\t\t\tmeta: { lineContext: 'codeFence' },\n\t\t\t});\n\t\t\tinCodeBlock = !inCodeBlock;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Inside a code block\n\t\tif (inCodeBlock) {\n\t\t\tsegments.push({\n\t\t\t\ttext: line,\n\t\t\t\ttype: 'codeBlock',\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Heading: # Title\n\t\tconst headingMatch = line.match(HEADING_RE);\n\t\tif (headingMatch && !isEscaped(line, 0) && isHeadingLevelEnabled(features, headingMatch[1]!.length)) {\n\t\t\tconst level = headingMatch[1]!.length;\n\t\t\tconst headingMeta = { lineContext: 'heading', headingLevel: String(level) };\n\t\t\tprevLineMeta = headingMeta;\n\t\t\tsegments.push({\n\t\t\t\ttext: `${headingMatch[1]} `,\n\t\t\t\ttype: 'delimiter',\n\t\t\t\tmeta: headingMeta,\n\t\t\t});\n\t\t\tappendInlineSegments(segments, headingMatch[2] ?? '', {\n\t\t\t\tbaseTextType: 'heading',\n\t\t\t\tmeta: headingMeta,\n\t\t\t\tfeatures,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Horizontal rule: ---, ***, ___\n\t\tif (isMarkdownFeatureEnabled(features, 'divider') && HORIZONTAL_RULE_RE.test(line)) {\n\t\t\tsegments.push({\n\t\t\t\ttext: line,\n\t\t\t\ttype: 'horizontalRule',\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Blockquote: > quote\n\t\tif (isMarkdownFeatureEnabled(features, 'quote')) {\n\t\t\tconst quoteMatch = line.match(BLOCKQUOTE_RE);\n\t\t\tif (quoteMatch) {\n\t\t\t\tconst quoteMeta = { lineContext: 'quote' };\n\t\t\t\tsegments.push({\n\t\t\t\t\ttext: quoteMatch[1] ?? '',\n\t\t\t\t\ttype: 'quoteMarker',\n\t\t\t\t\tmeta: quoteMeta,\n\t\t\t\t});\n\t\t\t\tappendInlineSegments(segments, quoteMatch[2] ?? '', {\n\t\t\t\t\tbaseTextType: 'quote',\n\t\t\t\t\tmeta: quoteMeta,\n\t\t\t\t\tfeatures,\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// Unordered list: - item\n\t\tif (isMarkdownFeatureEnabled(features, 'unorderedList')) {\n\t\t\tconst ulMatch = line.match(UNORDERED_LIST_RE);\n\t\t\tif (ulMatch) {\n\t\t\t\tsegments.push({\n\t\t\t\t\ttext: ulMatch[1] ?? '',\n\t\t\t\t\ttype: 'listMarker',\n\t\t\t\t});\n\t\t\t\tappendInlineSegments(segments, ulMatch[2] ?? '', { features });\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// Ordered list: 1. item\n\t\tif (isMarkdownFeatureEnabled(features, 'orderedList')) {\n\t\t\tconst olMatch = line.match(ORDERED_LIST_RE);\n\t\t\tif (olMatch) {\n\t\t\t\tsegments.push({\n\t\t\t\t\ttext: olMatch[1] ?? '',\n\t\t\t\t\ttype: 'listMarker',\n\t\t\t\t});\n\t\t\t\tappendInlineSegments(segments, olMatch[2] ?? '', { features });\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// Simple text line: inline parsing only\n\t\tappendInlineSegments(segments, line, { features });\n\t}\n\n\treturn segments;\n}\n\n// ---------------------------------------------------------------------------\n// Segment composition functions\n// ---------------------------------------------------------------------------\n\n/**\n * Analyzes inline text and adds semantic segments to the array.\n */\nfunction appendInlineSegments(segments: HighlightSegment[], text: string, options: AppendInlineOptions = {}): void {\n\tconst inlineSegs = parseInlineHighlight(text, undefined, options.features);\n\tfor (const seg of inlineSegs) {\n\t\tconst type = resolveInlineSegmentType(seg, options.baseTextType ?? 'text');\n\t\tconst mergedMeta = options.meta || seg.meta ? { ...(options.meta ?? {}), ...(seg.meta ?? {}) } : undefined;\n\t\tsegments.push({\n\t\t\ttext: seg.text,\n\t\t\ttype,\n\t\t\t...(mergedMeta ? { meta: mergedMeta } : {}),\n\t\t});\n\t}\n}\n\n/**\n * Maps a raw inline segment to its public semantic HighlightSegmentType.\n */\nfunction resolveInlineSegmentType(seg: RawInlineSegment, baseTextType: Extract<HighlightSegmentType, 'text' | 'heading' | 'quote'>): HighlightSegmentType {\n\tswitch (seg.type) {\n\t\tcase 'delimiter':\n\t\t\treturn 'delimiter';\n\t\tcase 'code':\n\t\t\treturn 'code';\n\t\tcase 'link-label':\n\t\t\treturn 'link';\n\t\tcase 'link-url':\n\t\t\treturn 'linkUrl';\n\t\tcase 'image-alt':\n\t\t\treturn 'image';\n\t\tcase 'text':\n\t\tdefault:\n\t\t\tif (seg.bold) return 'bold';\n\t\t\tif (seg.italic) return 'italic';\n\t\t\tif (seg.strikethrough) return 'strikethrough';\n\t\t\treturn baseTextType;\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Inline parser\n// ---------------------------------------------------------------------------\n\n/**\n * Inline parser that preserves markdown delimiters and tracks\n * formatting context (bold, italic) recursively.\n *\n * Unlike parseMarkdownInline in markdownParser.ts:\n * - Delimiters (**, _, `, etc.) are kept as 'delimiter' segments\n * - Bold/italic context is propagated to nested levels\n * - Produces flat segments (not a tree) for direct rendering\n *\n * @param content - Inline text to analyze\n * @param context - Formatting context inherited from upper level\n */\nfunction parseInlineHighlight(content: string, context: InlineContext = { bold: false, italic: false, strikethrough: false }, features?: MarkdownToolbarAction[]): RawInlineSegment[] {\n\tconst segments: RawInlineSegment[] = [];\n\tlet cursor = 0;\n\n\t/**\n\t * Adds text to segments array, merging adjacent segments\n\t * of same type to reduce number of Text nodes in rendering.\n\t */\n\tconst appendText = (value: string, type: InlineSegmentType = 'text') => {\n\t\tif (!value) return;\n\t\tconst last = segments[segments.length - 1];\n\t\t// Merge only if type and formatting context match\n\t\tif (last && last.type === type && last.bold === context.bold && last.italic === context.italic && last.strikethrough === context.strikethrough) {\n\t\t\tlast.text += value;\n\t\t\treturn;\n\t\t}\n\t\tsegments.push({\n\t\t\ttext: value,\n\t\t\ttype,\n\t\t\tbold: context.bold,\n\t\t\titalic: context.italic,\n\t\t\tstrikethrough: context.strikethrough,\n\t\t});\n\t};\n\n\twhile (cursor < content.length) {\n\t\t// Escape: \\* → * literal\n\t\tif (content[cursor] === '\\\\' && cursor + 1 < content.length) {\n\t\t\t// Keep the backslash visible as a delimiter to preserve character count\n\t\t\t// parity with the input value (required for correct cursor positioning).\n\t\t\tsegments.push({ text: '\\\\', type: 'delimiter', bold: false, italic: false, strikethrough: false });\n\t\t\tappendText(content[cursor + 1] ?? '');\n\t\t\tcursor += 2;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Inline code: `code`\n\t\tif (isMarkdownFeatureEnabled(features, 'code') && content[cursor] === '`') {\n\t\t\tconst closeIdx = findUnescapedToken(content, '`', cursor + 1);\n\t\t\tif (closeIdx !== -1) {\n\t\t\t\t// Backticks are delimiters, content is code\n\t\t\t\tsegments.push({ text: '`', type: 'delimiter', bold: false, italic: false, strikethrough: false });\n\t\t\t\tsegments.push({\n\t\t\t\t\ttext: content.slice(cursor + 1, closeIdx),\n\t\t\t\t\ttype: 'code',\n\t\t\t\t\tbold: false,\n\t\t\t\t\titalic: false,\n\t\t\t\t\tstrikethrough: false,\n\t\t\t\t});\n\t\t\t\tsegments.push({ text: '`', type: 'delimiter', bold: false, italic: false, strikethrough: false });\n\t\t\t\tcursor = closeIdx + 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// Bold: **text** or __text__\n\t\tif (isMarkdownFeatureEnabled(features, 'bold') && (content.startsWith('**', cursor) || content.startsWith('__', cursor))) {\n\t\t\tconst marker = content.slice(cursor, cursor + 2);\n\t\t\tconst closeIdx = findUnescapedToken(content, marker, cursor + 2);\n\t\t\tif (closeIdx !== -1) {\n\t\t\t\tsegments.push({ text: marker, type: 'delimiter', bold: false, italic: false, strikethrough: false });\n\t\t\t\t// Recursion with bold context active: inner content\n\t\t\t\t// inherits italic state from upper level\n\t\t\t\tconst inner = parseInlineHighlight(content.slice(cursor + 2, closeIdx), { ...context, bold: true }, features);\n\t\t\t\tsegments.push(...inner);\n\t\t\t\tsegments.push({ text: marker, type: 'delimiter', bold: false, italic: false, strikethrough: false });\n\t\t\t\tcursor = closeIdx + 2;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// Strikethrough: ~~text~~\n\t\tif (isMarkdownFeatureEnabled(features, 'strikethrough') && content.startsWith('~~', cursor)) {\n\t\t\tconst closeIdx = findUnescapedToken(content, '~~', cursor + 2);\n\t\t\tif (closeIdx !== -1) {\n\t\t\t\tsegments.push({ text: '~~', type: 'delimiter', bold: false, italic: false, strikethrough: false });\n\t\t\t\tconst inner = parseInlineHighlight(content.slice(cursor + 2, closeIdx), { ...context, strikethrough: true }, features);\n\t\t\t\tsegments.push(...inner);\n\t\t\t\tsegments.push({ text: '~~', type: 'delimiter', bold: false, italic: false, strikethrough: false });\n\t\t\t\tcursor = closeIdx + 2;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// Italic: *text* or _text_\n\t\tif (isMarkdownFeatureEnabled(features, 'italic') && (content[cursor] === '*' || content[cursor] === '_')) {\n\t\t\tconst marker = content[cursor]!;\n\t\t\tconst closeIdx = findUnescapedToken(content, marker, cursor + 1);\n\t\t\tif (closeIdx !== -1) {\n\t\t\t\tsegments.push({ text: marker, type: 'delimiter', bold: false, italic: false, strikethrough: false });\n\t\t\t\t// Recursion with italic context active: inner content\n\t\t\t\t// inherits bold state from upper level\n\t\t\t\tconst inner = parseInlineHighlight(content.slice(cursor + 1, closeIdx), { ...context, italic: true }, features);\n\t\t\t\tsegments.push(...inner);\n\t\t\t\tsegments.push({ text: marker, type: 'delimiter', bold: false, italic: false, strikethrough: false });\n\t\t\t\tcursor = closeIdx + 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// Image: ![alt](url) or ![alt](url \"title\")\n\t\tif (content[cursor] === '!' && content[cursor + 1] === '[') {\n\t\t\tif (isMarkdownFeatureEnabled(features, 'image')) {\n\t\t\t\tconst altClose = findUnescapedToken(content, ']', cursor + 2);\n\t\t\t\tif (altClose !== -1 && content[altClose + 1] === '(') {\n\t\t\t\t\tconst srcClose = findUnescapedToken(content, ')', altClose + 2);\n\t\t\t\t\tif (srcClose !== -1) {\n\t\t\t\t\t\tconst fullText = content.slice(cursor, srcClose + 1);\n\t\t\t\t\t\tconst alt = content.slice(cursor + 2, altClose);\n\t\t\t\t\t\tconst rawUrl = content.slice(altClose + 2, srcClose).trim();\n\t\t\t\t\t\tconst { src, title } = parseImageSourceAndTitle(rawUrl, { unescapeSrc: false });\n\t\t\t\t\t\tsegments.push({\n\t\t\t\t\t\t\ttext: fullText,\n\t\t\t\t\t\t\ttype: 'image-alt',\n\t\t\t\t\t\t\tbold: context.bold,\n\t\t\t\t\t\t\titalic: context.italic,\n\t\t\t\t\t\t\tstrikethrough: context.strikethrough,\n\t\t\t\t\t\t\tmeta: { src, alt, ...(title ? { title } : {}) },\n\t\t\t\t\t\t});\n\t\t\t\t\t\tcursor = srcClose + 1;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Image disabled: consume \"!\" as plain text and skip ahead so\n\t\t\t\t// the link parser does not pick up \"[alt](url)\" as a link.\n\t\t\t\tconst altClose = findUnescapedToken(content, ']', cursor + 2);\n\t\t\t\tif (altClose !== -1 && content[altClose + 1] === '(') {\n\t\t\t\t\tconst srcClose = findUnescapedToken(content, ')', altClose + 2);\n\t\t\t\t\tif (srcClose !== -1) {\n\t\t\t\t\t\tappendText(content.slice(cursor, srcClose + 1));\n\t\t\t\t\t\tcursor = srcClose + 1;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tappendText('!');\n\t\t\t\tcursor += 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// Link: [label](url)\n\t\tif (content[cursor] === '[') {\n\t\t\tconst labelClose = findUnescapedToken(content, ']', cursor + 1);\n\t\t\tif (labelClose !== -1 && content[labelClose + 1] === '(') {\n\t\t\t\tconst hrefClose = findUnescapedToken(content, ')', labelClose + 2);\n\t\t\t\tif (hrefClose !== -1) {\n\t\t\t\t\t// Delimiters [] and () are tagged separately from label/url\n\t\t\t\t\tsegments.push({ text: '[', type: 'delimiter', bold: context.bold, italic: context.italic, strikethrough: context.strikethrough });\n\t\t\t\t\tsegments.push({\n\t\t\t\t\t\ttext: content.slice(cursor + 1, labelClose),\n\t\t\t\t\t\ttype: 'link-label',\n\t\t\t\t\t\tbold: context.bold,\n\t\t\t\t\t\titalic: context.italic,\n\t\t\t\t\t\tstrikethrough: context.strikethrough,\n\t\t\t\t\t});\n\t\t\t\t\tsegments.push({ text: '](', type: 'delimiter', bold: context.bold, italic: context.italic, strikethrough: context.strikethrough });\n\t\t\t\t\tsegments.push({\n\t\t\t\t\t\ttext: content.slice(labelClose + 2, hrefClose),\n\t\t\t\t\t\ttype: 'link-url',\n\t\t\t\t\t\tbold: context.bold,\n\t\t\t\t\t\titalic: context.italic,\n\t\t\t\t\t\tstrikethrough: context.strikethrough,\n\t\t\t\t\t});\n\t\t\t\t\tsegments.push({ text: ')', type: 'delimiter', bold: context.bold, italic: context.italic, strikethrough: context.strikethrough });\n\t\t\t\t\tcursor = hrefClose + 1;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Simple text character\n\t\tappendText(content[cursor] ?? '');\n\t\tcursor += 1;\n\t}\n\n\treturn segments;\n}\n"]}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Type definitions for the markdown syntax-highlighting module.
3
+ *
4
+ * Public types (`HighlightSegmentType`, `HighlightSegment`) are re-exported
5
+ * from `index.ts` for consumers who provide custom segment components.
6
+ * Internal types are used only within `markdownHighlight.ts`.
7
+ */
8
+ /**
9
+ * Semantic type of a highlight segment.
10
+ * Exposed to consumers so they can provide custom render components per type.
11
+ */
12
+ export type HighlightSegmentType = 'text' | 'delimiter' | 'heading' | 'bold' | 'italic' | 'strikethrough' | 'code' | 'codeBlock' | 'link' | 'linkUrl' | 'image' | 'quote' | 'quoteMarker' | 'listMarker' | 'horizontalRule';
13
+ /** Semantic highlight segment, ready for rendering via segment components. */
14
+ export type HighlightSegment = {
15
+ text: string;
16
+ type: HighlightSegmentType;
17
+ /** Optional metadata (e.g. image src, alt, title). */
18
+ meta?: Record<string, string>;
19
+ };
20
+ /**
21
+ * Semantic type of an inline segment.
22
+ * Internally used to map inline tokens to public segment types.
23
+ */
24
+ export type InlineSegmentType = 'text' | 'delimiter' | 'code' | 'link-label' | 'link-url' | 'image-alt';
25
+ /**
26
+ * Inline formatting context, propagated recursively
27
+ * through nesting levels (e.g. bold inside italic).
28
+ */
29
+ export type InlineContext = {
30
+ bold: boolean;
31
+ italic: boolean;
32
+ strikethrough: boolean;
33
+ };
34
+ /**
35
+ * Intermediate segment produced by the inline parser.
36
+ * Contains both semantic type and formatting context,
37
+ * which will be combined to produce the final semantic segment.
38
+ */
39
+ export type RawInlineSegment = {
40
+ text: string;
41
+ type: InlineSegmentType;
42
+ bold: boolean;
43
+ italic: boolean;
44
+ strikethrough: boolean;
45
+ /** Optional metadata for image segments. */
46
+ meta?: Record<string, string>;
47
+ };
48
+ //# sourceMappingURL=markdownHighlight.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdownHighlight.types.d.ts","sourceRoot":"","sources":["../src/markdownHighlight.types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAC7B,MAAM,GACN,WAAW,GACX,SAAS,GACT,MAAM,GACN,QAAQ,GACR,eAAe,GACf,MAAM,GACN,WAAW,GACX,MAAM,GACN,SAAS,GACT,OAAO,GACP,OAAO,GACP,aAAa,GACb,YAAY,GACZ,gBAAgB,CAAC;AAEpB,8EAA8E;AAC9E,MAAM,MAAM,gBAAgB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,oBAAoB,CAAC;IAC3B,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B,CAAC;AAMF;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,GAAG,YAAY,GAAG,UAAU,GAAG,WAAW,CAAC;AAExG;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG;IAC3B,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,OAAO,CAAC;IACvB,4CAA4C;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Type definitions for the markdown syntax-highlighting module.
3
+ *
4
+ * Public types (`HighlightSegmentType`, `HighlightSegment`) are re-exported
5
+ * from `index.ts` for consumers who provide custom segment components.
6
+ * Internal types are used only within `markdownHighlight.ts`.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=markdownHighlight.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdownHighlight.types.js","sourceRoot":"","sources":["../src/markdownHighlight.types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG","sourcesContent":["/**\n * Type definitions for the markdown syntax-highlighting module.\n *\n * Public types (`HighlightSegmentType`, `HighlightSegment`) are re-exported\n * from `index.ts` for consumers who provide custom segment components.\n * Internal types are used only within `markdownHighlight.ts`.\n */\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * Semantic type of a highlight segment.\n * Exposed to consumers so they can provide custom render components per type.\n */\nexport type HighlightSegmentType =\n\t| 'text'\n\t| 'delimiter'\n\t| 'heading'\n\t| 'bold'\n\t| 'italic'\n\t| 'strikethrough'\n\t| 'code'\n\t| 'codeBlock'\n\t| 'link'\n\t| 'linkUrl'\n\t| 'image'\n\t| 'quote'\n\t| 'quoteMarker'\n\t| 'listMarker'\n\t| 'horizontalRule';\n\n/** Semantic highlight segment, ready for rendering via segment components. */\nexport type HighlightSegment = {\n\ttext: string;\n\ttype: HighlightSegmentType;\n\t/** Optional metadata (e.g. image src, alt, title). */\n\tmeta?: Record<string, string>;\n};\n\n// ---------------------------------------------------------------------------\n// Internal types (used only inside markdownHighlight.ts)\n// ---------------------------------------------------------------------------\n\n/**\n * Semantic type of an inline segment.\n * Internally used to map inline tokens to public segment types.\n */\nexport type InlineSegmentType = 'text' | 'delimiter' | 'code' | 'link-label' | 'link-url' | 'image-alt';\n\n/**\n * Inline formatting context, propagated recursively\n * through nesting levels (e.g. bold inside italic).\n */\nexport type InlineContext = {\n\tbold: boolean;\n\titalic: boolean;\n\tstrikethrough: boolean;\n};\n\n/**\n * Intermediate segment produced by the inline parser.\n * Contains both semantic type and formatting context,\n * which will be combined to produce the final semantic segment.\n */\nexport type RawInlineSegment = {\n\ttext: string;\n\ttype: InlineSegmentType;\n\tbold: boolean;\n\titalic: boolean;\n\tstrikethrough: boolean;\n\t/** Optional metadata for image segments. */\n\tmeta?: Record<string, string>;\n};\n"]}
@@ -0,0 +1,16 @@
1
+ import type { MarkdownBlockNode, MarkdownInlineNode, MarkdownToolbarAction } from './markdownCore.types';
2
+ /**
3
+ * Parses markdown text into block nodes.
4
+ *
5
+ * Parsing is line-oriented: block-level constructs are identified first,
6
+ * then text fragments are delegated to the inline parser.
7
+ */
8
+ export declare function parseMarkdown(markdown: string, features?: MarkdownToolbarAction[]): MarkdownBlockNode[];
9
+ /**
10
+ * Parses inline markdown tokens inside a block.
11
+ *
12
+ * The parser scans left-to-right and uses recursion for nested emphasis
13
+ * and link labels.
14
+ */
15
+ export declare function parseMarkdownInline(content: string, features?: MarkdownToolbarAction[]): MarkdownInlineNode[];
16
+ //# sourceMappingURL=markdownParser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdownParser.d.ts","sourceRoot":"","sources":["../src/markdownParser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAmBzG;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,qBAAqB,EAAE,GAAG,iBAAiB,EAAE,CAsHvG;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,qBAAqB,EAAE,GAAG,kBAAkB,EAAE,CA2I7G"}