diff --git a/CHANGELOG.md b/CHANGELOG.md
index c0f6709a31..b93cd09319 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -81,6 +81,7 @@ Notes: web developers are advised to use [`~` (tilde range)](https://github.com/
- Improved drop zone behavior and styling in Fluent theme, in PR [#5328](https://github.com/microsoft/BotFramework-WebChat/pull/5328), by [@OEvgeny](https://github.com/OEvgeny)
- Excluded side effects from module entry points to prevent global scope modifications, in PR [#5329](https://github.com/microsoft/BotFramework-WebChat/pull/5329), by [@OEvgeny](https://github.com/OEvgeny)
- Moved to `micromark` for rendering Markdown, instead of `markdown-it`, in PR [#5330](https://github.com/microsoft/BotFramework-WebChat/pull/5330), by [@compulim](https://github.com/compulim)
+- Improved view code dialog UI in Fluent theme with better styling and accessibility, in PR [#5337](https://github.com/microsoft/BotFramework-WebChat/pull/5337), by [@OEvgeny](https://github.com/OEvgeny)
### Fixed
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-fluent-right-fluent-5-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-fluent-right-fluent-5-snap.png
index 7a22155044..ce4149fcae 100644
Binary files a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-fluent-right-fluent-5-snap.png and b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-fluent-right-fluent-5-snap.png differ
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-fluent-right-fluent-6-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-fluent-right-fluent-6-snap.png
index 7201ab4642..3966ce7ab1 100644
Binary files a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-fluent-right-fluent-6-snap.png and b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-fluent-right-fluent-6-snap.png differ
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-fluent-right-fluent-7-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-fluent-right-fluent-7-snap.png
index 0ca06ad684..3a101218f3 100644
Binary files a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-fluent-right-fluent-7-snap.png and b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-fluent-right-fluent-7-snap.png differ
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-codeblock-1-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-codeblock-1-snap.png
new file mode 100644
index 0000000000..0b6193e6fb
Binary files /dev/null and b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-codeblock-1-snap.png differ
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-codeblock-2-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-codeblock-2-snap.png
new file mode 100644
index 0000000000..96fc77ff62
Binary files /dev/null and b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-codeblock-2-snap.png differ
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-codeblock-3-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-codeblock-3-snap.png
new file mode 100644
index 0000000000..ea87fed004
Binary files /dev/null and b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-codeblock-3-snap.png differ
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-codeblock-4-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-codeblock-4-snap.png
new file mode 100644
index 0000000000..8f96e8baf7
Binary files /dev/null and b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-codeblock-4-snap.png differ
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-codeblock-dark-1-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-codeblock-dark-1-snap.png
new file mode 100644
index 0000000000..0b6193e6fb
Binary files /dev/null and b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-codeblock-dark-1-snap.png differ
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-codeblock-dark-2-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-codeblock-dark-2-snap.png
new file mode 100644
index 0000000000..96fc77ff62
Binary files /dev/null and b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-codeblock-dark-2-snap.png differ
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-codeblock-dark-3-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-codeblock-dark-3-snap.png
new file mode 100644
index 0000000000..851f9a1e76
Binary files /dev/null and b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-codeblock-dark-3-snap.png differ
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-codeblock-dark-4-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-codeblock-dark-4-snap.png
new file mode 100644
index 0000000000..8f96e8baf7
Binary files /dev/null and b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-codeblock-dark-4-snap.png differ
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-pre-chat-message-5-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-pre-chat-message-5-snap.png
index d0406837f1..6ca9c5577f 100644
Binary files a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-pre-chat-message-5-snap.png and b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-pre-chat-message-5-snap.png differ
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-pre-chat-message-6-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-pre-chat-message-6-snap.png
index 8bfc0a9128..fd0a4b497a 100644
Binary files a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-pre-chat-message-6-snap.png and b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-pre-chat-message-6-snap.png differ
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-pre-chat-message-7-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-pre-chat-message-7-snap.png
index d0406837f1..6ca9c5577f 100644
Binary files a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-pre-chat-message-7-snap.png and b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-pre-chat-message-7-snap.png differ
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-transcript-13-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-transcript-13-snap.png
index f1f9c6892b..fb78f31fe0 100644
Binary files a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-transcript-13-snap.png and b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-transcript-13-snap.png differ
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-transcript-14-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-transcript-14-snap.png
index 4257b5e581..2dcd63f441 100644
Binary files a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-transcript-14-snap.png and b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-transcript-14-snap.png differ
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-transcript-15-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-transcript-15-snap.png
index 89b13c67ef..7ae71df301 100644
Binary files a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-transcript-15-snap.png and b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-transcript-15-snap.png differ
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-transcript-5-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-transcript-5-snap.png
index a19e96afe3..17e13777e2 100644
Binary files a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-transcript-5-snap.png and b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-transcript-5-snap.png differ
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-transcript-6-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-transcript-6-snap.png
index 6c843bf36b..be21567518 100644
Binary files a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-transcript-6-snap.png and b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-transcript-6-snap.png differ
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-transcript-7-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-transcript-7-snap.png
index 65cd263e5b..57552d31ee 100644
Binary files a/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-transcript-7-snap.png and b/__tests__/__image_snapshots__/html/side-by-side-wide-dark-js-fluent-theme-applied-dark-theme-applied-side-by-side-left-transcript-right-transcript-7-snap.png differ
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-js-fluent-theme-applied-side-by-side-left-transcript-right-codeblock-1-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-js-fluent-theme-applied-side-by-side-left-transcript-right-codeblock-1-snap.png
new file mode 100644
index 0000000000..4668432512
Binary files /dev/null and b/__tests__/__image_snapshots__/html/side-by-side-wide-js-fluent-theme-applied-side-by-side-left-transcript-right-codeblock-1-snap.png differ
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-js-fluent-theme-applied-side-by-side-left-transcript-right-codeblock-2-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-js-fluent-theme-applied-side-by-side-left-transcript-right-codeblock-2-snap.png
new file mode 100644
index 0000000000..cf31297d70
Binary files /dev/null and b/__tests__/__image_snapshots__/html/side-by-side-wide-js-fluent-theme-applied-side-by-side-left-transcript-right-codeblock-2-snap.png differ
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-js-fluent-theme-applied-side-by-side-left-transcript-right-codeblock-3-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-js-fluent-theme-applied-side-by-side-left-transcript-right-codeblock-3-snap.png
new file mode 100644
index 0000000000..7fb56a3e8e
Binary files /dev/null and b/__tests__/__image_snapshots__/html/side-by-side-wide-js-fluent-theme-applied-side-by-side-left-transcript-right-codeblock-3-snap.png differ
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-js-fluent-theme-applied-side-by-side-left-transcript-right-codeblock-4-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-js-fluent-theme-applied-side-by-side-left-transcript-right-codeblock-4-snap.png
new file mode 100644
index 0000000000..1cf411ee19
Binary files /dev/null and b/__tests__/__image_snapshots__/html/side-by-side-wide-js-fluent-theme-applied-side-by-side-left-transcript-right-codeblock-4-snap.png differ
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-js-fluent-theme-applied-side-by-side-left-transcript-right-codeblock-dark-1-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-js-fluent-theme-applied-side-by-side-left-transcript-right-codeblock-dark-1-snap.png
new file mode 100644
index 0000000000..4668432512
Binary files /dev/null and b/__tests__/__image_snapshots__/html/side-by-side-wide-js-fluent-theme-applied-side-by-side-left-transcript-right-codeblock-dark-1-snap.png differ
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-js-fluent-theme-applied-side-by-side-left-transcript-right-codeblock-dark-2-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-js-fluent-theme-applied-side-by-side-left-transcript-right-codeblock-dark-2-snap.png
new file mode 100644
index 0000000000..cf31297d70
Binary files /dev/null and b/__tests__/__image_snapshots__/html/side-by-side-wide-js-fluent-theme-applied-side-by-side-left-transcript-right-codeblock-dark-2-snap.png differ
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-js-fluent-theme-applied-side-by-side-left-transcript-right-codeblock-dark-3-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-js-fluent-theme-applied-side-by-side-left-transcript-right-codeblock-dark-3-snap.png
new file mode 100644
index 0000000000..67626f3be8
Binary files /dev/null and b/__tests__/__image_snapshots__/html/side-by-side-wide-js-fluent-theme-applied-side-by-side-left-transcript-right-codeblock-dark-3-snap.png differ
diff --git a/__tests__/__image_snapshots__/html/side-by-side-wide-js-fluent-theme-applied-side-by-side-left-transcript-right-codeblock-dark-4-snap.png b/__tests__/__image_snapshots__/html/side-by-side-wide-js-fluent-theme-applied-side-by-side-left-transcript-right-codeblock-dark-4-snap.png
new file mode 100644
index 0000000000..1cf411ee19
Binary files /dev/null and b/__tests__/__image_snapshots__/html/side-by-side-wide-js-fluent-theme-applied-side-by-side-left-transcript-right-codeblock-dark-4-snap.png differ
diff --git a/__tests__/html/fluentTheme/side-by-side.wide.dark.html b/__tests__/html/fluentTheme/side-by-side.wide.dark.html
index 8e8af513fb..2485974b95 100644
--- a/__tests__/html/fluentTheme/side-by-side.wide.dark.html
+++ b/__tests__/html/fluentTheme/side-by-side.wide.dark.html
@@ -73,10 +73,17 @@
let timestampStart = new Date(2020, 7, 9).getTime();
const timestamp = () => new Date(timestampStart += 100).toISOString();
- const [leftTranscriptIndex = 0, rightTranscriptIndex = 1] = new URLSearchParams(location.search).getAll('transcript');
- const [leftVariant = 'fluent', rightVariant = 'copilot'] = new URLSearchParams(location.search).getAll('variant');
+ const searchParams = new URLSearchParams(location.search);
- const sendBoxIndexes = new URLSearchParams(location.search).getAll('focus');
+ const [leftTranscriptIndex = 0, rightTranscriptIndex = 1] = searchParams.getAll('transcript');
+ const [leftVariant = 'fluent', rightVariant = 'copilot'] = searchParams.getAll('variant');
+
+ const sendBoxIndexes = searchParams.getAll('focus');
+ const activeFocusPresets = searchParams.getAll('focus-preset');
+
+ const adjustStyleOptions = Object.fromEntries(['codeBlockTheme']
+ .map(key => [key, searchParams.get(key)])
+ .filter(([key, value]) => value));
const botIcon = 'data:image/png;base64,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';
@@ -94,6 +101,27 @@
}
};
+ const waveSvg = `data:image/svg+xml;utf8,${encodeURIComponent(`
+`)}`;
+
const transcripts = [[
{
timestamp: timestamp(),
@@ -511,6 +539,63 @@
streamSequence: 99
}
}
+ ], [
+ {
+ timestamp: timestamp(),
+ from: { role: 'bot' },
+ entities: [{
+ ...aiMessageEntity,
+ isBasedOn: {
+ '@type': 'SoftwareSourceCode',
+ 'programmingLanguage': 'python',
+ "text": `import numpy as np
+import matplotlib.pyplot as plt
+
+def plot_sine_waves():
+ """Create a beautiful visualization of sine waves with different frequencies."""
+ # Generate time points
+ t = np.linspace(0, 10, 1000)
+
+ # Create waves with different frequencies and phases
+ wave1 = np.sin(t)
+ wave2 = 0.5 * np.sin(2 * t + np.pi/4)
+ wave3 = 0.3 * np.sin(3 * t + np.pi/3)
+
+ # Combine waves
+ combined = wave1 + wave2 + wave3
+
+ # Create a stylish plot
+ plt.style.use('seaborn-darkgrid')
+ plt.figure(figsize=(12, 8))
+
+ # Plot individual waves
+ plt.plot(t, wave1, label='Primary Wave', alpha=0.5)
+ plt.plot(t, wave2, label='Second Harmonic', alpha=0.5)
+ plt.plot(t, wave3, label='Third Harmonic', alpha=0.5)
+
+ # Plot combined wave with a thicker line
+ plt.plot(t, combined, 'r-',
+ label='Combined Wave',
+ linewidth=2)
+
+ plt.title('Harmonic Wave Composition', fontsize=14)
+ plt.xlabel('Time', fontsize=12)
+ plt.ylabel('Amplitude', fontsize=12)
+ plt.legend()
+ plt.grid(True, alpha=0.3)
+
+ # Show the plot
+ plt.tight_layout()
+ plt.show()
+
+# Generate the visualization
+plot_sine_waves()`
+ }
+ }],
+ id: "a4c0c01d-c06e-4dde-9278-265c607b545b-82",
+ type: "message",
+ text: `This example demonstrates creating a beautiful visualization of harmonic waves using Python's Matplotlib library. The code generates three sine waves with different frequencies and phases, then combines them to show wave interference patterns.\n`,
+ }
]];
const leftStore = testHelpers.createStore();
@@ -557,7 +642,8 @@
TEXT_INPUT_PLACEHOLDER: 'Describe how your copilot should behave'
}}
styleOptions={{
- maxMessageLength: null
+ maxMessageLength: null,
+ ...adjustStyleOptions
}}
/>
@@ -568,12 +654,14 @@
directLine={rightDirectLine}
store={rightStore}
overrideLocalizedStrings={{
- TEXT_INPUT_PLACEHOLDER: 'Ask a work question or use / to reference people, files and more'
+ TEXT_INPUT_PLACEHOLDER: 'Ask a work question or use / to reference people, files and more',
+ ACTIVITY_CODE_CAUTION: 'AI-generated code. Review and use carefully. [More info on FAQ](https://aka.ms/AIandCopilotFAQs).'
}}
styleOptions={{
groupTimestamp: 1,
timestampFormat: 'absolute',
- botAvatarBackgroundColor: '#304E7A'
+ botAvatarBackgroundColor: '#304E7A',
+ ...adjustStyleOptions
}}
/>
@@ -586,30 +674,56 @@
await host.snapshot();
- const sendboxes = Array.from(document.querySelectorAll(`[data-testid="${WebChat.testIds.sendBoxTextBox}"]`)).filter((_, index) => sendBoxIndexes.includes(String(index)));
-
- for (const sendbox of sendboxes) {
- sendbox.focus();
- await host.sendKeys('Next message');
- await host.snapshot();
- await host.sendKeys('ENTER');
- // hide timestamp to not fail snapshot if is not relative
- sendbox.parentElement.parentElement.parentElement.parentElement.querySelector('.webchat__basic-transcript__activity:last-child .webchat__stacked-layout__status').style.opacity = 0
- await host.snapshot();
- await host.sendShiftTab();
- await host.snapshot();
- await host.sendKeys('HOME');
- await host.snapshot();
- await host.sendKeys('END');
- await host.snapshot();
- await host.sendKeys('ARROW_UP');
- await host.snapshot();
- await host.sendKeys('ENTER');
- await host.sendShiftTab();
- await host.snapshot();
- await host.sendKeys('ENTER');
- await host.snapshot();
- await host.sendKeys('ESCAPE');
+ const focusPresetsMap = new Map(Object.entries({
+ navigation: async sendbox => {
+ sendbox.focus();
+ await host.sendKeys('Next message');
+ await host.snapshot();
+ await host.sendKeys('ENTER');
+ // hide timestamp to not fail snapshot if is not relative
+ sendbox.parentElement.parentElement.parentElement.parentElement.querySelector('.webchat__basic-transcript__activity:last-child .webchat__stacked-layout__status').style.opacity = 0
+ await host.snapshot();
+ await host.sendShiftTab();
+ await host.snapshot();
+ await host.sendKeys('HOME');
+ await host.snapshot();
+ await host.sendKeys('END');
+ await host.snapshot();
+ await host.sendKeys('ARROW_UP');
+ await host.snapshot();
+ await host.sendKeys('ENTER');
+ await host.sendShiftTab();
+ await host.snapshot();
+ await host.sendKeys('ENTER');
+ await host.snapshot();
+ await host.sendKeys('ESCAPE');
+ },
+ viewCode: async sendbox => {
+ sendbox.focus();
+ await host.sendShiftTab();
+ await host.sendKeys('ARROW_UP');
+ await host.sendKeys('ENTER');
+ await host.snapshot();
+ await host.sendKeys('ENTER');
+ await host.snapshot();
+ await host.sendKeys('ENTER');
+ await host.snapshot();
+ }
+ }));
+
+ const sendboxes = Array.from(document.querySelectorAll(`[data-testid="${WebChat.testIds.sendBoxTextBox}"]`))
+ .filter((_, index) => sendBoxIndexes.includes(String(index)));
+
+ const focusPresets = activeFocusPresets
+ .map(presetName => focusPresetsMap.get(presetName))
+ .filter(preset => preset)
+
+ if (!focusPresets.length) focusPresets.push(focusPresetsMap.get('navigation'));
+
+ for (const preset of focusPresets) {
+ for (const sendbox of sendboxes) {
+ await preset(sendbox)
+ }
}
});
// TODO: unskip and try ShadowDOM when we get support
diff --git a/__tests__/html/fluentTheme/side-by-side.wide.dark.js b/__tests__/html/fluentTheme/side-by-side.wide.dark.js
index b7a645dec5..464c432f78 100644
--- a/__tests__/html/fluentTheme/side-by-side.wide.dark.js
+++ b/__tests__/html/fluentTheme/side-by-side.wide.dark.js
@@ -14,5 +14,9 @@ describe('Fluent theme applied', () => {
runHTML('fluentTheme/side-by-side.wide.dark?transcript=0&transcript=4'));
test('side by side left - fluent, right - fluent', () =>
runHTML('fluentTheme/side-by-side.wide.dark?transcript=0&transcript=2&focus=1&variant=fluent&variant=fluent'));
+ test('side by side left - transcript, right - codeblock', () =>
+ runHTML('fluentTheme/side-by-side.wide.dark?transcript=0&transcript=5&focus=1&focus-preset=viewCode'));
+ test('side by side left - transcript, right - codeblock dark', () =>
+ runHTML('fluentTheme/side-by-side.wide.dark?transcript=0&transcript=5&focus=1&focus-preset=viewCode&codeBlockTheme=github-dark-default'));
});
});
diff --git a/__tests__/html/fluentTheme/side-by-side.wide.html b/__tests__/html/fluentTheme/side-by-side.wide.html
index d3f116ab62..b1a165a264 100644
--- a/__tests__/html/fluentTheme/side-by-side.wide.html
+++ b/__tests__/html/fluentTheme/side-by-side.wide.html
@@ -82,10 +82,18 @@
let timestampStart = new Date(2020, 7, 9).getTime();
const timestamp = () => new Date(timestampStart += 100).toISOString();
- const [leftTranscriptIndex = 0, rightTranscriptIndex = 1] = new URLSearchParams(location.search).getAll('transcript');
- const [leftVariant = 'fluent', rightVariant = 'copilot'] = new URLSearchParams(location.search).getAll('variant');
- const sendBoxIndexes = new URLSearchParams(location.search).getAll('focus');
+ const searchParams = new URLSearchParams(location.search);
+
+ const [leftTranscriptIndex = 0, rightTranscriptIndex = 1] = searchParams.getAll('transcript');
+ const [leftVariant = 'fluent', rightVariant = 'copilot'] = searchParams.getAll('variant');
+
+ const sendBoxIndexes = searchParams.getAll('focus');
+ const activeFocusPresets = searchParams.getAll('focus-preset');
+
+ const adjustStyleOptions = Object.fromEntries(['codeBlockTheme']
+ .map(key => [key, searchParams.get(key)])
+ .filter(([key, value]) => value));
const botIcon = 'data:image/png;base64,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';
@@ -103,6 +111,27 @@
}
};
+ const waveSvg = `data:image/svg+xml;utf8,${encodeURIComponent(`
+`)}`;
+
const transcripts = [[
{
timestamp: timestamp(),
@@ -520,6 +549,63 @@
streamSequence: 99
}
}
+ ], [
+ {
+ timestamp: timestamp(),
+ from: { role: 'bot' },
+ entities: [{
+ ...aiMessageEntity,
+ isBasedOn: {
+ '@type': 'SoftwareSourceCode',
+ 'programmingLanguage': 'python',
+ "text": `import numpy as np
+import matplotlib.pyplot as plt
+
+def plot_sine_waves():
+ """Create a beautiful visualization of sine waves with different frequencies."""
+ # Generate time points
+ t = np.linspace(0, 10, 1000)
+
+ # Create waves with different frequencies and phases
+ wave1 = np.sin(t)
+ wave2 = 0.5 * np.sin(2 * t + np.pi/4)
+ wave3 = 0.3 * np.sin(3 * t + np.pi/3)
+
+ # Combine waves
+ combined = wave1 + wave2 + wave3
+
+ # Create a stylish plot
+ plt.style.use('seaborn-darkgrid')
+ plt.figure(figsize=(12, 8))
+
+ # Plot individual waves
+ plt.plot(t, wave1, label='Primary Wave', alpha=0.5)
+ plt.plot(t, wave2, label='Second Harmonic', alpha=0.5)
+ plt.plot(t, wave3, label='Third Harmonic', alpha=0.5)
+
+ # Plot combined wave with a thicker line
+ plt.plot(t, combined, 'r-',
+ label='Combined Wave',
+ linewidth=2)
+
+ plt.title('Harmonic Wave Composition', fontsize=14)
+ plt.xlabel('Time', fontsize=12)
+ plt.ylabel('Amplitude', fontsize=12)
+ plt.legend()
+ plt.grid(True, alpha=0.3)
+
+ # Show the plot
+ plt.tight_layout()
+ plt.show()
+
+# Generate the visualization
+plot_sine_waves()`
+ }
+ }],
+ id: "a4c0c01d-c06e-4dde-9278-265c607b545b-82",
+ type: "message",
+ text: `This example demonstrates creating a beautiful visualization of harmonic waves using Python's Matplotlib library. The code generates three sine waves with different frequencies and phases, then combines them to show wave interference patterns.\n`,
+ }
]];
const leftStore = testHelpers.createStore();
@@ -538,7 +624,8 @@
TEXT_INPUT_PLACEHOLDER: 'Describe how your copilot should behave'
}}
styleOptions={{
- maxMessageLength: null
+ maxMessageLength: null,
+ ...adjustStyleOptions
}}
/>
@@ -549,12 +636,14 @@
directLine={rightDirectLine}
store={rightStore}
overrideLocalizedStrings={{
- TEXT_INPUT_PLACEHOLDER: 'Ask a work question or use / to reference people, files and more'
+ TEXT_INPUT_PLACEHOLDER: 'Ask a work question or use / to reference people, files and more',
+ ACTIVITY_CODE_CAUTION: 'AI-generated code. Review and use carefully. [More info on FAQ](https://aka.ms/AIandCopilotFAQs).'
}}
styleOptions={{
groupTimestamp: 1,
timestampFormat: 'absolute',
botAvatarBackgroundColor: '#304E7A',
+ ...adjustStyleOptions
}}
/>
@@ -568,30 +657,56 @@
await host.snapshot();
- const sendboxes = Array.from(document.querySelectorAll(`[data-testid="${WebChat.testIds.sendBoxTextBox}"]`)).filter((_, index) => sendBoxIndexes.includes(String(index)));
-
- for (const sendbox of sendboxes) {
- sendbox.focus();
- await host.sendKeys('Next message');
- await host.snapshot();
- await host.sendKeys('ENTER');
- // hide timestamp to not fail snapshot if is not relative
- sendbox.parentElement.parentElement.parentElement.parentElement.querySelector('.webchat__basic-transcript__activity:last-child .webchat__stacked-layout__status').style.opacity = 0
- await host.snapshot();
- await host.sendShiftTab();
- await host.snapshot();
- await host.sendKeys('HOME');
- await host.snapshot();
- await host.sendKeys('END');
- await host.snapshot();
- await host.sendKeys('ARROW_UP');
- await host.snapshot();
- await host.sendKeys('ENTER');
- await host.sendShiftTab();
- await host.snapshot();
- await host.sendKeys('ENTER');
- await host.snapshot();
- await host.sendKeys('ESCAPE');
+ const focusPresetsMap = new Map(Object.entries({
+ navigation: async sendbox => {
+ sendbox.focus();
+ await host.sendKeys('Next message');
+ await host.snapshot();
+ await host.sendKeys('ENTER');
+ // hide timestamp to not fail snapshot if is not relative
+ sendbox.parentElement.parentElement.parentElement.parentElement.querySelector('.webchat__basic-transcript__activity:last-child .webchat__stacked-layout__status').style.opacity = 0
+ await host.snapshot();
+ await host.sendShiftTab();
+ await host.snapshot();
+ await host.sendKeys('HOME');
+ await host.snapshot();
+ await host.sendKeys('END');
+ await host.snapshot();
+ await host.sendKeys('ARROW_UP');
+ await host.snapshot();
+ await host.sendKeys('ENTER');
+ await host.sendShiftTab();
+ await host.snapshot();
+ await host.sendKeys('ENTER');
+ await host.snapshot();
+ await host.sendKeys('ESCAPE');
+ },
+ viewCode: async sendbox => {
+ sendbox.focus();
+ await host.sendShiftTab();
+ await host.sendKeys('ARROW_UP');
+ await host.sendKeys('ENTER');
+ await host.snapshot();
+ await host.sendKeys('ENTER');
+ await host.snapshot();
+ await host.sendKeys('ENTER');
+ await host.snapshot();
+ }
+ }));
+
+ const sendboxes = Array.from(document.querySelectorAll(`[data-testid="${WebChat.testIds.sendBoxTextBox}"]`))
+ .filter((_, index) => sendBoxIndexes.includes(String(index)));
+
+ const focusPresets = activeFocusPresets
+ .map(presetName => focusPresetsMap.get(presetName))
+ .filter(preset => preset)
+
+ if (!focusPresets.length) focusPresets.push(focusPresetsMap.get('navigation'));
+
+ for (const preset of focusPresets) {
+ for (const sendbox of sendboxes) {
+ await preset(sendbox)
+ }
}
});
// TODO: unskip and try ShadowDOM when we get support
diff --git a/__tests__/html/fluentTheme/side-by-side.wide.js b/__tests__/html/fluentTheme/side-by-side.wide.js
index 690b516590..06f0a39000 100644
--- a/__tests__/html/fluentTheme/side-by-side.wide.js
+++ b/__tests__/html/fluentTheme/side-by-side.wide.js
@@ -13,4 +13,8 @@ describe('Fluent theme applied', () => {
runHTML('fluentTheme/side-by-side.wide?transcript=0&transcript=4'));
test('side by side left - fluent, right - fluent', () =>
runHTML('fluentTheme/side-by-side.wide?transcript=0&transcript=2&focus=1&variant=fluent&variant=fluent'));
+ test('side by side left - transcript, right - codeblock', () =>
+ runHTML('fluentTheme/side-by-side.wide?transcript=0&transcript=5&focus=1&focus-preset=viewCode'));
+ test('side by side left - transcript, right - codeblock dark', () =>
+ runHTML('fluentTheme/side-by-side.wide?transcript=0&transcript=5&focus=1&focus-preset=viewCode&codeBlockTheme=github-dark-default'));
});
diff --git a/packages/api/src/StyleOptions.ts b/packages/api/src/StyleOptions.ts
index 867a493eac..77a7c41687 100644
--- a/packages/api/src/StyleOptions.ts
+++ b/packages/api/src/StyleOptions.ts
@@ -916,6 +916,18 @@ type StyleOptions = {
* New in 4.19.0.
*/
borderAnimationColor3?: string;
+
+ /**
+ * Code block theme
+ *
+ * - `'github-light-default'` - use light theme for code blocks
+ * - `'github-dark-default'` - use dark theme for code blocks
+ *
+ * @default 'github-light-default'
+ *
+ * New in 4.19.0.
+ */
+ codeBlockTheme?: 'github-light-default' | 'github-dark-default';
};
// StrictStyleOptions is only used internally in Web Chat and for simplifying our code:
diff --git a/packages/api/src/defaultStyleOptions.ts b/packages/api/src/defaultStyleOptions.ts
index f797acf47a..ec3147fcbd 100644
--- a/packages/api/src/defaultStyleOptions.ts
+++ b/packages/api/src/defaultStyleOptions.ts
@@ -303,7 +303,9 @@ const DEFAULT_OPTIONS: Required = {
// Border animation
borderAnimationColor1: '#203C91',
borderAnimationColor2: '#4DD3FF',
- borderAnimationColor3: '#2B8DD8'
+ borderAnimationColor3: '#2B8DD8',
+
+ codeBlockTheme: 'github-light-default' as const
};
export default DEFAULT_OPTIONS;
diff --git a/packages/component/src/Attachment/Text/private/ActivityViewCodeButton.tsx b/packages/component/src/Attachment/Text/private/ActivityViewCodeButton.tsx
index 6d6efd09c7..a34be6d48f 100644
--- a/packages/component/src/Attachment/Text/private/ActivityViewCodeButton.tsx
+++ b/packages/component/src/Attachment/Text/private/ActivityViewCodeButton.tsx
@@ -31,10 +31,7 @@ const ViewCodeButton = ({ className, code, language, title = '', isAIGenerated =
{isAIGenerated && (
-
+
)}
diff --git a/packages/component/src/Attachment/Text/private/CodeContent.tsx b/packages/component/src/Attachment/Text/private/CodeContent.tsx
index 262a59f06e..f39c4a2be5 100644
--- a/packages/component/src/Attachment/Text/private/CodeContent.tsx
+++ b/packages/component/src/Attachment/Text/private/CodeContent.tsx
@@ -13,11 +13,12 @@ type Props = Readonly<{
title: string;
}>;
-const { useLocalizer } = hooks;
+const { useLocalizer, useStyleOptions } = hooks;
const highlighterPromise = createHighlighter();
const CodeContent = memo(({ children, className, code, language, title }: Props) => {
+ const [{ codeBlockTheme }] = useStyleOptions();
const [highlightedCode, setHighlightedCode] = useState('');
const localize = useLocalizer();
@@ -35,7 +36,7 @@ const CodeContent = memo(({ children, className, code, language, title }: Props)
try {
const html = highlighter.codeToHtml(code, {
lang: language,
- theme: 'github-light-default'
+ theme: codeBlockTheme
});
setHighlightedCode(html);
@@ -52,7 +53,7 @@ const CodeContent = memo(({ children, className, code, language, title }: Props)
return () => {
mounted = false;
};
- }, [code, language]);
+ }, [code, codeBlockTheme, language]);
return (
diff --git a/packages/component/src/Attachment/Text/private/shiki.ts b/packages/component/src/Attachment/Text/private/shiki.ts
index 5a083989a5..51da75ac95 100644
--- a/packages/component/src/Attachment/Text/private/shiki.ts
+++ b/packages/component/src/Attachment/Text/private/shiki.ts
@@ -1,5 +1,5 @@
// `shiki/core` entry does not include any themes or languages or the wasm binary.
-import { createHighlighterCore } from 'shiki/core';
+import { createHighlighterCore, type ThemeRegistrationRaw } from 'shiki/core';
import { createJavaScriptRegexEngine } from 'shiki/engine-javascript.mjs';
// directly import the theme and language modules, only the ones you imported will be bundled.
@@ -10,13 +10,19 @@ import languageJavaScript from 'shiki/langs/js.mjs';
import languagePython from 'shiki/langs/py.mjs';
import languageTypeScript from 'shiki/langs/ts.mjs';
+function addjustTheme(theme: ThemeRegistrationRaw): ThemeRegistrationRaw {
+ return {
+ ...theme,
+ colors: {
+ ...theme.colors,
+ 'editor.background': `var(--webchat__code-block--background, ${theme.colors['editor.background']})`
+ }
+ };
+}
+
function createHighlighter() {
return createHighlighterCore({
- themes: [
- // instead of strings, you need to pass the imported module
- themeGitHubDark,
- themeGitHubLight
- ],
+ themes: [addjustTheme(themeGitHubDark), addjustTheme(themeGitHubLight)],
langs: [languageJavaScript, languagePython, languageTypeScript],
engine: createJavaScriptRegexEngine()
});
diff --git a/packages/fluent-theme/src/components/theme/Theme.module.css b/packages/fluent-theme/src/components/theme/Theme.module.css
index dffd36ea28..bd88b9edd4 100644
--- a/packages/fluent-theme/src/components/theme/Theme.module.css
+++ b/packages/fluent-theme/src/components/theme/Theme.module.css
@@ -2,7 +2,7 @@
/* biome-ignore format: do not print each class on the new line */
.a, .b, .c, .d, .e, .f, .g, .h, .i, .j, .k, .l, .m, .n, .o, .p, .q, .r, .s, .t, .v, .w, .u, .x, .y, .z,
.A, .B, .C, .D, .E, .F, .G, .H, .I, .J, .K, .L, .M, .N, .O, .P, .Q, .R, .S, .T, .V, .W, .U, .X, .Y, .Z {
- /* biome-ignore lint: esbuild considers empty global classes as used and removes them due to lack of rules */
+ /* esbuild considers empty global classes as used and removes them due to lack of rules */
}
}
@@ -72,6 +72,10 @@
--webchat-colorGray190: var(--colorGray190, #201f1e);
--webchat-colorGray200: var(--colorGray200, #1b1a19);
+ /* New greys from the link above not exposed by Fluent */
+ --webchat-colorGrey8: #141414;
+ --webchat-colorGrey98: #fafafa;
+
/* https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/utils/shadows.ts */
--webchat-shadow2: var(--shadow2, 0 0 2px rgba(0, 0, 0, 12%), 0 1px 2px rgba(0, 0, 0, 14%));
--webchat-shadow4: var(--shadow4, 0 0 2px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.14));
@@ -115,6 +119,7 @@
'Helvetica Neue',
sans-serif
);
+ --webchat-fontFamilyMonospace: var(--fontFamilyMonospace, Consolas, 'Courier New', Courier, monospace);
--webchat-fontFamilyNumeric: var(
--fontFamilyNumeric,
Bahnschrift,
@@ -161,7 +166,7 @@
/* https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/global/strokeWidths.ts */
--webchat-strokeWidthThin: var(--strokeWidthThin, 1px);
- --webchat-strokeWidthThick: var(--strokeWidthThicker, 2px);
+ --webchat-strokeWidthThick: var(--strokeWidthThick, 2px);
--webchat-strokeWidthThicker: var(--strokeWidthThicker, 3px);
/* https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/global/durations.ts */
@@ -217,8 +222,9 @@
padding-inline-start: var(--webchat-spacingHorizontalMNudge);
}
-/* Transcript scrollable */
-:global(.webchat-fluent).theme :global(.webchat__basic-transcript .webchat__basic-transcript__scrollable) {
+/* Scrollbars */
+:global(.webchat-fluent).theme :global(.webchat__basic-transcript .webchat__basic-transcript__scrollable),
+:global(.webchat-fluent).theme :global(.webchat__view-code-dialog__code-body) {
/* Edge uses -webkit-scrollbar if scrollbar-* is not set */
scrollbar-color: unset;
scrollbar-width: unset;
@@ -231,6 +237,10 @@
visibility: hidden;
}
+ &::-webkit-scrollbar-corner {
+ background: transparent;
+ }
+
&:hover::-webkit-scrollbar {
width: var(--webchat-spacingVerticalMNudge);
}
@@ -357,7 +367,7 @@
}
/* TODO: align with original fluent modal styles in WebChat as they don't match v9 anymore */
- :global(.webchat__modal-dialog__close-button):focus:not(:active):hover {
+ :global(.webchat__modal-dialog__close-button):not(:active):hover {
background-color: var(--webchat-colorNeutralBackground3);
}
@@ -378,6 +388,125 @@
}
}
+/* View Code dialog */
+:global(.webchat-fluent).theme :global(.webchat__modal-dialog.webchat__view-code-dialog) {
+ :global(.webchat__modal-dialog__close-button-layout) {
+ display: flex;
+ padding: var(--webchat-spacingVerticalS) var(--webchat-spacingHorizontalS);
+ }
+
+ :global(.webchat__modal-dialog__close-button) {
+ align-items: center;
+ aspect-ratio: 1;
+ display: flex;
+ height: var(--webchat-lineHeightBase300);
+ justify-content: center;
+ padding: 0;
+ width: unset;
+ }
+
+ :global(.webchat__view-code-dialog__copy-button) {
+ background: transparent;
+ border: none;
+ color: var(--webchat-colorNeutralForeground1);
+ height: 20px;
+ margin-block-start: var(--webchat-spacingVerticalS);
+ padding: 0;
+ position: absolute;
+ right: 32px;
+ top: 0;
+ transition: background-color var(--webchat-durationNormal) var(--webchat-curveDecelerateMid);
+ width: 20px;
+
+ :global(.webchat__code-block-copy-button__icon) {
+ background-color: currentColor;
+ }
+
+ &:hover {
+ background: var(--webchat-colorNeutralBackground3);
+ }
+
+ &:active {
+ background: var(--webchat-colorNeutralBackground3);
+ }
+
+ &:focus {
+ outline-color: var(--webchat-colorStrokeFocus2);
+ }
+ }
+
+ :global(.webchat__modal-dialog__box) {
+ width: fit-content;
+ }
+
+ :global(.webchat__modal-dialog__body) {
+ margin: 0;
+ padding: var(--webchat-spacingVerticalS) var(--webchat-spacingHorizontalM);
+ }
+
+ :global(.webchat__view-code-dialog__title) {
+ font-size: var(--webchat-fontSizeBase300);
+ font-weight: var(--webchat-fontWeightSemibold);
+ line-height: var(--webchat-lineHeightBase300);
+ }
+
+ :global(.webchat__view-code-dialog__body) {
+ display: contents;
+ }
+
+ :global(.webchat__view-code-dialog__code-body) {
+ background: var(--webchat__code-block--background);
+ font-family: var(--webchat-fontFamilyMonospace);
+ font-size: var(--webchat-fontSizeBase300);
+ line-height: var(--webchat-fontSizeBase300);
+ margin-inline: calc(var(--webchat-spacingHorizontalM) * -1);
+ padding-inline: var(--webchat-spacingHorizontalM);
+ }
+
+ :global(.webchat__view-code-dialog__code-body:has(.shiki:focus-visible)):focus-within {
+ outline: var(--webchat-strokeWidthThick) solid var(--webchat-colorStrokeFocus2);
+ outline-offset: calc(var(--webchat-strokeWidthThick) * -1);
+
+ :global(.shiki) {
+ outline: none;
+ }
+ }
+
+ :global(.webchat__view-code-dialog__code-body:has(.shiki.github-light-default)) {
+ --webchat__code-block--background: var(--codeBlockBackground, var(--webchat-colorGrey98));
+ }
+
+ :global(.webchat__view-code-dialog__code-body:has(.shiki.github-dark-default)) {
+ --webchat__code-block--background: var(--codeBlockBackground, var(--webchat-colorGrey8));
+ }
+
+ :global(.webchat__view-code-dialog__footer) {
+ color: var(--webchat-colorNeutralForeground4);
+ font-size: var(--webchat-fontSizeBase100);
+ line-height: var(--webchat-lineHeightBase100);
+ }
+
+ :global(.webchat__view-code-dialog__link) {
+ color: var(--webchat-colorBrandForegroundLink);
+ text-decoration-color: transparent;
+
+ &:target {
+ color: var(--webchat-colorBrandForegroundLinkSelected);
+ }
+ &:hover {
+ color: var(--webchat-colorBrandForegroundLinkHover);
+ text-decoration: underline 1px currentColor;
+ }
+ &:active {
+ color: var(--webchat-colorBrandForegroundLinkPressed);
+ }
+ &:focus-visible {
+ outline: none;
+ text-decoration: underline 1px double var(--webchat-colorStrokeFocus2);
+ }
+ }
+}
+
/* Activity button */
:global(.webchat-fluent).theme :global(.webchat__activity-button) {
background: var(--webchat-colorNeutralBackground1);