Tooltip on absolute element in React JS - css

I am using this library https://tvkhoa.github.io/testlib/ to make some nice tooltip in my React App.
I use that code in my own component which look like this
const Tooltip = ({className, children, text, placement = 'bottom', isDisabled = false}) => {
return (
<ReactTippyTooltip className={className} html={<span>{text}</span>}
theme="dark" position={placement} arrow={true} arrowSize="regular"
animation="shift" hideDelay={300}>
{children}
</ReactTippyTooltip>
);
};
On basic elements such as simple images or buttons, everything works fine. But in some cases, I need to have a tooltip on an absolute element. For example on an InfoButton which overlaps an image.
<div className="relative"> <!-- container -->
<img />
<Tooltip> <!-- tooltip container -->
<InfoButton className="absolute top-0 left-0">
</Tooltip>
</div>
But I noticed that the tooltip appears bellow the image, instead of bellow the InfoButton.
If I have a look with the devtool, I can see that my InfoButton is inside a div that represents ReactTippyTooltip, and that div is 0*0 and is positionned bellow the image in the DOM. This is because only its content (InfoButton) is absolute and positionned inside the image. It can be summarized by the following image
I put a className to ReactTippyTooltip as a workaround and I made it absolute as well. Like this my tooltip is at the right place, but I feel like there is something wrong with what I am my doing.
Has anyone encountered some issues with tooltip on absolute elements ?
Can I do some better code with the library I am using ?
Does it exist some react tooltip library that use reference of the element to display the tooltip ?

Related

react-syntax-highlighter is not working with TailwindCSS

