Darkmode not working on tailwind headless UI - reactjs

Darkmode works everywhere in my react app, except on a headless ui combobox. I put a styled h1 in the same component and applied dark:bg-red-200(and any other style) no problem. The combobox accept all other tailwind utilities including attibutes like hover: but not the dark: property.

For others (such as me) stumbling upon this:
E.g. the Dialog-component (and I assume others too) render right in the body tag (source)
If you are using "the class strategy" to handle dark mode (i.e. adding a "dark" class to the wrapper) this will be a problem, because the class is not anymore parent to the Dialog
Solution I ended up using:
I ended up using useEffect to add the dark class to the body:
useEffect(() => {
if(darkMode){
document.body.classList.add('dark')
}else{
document.body.classList.remove('dark')
}
}, [darkMode])

Related

import { styled } from '#mui/material/styles'; displayName not showing

Using Mui styled function to style both jsx elements and MUI components. The displayName is not showing when I debug the element in Chrome or any browser for that matter.
Anyone know how to fix this.
I'm using Vite for my setup.
const MyComponent = styled('div')`
display: flex;
`;
As you can see from the below screenshot its not showing MyComponent display name instead its showing css-1vht943
You can see class only inside the Element tab. When you click on one of the lines which contains the class name.
You can find all the CSS related to that class under the styles tab including display name for your case. Please check the image below
If you want to have a name I think you can use styled('div', { name: 'MyTheme'}), then you will see something like <div class="css-t7mscw-MyTheme-root"></div>. Don't know if this is what you want, but here it is vaguely mentioned in the doc.

Description and default value not appearing in Storybook when rendering React/Mui components

I'm using Storybook v6.5.9 to render out my React/MUI components. Everything works fine, but I can't get the description or default value to appear in the canvas under the Controls tab:
The description appears fine when looking at the Docs tab:
There's nothing in the default export and I haven't changed any default options out of the box.
According to the React Storybook docs under controls here
Under the directory of .storybook/preview.js
We need to add the following under controls key
export const parameters = {
.....
controls: {
expanded: true
}
.....
}
This ensures that each control is viewed in expanded mode globally (both in Canvas and Docs tabs)

How can I test a popover from chakra-ui

I need to test a popover from chakra-ui in a React App.
I tried with this. But It does not find the popover. If I try by text, then I cannot assert if it is visible.
it('show a popover when hover terms and conditions', () => {
render(<SummaryForm />);
const link = screen.getByText(/terms and conditions/i);
const popover = screen.getByRole('dialog');
expect(popover.parentNode).not.toBeVisible();
userEvent.click(link);
expect(popover.parentNode).toBeVisible();
});
Try using the hidden option of the API:
const popover = screen.getByRole('dialog', {hidden: true})
ChakraUI renders a wrapper div around the section that has the dialog role. You can see this by using screen.debug() if you are using the testing-library. Notice the wrapper controls the visibility of said section, which starts as hidden, with styling elements and aria tags.
Using the hidden option allows you to look amognst the elements that aren't visible in the accessibility tree.
Since you want to test the popover, you should know there are some issues with modifying and checking the visibility of the popover when using jest-dom.
The chakra Modal applies a transform style to toggle its visibility. toBeVisible only checks a limited set of style attributes - transform is not one of them - so you might have to check for those instead, for example:
For invisibility:
expect(screen.getByRole('dialog')).toHaveStyle('transform: translateX(0px) translateY(0.18967%) translateZ(0);')
try toBeInTheDocument() or toMatchSnapshot()

Dynamically changing Less variables in React Gatsby app with Ant Design at runtime

