Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
69a334f
Clean CSS injection
compulim Oct 7, 2025
f88316d
Clean up nonce usage
compulim Oct 7, 2025
2b4cacb
Remove nonce from <ThemeProvider>
compulim Oct 7, 2025
d590d10
Rename <WebChatTheme> to <Inject*CSS>
compulim Oct 8, 2025
14ebc9a
Clean up
compulim Oct 8, 2025
a741a60
Add comment
compulim Oct 8, 2025
1a74333
Add comment
compulim Oct 8, 2025
b890931
Fix identifier
compulim Oct 8, 2025
bfd5f2d
Remove nonce requirement
compulim Oct 8, 2025
1c606e9
Direct inject after building style elements
compulim Oct 9, 2025
474af5a
Add entry
compulim Oct 9, 2025
67600b7
Remove launcher experience
compulim Oct 9, 2025
30aaac5
Fix imports
compulim Oct 9, 2025
948bf37
Fix imports
compulim Oct 9, 2025
1c9e842
Fix tests
compulim Oct 9, 2025
4bfc718
Better imports
compulim Oct 9, 2025
7b2f79f
Use Happy DOM
compulim Oct 9, 2025
0016d4c
Return children as-is
compulim Oct 9, 2025
6f13288
Merge branch 'main' into feat-clean-up-theme-provider
compulim Oct 9, 2025
9399590
Remove unnecessary files
compulim Oct 9, 2025
a986552
Dedupe across instances
compulim Oct 9, 2025
4bd60d9
Add test
compulim Oct 9, 2025
3559026
Use hooks
compulim Oct 9, 2025
fd4ae05
Mvoe from hook to leaf node
compulim Oct 9, 2025
382ba4b
Move to create CSS function
compulim Oct 10, 2025
3170c13
Fix tsup
compulim Oct 10, 2025
e23d3b3
Allow rectifying twice
compulim Oct 10, 2025
41066ad
Mark nonce as optional
compulim Oct 10, 2025
b60ae40
Reverse order
compulim Oct 10, 2025
e44e898
Add component
compulim Oct 10, 2025
74b2dde
Add /component
compulim Oct 10, 2025
7f65a52
Remove snapshots
compulim Oct 10, 2025
acba8f0
Fix script-0.mjs
compulim Oct 10, 2025
f45fc60
Fix script-0.mjs
compulim Oct 10, 2025
8b4e058
Fix styleOptions
compulim Oct 10, 2025
d361f11
Allow cascaded rectify style options
compulim Oct 11, 2025
c27f54e
Separate stylesRoot from fluent-theme
compulim Oct 11, 2025
8ccf86a
Mark stylesRoot as optional
compulim Oct 11, 2025
8264448
Componentize <InjectStyleElements>
compulim Oct 11, 2025
5ddcf8c
Fix --watch 200
compulim Oct 11, 2025
68ad21f
Fix flakiness
compulim Oct 11, 2025
ac14353
Fix test
compulim Oct 11, 2025
0f96477
Fix test
compulim Oct 11, 2025
15b68c3
Fix --watch 200
compulim Oct 11, 2025
7b10338
Move stylesheet to bottommost on re-inject
compulim Oct 11, 2025
597141b
Fix hideScrollToEndButton
compulim Oct 11, 2025
6a5fc7b
Fix hideScrollToEndButton
compulim Oct 11, 2025
c7b2465
Clean up
compulim Oct 12, 2025
b7e5c80
Clean up
compulim Oct 12, 2025
75ddff7
Clean up
compulim Oct 12, 2025
ae1c734
Rename *CSS -> *Stylesheet
compulim Oct 12, 2025
8693e87
Componentize as <FluentThemeStylesheet>
compulim Oct 12, 2025
2c0dbeb
Merge branch 'main' into feat-clean-up-theme-provider
compulim Oct 12, 2025
7b14061
Rename to <CSSCustomPropertiesContainer>
compulim Oct 12, 2025
d8899c7
Fix tests
compulim Oct 12, 2025
015793b
Fix styleRoots and import hooks
compulim Oct 12, 2025
58aec61
Add importmap for hook
compulim Oct 12, 2025
a461ee0
Merge branch 'main' into feat-clean-up-theme-provider
compulim Oct 13, 2025
e4c0709
Move InjectStyleElements to styles package
compulim Oct 14, 2025
77aba36
Yellow instead of white
compulim Oct 14, 2025
55274ef
Add styles as devDependencies
compulim Oct 14, 2025
fb6c67f
Fix import map
compulim Oct 14, 2025
fa184dc
Retrigger checks
compulim Oct 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ Notes: web developers are advised to use [`~` (tilde range)](https://github.com/
- `import { hooks } from 'botframework-webchat'` should be replaced by `import * as hooks from 'botframework-webchat/hook'`
- Added target to Chrome 100 and re-enable Lightning CSS for ESM builds, by [@compulim](https://github.com/compulim) in PR [#5602](https://github.com/microsoft/BotFramework-WebChat/pull/5602)
- Relaxed `role` prop to allow any string instead of ARIA landmark roles, in PR [#5561](https://github.com/microsoft/BotFramework-WebChat/pull/5561), by [@compulim](https://github.com/compulim)
- Cleaned up `<ThemeProvider>` and various CSS related code, in PR [#5611](https://github.com/microsoft/BotFramework-WebChat/pull/5611), by [@compulim](https://github.com/compulim)

### Changed

Expand Down
Binary file not shown.
2 changes: 1 addition & 1 deletion __tests__/html/fluentTheme/customElement/shadowRoot.html
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
);

render(
<FluentThemeProvider>
<FluentThemeProvider nonce="test" stylesRoot={this.shadowRoot}>
<App />
</FluentThemeProvider>,
container
Expand Down
5 changes: 0 additions & 5 deletions __tests__/html/hooks.useInjectStyles.changeNonce.js

This file was deleted.

5 changes: 0 additions & 5 deletions __tests__/html/hooks.useInjectStyles.changeRoot.js

This file was deleted.

5 changes: 0 additions & 5 deletions __tests__/html/hooks.useInjectStyles.dupeElement.js

This file was deleted.

5 changes: 0 additions & 5 deletions __tests__/html/hooks.useInjectStyles.js

This file was deleted.

5 changes: 0 additions & 5 deletions __tests__/html/hooks.useInjectStyles.link.js

This file was deleted.

8 changes: 5 additions & 3 deletions __tests__/html2/activity/message-status.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
"@fluentui/tokens": "https://esm.sh/@fluentui/tokens?deps=react@18&exports=createDarkTheme,webLightTheme",
"@testduet/wait-for": "https://unpkg.com/@testduet/wait-for@main/dist/wait-for.mjs",
"botframework-webchat": "/__dist__/packages/bundle/static/botframework-webchat.js",
"botframework-webchat/component": "/__dist__/packages/bundle/static/botframework-webchat/component.js",
"botframework-webchat/decorator": "/__dist__/packages/bundle/static/botframework-webchat/decorator.js",
"botframework-webchat/hook": "/__dist__/packages/bundle/static/botframework-webchat/hook.js",
"botframework-webchat/internal": "/__dist__/packages/bundle/static/botframework-webchat/internal.js",
"botframework-webchat-fluent-theme": "/__dist__/packages/fluent-theme/static/botframework-webchat-fluent-theme.js",
"react": "https://esm.sh/react@18",
Expand Down Expand Up @@ -57,7 +59,7 @@

// TODO: This is for `createDirectLineEmulator` only, should find ways to eliminate this line.
window.WebChat = { createStoreWithOptions };

run(async function () {
const { directLine, store } = createDirectLineEmulator();

Expand Down Expand Up @@ -276,7 +278,7 @@
author
}]
});

await pageConditions.numActivitiesShown(6);
await host.snapshot('local');

Expand Down Expand Up @@ -362,4 +364,4 @@
</script>
</body>

</html>
</html>
6 changes: 4 additions & 2 deletions __tests__/html2/citation/url.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@
"@fluentui/tokens": "https://esm.sh/@fluentui/tokens?deps=react@18&exports=createDarkTheme,webLightTheme",
"@testduet/wait-for": "https://unpkg.com/@testduet/wait-for@main/dist/wait-for.mjs",
"botframework-webchat": "/__dist__/packages/bundle/static/botframework-webchat.js",
"botframework-webchat/component": "/__dist__/packages/bundle/static/botframework-webchat/component.js",
"botframework-webchat/decorator": "/__dist__/packages/bundle/static/botframework-webchat/decorator.js",
"botframework-webchat/internal": "/__dist__/packages/bundle/static/botframework-webchat/internal.js",
"botframework-webchat/hook": "/__dist__/packages/bundle/static/botframework-webchat/hook.js",
"botframework-webchat-fluent-theme": "/__dist__/packages/fluent-theme/static/botframework-webchat-fluent-theme.js",
"react": "https://esm.sh/react@18",
"react-dom": "https://esm.sh/react-dom@18",
Expand Down Expand Up @@ -334,10 +336,10 @@
'mailto:support+roadmap@example.com?subject=Roadmap%20Review%20%5BTemplate%5D&body=Please%20review%20slide%203.%0AThanks%21',
'https://example.sharepoint.com/sites/Docs/Q1%231%20Plan.pptx'
]);

