artifactuse 0.1.25 → 0.1.28

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.
@@ -66,7 +66,7 @@ export function provideArtifactuse(config?: {
66
66
  isFullscreen: boolean;
67
67
  };
68
68
  subscribe: (callback: any) => () => void;
69
- processMessage: (content: any, messageId: any) => {
69
+ processMessage: (content: any, messageId: any, overrides?: {}) => {
70
70
  html: string | Promise<string>;
71
71
  artifacts: any[];
72
72
  };
@@ -183,7 +183,7 @@ export function provideArtifactuse(config?: {
183
183
  hasArtifacts: import("vue").ComputedRef<boolean>;
184
184
  panelTypes: import("vue").ComputedRef<any>;
185
185
  activePanelUrl: import("vue").ComputedRef<any>;
186
- processMessage: (content: any, messageId: any) => {
186
+ processMessage: (content: any, messageId: any, overrides?: {}) => {
187
187
  html: string | Promise<string>;
188
188
  artifacts: any[];
189
189
  };
@@ -278,7 +278,7 @@ export function createArtifactuseComposable(config?: {}): {
278
278
  isFullscreen: boolean;
279
279
  };
280
280
  subscribe: (callback: any) => () => void;
281
- processMessage: (content: any, messageId: any) => {
281
+ processMessage: (content: any, messageId: any, overrides?: {}) => {
282
282
  html: string | Promise<string>;
283
283
  artifacts: any[];
284
284
  };
@@ -395,7 +395,7 @@ export function createArtifactuseComposable(config?: {}): {
395
395
  hasArtifacts: import("vue").ComputedRef<boolean>;
396
396
  panelTypes: import("vue").ComputedRef<any>;
397
397
  activePanelUrl: import("vue").ComputedRef<any>;
398
- processMessage: (content: any, messageId: any) => {
398
+ processMessage: (content: any, messageId: any, overrides?: {}) => {
399
399
  html: string | Promise<string>;
400
400
  artifacts: any[];
401
401
  };
@@ -23,7 +23,7 @@ const ARTIFACT_TYPES = {
23
23
  const PREVIEWABLE_LANGUAGES = [
24
24
  // Code languages
25
25
  'html', 'htm', 'svg', 'markdown', 'md', 'jsx', 'vue',
26
- 'diff', 'patch', 'json',
26
+ 'diff', 'patch', 'smartdiff', 'json',
27
27
  'javascript', 'js', 'python', 'py',
28
28
  // Visual editors
29
29
  'canvas', 'whiteboard', 'drawing',
@@ -40,7 +40,7 @@ const PANEL_LANGUAGES = [
40
40
  'video', 'videoeditor', 'timeline',
41
41
  'canvas', 'whiteboard', 'drawing',
42
42
  // Code (panel for preview)
43
- 'json', 'svg', 'diff', 'patch',
43
+ 'json', 'svg', 'diff', 'patch', 'smartdiff',
44
44
  'javascript', 'js', 'python', 'py',
45
45
  'jsx', 'vue', 'html', 'htm',
46
46
  // Structured artifacts (form can be panel based on complexity)
@@ -117,6 +117,7 @@ function getLanguageDisplayName(language) {
117
117
  docker: 'Docker',
118
118
  diff: 'Diff',
119
119
  patch: 'Patch',
120
+ smartdiff: 'Smart Diff',
120
121
  // Visual editors
121
122
  canvas: 'Canvas',
122
123
  video: 'Video Editor',
@@ -241,6 +242,7 @@ function getLanguageIcon(language) {
241
242
  sql: '<path d="M12 3C7.58 3 4 4.79 4 7v10c0 2.21 3.58 4 8 4s8-1.79 8-4V7c0-2.21-3.58-4-8-4m0 2c3.87 0 6 1.5 6 2s-2.13 2-6 2-6-1.5-6-2 2.13-2 6-2M6 17v-2.7c1.56.84 3.67 1.36 6 1.36s4.44-.52 6-1.36V17c0 .5-2.13 2-6 2s-6-1.5-6-2m0-5v-2.7c1.56.84 3.67 1.36 6 1.36s4.44-.52 6-1.36V12c0 .5-2.13 2-6 2s-6-1.5-6-2z"/>',
242
243
  diff: '<path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z"/>',
243
244
  patch: '<path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z"/>',
245
+ smartdiff: '<path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z"/>',
244
246
  canvas: '<rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><line x1="3" y1="9" x2="21" y2="9"/><line x1="9" y1="21" x2="9" y2="9"/>',
245
247
  whiteboard: '<rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><line x1="3" y1="9" x2="21" y2="9"/><line x1="9" y1="21" x2="9" y2="9"/>',
246
248
  drawing: '<path d="M12 19l7-7 3 3-7 7-3-3z"/><path d="M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z"/><path d="M2 2l7.586 7.586"/>',
@@ -282,6 +284,18 @@ function decodeHtml(encoded) {
282
284
  .replace(/&nbsp;/g, ' ');
283
285
  }
284
286
 
287
+ /**
288
+ * Encode HTML for safe embedding
289
+ */
290
+ function encodeHtml(code) {
291
+ return code
292
+ .replace(/&/g, '&amp;')
293
+ .replace(/"/g, '&quot;')
294
+ .replace(/'/g, '&#39;')
295
+ .replace(/</g, '&lt;')
296
+ .replace(/>/g, '&gt;');
297
+ }
298
+
285
299
  /**
286
300
  * Encode JSON for safe embedding in HTML attributes using Base64
287
301
  */
@@ -306,6 +320,16 @@ function encodeJsonForAttribute(obj) {
306
320
  function extractArtifactTitle(code, language) {
307
321
  const langLower = language?.toLowerCase();
308
322
 
323
+ // For smartdiff, extract language from JSON
324
+ if (langLower === 'smartdiff') {
325
+ try {
326
+ const json = JSON.parse(code);
327
+ return json.language ? `${getLanguageDisplayName(json.language)} Diff` : 'Smart Diff';
328
+ } catch {
329
+ return 'Smart Diff';
330
+ }
331
+ }
332
+
309
333
  // For form/social, try to extract title from JSON
310
334
  if (langLower === 'form' || langLower === 'social') {
311
335
  try {
@@ -370,6 +394,75 @@ function extractArtifactTitle(code, language) {
370
394
  return `${getLanguageDisplayName(language)} Code`;
371
395
  }
372
396
 
397
+ /**
398
+ * Compute a simple line-by-line diff for inline preview display
399
+ * Produces +/- prefixed lines that Prism highlights with language-diff
400
+ */
401
+ function computeSimpleDiff(oldCode, newCode) {
402
+ const oldLines = (oldCode || '').split('\n');
403
+ const newLines = (newCode || '').split('\n');
404
+ const result = [];
405
+ const max = Math.max(oldLines.length, newLines.length);
406
+ for (let i = 0; i < max; i++) {
407
+ const oldLine = i < oldLines.length ? oldLines[i] : undefined;
408
+ const newLine = i < newLines.length ? newLines[i] : undefined;
409
+ if (oldLine === newLine) {
410
+ result.push(' ' + oldLine);
411
+ } else {
412
+ if (oldLine !== undefined) result.push('-' + oldLine);
413
+ if (newLine !== undefined) result.push('+' + newLine);
414
+ }
415
+ }
416
+ return result.join('\n');
417
+ }
418
+
419
+ /**
420
+ * Create inline preview HTML for an artifact
421
+ * Shows truncated code with fade overlay for long content
422
+ */
423
+ function createInlinePreview(artifact, code, langLower, inlinePreview) {
424
+ const maxLines = inlinePreview.maxLines || 15;
425
+
426
+ // Smartdiff: parse JSON, compute diff, use actual language for highlighting
427
+ if (langLower === 'smartdiff') {
428
+ try {
429
+ const diffData = JSON.parse(code);
430
+ const diffText = computeSimpleDiff(diffData.oldCode, diffData.newCode);
431
+ const allDiffLines = diffText.split('\n');
432
+ const truncDiffLines = allDiffLines.slice(0, maxLines);
433
+
434
+ // Separate markers (+/-/space) from code content
435
+ const markers = truncDiffLines.map(l => l[0] || ' ');
436
+ const codeLines = truncDiffLines.map(l => l.slice(1));
437
+ const encoded = encodeHtml(codeLines.join('\n'));
438
+ const isTruncated = allDiffLines.length > maxLines;
439
+ const actualLang = diffData.language || 'plaintext';
440
+
441
+ return `<div class="artifactuse-inline-preview${isTruncated ? ' artifactuse-inline-preview--truncated' : ''}" data-artifact-id="${artifact.id}" data-smartdiff="true" data-smartdiff-markers="${markers.join(',')}">`
442
+ + `<pre class="artifactuse-inline-preview__pre"><code class="language-${actualLang}">${encoded}</code></pre>`
443
+ + (isTruncated ? `<div class="artifactuse-inline-preview__fade"><span class="artifactuse-inline-preview__action">View full diff (${allDiffLines.length} lines)</span></div>` : '')
444
+ + `</div>`;
445
+ } catch {
446
+ // Fallback: show raw content as JSON
447
+ }
448
+ }
449
+
450
+ // Standard code blocks (and diff/patch)
451
+ let previewCode = code;
452
+ let previewLang = langLower;
453
+
454
+ const lines = previewCode.split('\n');
455
+ const truncated = lines.slice(0, maxLines).join('\n');
456
+ const encoded = encodeHtml(truncated);
457
+ const isTruncated = lines.length > maxLines;
458
+ const label = langLower === 'diff' || langLower === 'patch' ? 'diff' : 'code';
459
+
460
+ return `<div class="artifactuse-inline-preview${isTruncated ? ' artifactuse-inline-preview--truncated' : ''}" data-artifact-id="${artifact.id}">`
461
+ + `<pre class="artifactuse-inline-preview__pre"><code class="language-${previewLang}">${encoded}</code></pre>`
462
+ + (isTruncated ? `<div class="artifactuse-inline-preview__fade"><span class="artifactuse-inline-preview__action">View full ${label} (${lines.length} lines)</span></div>` : '')
463
+ + `</div>`;
464
+ }
465
+
373
466
  /**
374
467
  * Create artifact placeholder HTML
375
468
  */
@@ -491,7 +584,25 @@ function extractCodeBlockArtifacts(html, messageId, options = {}) {
491
584
  minLines = 3,
492
585
  minLength = 50,
493
586
  extractAll = false,
587
+ inlinePreview = null,
588
+ inlineCode = null,
589
+ tabs = null,
590
+ viewMode = null,
494
591
  } = options;
592
+
593
+ function shouldShowPreview(lang) {
594
+ if (!inlinePreview) return false;
595
+ if (inlinePreview.languages === true) return true;
596
+ if (Array.isArray(inlinePreview.languages)) return inlinePreview.languages.includes(lang);
597
+ return false;
598
+ }
599
+
600
+ function shouldShowInlineCode(lang) {
601
+ if (!inlineCode) return false;
602
+ if (inlineCode.languages === true) return true;
603
+ if (Array.isArray(inlineCode.languages)) return inlineCode.languages.includes(lang);
604
+ return false;
605
+ }
495
606
 
496
607
  const artifacts = [];
497
608
  const codeBlockRegex = /<pre><code class="language-(\w+)">([\s\S]*?)<\/code><\/pre>/gi;
@@ -510,6 +621,12 @@ function extractCodeBlockArtifacts(html, messageId, options = {}) {
510
621
  }
511
622
  }
512
623
 
624
+ // inlineCode: highest priority — skip extraction, leave code block as-is
625
+ if (shouldShowInlineCode(langLower)) {
626
+ blockIndex++;
627
+ return match;
628
+ }
629
+
513
630
  // Artifact extraction logic
514
631
  const isPreviewableLang = isPreviewable(langLower);
515
632
 
@@ -517,25 +634,37 @@ function extractCodeBlockArtifacts(html, messageId, options = {}) {
517
634
 
518
635
  if (extractAll) {
519
636
  shouldExtract = true;
520
- } else if (langLower === 'diff' || langLower === 'patch') {
637
+ } else if (langLower === 'diff' || langLower === 'patch' || langLower === 'smartdiff') {
521
638
  shouldExtract = lineCount > 10;
522
639
  } else if (isPreviewableLang) {
523
640
  shouldExtract = true;
524
641
  } else {
525
642
  shouldExtract = code.length >= minLength && lineCount >= minLines;
526
643
  }
527
-
644
+
645
+ // Force extraction when inline preview is configured for this language
646
+ if (!shouldExtract && shouldShowPreview(langLower)) {
647
+ shouldExtract = true;
648
+ }
649
+
528
650
  if (shouldExtract) {
529
651
  const artifact = createArtifact(code, langLower, messageId, blockIndex);
652
+ if (tabs) artifact.tabs = tabs;
653
+ if (viewMode) artifact.viewMode = viewMode;
530
654
  blockIndex++;
531
655
  artifacts.push(artifact);
532
-
656
+
657
+ // Inline preview mode: show truncated code instead of card
658
+ if (shouldShowPreview(langLower)) {
659
+ return createInlinePreview(artifact, code, langLower, inlinePreview);
660
+ }
661
+
533
662
  // Determine placeholder type based on artifact
534
663
  let placeholderType = 'panel';
535
664
  if (artifact.isInline) {
536
665
  placeholderType = artifact.type === 'social' ? 'inline-social' : 'inline-form';
537
666
  }
538
-
667
+
539
668
  return createArtifactPlaceholder(artifact, placeholderType);
540
669
  }
541
670
 
@@ -6313,6 +6442,7 @@ const DEFAULT_PANELS = {
6313
6442
  // Diff/patches
6314
6443
  diff: 'diff-panel',
6315
6444
  patch: 'diff-panel',
6445
+ smartdiff: 'diff-panel',
6316
6446
 
6317
6447
  // Plain text
6318
6448
  txt: 'code-panel',
@@ -6693,18 +6823,30 @@ function createArtifactuse(userConfig = {}) {
6693
6823
  * Process AI agent message content
6694
6824
  * Returns processed HTML with artifact placeholders
6695
6825
  */
6696
- function processMessage(content, messageId) {
6826
+ function processMessage(content, messageId, overrides = {}) {
6697
6827
  // First, convert markdown to HTML
6698
6828
  let html = d.parse(content);
6699
-
6829
+
6700
6830
  const artifacts = [];
6701
-
6831
+
6702
6832
  // Get current resolved theme for processors that need it
6703
6833
  const processorOptions = { theme: theme.resolved };
6704
-
6834
+
6835
+ // Merge overrides with global config (component prop → global config → default)
6836
+ const inlinePreview = overrides.inlinePreview ?? config.inlinePreview ?? null;
6837
+ const inlineCode = overrides.inlineCode ?? config.inlineCode ?? null;
6838
+ const tabs = overrides.tabs ?? config.tabs ?? null;
6839
+ const viewMode = overrides.viewMode ?? config.viewMode ?? null;
6840
+
6705
6841
  // Extract all code block artifacts (code, form, social)
6706
6842
  if (config.processors.codeBlocks) {
6707
- const result = extractCodeBlockArtifacts(html, messageId, config.codeExtraction);
6843
+ const result = extractCodeBlockArtifacts(html, messageId, {
6844
+ ...config.codeExtraction,
6845
+ inlinePreview,
6846
+ inlineCode,
6847
+ tabs,
6848
+ viewMode,
6849
+ });
6708
6850
  html = result.html;
6709
6851
  artifacts.push(...result.artifacts);
6710
6852
  }
@@ -6815,6 +6957,25 @@ function createArtifactuse(userConfig = {}) {
6815
6957
  // Apply syntax highlighting if enabled
6816
6958
  if (config.syntaxHighlight) {
6817
6959
  highlightAll(container);
6960
+
6961
+ // Post-process smartdiff inline previews:
6962
+ // Prism highlighted the code with the actual language grammar.
6963
+ // Now wrap each line in .token.deleted / .token.inserted based on markers.
6964
+ const el = container === document ? document : container;
6965
+ const smartdiffPreviews = el.querySelectorAll('.artifactuse-inline-preview[data-smartdiff]');
6966
+ smartdiffPreviews.forEach(preview => {
6967
+ const codeEl = preview.querySelector('code');
6968
+ if (!codeEl || codeEl.dataset.smartdiffProcessed) return;
6969
+ const markers = preview.dataset.smartdiffMarkers?.split(',') || [];
6970
+ const lines = codeEl.innerHTML.split('\n');
6971
+ codeEl.innerHTML = lines.map((line, i) => {
6972
+ const marker = markers[i];
6973
+ if (marker === '-') return `<span class="token deleted">${line}</span>`;
6974
+ if (marker === '+') return `<span class="token inserted">${line}</span>`;
6975
+ return line;
6976
+ }).join('\n');
6977
+ codeEl.dataset.smartdiffProcessed = 'true';
6978
+ });
6818
6979
  }
6819
6980
 
6820
6981
  await Promise.all(promises);
@@ -6832,7 +6993,10 @@ function createArtifactuse(userConfig = {}) {
6832
6993
 
6833
6994
  state.setActiveArtifact(artifact.id);
6834
6995
  state.setPanelOpen(true);
6835
-
6996
+ if (artifact.viewMode) {
6997
+ state.setViewMode(artifact.viewMode);
6998
+ }
6999
+
6836
7000
  emit('artifact:opened', artifact);
6837
7001
  }
6838
7002
 
@@ -10971,6 +11135,26 @@ var script$2 = {
10971
11135
  type: Boolean,
10972
11136
  default: false,
10973
11137
  },
11138
+ // Override global inlinePreview config for this message
11139
+ inlinePreview: {
11140
+ type: Object,
11141
+ default: null,
11142
+ },
11143
+ // Show full inline code (no extraction) for listed languages
11144
+ inlineCode: {
11145
+ type: Object,
11146
+ default: null,
11147
+ },
11148
+ // Override visible panel tabs for artifacts from this message
11149
+ tabs: {
11150
+ type: Array,
11151
+ default: null,
11152
+ },
11153
+ // Override initial panel view mode for artifacts from this message
11154
+ viewMode: {
11155
+ type: String,
11156
+ default: null,
11157
+ },
10974
11158
  },
10975
11159
 
10976
11160
  setup(props, { emit }) {
@@ -11001,6 +11185,9 @@ var script$2 = {
11001
11185
  // Get active artifact ID from state
11002
11186
  const activeArtifactId = computed(() => state.activeArtifactId);
11003
11187
 
11188
+ // Resolve inlineCards: component prop → global config → default (true)
11189
+ const effectiveInlineCards = computed(() => props.inlineCards ?? instance?.config?.inlineCards ?? true);
11190
+
11004
11191
  /**
11005
11192
  * Track if this message was ever "live" (typed/streamed) in this session
11006
11193
  * Used to determine if forms should be active or inactive
@@ -11349,7 +11536,12 @@ var script$2 = {
11349
11536
  () => props.content,
11350
11537
  (newContent) => {
11351
11538
  if (newContent) {
11352
- const result = processMessage(newContent, props.messageId);
11539
+ const result = processMessage(newContent, props.messageId, {
11540
+ inlinePreview: props.inlinePreview,
11541
+ inlineCode: props.inlineCode,
11542
+ tabs: props.tabs,
11543
+ viewMode: props.viewMode,
11544
+ });
11353
11545
  processedHtml.value = result.html;
11354
11546
  messageArtifacts.value = result.artifacts;
11355
11547
 
@@ -11382,6 +11574,19 @@ var script$2 = {
11382
11574
  removeMediaListeners();
11383
11575
  });
11384
11576
 
11577
+ function handleContentClick(e) {
11578
+ const preview = e.target.closest('.artifactuse-inline-preview');
11579
+ if (preview) {
11580
+ const artifactId = preview.dataset.artifactId;
11581
+ if (artifactId) {
11582
+ const artifact = state.artifacts.find(a => a.id === artifactId);
11583
+ if (artifact) {
11584
+ handleOpenArtifact(artifact);
11585
+ }
11586
+ }
11587
+ }
11588
+ }
11589
+
11385
11590
  function handleOpenArtifact(artifact) {
11386
11591
  openArtifact(artifact);
11387
11592
  emit('artifact-open', artifact);
@@ -11427,11 +11632,13 @@ var script$2 = {
11427
11632
  viewerCaption,
11428
11633
  theme,
11429
11634
  activeArtifactId,
11635
+ effectiveInlineCards,
11430
11636
  contentSegments,
11431
11637
  formInitialState,
11432
11638
  openViewer,
11433
11639
  closeViewer,
11434
11640
  attachMediaListeners,
11641
+ handleContentClick,
11435
11642
  handleOpenArtifact,
11436
11643
  handleArtifactCopy,
11437
11644
  handleArtifactDownload,
@@ -11458,7 +11665,11 @@ var __vue_render__$2 = function () {
11458
11665
  [
11459
11666
  _c(
11460
11667
  "div",
11461
- { ref: "contentRef", staticClass: "artifactuse-message-content" },
11668
+ {
11669
+ ref: "contentRef",
11670
+ staticClass: "artifactuse-message-content",
11671
+ on: { click: _vm.handleContentClick },
11672
+ },
11462
11673
  [
11463
11674
  _vm._l(_vm.contentSegments, function (segment, index) {
11464
11675
  return [
@@ -11487,7 +11698,7 @@ var __vue_render__$2 = function () {
11487
11698
  attrs: { artifact: segment.artifact, theme: _vm.theme },
11488
11699
  on: { copy: _vm.handleSocialCopy },
11489
11700
  })
11490
- : segment.type === "panel" && _vm.inlineCards
11701
+ : segment.type === "panel" && _vm.effectiveInlineCards
11491
11702
  ? _c("ArtifactuseCard", {
11492
11703
  key: "panel-" + index,
11493
11704
  attrs: {
@@ -27090,27 +27301,54 @@ var script$1 = defineComponent({
27090
27301
  };
27091
27302
  });
27092
27303
 
27304
+ // Smartdiff: per-line language-aware highlighting
27305
+ function highlightSmartDiff(artifact) {
27306
+ if (artifact.language !== 'smartdiff') return null;
27307
+ try {
27308
+ const data = JSON.parse(artifact.code);
27309
+ if (data.oldCode === undefined || data.newCode === undefined) return null;
27310
+ const lang = data.language || 'plaintext';
27311
+ const grammar = isPrismAvailable() && window.Prism.languages[lang];
27312
+ const diffLines = computeSimpleDiff(data.oldCode, data.newCode).split('\n');
27313
+
27314
+ const highlighted = diffLines.map(line => {
27315
+ const prefix = line[0];
27316
+ const content = line.slice(1);
27317
+ const hl = grammar ? window.Prism.highlight(content, grammar, lang) : content;
27318
+ if (prefix === '-') return `<span class="token deleted">${hl}</span>`;
27319
+ if (prefix === '+') return `<span class="token inserted">${hl}</span>`;
27320
+ return hl;
27321
+ }).join('\n');
27322
+
27323
+ return { html: highlighted, lineCount: diffLines.length };
27324
+ } catch { return null; }
27325
+ }
27326
+
27093
27327
  // Methods
27094
27328
  function generateLineNumbers() {
27095
27329
  if (!lineNumbersRef.value || !activeArtifact.value?.code) return;
27096
-
27097
- const lines = activeArtifact.value.code.split('\n').length;
27330
+ const sd = highlightSmartDiff(activeArtifact.value);
27331
+ const lines = sd ? sd.lineCount : activeArtifact.value.code.split('\n').length;
27098
27332
  const html = Array.from({ length: lines }, (_, i) => `<div>${i + 1}</div>`).join('');
27099
27333
  lineNumbersRef.value.innerHTML = html;
27100
27334
  }
27101
-
27335
+
27102
27336
  function highlightCode() {
27103
27337
  if (codeRef.value && isPrismAvailable() && activeArtifact.value?.code) {
27104
- const grammar = window.Prism.languages[normalizedLanguage.value];
27105
- if (grammar) {
27106
- codeRef.value.innerHTML = window.Prism.highlight(
27107
- activeArtifact.value.code,
27108
- grammar,
27109
- normalizedLanguage.value
27110
- );
27338
+ const sd = highlightSmartDiff(activeArtifact.value);
27339
+ if (sd) {
27340
+ codeRef.value.innerHTML = sd.html;
27111
27341
  } else {
27112
- // Fallback: set as text if no grammar available
27113
- codeRef.value.textContent = activeArtifact.value.code;
27342
+ const grammar = window.Prism.languages[normalizedLanguage.value];
27343
+ if (grammar) {
27344
+ codeRef.value.innerHTML = window.Prism.highlight(
27345
+ activeArtifact.value.code,
27346
+ grammar,
27347
+ normalizedLanguage.value
27348
+ );
27349
+ } else {
27350
+ codeRef.value.textContent = activeArtifact.value.code;
27351
+ }
27114
27352
  }
27115
27353
  codeRef.value.dataset.highlighted = 'true';
27116
27354
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "artifactuse",
3
- "version": "0.1.25",
3
+ "version": "0.1.28",
4
4
  "type": "module",
5
5
  "description": "The Artifact SDK for AI Agents - Turn AI outputs into interactive experiences",
6
6
  "author": "Artifactuse",