One component of my website is based on the following .js code:
items.add(
`field-${field.id()}`,
<div className="Mason-Field Form-group">
<label>
{field.icon() ? <>{icon(field.icon())} </> : null}
{field.name()}
</label>
,<div className="FormControl Mason-Inline-Answers">{answer_list}</div>,
</div>
);
In the website, the commas are literally in the JSX just like they appear in the output. This must be an oversight when the hyperscript was converted to JSX. See the following test post screenshot.
I personally am not able to fix this in the .js level. Is there a way to hide the commas in the CSS level?
Test pose
The approach is to set the font color of the outer div to transparent and then set it again on the children:
.Mason-Field.Form-group { color: transparent }
.Mason-Field.Form-group > * { color: initial }
Depending on your other classes FormControl and Mason-Inline-Answers, you might need to be more specific.
Related
I have been trying to change the underline color decoration of some text according to a specific value given to a React component via this method:
<span className={`underline underline-offset-4 decoration-4 decoration-${decorationColor ? decorationColor : 'primary'}`}> {sentence.text}</span>
However, it is not working correctly. When I inspect the HTML file it has indeed the color I wrote, for instance: decoration-secondary. Nevertheless, the text doesn't appear to be changing accordingly.
If I write directly 'decoration-secondary' instead of passing 'secondary' within the props and then using decoration-${decorationColor ? decorationColor : 'primary'}, it suddenly works.
I found out that this only happens whenever I had not previously directly written the class name within the file. For example: I have used 'bg-primary', 'bg-secondary', and several times in other parts of the app, and thus, when using `bg-${decorationColor ? decorationColor : 'primary'}' it just works perfectly.
TailwindCSS doesn't allow you to generate classes dynamically. So when you use the following to generate the class…
`underline underline-offset-4 decoration-4 decoration-${decorationColor ? decorationColor : 'primary'}
…TailwindCSS will not pick that up as a valid TailwindCSS class and therefore will not produce the necessary CSS.
Instead, you must include the full name of the class in your source code. You can return the full value like this
function myDecoStyle(decorationColor) {
if(decorationColor)
return "underline underline-offset-4 decoration-4 decoration-"+decorationColor;
else
return "underline underline-offset-4 decoration-4 decoration-primary";
}
where decorationColor is your colour value you are passing here.
By doing it this way, the entire string for every class is in your source code, so TailwindCSS will know to generate the applicable CSS.
And use it like
<span className={`${myDecoStyle(secondary)}`}> {sentence.text}</span>
Read more: https://tailwindcss.com/docs/content-configuration#class-detection-in-depth
In a couple of places of my app, I have some code I am not very proud of. I need to find some elements that are handled by materialize to manipulate them, so that they are displayed according to my needs.
So I do this two things in two different parts of my code:
// 1.- set style from grey (placeholder text) to black(input text) and erase placeholder only on 1rst option select
const dropdownWrapper = document.getElementsByClassName('select-dropdown dropdown-trigger')[0];
dropdownWrapper.setAttribute("style", "color:black;");
// 2.- remove AM PM labels from display
let ampmLabels = document.getElementsByClassName('timepicker-span-am-pm')[0];
ampmLabels.setAttribute("style", "display:none;");
I don't consider useRef because the elements are not part of any specific component. They are in the DOM put there by materialize when I initialize the materialize element in my component and I manipulate them from that component to fit my needs when they're displayed.
As I know there are no more elements of this type when I run de code, the document.getElementsByClassName('select-dropdown dropdown-trigger')[0]; works, but isn't there a more elegant way to find a manipulate dom elements to do this?
Edit:
The componenet where the color cannot be changed is an input type with a type="text" attribute:
html with dropdownWrapper.classList.add('text-black');:
<input class="select-dropdown dropdown-trigger text-black" type="text" readonly="true" data-target="select-options-ee9a6017-aef6-ecbf-c2a1-298693b77804">
html with dropdownWrapper.setAttribute("style", "color:black;");:
<input class="select-dropdown dropdown-trigger" type="text" readonly="true" data-target="select-options-ee9a6017-aef6-ecbf-c2a1-298693b77804" style="color: black;">
Seems that because of that the dropdownWrapper.classList.add('text-black'); does not work. This adds the text black to the class name in the class="select-dropdown dropdown-trigger text-black" (note the text-black at the end) but does not change the text color even if the .text-black {color: black} is added to the css file.
The style change with setAttribute, produces the style="color: black;" at the end of the html that is what seems what is actually changing the color.
You can do something like this:
function addClass(selector, className) {
const element = document.querySelector(selector);
element.classList.add(className);
}
/* maybe move these strings to constants, add comments*/
addClass('.select-dropdown.dropdown-trigger', 'text-black');
addClass('.timepicker-span-am-pm', 'hidden');
Tiny improvements:
You can use document.querySelector()
You can also add the styles in a CSS class and use classList API:
Long version:
const dropdownWrapper = document.querySelector('.select-dropdown.dropdown-trigger');
dropdownWrapper.classList.add('text-black');
const ampmLabels = document.querySelector('.timepicker-span-am-pm');
ampmLabels.classList.add('hidden');
I have multiple components in my project, most of which are simple containers for specific content, with a bit of styling. They typically look like this—
function Portion(props) {
return (
<div id={props.id} className={`portion ${props.className}`}>
{props.children}
</div>
)
}
I have the extra ${props.className} so that it’s easy to add more classes if need be. Now, the problem is that if there are no extra classes for that element, React adds an undefined class.
How can I avoid that?
Try using
${props.className || ""}
you can add a condition;
className={`portion ${props.className || ””}`}
So, expect two simple components that I have built:
import {Input} from 'semantic-ui-react';
import {Select} from 'semantic-ui-react';
const CategoriesDropdown = ({categories, onCategorySelected, selectedCategory}) => {
const handleChange = (e, {value})=>{
onCategorySelected(value);
};
return (
<Select placeholder="Select category" search options={categories} onChange={handleChange} value={selectedCategory} />
);
};
const IdentifiersInput = ({identifiers, onIdentifiersChanged}) => {
return (
<Input placeholder="Enter identifiers..." value={identifiers} onChange={onIdentifiersChanged}/>
);
};
Nothing fancy so far.
But now, I am building another component that displays those two in a flexbox row:
<Box>
<CategoriesDropdown categories={categories} selectedCategory={selectedCategoryId}
onCategorySelected={this.selectCategory}/>
<IdentifiersInput identifiers={identifiers} onIdentifiersChanged={this.changeIdentifiers}/>
</Box>
Unfortunately they are both displayed right next to each other without any margin in between.
Usually, I would just add a margin-left style to the second element, but because it is a React component, that doesn't work. Using style={{marginLeft: '20px'}} doesn't work as well, because the IdentifiersInput component doesn't use it.
I know that I can fix it by doing this: <Input style={style} ... inside the IdentifiersInput component.
However, this seems to be a very tedious way of achieving this goal. Basically, I have to add this to every single component I am writing.
I clearly must be missing something here. How am I supposed to apply such layout CSS properties to React components?
I think I understand.
1) Applying CSS directly to React Components does not work--I can confirm that.
2) Passing props down to the low level elements is tedious, confirmed but viable.
Notice hasMargin prop:
<Box>
<CategoriesDropdown
categories={categories}
selectedCategory={selectedCategoryId}
onCategorySelected={this.selectCategory}
/>
<IdentifiersInput
identifiers={identifiers}
onIdentifiersChanged={this.changeIdentifiers}
hasMargin
/>
</Box>
Possible input:
const IdentifiersInput = ({identifiers, onIdentifiersChanged, className, hasMargin }) => {
return (
<Input
className={className}
placeholder="Enter identifiers..."
value={identifiers}
onChange={onIdentifiersChanged}
style={hasMargin ? ({ marginLeft: '0.8rem' }) : ({})}
/>
);
};
NOTE: I do not like style as much as I like adding an additional class because classes can be adjusted via media queries:
const IdentifiersInput = ({identifiers, onIdentifiersChanged, className, hasMargin }) => {
const inputPosition = hasMargin ? `${className} margin-sm` : className
return (
<Input
className={inputPosition}
placeholder="Enter identifiers..."
value={identifiers}
onChange={onIdentifiersChanged}
/>
);
};
If you find inputPosition too verbose as shown above:
className={hasMargin ? `${className} margin-sm` : className}
3) You could accomplish it using a divider Component, sacreligious yet rapidly effective
<Box>
<CategoriesDropdown
categories={categories}
selectedCategory={selectedCategoryId}
onCategorySelected={this.selectCategory}
/>
<div className="divider" />
<IdentifiersInput
identifiers={identifiers}
onIdentifiersChanged={this.changeIdentifiers}
/>
</Box>
You can use media queries and control padding at any breakpoints if desired.
4) CSS pseudo-elements or pseudo-classes, I don't see any mention of them in answers so far.
MDN: https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes
CSS Tricks: https://css-tricks.com/pseudo-class-selectors/
Usually, when you have a random collection of DOM elements, you can calculate a way using CSS to wrangle them into the correct position. The list of available pseudo-classes is in that MDN link. It honestly helps to just look at them and reason about potential combinations.
My current issue is I don't know what is in <Box /> other than it probably has a div with display: flex; on it. If all we have to go on is that and the div is called <div className="Box">, maybe some CSS like this will fix it:
.Box {
display: flex;
}
.Box:first-child {
margin-right: 0.8rem;
}
This is why it is extremely important to know exactly what the surrounding elements will or can be, and exactly which CSS classes/IDs are nearby. We are basically trying to hook into something and correctly identify the left child in Box and add margin to the right of it, or target the right child and add margin to the left of it (or depending on everything, target both and split the additional margin onto both).
Remember there is also ::before and ::after. You are welcome to get creative and find a solution that involves position:relative and position: absolute and adds no markup.
I will leave my answer like that for now, because I think either you already thought about pseudo-selectors, or you will quickly find something that works :)
That or the divider is actually quite viable. The fact you can use media queries alleviates you from concern of future management or scalability of the components. I would not say the same about <div style={{}} />.
As your component specializes another single component it would be a good practice to pass any props your wrapper does not care for to the wrapped component. Otherwise you will loose the ability to use the api of the original <Input>component including passing styles to it:
const IdentifiersInput = ({identifiers, onIdentifiersChanged, ...props}) = (
<Input
{...props}
placeholder="Enter identifiers..."
value={identifiers}
onChange={onIdentifiersChanged}
/>
);
There may be valid cases where you explicitly want to prevent users to be able to pass props to the wrapped component but that does not look like one of those to me.
I clearly must be missing something here. How am I supposed to apply
such layout CSS properties to React components?
You did not miss something. A react component has no generic way to be styled because it is no DOM element. It can have a very complicated and nested DOM representation or no representation at all. So at some point you as the designer of the component have to decided where the styles, ids and class names should be applied. In your case it is as easy as passing these props down and let the <Input> and <Select>component decide. I find that to be quite elegant rather than tedious.
I see several ways to do it, but the easiest I see would be to pass a className to IdentifiersInput like so:
<IdentifiersInput className="marginLeft" identifiers={identifiers} onIdentifiersChanged={this.changeIdentifiers}/>
Inside IdentifiersInput I would just set that class to the Input:
const IdentifiersInput = ({identifiers, onIdentifiersChanged, className}) => {
return (
<Input className={className} placeholder="Enter identifiers..." value={identifiers} onChange={onIdentifiersChanged}/>
);
};
Semantic UI's Input element can receive a className prop.
I would then just use CSS or SCSS to add styles to that particular class. In this case, the margin you want.
I am using this color picker http://acko.net/blog/farbtastic-jquery-color-picker-plug-in/
Its by steven
Though from the docs i am using it as
$(document).ready(function() {
$('#picker').farbtastic('#color');
});
And html code is `
`
I have to create it into two separate division. I want color hex value to be changed in input but shows the colour in another division background.
If i use it like this
<div id="colorpicker"></div>
<input type="text" id="color" name="color" value="#123456" />
<div id='color' ></div>
The update will take place in one id so in this only input will change with color and its hex value.
From the script http://acko.net/files/farbtastic/demo/farbtastic.js
it takes only one parameter in function so i want this way, that when ever color of division change the color hex value should update under input.
You still can't use two elements with the same ID. It doesn't work that way. From the script authors web page, passing in the destination ID gives you exactly what the demo does. If you scroll further down, there are instructions where you can pass in a function. This is what you want to do:
$('#colorpicker').farbtastic(setColors);
var setColors = function(color){
$('#colorText').val(color);
$('#colorBackground').css('background-color' : color);
}
I haven't tested this, but you should get the point and be on the right road.
[UPDATE]
I tested this in a fiddle, and it doesn't work, though it is exact per the authors documentation. So what you can do is:
<div id="colorpicker"></div>
<input type="text" id="colorText" value="#123456" />
<div id="colorDiv">div<div>
Two seperate ID's, one for the div, one for the text, and just select them both:
var domNodes = $('#colorDiv, #colorText');
$('#colorpicker').farbtastic(domNodes);
Here is the Fiddle
Also, if you don't want the input to have the background color at all, you can override the default functionality and do whatever you want like:
JSFiddle
$.farbtastic(colorpicker).linkTo(callBack);
function callBack(color) {
$('#colorText').val(color);
$('#colorDiv').css('background-color', color);
}