await host.snapshot('local');
});
</script>
</body>

</html>
</html>
3 changes: 2 additions & 1 deletion __tests__/html2/fluentTheme/carousel.html
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
// Verify the sent message
await pageConditions.numActivitiesShown(1);
await pageConditions.allOutgoingActivitiesSent();
await pageConditions.allImagesLoaded();
await host.snapshot('local');

// Wait for and verify bot response
Expand All @@ -73,4 +74,4 @@
</script>
</body>

</html>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,26 @@
<script crossorigin="anonymous" src="/test-page-object.js"></script>
<script crossorigin="anonymous" src="/__dist__/webchat-es5.js"></script>
<meta http-equiv="content-security-policy" content="style-src-elem 'nonce-1'" />
<style nonce="1">
main {
background-color: Yellow!important;
}
</style>
</head>
<body>
<main id="webchat"></main>
<script type="text/babel" data-presets="env,stage-3,react">
const {
testHelpers: { createDirectLineEmulator },
WebChat: {
Components: { Composer },
internal: { useInjectStyles }
internal: { InjectStyleElements }
}
} = window;

function createStyle(body) {
const styleElement = document.createElement('style');

styleElement.dataset['testid'] = 'style';
styleElement.innerHTML = body;

return styleElement;
Expand All @@ -33,41 +38,48 @@
async function () {
const { directLine, store } = createDirectLineEmulator();

const RunFunction = ({ fn }) => {
fn();

return false;
};

const renderWithFunction = fn =>
const render = ({ nonce, styleElements, stylesRoot }) =>
new Promise(resolve =>
ReactDOM.render(
<Composer directLine={directLine} store={store}>
<RunFunction fn={() => resolve(fn && fn())} key={Date.now() + ''} />
</Composer>,
document.getElementById('webchat')
<InjectStyleElements at={stylesRoot} nonce={nonce} styleElements={styleElements} />,
document.getElementById('webchat'),
resolve
)
);

const styleElement = createStyle('main { background-color: Red!important; }');

await renderWithFunction(() => useInjectStyles([styleElement], '1'));
await host.snapshot();
// WHEN: Inject with nonce of "1".
await render({ nonce: '1', styleElements: [styleElement] });

const allInjectedStyles1 = document.head.querySelectorAll('style:not([data-emotion]):not([data-webchat-injected])');
Comment thread
OEvgeny marked this conversation as resolved.
// THEN: Should render in red color.
await host.snapshot('local');

// THEN: The cloned/injected style should be the last child.
expect(document.head.lastChild).toHaveProperty('textContent', styleElement.textContent);

// THEN: Only one <style> element is added.
const allInjectedStyles1 = document.head.querySelectorAll('style[data-testid="style"]');

expect(allInjectedStyles1).toHaveLength(1);
expect(allInjectedStyles1[0]).toBe(styleElement);
expect(allInjectedStyles1[0]).toHaveProperty('textContent', styleElement.textContent);
expect(allInjectedStyles1[0].getAttribute('nonce')).toBe('1');

// WHEN: Inject with nonce of "2".
await render({ nonce: '2', styleElements: [styleElement] });

await renderWithFunction(() => useInjectStyles([styleElement], '2'));
// THEN: No color should be applied as nonce don't match.
await host.snapshot('local');

// No color should be applied as nonce don't match.
await host.snapshot();
// THEN: The cloned/injected style should be the last child.
expect(document.head.lastChild).toHaveProperty('textContent', styleElement.textContent);

const allInjectedStyles2 = document.head.querySelectorAll('style:not([data-emotion]):not([data-webchat-injected])');
// THEN: Only one <style> element is added.
const allInjectedStyles2 = document.head.querySelectorAll('style[data-testid="style"]');

expect(allInjectedStyles2).toHaveLength(1);
expect(allInjectedStyles2[0]).toBe(styleElement);
expect(allInjectedStyles2[0]).toHaveProperty('textContent', styleElement.textContent);
expect(allInjectedStyles2[0].getAttribute('nonce')).toBe('2');
},
{ ignoreErrors: 'violate the following Content Security Policy directive' }
);
Expand Down
77 changes: 77 additions & 0 deletions __tests__/html2/hooks/useInjectStylesElements/changeRoot.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<!doctype html>
<html lang="en-US">
<head>
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
<script crossorigin="anonymous" src="https://unpkg.com/@babel/standalone@7.8.7/babel.min.js"></script>
<script crossorigin="anonymous" src="https://unpkg.com/react@16.8.6/umd/react.development.js"></script>
<script crossorigin="anonymous" src="https://unpkg.com/react-dom@16.8.6/umd/react-dom.development.js"></script>
<script crossorigin="anonymous" src="/test-harness.js"></script>
<script crossorigin="anonymous" src="/test-page-object.js"></script>
<script crossorigin="anonymous" src="/__dist__/webchat-es5.js"></script>
</head>
<body>
<main id="webchat"></main>
<script type="text/babel" data-presets="env,stage-3,react">
const {
testHelpers: { createDirectLineEmulator },
WebChat: {
internal: { InjectStyleElements }
}
} = window;

