Skip to content

Commit

Permalink
fix: Update useStyledComponentsTarget to support case where head tag …
Browse files Browse the repository at this point in the history
…is removed. (#414)

## Changes
- Re-fixed an issue where widget style is not applied due to style tag
being dynamically removed and then re-added in the head tag in a
WordPress like environment

ticket: [AA-772](https://sendbird.atlassian.net/browse/AA-722)

## Additional Notes
- 

## Checklist
Before requesting a code review, please check the following:
- [ ] **[Required]** CI has passed all checks.
- [ ] **[Required]** A self-review has been conducted to ensure there
are no minor mistakes.
- [ ] **[Required]** Unnecessary comments/debugging code have been
removed.
- [ ] **[Required]** All requirements specified in the ticket have been
accurately implemented.
- [ ] Ensure the ticket has been updated with the sprint, status, and
story points.


[AA-772]:
https://sendbird.atlassian.net/browse/AA-772?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
  • Loading branch information
liamcho authored Jan 24, 2025
1 parent d846758 commit 680f72f
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 20 deletions.
2 changes: 1 addition & 1 deletion packages/self-service/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const version = getWidgetVersion();

// https://vitejs.dev/config/
export default defineConfig({
plugins: [react(), cssInjectedByJsPlugin()],
plugins: [react(), cssInjectedByJsPlugin({ styleId: 'sendbird-css-inject-id' })],
build: {
outDir: `./dist/${version}`,
rollupOptions: {
Expand Down
51 changes: 32 additions & 19 deletions src/hooks/useStyledComponentsTarget.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { useLayoutEffect, useState } from 'react';
import { version } from 'styled-components/package.json';

const StyledId = 'sendbird-css-inject-id';

function isSCTarget(node: Node): node is HTMLStyleElement {
return node instanceof HTMLStyleElement && node.getAttribute('data-styled-version') === version;
}
Expand All @@ -10,35 +12,46 @@ function isSCTarget(node: Node): node is HTMLStyleElement {
* When styled-components, which has already been initialized, is re-added to the head, for example `document.head.innerHTML += ''`, the styles may not render correctly.
* Therefore, the target is moved to the body tag.
* Similarly, the issue could also rise in below cases and the hook handles them accordingly:
* - If styles are removed from <head>, switch to <body>.
* - If styles are removed from <head>, re-add to head if head exists or switch to <body>.
* This is a short-term solution, and in the long run, we plan to remove styled-components altogether.
* */
export function useStyledComponentsTarget() {
const [target, setTarget] = useState(document.head);

useLayoutEffect(() => {
const handleRemovedStyle = (styleElement: HTMLElement) => {
if (styleElement && styleElement.parentElement !== document.body) {
if (document.head) {
console.warn('[useStyledComponentsTarget]: Head exists, re-adding style element ${StyledId} to <head>.');
document.head.appendChild(styleElement);
setTarget(document.head);
} else {
console.warn('[useStyledComponentsTarget]: Head missing, moving style element ${StyledId} to <body>.');
document.body.appendChild(styleElement);
setTarget(document.body);
}
}
};

const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
// Case 1: Detect if styles are added to <head>
if (mutation.target === document.head && mutation.addedNodes.length > 0) {
for (const node of mutation.addedNodes) {
if (isSCTarget(node)) {
console.warn('Styled Components styles re-injected, switching to <body>');
setTarget(document.body);
return;
}
// Handle added nodes
Array.from(mutation.addedNodes).forEach((node) => {
if (isSCTarget(node)) {
console.warn('[useStyledComponentsTarget]: Styled Components styles re-injected, switching to <body>');
setTarget(document.body);
}
}
// Case 2: Detect if styles are removed from <head>
if (mutation.target === document.head && mutation.removedNodes.length > 0) {
for (const node of mutation.removedNodes) {
if (isSCTarget(node)) {
console.warn('Styled Components styles removed, switching to <body>');
setTarget(document.body);
return;
}
});

// Handle removed nodes
Array.from(mutation.removedNodes).forEach((node) => {
if (isSCTarget(node)) {
console.warn('[useStyledComponentsTarget]: Styled Components styles removed, switching to <body>');
setTarget(document.body);
} else if (node instanceof HTMLElement && node.id === StyledId) {
handleRemovedStyle(node);
}
}
});
});
});

Expand Down

0 comments on commit 680f72f

Please sign in to comment.