Fullscreen detection with react styled-components - reactjs

I'm using React and styled-components. I would like to hide the Navbar when user switch full screen mode by pressing F11 (Chrome).
I have tried following:
const NavbarContainer = styled.div`
height: 30px;
background-color: mediumseagreen;
padding: 10px 20px;
display: flex;
justify-content: space-between;
align-items: center;
color: white;
& :fullscreen {
display: none;
};
`
What else is needed to make it work? Currently the Navbar is still visible when I go fullscreen.

We have two options to resolve the problem with fullscreen mode.
First solution:
In styled-components you will need to use the #media all and (display-mode: fullscreen) instead of the :fullscreen pseudo-class, because this pseudo-class works only with Fullscreen API.
This will triggered with F11 key as an on/off switch, however we cann't use the Esc key to cancel the fullscreen mode.
const NavbarContainer = styled.div`
height: 30px;
background-color: mediumseagreen;
padding: 10px 20px;
display: flex;
justify-content: space-between;
align-items: center;
color: white;
#media all and (display-mode: fullscreen) {
display: none;
}
`;
Second solution:
We using Fullscreen API, when we will call this API after that the :fullscreen pseudo-class will works. This approach is good if you want to use Esc key to exit from fullscreen mode, also to assign another key (like Enter) or element (like button) to trigger fullscreen mode.
The Fullscreen API adds methods to present a specific Element (and its descendants) in fullscreen mode, and to exit fullscreen mode once it is no longer needed. This makes it possible to present desired content—such as an online game—using the user's entire screen, removing all browser user interface elements and other applications from the screen until fullscreen mode is shut off. MDN
Although, if we using #media query in our css instead of :fullscreen pseudo-class, we also can to use F11 key as a trigger. As a plus, with this approach, we will recive two different notifications about of exiting the fullscreen mode.
import { useEffect, useRef } from "react";
import styled from "styled-components";
const NavbarContainer = styled.div`
height: 30px;
background-color: mediumseagreen;
padding: 10px 20px;
display: flex;
justify-content: space-between;
align-items: center;
color: white;
#media all and (display-mode: fullscreen) {
display: none;
}
`;
const FullScreenButton = styled.button`
padding: 0.5rem 1rem;
#media all and (display-mode: fullscreen) {
display: none;
}
`;
export default function App() {
const refNavbar = useRef<HTMLDivElement>(null);
useEffect(() => {
const navbar = refNavbar.current;
const actionFn = (event: KeyboardEvent) => {
if ((event.key === 'Enter') && navbar) {
navbar.requestFullscreen();
return;
}
};
document.addEventListener('keyup', actionFn, false);
return () => {
document.removeEventListener('keyup', actionFn, false);
};
}, []);
const fullScreenOnClick = () => {
const navbar = refNavbar.current;
if (!navbar) return;
navbar.requestFullscreen();
};
return (
<div className="App">
<NavbarContainer ref={refNavbar}>Navigation</NavbarContainer>
<section>
<p>(User content!)</p>
<FullScreenButton onClick={fullScreenOnClick}>Fullscreen mode</FullScreenButton>
</section>
</div>
);
}
Caveat: Fullscreen API with assigned F11 key as trigger.
If you will try to assign the F11 key using the Fullscreen API to be able to exit also with the Esc key you will get strange behavior. It may be the cause of two different events Fullscreen API (with Esc key) and F11 key.
Fullscreen API issue with F11 and Esc buttons.
F11 key can exit programmatic-fullscreen, but programmatic-exitFullscreen cannot exit F11-fullscreen. Which is the problem you are running into. Also, Esc key cannot exit F11-fullscreen, but does exit programmatic-fullscreen. Fullscreen API not working if triggered with F11
Additionally:
Another interesting issue about :fullscreen pseudo-class. If you want to hide more than one element (like a button), this doesn't works as it will be bind to the current element. It's better to use the #media query.
Navbar and botton have a :fullscreen pseudo-class

The way it works:
const NavbarContainer = styled.div`
height: 30px;
background-color: blueviolet;
padding: 10px 20px;
display: flex;
justify-content: space-between;
align-items: center;
color: white;
#media all and (display-mode: fullscreen) {
display: none;
}
`;
The :fullscreen pseudo-class is used for a different purpose. Using javascript you can represent any DOM element to full-screen.
For example, if you will do the following thing:
document.querySelector('#navbar')?.requestFullscreen()
...then #navbar:fullscreen will work.