function createStyle(body) {
const styleElement = document.createElement('style');

styleElement.dataset['testid'] = 'style';
styleElement.innerHTML = body;

return styleElement;
}

run(async function () {
const { directLine, store } = createDirectLineEmulator();

const render = ({ nonce, styleElements, stylesRoot }) =>
new Promise(resolve =>
ReactDOM.render(
<InjectStyleElements at={stylesRoot} nonce={nonce} styleElements={styleElements} />,
document.getElementById('webchat'),
resolve
)
);

const styleElement = createStyle('main { background-color: Red!important; }');

// WHEN: Inject into default (document.head).
await render({ styleElements: [styleElement] });

// THEN: Should render red.
await host.snapshot('local');

// THEN: Should inject into document.head.
const styleElementsInHead = document.head.querySelectorAll('style[data-testid="style"]');

expect(styleElementsInHead).toHaveLength(1);
expect(styleElementsInHead[0]).toHaveProperty('textContent', styleElement.textContent);

// THEN: Should not inject into document.body.
expect(document.body.querySelectorAll('style[data-testid="style"]')).toHaveLength(0);

// WHEN: Inject into document.body.
await render({ styleElements: [styleElement], stylesRoot: document.body });

// THEN: Should render red.
await host.snapshot('local');

// THEN: Should inject into document.body.
const styleElementsInBody = document.body.querySelectorAll('style[data-testid="style"]');

expect(styleElementsInBody).toHaveLength(1);
expect(styleElementsInBody[0]).toHaveProperty('textContent', styleElement.textContent);

// THEN: Should not inject into document.head.
expect(document.head.querySelectorAll('style[data-testid="style"]')).toHaveLength(0);
});
</script>
</body>
</html>
91 changes: 91 additions & 0 deletions __tests__/html2/hooks/useInjectStylesElements/dupeElement.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<!doctype html>
<html lang="en-US">
<head>
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
<script crossorigin="anonymous" src="https://unpkg.com/@babel/standalone@7.8.7/babel.min.js"></script>
<script crossorigin="anonymous" src="https://unpkg.com/react@16.8.6/umd/react.development.js"></script>
<script crossorigin="anonymous" src="https://unpkg.com/react-dom@16.8.6/umd/react-dom.development.js"></script>
<script crossorigin="anonymous" src="/test-harness.js"></script>
<script crossorigin="anonymous" src="/test-page-object.js"></script>
<script crossorigin="anonymous" src="/__dist__/webchat-es5.js"></script>
<style>
main {
background-color: Yellow !important;
}
</style>
</head>
<body>
<main id="webchat"></main>
<script type="text/babel" data-presets="env,stage-3,react">
const {
testHelpers: { createDirectLineEmulator },
WebChat: {
internal: { InjectStyleElements }
}
} = window;

