I am using material-ui + react. I am building a simple form and everything is working fine except I have a small UI that Im not sure how to fix. Whenever I use the browser auto-complete, the input field remains highlighted. I've been digging through the CSS in the chrome dev tools and cannot find what is setting this.
This happens in all textfields right now.
Still happens when I remove custom styling from the component.
Hard to put into words so here are some screenshots:
Before:
After:
It then remains highlighted after I click away and select something else. However, if I type in a password this highlighting does not take place.
Component:
const useStyles = makeStyles(theme => ({
border: {
'& .MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline': {
borderColor: theme.palette.secondary.main
},
width: '75%',
alignSelf: 'center'
},
})
const LoginForm = () => {
const classes = useStyles();
<TextField
name='password'
type='password'
value={formik.values.password}
className={classes.border}
variant='outlined'
label='Password'
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={formik.touched.password && Boolean(formik.errors.password)}
helperText={formik.touched.password ? formik.errors.password : ''}
/>
}
Adding this to my theme.js seemed to fix the issue for me:
const theme = {
overrides: {
MuiOutlinedInput: {
input: {
'&:-webkit-autofill': {
WebkitBoxShadow: '0 0 0 100px #303030 inset',
WebkitTextFillColor: '#fff',
},
},
},
}
}
Related
I want to animate a search icon on click in React. I am using useRef hook to get the element and I pass some custom style to the component.
const [searchBar, setSearchBar ] = useState(false);
const searchIcon = useRef();
const searchIconStyle = {
transition: 'rotate .3s ease', // smooth transition
rotate: searchBar? "360deg" : "0",
}
function handleSearchClick(e) {
setSearchBar(prevState => !prevState);
}
So, the code from above is working first time when I click, but it doesn't afterwards. The search icon is a FontAwesome component
{searchBar && <input type="search" placeholder="Search product..."/>}
<FontAwesomeIcon icon={faMagnifyingGlass} className="search-icon"
onClick={handleSearchClick} ref={searchIcon} style={searchIconStyle}/>
How can I animate the icon on each click (depending on the change of searchBar variable?)
you're not setting the rotate property properly.
just change :
rotate: searchBar? "360deg" : "0",
to :
rotate: searchBar? "360deg" : "0deg",
this is a demo in codesandbox ( I used a button instead of FontAwesomeIcon cause you didn't tell which library you are using)
I like use classnames. Example for you:
className={classNames(
{ 'basicStyle': true},
{ 'withoutAnimation': !searchBar },
{ 'withAnimation': searchBar },
)}
So I am using storybook for my svelte + tailwind app, and I am now trying to make sure that I can toggle darkmode.
So for my tailwind.config.js I added this
module.exports = {
darkMode: "class",
and I installed this addon to storybook
https://github.com/hipstersmoothie/storybook-dark-mode
with this config .storybook/preview.js
export const parameters = {
darkMode: {
darkClass: "dark",
stylePreview: false,
},
And by looking in the DOM of the storybook iframe I can see that "dark" is applied to the body.
But when I create a component with this HTML
<div class="inline">
<div class="w-8 h-8 bg-blue-500 dark:bg-green-500" />
</div>
the box is always blue.
So I thought maybe purgecss was removing it, and so I added safelist: ["dark"] to it's options but without any luck.
So to make things more complicated I tested this component
<div class="inline">
<div class="w-8 h-8 bg-blue-500 dark:bg-green-500" />
</div>
<div class="inline dark">
<div class="w-8 h-8 bg-blue-500 dark:bg-green-500" />
</div>
and to my surprise, one of the boxes turned green.
Honestly, I am not entirely sure if this is because of svelte, storybook, tailwind, or the darkmode storybook plugin.
But I would really appreciate help if anyone has seen something similar
You could try ignoring purgecss when watching for storybook.
I am not sure about your exact setup but in my case I added a conditional in postcss.config.js for storybook to work correctly:
const isProduction =
!process.env.ROLLUP_WATCH &&
!process.env.LIVERELOAD &&
process.env.NODE_ENV !== 'development'
module.exports = {
plugins: [
require('tailwindcss'),
...(isProduction ? [purgecss] : [])
]
};
My .storybook/preview.js contains the following:
export const parameters = {
darkMode: {
stylePreview: true,
darkClass: 'dark',
lightClass: 'light',
}
}
The only thing which still doesn't work after this is the white text in dark mode, so I had to add .dark { color: white; } to my css.
I had this issue as well but it was because I defined a prefix of vc- in my tailwind.config.js file.
When I configured the addon https://github.com/hipstersmoothie/storybook-dark-mode, I used the class dark not vc-dark in .storybook/preview.js:
export const parameters = {
darkMode: {
dark: { ...themes.dark },
light: { ...themes.light },
darkClass: 'dark',
stylePreview: true
}
}
should be
export const parameters = {
darkMode: {
dark: { ...themes.dark },
light: { ...themes.light },
darkClass: 'vc-dark',
stylePreview: true
}
}
Not sure if you, (OP), have a prefix defined in your tailwind.config.js file but it's something to watch out for, if others are having the same issue.
Even with the prefix, you can still use the dark variant normally, just don't forget to use the prefix when referencing class names after the variant:
<div class="vc-bg-blue-500 dark:vc-bg-green-500" />
This happens because components are rendered inside of an iframe and storybook-dark-mode (SDM) only sets the class to "dark" on the body of the main document.
I verified this by inspecting and adding it manually. Assuming that you have darkMode: 'class' set in your tailwind config, you should see it work as soon as you set <body class="dark"> inside that iframe. This is why when OP wrapped it in a parent with "dark", it worked for that instance only.
First attempt
The question to me is how to get that class applied to the body of the iframe as well? Reading SDM docs, it implies that it would apply it to the app as well as the preview window, but that doesn't seem to happen for me.
Interestingly, there is an add-on called storybook-tailwind-dark-mode (STDM) which adds "dark" to the <html> of the iframed document, so that's good; but it's a separate button. You can have your components render in dark or light mode independent of dark mode on the app itself.
This is currently the only way it's working for me and I'd like to see/make a fork off one of these where it does both at once.
FWIW, without Tailwind, we were using a ThemeProvider from StyledComponents that leveraged useDarkMode() from SDM to then pass that down to all the StyledComponents (which we're migrating away from in favor of Tailwind). It would be nice to leverage that somehow.
Final answer
That previous paragraph gave me some inspiration. Storybook has decorators, which are basically functions that return components. We can wrap our stories with some HTML and give it a class based on useDarkMode().
Below is more or less what I ended up using and it's working great. One button to control dark mode, no need for an additional tailwind-specific dependency, and I'm still able to use my StyledComponent theming for the components that haven't been migrated yet.
.storybook/theme.js
import React from 'react'
import { ThemeProvider } from 'styled-components'
import { themeV2, GlobalStylesV2 } from 'propritary-design-library'
import { useDarkMode } from 'storybook-dark-mode'
import '../src/index.css'
const ThemeDecorator = storyFn => {
const mode = useDarkMode() ? 'dark' : 'light'
return (
<ThemeProvider theme={themeV2(mode)}>
<section className={mode}>
<GlobalStylesV2 />
{storyFn()}
</section>
</ThemeProvider>
)
}
export default ThemeDecorator
.storybook/preview.js
import { addDecorator } from '#storybook/react'
import ThemeDecorator from './theme'
addDecorator(ThemeDecorator)
export const parameters = {
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
}
Updated Question for more Clarity:
Need to display some texts and links as innerHTML(data from service/DB) in the Angular HTML and when user clicks, it should go to Typescript and programmatically navigates by router.navigate
Also, How to add DomSanitizer from #ViewChild/ElementRef
Added all example in below code
Here is the updated stackblitz code
As shown in screenshot from angular.io some texts and some links
Sorry, I didn't realize you answered my comment. Angular routing is not secondary, if you don't use Angular modules you'll end up with just an HTML/CSS/Typescript application. you need at least the RouterModule for Angular to be able to use routing and hence, do what it's supposed to with the DOM.
First:
You are not importing RouterModule
solution:
imports: [
BrowserModule,
FormsModule,
RouterModule.forRoot([]) // this one
]
Second:
You can't bind Angular events through innerHTML property
fix:
Make use of #ViewChild directive to change your innerHTML property and manually bind to the click event, so change in your app.component.html from
<div id="box" [innerHTML]="shouldbedivcontent" ></div>
to
<div #box id="box"></div>
Now, in your app.component.ts, add a property to hold a reference to that "box" element so you can later make some changes to the dom with it:
#ViewChild('box') container: ElementRef;
Implement AfterViewInit, that hook is where you will be able to actually handle your container, if you try using it for example in OnInit you'd get undefined because that component's html is not in the dom yet.
export class AppComponent implements AfterViewInit {
and
ngAfterViewInit() {
this.container.nativeElement.innerHTML = this.shouldbedivcontent;
this.container.nativeElement.addEventListener('click',
() => this.goto('bar')
);
}
change shouldbedivcontent property from:
'1) this is a click
<a (click)="goto("bar")">Click</a><br>
2)this is with routerlink
<a routerLink="" (click)="goto("bar")">Click</a><br>
3)This only works with href
bar and test'
to
'1) this is a click
<a id="link_1">Click</a><br>
2)this is with routerlink
<a [routerLink]="" (click)="goto(\'bar\')">Click</a><br>
3)This only works with href
bar and test'
And even so you'd still not get the default anchor style unless you apply some styling yourself.
Third
You are not HTML sanitizing, which could be dangerous. read more here
MY SUGGESTION:
Seems like a lot to do for you and a lot to read for someone else working alongside you for something you could easily do like in the example below!
Move your html to your app.component.html:
<div id="box">
1) this is a click
<a (click)="goto('bar')">Click</a><br>
2)this is with routerlink
<a routerLink="" (click)="goto('bar')">Click</a><br>
3)This only works with href
bar and test
</div>
<p>Below is actual content</p>
You'll notice that everything works now, except the anchor without routerLink or href, because that's not a link.
EDIT:
Looking at the new stackblitz, i suggest a change of approach, binding to innerHTML is ok when working with plain text or even some simple html but not a great choice to bind events or routing logic.
Angular's Renderer2 provides with a bunch of methods to dyncamically add elements to the DOM. With that on the table, you just need a little effort to take that simple html you get from your backend and turn it into something like (paste this property in your code to test it along the rest of the code provided below):
public jsonHTML = [
{
tagName: '',
text: 'some text with click ',
attributes: {
}
},
{
tagName: 'a',
text: 'bar',
attributes: {
value: 'bar' // goto parameter
}
},
{
tagName: '',
text: ' some more text with click ',
attributes: {
}
},
{
tagName: 'a',
text: 'foo',
attributes: {
value: 'foo' // goto parameter
}
}
]
Once you have it, it's way easier to create all of those elements dynamically:
this is for the code in your Q1:
Inject Renderer2 with private r2: Renderer2
And replace the Q1 related code in AfterViewInit hook to:
const parent = this.r2.createElement('div'); // container div to our stuff
this.jsonHTML.forEach((element) => {
const attributes = Object.keys(element.attributes);
const el = element.tagName && this.r2.createElement(element.tagName);
const text = this.r2.createText(element.text);
if (!el) { // when there's no tag to create we just create text directly into the div.
this.r2.appendChild(
parent,
text
);
} else { // otherwise we create it inside <a></a>
this.r2.appendChild(
el,
text
);
this.r2.appendChild(
parent,
el
);
}
if (attributes.length > 0) {
attributes.forEach((name) => {
if (el) {
this.r2.setAttribute(el, name, element.attributes[name]); // just the value attribute for now
if (name === 'value') {
this.r2.listen(el, 'click', () => {
this.goto(element.attributes[name]); // event binding with property "value" as parameter to navigate to
})
}
} else {
throw new Error('no html tag specified as element...');
}
})
}
})
this.r2.appendChild(this.container.nativeElement, parent); // div added to the DOM
No html sanitizer needed and no need to use routerLink either just inject Router and navigate to the route you want! Make improvements to the code t make it fit your needs, it should be at least a good starting point
Good Luck!
You have a css problem.
looks like a link
<a [routerLink]="something"></a> looks like a link, because if you inspect the HTML it actually gets an href property added because of routerLink
<a (click)="goTo()"></a> does NOT look like a link, because there is no href
Chrome and Safari default user agents css will not style <a> without an href (haven't confirmed Firefox but I'm sure its likely). Same thing for frameworks like bootstrap.
Updated stackblitz with CSS moved to global, not app.css
https://stackblitz.com/edit/angular-ivy-kkgmkc?embed=1&file=src/styles.css
This will style all links as the default blue, or -webkit-link if that browser supports it. It should be in your global.css file if you want it to work through the whole app.
a {
color: rgb(0, 0, 238);
color: -webkit-link;
cursor: pointer;
text-decoration: underline;
}
this works perfectly for me :D
#Directive({
selector: "[linkify]",
})
// * Apply Angular Routing behavior, PreventDefault behavior
export class CustomLinkDirective {
#Input()
appStyle: boolean = true;
constructor(
private router: Router,
private ref: ElementRef,
#Inject(PLATFORM_ID) private platformId: Object
) {}
#HostListener("click", ["$event"])
onClick(e: any) {
e.preventDefault();
const href = e.target.getAttribute("href");
href && this.router.navigate([href]);
}
ngAfterViewInit() {
if (isPlatformBrowser(this.platformId)) {
this.ref.nativeElement.querySelectorAll("a").forEach((a: HTMLElement) => {
const href = a.getAttribute("href");
href &&
this.appStyle &&
a.classList.add("text-indigo-600", "hover:text-indigo-500");
});
}
}
}
HOW I USE IT
<p linkify
class="mt-3 text-lg text-gray-500 include-link"
[innerHtml]="apiSectionText"
></p>
result
I'm wondering what the best way to style the gmap-autocomplete field like a vuetify v-text-field.
I've looked at Vuetify-google-autocomplete module but it's throwing lots of errors and being more or an issue than i expected.
Whats the easiest way to make
<gmap-autocomplete></gmap-autocomplete>
Look like
<v-text-field></v-text-field>
without changing functionality
I have implemented a google address autocomplete with vue and vuetify.
You need to use "v-autocomplete" instead of "v-text-field". Its a vuetify component too
I will share some code about my implementation with the basics (my component is more complex)
Keep in mind to put your APIKEY in the URL
Also, In my implementation, I have added debounce library for add some delay in the autocomplete, I can add the code with this feature if you wish
CODE:
<template>
<v-autocomplete
prepend-icon="account_box"
v-model="address"
:items="items"
name="address"
:search-input.sync="search"
label="Address"
placeholder="Address"
class="pa-3"
autocomplete="off"
:loading="loading"
:filter="d=>d"
color="secondary"
item-color="secondary"
return-object
#change="change"
></v-autocomplete>
</template>
<script>
export default {
data() {
return {
items: [],
search: null,
address: null
}
},
watch: {
search(){
//Optional: here you can add some delay
this.googleSearch()
}
},
methods: {
googleSearch() {
let url = 'https://maps.googleapis.com/maps/api/geocode/json?key={YOURAPIKEY}&address='
fetch(url + this.address)
.then((response) => {
return response.json()
})
.then(jsonResult => {
this.items = jsonResult.map(item => {
//You can explore and use other information inside "item" like latitude, longitude, country, City, zipCode
return {
text: item.formatted_address,
value: item.formatted_address
}
})
}).catch(err => {
//handle errors
console.log(err)
})
}
}
}
</script>
Try this one, worked for me:
https://www.npmjs.com/package/vuetify-google-autocomplete
npm i vuetify-google-autocomplete
I needed to bind "id" to something unique in order to have multiple instances of the field on the same page.
while not using the exact same thing I found out that I had to globally style the element to what I wanted it to be.
The below code is what I used:
<style global>
#vuetify-google-autocomplete-id {
border-top-width: 0px !important;
border-right-width: 0px !important;
border-bottom-width: 0px !important;
border-left-width: 0px !important;
}
</style>
I hope it can help anyone who is looking for a solution.
Hey everyone, I am using the React Semantic Ui Library and I have a question about theming.
I am using a menu collection and I want to custom 1 thing:
in semantic-UI/site/collections/menu.variables I have my variable #secondaryPointingActiveBorderColor: #black;
and I want to change his color if, but if I do that in this file that will be global for all menu and I want to edit the color just for one specific menu so I moved on my menu.overrides file but how can I select my variable with CSS?
In my project I am using the Semantic Ui Component like this :
<Tab className={styles.tab} menu={{ secondary: true, pointing: true }} panes={panes} />
In the picture, you can see the React Component and his HTML equivalent? I tried with
.tab.ui.pointing.secondary.menu{
border-color:red;
}
The selector was
.ui.secondary.pointing.menu .active.item {
border-color: red;
}
The class to target the required element in your case can be achieved by:
.ui.secondary.pointing.menu .active.item {
border-color: red;
}
But this till affect all the menu active items, so hence we need to have our own specific selecter.
So I'll be adding a class named as stack-overflow (change the name acc to your use case)
import React from "react";
import { Tab } from "semantic-ui-react";
import "./style.css";
const panes = [
{
menuItem: "Tab 1",
render: () => <Tab.Pane attached={false}>Tab 1 Content</Tab.Pane>
},
{
menuItem: "Tab 2",
render: () => <Tab.Pane attached={false}>Tab 2 Content</Tab.Pane>
},
{
menuItem: "Tab 3",
render: () => <Tab.Pane attached={false}>Tab 3 Content</Tab.Pane>
}
];
const TabExampleSecondaryPointing = () => (
<Tab
className="stack-overflow"
menu={{ secondary: true, pointing: true }}
panes={panes}
/>
);
export default TabExampleSecondaryPointing;
// style.css
.stack-overflow .ui.secondary.pointing.menu .active.item {
border-color: red;
}
Here is a sandbox for demonstration: Sandbox link