I think that was it
const NavbarContainer = styled.div`
height: 30px;
background-color: mediumseagreen;
padding: 10px 20px;
display: flex;
justify-content: space-between;
align-items: center;
color: white;
&::-webkit-full-screen {
display: none;
}
`

Related

After upgrade to version 5 'styled-components' is broken

I have the below components made with styled-components. I used to work fine with version 4.2.0. In order to cover my App with unit-tests, I upgraded styled-components to the version: 5.3.6.
After that, styled components stopped working on the "first render" when I am running a pre-compiled bundle. Under "development server" everything is still running normally.
However, when the page renders from a bundle, styles are missing. When I inspect the page, there is a style name my divs, and those styles do not exist.
My components are below:
import styled from 'styled-components';
export default styled.div`
text-align: center;
width: 46px;
min-height: 100vh;
flex-direction: column;
background-color: ${({ admin }) => (admin ? '#ffffff' : '#262626')};
overflow: hidden;
white-space: nowrap;
&:hover {
width: 250px;
text-align: left;
}
#media (max-width: 768px) {
display: none;
&.mobileOpen {
display: flex;
&:hover {
width: 46px;
text-align: left;
}
}
`;
export const MobileNavBar = styled.div`
#media (min-width: 769px) {
display: none;
}
#media (max-width: 768px) {
position: fixed;
z-index: 10;
text-align: center;
width: 100vw;
height: 60px;
flex-direction: row;
background-color: ${({ admin }) => (admin ? '#ffffff' : '#262626')};
overflow: hidden;
white-space: nowrap;
justify-content: space-between;
}
`;
export const MobileNavBarOpen = styled.div`
position: fixed;
top: 60px;
text-align: center;
width: 46px;
height: 100vh;
flex-direction: column;
background-color: ${({ admin }) => (admin ? '#ffffff' : '#262626')};
overflow: hidden;
white-space: nowrap;
padding-bottom: 100px;
&:hover {
width: 250px;
text-align: left;
}
#media (max-width: 768px) {
display: none;
&.mobileOpen {
display: flex;
&:hover {
width: 46px;
text-align: left;
}
}
`;
My best guess is that styles are generated, then there is a render, and the class name changes under this re-render. The new style-class name is different from the previous one, so my styles are not being associated with the components. I don't have SSR or anything fancy here, just building the bundle with CRA npm run build.
Interestingly, if I press the browser refresh button, the styles appear fine.
What could I do to fix this?

Styled Components Injects wrong classes on wrong elements

