diff --git a/CHANGELOG.md b/CHANGELOG.md index 58064fcd3f..0af672a111 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -313,7 +313,10 @@ Breaking changes in this release: - Bumped Chrome in Docker to 141 from 110, in PR [#5619](https://github.com/microsoft/BotFramework-WebChat/pull/5619), by [@compulim](https://github.com/compulim) - Bumped to [`valibot@1.2.0`](https://npmjs.com/package/valibot/v/1.2.0), in PR [#5650](https://github.com/microsoft/BotFramework-WebChat/pull/5650), by [@compulim](https://github.com/compulim) - Pinned to [`botframework-directlinespeech-sdk@4.18.1-main.20251208.8ccadd6`](https://npmjs.com/package/botframework-directlinespeech-sdk/v/4.18.1-main.20251208.8ccadd6), by [@OEvgeny](https://github.com/OEvgeny) in PR [#5662](https://github.com/microsoft/BotFramework-WebChat/pull/5662) -- Converted remaining activity components to CSS Modules, in PR [#5668](https://github.com/microsoft/BotFramework-WebChat/pull/5668), in PR [#5669](https://github.com/microsoft/BotFramework-WebChat/pull/5669), by [@OEvgeny](https://github.com/OEvgeny) +- Converted activity components to CSS Modules + - Bubble, carousel, say-alt, in PR [#5668](https://github.com/microsoft/BotFramework-WebChat/pull/5668), by [@OEvgeny](https://github.com/OEvgeny) + - Activity status, in PR [#5669](https://github.com/microsoft/BotFramework-WebChat/pull/5669), by [@OEvgeny](https://github.com/OEvgeny) + - Text attachment and related components, in PR [#5670](https://github.com/microsoft/BotFramework-WebChat/pull/5670), by [@OEvgeny](https://github.com/OEvgeny) ### Deprecated diff --git a/__tests__/html2/activity/citation.longRef.html b/__tests__/html2/activity/citation.longRef.html index d7c2269f16..14bff48258 100644 --- a/__tests__/html2/activity/citation.longRef.html +++ b/__tests__/html2/activity/citation.longRef.html @@ -53,7 +53,7 @@ await host.snapshot('local'); - const markdownElement = pageElements.activities()[0].querySelector('.webchat__text-content__markdown'); + const markdownElement = pageElements.activities()[0].querySelector('.text-content__markdown'); const markdownLinks = markdownElement.querySelectorAll('a'); const markdownButtons = markdownElement.querySelectorAll('button'); diff --git a/__tests__/html2/basic/customIcons.html b/__tests__/html2/basic/customIcons.html index 9d060800d3..f875c9b113 100644 --- a/__tests__/html2/basic/customIcons.html +++ b/__tests__/html2/basic/customIcons.html @@ -39,11 +39,11 @@ --webchat__fluent-icon--mask: var(--icon); } - #webchat .webchat__activity-button .component-icon.icon--view-code { + #webchat .activity-button .component-icon.icon--view-code { --webchat__component-icon--mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M8 17.308L2.692 12L8 6.692l.714.714l-4.6 4.6L8.708 16.6zm8 0l-.713-.714l4.6-4.6L15.292 7.4L16 6.692L21.308 12z'/%3E%3C/svg%3E"); } - #webchat .webchat__activity-button .component-icon.icon--copy { + #webchat .activity-button .component-icon.icon--copy { --webchat__component-icon--mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M9.116 17q-.691 0-1.153-.462T7.5 15.385V4.615q0-.69.463-1.153T9.116 3h7.769q.69 0 1.153.462t.462 1.153v10.77q0 .69-.462 1.152T16.884 17zm0-1h7.769q.23 0 .423-.192t.192-.423V4.615q0-.23-.192-.423T16.884 4H9.116q-.231 0-.424.192t-.192.423v10.77q0 .23.192.423t.423.192m-3 4q-.69 0-1.153-.462T4.5 18.385V6.615h1v11.77q0 .23.192.423t.423.192h8.77v1zM8.5 16V4z'/%3E%3C/svg%3E"); } diff --git a/__tests__/html2/citation/basic.html b/__tests__/html2/citation/basic.html index 19919bac67..06362a9487 100644 --- a/__tests__/html2/citation/basic.html +++ b/__tests__/html2/citation/basic.html @@ -44,7 +44,7 @@ await host.snapshot('local'); - const markdownElement = pageElements.activities()[0].querySelector('.webchat__text-content__markdown'); + const markdownElement = pageElements.activities()[0].querySelector('.text-content__markdown'); const markdownLinks = markdownElement.querySelectorAll('a'); const markdownButtons = markdownElement.querySelectorAll('button'); diff --git a/__tests__/html2/citation/claimInterpreter/dangerousLink.html b/__tests__/html2/citation/claimInterpreter/dangerousLink.html index 908ea753ec..934b440174 100644 --- a/__tests__/html2/citation/claimInterpreter/dangerousLink.html +++ b/__tests__/html2/citation/claimInterpreter/dangerousLink.html @@ -57,7 +57,7 @@ await host.snapshot('local'); - const markdownElement = pageElements.activities()[0].querySelector('.webchat__text-content__markdown'); + const markdownElement = pageElements.activities()[0].querySelector('.text-content__markdown'); const markdownLinks = markdownElement.querySelectorAll('a'); // The javascript: shouldn't be a link. diff --git a/__tests__/html2/citation/markdownPreferredOverEntities.html b/__tests__/html2/citation/markdownPreferredOverEntities.html index d220ff39a8..dacfd6f89e 100644 --- a/__tests__/html2/citation/markdownPreferredOverEntities.html +++ b/__tests__/html2/citation/markdownPreferredOverEntities.html @@ -78,7 +78,7 @@ await host.snapshot('local'); - const markdownElement = pageElements.activities()[0].querySelector('.webchat__text-content__markdown'); + const markdownElement = pageElements.activities()[0].querySelector('.text-content__markdown'); const markdownClickableLinks = markdownElement.querySelectorAll('a[href]'); // The javascript: shouldn't be a link. diff --git a/__tests__/html2/citation/showModal.close.button.html b/__tests__/html2/citation/showModal.close.button.html index f6b12539c6..27bb2916cc 100644 --- a/__tests__/html2/citation/showModal.close.button.html +++ b/__tests__/html2/citation/showModal.close.button.html @@ -41,7 +41,7 @@ type: 'message' }); - const markdownElement = pageElements.activities()[0].querySelector('.webchat__text-content__markdown'); + const markdownElement = pageElements.activities()[0].querySelector('.text-content__markdown'); const markdownButtons = markdownElement.querySelectorAll('button'); await host.click(markdownButtons[0]); diff --git a/__tests__/html2/citation/showModal.close.escape.html b/__tests__/html2/citation/showModal.close.escape.html index 9391d3782e..3a126fc3e6 100644 --- a/__tests__/html2/citation/showModal.close.escape.html +++ b/__tests__/html2/citation/showModal.close.escape.html @@ -41,7 +41,7 @@ type: 'message' }); - const markdownElement = pageElements.activities()[0].querySelector('.webchat__text-content__markdown'); + const markdownElement = pageElements.activities()[0].querySelector('.text-content__markdown'); const markdownButtons = markdownElement.querySelectorAll('button'); await host.click(markdownButtons[0]); diff --git a/__tests__/html2/citation/showModal.markdown.html b/__tests__/html2/citation/showModal.markdown.html index b8e72f773c..355e2010ef 100644 --- a/__tests__/html2/citation/showModal.markdown.html +++ b/__tests__/html2/citation/showModal.markdown.html @@ -42,7 +42,7 @@ type: 'message' }); - const markdownElement = pageElements.activities()[0].querySelector('.webchat__text-content__markdown'); + const markdownElement = pageElements.activities()[0].querySelector('.text-content__markdown'); const markdownButtons = markdownElement.querySelectorAll('button'); await host.click(markdownButtons[0]); diff --git a/__tests__/html2/citation/showModal.width.desktop.html b/__tests__/html2/citation/showModal.width.desktop.html index 914c293eb4..9ca7b39e7d 100644 --- a/__tests__/html2/citation/showModal.width.desktop.html +++ b/__tests__/html2/citation/showModal.width.desktop.html @@ -44,7 +44,7 @@ await host.snapshot('local'); - const markdownElement = pageElements.activities()[0].querySelector('.webchat__text-content__markdown'); + const markdownElement = pageElements.activities()[0].querySelector('.text-content__markdown'); const markdownButtons = markdownElement.querySelectorAll('button'); await host.click(markdownButtons[0]); diff --git a/__tests__/html2/citation/showModal.width.mobile.html b/__tests__/html2/citation/showModal.width.mobile.html index 0e2edade51..24287d1785 100644 --- a/__tests__/html2/citation/showModal.width.mobile.html +++ b/__tests__/html2/citation/showModal.width.mobile.html @@ -43,7 +43,7 @@ await host.snapshot('local'); - const markdownElement = pageElements.activities()[0].querySelector('.webchat__text-content__markdown'); + const markdownElement = pageElements.activities()[0].querySelector('.text-content__markdown'); const markdownButtons = markdownElement.querySelectorAll('button'); await host.click(markdownButtons[0]); diff --git a/__tests__/html2/citation/url.html b/__tests__/html2/citation/url.html index 0fe3bf8899..780978635a 100644 --- a/__tests__/html2/citation/url.html +++ b/__tests__/html2/citation/url.html @@ -324,7 +324,7 @@ ] }); - expect(Array.from(document.querySelectorAll('.webchat__render-markdown a')).map(a => a.href)).toEqual([ + expect(Array.from(document.querySelectorAll('.render-markdown a')).map(a => a.href)).toEqual([ 'https://example.sharepoint.com/sites/Docs/2025%20Product%20Area%20Review%20%5BTemplate%5D.pptx', 'https://example.sharepoint.com/sites/Docs/2025%20Product%20Area%20Review%20%5BTemplate%5D.pptx', 'https://files.example.com/search?tags%5B%5D=a&tags%5B%5D=a%2Fb&redirect=https%3A%2F%2Fexample.com%2Fx%3Fy%3Dz', diff --git a/__tests__/html2/copyButton/behavior.html b/__tests__/html2/copyButton/behavior.html index d2fa06f703..6ad3bf96d5 100644 --- a/__tests__/html2/copyButton/behavior.html +++ b/__tests__/html2/copyButton/behavior.html @@ -24,7 +24,7 @@ const App = () => ( -
+
diff --git a/__tests__/html2/hooks/useRenderMarkdownAsHTML.custom.html b/__tests__/html2/hooks/useRenderMarkdownAsHTML.custom.html index 64f07259e4..dda1e3c3df 100644 --- a/__tests__/html2/hooks/useRenderMarkdownAsHTML.custom.html +++ b/__tests__/html2/hooks/useRenderMarkdownAsHTML.custom.html @@ -40,12 +40,12 @@ const renderMarkdownAsHTML = await renderHook(() => useRenderMarkdownAsHTML()); const actual = renderMarkdownAsHTML('Hello, World!').replace( - /webchat--css-[\d\w]*-[\d\w]*/u, - 'webchat--css-xxxxx-xxxxx' + /w[\d\w\-]{6}_/gu, + 'wxxxxxx_' ); expect(actual).toBe( - '

HELLO, WORLD!

' + '

HELLO, WORLD!

' ); }); diff --git a/__tests__/html2/hooks/useRenderMarkdownAsHTML.default.html b/__tests__/html2/hooks/useRenderMarkdownAsHTML.default.html index d51e5d26b4..a478d35498 100644 --- a/__tests__/html2/hooks/useRenderMarkdownAsHTML.default.html +++ b/__tests__/html2/hooks/useRenderMarkdownAsHTML.default.html @@ -36,12 +36,12 @@ const renderMarkdownAsHTML = await renderHook(() => useRenderMarkdownAsHTML()); const actual = renderMarkdownAsHTML('Hello, World!').replace( - /webchat--css-[\d\w]*-[\d\w]*/u, - 'webchat--css-xxxxx-xxxxx' + /w[\d\w\-]{6}_/gu, + 'wxxxxxx_' ); expect(actual).toBe( - '

Hello, World!

' + '

Hello, World!

' ); }); diff --git a/__tests__/html2/hooks/useRenderMarkdownAsHTML.externalLink.html b/__tests__/html2/hooks/useRenderMarkdownAsHTML.externalLink.html index 11d7942dff..66227b007e 100644 --- a/__tests__/html2/hooks/useRenderMarkdownAsHTML.externalLink.html +++ b/__tests__/html2/hooks/useRenderMarkdownAsHTML.externalLink.html @@ -36,12 +36,12 @@ const renderMarkdownAsHTML = await renderHook(() => useRenderMarkdownAsHTML()); const actual = renderMarkdownAsHTML('Click [here](https://aka.ms/) to find out more.').replace( - /webchat--css-[\d\w]*-[\d\w]*/u, - 'webchat--css-xxxxx-xxxxx' + /w[\d\w\-]{6}_/gu, + 'wxxxxxx_' ); expect(actual).toBe( - `

Click \u200Bhere\u200B to find out more.

` + `

Click \u200Bhere\u200B to find out more.

` ); }); diff --git a/__tests__/html2/hooks/useRenderMarkdownAsHTML.externalLink.yue.html b/__tests__/html2/hooks/useRenderMarkdownAsHTML.externalLink.yue.html index 24fe89ac6f..75599e408a 100644 --- a/__tests__/html2/hooks/useRenderMarkdownAsHTML.externalLink.yue.html +++ b/__tests__/html2/hooks/useRenderMarkdownAsHTML.externalLink.yue.html @@ -40,12 +40,12 @@ const renderMarkdownAsHTML = await renderHook(() => useRenderMarkdownAsHTML()); const actual = renderMarkdownAsHTML('Click [here](https://aka.ms/) to find out more.').replace( - /webchat--css-[\d\w]*-[\d\w]*/u, - 'webchat--css-xxxxx-xxxxx' + /w[\d\w\-]{6}_/gu, + 'wxxxxxx_' ); expect(actual).toBe( - `

Click \u200Bhere\u200B to find out more.

` + `

Click \u200Bhere\u200B to find out more.

` ); }); diff --git a/__tests__/html2/linkDefinition/badge.html b/__tests__/html2/linkDefinition/badge.html index b27e15b997..d410cf435e 100644 --- a/__tests__/html2/linkDefinition/badge.html +++ b/__tests__/html2/linkDefinition/badge.html @@ -180,57 +180,57 @@ const [firstActivityElement] = pageElements.activities(); - const linkDefinitions = firstActivityElement.querySelectorAll('.webchat__link-definitions__list-item'); + const linkDefinitions = firstActivityElement.querySelectorAll('.link-definitions__list-item'); expect(linkDefinitions).toHaveProperty('length', 5); - expect(linkDefinitions[0].querySelector('.webchat__link-definitions__list-item-box').tagName).toBe('A'); + expect(linkDefinitions[0].querySelector('.link-definitions__list-item-box').tagName).toBe('A'); expect( - linkDefinitions[0].querySelector('.webchat__link-definitions__list-item-text').getAttribute('title') + linkDefinitions[0].querySelector('.link-definitions__list-item-text').getAttribute('title') ).toBe('Sint amet id officia dolor ex eiusmod ipsum ipsum magna fugiat'); expect( - linkDefinitions[0].querySelector('.webchat__link-definitions__list-item-badge').getAttribute('title') + linkDefinitions[0].querySelector('.link-definitions__list-item-badge').getAttribute('title') ).toBe( 'Sit veniam do irure velit est et quis ut Lorem reprehenderit commodo cillum occaecat\n\nNisi quis ut sint elit est nulla enim eiusmod. Deserunt commodo pariatur nostrud culpa aliquip esse pariatur exercitation nulla do proident. Est qui eiusmod aliquip deserunt labore consequat fugiat. Ullamco reprehenderit nostrud eiusmod nisi nulla esse id. Reprehenderit aliqua quis consectetur sit cupidatat fugiat Lorem ex labore. Eiusmod velit laborum quis tempor incididunt excepteur culpa esse nulla.' ); - expect(linkDefinitions[1].querySelector('.webchat__link-definitions__list-item-box').tagName).toBe('A'); + expect(linkDefinitions[1].querySelector('.link-definitions__list-item-box').tagName).toBe('A'); expect( - linkDefinitions[1].querySelector('.webchat__link-definitions__list-item-text').getAttribute('title') + linkDefinitions[1].querySelector('.link-definitions__list-item-text').getAttribute('title') ).toBe('Laboris cupidatat voluptate'); - expect(linkDefinitions[1].querySelector('.webchat__link-definitions__list-item-badge')).toBeNull(); + expect(linkDefinitions[1].querySelector('.link-definitions__list-item-badge')).toBeNull(); - expect(linkDefinitions[2].querySelector('.webchat__link-definitions__list-item-box').tagName).toBe('BUTTON'); + expect(linkDefinitions[2].querySelector('.link-definitions__list-item-box').tagName).toBe('BUTTON'); expect( - linkDefinitions[2].querySelector('.webchat__link-definitions__list-item-text').getAttribute('title') + linkDefinitions[2].querySelector('.link-definitions__list-item-text').getAttribute('title') ).toBe('Velit nulla culpa eu ea consectetur consectetur dolore velit'); expect( - linkDefinitions[2].querySelector('.webchat__link-definitions__list-item-badge').getAttribute('title') + linkDefinitions[2].querySelector('.link-definitions__list-item-badge').getAttribute('title') ).toBe('Velit exercitation'); - expect(linkDefinitions[3].querySelector('.webchat__link-definitions__list-item-box').tagName).toBe('BUTTON'); + expect(linkDefinitions[3].querySelector('.link-definitions__list-item-box').tagName).toBe('BUTTON'); expect( - linkDefinitions[3].querySelector('.webchat__link-definitions__list-item-text').getAttribute('title') + linkDefinitions[3].querySelector('.link-definitions__list-item-text').getAttribute('title') ).toBe('Adipisicing enim nulla'); - expect(linkDefinitions[3].querySelector('.webchat__link-definitions__list-item-badge')).toBeNull(); + expect(linkDefinitions[3].querySelector('.link-definitions__list-item-badge')).toBeNull(); - expect(document.querySelector('.webchat__link-definitions__header-text')).toHaveProperty( + expect(document.querySelector('.link-definitions__header-text')).toHaveProperty( 'textContent', '5 references' ); - expect(document.querySelector('.webchat__link-definitions__message-sensitivity-label-text')).toHaveProperty( + expect(document.querySelector('.link-definitions__message-sensitivity-label-text')).toHaveProperty( 'textContent', 'Sit veniam do irure velit est et quis ut Lorem reprehenderit commodo cillum occaecat' ); - expect(document.querySelector('.webchat__link-definitions__message-sensitivity-label')).toHaveProperty( + expect(document.querySelector('.link-definitions__message-sensitivity-label')).toHaveProperty( 'title', 'Sit veniam do irure velit est et quis ut Lorem reprehenderit commodo cillum occaecat\n\nNisi quis ut sint elit est nulla enim eiusmod. Deserunt commodo pariatur nostrud culpa aliquip esse pariatur exercitation nulla do proident. Est qui eiusmod aliquip deserunt labore consequat fugiat. Ullamco reprehenderit nostrud eiusmod nisi nulla esse id. Reprehenderit aliqua quis consectetur sit cupidatat fugiat Lorem ex labore. Eiusmod velit laborum quis tempor incididunt excepteur culpa esse nulla.' ); expect( - document.querySelector('.webchat__link-definitions__message-sensitivity-label--is-encrypted') + document.querySelector('.link-definitions__message-sensitivity-label--is-encrypted') ).toBeTruthy(); }); diff --git a/__tests__/html2/linkDefinition/identifierAsString.html b/__tests__/html2/linkDefinition/identifierAsString.html index 034403ef1c..234c6c3238 100644 --- a/__tests__/html2/linkDefinition/identifierAsString.html +++ b/__tests__/html2/linkDefinition/identifierAsString.html @@ -31,29 +31,29 @@ const [firstActivityElement] = pageElements.activities(); - const linkDefinitions = firstActivityElement.querySelectorAll('.webchat__link-definitions__list-item'); + const linkDefinitions = firstActivityElement.querySelectorAll('.link-definitions__list-item'); expect(linkDefinitions).toHaveProperty('length', 3); - expect(linkDefinitions[0].querySelector('.webchat__link-definitions__list-item-box').tagName).toBe('A'); + expect(linkDefinitions[0].querySelector('.link-definitions__list-item-box').tagName).toBe('A'); expect( - linkDefinitions[0].querySelector('.webchat__link-definitions__list-item-text').getAttribute('title') + linkDefinitions[0].querySelector('.link-definitions__list-item-text').getAttribute('title') ).toBe('Sint amet id officia dolor ex eiusmod ipsum ipsum magna fugiat'); - expect(linkDefinitions[1].querySelector('.webchat__link-definitions__list-item-box').tagName).toBe('A'); + expect(linkDefinitions[1].querySelector('.link-definitions__list-item-box').tagName).toBe('A'); expect( - linkDefinitions[1].querySelector('.webchat__link-definitions__list-item-text').getAttribute('title') + linkDefinitions[1].querySelector('.link-definitions__list-item-text').getAttribute('title') ).toBe('Laboris cupidatat voluptate'); - expect(linkDefinitions[1].querySelector('.webchat__link-definitions__list-item-badge')).toBeNull(); + expect(linkDefinitions[1].querySelector('.link-definitions__list-item-badge')).toBeNull(); - expect(linkDefinitions[2].querySelector('.webchat__link-definitions__list-item-box').tagName).toBe('A'); + expect(linkDefinitions[2].querySelector('.link-definitions__list-item-box').tagName).toBe('A'); expect( - linkDefinitions[2].querySelector('.webchat__link-definitions__list-item-text').getAttribute('title') + linkDefinitions[2].querySelector('.link-definitions__list-item-text').getAttribute('title') ).toBe('Velit nulla culpa eu ea consectetur consectetur dolore velit'); expect( [].map.call( - firstActivityElement.querySelectorAll('.webchat__link-definitions__badge'), + firstActivityElement.querySelectorAll('.link-definitions__badge'), ({ textContent }) => textContent ) ).toEqual(['Abc', 'DEF', 'xyz']); diff --git a/__tests__/html2/linkDefinition/reference.html b/__tests__/html2/linkDefinition/reference.html index 7a6347171e..6115efeae5 100644 --- a/__tests__/html2/linkDefinition/reference.html +++ b/__tests__/html2/linkDefinition/reference.html @@ -112,55 +112,55 @@ const activityElement = pageElements.activities()[2]; - const linkDefinitions = activityElement.querySelectorAll('.webchat__link-definitions__list-item'); + const linkDefinitions = activityElement.querySelectorAll('.link-definitions__list-item'); expect(linkDefinitions).toHaveProperty('length', 3); - expect(linkDefinitions[0].querySelector('.webchat__link-definitions__list-item-box').tagName).toBe('A'); + expect(linkDefinitions[0].querySelector('.link-definitions__list-item-box').tagName).toBe('A'); expect( - linkDefinitions[0].querySelector('.webchat__link-definitions__list-item-text').getAttribute('title') + linkDefinitions[0].querySelector('.link-definitions__list-item-text').getAttribute('title') ).toBe('IT - Proxy Settings for external access'); - expect(linkDefinitions[0].querySelector('.webchat__link-definitions__list-item-badge')).toHaveProperty( + expect(linkDefinitions[0].querySelector('.link-definitions__list-item-badge')).toHaveProperty( 'textContent', 'General' ); expect( - linkDefinitions[0].querySelector('.webchat__link-definitions__list-item-badge').getAttribute('title') + linkDefinitions[0].querySelector('.link-definitions__list-item-badge').getAttribute('title') ).toBe('General'); - expect(linkDefinitions[1].querySelector('.webchat__link-definitions__list-item-box').tagName).toBe('A'); + expect(linkDefinitions[1].querySelector('.link-definitions__list-item-box').tagName).toBe('A'); expect( - linkDefinitions[1].querySelector('.webchat__link-definitions__list-item-text').getAttribute('title') + linkDefinitions[1].querySelector('.link-definitions__list-item-text').getAttribute('title') ).toBe('Changing proxy settings - Windows 11'); - expect(linkDefinitions[1].querySelector('.webchat__link-definitions__list-item-badge')).toBeNull(); + expect(linkDefinitions[1].querySelector('.link-definitions__list-item-badge')).toBeNull(); - expect(linkDefinitions[2].querySelector('.webchat__link-definitions__list-item-box').tagName).toBe('A'); + expect(linkDefinitions[2].querySelector('.link-definitions__list-item-box').tagName).toBe('A'); expect( - linkDefinitions[2].querySelector('.webchat__link-definitions__list-item-text').getAttribute('title') + linkDefinitions[2].querySelector('.link-definitions__list-item-text').getAttribute('title') ).toBe('How to renew authentication token'); expect( - linkDefinitions[2].querySelector('.webchat__link-definitions__list-item-badge').getAttribute('title') + linkDefinitions[2].querySelector('.link-definitions__list-item-badge').getAttribute('title') ).toBe( 'Confidential\\Any User (No Protection)\n\nData is classified as Confidential but is NOT PROTECTED to allow access by approved NDA business partners. If a higher level of protection is needed please change the sensitivity level of the cited content.' ); - expect(document.querySelector('.webchat__link-definitions__header-text')).toHaveProperty( + expect(document.querySelector('.link-definitions__header-text')).toHaveProperty( 'textContent', '3 references' ); - expect(document.querySelector('.webchat__link-definitions__message-sensitivity-label-text')).toHaveProperty( + expect(document.querySelector('.link-definitions__message-sensitivity-label-text')).toHaveProperty( 'textContent', 'Confidential\\Any User (No Protection)' ); - expect(document.querySelector('.webchat__link-definitions__message-sensitivity-label')).toHaveProperty( + expect(document.querySelector('.link-definitions__message-sensitivity-label')).toHaveProperty( 'title', 'Confidential\\Any User (No Protection)\n\nData is classified as Confidential but is NOT PROTECTED to allow access by approved NDA business partners. If a higher level of protection is needed please change the sensitivity level of the cited content.' ); expect( - document.querySelector('.webchat__link-definitions__message-sensitivity-label--is-encrypted') + document.querySelector('.link-definitions__message-sensitivity-label--is-encrypted') ).toBeTruthy(); }); diff --git a/__tests__/html2/markdownRenderHTML/default.adaptiveCards.html b/__tests__/html2/markdownRenderHTML/default.adaptiveCards.html index 49fefc32d3..296ffb56c1 100644 --- a/__tests__/html2/markdownRenderHTML/default.adaptiveCards.html +++ b/__tests__/html2/markdownRenderHTML/default.adaptiveCards.html @@ -55,7 +55,7 @@ const [firstActivityElement] = pageElements.activities(); const link = firstActivityElement.querySelector('[href="http://example.com"]'); - const linkImage = link.querySelector('.webchat__render-markdown__external-link-icon'); + const linkImage = link.querySelector('.render-markdown__external-link-icon'); expect(link.getAttribute('aria-label')).toBe('link in it Opens in a new window; external.'); expect(link.getAttribute('target')).toBe('_blank'); diff --git a/__tests__/html2/markdownRenderHTML/default.citationModal.html b/__tests__/html2/markdownRenderHTML/default.citationModal.html index a488a6766b..122cab0c18 100644 --- a/__tests__/html2/markdownRenderHTML/default.citationModal.html +++ b/__tests__/html2/markdownRenderHTML/default.citationModal.html @@ -84,14 +84,14 @@ const [firstActivityElement] = pageElements.activities(); - const linkDefinitions = firstActivityElement.querySelectorAll('.webchat__link-definitions__list-item'); + const linkDefinitions = firstActivityElement.querySelectorAll('.link-definitions__list-item'); expect(linkDefinitions).toHaveProperty('length', 5); linkDefinitions[3].querySelector('button').click(); const link = document.querySelector('dialog [href="http://example.com"]'); - const linkImage = link.querySelector('.webchat__render-markdown__external-link-icon'); + const linkImage = link.querySelector('.render-markdown__external-link-icon'); expect(link.getAttribute('aria-label')).toBe('link in it Opens in a new window; external.'); expect(link.getAttribute('target')).toBe('_blank'); diff --git a/__tests__/html2/markdownRenderHTML/default.messageActivity.html b/__tests__/html2/markdownRenderHTML/default.messageActivity.html index 8d33f80b37..323af93375 100644 --- a/__tests__/html2/markdownRenderHTML/default.messageActivity.html +++ b/__tests__/html2/markdownRenderHTML/default.messageActivity.html @@ -28,7 +28,7 @@ const [firstActivityElement] = pageElements.activities(); const link = firstActivityElement.querySelector('[href="http://example.com"]'); - const linkImage = link.querySelector('.webchat__render-markdown__external-link-icon'); + const linkImage = link.querySelector('.render-markdown__external-link-icon'); expect(link.getAttribute('aria-label')).toBe('link in it Opens in a new window; external.'); expect(link.getAttribute('target')).toBe('_blank'); diff --git a/__tests__/html2/markdownRenderHTML/false.adaptiveCards.html b/__tests__/html2/markdownRenderHTML/false.adaptiveCards.html index a798147a07..e72bca4ec2 100644 --- a/__tests__/html2/markdownRenderHTML/false.adaptiveCards.html +++ b/__tests__/html2/markdownRenderHTML/false.adaptiveCards.html @@ -57,7 +57,7 @@ const [firstActivityElement] = pageElements.activities(); - const markdownElement = firstActivityElement.querySelectorAll('.webchat__render-markdown')[1]; + const markdownElement = firstActivityElement.querySelectorAll('.render-markdown')[1]; expect(markdownElement.innerHTML.startsWith('

Header

\n<p>This is some text')).toBe(true); diff --git a/__tests__/html2/markdownRenderHTML/false.citationModal.html b/__tests__/html2/markdownRenderHTML/false.citationModal.html index ab38f5b601..74f723b9f1 100644 --- a/__tests__/html2/markdownRenderHTML/false.citationModal.html +++ b/__tests__/html2/markdownRenderHTML/false.citationModal.html @@ -89,13 +89,13 @@ const [firstActivityElement] = pageElements.activities(); - const linkDefinitions = firstActivityElement.querySelectorAll('.webchat__link-definitions__list-item'); + const linkDefinitions = firstActivityElement.querySelectorAll('.link-definitions__list-item'); expect(linkDefinitions).toHaveProperty('length', 5); linkDefinitions[3].querySelector('button').click(); - const markdownElement = document.querySelectorAll('dialog .webchat__render-markdown')[1]; + const markdownElement = document.querySelectorAll('dialog .render-markdown')[1]; expect(markdownElement.innerHTML.startsWith('

Header

\n<p>This is some text')).toBe(true); diff --git a/__tests__/html2/markdownRenderHTML/false.messageActivity.html b/__tests__/html2/markdownRenderHTML/false.messageActivity.html index aefd33d5b4..5885a53380 100644 --- a/__tests__/html2/markdownRenderHTML/false.messageActivity.html +++ b/__tests__/html2/markdownRenderHTML/false.messageActivity.html @@ -30,7 +30,7 @@ const [firstActivityElement] = pageElements.activities(); - const markdownElement = firstActivityElement.querySelector('.webchat__render-markdown'); + const markdownElement = firstActivityElement.querySelector('.render-markdown'); expect(markdownElement.innerHTML.startsWith('

Header

\n<p>This is some text')).toBe(true); diff --git a/__tests__/html2/part-grouping/keyboard.html b/__tests__/html2/part-grouping/keyboard.html index e7796a12ae..8cf11c7e36 100644 --- a/__tests__/html2/part-grouping/keyboard.html +++ b/__tests__/html2/part-grouping/keyboard.html @@ -135,9 +135,9 @@ await pageObjects.focusTranscript(); const groupHeaders = () => document.querySelectorAll('.collapsible-grouping__header'); - const expandCollapseButtons = () => document.querySelectorAll('.collapsible-grouping__header .webchat__activity-button'); - const expandedGroups = () => document.querySelectorAll('.collapsible-grouping__header .webchat__activity-button[aria-expanded="true"]'); - const collapsedGroups = () => document.querySelectorAll('.collapsible-grouping__header .webchat__activity-button[aria-expanded="false"]'); + const expandCollapseButtons = () => document.querySelectorAll('.collapsible-grouping__header .activity-button'); + const expandedGroups = () => document.querySelectorAll('.collapsible-grouping__header .activity-button[aria-expanded="true"]'); + const collapsedGroups = () => document.querySelectorAll('.collapsible-grouping__header .activity-button[aria-expanded="false"]'); await waitFor(async () => expect(groupHeaders()).toHaveLength(2)); await waitFor(async () => expect(expandCollapseButtons()).toHaveLength(2)); diff --git a/__tests__/html2/part-grouping/navigation.html b/__tests__/html2/part-grouping/navigation.html index 4e11bb71ca..caac30fedd 100644 --- a/__tests__/html2/part-grouping/navigation.html +++ b/__tests__/html2/part-grouping/navigation.html @@ -166,7 +166,7 @@ // Test Case 2: Collapsed group navigation. // When: Collapsing group 1 and group 2. - const groupHeaders = () => document.querySelectorAll('.collapsible-grouping__header .webchat__activity-button'); + const groupHeaders = () => document.querySelectorAll('.collapsible-grouping__header .activity-button'); await waitFor(async () => expect(groupHeaders()).toHaveLength(2)); for (const header of groupHeaders()) { diff --git a/__tests__/html2/performance/renderActivity.profiling.html b/__tests__/html2/performance/renderActivity.profiling.html index 6d17f1e1c7..f93d845343 100644 --- a/__tests__/html2/performance/renderActivity.profiling.html +++ b/__tests__/html2/performance/renderActivity.profiling.html @@ -64,7 +64,7 @@ const commits = new Map(); function handleRender(id, renderPhase, actualDuration, baseDuration, startTime, commitTime) { const commit = commits.get(commitTime) ?? {}; - commit.activitiesCount = document.querySelectorAll('.webchat__bubble__content').length; + commit.activitiesCount = document.querySelectorAll('.bubble__content').length; commit.commit = commitTime; commit[`${id} ${renderPhase} actual`] ??= 0; commit[`${id} ${renderPhase} actual`] += actualDuration; diff --git a/packages/bundle/src/__tests__/renderMarkdown.spec.js b/packages/bundle/src/__tests__/renderMarkdown.spec.js index e454806a31..8452776300 100644 --- a/packages/bundle/src/__tests__/renderMarkdown.spec.js +++ b/packages/bundle/src/__tests__/renderMarkdown.spec.js @@ -8,7 +8,7 @@ describe('renderMarkdown', () => { codeBlockCopyButtonAltCopied: 'Copied', codeBlockCopyButtonAltCopy: 'Copy', codeBlockCopyButtonTagName: 'webchat--code-block-copy-button', - codeBlockCopyButtonClassName: 'webchat__code-block-copy-button', + codeBlockCopyButtonClassName: 'code-block-copy-button', copyButtonAlt: 'Copy', copyButtonCopiedAlt: 'Copied' }; @@ -72,7 +72,7 @@ describe('renderMarkdown', () => { const styleOptions = { markdownRespectCRLF: true }; expect(renderMarkdown('[example](https://sample.com)', styleOptions, renderMarkdownOptions)).toBe( - `

\u200Bexample\u200B

` + `

\u200Bexample\u200B

` ); }); @@ -81,7 +81,7 @@ describe('renderMarkdown', () => { const options = { externalLinkAlt: 'Opens in a new window, external.' }; expect(renderMarkdown('[example](https://sample.com)', styleOptions, options)).toBe( - `

\u200Bexample\u200B

` + `

\u200Bexample\u200B

` ); }); diff --git a/packages/bundle/src/markdown/renderMarkdown.ts b/packages/bundle/src/markdown/renderMarkdown.ts index a4c7d49089..0370e898f8 100644 --- a/packages/bundle/src/markdown/renderMarkdown.ts +++ b/packages/bundle/src/markdown/renderMarkdown.ts @@ -55,7 +55,7 @@ export default function render( ariaLabelSegments.push(linkDefinition.title || linkDefinition?.parsedUrl?.host || linkDefinition.url); // linkDefinition.identifier is uppercase, while linkDefinition.label is as-is. - linkDefinition.label === textContent && classes.add('webchat__render-markdown__pure-identifier'); + linkDefinition.label === textContent && classes.add('render-markdown__pure-identifier'); } // Let javascript: fell through. Our sanitizer will catch and remove it from . @@ -68,10 +68,10 @@ export default function render( if (!ALLOWED_SCHEMES.map(scheme => `${scheme}:`).includes(protocol)) { decoration.asButton = true; - classes.add('webchat__render-markdown__citation'); + classes.add('render-markdown__citation'); } else if (protocol === 'http:' || protocol === 'https:') { decoration.iconAlt = externalLinkAlt; - decoration.iconClassName = 'webchat__render-markdown__external-link-icon'; + decoration.iconClassName = 'render-markdown__external-link-icon'; ariaLabelSegments.push(externalLinkAlt); } diff --git a/packages/component/src/Activity/StackedLayout.module.css b/packages/component/src/Activity/StackedLayout.module.css index 34cde90da8..34d975de4e 100644 --- a/packages/component/src/Activity/StackedLayout.module.css +++ b/packages/component/src/Activity/StackedLayout.module.css @@ -116,7 +116,7 @@ place-self: start; width: 1em; - &:has(+ :global(.webchat__text-content)) { + &:has(+ :global(.text-content)) { font-size: 1em; } diff --git a/packages/component/src/Attachment/Text/TextContent.module.css b/packages/component/src/Attachment/Text/TextContent.module.css new file mode 100644 index 0000000000..90d7d20be5 --- /dev/null +++ b/packages/component/src/Attachment/Text/TextContent.module.css @@ -0,0 +1,45 @@ +:global(.webchat) .text-content { + font-family: var(--webchat__font--primary); + margin: 0; + min-height: calc(var(--webchat__min-height--bubble) - var(--webchat__padding--regular) * 2); + padding: var(--webchat__padding--regular); + + &.text-content--is-markdown { + display: flex; + flex-direction: column; + justify-content: center; + gap: var(--webchat__padding--regular); + min-width: 0; + } + + .text-content__markdown img:not(:global(.render-markdown__external-link-icon)) { + max-width: var(--webchat__max-width--message-bubble); + min-width: var(--webchat__min-width--message-bubble); + width: 100%; + } + + .text-content__markdown pre { + overflow: hidden; + } + + .text-content__open-in-new-window-icon { + height: 0.75em; + } + + .text-content__activity-actions { + align-self: flex-start; + display: flex; + flex-wrap: wrap; + gap: 8px calc(var(--webchat__padding--regular) / 2); + width: 100%; + } + + .text-content__activity-actions:empty { + display: none; + } + + .text-content__generated-badge { + color: var(--webchat__color--subtle); + font-size: var(--webchat__font-size--small); + } +} diff --git a/packages/component/src/Attachment/Text/TextContent.tsx b/packages/component/src/Attachment/Text/TextContent.tsx index 12bf250b15..0d031521b7 100644 --- a/packages/component/src/Attachment/Text/TextContent.tsx +++ b/packages/component/src/Attachment/Text/TextContent.tsx @@ -1,16 +1,16 @@ import { validateProps } from '@msinternal/botframework-webchat-react-valibot'; +import { useStyles } from '@msinternal/botframework-webchat-styles/react'; import { hooks } from 'botframework-webchat-api'; -import classNames from 'classnames'; import React, { memo, useMemo } from 'react'; import { any, object, optional, pipe, readonly, string, type InferInput } from 'valibot'; -import { useStyleToEmotionObject } from '../../hooks/internal/styleToEmotionObject'; import useRenderMarkdownAsHTML from '../../hooks/useRenderMarkdownAsHTML'; -import CustomPropertyNames from '../../Styles/CustomPropertyNames'; import isAIGeneratedActivity from './private/isAIGeneratedActivity'; import MarkdownTextContent from './private/MarkdownTextContent'; import PlainTextContent from './private/PlainTextContent'; +import styles from './TextContent.module.css'; + const { useLocalizer } = hooks; const textContentPropsSchema = pipe( @@ -24,28 +24,19 @@ const textContentPropsSchema = pipe( type TextContentProps = InferInput; -const generatedBadgeStyle = { - '&.webchat__text-content__generated-badge': { - color: `var(${CustomPropertyNames.ColorSubtle})`, - fontSize: `var(${CustomPropertyNames.FontSizeSmall})` - } -}; - function TextContent(props: TextContentProps) { const { activity, contentType = 'text/plain', text } = validateProps(textContentPropsSchema, props); + const classNames = useStyles(styles); const supportMarkdown = !!useRenderMarkdownAsHTML('message activity'); const localize = useLocalizer(); - const generatedBadgeClassName = useStyleToEmotionObject()(generatedBadgeStyle) + ''; const generatedBadge = useMemo( () => isAIGeneratedActivity(activity) && ( -
- {localize('ACTIVITY_CONTENT_CAUTION')} -
+
{localize('ACTIVITY_CONTENT_CAUTION')}
), - [activity, generatedBadgeClassName, localize] + [activity, classNames, localize] ); return text ? ( diff --git a/packages/component/src/Attachment/Text/private/ActivityButton.module.css b/packages/component/src/Attachment/Text/private/ActivityButton.module.css new file mode 100644 index 0000000000..30bbcea3c7 --- /dev/null +++ b/packages/component/src/Attachment/Text/private/ActivityButton.module.css @@ -0,0 +1,45 @@ +:global(.webchat) .activity-button { + align-items: center; + appearance: none; + background: #fff; + border-radius: 4px; + border: 1px solid #d1d1d1; + color: #242424; + display: flex; + gap: 4px; + justify-content: center; + padding: 5px 12px; + + &:hover { + background: #f5f5f5; + border: 1px solid #c7c7c7; + color: #242424; + } + + &:active { + background: #e0e0e0; + border: 1px solid #b3b3b3; + color: #242424; + } + + &:focus-visible { + background: #fff; + outline: 2px solid #000; + outline-offset: -2px; + } + + &[aria-disabled='true'] { + background: #f0f0f0; + border: 1px solid #e0e0e0; + color: #bdbdbd; + cursor: not-allowed; + } + + .activity-button__icon { + height: 20px; + width: 20px; + + --webchat__component-icon--color: #707070; + --webchat__component-icon--size: 20px; + } +} diff --git a/packages/component/src/Attachment/Text/private/ActivityButton.tsx b/packages/component/src/Attachment/Text/private/ActivityButton.tsx index c027e09ecd..9cc0130ab4 100644 --- a/packages/component/src/Attachment/Text/private/ActivityButton.tsx +++ b/packages/component/src/Attachment/Text/private/ActivityButton.tsx @@ -1,5 +1,6 @@ import { reactNode, validateProps } from '@msinternal/botframework-webchat-react-valibot'; -import classNames from 'classnames'; +import { useStyles } from '@msinternal/botframework-webchat-styles/react'; +import cx from 'classnames'; import React, { forwardRef, memo, useCallback } from 'react'; import { useRefFrom } from 'use-ref-from'; import { @@ -15,9 +16,10 @@ import { type InferInput } from 'valibot'; -import useStyleSet from '../../../hooks/useStyleSet'; import { ComponentIcon, componentIconPropsSchema } from '../../../Icon'; +import styles from './ActivityButton.module.css'; + const activityButtonPropsSchema = pipe( object({ 'aria-controls': optional(string()), @@ -50,7 +52,7 @@ const ActivityButton = forwardRef((props text } = validateProps(activityButtonPropsSchema, props); - const [{ activityButton }] = useStyleSet(); + const classNames = useStyles(styles); const onClickRef = useRefFrom(onClick); const handleClick = useCallback(() => onClickRef.current?.(), [onClickRef]); @@ -61,7 +63,7 @@ const ActivityButton = forwardRef((props aria-disabled={disabled ? 'true' : undefined} aria-expanded={ariaExpanded} aria-pressed={ariaPressed} - className={classNames(activityButton, 'webchat__activity-button', className)} + className={cx(classNames['activity-button'], className)} data-testid={dataTestId} onClick={disabled ? undefined : handleClick} ref={ref} @@ -69,8 +71,8 @@ const ActivityButton = forwardRef((props tabIndex={disabled ? -1 : undefined} type="button" > - {icon && } - {text && {text}} + {icon && } + {text && {text}} {children} ); diff --git a/packages/component/src/Attachment/Text/private/ActivityCopyButton.module.css b/packages/component/src/Attachment/Text/private/ActivityCopyButton.module.css new file mode 100644 index 0000000000..a60a1c0e8d --- /dev/null +++ b/packages/component/src/Attachment/Text/private/ActivityCopyButton.module.css @@ -0,0 +1,45 @@ +:global(.webchat) .activity-copy-button { + overflow: clip; + position: relative; + + @supports not (overflow: clip) { + overflow: hidden; + } + + .activity-copy-button__copied-text { + align-items: center; + background-color: #fff; + display: flex; + height: 100%; + justify-content: center; + position: absolute; + visibility: hidden; + width: 100%; + } + + &.activity-copy-button--copied { + .activity-copy-button__copied-text { + animation: webchat__activity-copy-button__copied-animation 0.7s linear; + } + + .activity-button__icon, + .activity-button__text { + visibility: hidden; + } + } +} + +.activity-copy-button__copy-announcement { + pointer-events: none; +} + +@keyframes webchat__activity-copy-button__copied-animation { + 0% { + /* This is set during the animation only hence shouldn't spill when hidden from the above tree */ + visibility: visible; + } + + 100% { + visibility: unset; + } +} diff --git a/packages/component/src/Attachment/Text/private/ActivityCopyButton.tsx b/packages/component/src/Attachment/Text/private/ActivityCopyButton.tsx index 309ac43da6..5656f96304 100644 --- a/packages/component/src/Attachment/Text/private/ActivityCopyButton.tsx +++ b/packages/component/src/Attachment/Text/private/ActivityCopyButton.tsx @@ -1,14 +1,16 @@ import { validateProps } from '@msinternal/botframework-webchat-react-valibot'; +import { useStyles } from '@msinternal/botframework-webchat-styles/react'; import { hooks } from 'botframework-webchat-api'; -import classNames from 'classnames'; +import cx from 'classnames'; import React, { memo, useCallback, useEffect, useRef, useState } from 'react'; import { instance, nullable, object, optional, pipe, readonly, string, type InferInput } from 'valibot'; -import useStyleSet from '../../../hooks/useStyleSet'; import { useQueueStaticElement } from '../../../providers/LiveRegionTwin'; import refObject from '../../../types/internal/refObject'; import ActivityButton from './ActivityButton'; +import styles from './ActivityCopyButton.module.css'; + const { useLocalizer, useUIState } = hooks; const activityCopyButtonPropsSchema = pipe( @@ -24,7 +26,7 @@ type ActivityCopyButtonProps = InferInput; const ActivityCopyButton = (props: ActivityCopyButtonProps) => { const { className, targetRef } = validateProps(activityCopyButtonPropsSchema, props); - const [{ activityButton, activityCopyButton }] = useStyleSet(); + const classNames = useStyles(styles); const [permissionGranted, setPermissionGranted] = useState(false); const [uiState] = useUIState(); const buttonRef = useRef(null); @@ -39,13 +41,14 @@ const ActivityCopyButton = (props: ActivityCopyButtonProps) => { const { current } = buttonRef; if (current) { - const handleAnimationEnd = () => current.classList.remove('webchat__activity-copy-button--copied'); + const handleAnimationEnd = () => + current.classList.remove(...classNames['activity-copy-button--copied'].split(/\s+/gu)); current.addEventListener('animationend', handleAnimationEnd); return () => current.removeEventListener('animationend', handleAnimationEnd); } - }, [buttonRef]); + }, [buttonRef, classNames]); const handleClick = useCallback(() => { const htmlText = targetRef.current?.outerHTML; @@ -60,16 +63,16 @@ const ActivityCopyButton = (props: ActivityCopyButtonProps) => { ]) .catch(error => console.error(`botframework-webchat-fluent-theme: Failed to copy to clipboard.`, error)); - buttonRef.current?.classList.remove('webchat__activity-copy-button--copied'); + buttonRef.current?.classList.remove(...classNames['activity-copy-button--copied'].split(/\s+/gu)); // Reading `offsetWidth` will trigger a reflow and this is critical for resetting the animation. // https://css-tricks.com/restart-css-animation/#aa-update-another-javascript-method-to-restart-a-css-animation buttonRef.current?.offsetWidth; - buttonRef.current?.classList.add('webchat__activity-copy-button--copied'); + buttonRef.current?.classList.add(...classNames['activity-copy-button--copied'].split(/\s+/gu)); - queueStaticElement(
{copiedText}
); - }, [buttonRef, copiedText, queueStaticElement, targetRef]); + queueStaticElement(
{copiedText}
); + }, [classNames, copiedText, queueStaticElement, targetRef]); useEffect(() => { let unmounted = false; @@ -87,13 +90,7 @@ const ActivityCopyButton = (props: ActivityCopyButtonProps) => { return ( { ref={buttonRef} text={copyText} > - {copiedText} + {copiedText} ); }; diff --git a/packages/component/src/Attachment/Text/private/ActivityViewCodeButton.tsx b/packages/component/src/Attachment/Text/private/ActivityViewCodeButton.tsx index 7395db4154..81df30912c 100644 --- a/packages/component/src/Attachment/Text/private/ActivityViewCodeButton.tsx +++ b/packages/component/src/Attachment/Text/private/ActivityViewCodeButton.tsx @@ -1,11 +1,9 @@ import { validateProps } from '@msinternal/botframework-webchat-react-valibot'; import { useStyles } from '@msinternal/botframework-webchat-styles/react'; import { hooks } from 'botframework-webchat-api'; -import cx from 'classnames'; import React, { memo, useCallback } from 'react'; import { boolean, object, optional, pipe, readonly, string, type InferInput } from 'valibot'; -import useStyleSet from '../../../hooks/useStyleSet'; import useShowModal from '../../../providers/ModalDialog/useShowModal'; import LocalizedString from '../../../Utils/LocalizedString'; import ActivityButton from './ActivityButton'; @@ -32,7 +30,6 @@ const ActivityViewCodeButton = (props: ActivityViewCodeButtonProps) => { const { className, code, language, title, isAIGenerated } = validateProps(activityViewCodeButtonPropsSchema, props); const classNames = useStyles(styles); - const [{ activityButton }] = useStyleSet(); const showModal = useShowModal(); const localize = useLocalizer(); @@ -42,13 +39,13 @@ const ActivityViewCodeButton = (props: ActivityViewCodeButtonProps) => { {isAIGenerated && (
- +
)}
), { - className: cx('webchat__view-code-dialog', classNames['view-code-dialog']), + className: classNames['view-code-dialog'], 'aria-label': localize('ACTIVITY_CODE_ALT', title ?? '') } ); @@ -56,7 +53,7 @@ const ActivityViewCodeButton = (props: ActivityViewCodeButtonProps) => { return ( ({ __html: renderMarkdownAsHTML(markdown) }), [markdown, renderMarkdownAsHTML]); return ( - {headerText &&

{headerText}

} + {headerText &&

{headerText}

} {renderMarkdownAsHTML ? (
) : ( -
{markdown}
+
{markdown}
)} ); diff --git a/packages/component/src/Attachment/Text/private/MarkdownTextContent.tsx b/packages/component/src/Attachment/Text/private/MarkdownTextContent.tsx index b0fd74b758..895c9e3c98 100644 --- a/packages/component/src/Attachment/Text/private/MarkdownTextContent.tsx +++ b/packages/component/src/Attachment/Text/private/MarkdownTextContent.tsx @@ -1,4 +1,5 @@ import { reactNode, validateProps } from '@msinternal/botframework-webchat-react-valibot'; +import { useStyles } from '@msinternal/botframework-webchat-styles/react'; import { hooks } from 'botframework-webchat-api'; import { getOrgSchemaMessage, @@ -7,7 +8,7 @@ import { type OrgSchemaClaim, type WebChatActivity } from 'botframework-webchat-core'; -import classNames from 'classnames'; +import cx from 'classnames'; import type { Definition } from 'mdast'; import { fromMarkdown } from 'mdast-util-from-markdown'; import React, { memo, useCallback, useMemo, useRef, type MouseEventHandler } from 'react'; @@ -19,7 +20,6 @@ import { LinkDefinitionItem, LinkDefinitions } from '../../../LinkDefinition/ind import dereferenceBlankNodes from '../../../Utils/JSONLinkedData/dereferenceBlankNodes'; import useSanitizeHrefCallback from '../../../hooks/internal/useSanitizeHrefCallback'; import useRenderMarkdownAsHTML from '../../../hooks/useRenderMarkdownAsHTML'; -import useStyleSet from '../../../hooks/useStyleSet'; import useShowModal from '../../../providers/ModalDialog/useShowModal'; import { type PropsOf } from '../../../types/PropsOf'; import ActivityCopyButton from './ActivityCopyButton'; @@ -30,6 +30,9 @@ import isAIGeneratedActivity from './isAIGeneratedActivity'; import isBasedOnSoftwareSourceCode from './isBasedOnSoftwareSourceCode'; import isHTMLButtonElement from './isHTMLButtonElement'; +import citationModalStyles from './CitationModal.module.css'; +import textContentStyles from '../TextContent.module.css'; + const { useLocalizer, useStyleOptions } = hooks; type Entry = { @@ -76,14 +79,10 @@ function isCitingInline(claim: OrgSchemaClaim): claim is OrgSchemaClaim & { function MarkdownTextContent(props: MarkdownTextContentProps) { const { activity, children, markdown } = validateProps(markdownTextContentPropsSchema, props); + const citationModalClassNames = useStyles(citationModalStyles); + const textContentClassNames = useStyles(textContentStyles); + const [{ feedbackActionsPlacement }] = useStyleOptions(); - const [ - { - citationModalDialog: citationModalDialogStyleSet, - renderMarkdown: renderMarkdownStyleSet, - textContent: textContentStyleSet - } - ] = useStyleSet(); const contentRef = useRef(null); const localize = useLocalizer(); const graph = useMemo(() => dereferenceBlankNodes(activity.entities || []), [activity.entities]); @@ -112,10 +111,10 @@ function MarkdownTextContent(props: MarkdownTextContentProps) { (title, text, altText) => { showModal(() => , { 'aria-label': altText || title || citationModalDialogLabel, - className: classNames('webchat__citation-modal-dialog', citationModalDialogStyleSet) + className: citationModalClassNames['citation-modal-dialog'] }); }, - [citationModalDialogStyleSet, citationModalDialogLabel, showModal] + [citationModalClassNames, citationModalDialogLabel, showModal] ); const sanitizeHref = useSanitizeHrefCallback(); @@ -283,11 +282,9 @@ function MarkdownTextContent(props: MarkdownTextContentProps) { const getEntryDescription = (entry: Entry) => entry.claim?.appearance?.usageInfo?.description; return ( -
+
)} -
+
{activity.type === 'message' && isBasedOnSoftwareSourceCode(messageThing) && messageThing.isBasedOn.text && !messageThing.keywords?.includes?.('Collapsible') ? ( ) : null} {activity.type === 'message' && activity.text && messageThing?.keywords?.includes('AllowCopy') ? ( - + ) : null} {activity.type === 'message' && feedbackActionsPlacement === 'activity-actions' && ( diff --git a/packages/component/src/Attachment/Text/private/MessageSensitivityLabel.tsx b/packages/component/src/Attachment/Text/private/MessageSensitivityLabel.tsx index 3d904f3746..979d3d922c 100644 --- a/packages/component/src/Attachment/Text/private/MessageSensitivityLabel.tsx +++ b/packages/component/src/Attachment/Text/private/MessageSensitivityLabel.tsx @@ -1,10 +1,13 @@ import { validateProps } from '@msinternal/botframework-webchat-react-valibot'; -import classNames from 'classnames'; +import { useStyles } from '@msinternal/botframework-webchat-styles/react'; +import cx from 'classnames'; import React, { memo, useMemo } from 'react'; import { boolean, object, optional, pipe, readonly, string, type InferInput } from 'valibot'; import ShieldIcon from './ShieldIcon'; +import styles from '../../../LinkDefinition/LinkDefinitions.module.css'; + const messageSensitivityLabelPropsSchema = pipe( object({ className: optional(string()), @@ -21,23 +24,25 @@ type MessageSensitivityLabelProps = InferInput [name, title].filter(Boolean).join('\n\n'), [name, title])} > - {name} + {name}
); } diff --git a/packages/component/src/Attachment/Text/private/PlainTextContent.tsx b/packages/component/src/Attachment/Text/private/PlainTextContent.tsx index d8acd8b129..942f711a1b 100644 --- a/packages/component/src/Attachment/Text/private/PlainTextContent.tsx +++ b/packages/component/src/Attachment/Text/private/PlainTextContent.tsx @@ -1,9 +1,10 @@ import { reactNode, validateProps } from '@msinternal/botframework-webchat-react-valibot'; -import classNames from 'classnames'; +import { useStyles } from '@msinternal/botframework-webchat-styles/react'; +import cx from 'classnames'; import React, { Fragment, memo } from 'react'; import { object, optional, pipe, readonly, string, type InferInput } from 'valibot'; -import useStyleSet from '../../../hooks/useStyleSet'; +import styles from '../TextContent.module.css'; const plainTextContentPropsSchema = pipe( object({ @@ -18,25 +19,16 @@ type PlainTextContentProps = InferInput; function PlainTextContent(props: PlainTextContentProps) { const { children, text } = validateProps(plainTextContentPropsSchema, props); - const [{ textContent: textContentStyleSet }] = useStyleSet(); + const classNames = useStyles(styles); return ( {(text || '').split('\n').map(line => ( -

+

{line.trim()}

))} - {children && ( -
- {children} -
- )} + {children &&
{children}
}
); } diff --git a/packages/component/src/LinkDefinition/LinkDefinitionItem.tsx b/packages/component/src/LinkDefinition/LinkDefinitionItem.tsx index e1ec786364..6b71380067 100644 --- a/packages/component/src/LinkDefinition/LinkDefinitionItem.tsx +++ b/packages/component/src/LinkDefinition/LinkDefinitionItem.tsx @@ -1,4 +1,6 @@ import { validateProps } from '@msinternal/botframework-webchat-react-valibot'; +import { useStyles } from '@msinternal/botframework-webchat-styles/react'; +import cx from 'classnames'; import React, { memo, useCallback, type MouseEventHandler } from 'react'; import { useRefFrom } from 'use-ref-from'; import { custom, object, optional, pipe, readonly, string, type InferInput } from 'valibot'; @@ -6,6 +8,8 @@ import { custom, object, optional, pipe, readonly, string, type InferInput } fro import ItemBody from './private/ItemBody'; import extractHostnameWithSubdomain from './private/extractHostnameWithSubdomain'; +import styles from './LinkDefinitions.module.css'; + const linkDefinitionItemPropsSchema = pipe( object({ // Displayed beneath the main link of the citation if it exists @@ -41,6 +45,8 @@ const LinkDefinitionItem = memo(function LinkDefinitionItem(props: LinkDefinitio props ); + const classNames = useStyles(styles); + const onClickRef = useRefFrom(onClick); const handleClick = useCallback>( @@ -62,7 +68,10 @@ const LinkDefinitionItem = memo(function LinkDefinitionItem(props: LinkDefinitio // URL is sanitized. // eslint-disable-next-line react/forbid-elements
) : (