I have a React component which should return a <h1> with an position: absolute <div> as accent after the first word-break:
e.g. First example (accent cube positioned fine)
e.g. Second example (accent cube should be positioned right after "SIT")
Since I want to use this component for several projects and different text lengths, I am trying to find a dynamic solution rather than setting the CSS on each of the accent cubes.
Am I missing an CSS property? Or is JS necessary to recalculate the <div> after word-breaks?
Have already tried inline, etc. But the gap (between text and div) on some word-breaks still persist.
Acceptance criteria: Text comes from CMS and would like to make the component take a string without the need for special characters: e.g. |,etc. to replace with the cube div
My code so far (with Tailwind):
type IHeadingProps = {
text: string | JSX.Element;
classList?: string;
url?: string;
cube?: "small" | "base" | "large";
onClick?: () => {};
};
const Heading = ({ text, classList, cube, url, onClick }: IHeadingProps) => {
const headingClasses = classList
? classList
: "text-4xl xl:text-6xl uppercase";
let cubeDivSize;
if (cube === "small") {
cubeDivSize = "h-3 w-3 lg:h-4 lg:w-4 xl:h-5 xl:w-5";
} else if (cube === "base") {
cubeDivSize = "h-4 w-4 lg:h-5 lg:w-5 xl:h-6 xl:w-6";
} else if (cube === "large") {
cubeDivSize = "h-5 w-5 lg:h-6 lg:w-6 xl:h-7 xl:w-7";
}
const cubeDiv = (
<div
className={`absolute right-[-1rem] -top-3 rounded-sm bg-levaro-primary lg:right-[-1.5rem] lg:-top-4 xl:-top-5 xl:rounded ${cubeDivSize}`}
data-testid="accent-cube"></div>
);
if (url) {
return (
<h1 className={`${cube && "relative inline-block"} ${headingClasses}`}>
<a href={url}>
{text}
{cube && cubeDiv}
</a>
</h1>
);
} else {
return (
<h1
className={`${cube && "relative inline-block"} ${headingClasses}`}
onClick={onClick}>
{text}
{cube && cubeDiv}
</h1>
);
}
};
export default Heading;
Thanks in advance!
Related
Hello this is for a React/Gatsby website i'm working on.
I'm searching for a way to animate the child paragraph of a div using only CSS transition:
<div>
<p>{excerpt}</p>
</div>
Where excerpt is a variable i'm changing via Javascript when the cursor hovers the parent <div>.
This is the simplified React component. excerpt is a React state:
import React, { useState } from 'react'
const PostExcerpt = ({ post, featured }) => {
const [excerpt, setExcerpt] = useState(post.shortExcerpt)
const handleHover = (event, hover) => {
event.preventDefault()
if (hover) setExcerpt(post.longExcerpt)
else setExcerpt(post.shortExcerpt)
}
return (
<div
onPointerOver={(event) => {
handleHover(event, true)
}}
onPointerOut={(event) => {
handleHover(event, false)
}}
>
<p>{excerpt}</p>
</div>
)
}
export default PostExcerpt
The height of the <p> is adjusted automatically when content changes and i would like to animate the height change.
How can I transition height: 0; to height: auto; using CSS? doesn't apply because the height of my element is always set to auto. It simply changes because it follows content dimensions.
The problem I am having seems to defeat the very purpose of CSS in JS. I am using styled-compomnents. And when I tried to use a classname that is being used somewhere up in the react tree inside a styled component. The upper component classname styles somehow get applied to the classname I used down (very) the tree.
Steps to reproduce
Render UpperComponent anywhere in a react project.
const StyledContainer = styled.div`
.title {
color: red;
margin-bottom: 32px;
}
`;
const UpperComponent = () => {
return (
<StyledContainer>
<FirstComponent />
<h4 className="title"> text inside upper component </h4>
</StyledContainer>
);
};
const FirstStyledContainer = styled.div``;
const FirstComponent = () => {
return (
<FirstStyledContainer>
<h4 className="title">text inside first component</h4>
<SecondComponent />
</FirstStyledContainer>
);
};
const SecondComponent = () => {
return (
<div>
<h4 className="title">text inside second component</h4>
<ThirdComponent />
</div>
);
};
const ThirdComponent = () => {
return (
<div>
<h4 className="title">text inside second component </h4>
</div>
);
};
Expected Behavior
title classname in the UpperComponent should not affect it's descendants' elements with the same classname. It should be scoped only to <h4 className="title"> text inside upper component </h4>
Actual Behavior
.title { color: red; margin-bottom: 32px; } class styles get applied to all the components inside UpperComponent. title somehow makes it down to ThirdCompoent which is nested inide two components.
Is this expected behavior or am I missing something basic (best practice)?
If you want enforce the scoping - You can remove the class names and/or let "styled component" name them (generates a random hash class name) by creating a TitleStyle and attach to the title div (class name "title" can be removed). This should scope to that title only then. Right ?
Another alternative
Yes the FirstComponent and SecondComponent (etc) will catch the css rule from the top. This is the expected result for me. Its not like when we do this below !
<div style = {{color:"red"}}>Test</div>
This would apply the css inline to that div only.
I would slightly change the names of the title classes like so
const StyledContainer = styled.div`
.title {
color: red;
margin-bottom: 32px;
&.secondary { color: pink; }
&.thirdly { color: yellow; }
}
`;
const UpperComponent = () => {
return (
<StyledContainer>
<FirstComponent />
<h4 className="title"> text inside upper component </h4>
</StyledContainer>
);
};
const SecondComponent = () => {
return (
<div>
<h4 className="title secondary">text inside second component</h4>
<ThirdComponent />
</div>
);
};
const ThirdComponent = () => {
return (
<div>
<h4 className="title thirdly">text inside second component </h4>
</div>
);
};
The & is a SCSS operator and works fine with styled components.
CSS is more benifical to behave this way as passing css rules down is more effecient. Work with this effeciency ! You want to create site wide CSS patterns, try avoid specific targeting unless your sure its required (Which should be not too common).
What I do moslty is, created a styled component for the react component, so one per react components to handle all css/scss in that react component.
Daniel
This is working as it should. You're selecting all the .titles in that styled-component.
In the end, styled-components just generate a unique class name for every styled-component you made. So the rules of CSS still work there.
You can
You can select only the direct descendant .title.
const StyledContainer = styled.div`
>.title {
// rules...
}
`
Change the class name to something more specific.
Nest the CSS rule on the parent. So instead of this,
const StyledContainer = styled.div`
.title {
// rules...
}
`
Wrap your h4 with another element and do this
const StyledContainer = styled.div`
.wrapperClassName {
.title {
// rules...
}
}
`
I am trying to add a basic deck.gl (mapbox static map) to a react project - which I can do; however, once the map is loaded it takes up the entire page and any other information is hidden behind the map. For example, I have some text in a <p> above the map and it gets hidden behind the map, when it should show just above it.
Any attempt to resize the div that the map sits in has been unsuccessful:
margin-top, height etc..
The class is called DglMap
class DglMap extends Component {
render() {
const layers = [];
return (
<div className="dglMapStyle">
<DeckGL
initialViewState={initialViewState}
controller={true}
layers={layers}
>
<StaticMap mapboxApiAccessToken={MAPBOX_ACCESS_TOKEN} />
</DeckGL>
</div>
);
}
}
added to a class called Content
class Content extends Component {
state = {};
render() {
return (
<div>
<BaseMap />
</div>
);
}
}
added to app.js
function App() {
return (
<Router>
<div>
<SomeText />
<Route exact path="/" component={MainContent} />
</div>
</Router>
);
}
export default App;
The file SomeText returns <div><p>SomeText</p></div>
The expected result is for the map to show underneath the text and not show on top of it. In another case I may want to resize the map to a specific size; for example 500x500px.
Any help appreciated and happy to elaborate.
Cheers!
In the part of Deck.Gl where the width and the height of the canvas is set,
there seems to be this code:
if (width || width === 0) {
width = Number.isFinite(width) ? `${width}px` : width;
this.canvas.style.width = width;
}
if (height || height === 0) {
height = Number.isFinite(height) ? `${height}px` : height;
this.canvas.style.position = 'absolute';
this.canvas.style.height = height;
}
which adds absolute positioning regardless of width and height, which might cause some fo your problems. Try adding left and top css styles to move the canvas. Resizing of the canvas should however work without any problems, see snippet below that works.
<DeckGL width={width} height={height}></DeckGL>
I've build an app that displays many text areas. I personally use the app with two languages - English, and another language which is aligned to the right. By default the text-areas align to the left. If I want to change and align them to the right I can simply press right CTR+Shift. The app is build in React, and when the screen re-renders it is aligned to the left again. I want to somehow control the alignment - recognize if a user chooses to align in a certain way, and save it to the state. How can I recognize how the user chooses to align the text, or if he presses right or left CTR+Shift? And how do I change the text-area so the alignment is controlled?
const alignment = ['left', 'right', 'center'];
class Example extends React.component {
constructor() {
super();
this.state = { align: 'left' };
this.handleKeyDown = this.handleKeyDown.bind(this);
}
handleKeyDown(e) { // Passes click event to state
if (e.shiftKey && (e.metaKey || e.ctrlKey)) { // meta key for macbook support
this.setState({ align: 'right' });
}
}
render() {
return (
<div className={s.root}>
<div style={{ textAlign: this.state.align }}> // Sets div text alignment
<textarea onKeyDown={this.handleKeyDown} />
</div>
</div>
);
}
}
}
I Create a CKEditor Widget and the color and background color not enable when I Select for example a paragraphe.
Here is my widget
CKEDITOR.plugins.add( 'applivewidget', {
requires: 'widget',
icons: 'applivewidgetLeftCol,applivewidgetRightCol,applivewidgetThreeCol,applivewidgetTwoCol',
init: function( editor ) {
// Configurable settings
var allowedText = editor.config.applivewidget_allowedText != undefined ? editor.config.applivewidget_allowedText : 'font;div{background-color};h2{color};p{color, font} [font];span;br;ul;ol;li;strong;em;h3;img{ height, width } [!src,width,height];';
CKEDITOR.dialog.add( 'applivewidgetLeftCol', this.path + 'dialogs/applivewidget.js' );
var showButtons = editor.config.applivewidgetShowButtons != undefined ? editor.config.applivewidgetShowButtons : true;
// Define the widgets
editor.widgets.add( 'applivewidgetLeftCol', {
button: showButtons ? 'Add left column box' : undefined,
dialog: 'applivewidgetLeftCol',
template:
'<div class="span_wrapper col_1_2">' +
'<div class="span equal edit1 span1_3 wow bounceIn"><p class="nopadding"><img src="/sites/all/themes/cefort/images/img450_375.png" /></p></div>' +
'<div class="span equal edit2 span2_3 wow bounceIn"><h2>Sub Title</h2><p>Content</p></div>' +
'</div>',
init: function() {
var bgc = this.element.getChild(0).getStyle( 'background-color' );
if ( bgc )
this.setData( 'bgc', bgc );
},
data: function() {
if ( this.data.bgc == '' )
{
this.element.getChild(0).removeStyle( 'background-color' );
this.element.getChild(1).removeStyle( 'background-color');
}
else
{
this.element.getChild(0).setStyle( 'background-color', '#'+this.data.bgc );
this.element.getChild(1).setStyle( 'background-color', '#'+this.data.bgc );
}
},
editables: {
col1: {
selector: '.edit1',
allowedContent: allowedText
},
col2: {
selector: '.edit2',
allowedContent: allowedText
}
},
allowedContent: allowedText,
upcast: function( element ) {
return element.name == 'div' && element.hasClass( 'col_1_2' );
}
} );
I'm not able to select my text color of the previous widget.
Please help
Thanks
The issue comes from your allowedText content, which I seem pretty weird.
Here is its content, where I added spaces to make it more readable:
'font; div{background-color}; h2{color}; p{color, font} [font]; span; br; ul; ol; li; strong; em; h3; img{ height, width } [!src,width,height];'
First you directly quote font, which is no longer a valid element in HTML 5: so it has no effect here.
Then you allow font style and font attribute to p element: both have only a chance to be useful if some (already entered) content quotes them. The same remark applies to div{background-color}, h2{color} and p{color}.
All these specifications don't meet the way CKEditor creates font or color styles variations, which is like <span style="font-family:...">, <span style="font-style:...">, <span style="color:..."> or <span style="background-color:...">.
So for your text color feature to be active you must write span {color}, or span {background-color} for background color feature, and so on.
More simply I suggest you merely write span {*} to have all of these features active, unless you want to specifically limit what is allowed.
Also note that you may simplify your allowedContent string where a number of elements share the same properties (or not property at all), like in br ul ol li strong em h3;.