function createStyle(body) {
const styleElement = document.createElement('style');

styleElement.dataset['testid'] = 'style';
styleElement.innerHTML = body;

return styleElement;
}

run(async function () {
const { directLine, store } = createDirectLineEmulator();

const render = ({ nonce, styleElements, stylesRoot }) =>
new Promise(resolve =>
ReactDOM.render(
<InjectStyleElements at={stylesRoot} nonce={nonce} styleElements={styleElements} />,
document.getElementById('webchat'),
resolve
)
);

const styleElement = createStyle('main { background-color: Red!important; }');

await render({ styleElements: [styleElement, styleElement] });

// THEN: Should render in red.
await host.snapshot('local');

const allInjectedStyles1 = document.head.querySelectorAll('style[data-testid="style"]');

expect(allInjectedStyles1).toHaveLength(1);
expect(allInjectedStyles1[0]).toHaveProperty('textContent', styleElement.textContent);

await render({ styleElements: [styleElement, styleElement] });

// THEN: Should render in red.
await host.snapshot('local');

const allInjectedStyles2 = document.head.querySelectorAll('style[data-testid="style"]');

expect(allInjectedStyles2).toHaveLength(1);
expect(allInjectedStyles2[0]).toHaveProperty('textContent', styleElement.textContent);

await render({ styleElements: [styleElement] });

// THEN: Should render in red.
await host.snapshot('local');

const allInjectedStyles3 = document.head.querySelectorAll('style[data-testid="style"]');

expect(allInjectedStyles3).toHaveLength(1);
expect(allInjectedStyles3[0]).toHaveProperty('textContent', styleElement.textContent);

await render({ styleElements: [] });

// THEN: Should render in white because all stylesheet should have been removed.
await host.snapshot('local');

const allInjectedStyles4 = document.head.querySelectorAll('style[data-testid="style"]');

expect(allInjectedStyles4).toHaveLength(0);
});
</script>
</body>
</html>
Comment thread
compulim marked this conversation as resolved.
File renamed without changes
Loading
Loading