We are building a White Label platform using React, GatsbyJs and Ant Design. We are stuck with Gatsby and Ant Design because we are migrating from an existing system and changing any of those would bring huge impact. Also, we must have a single deploy. Having a build for each White Label is not an option.
So, we need to be able to change style (mainly color) at runtime.
The problem is: Ant Design uses less variables to define it's themes and we're not able to change them at runtime, not even with less's modifyVars.
The thing is we MUST change less variables, and not global CSS or use other means
Ant Design derivates the main variables many times to get adjacent properties. So, for instance, if we define #primary-color as red, when we add a Button to the screen, Ant Design also defines it's border color, hover color, and many other details with different shades of red.
This means that, if we were to use other styling tool, we would need to generate those color derivations and replace every little property for every component. This would be chaos.
Scenario
We are using gatsby-plugin-antd and gatsby-plugin-less to load less and change vars at build time. Our gatsby-config.js looks like this:
module.exports = {
siteMetadata: {
siteUrl: 'https://www.yourdomain.tld',
title: 'yourtitle'
},
plugins: [
'gatsby-plugin-root-import',
'gatsby-plugin-typescript',
{
resolve: 'gatsby-plugin-antd',
options: {
style: true
}
},
{
resolve: 'gatsby-plugin-less',
options: {
lessOptions: {
javascriptEnabled: true,
modifyVars: {
'primary-color': '#FFFFFF',
'link-color': '#000000',
'success-color': '#FFFFFF',
'warning-color': '#000000'
}
}
}
}
]
};
We import styling in our gatsby-browser.js file:
import './src/styles/index';
Our styles/index has:
import 'tachyons';
import './global.css';
import './antd.less';
antd.less:
#import '~antd/dist/antd.less';
And global.css has some general CSS for the project.
It's working fine with the defined variables at build time.
What we attempted so far...
We have tried out this plugin:
https://github.com/mzohaibqc/antd-theme-webpack-plugin
Which supposedly does exactly what we need. But there's no example using Gatsby.
We then tried to add the plugin using the gatsby-node.js as mentioned here:
https://www.gatsbyjs.com/docs/how-to/custom-configuration/add-custom-webpack-config/
First, we tried using index.html as the indexFileName for the pluggin. It just doesn't work.
Then, following the plugin docs, we tried using indexFileName as false and importing the following scripts using Helmet at our pages/index.tsx:
<script> window.less = { async: false, env: 'production' };
</script> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/less.js/2.7.2/less.min.js"></script> ```
Also didn't work. If we define indexFileName as false, we get memory over the heap.
If we keep indexFileName as 'index.html' and just add the scripts, we are able to call window.less.modifyVars and it returns successfully (we are logging the Promise's then and error) but it doesn't affect antd's variables.
We then tried doing something similar, but instead of loading less externally, we installed it as a node_module and imported it to the file and used it directly in a similar fashion. Got the same result: modifyVars runs and returns successfully but doesn't affect antd.
Then, we tried something a bit different: we removed gatsby plugins and tried importing less from antd directly, as suggested here:
https://ant.design/docs/react/customize-theme
So we imported it like this:
#import '~antd/lib/style/themes/default.less';
#import '~antd/dist/antd.less';
#import 'your-theme-file.less';
Also, no good. It's different from the previous scenario, because style gets updated after you save your code. No need to stop Gatsby, as the first solutions. But, modifyVars still has no affect on antd components.
Then, to isolate the issue, we tried to style a basic HTML component - a button - to check if the issue was with gatsby or antd. And... still no success. less.modifyVars didn't work to change a basic button style on runtime.
So, we think it's probably something between Gatsby and Less. We checked gatsby-plugin-antd and gatsby-plugin-less to see if we could find something, but found nothing useful.
We assume that the "less instance" or "less context" used by gatsby's less-loader during build time is not the same we are calling modifyVars on. So it doesn't affect the original vars.
Totally stuck. Please, help!
EDIT - SOLUTION
Ant Design team has just released - TODAY - a new alpha version that includes dynamic theming, using CSS Variables.
https://ant.design/docs/react/customize-theme-variable
It works fine, so far. Closing the issue.
EDIT 2
There's a more detailed solution on the accepted answer.
Ant Design team has just released - TODAY - a new alpha version that includes dynamic theming, using CSS Variables.
https://ant.design/docs/react/customize-theme-variable
It works fine, so far.
EDIT - Detailed solution
I removed gatsby-plugin-antd and gatsby-plugin-less from the project. Also removed the import of antd less file.
Instead, in my styles/index.tsx (which is imported in gatsby-browser.js), I'm importing the variables.min.css file:
import 'antd/dist/antd.variable.min.css';
Then, whenever I want to change Ant Design variables, I just use:
import { ConfigProvider } from 'antd';
...
ConfigProvider.config({
theme: {
primaryColor: '#[DESIRED_COLOR_HEX]'
}
});
Provider
Since this has to be done every time the site is loaded, I'm creating a ThemeProvider that wraps every page and defines the theme. It fetches theme data from the backend and sets Ant Design theme variables.
Example code:
import { Spin } from 'antd';
import React, { useEffect, useState } from 'react';
import { ConfigProvider } from 'antd';
import { Theme } from './theme.interface';
interface Props {
children: React.ReactNode;
}
export const ThemeProvider = ({ children }: Props): JSX.Element => {
const [themeVars, setThemeVars] = useState<Theme>(null);
useEffect(() => {
async function fetchMyAPI() {
const result = await getThemeFromBackend(); // Make API call with Axios
if (result) setThemeVars(result);
}
fetchMyAPI();
}, []);
useEffect(() => {
if (themeVars) {
ConfigProvider.config({
theme: {
primaryColor: `#${themeVars.primaryColor}`
}
});
}
}, [themeVars]);
return <div>{!themeVars ? <Spin size="large" /> : <>{children}</>}</div>;
};
And it can be used like this:
...
<ThemeProvider>
<h1>My page header</h1>
<p>Page content...</p>
</ThemeProvider>
...
Note: You can save theme data on local storage for performance improvement, so you don't have to call your backend everytime your site reloads. Maybe you'll just have to refresh it from time to time.

How to add mobile gestures (eg. touch & swipe) to a React Bootstrap carousel component?

This similar question has dozens of answers for JQuery version but here I am using a react-bootstrap carousel component and I would like to add mobile gesture capability to it. How do I do it?
In JQuery, the straightforward answer will be to use Hammer.js to add event handler targeting the carousel and after that, use something along $(target_your_carousel).carousel('next/prev') to slide next/prev.
In React, however, we have ref to target the carousel but how do we even activate the next/prev?
One more way may be through a popular react library (as of May 2019) called react-swipeable. But after hooking it to the carousel, the same problem arises, how do we activate the next/prev?
Update: I realize that the "touch" data-attribute is introduced to upstream vanilla Bootstrap 4.2 as mentioned in react-bootstrap's Github issue. Maybe we can use latest version of Bootstrap with react-bootstrap?
In the end, I used this workaround.
Using react-swipeable, we can wrap the Carousel with Swipeable. Using ref to target the child Carousel and activate the child's methods.
import React, { Component } from 'react';
import { Swipeable } from 'react-swipeable';
class FooClass extends Components {
constructor() { ...
this.carouselRef = React.createRef(); }
render() {
onSwipedLeft: () => { this.carouselRef.current.next(); }
return {
<Carousel ref={this.carouselRef}> ...
This answer may be outdated soon because since "touch" data-attribute is introduced into upstream Bootstrap 4.2, the downstream react-bootstrap should support it in the future. In the future, just add "touch" attribute to the Carousel component.
<Carousel touch={true}>

Resources