I'm witnessing a weird behavior when in styled-components with SSR in remix.run
I have a ProductCard Component that renders a normal product card with styled-components
ProductCard.tsx
import Button from "../Button";
function ProductCard({ product }: props) {
return (
<>
<Wrapper>
....
<ButtonsWrapper>
<Cart
onClick={addToCart}
mode={addedToCart ? "secondary" : "primary"}
disabled={loading}
key="cart-button"
>
{addedToCart ? "Added!" : "Add to cart"}
{loading && <LoadingSpinner src="/images/responses/loader.svg" />}
</Cart>
<ShareButton mode="secondary" aria-label="share">
<Icon id="share" />
</ShareButton>
</ButtonsWrapper>
</Wrapper>
</>
);
}
const Cart = styled(Button)`
flex: 1.1;
display: flex;
justify-content: center;
gap: 10px;
`;
const ShareButton = styled(Button)`
padding: 0.9rem;
`;
const Wrapper = styled.div`
--border-radius: ${clamp(15, 20)};
--columnGap: ${clamp(20, 30)};
display: flex;
flex-direction: column;
gap: var(--columnGap);
justify-content: space-between;
width: 100%;
height: 100%;
margin: auto;
background-color: var(--azure-15);
padding: 1.9rem 1.5rem;
border-radius: var(--border-radius);
box-shadow: var(--box-shadow-lg);
border: var(--border-lg);
`;
const ButtonsWrapper = styled.div`
display: flex;
justify-content: space-between;
gap: 0.625rem;
`;
export default ProductCard;
Button.tsx
const Button = styled.button<{ mode: "primary" | "secondary" | "dark" }>`
display: grid;
/* justify-content: center; */
align-items: center;
text-align: center;
color: var(--mintCream);
padding: ${clamp(9, 10)} ${clamp(20, 30)}; // this clamp function just generates the css clamp func with calculating the values with some equations
box-shadow: var(--box-shadow-md);
border: var(--border-md);
border-radius: 12px;
text-decoration: none;
cursor: pointer;
transition: all 500ms ease;
font-size: ${clamp(13, 16)};
&:disabled {
cursor: not-allowed;
opacity: 0.7;
}
#media (hover: hover) and (pointer: fine) {
&:hover:enabled {
transform: translateY(-2px); }
}
width: fit-content;
`;
The normal render of this Component is as follows
But when navigating to another path and returning to it on / , it renders like this
This problem only happens in production and works fine on local server...
when inspecting elements, I find that the class name of the Cart Component is also injected into the ShareButton Element
I can't find an explanation for this problem and it gets weirder... When I swap the order of the variables Cart and ShareButton or swap them with the Wrapper Element, some other weird behaviors happen like the one below
In this case, the class name of the Cart Component got injected on the parent elemnt of the parent element of the ProductCard Component
I've probably hit on 4 of these rendering issues but all of them share the same problem, the class name of the Cart Components gets injected on a wrong dom element, whether it's a parent or a sibiling
You can view the first weird behaviour here https://store.ieeenu.com
You will find the product component on the root path, navigate to some path like categories/circuits-1-ecen101 and return to the root and you will see the issue
also, you can review the second weird behavior in a previous build here
https://ieee-nu-store-r243eocii-omarkhled.vercel.app/
I just changed the initialization order of the Cart and ShareButton Components as I said earlier
I don't know whether this problem is from styled-components or from remix (this is the first time for me using remix), it's mentioned here https://github.com/remix-run/remix/issues/1032 that the lack of the babel-plugin-styled-components in remix.run introduces some problems in rehydration but I'm not sure that this is the issue I'm facing...
Thanks for reading this till the end and excuse my English, I'm not a native speaker :"

Effect to selected link gastby styled-component

I have a header and I want to mark the link currently by selecting.
With Styled-Component I must write something like: Const NavLink = styled (link) ... But with the properties of the NAV element there is one that is called ActiveClassname and it can be put on an already defined class, my question is how I define that Independent class with Styled-Component.
I would like to create a class that is called something like Linkactive and that can happen something so ActiveClassname = "Linkactive". But I have not been able to.
code of navMenu
<NavMenu>
{menuData.map((item, index) => (
<NavLink to={item.link} key={index} activeClassName="active">
{item.title}
</NavLink>
))}
</NavMenu>
code with styled-component
const NavMenu = styled.div`
display: flex;
align-items: center;
/* margin-right: -48px; */
#media screen and (max-width: 768px) {
display: none;
}`
const NavLink = styled(Link)`
color: #00286d;
display: flex;
align-items: center;
text-decoration: none;
padding: 0 1rem;
height: 100%;
cursor: pointer;
`
You can define static props/attributes using .attrs
This is a chainable method that attaches some props to a styled
component.
const NavLink = styled(Link).attrs(() => ({
activeClassName: "LinkActive",
}))`
color: #00286d;
display: flex;
align-items: center;
text-decoration: none;
padding: 0 1rem;
height: 100%;
cursor: pointer;
&.LinkActive {
// Apply active style here
}
`
If you wanted to use the activeClassName. You can create a class selector on the styling of your NavMenu.
That way, it would only affect .active class of direct/deep child nodes of your NavMenu
const NavMenu = styled.div`
display: flex;
align-items: center;
& .active {
// whatever styling you want
}
#media screen and (max-width: 768px) {
display: none;
}
`;

styled-component dropdown make parent:hover color stay while child:hover

