-
Notifications
You must be signed in to change notification settings - Fork 4k
feat(js,react): inbox and styles under the shadow root #8262
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
✅ Deploy Preview for dashboard-v2-novu-staging canceled.
|
@@ -129,7 +129,7 @@ export const DefaultNotification = (props: DefaultNotificationProps) => { | |||
{(subject) => ( | |||
<Markdown | |||
appearanceKey="notificationSubject" | |||
class="nt-text-start nt-font-medium" | |||
class="nt-text-start nt-font-medium nt-whitespace-pre-wrap [word-break:break-word]" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -67,33 +68,40 @@ type RendererProps = { | |||
preferencesFilter?: PreferencesFilter; | |||
routerPush?: RouterPush; | |||
novu?: Novu; | |||
containerElement?: Node | null | undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the new prop that defines where the Inbox and its styles will be embedded; the name TBD;
const id = 'novu-default-css'; | ||
const el = document.getElementById(id); | ||
const id = NOVU_DEFAULT_CSS_ID; | ||
const root = props.containerElement instanceof ShadowRoot ? props.containerElement : document; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if the containerElement
is a shadow root, then use it to find the default styles
const stylesContainer = props.containerElement ?? document.head; | ||
stylesContainer.insertBefore(styleEl, stylesContainer.firstChild); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
inject the default styles to the containerElement
if provided otherwise document head
if ( | ||
active() !== floating() || | ||
floating()?.contains(e.target as Node) || | ||
(container && (e.target as Element).shadowRoot === container) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if the target shadow root is the container where the inbox is embedded, then do not close it;
const getRoot = () => { | ||
const container = containerElement(); | ||
|
||
return container instanceof ShadowRoot ? container : document; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
handle tab and keyboard navigation on components, for example tabs
|
||
return ( | ||
<Show when={open()}> | ||
{/* we can safely use portal to document.body here as this element | ||
won't be focused and close other portals (outside solid world) as a result */} | ||
<Portal> | ||
<Portal mount={portalContainer()}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mount tooltips inside the "container" not body
@@ -28,7 +28,7 @@ export function TooltipRoot(props: TooltipRootProps) { | |||
|
|||
const position = useFloating(reference, floating, { | |||
placement: props.placement || 'top', | |||
strategy: 'absolute', | |||
strategy: 'fixed', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the absolute
strategy doesn't work well for the tooltips, that's why changed to fixed
const defaultCssStyles = root.getElementById(NOVU_DEFAULT_CSS_ID); | ||
if (defaultCssStyles) { | ||
stylesContainer.insertBefore(styleEl, defaultCssStyles.nextSibling); | ||
} else { | ||
stylesContainer.appendChild(styleEl); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
default styles and appearance styles should come together one after another
packages/js/src/ui/novuUI.tsx
Outdated
if (typeof containerElement === 'string') { | ||
return document.querySelector(containerElement) ?? document.getElementById(containerElement); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if the containerElement
is CSS selector then try to find elements
packages/react/src/utils/types.ts
Outdated
@@ -38,6 +38,7 @@ export type BaseProps = { | |||
localization?: Localization; | |||
tabs?: Array<Tab>; | |||
preferencesFilter?: PreferencesFilter; | |||
containerElement?: Node | null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@LetItRock what do you think about: container
similar to Radix terminology?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@scopsy yes, Emotion is using similar name as well ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool! Than let's go with it?
@novu/js
@novu/nextjs
novu
@novu/react
@novu/react-native
commit: |
What changed? Why was the change needed?
Inbox
The new
containerElement
prop allows specifying the "container" that will be used to render Bell, Inbox and Popover, and its internal styles. ThecontainerElement
prop takes aNode
which can be anHTMLElement
orShadowRoot
, or a CSS selector.Example of usage:
Screenshots
Screen.Recording.2025-05-07.at.13.57.40.mov
Screen.Recording.2025-05-07.at.13.56.18.mov