@ai-matrx/print 0.2.0 → 0.3.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.
@@ -0,0 +1,1260 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/markdown.ts
21
+ var markdown_exports = {};
22
+ __export(markdown_exports, {
23
+ MARKDOWN_ARTICLE_CSS: () => MARKDOWN_ARTICLE_CSS,
24
+ MARKDOWN_ARTICLE_TOKENS_CSS: () => MARKDOWN_ARTICLE_TOKENS_CSS,
25
+ MARKDOWN_DOCUMENT_CSS: () => MARKDOWN_DOCUMENT_CSS,
26
+ MARKDOWN_DOCUMENT_TOKENS_CSS: () => MARKDOWN_DOCUMENT_TOKENS_CSS,
27
+ PRINT_ACTIONS_CSS: () => PRINT_ACTIONS_CSS,
28
+ getMarkdownStylesheet: () => getMarkdownStylesheet,
29
+ hasThinkingContent: () => hasThinkingContent,
30
+ markdownToArticleHtml: () => markdownToArticleHtml,
31
+ markdownToHtml: () => markdownToHtml,
32
+ markdownToHtmlForSkin: () => markdownToHtmlForSkin,
33
+ printMarkdown: () => printMarkdown,
34
+ removeThinkingContent: () => removeThinkingContent,
35
+ renderMarkdownDocument: () => renderMarkdownDocument
36
+ });
37
+ module.exports = __toCommonJS(markdown_exports);
38
+
39
+ // src/core.ts
40
+ function escapeHtml(str) {
41
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
42
+ }
43
+ function openPrintWindow(htmlDocument, filename = "print", windowFeatures = "width=920,height=720,scrollbars=yes") {
44
+ const win = window.open("", "_blank", windowFeatures);
45
+ if (!win) {
46
+ const blob = new Blob([htmlDocument], { type: "text/html;charset=utf-8" });
47
+ const url = URL.createObjectURL(blob);
48
+ const a = document.createElement("a");
49
+ a.href = url;
50
+ a.download = `${filename.replace(/\s+/g, "-").toLowerCase()}.html`;
51
+ document.body.appendChild(a);
52
+ a.click();
53
+ document.body.removeChild(a);
54
+ setTimeout(() => URL.revokeObjectURL(url), 0);
55
+ return "downloaded";
56
+ }
57
+ win.document.open();
58
+ win.document.write(htmlDocument);
59
+ win.document.close();
60
+ return "opened";
61
+ }
62
+
63
+ // src/markdown-css.ts
64
+ var MARKDOWN_DOCUMENT_TOKENS_CSS = `:root {
65
+ --matrx-print-accent: #667eea;
66
+ --matrx-print-accent-2: #764ba2;
67
+ --matrx-print-bg: #ffffff;
68
+ --matrx-print-border: #e1e1e1;
69
+ --matrx-print-border-muted: #d1d5db;
70
+ --matrx-print-border-strong: #e5e5e5;
71
+ --matrx-print-code-bg: #f5f5f5;
72
+ --matrx-print-code-block-bg: #f8f8f8;
73
+ --matrx-print-code-block-fg: #333;
74
+ --matrx-print-code-fg: #d73a49;
75
+ --matrx-print-fg: #1a1a1a;
76
+ --matrx-print-fg-muted: #4a4a4a;
77
+ --matrx-print-fg-subtle: #6b7280;
78
+ --matrx-print-heading: #2a2a2a;
79
+ --matrx-print-heading-sub: #3a3a3a;
80
+ --matrx-print-link-fg: #374151;
81
+ --matrx-print-link-hover-fg: #1f2937;
82
+ --matrx-print-link-underline: #9ca3af;
83
+ --matrx-print-quote-fg: #666;
84
+ --matrx-print-shadow: rgba(0, 0, 0, 0.1);
85
+ --matrx-print-shadow-strong: rgba(0, 0, 0, 0.2);
86
+ --matrx-print-success: #2d5016;
87
+ --matrx-print-success-2: #1e3a0f;
88
+ --matrx-print-surface: #f8f9fa;
89
+ --matrx-print-table-fg: #333333;
90
+ }`;
91
+ var MARKDOWN_ARTICLE_TOKENS_CSS = `:root {
92
+ --matrx-print-accent: #2563eb;
93
+ --matrx-print-bg: #fff;
94
+ --matrx-print-border: #e5e7eb;
95
+ --matrx-print-border-muted: #d1d5db;
96
+ --matrx-print-code-bg: #f1f5f9;
97
+ --matrx-print-fg: #1a1a1a;
98
+ --matrx-print-fg-muted: #374151;
99
+ --matrx-print-fg-subtle: #64748b;
100
+ --matrx-print-heading: #111827;
101
+ --matrx-print-ink: #0f172a;
102
+ --matrx-print-line: #e2e8f0;
103
+ --matrx-print-quote-bg: #f5f3ff;
104
+ --matrx-print-quote-border: #6366f1;
105
+ --matrx-print-surface: #f8fafc;
106
+ --matrx-print-surface-sunken: #f3f4f6;
107
+ --matrx-print-table-head-bg: #1e293b;
108
+ --matrx-print-table-head-border: #334155;
109
+ }`;
110
+ var MARKDOWN_DOCUMENT_CSS = `/*
111
+ * MATRX WordPress CSS - Production Ready
112
+ * Use this CSS in your WordPress theme to style MATRX content
113
+ * All styles are scoped to .matrx-content-container to avoid conflicts
114
+ */
115
+
116
+ /* Content Container */
117
+ .matrx-content-container {
118
+ max-width: 800px;
119
+ margin: 0 auto;
120
+ padding: 2rem;
121
+ line-height: 1.6;
122
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
123
+ }
124
+
125
+ /* Typography */
126
+ .matrx-h1 {
127
+ font-size: 2.5rem;
128
+ font-weight: 700;
129
+ margin: 0 0 1.5rem 0;
130
+ color: var(--matrx-print-fg, #1a1a1a);
131
+ line-height: 1.2;
132
+ }
133
+
134
+ .matrx-h2 {
135
+ font-size: 1.8rem;
136
+ font-weight: 600;
137
+ margin: 3rem 0 1rem 0 !important;
138
+ color: var(--matrx-print-heading, #2a2a2a);
139
+ line-height: 1.3 !important;
140
+ border-bottom: 2px solid var(--matrx-print-border-strong, #e5e5e5);
141
+ padding-bottom: 0.75rem !important;
142
+ padding-top: 0 !important;
143
+ }
144
+
145
+ .matrx-h3 {
146
+ font-size: 1.3rem;
147
+ font-weight: 600;
148
+ margin: 2rem 0 1rem 0;
149
+ color: var(--matrx-print-heading-sub, #3a3a3a);
150
+ line-height: 1.4;
151
+ }
152
+
153
+ .matrx-h4 {
154
+ font-size: 1.1rem;
155
+ font-weight: 600;
156
+ margin: 1.5rem 0 0.75rem 0;
157
+ color: var(--matrx-print-heading-sub, #3a3a3a);
158
+ line-height: 1.4;
159
+ }
160
+
161
+ .matrx-h5 {
162
+ font-size: 1rem;
163
+ font-weight: 600;
164
+ margin: 1.25rem 0 0.5rem 0;
165
+ color: var(--matrx-print-heading-sub, #3a3a3a);
166
+ line-height: 1.4;
167
+ }
168
+
169
+ .matrx-h6 {
170
+ font-size: 0.9rem;
171
+ font-weight: 600;
172
+ margin: 1rem 0 0.5rem 0;
173
+ color: var(--matrx-print-heading-sub, #3a3a3a);
174
+ line-height: 1.4;
175
+ }
176
+
177
+ /* Paragraphs */
178
+ .matrx-intro {
179
+ font-size: 1.1rem;
180
+ color: var(--matrx-print-fg-muted, #4a4a4a);
181
+ margin-bottom: 2rem;
182
+ padding: 1.5rem;
183
+ background: var(--matrx-print-surface, #f8f9fa);
184
+ border-left: 4px solid var(--matrx-print-border-muted, #d1d5db);
185
+ border-radius: 0 8px 8px 0;
186
+ }
187
+
188
+ .matrx-paragraph {
189
+ font-size: 1rem;
190
+ color: var(--matrx-print-fg-muted, #4a4a4a);
191
+ margin-bottom: 1.5rem;
192
+ text-align: justify;
193
+ }
194
+
195
+ /* Text Formatting */
196
+ .matrx-em {
197
+ font-style: italic;
198
+ color: var(--matrx-print-heading, #2a2a2a);
199
+ }
200
+
201
+ .matrx-strong {
202
+ font-weight: 600;
203
+ color: var(--matrx-print-heading, #2a2a2a);
204
+ }
205
+
206
+ /* Links */
207
+ .matrx-link {
208
+ color: var(--matrx-print-link-fg, #374151);
209
+ text-decoration: underline;
210
+ text-decoration-color: var(--matrx-print-border-muted, #d1d5db);
211
+ text-underline-offset: 3px;
212
+ transition: all 0.2s ease;
213
+ }
214
+
215
+ .matrx-link:hover {
216
+ color: var(--matrx-print-link-hover-fg, #1f2937);
217
+ text-decoration-color: var(--matrx-print-link-underline, #9ca3af);
218
+ }
219
+
220
+ /* Images */
221
+ .matrx-image {
222
+ max-width: 100%;
223
+ height: auto;
224
+ display: block;
225
+ margin: 1.5rem auto;
226
+ border-radius: 8px;
227
+ box-shadow: 0 2px 8px var(--matrx-print-shadow, rgba(0, 0, 0, 0.1));
228
+ }
229
+
230
+ /* Lists */
231
+ .matrx-list {
232
+ margin: 1.5rem 0;
233
+ padding-left: 0;
234
+ }
235
+
236
+ .matrx-bullet-list {
237
+ list-style: none;
238
+ }
239
+
240
+ .matrx-list-item {
241
+ margin-bottom: 1rem;
242
+ padding-left: 1.5rem;
243
+ position: relative;
244
+ color: var(--matrx-print-fg-muted, #4a4a4a);
245
+ }
246
+
247
+ .matrx-list-item::before {
248
+ content: "\u2022";
249
+ color: var(--matrx-print-fg-subtle, #6b7280);
250
+ font-weight: bold;
251
+ position: absolute;
252
+ left: 0;
253
+ top: 0;
254
+ font-size: 1.2rem;
255
+ }
256
+
257
+ /* Numbered Lists */
258
+ .matrx-numbered-list {
259
+ list-style: decimal;
260
+ padding-left: 2rem;
261
+ }
262
+
263
+ .matrx-numbered-list > .matrx-list-item {
264
+ padding-left: 0.5rem;
265
+ }
266
+
267
+ .matrx-numbered-list > .matrx-list-item::before {
268
+ content: none;
269
+ /* Remove the bullet */
270
+ }
271
+
272
+ /* Nested list indentation */
273
+ .matrx-nested-list {
274
+ margin-top: 0.5rem;
275
+ margin-bottom: 0.5rem;
276
+ padding-left: 1.5rem !important;
277
+ }
278
+
279
+ /* Ensure nested lists within list items are properly indented */
280
+ .matrx-list-item > .matrx-list {
281
+ margin-top: 0.5rem;
282
+ margin-bottom: 0.5rem;
283
+ padding-left: 1.5rem;
284
+ }
285
+
286
+ /* For multiple levels of nesting, increase indentation */
287
+ .matrx-nested-list .matrx-nested-list {
288
+ padding-left: 1.5rem !important;
289
+ }
290
+
291
+ /* Code */
292
+ .matrx-content-container .matrx-inline-code {
293
+ background-color: var(--matrx-print-code-bg, #f5f5f5);
294
+ padding: 0.125rem 0.25rem;
295
+ border-radius: 0.25rem;
296
+ font-family: "Monaco", "Menlo", "Ubuntu Mono", monospace;
297
+ font-size: 0.875rem;
298
+ color: var(--matrx-print-code-fg, #d73a49);
299
+ }
300
+
301
+ .matrx-content-container .matrx-code-block {
302
+ background-color: var(--matrx-print-code-block-bg, #f8f8f8);
303
+ border: 1px solid var(--matrx-print-border, #e1e1e1);
304
+ border-radius: 0.375rem;
305
+ padding: 1rem;
306
+ margin: 1.5rem 0;
307
+ overflow-x: auto;
308
+ }
309
+
310
+ .matrx-content-container .matrx-code {
311
+ font-family: "Monaco", "Menlo", "Ubuntu Mono", monospace;
312
+ font-size: 0.875rem;
313
+ line-height: 1.5;
314
+ color: var(--matrx-print-code-block-fg, #333);
315
+ }
316
+
317
+ /* Blockquotes */
318
+ .matrx-content-container .matrx-blockquote {
319
+ border-left: 4px solid var(--matrx-print-border, #e1e1e1);
320
+ padding-left: 1rem;
321
+ margin: 1.5rem 0;
322
+ font-style: italic;
323
+ color: var(--matrx-print-quote-fg, #666);
324
+ }
325
+
326
+ /* Tables */
327
+ .matrx-content-container .matrx-table {
328
+ width: 100%;
329
+ border-collapse: collapse;
330
+ margin: 1.5rem 0;
331
+ border: 1px solid var(--matrx-print-border, #e1e1e1);
332
+ }
333
+
334
+ .matrx-content-container .matrx-table-header {
335
+ background-color: var(--matrx-print-surface, #f8f9fa);
336
+ font-weight: 600;
337
+ padding: 0.75rem;
338
+ border: 1px solid var(--matrx-print-border, #e1e1e1);
339
+ text-align: left;
340
+ }
341
+
342
+ .matrx-content-container .matrx-table-cell {
343
+ padding: 0.75rem;
344
+ border: 1px solid var(--matrx-print-border, #e1e1e1);
345
+ }
346
+
347
+ .matrx-content-container .matrx-table-row:nth-child(even) {
348
+ background-color: var(--matrx-print-surface, #f8f9fa);
349
+ }
350
+
351
+ /* Images */
352
+ .matrx-content-container .matrx-image {
353
+ max-width: 100%;
354
+ height: auto;
355
+ border-radius: 0.375rem;
356
+ margin: 1rem 0;
357
+ }
358
+
359
+ /* Horizontal Rules */
360
+ .matrx-content-container .matrx-hr {
361
+ border: none;
362
+ border-top: 1px solid var(--matrx-print-border, #e1e1e1);
363
+ margin: 2rem 0;
364
+ }
365
+
366
+ /* FAQ Styles - Clean Design */
367
+ .matrx-faq-item {
368
+ margin-bottom: 2rem;
369
+ padding: 1.5rem;
370
+ background: var(--matrx-print-surface, #f8f9fa);
371
+ border-radius: 8px;
372
+ border-left: 4px solid var(--matrx-print-border-muted, #d1d5db);
373
+ }
374
+
375
+ .matrx-faq-question {
376
+ font-size: 1.2rem;
377
+ font-weight: 600;
378
+ margin: 0 0 0.75rem 0;
379
+ color: var(--matrx-print-heading, #2a2a2a);
380
+ }
381
+
382
+ .matrx-faq-answer {
383
+ margin: 0;
384
+ color: var(--matrx-print-fg-muted, #4a4a4a);
385
+ line-height: 1.6;
386
+ }
387
+
388
+ /* Code Blocks */
389
+ .matrx-inline-code {
390
+ background-color: var(--matrx-print-code-bg, #f5f5f5);
391
+ padding: 0.125rem 0.25rem;
392
+ border-radius: 0.25rem;
393
+ font-family: "Monaco", "Menlo", "Ubuntu Mono", monospace;
394
+ font-size: 0.875rem;
395
+ color: var(--matrx-print-code-fg, #d73a49);
396
+ }
397
+
398
+ .matrx-code-block {
399
+ background-color: var(--matrx-print-code-block-bg, #f8f8f8);
400
+ border: 1px solid var(--matrx-print-border, #e1e1e1);
401
+ border-radius: 0.375rem;
402
+ padding: 1rem;
403
+ margin: 1.5rem 0;
404
+ overflow-x: auto;
405
+ }
406
+
407
+ .matrx-code {
408
+ font-family: "Monaco", "Menlo", "Ubuntu Mono", monospace;
409
+ font-size: 0.875rem;
410
+ line-height: 1.5;
411
+ color: var(--matrx-print-code-block-fg, #333);
412
+ }
413
+
414
+ /* Blockquotes */
415
+ .matrx-blockquote {
416
+ border-left: 4px solid var(--matrx-print-border, #e1e1e1);
417
+ padding-left: 1rem;
418
+ margin: 1.5rem 0;
419
+ font-style: italic;
420
+ color: var(--matrx-print-quote-fg, #666);
421
+ }
422
+
423
+ /* Tables */
424
+ .matrx-table {
425
+ width: 100%;
426
+ border-collapse: collapse;
427
+ margin: 1.5rem 0;
428
+ border: 1px solid var(--matrx-print-border, #e1e1e1);
429
+ color: var(--matrx-print-table-fg, #333333);
430
+ }
431
+
432
+ .matrx-table-head {
433
+ background-color: var(--matrx-print-surface, #f8f9fa);
434
+ }
435
+
436
+ .matrx-table-body {
437
+ background-color: var(--matrx-print-bg, #ffffff);
438
+ }
439
+
440
+ .matrx-table-header {
441
+ background-color: var(--matrx-print-surface, #f8f9fa);
442
+ font-weight: 600;
443
+ padding: 0.75rem;
444
+ border: 1px solid var(--matrx-print-border, #e1e1e1);
445
+ text-align: left;
446
+ color: var(--matrx-print-table-fg, #333333);
447
+ }
448
+
449
+ .matrx-table-cell {
450
+ padding: 0.75rem;
451
+ border: 1px solid var(--matrx-print-border, #e1e1e1);
452
+ color: var(--matrx-print-table-fg, #333333);
453
+ }
454
+
455
+ .matrx-table-row {
456
+ color: var(--matrx-print-table-fg, #333333);
457
+ }
458
+
459
+ .matrx-table-row:nth-child(even) {
460
+ background-color: var(--matrx-print-surface, #f8f9fa);
461
+ }
462
+
463
+ /* Ensure table content doesn't inherit external colors */
464
+ .matrx-table * {
465
+ color: inherit;
466
+ }
467
+
468
+ /* Images */
469
+ .matrx-image {
470
+ max-width: 100%;
471
+ height: auto;
472
+ border-radius: 0.375rem;
473
+ margin: 1rem 0;
474
+ }
475
+
476
+ /* Horizontal Rules */
477
+ .matrx-hr {
478
+ border: none;
479
+ border-top: 1px solid var(--matrx-print-border, #e1e1e1);
480
+ margin: 2rem 0;
481
+ }
482
+
483
+ /* Utility Classes */
484
+ .matrx-div {
485
+ margin: 0.5rem 0;
486
+ }
487
+
488
+ .matrx-span {
489
+ /* Inherit parent styling by default */
490
+ }
491
+
492
+ /* Flashcard Styles */
493
+ .matrx-flashcards-container {
494
+ margin: 2rem 0;
495
+ display: flex;
496
+ flex-direction: column;
497
+ gap: 0.5rem;
498
+ }
499
+
500
+ .matrx-flashcard {
501
+ perspective: 1000px;
502
+ perspective-origin: center center;
503
+ height: 200px;
504
+ cursor: pointer;
505
+ position: relative;
506
+ margin-bottom: 0.5rem;
507
+ }
508
+
509
+ .matrx-flashcard-input {
510
+ display: none;
511
+ }
512
+
513
+ .matrx-flashcard-inner {
514
+ position: absolute;
515
+ top: 0;
516
+ left: 0;
517
+ width: 100%;
518
+ height: 100%;
519
+ transition: transform 0.6s;
520
+ transform-style: preserve-3d;
521
+ transform-origin: center center;
522
+ }
523
+
524
+ .matrx-flashcard-input:checked ~ .matrx-flashcard-inner {
525
+ transform: rotateY(180deg);
526
+ }
527
+
528
+ .matrx-flashcard-front,
529
+ .matrx-flashcard-back {
530
+ position: absolute;
531
+ top: 0;
532
+ left: 0;
533
+ width: 100%;
534
+ height: 100%;
535
+ backface-visibility: hidden;
536
+ border-radius: 12px;
537
+ display: flex;
538
+ align-items: center;
539
+ justify-content: center;
540
+ padding: 1.5rem;
541
+ box-shadow: 0 4px 6px var(--matrx-print-shadow, rgba(0, 0, 0, 0.1));
542
+ transition: box-shadow 0.3s ease;
543
+ box-sizing: border-box;
544
+ }
545
+
546
+ .matrx-flashcard-front {
547
+ background: linear-gradient(135deg, var(--matrx-print-accent, #667eea) 0%, var(--matrx-print-accent-2, #764ba2) 100%);
548
+ color: white;
549
+ }
550
+
551
+ .matrx-flashcard-back {
552
+ background: linear-gradient(135deg, var(--matrx-print-success, #2d5016) 0%, var(--matrx-print-success-2, #1e3a0f) 100%);
553
+ color: white;
554
+ transform: rotateY(180deg);
555
+ }
556
+
557
+ .matrx-flashcard:hover .matrx-flashcard-front,
558
+ .matrx-flashcard:hover .matrx-flashcard-back {
559
+ box-shadow: 0 8px 16px var(--matrx-print-shadow-strong, rgba(0, 0, 0, 0.2));
560
+ }
561
+
562
+ .matrx-flashcard-content {
563
+ text-align: center;
564
+ font-size: 1.3rem;
565
+ line-height: 1.8;
566
+ max-height: 100%;
567
+ width: 100%;
568
+ overflow: hidden;
569
+ }
570
+
571
+ .matrx-flashcard-label {
572
+ cursor: pointer;
573
+ user-select: none;
574
+ position: absolute;
575
+ top: 0;
576
+ left: 0;
577
+ width: 100%;
578
+ height: 100%;
579
+ z-index: 10;
580
+ }
581
+
582
+ .matrx-flashcard-indicator {
583
+ position: absolute;
584
+ bottom: 12px;
585
+ right: 16px;
586
+ font-size: 0.75rem;
587
+ opacity: 0.8;
588
+ font-weight: 500;
589
+ letter-spacing: 0.5px;
590
+ }
591
+
592
+ /* Responsive adjustments */
593
+ @media (max-width: 768px) {
594
+ .matrx-flashcard {
595
+ height: 180px;
596
+ }
597
+
598
+ .matrx-flashcard-content {
599
+ font-size: 1rem;
600
+ }
601
+
602
+ .matrx-flashcard-front,
603
+ .matrx-flashcard-back {
604
+ padding: 1.25rem;
605
+ }
606
+ }
607
+
608
+ @media (max-width: 480px) {
609
+ .matrx-flashcard {
610
+ height: 160px;
611
+ }
612
+
613
+ .matrx-flashcard-content {
614
+ font-size: 0.95rem;
615
+ }
616
+
617
+ .matrx-flashcard-front,
618
+ .matrx-flashcard-back {
619
+ padding: 1rem;
620
+ }
621
+ }
622
+
623
+ /* Responsive Design */
624
+ @media (max-width: 768px) {
625
+ .matrx-content-container {
626
+ padding: 1rem;
627
+ }
628
+
629
+ .matrx-h1 {
630
+ font-size: 2rem;
631
+ }
632
+
633
+ .matrx-h2 {
634
+ font-size: 1.5rem;
635
+ margin: 2rem 0 1rem 0 !important;
636
+ }
637
+
638
+ .matrx-h3 {
639
+ font-size: 1.2rem;
640
+ }
641
+
642
+ .matrx-h4 {
643
+ font-size: 1.05rem;
644
+ }
645
+
646
+ .matrx-h5 {
647
+ font-size: 0.95rem;
648
+ }
649
+
650
+ .matrx-h6 {
651
+ font-size: 0.9rem;
652
+ }
653
+
654
+ .matrx-intro {
655
+ padding: 1rem;
656
+ font-size: 1rem;
657
+ }
658
+
659
+ .matrx-faq-question {
660
+ font-size: 1.1rem;
661
+ margin: 1.5rem 0 0.75rem 0;
662
+ }
663
+
664
+ .matrx-paragraph {
665
+ text-align: left;
666
+ }
667
+
668
+ .matrx-table {
669
+ font-size: 0.875rem;
670
+ }
671
+
672
+ .matrx-table-header,
673
+ .matrx-table-cell {
674
+ padding: 0.5rem;
675
+ }
676
+
677
+ .matrx-code-block {
678
+ padding: 0.75rem;
679
+ margin: 1rem 0;
680
+ }
681
+ }
682
+
683
+ @media (max-width: 480px) {
684
+ .matrx-content-container {
685
+ padding: 0.75rem;
686
+ }
687
+
688
+ .matrx-h1 {
689
+ font-size: 1.75rem;
690
+ margin-bottom: 1rem;
691
+ }
692
+
693
+ .matrx-h2 {
694
+ font-size: 1.3rem;
695
+ margin: 1.5rem 0 0.75rem 0 !important;
696
+ }
697
+
698
+ .matrx-h3 {
699
+ font-size: 1.1rem;
700
+ margin: 1.5rem 0 0.75rem 0;
701
+ }
702
+
703
+ .matrx-h4 {
704
+ font-size: 1rem;
705
+ margin: 1.25rem 0 0.5rem 0;
706
+ }
707
+
708
+ .matrx-h5 {
709
+ font-size: 0.9rem;
710
+ margin: 1rem 0 0.5rem 0;
711
+ }
712
+
713
+ .matrx-h6 {
714
+ font-size: 0.85rem;
715
+ margin: 1rem 0 0.5rem 0;
716
+ }
717
+
718
+ .matrx-intro {
719
+ padding: 0.75rem;
720
+ margin-bottom: 1.5rem;
721
+ }
722
+
723
+ .matrx-paragraph {
724
+ margin-bottom: 1.25rem;
725
+ }
726
+
727
+ .matrx-list-item {
728
+ margin-bottom: 0.75rem;
729
+ }
730
+
731
+ .matrx-table-header,
732
+ .matrx-table-cell {
733
+ padding: 0.375rem;
734
+ }
735
+
736
+ .matrx-code-block {
737
+ padding: 0.5rem;
738
+ font-size: 0.8rem;
739
+ }
740
+
741
+ .matrx-inline-code {
742
+ font-size: 0.8rem;
743
+ }
744
+ }
745
+ /* Print / PDF hard parts \u2014 added by @ai-matrx/print 0.3.0. */
746
+ @media print {
747
+ .matrx-content-container {
748
+ max-width: 100%;
749
+ padding: 0;
750
+ }
751
+
752
+ .matrx-h1,
753
+ .matrx-h2,
754
+ .matrx-h3,
755
+ .matrx-h4,
756
+ .matrx-h5,
757
+ .matrx-h6 {
758
+ page-break-after: avoid;
759
+ break-after: avoid;
760
+ }
761
+
762
+ .matrx-paragraph,
763
+ .matrx-intro {
764
+ orphans: 3;
765
+ widows: 3;
766
+ }
767
+
768
+ .matrx-table,
769
+ .matrx-code-block,
770
+ .matrx-blockquote,
771
+ .matrx-list-item,
772
+ .matrx-image,
773
+ .matrx-faq-item,
774
+ .matrx-flashcard {
775
+ page-break-inside: avoid;
776
+ break-inside: avoid;
777
+ }
778
+
779
+ .matrx-table-header,
780
+ .matrx-code-block,
781
+ .matrx-blockquote,
782
+ .matrx-flashcard {
783
+ -webkit-print-color-adjust: exact;
784
+ print-color-adjust: exact;
785
+ }
786
+
787
+ .matrx-link {
788
+ text-decoration: underline;
789
+ }
790
+ }
791
+ `;
792
+ var MARKDOWN_ARTICLE_CSS = `*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}body{font-family:Georgia,'Times New Roman',serif;font-size:11pt;line-height:1.7;color:var(--matrx-print-fg, #1a1a1a);background:var(--matrx-print-bg, #fff);max-width:780px;margin:0 auto;padding:32px 40px}.print-actions{display:flex;gap:10px;margin-bottom:28px;padding-bottom:20px;border-bottom:2px solid var(--matrx-print-border, #e5e7eb)}.print-btn{display:inline-flex;align-items:center;gap:6px;padding:8px 20px;border-radius:8px;font-size:13px;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;cursor:pointer;border:none;font-weight:600;transition:opacity .15s}.print-btn:hover{opacity:.85}.print-btn-primary{background:var(--matrx-print-accent, #2563eb);color:var(--matrx-print-bg, #fff)}.print-btn-secondary{background:var(--matrx-print-surface-sunken, #f3f4f6);color:var(--matrx-print-fg-muted, #374151);border:1px solid var(--matrx-print-border-muted, #d1d5db)}h1,h2,h3,h4,h5,h6{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','Helvetica Neue',sans-serif;font-weight:700;line-height:1.3;color:var(--matrx-print-heading, #111827);margin-top:1.6em;margin-bottom:.5em;page-break-after:avoid}h1{font-size:24pt;border-bottom:2px solid var(--matrx-print-border, #e5e7eb);padding-bottom:.3em;margin-top:0}h2{font-size:18pt;border-bottom:1px solid var(--matrx-print-border, #e5e7eb);padding-bottom:.2em}h3{font-size:14pt}p{margin-bottom:.9em;orphans:3;widows:3}a{color:var(--matrx-print-accent, #2563eb);text-decoration:underline;word-break:break-word}ul,ol{margin:.6em 0 .9em 0;padding-left:1.8em}li{margin-bottom:.3em;page-break-inside:avoid}blockquote{margin:1em 0;padding:.7em 1em .7em 1.2em;border-left:4px solid var(--matrx-print-quote-border, #6366f1);background:var(--matrx-print-quote-bg, #f5f3ff);border-radius:0 6px 6px 0;color:var(--matrx-print-fg-muted, #374151);font-style:italic;page-break-inside:avoid}.inline-code{font-family:'JetBrains Mono','Fira Code',monospace;font-size:9.5pt;background:var(--matrx-print-code-bg, #f1f5f9);color:var(--matrx-print-ink, #0f172a);padding:1px 5px;border-radius:4px;border:1px solid var(--matrx-print-line, #e2e8f0)}.code-block-wrapper{position:relative;margin:1em 0 1.2em;border-radius:8px;overflow:hidden;border:1px solid var(--matrx-print-line, #e2e8f0);page-break-inside:avoid}.code-lang{display:block;font-family:-apple-system,sans-serif;font-size:9pt;font-weight:600;color:var(--matrx-print-fg-subtle, #64748b);background:var(--matrx-print-surface, #f8fafc);padding:4px 12px;border-bottom:1px solid var(--matrx-print-line, #e2e8f0);text-transform:uppercase;letter-spacing:.05em}.code-block{margin:0;padding:14px 16px;background:var(--matrx-print-ink, #0f172a);color:var(--matrx-print-line, #e2e8f0);font-family:'JetBrains Mono',monospace;font-size:9pt;line-height:1.6;overflow-x:auto;white-space:pre;tab-size:2}.print-table{width:100%;border-collapse:collapse;margin:1em 0 1.2em;font-size:10pt;page-break-inside:avoid}.print-table th{background:var(--matrx-print-table-head-bg, #1e293b);color:var(--matrx-print-surface, #f8fafc);font-family:-apple-system,sans-serif;font-weight:600;font-size:9.5pt;text-align:left;padding:8px 12px;border:1px solid var(--matrx-print-table-head-border, #334155)}.print-table td{padding:7px 12px;border:1px solid var(--matrx-print-line, #e2e8f0);vertical-align:top}.print-table tr:nth-child(even) td{background:var(--matrx-print-surface, #f8fafc)}hr{border:none;border-top:2px solid var(--matrx-print-border, #e5e7eb);margin:1.5em 0}@media print{body{max-width:100%;padding:0;font-size:10.5pt}.print-actions{display:none!important}.code-block,.print-table th,blockquote{color-adjust:exact;-webkit-print-color-adjust:exact;print-color-adjust:exact}a[href]::after{content:" ("attr(href)")";font-size:9pt;color:var(--matrx-print-fg-subtle, #64748b)}a[href^="#"]::after,a[href^="javascript:"]::after{content:""}h1,h2,h3{page-break-after:avoid}pre,blockquote,table{page-break-inside:avoid}}`;
793
+
794
+ // src/markdown.ts
795
+ function removeThinkingContent(content) {
796
+ if (!content) return "";
797
+ let result = content.replace(/\n*<thinking>[\s\S]*?<\/thinking>\n*/gi, "\n").replace(/\n*<think>[\s\S]*?<\/think>\n*/gi, "\n").replace(/\n*<reasoning>[\s\S]*?<\/reasoning>\n*/gi, "\n");
798
+ result = result.replace(/\n{3,}/g, "\n\n");
799
+ return result.trim();
800
+ }
801
+ function hasThinkingContent(content) {
802
+ if (!content) return false;
803
+ return /<thinking>|<think>|<reasoning>/i.test(content);
804
+ }
805
+ function convertMarkdownTables(html) {
806
+ const tableRegex = /^(\|.*\|)\s*\n(\|[-\s:|]*\|)\s*\n((?:\|.*\|\s*\n?)*)/gm;
807
+ return html.replace(
808
+ tableRegex,
809
+ (_match, headerRow, _separatorRow, bodyRows) => {
810
+ const headers = headerRow.split("|").map((cell) => cell.trim()).filter((cell) => cell !== "");
811
+ const rows = bodyRows.trim().split("\n").filter((row) => row.trim()).map(
812
+ (row) => row.split("|").map((cell) => cell.trim()).filter((cell) => cell !== "")
813
+ );
814
+ let tableHtml = '<table class="matrx-table">\n';
815
+ if (headers.length > 0) {
816
+ tableHtml += '<thead class="matrx-table-head">\n<tr class="matrx-table-row">\n';
817
+ for (const header of headers) {
818
+ tableHtml += `<th class="matrx-table-header">${header}</th>
819
+ `;
820
+ }
821
+ tableHtml += "</tr>\n</thead>\n";
822
+ }
823
+ if (rows.length > 0) {
824
+ tableHtml += '<tbody class="matrx-table-body">\n';
825
+ for (const row of rows) {
826
+ if (row.length === 0) continue;
827
+ tableHtml += '<tr class="matrx-table-row">\n';
828
+ for (const cell of row) {
829
+ tableHtml += `<td class="matrx-table-cell">${cell}</td>
830
+ `;
831
+ }
832
+ tableHtml += "</tr>\n";
833
+ }
834
+ tableHtml += "</tbody>\n";
835
+ }
836
+ return `${tableHtml}</table>
837
+ `;
838
+ }
839
+ );
840
+ }
841
+ function markdownToHtml(markdown, options = {}) {
842
+ const notice = options.onNotice;
843
+ if (!markdown) {
844
+ notice?.({
845
+ code: "empty-output",
846
+ message: "markdownToHtml received an empty string.",
847
+ remedy: "Check the content is loaded before converting; nothing was rendered."
848
+ });
849
+ return "";
850
+ }
851
+ const startWrapper = '<div class="matrx-content-container">';
852
+ const endWrapper = "</div>";
853
+ let html = options.includeThinking ? markdown : removeThinkingContent(markdown);
854
+ const flashcardPlaceholders = [];
855
+ let flashcardIndex = 0;
856
+ let globalCardIndex = 0;
857
+ html = html.replace(
858
+ /<flashcards>([\s\S]*?)<\/flashcards>/gi,
859
+ (_match, content) => {
860
+ const cards = content.split(/\n*---\n*/g).map((card) => card.trim()).filter((card) => card.length > 0);
861
+ if (cards.length === 0) return "";
862
+ let flashcardsHtml = '<div class="matrx-flashcards-container">\n';
863
+ for (const card of cards) {
864
+ const frontMatch = card.match(/Front:\s*(.+?)(?=\n|$)/i);
865
+ const backMatch = card.match(/Back:\s*([\s\S]+?)$/i);
866
+ const front = frontMatch?.[1]?.trim();
867
+ const back = backMatch?.[1]?.trim();
868
+ if (!front || !back) {
869
+ notice?.({
870
+ code: "flashcard-malformed",
871
+ message: `A flashcard was skipped: it is missing a ${front ? "Back:" : "Front:"} line.`,
872
+ remedy: 'Every card inside <flashcards> needs both "Front: \u2026" and "Back: \u2026", separated from the next card by ---.'
873
+ });
874
+ continue;
875
+ }
876
+ globalCardIndex++;
877
+ const cardId = `card${globalCardIndex}`;
878
+ flashcardsHtml += ` <div class="matrx-flashcard">
879
+ <input type="checkbox" class="matrx-flashcard-input" id="${cardId}">
880
+ <label for="${cardId}" class="matrx-flashcard-label"></label>
881
+ <div class="matrx-flashcard-inner">
882
+ <div class="matrx-flashcard-front">
883
+ <div class="matrx-flashcard-content">
884
+ <strong>${front}</strong>
885
+ </div>
886
+ <span class="matrx-flashcard-indicator">CLICK TO FLIP</span>
887
+ </div>
888
+ <div class="matrx-flashcard-back">
889
+ <div class="matrx-flashcard-content">
890
+ ${back}
891
+ </div>
892
+ <span class="matrx-flashcard-indicator">CLICK TO FLIP</span>
893
+ </div>
894
+ </div>
895
+ </div>
896
+
897
+ `;
898
+ }
899
+ flashcardsHtml += "</div>\n";
900
+ const placeholder = `\u03A9FLASHCARD\u03A9${flashcardIndex}\u03A9FLASHCARD\u03A9`;
901
+ flashcardPlaceholders.push({ placeholder, html: flashcardsHtml });
902
+ flashcardIndex++;
903
+ return placeholder;
904
+ }
905
+ );
906
+ html = html.replace(/^[-]{3,}$/gm, '<hr class="matrx-hr">');
907
+ html = html.replace(/^[*]{3,}$/gm, '<hr class="matrx-hr">');
908
+ const imagePlaceholders = [];
909
+ let imageIndex = 0;
910
+ html = html.replace(
911
+ /!\[([^\]]*)\]\(([^)]+)\)/g,
912
+ (_match, altText, url) => {
913
+ const placeholder = `\u03A9IMAGE\u03A9${imageIndex}\u03A9IMAGE\u03A9`;
914
+ imagePlaceholders.push({
915
+ placeholder,
916
+ html: `<img class="matrx-image" src="${url}" alt="${altText}" />`
917
+ });
918
+ imageIndex++;
919
+ return placeholder;
920
+ }
921
+ );
922
+ const linkPlaceholders = [];
923
+ let linkIndex = 0;
924
+ html = html.replace(
925
+ /\[([^\]]+)\]\(([^)]+)\)/g,
926
+ (_match, linkText, url) => {
927
+ const placeholder = `\u03A9LINK\u03A9${linkIndex}\u03A9LINK\u03A9`;
928
+ linkPlaceholders.push({
929
+ placeholder,
930
+ html: `<a class="matrx-link" href="${url}">${linkText}</a>`
931
+ });
932
+ linkIndex++;
933
+ return placeholder;
934
+ }
935
+ );
936
+ html = html.replace(/^# (.+)$/gm, '<h1 class="matrx-h1">$1</h1>').replace(/^## (.+)$/gm, '<h2 class="matrx-h2">$1</h2>').replace(/^### (.+)$/gm, '<h3 class="matrx-h3">$1</h3>').replace(/^#### (.+)$/gm, '<h4 class="matrx-h4">$1</h4>').replace(/^##### (.+)$/gm, '<h5 class="matrx-h5">$1</h5>').replace(/^###### (.+)$/gm, '<h6 class="matrx-h6">$1</h6>');
937
+ html = html.replace(/\*\*(.+?)\*\*/g, '<strong class="matrx-strong">$1</strong>').replace(/\*(.+?)\*/g, '<em class="matrx-em">$1</em>').replace(/__(.+?)__/g, '<strong class="matrx-strong">$1</strong>').replace(/_(.+?)_/g, '<em class="matrx-em">$1</em>');
938
+ const lines = html.split("\n");
939
+ let processedHtml = "";
940
+ const listStack = [];
941
+ let lastListItem = "";
942
+ const top = () => listStack[listStack.length - 1];
943
+ const closeDeeperThan = (indent) => {
944
+ while (listStack.length > 0 && top().indent > indent) {
945
+ if (lastListItem) {
946
+ processedHtml += "</li>\n";
947
+ lastListItem = "";
948
+ }
949
+ const closing = listStack.pop();
950
+ if (!closing) break;
951
+ processedHtml += closing.type === "ol" ? "</ol>\n" : "</ul>\n";
952
+ if (listStack.length > 0) processedHtml += "</li>\n";
953
+ }
954
+ };
955
+ for (const line of lines) {
956
+ const numberedMatch = line.match(/^(\s*)(\d+)\.\s+(.+)$/);
957
+ if (numberedMatch) {
958
+ const indent = (numberedMatch[1] ?? "").length;
959
+ const content = numberedMatch[3] ?? "";
960
+ const current = top();
961
+ if (current && indent > current.indent) {
962
+ processedHtml += '\n<ol class="matrx-list matrx-numbered-list matrx-nested-list">\n';
963
+ listStack.push({ type: "ol", indent });
964
+ processedHtml += `<li class="matrx-list-item">${content}`;
965
+ lastListItem = "ol";
966
+ } else {
967
+ closeDeeperThan(indent);
968
+ if (lastListItem && top()?.indent === indent) processedHtml += "</li>\n";
969
+ const now = top();
970
+ if (!now || now.indent !== indent || now.type !== "ol") {
971
+ processedHtml += '<ol class="matrx-list matrx-numbered-list">\n';
972
+ listStack.push({ type: "ol", indent });
973
+ }
974
+ processedHtml += `<li class="matrx-list-item">${content}`;
975
+ lastListItem = "ol";
976
+ }
977
+ continue;
978
+ }
979
+ const bulletMatch = line.match(/^(\s*)[*\-+]\s+(.+)$/);
980
+ if (bulletMatch) {
981
+ const indent = (bulletMatch[1] ?? "").length;
982
+ const content = bulletMatch[2] ?? "";
983
+ const current = top();
984
+ if (current && indent > current.indent) {
985
+ processedHtml += '\n<ul class="matrx-list matrx-bullet-list matrx-nested-list">\n';
986
+ listStack.push({ type: "ul", indent });
987
+ processedHtml += `<li class="matrx-list-item">${content}`;
988
+ lastListItem = "ul";
989
+ } else {
990
+ closeDeeperThan(indent);
991
+ if (lastListItem && top()?.indent === indent) processedHtml += "</li>\n";
992
+ const now = top();
993
+ if (!now || now.indent !== indent || now.type !== "ul") {
994
+ processedHtml += '<ul class="matrx-list matrx-bullet-list">\n';
995
+ listStack.push({ type: "ul", indent });
996
+ }
997
+ processedHtml += `<li class="matrx-list-item">${content}`;
998
+ lastListItem = "ul";
999
+ }
1000
+ continue;
1001
+ }
1002
+ if (line.trim() !== "") {
1003
+ while (listStack.length > 0) {
1004
+ if (lastListItem) {
1005
+ processedHtml += "</li>\n";
1006
+ lastListItem = "";
1007
+ }
1008
+ const closing = listStack.pop();
1009
+ if (!closing) break;
1010
+ processedHtml += closing.type === "ol" ? "</ol>\n" : "</ul>\n";
1011
+ if (listStack.length > 0) processedHtml += "</li>\n";
1012
+ }
1013
+ }
1014
+ processedHtml += `${line}
1015
+ `;
1016
+ }
1017
+ while (listStack.length > 0) {
1018
+ if (lastListItem) {
1019
+ processedHtml += "</li>\n";
1020
+ lastListItem = "";
1021
+ }
1022
+ const closing = listStack.pop();
1023
+ if (!closing) break;
1024
+ processedHtml += closing.type === "ol" ? "</ol>\n" : "</ul>\n";
1025
+ if (listStack.length > 0) processedHtml += "</li>\n";
1026
+ }
1027
+ html = processedHtml;
1028
+ html = html.replace(/^> (.+)$/gm, '<blockquote class="matrx-blockquote">$1</blockquote>');
1029
+ html = html.replace(
1030
+ /```([^`]+)```/gs,
1031
+ '<pre class="matrx-code-block"><code class="matrx-code">$1</code></pre>'
1032
+ );
1033
+ html = html.replace(/`([^`]+)`/g, '<code class="matrx-inline-code">$1</code>');
1034
+ html = convertMarkdownTables(html);
1035
+ html = html.replace(/<table>/g, '<table class="matrx-table">').replace(/<thead>/g, '<thead class="matrx-table-head">').replace(/<tbody>/g, '<tbody class="matrx-table-body">').replace(/<tr>/g, '<tr class="matrx-table-row">').replace(/<th>/g, '<th class="matrx-table-header">').replace(/<td>/g, '<td class="matrx-table-cell">');
1036
+ html = html.replace(/<img([^>]*)>/g, '<img class="matrx-image"$1>');
1037
+ html = html.replace(/<div(?!\s+class="matrx-)([^>]*)>/g, '<div class="matrx-div"$1>');
1038
+ html = html.replace(/<span([^>]*)>/g, '<span class="matrx-span"$1>');
1039
+ html = html.replace(/^([^<\n].+)$/gm, '<p class="matrx-paragraph">$1</p>');
1040
+ html = html.replace(
1041
+ /<\/p>\s*<p class="matrx-paragraph">/g,
1042
+ '</p><p class="matrx-paragraph">'
1043
+ );
1044
+ html = html.replace(
1045
+ /(<h1 class="matrx-h1">[\s\S]*?<\/h1>\s*)<p class="matrx-paragraph">([\s\S]*?)<\/p>/g,
1046
+ '$1<p class="matrx-intro">$2</p>'
1047
+ );
1048
+ html = html.replace(
1049
+ /^<strong class="matrx-strong">([^<]*\?[^<]*)<\/strong>$/gm,
1050
+ '<h3 class="matrx-h3">$1</h3>'
1051
+ );
1052
+ html = html.replace(
1053
+ /<p class="matrx-paragraph"><strong class="matrx-strong">([^<]*\?[^<]*)<\/strong><\/p>/g,
1054
+ '<h3 class="matrx-h3">$1</h3>'
1055
+ );
1056
+ html = html.replace(
1057
+ /<h3 class="matrx-h3">([^<]*\?[^<]*)<\/h3>/g,
1058
+ '<div class="matrx-faq-question">$1</div>'
1059
+ );
1060
+ html = html.replace(
1061
+ /(<div class="matrx-faq-question">[^<]*<\/div>)\s*(<p class="matrx-paragraph">[\s\S]*?<\/p>)/g,
1062
+ '<div class="matrx-faq-item">$1<div class="matrx-faq-answer">$2</div></div>'
1063
+ );
1064
+ html = html.replace(
1065
+ /(<div class="matrx-faq-question">[^<]*<\/div>)(?!\s*<div class="matrx-faq-answer">)/g,
1066
+ '<div class="matrx-faq-item">$1<div class="matrx-faq-answer"></div></div>'
1067
+ );
1068
+ html = html.replace(
1069
+ /(<div class="matrx-faq-answer">)<p class="matrx-paragraph">([\s\S]*?)<\/p>(<\/div>)/g,
1070
+ "$1$2$3"
1071
+ );
1072
+ for (const { placeholder, html: imageHtml } of imagePlaceholders) {
1073
+ if (html.includes(placeholder)) html = html.replaceAll(placeholder, imageHtml);
1074
+ }
1075
+ html = html.replace(/<p class="matrx-paragraph">\s*(<img[^>]*>)\s*<\/p>/g, "$1");
1076
+ for (const { placeholder, html: linkHtml } of linkPlaceholders) {
1077
+ if (html.includes(placeholder)) html = html.replaceAll(placeholder, linkHtml);
1078
+ }
1079
+ for (const { placeholder, html: cardHtml } of flashcardPlaceholders) {
1080
+ if (html.includes(placeholder)) html = html.replaceAll(placeholder, cardHtml);
1081
+ }
1082
+ return startWrapper + html + endWrapper;
1083
+ }
1084
+ function convertArticleTables(html) {
1085
+ const tableRegex = /^(\|.*\|)\s*\n(\|[-\s:|]*\|)\s*\n((?:\|.*\|\s*\n?)*)/gm;
1086
+ return html.replace(
1087
+ tableRegex,
1088
+ (_match, headerRow, _sep, bodyRows) => {
1089
+ const headers = headerRow.split("|").map((c) => c.trim()).filter((c) => c !== "");
1090
+ const rows = bodyRows.trim().split("\n").filter((r) => r.trim()).map(
1091
+ (r) => r.split("|").map((c) => c.trim()).filter((c) => c !== "")
1092
+ );
1093
+ let t = '<table class="print-table">\n';
1094
+ if (headers.length) {
1095
+ t += `<thead><tr>${headers.map((h) => `<th>${h}</th>`).join("")}</tr></thead>
1096
+ `;
1097
+ }
1098
+ if (rows.length) {
1099
+ t += `<tbody>${rows.map(
1100
+ (r) => r.length ? `<tr>${r.map((c) => `<td>${c}</td>`).join("")}</tr>` : ""
1101
+ ).join("\n")}</tbody>
1102
+ `;
1103
+ }
1104
+ return `${t}</table>
1105
+ `;
1106
+ }
1107
+ );
1108
+ }
1109
+ function markdownToArticleHtml(markdown, options = {}) {
1110
+ if (!markdown) {
1111
+ options.onNotice?.({
1112
+ code: "empty-output",
1113
+ message: "markdownToArticleHtml received an empty string.",
1114
+ remedy: "Check the content is loaded before printing; nothing was rendered."
1115
+ });
1116
+ return "";
1117
+ }
1118
+ let html = options.includeThinking ? markdown : removeThinkingContent(markdown);
1119
+ html = convertArticleTables(html);
1120
+ const codeBlockPlaceholders = [];
1121
+ let codeIdx = 0;
1122
+ html = html.replace(
1123
+ /```(\w*)\n?([\s\S]*?)```/g,
1124
+ (_m, lang, code) => {
1125
+ const ph = `\u03A9CODEBLOCK\u03A9${codeIdx}\u03A9CODEBLOCK\u03A9`;
1126
+ const langLabel = lang ? `<span class="code-lang">${lang}</span>` : "";
1127
+ codeBlockPlaceholders.push({
1128
+ placeholder: ph,
1129
+ html: `<div class="code-block-wrapper">${langLabel}<pre class="code-block"><code>${escapeHtml(
1130
+ code.trim()
1131
+ )}</code></pre></div>`
1132
+ });
1133
+ codeIdx++;
1134
+ return ph;
1135
+ }
1136
+ );
1137
+ const linkPlaceholders = [];
1138
+ let linkIdx = 0;
1139
+ html = html.replace(
1140
+ /\[([^\]]+)\]\(([^)]+)\)/g,
1141
+ (_m, text, url) => {
1142
+ const ph = `\u03A9LINK\u03A9${linkIdx}\u03A9LINK\u03A9`;
1143
+ linkPlaceholders.push({ placeholder: ph, html: `<a href="${url}">${text}</a>` });
1144
+ linkIdx++;
1145
+ return ph;
1146
+ }
1147
+ );
1148
+ html = html.replace(/^#{6}\s+(.+)$/gm, "<h6>$1</h6>").replace(/^#{5}\s+(.+)$/gm, "<h5>$1</h5>").replace(/^#{4}\s+(.+)$/gm, "<h4>$1</h4>").replace(/^#{3}\s+(.+)$/gm, "<h3>$1</h3>").replace(/^#{2}\s+(.+)$/gm, "<h2>$1</h2>").replace(/^#{1}\s+(.+)$/gm, "<h1>$1</h1>");
1149
+ html = html.replace(/^> (.+)$/gm, "<blockquote>$1</blockquote>");
1150
+ html = html.replace(/^[-*_]{3,}$/gm, "<hr>");
1151
+ html = html.replace(/\*\*\*(.+?)\*\*\*/g, "<strong><em>$1</em></strong>").replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>").replace(/\*(.+?)\*/g, "<em>$1</em>").replace(/___(.+?)___/g, "<strong><em>$1</em></strong>").replace(/__(.+?)__/g, "<strong>$1</strong>").replace(/_([^_\s][^_]*)_/g, "<em>$1</em>");
1152
+ html = html.replace(/`([^`]+)`/g, '<code class="inline-code">$1</code>');
1153
+ const lines = html.split("\n");
1154
+ const result = [];
1155
+ let inUl = false;
1156
+ let inOl = false;
1157
+ for (const line of lines) {
1158
+ const ulMatch = line.match(/^(\s*)[-*+]\s+(.+)$/);
1159
+ const olMatch = line.match(/^(\s*)\d+\.\s+(.+)$/);
1160
+ if (ulMatch) {
1161
+ if (inOl) {
1162
+ result.push("</ol>");
1163
+ inOl = false;
1164
+ }
1165
+ if (!inUl) {
1166
+ result.push("<ul>");
1167
+ inUl = true;
1168
+ }
1169
+ result.push(`<li>${ulMatch[2] ?? ""}</li>`);
1170
+ } else if (olMatch) {
1171
+ if (inUl) {
1172
+ result.push("</ul>");
1173
+ inUl = false;
1174
+ }
1175
+ if (!inOl) {
1176
+ result.push("<ol>");
1177
+ inOl = true;
1178
+ }
1179
+ result.push(`<li>${olMatch[2] ?? ""}</li>`);
1180
+ } else {
1181
+ if (inUl) {
1182
+ result.push("</ul>");
1183
+ inUl = false;
1184
+ }
1185
+ if (inOl) {
1186
+ result.push("</ol>");
1187
+ inOl = false;
1188
+ }
1189
+ result.push(line);
1190
+ }
1191
+ }
1192
+ if (inUl) result.push("</ul>");
1193
+ if (inOl) result.push("</ol>");
1194
+ html = result.join("\n");
1195
+ html = html.split("\n").map((line) => {
1196
+ const t = line.trim();
1197
+ if (!t) return "";
1198
+ if (/^<(h[1-6]|ul|ol|li|blockquote|pre|hr|table|thead|tbody|tr|th|td|div|ΩCODE)/.test(t)) {
1199
+ return line;
1200
+ }
1201
+ return `<p>${t}</p>`;
1202
+ }).join("\n");
1203
+ for (const { placeholder, html: ph } of codeBlockPlaceholders) {
1204
+ html = html.replace(`<p>${placeholder}</p>`, ph);
1205
+ html = html.replace(placeholder, ph);
1206
+ }
1207
+ for (const { placeholder, html: ph } of linkPlaceholders) {
1208
+ html = html.replaceAll(placeholder, ph);
1209
+ }
1210
+ return html;
1211
+ }
1212
+ var PRINT_ACTIONS_CSS = `
1213
+ .print-actions { display: flex; gap: 10px; margin: 0 auto 28px; max-width: 800px; padding: 0 2rem 20px; border-bottom: 2px solid var(--matrx-print-border, #e1e1e1); }
1214
+ .print-btn { display: inline-flex; align-items: center; gap: 6px; padding: 8px 20px; border-radius: 8px; font-size: 13px; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; cursor: pointer; border: none; font-weight: 600; }
1215
+ .print-btn-primary { background: var(--matrx-print-accent, #667eea); color: var(--matrx-print-bg, #ffffff); }
1216
+ .print-btn-secondary { background: var(--matrx-print-surface, #f8f9fa); color: var(--matrx-print-fg-strong, #374151); border: 1px solid var(--matrx-print-border-muted, #d1d5db); }
1217
+ @media print { .print-actions { display: none !important; } }
1218
+ `;
1219
+ function getMarkdownStylesheet(options = {}) {
1220
+ const skin = options.skin ?? "document";
1221
+ const base = skin === "article" ? `${MARKDOWN_ARTICLE_TOKENS_CSS}
1222
+ ${MARKDOWN_ARTICLE_CSS}` : `${MARKDOWN_DOCUMENT_TOKENS_CSS}
1223
+ ${MARKDOWN_DOCUMENT_CSS}`;
1224
+ return [base, options.tokens ?? "", options.extraCss ?? ""].filter((part) => part.trim().length > 0).join("\n");
1225
+ }
1226
+ function markdownToHtmlForSkin(markdown, skin, options = {}) {
1227
+ return skin === "article" ? markdownToArticleHtml(markdown, options) : markdownToHtml(markdown, options);
1228
+ }
1229
+ function renderMarkdownDocument(markdown, options = {}) {
1230
+ const skin = options.skin ?? "document";
1231
+ const title = options.title ?? "AI Response";
1232
+ const convert = options.convertToHtml ?? ((md) => markdownToHtmlForSkin(
1233
+ md,
1234
+ skin,
1235
+ options.onNotice ? { onNotice: options.onNotice } : {}
1236
+ ));
1237
+ const bodyHtml = convert(markdown);
1238
+ const css = options.css ?? getMarkdownStylesheet({
1239
+ skin,
1240
+ ...options.tokens === void 0 ? {} : { tokens: options.tokens },
1241
+ ...options.extraCss === void 0 ? {} : { extraCss: options.extraCss }
1242
+ });
1243
+ const chrome = options.withPrintActions && skin !== "article" ? PRINT_ACTIONS_CSS : "";
1244
+ const actions = options.withPrintActions ? '<div class="print-actions"><button class="print-btn print-btn-primary" onclick="window.print()">Print / Save as PDF</button><button class="print-btn print-btn-secondary" onclick="window.close()">Close</button></div>' : "";
1245
+ return `<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0"><title>${escapeHtml(
1246
+ title
1247
+ )}</title>
1248
+ <style>${css}${chrome}</style></head>
1249
+ <body>${actions}<div class="content">${bodyHtml}</div></body></html>`;
1250
+ }
1251
+ function printMarkdown(markdown, options = {}) {
1252
+ const title = options.title ?? "AI Response";
1253
+ const doc = renderMarkdownDocument(markdown, {
1254
+ ...options,
1255
+ title,
1256
+ withPrintActions: options.withPrintActions ?? true
1257
+ });
1258
+ return options.windowFeatures === void 0 ? openPrintWindow(doc, title) : openPrintWindow(doc, title, options.windowFeatures);
1259
+ }
1260
+ //# sourceMappingURL=markdown.cjs.map