I am displaying sanity block content using [#sanity/block-content-to-react](#sanity/block-content-to-react). The BlockContent component is wrapper by div with class of "prose".
<div className="prose prose-zinc font-display prose-h1:font-normal prose-code:mx-1 prose-code:before:content-none prose-code:after:content-none dark:prose-invert ">
<BlockContent
// Pass in block content straight from Sanity.io
blocks={singleBlog.body}
serializers={serializers}
/>
</div>
In my serializers, I am passing custom <Code/> component.
const serializers = {
types: {
code: (props) => <Code props={props} />,
},
};
In my custom code component, I am using Syntax Highlighter to wrap by code content.
<SyntaxHighlighter style={theme} language={props.node.language}>
{props.node.code}
</SyntaxHighlighter>
But, no matter which theme I choose, it only changes the background colors and font sizes but has no effect in text colors.
I thought 'prose' class on wrapper div was causing the problem. But remove that didn't work either.
{/* <div className="prose prose-zinc font-display prose-h1:font-normal prose-code:mx-1 prose-code:before:content-none prose-code:after:content-none dark:prose-invert "> */}
<BlockContent
// Pass in block content straight from Sanity.io
blocks={singleBlog.body}
serializers={serializers}
/>
{/* </div> */}
Does anyone have any solution ?
I am not sure if you are using a custom theme or if you are using one of the many option. But if you are using the available one that you can find here: https://react-syntax-highlighter.github.io/react-syntax-highlighter/demo/prism.html
Then it may be a problem with your imports.
If I import the theme like that (using the hljs ): import {dark} from "react-syntax-highlighter/dist/esm/styles/hljs"; I only get background color.
If I import the theme like this using the 'prism' option I get the text color too: import {dark} from "react-syntax-highlighter/dist/esm/styles/prism";

How to add Bootstrap 5 padding uniformly across sides?

I am trying to experiment with Bootstrap 5 within React, but somehow fail to understand the padding and margin. Consider the following code:
const Breadcrumbs = (props) => {
return (
<div className={"bg-dark rounded-start"}>
<Breadcrumb>
<Breadcrumb.Item href="#">Home</Breadcrumb.Item>
<Breadcrumb.Item href="https://somelink.com">
Library
</Breadcrumb.Item>
<Breadcrumb.Item active>Data</Breadcrumb.Item>
</Breadcrumb>
</div>
)
}
Its a Component which is later on shown in a Container. I chose a dark background to better show the issue. With this code, the Breadcrumbs render like this:
Now I want them to have some padding within the surrounding box, lets say only in vertical direction. According to the Spacing documentation I should be adding modifier classes, for example py-2 which should add a Padding to both top and bottom to $spacer * .5. When applying the additional class like this:
const Breadcrumbs = (props) => {
return (
<div className={"bg-dark py-2 rounded-start"}>
<Breadcrumb>
<Breadcrumb.Item href="#">Home</Breadcrumb.Item>
<Breadcrumb.Item href="https://somelink.com">
Library
</Breadcrumb.Item>
<Breadcrumb.Item active>Data</Breadcrumb.Item>
</Breadcrumb>
</div>
)
}
It now looks like this:
My question now is: how can I add padding that keeps the Breacrumbs vertically centered within the surrounding div?
//Edit: I think I found something. The <ol> element created by Breadcrumb has a margin-bottom set. How can I remove that?

Center spinner in viewport on bootstrap overlay

I'm using the bootstrap-vue overlay on a page that has long content scrolled via the browser window.
<b-overlay :show="loading">
The overlay correctly covers all of the content, even the part below the viewport, but the overlay's built-in spinner is centered on the content rather than the viewport, so the spinner ends up near or below the bottom of the viewport when the content is long enough.
I've tried custom content via a slot, like this...
<b-overlay :show="loading">
<template v-slot:overlay>
<div style="???" class="text-center">
<p style="???">Make me a spinner and center me on the viewport</p>
<b-button
</div>
</template>
...with dozens of ideas for style="???", including position:absolute with different tops, including top=50vh, including !important strewn around, etc., but the content doesn't budge.
// Note that this snippet doesn't run, because I don't see a way to get
// bootstrap-vue via CDN
var app = new Vue({
el: '#app',
data: function() {
return {
message: 'Hello Vue!',
messages: []
}
},
mounted() {
for (let i=0; i<50; i++)
this.messages.push(i)
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<b-overlay :show="true">
{{ message }}
<!-- long content below extends the overlay size -->
<!-- this moves the spinner down and off the viewport -->
<ul>
<li v-for="m in messages" :key="m">{{m}}</li>
</ul>
</b-overlay>
</div>
I think key to solving this is finding the CSS selector that allows me to change the spinner's position to "fixed" as opposed to "absolute" which seems to be what bootstrap generates.
To get spinner on center of screen you need to make it as direct child of body.
If it is nested it will have restrict area inside immediate parents area.
Try to add that separately or once your DOM ready detach overlay and append to body tag.
I ran into the same issue. Adding this line of CSS on the component resolved it for me:
<style>
.position-absolute {
position: fixed !important;
}
</style>
Note: make sure to not include the scoped keyword in your <style> tag, as this will not work for Bootstrap classes.

What is the correct way to style canvas area is storybook

In storybook, all stories are sitting tight agains the top left corner of the container.
This is causing problems when displaying items that have visual appearance outside the relative container e.g. a box-shadow.
So I am wondering what is the best way to add margin to the surrounding container. I had a look in the theming docs of storybook, but could not find anything related?
In .storybook/preview.js, you can just add the following:
addDecorator(storyFn => (
<>
<div style={{ margin: '1rem' }}>{storyFn()}</div>
</>
))
This way all the stories will appear with a margin of 1rem.
Adding to my preview.js:
export const decorators = [
(Story) => (
<div style={{ margin: '3em'}}>
<Story />
</div>
)
]
solved the problem for me
It's better to add padding on each component because not all components needs margins.
For example, in your .stories.tsx file
const Template: ComponentStory<typeof IconButton> = (args) => (
<div style="padding: 20px"><YourComponent {...args} /></div>
)
You can even use layout parameter to center all stories in the UI globally.
See Story layout for more details.
<!-- Checkbox.stories.mdx -->
import { Meta } from '#storybook/addon-docs';
import { Checkbox } from './Checkbox';
<Meta
title="Checkbox"
parameters={{
layout: 'centered',
}}
component={Checkbox}
/>

React css layouting inner components

Imagine that I have such html code:
<header>
<div class="header__logo logo">
<img class="logo__img" ...>
<span class="logo__status"...>
</div>
</header>
Here
.logo - is class that has styles, special for logo component.
.header-logo - has styles positioning logo inside the header.
So in react inside header component I would like to have something like:
<header>
<Logo className="header__logo" />
<header/>
But I can't since react is not automaticly handle className property.
Here I see this options:
Create a div wrapper to the Logo component and add this class to wrapper. As for me it is not an elegant way because it produce a lot of unnecessary divs.
Add logic to the Logo component, that will handle className property and append all outer classes to the root div inside the component. This is also ugly, because I have to add this boilerplate logic each time I want to layout a component inside some other component.
What is the react approach for solving such problems?
Yes, you cannot provide className attribute to a react Component. If you want to provide custom class to the same component, you can provide the className as a prop to the component which is added as a className in the child component.
I believe u need to do something like this.
var Header = React.createClass({
render: function() {
return (
<header>
<Logo customClass="header__logo logo"/>
</header>
);
}
});
var Logo = React.createClass({
render: function() {
return (
<div className={this.props.customClass}>
<img className="logo__img" />
<span className="logo__status" ></span>
</div>
);
}
});
Let me know if this is what you wanted to know or something else.

Resources