markstream-angular 0.0.9-beta.2 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.css CHANGED
@@ -25,6 +25,20 @@ markstream-angular {
25
25
  --secondary: 210 40% 96%;
26
26
  --muted: 210 40% 96%;
27
27
  --muted-foreground: 215.4 16.3% 46.9%;
28
+ --ms-font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
29
+ --ms-text-label: 0.75rem;
30
+ --ms-inset-panel-x: 0.625rem;
31
+ --ms-inset-panel-y: 0.375rem;
32
+ --ms-gap-header-main: 0.625rem;
33
+ --ms-gap-header-actions: 0.125rem;
34
+ /* Unified default code surface; explicit editor themes may override it. */
35
+ --code-bg: #fff;
36
+ --code-fg: hsl(0 0% 10%);
37
+ --code-border: hsl(0 0% 87%);
38
+ --code-header-bg: hsl(0 0% 93.5%);
39
+ --code-action-fg: hsl(0 0% 43%);
40
+ --code-action-hover-bg: hsl(0 0% 91%);
41
+ --code-action-hover-fg: hsl(0 0% 10%);
28
42
  color: hsl(var(--foreground));
29
43
  font:
30
44
  400 16px/1.72 "IBM Plex Sans", "Segoe UI", sans-serif;
@@ -48,6 +62,13 @@ markstream-angular {
48
62
  --secondary: 217.2 32.6% 17.5%;
49
63
  --muted: 217.2 32.6% 17.5%;
50
64
  --muted-foreground: 215 20.2% 65.1%;
65
+ --code-bg: #111827;
66
+ --code-fg: hsl(0 0% 93%);
67
+ --code-border: hsl(0 0% 20%);
68
+ --code-header-bg: hsl(0 0% 16%);
69
+ --code-action-fg: hsl(0 0% 60%);
70
+ --code-action-hover-bg: hsl(0 0% 24%);
71
+ --code-action-hover-fg: hsl(0 0% 93%);
51
72
  }
52
73
 
53
74
  .markstream-angular > :first-child {
@@ -279,8 +300,8 @@ markstream-angular {
279
300
  overflow: auto;
280
301
  padding: 1rem 1.1rem;
281
302
  border-radius: 1rem;
282
- background: #0f172a;
283
- color: #e2e8f0;
303
+ background: var(--code-bg);
304
+ color: var(--code-fg);
284
305
  box-shadow: inset 0 0 0 1px rgba(148, 163, 184, 0.14);
285
306
  }
286
307
 
@@ -290,6 +311,85 @@ markstream-angular {
290
311
  color: inherit;
291
312
  }
292
313
 
314
+ /* ── Pre line numbers (aligned with the Vue 3 PreCodeNode) ── */
315
+ .markstream-angular markstream-angular-pre-code-node:not(.code-editor-fallback-surface) > pre[data-markstream-pre='1']:not(.markstream-pre--diff-preview) {
316
+ box-sizing: border-box;
317
+ width: 100%;
318
+ margin: 0;
319
+ padding: 0;
320
+ overflow: auto;
321
+ border: 0;
322
+ border-radius: 0;
323
+ background: var(--code-bg, #fff);
324
+ color: var(--code-fg, hsl(0 0% 10%));
325
+ box-shadow: none;
326
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
327
+ font-size: 16px;
328
+ font-weight: 400;
329
+ line-height: 28px;
330
+ tab-size: var(--markstream-pre-tab-size, 4);
331
+ }
332
+
333
+ .markstream-angular markstream-angular-pre-code-node:not(.code-editor-fallback-surface) > pre[data-markstream-pre='1']:not(.markstream-pre--diff-preview) > code {
334
+ color: inherit;
335
+ background: transparent;
336
+ font: inherit;
337
+ }
338
+
339
+ .markstream-angular pre.markstream-pre--line-numbers {
340
+ position: relative;
341
+ --markstream-pre-line-number-top: var(--markstream-code-padding-y, 0px);
342
+ --markstream-pre-line-number-left: 0px;
343
+ --markstream-pre-line-number-padding-left: 2ch;
344
+ --markstream-pre-line-number-padding-right: 1ch;
345
+ --markstream-pre-line-number-separator-width: 2px;
346
+ --markstream-pre-line-number-gap-to-code: 1ch;
347
+ }
348
+
349
+ .markstream-angular pre.markstream-pre--line-numbers > .markstream-pre__line-numbers {
350
+ position: absolute;
351
+ top: var(--markstream-pre-line-number-top, 0);
352
+ left: var(--markstream-pre-line-number-left, 0);
353
+ box-sizing: content-box;
354
+ display: flex;
355
+ flex-direction: column;
356
+ align-items: flex-end;
357
+ width: var(--markstream-pre-line-number-width, 2ch);
358
+ min-width: var(--markstream-pre-line-number-width, 2ch);
359
+ padding-left: var(--markstream-pre-line-number-padding-left, 2ch);
360
+ padding-right: var(--markstream-pre-line-number-padding-right, 1ch);
361
+ border-right: var(--markstream-pre-line-number-separator-width, 2px) solid transparent;
362
+ color: var(--code-line-number, rgba(148, 163, 184, 0.7));
363
+ font: inherit;
364
+ font-variant-numeric: tabular-nums;
365
+ line-height: inherit;
366
+ pointer-events: none;
367
+ user-select: none;
368
+ }
369
+
370
+ .markstream-angular pre.markstream-pre--line-numbers > .markstream-pre__line-numbers > .markstream-pre__line-numbers-text {
371
+ display: block;
372
+ min-height: 1lh;
373
+ text-align: right;
374
+ white-space: pre;
375
+ }
376
+
377
+ .markstream-angular pre.markstream-pre--line-numbers > .markstream-pre__code {
378
+ display: block;
379
+ box-sizing: border-box;
380
+ min-width: 100%;
381
+ padding-left: var(--markstream-code-padding-left, 52px);
382
+ padding-right: var(--markstream-code-padding-x, 12px);
383
+ color: inherit;
384
+ background: transparent;
385
+ font: inherit;
386
+ }
387
+
388
+ .markstream-angular .code-editor-fallback-surface > pre.markstream-pre--line-numbers > .markstream-pre__code {
389
+ padding-left: 0;
390
+ padding-right: 0;
391
+ }
392
+
293
393
  .markstream-angular blockquote,
294
394
  .markstream-angular .blockquote-node {
295
395
  font-weight: 500;
@@ -1016,22 +1116,24 @@ body > div[id^="dmermaid-"] {
1016
1116
  }
1017
1117
 
1018
1118
  .markstream-angular .code-block-container {
1019
- --markstream-code-fallback-bg: #ffffff;
1020
- --markstream-code-fallback-fg: #111827;
1119
+ --markstream-code-fallback-bg: var(--code-bg);
1120
+ --markstream-code-fallback-fg: var(--code-fg);
1021
1121
  margin: 1rem 0;
1022
1122
  overflow: hidden;
1023
1123
  border: 1px solid rgba(148, 163, 184, 0.24);
1024
1124
  border-radius: 0.75rem;
1025
- background: #ffffff;
1125
+ background: var(--markstream-code-fallback-bg);
1126
+ color: var(--markstream-code-fallback-fg);
1026
1127
  box-shadow: 0 18px 38px -28px rgba(15, 23, 42, 0.45);
1027
1128
  }
1028
1129
 
1029
1130
  .markstream-angular .code-block-container.is-dark,
1030
1131
  .dark .markstream-angular .code-block-container {
1031
1132
  --markstream-code-fallback-bg: #111827;
1032
- --markstream-code-fallback-fg: #e5e7eb;
1133
+ --markstream-code-fallback-fg: hsl(0 0% 93%);
1033
1134
  border-color: rgba(71, 85, 105, 0.55);
1034
- background: #0f172a;
1135
+ background: var(--markstream-code-fallback-bg);
1136
+ color: var(--markstream-code-fallback-fg);
1035
1137
  box-shadow: 0 22px 44px -30px rgba(2, 6, 23, 0.95);
1036
1138
  }
1037
1139
 
@@ -1055,27 +1157,47 @@ body > div[id^="dmermaid-"] {
1055
1157
  display: flex;
1056
1158
  align-items: center;
1057
1159
  justify-content: space-between;
1058
- gap: 0.75rem;
1059
- padding: 0.625rem 1rem;
1060
- border-bottom: 1px solid rgba(148, 163, 184, 0.1);
1160
+ gap: var(--ms-gap-header, 1rem);
1161
+ min-height: 1.75rem;
1162
+ padding: var(--ms-inset-panel-y, 0.375rem) var(--ms-inset-panel-x, 0.625rem);
1163
+ border-bottom: 1px solid var(--code-border, rgba(148, 163, 184, 0.1));
1164
+ font-family: var(--ms-font-sans, ui-sans-serif, system-ui, sans-serif);
1165
+ line-height: 1.75;
1061
1166
  }
1062
1167
 
1063
1168
  .markstream-angular .code-block-header__meta {
1064
1169
  display: flex;
1065
1170
  flex: 1 1 auto;
1066
1171
  align-items: center;
1067
- gap: 0.5rem;
1172
+ gap: var(--ms-gap-header-main, 0.625rem);
1068
1173
  min-width: 0;
1174
+ overflow: hidden;
1175
+ }
1176
+
1177
+ .markstream-angular .code-header-copy {
1178
+ min-width: 0;
1179
+ display: grid;
1180
+ gap: 2px;
1069
1181
  }
1070
1182
 
1071
- .markstream-angular .code-block-header__label {
1183
+ .markstream-angular .code-header-title {
1072
1184
  min-width: 0;
1073
1185
  overflow: hidden;
1074
- color: inherit;
1075
1186
  text-overflow: ellipsis;
1076
1187
  white-space: nowrap;
1077
- font:
1078
- 500 0.95rem/1.2 "IBM Plex Mono", "SFMono-Regular", Consolas, monospace;
1188
+ font-size: var(--ms-text-label, 0.75rem);
1189
+ font-weight: 500;
1190
+ font-family: inherit;
1191
+ color: var(--code-action-fg, hsl(0 0% 43%));
1192
+ }
1193
+
1194
+ .markstream-angular .code-header-caption {
1195
+ min-width: 0;
1196
+ overflow: hidden;
1197
+ text-overflow: ellipsis;
1198
+ white-space: nowrap;
1199
+ font-size: 12px;
1200
+ color: var(--code-line-number, rgba(148, 163, 184, 0.7));
1079
1201
  }
1080
1202
 
1081
1203
  .markstream-angular .code-block-header__actions {
@@ -1083,7 +1205,7 @@ body > div[id^="dmermaid-"] {
1083
1205
  flex: 0 0 auto;
1084
1206
  align-items: center;
1085
1207
  justify-content: flex-end;
1086
- gap: 0.25rem;
1208
+ gap: var(--ms-gap-header-actions, 0.125rem);
1087
1209
  margin-left: auto;
1088
1210
  }
1089
1211
 
@@ -1091,12 +1213,6 @@ body > div[id^="dmermaid-"] {
1091
1213
  width: 1rem;
1092
1214
  height: 1rem;
1093
1215
  flex: 0 0 1rem;
1094
- color: #2563eb;
1095
- }
1096
-
1097
- .markstream-angular.dark .code-block-language-icon,
1098
- .dark .markstream-angular .code-block-language-icon {
1099
- color: #93c5fd;
1100
1216
  }
1101
1217
 
1102
1218
  .markstream-angular .code-block-language-icon svg,
@@ -1112,6 +1228,42 @@ body > div[id^="dmermaid-"] {
1112
1228
 
1113
1229
  .markstream-angular .code-block-body {
1114
1230
  position: relative;
1231
+ display: grid;
1232
+ min-height: 96px;
1233
+ min-width: 0;
1234
+ overflow: hidden;
1235
+ background: var(--markstream-code-fallback-bg);
1236
+ }
1237
+
1238
+ .markstream-angular .code-block-body > .code-editor-container,
1239
+ .markstream-angular .code-block-body > .code-editor-fallback-surface {
1240
+ grid-area: 1 / 1;
1241
+ }
1242
+
1243
+ .markstream-angular .code-editor-container {
1244
+ min-height: 96px;
1245
+ }
1246
+
1247
+ .markstream-angular .code-editor-fallback-surface {
1248
+ position: relative;
1249
+ z-index: 1;
1250
+ min-width: 0;
1251
+ }
1252
+
1253
+ .markstream-angular .code-editor-fallback-surface > pre {
1254
+ height: 100%;
1255
+ margin: 0;
1256
+ padding: var(--markstream-code-padding-y, 8px) var(--markstream-code-padding-x, 12px);
1257
+ padding-bottom: var(--markstream-code-padding-bottom, 8px);
1258
+ padding-left: var(--markstream-code-padding-left, 52px);
1259
+ border: 0;
1260
+ border-radius: 0;
1261
+ background: var(--markstream-code-fallback-bg, var(--code-bg, #fff));
1262
+ color: var(--markstream-code-fallback-fg, var(--code-fg));
1263
+ font-family: var(--markstream-code-font-family, "SF Mono", Monaco, Consolas, "Ubuntu Mono", "Liberation Mono", "Courier New", monospace);
1264
+ font-size: var(--vscode-editor-font-size, 12px);
1265
+ font-weight: 400;
1266
+ line-height: var(--vscode-editor-line-height, 18px);
1115
1267
  }
1116
1268
 
1117
1269
  .code-block-body--expanded {
@@ -1128,23 +1280,24 @@ body > div[id^="dmermaid-"] {
1128
1280
  display: inline-flex;
1129
1281
  align-items: center;
1130
1282
  justify-content: center;
1131
- width: 1.75rem;
1132
- height: 1.75rem;
1133
- padding: 0;
1283
+ width: auto;
1284
+ height: auto;
1285
+ padding: 0.375rem;
1134
1286
  border-radius: 0.375rem;
1135
- color: inherit;
1287
+ color: var(--code-action-fg, inherit);
1136
1288
  transition: background-color 140ms ease, color 140ms ease, transform 140ms ease, opacity 140ms ease;
1137
1289
  }
1138
1290
 
1139
1291
  .markstream-angular .code-action-btn:hover {
1140
- background: var(--vscode-editor-selectionBackground, rgba(148, 163, 184, 0.18));
1292
+ background: var(--code-action-hover-bg, rgba(148, 163, 184, 0.18));
1293
+ color: var(--code-action-hover-fg, inherit);
1141
1294
  }
1142
1295
 
1143
1296
  .markstream-angular .code-action-btn__icon,
1144
1297
  .markstream-angular .code-action-btn svg {
1145
1298
  display: block;
1146
- width: 0.8rem;
1147
- height: 0.8rem;
1299
+ width: 0.875rem;
1300
+ height: 0.875rem;
1148
1301
  flex: 0 0 auto;
1149
1302
  }
1150
1303
 
package/dist/index.d.ts CHANGED
@@ -274,9 +274,12 @@ declare class CodeBlockNodeComponent implements AfterViewInit, OnChanges, OnDest
274
274
  defaultFontSize: number;
275
275
  fontSize: number;
276
276
  private helpers;
277
+ private runtimeMonacoOptions;
277
278
  private createPromise;
278
279
  private syncPromise;
279
280
  private editorKind;
281
+ private editorStreamMode;
282
+ private lifecycleId;
280
283
  private viewReady;
281
284
  private destroyed;
282
285
  private copyTimer;
@@ -366,10 +369,14 @@ declare class CodeBlockNodeComponent implements AfterViewInit, OnChanges, OnDest
366
369
  get previewTitle(): string;
367
370
  get headerForeground(): string;
368
371
  get headerBackground(): string;
372
+ get headerTitle(): string;
373
+ get headerCaption(): string;
374
+ get fileLabel(): string;
369
375
  get ariaLabel(): string;
370
376
  get showLoadingPlaceholder(): boolean;
371
377
  get shouldDelayEditor(): boolean;
372
378
  get containerStyle(): Record<string, string>;
379
+ get preFallbackStyle(): Record<string, string>;
373
380
  readonly closeInlinePreview: () => void;
374
381
  ngAfterViewInit(): void;
375
382
  ngOnChanges(): void;
@@ -385,7 +392,13 @@ declare class CodeBlockNodeComponent implements AfterViewInit, OnChanges, OnDest
385
392
  private syncEditorState;
386
393
  private ensureHelpers;
387
394
  private recreateEditor;
395
+ private syncEditorGeometryVars;
388
396
  private updateEditor;
397
+ private hasRenderedEditorDom;
398
+ private getVisualEditorSurface;
399
+ private isEditorVisuallyReady;
400
+ private prepareEditorHandoff;
401
+ private nextAnimationFrame;
389
402
  private applyEditorFontSize;
390
403
  private applyEditorHeight;
391
404
  private resolveEditorHeight;
@@ -1111,13 +1124,26 @@ declare class ParagraphNodeComponent implements OnChanges {
1111
1124
 
1112
1125
  declare class PreCodeNodeComponent {
1113
1126
  node: AngularRenderableNode;
1127
+ showLineNumbers: boolean;
1128
+ private cachedCode;
1129
+ private cachedCount;
1130
+ private textCount;
1131
+ private textCache;
1114
1132
  get language(): string;
1115
1133
  get languageClass(): string;
1134
+ get preClasses(): {
1135
+ [x: string]: boolean;
1136
+ 'markstream-pre--line-numbers': boolean;
1137
+ };
1116
1138
  get ariaLabel(): string;
1117
1139
  get code(): string;
1118
1140
  get loading(): boolean;
1141
+ get displayCode(): string;
1142
+ get codeLineCount(): number;
1143
+ get lineNumbersText(): string;
1144
+ get lineNumberLayoutStyle(): Record<string, string> | null;
1119
1145
  static ɵfac: i0.ɵɵFactoryDeclaration<PreCodeNodeComponent, never>;
1120
- static ɵcmp: i0.ɵɵComponentDeclaration<PreCodeNodeComponent, "markstream-angular-pre-code-node", never, { "node": { "alias": "node"; "required": true; }; }, {}, never, never, true, never>;
1146
+ static ɵcmp: i0.ɵɵComponentDeclaration<PreCodeNodeComponent, "markstream-angular-pre-code-node", never, { "node": { "alias": "node"; "required": true; }; "showLineNumbers": { "alias": "showLineNumbers"; "required": false; }; }, {}, never, never, true, never>;
1121
1147
  }
1122
1148
 
1123
1149
  declare class ReferenceNodeComponent {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "markstream-angular",
3
3
  "type": "module",
4
- "version": "0.0.9-beta.2",
4
+ "version": "0.0.10",
5
5
  "description": "Angular 20+ standalone streaming Markdown renderer for AI chat, LLM token streams, SSE/WebSocket output, incomplete Markdown, Mermaid, KaTeX, Monaco-powered code blocks, and safe Angular component rendering.",
6
6
  "author": "Simon He",
7
7
  "license": "MIT",
@@ -73,6 +73,7 @@
73
73
  "@terrastruct/d2": ">=0.1.33",
74
74
  "katex": ">=0.16.22",
75
75
  "mermaid": ">=11",
76
+ "stream-diffs": ">=0.0.2",
76
77
  "stream-monaco": ">=0.0.48"
77
78
  },
78
79
  "peerDependenciesMeta": {
@@ -88,6 +89,9 @@
88
89
  "mermaid": {
89
90
  "optional": true
90
91
  },
92
+ "stream-diffs": {
93
+ "optional": true
94
+ },
91
95
  "stream-monaco": {
92
96
  "optional": true
93
97
  }
@@ -95,7 +99,7 @@
95
99
  "dependencies": {
96
100
  "@floating-ui/dom": "^1.8.0",
97
101
  "markstream-core": "1.0.3",
98
- "stream-markdown-parser": "1.2.0"
102
+ "stream-markdown-parser": "1.2.3"
99
103
  },
100
104
  "devDependencies": {
101
105
  "@angular/common": "^20.3.26",