I'm trying to make the parent background color stay changed on hover as I continue to hover over the dropdown items.
https://zqy0v.csb.app/dropdowns < dropdown
import React from "react";
import styled from "styled-components";
//============================================ styles =============================================
const DivDropdownContent = styled.div`
display: none;
position: absolute;
background-color: #f9f9f9;
min-width: 24.7rem;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
z-index: 1;
`;
const DivDropdown = styled.div`
position: relative;
display: inline-block;
&:hover ${DivDropdownContent} {
display: block;
}
`;
const SpanDropdownTitle = styled.div`
font-size: 1.6rem;
font-weight: bold;
padding: 2rem 6rem;
border-radius: 0.6rem;
border: 1px solid black;
&:hover {
cursor: pointer;
}
`;
const ItemDropdown = styled.p`
padding: 1rem;
&:hover {
cursor: pointer;
background: lightgray;
}
`;
//=========================================== component ===========================================
const BasicDropdown = props => {
return (
<DivDropdown>
<SpanDropdownTitle>Basic Dropdown</SpanDropdownTitle>
<DivDropdownContent>
<ItemDropdown>Item 1</ItemDropdown>
<ItemDropdown>Item 2</ItemDropdown>
<ItemDropdown>Item 3</ItemDropdown>
</DivDropdownContent>
</DivDropdown>
);
};
export default BasicDropdown;
Basically I would like the background color to stay changed for the parent while hovering over the child items in the dropdown, much like is done here https://woocommerce.com/
Is there an easy way to do this, or do I have to start getting complicated with using state and onPointerEnter and onPointerLeave?
I finally ended up finding the solution, and am a bit embarrassed.
const DivDropdown = styled.div`
position: relative;
display: inline-block;
&:hover ${DivDropdownContent} {
display: block;
}
`;
The Issue: ^This was only targeting the nested component when I added the background cover to the hover.
const DivDropdown = styled.div`
position: relative;
display: inline-block;
&:hover {
background: lightgray;
}
&:hover ${DivDropdownContent} {
display: block;
}
`;
The Fix: ^By adding the above, I was able to correct the behavior.
I'm going to leave this question up, because I wasn't able to find much tutorials on this through my internet searching. I think this is a fairly clean solution and think it will help others searching.

ReactJs - onClick not firing

Probably a super noobie question, but does anyone know why my onClick is not firing? I have tried changing the z-index in my CSS in case the button was too far back, but this did not change anything.
Here is my button module:
import React from 'react';
import classes from './button.module.css';
const button = (props)=>{
return(
<button onClick={()=>{console.log("hello");props.select()}} className={classes.button}>
<div className={classes.text_center}>
<div className={classes.button_text}>{props.text}</div></div>
</button>
);
}
export default button;
Later on I call the module:
this.state.skills?null:<Button select={()=>{console.log("hi");this.setState({skills:true})}} text={"Skills"}></Button>}.
The button actually displays fine, and the text is passed as a prop, but unfortunately I can't get the onClick to fire. Neither of the two console.log statements fire.
All help is appreciated.
///
As requested in the comments button.module.css:
#font-face {
font-family: 'Raleway';
src: url('../../../Fonts/Raleway/Raleway-Light.ttf') format('truetype') /* IE6-IE8 */
}
.button_choice{
width:10vw;
height:10vh;
top:25%;
border: 2px solid #4ca3dd;
position: relative;
display: inline-block;
margin-left:5vw;
background-color: white;
vertical-align: middle;
border-radius:10px;
padding:5px;
}
.button_choice:hover{
background-color: red;
}
.text_center{
height:100%;
width:100%;
position:relative;
display: table;
}
.text_center:hover{
background-color: blue;
}
.button_text{
font-family:"Raleway";
position:relative;
line-height: 30px;
font-size: 20px;
text-align: center;
display: table-cell;
vertical-align: middle;
}
/////
Slight break through :/, when considering the 3 classes below, .background_init is a div spreading over the whole page. On the press of a button, this div slides to half of the size on the left by changing to the class .background_left. The buttons are contained within background_right. If I change height in .background_left to 200px, the buttons work (including hover), but obviously this completely messes up my styling. Any suggestions?
.background_init{
width:100vw;
height:100vh;
background-color: #4ca3dd;
}
.background_left{
width:50vw;
height:100vh;
background-color: #4ca3dd;
transition: width 2s;
}
.background_right{
overflow: auto;
width:50vw;
height:100vh;
transition: width 2s;
}
I am not sure why this works, but instead of using 100vh and 100vw, I used display:absolute and width:50%/ 100% and height:100%. If anyone can explain why this works I would be extremely grateful.

Resources