I have a header with Logo, on left side, page title - in the middle, and user menu, on the right. Currently I'm displaying a SVG next to each page title. For example, on page /organizations I display this:
After that I've added a SVG that shows when I hover on the element (it's the same SVG, but filled)
How could I make transition between these two smooth? I'm using Tailwind for styling and tried adding transition-all to almost every class but that sadly didn't work.
This is the code responsible for switching between the SVGs:
const [hover, setHover] = React.useState(false);
const handleMouseOver = () => {
setHover(true);
};
const handleMouseLeave = () => {
setHover(false);
};
return (
...
<div className="w-1/2 flex justify-center">
<Link
to={getModuleInfo(pathname, t, organization).url}
className="max-w-fit flex items-center gap-2"
prefetch="intent"
>
<div
className="flex items-center gap-2"
onMouseOver={handleMouseOver}
onMouseLeave={handleMouseLeave}
>
<>
{hover
? getModuleInfo(pathname, t, organization).logoHover
: getModuleInfo(pathname, t, organization).logo}
</>
<h5 className="organizations text-md md:text-2xl font-sans font-normal text-center text-colublue-500">
{getModuleInfo(pathname, t, organization).title}
</h5>
</div>
</Link>
</div>
...
)
UPD: to make things more clear, these would be 2 SVG examples that I would like to transition between:
And this are the <svg> for them:
// Unfilled SVG
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.41421 2.58579C8.78929 2.21071 9.29799 2 9.82843 2H18C18.5304 2 19.0391 2.21071 19.4142 2.58579C19.7893 2.96086 20 3.46957 20 4V20C20 20.5304 19.7893 21.0391 19.4142 21.4142C19.0391 21.7893 18.5304 22 18 22H6C5.46957 22 4.96086 21.7893 4.58579 21.4142C4.21071 21.0391 4 20.5304 4 20V7.82843C4 7.29799 4.21071 6.78929 4.58579 6.41421L8.41421 2.58579Z" stroke="#052141" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10 2V7C10 7.55228 9.55228 8 9 8H4.5" stroke="#052141" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
// Filled SVG
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.82843 1C9.03278 1 8.26972 1.31607 7.70711 1.87868L3.87868 5.70711C3.31607 6.26972 3 7.03278 3 7.82843V20C3 20.7957 3.31607 21.5587 3.87868 22.1213C4.44129 22.6839 5.20435 23 6 23H18C18.7956 23 19.5587 22.6839 20.1213 22.1213C20.6839 21.5587 21 20.7957 21 20V4C21 3.20435 20.6839 2.44129 20.1213 1.87868C19.5587 1.31607 18.7956 1 18 1H9.82843ZM16.7071 9.29289C17.0976 9.68342 17.0976 10.3166 16.7071 10.7071L11.3738 16.0404C10.9832 16.431 10.3501 16.431 9.95956 16.0404L7.29289 13.3738C6.90237 12.9832 6.90237 12.3501 7.29289 11.9596C7.68342 11.569 8.31658 11.569 8.70711 11.9596L10.6667 13.9191L15.2929 9.29289C15.6834 8.90237 16.3166 8.90237 16.7071 9.29289Z" fill="#052141"/>
</svg>
With plain CSS and SVG, you can do this with opacity and transition.
.filled {
opacity: 0;
transition: opacity 0.3s;
}
svg:hover .filled {
opacity: 1;
}
<svg width="96" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.41421 2.58579C8.78929 2.21071 9.29799 2 9.82843 2H18C18.5304 2 19.0391 2.21071 19.4142 2.58579C19.7893 2.96086 20 3.46957 20 4V20C20 20.5304 19.7893 21.0391 19.4142 21.4142C19.0391 21.7893 18.5304 22 18 22H6C5.46957 22 4.96086 21.7893 4.58579 21.4142C4.21071 21.0391 4 20.5304 4 20V7.82843C4 7.29799 4.21071 6.78929 4.58579 6.41421L8.41421 2.58579Z" stroke="#052141" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10 2V7C10 7.55228 9.55228 8 9 8H4.5" stroke="#052141" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path class="filled" d="M9.82843 1C9.03278 1 8.26972 1.31607 7.70711 1.87868L3.87868 5.70711C3.31607 6.26972 3 7.03278 3 7.82843V20C3 20.7957 3.31607 21.5587 3.87868 22.1213C4.44129 22.6839 5.20435 23 6 23H18C18.7956 23 19.5587 22.6839 20.1213 22.1213C20.6839 21.5587 21 20.7957 21 20V4C21 3.20435 20.6839 2.44129 20.1213 1.87868C19.5587 1.31607 18.7956 1 18 1H9.82843ZM16.7071 9.29289C17.0976 9.68342 17.0976 10.3166 16.7071 10.7071L11.3738 16.0404C10.9832 16.431 10.3501 16.431 9.95956 16.0404L7.29289 13.3738C6.90237 12.9832 6.90237 12.3501 7.29289 11.9596C7.68342 11.569 8.31658 11.569 8.70711 11.9596L10.6667 13.9191L15.2929 9.29289C15.6834 8.90237 16.3166 8.90237 16.7071 9.29289Z" fill="#052141"/>
</svg>
You could also use css variables to transition between the design states.
Similar to #ksav's this approach will also need to combine both svgs.
This way we can render the icon with more design variations.
let icon = document.querySelector('.iconTrans');
function toggleState() {
icon.classList.toggle('active')
}
svg {
border: 1px solid #ccc;
overflow: visible;
width: 10em;
}
svg path {
transition: 1s;
}
.iconTrans {
--strokeColor: #052141;
--strokeWidth: 2px;
--opacity1: 1;
--opacity2: 0;
--fillColor: #052141;
}
.active {
--strokeColor: #052141;
--strokeWidth: 0px;
--opacity1: 0;
--opacity2: 1;
--fillColor: #ccc;
}
<p><button id="btnToggle" onclick="toggleState()">Toggle state</button></p>
<svg class="iconTrans" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path class="paper" d="M8.41421 2.58579C8.78929 2.21071 9.29799 2 9.82843 2H18C18.5304 2 19.0391 2.21071 19.4142 2.58579C19.7893 2.96086 20 3.46957 20 4V20C20 20.5304 19.7893 21.0391 19.4142 21.4142C19.0391 21.7893 18.5304 22 18 22H6C5.46957 22 4.96086 21.7893 4.58579 21.4142C4.21071 21.0391 4 20.5304 4 20V7.82843C4 7.29799 4.21071 6.78929 4.58579 6.41421L8.41421 2.58579Z
M10 2V7C10 7.55228 9.55228 8 9 8H4.5" style="stroke:var(--strokeColor); stroke-width:var(--strokeWidth); opacity:var(--opacity1)" stroke-linecap="round" stroke-linejoin="round" />
<path class="paperCheck" d="M9.82843 1C9.03278 1 8.26972 1.31607 7.70711 1.87868L3.87868 5.70711C3.31607 6.26972 3 7.03278 3 7.82843V20C3 20.7957 3.31607 21.5587 3.87868 22.1213C4.44129 22.6839 5.20435 23 6 23H18C18.7956 23 19.5587 22.6839 20.1213 22.1213C20.6839 21.5587 21 20.7957 21 20V4C21 3.20435 20.6839 2.44129 20.1213 1.87868C19.5587 1.31607 18.7956 1 18 1H9.82843Z
M16.7071 9.29289C17.0976 9.68342 17.0976 10.3166 16.7071 10.7071L11.3738 16.0404C10.9832 16.431 10.3501 16.431 9.95956 16.0404L7.29289 13.3738C6.90237 12.9832 6.90237 12.3501 7.29289 11.9596C7.68342 11.569 8.31658 11.569 8.70711 11.9596L10.6667 13.9191L15.2929 9.29289C15.6834 8.90237 16.3166 8.90237 16.7071 9.29289Z" style="fill:var(--fillColor); opacity:var(--opacity2); " />
</svg>
Related
I took the audio player code from this article, made a few style changes, and am now attempting to display multiple such players on one page. Currently, only the first player responds to clicks.
I used row and column elements to display full-page rows with 3 players per row, each player having its own icon image and audio source file. My trouble is now in establishing the index-searching procedure so that the JS can play audio_X when button_X is clicked.
I've tried other solutions on StackOverflow to no avail, so I've removed all the changes I tried and am starting again from square one.
const playerButton = document.querySelector('.player-button'),
audio = document.querySelector('audio'),
playIcon = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="#3D3132">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z" clip-rule="evenodd" />
</svg>
`,
pauseIcon = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="#3D3132">
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zM7 8a1 1 0 012 0v4a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v4a1 1 0 102 0V8a1 1 0 00-1-1z" clip-rule="evenodd" />
</svg>
`;
function toggleAudio() {
if (audio.paused) {
audio.play();
playerButton.innerHTML = pauseIcon;
// document.getElementById("1").style.opacity = "1";
} else {
audio.pause();
playerButton.innerHTML = playIcon;
// document.getElementById("1").style.opacity = "0";
}
}
playerButton.addEventListener('click', toggleAudio);
function audioEnded() {
playerButton.innerHTML = playIcon;
}
audio.onended = audioEnded;
const timeline = document.querySelector('.timeline');
function changeTimelinePosition() {
const percentagePosition = (100 * audio.currentTime) / audio.duration;
timeline.style.backgroundSize = `${percentagePosition}% 100%`;
timeline.value = percentagePosition;
}
audio.ontimeupdate = changeTimelinePosition;
function changeSeek() {
const time = (timeline.value * audio.duration) / 100;
audio.currentTime = time;
}
timeline.addEventListener('change', changeSeek);
const soundButton = document.querySelector('.sound-button'),
soundIcon = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="#3D3132">
<path fill-rule="evenodd" d="M9.383 3.076A1 1 0 0110 4v12a1 1 0 01-1.707.707L4.586 13H2a1 1 0 01-1-1V8a1 1 0 011-1h2.586l3.707-3.707a1 1 0 011.09-.217zM14.657 2.929a1 1 0 011.414 0A9.972 9.972 0 0119 10a9.972 9.972 0 01-2.929 7.071 1 1 0 01-1.414-1.414A7.971 7.971 0 0017 10c0-2.21-.894-4.208-2.343-5.657a1 1 0 010-1.414zm-2.829 2.828a1 1 0 011.415 0A5.983 5.983 0 0115 10a5.984 5.984 0 01-1.757 4.243 1 1 0 01-1.415-1.415A3.984 3.984 0 0013 10a3.983 3.983 0 00-1.172-2.828 1 1 0 010-1.415z" clip-rule="evenodd" />
</svg>`,
muteIcon = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="#3D3132">
<path fill-rule="evenodd" d="M9.383 3.076A1 1 0 0110 4v12a1 1 0 01-1.707.707L4.586 13H2a1 1 0 01-1-1V8a1 1 0 011-1h2.586l3.707-3.707a1 1 0 011.09-.217zM12.293 7.293a1 1 0 011.414 0L15 8.586l1.293-1.293a1 1 0 111.414 1.414L16.414 10l1.293 1.293a1 1 0 01-1.414 1.414L15 11.414l-1.293 1.293a1 1 0 01-1.414-1.414L13.586 10l-1.293-1.293a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>`;
function toggleSound() {
audio.muted = !audio.muted;
soundButton.innerHTML = audio.muted ? muteIcon : soundIcon;
}
soundButton.addEventListener('click', toggleSound);
<div class="audio-player left">
<div class="icon-container">
<img src="coverart1.jpg" style="width: 100%" alt="">
<!--<svg xmlns="http://www.w3.org/2000/svg" class="audio-icon" viewBox="0 0 20 20" fill="currentColor">
<path d="blahblahblahpath" />
</svg>-->
<audio src="audio/1.mp3"></audio>
</div>
<div class="controls">
<button class="player-button">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="#3D3132">
<path fill-rule="evenodd" d="blahblahblahpath" />
</svg>
</button>
<input type="range" class="timeline" max="100" value="0">
<button class="sound-button">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="#3D3132">
<path fill-rule="evenodd" d="blahblahblahpath" clip-rule="evenodd" />
</svg>
</button>
</div>
</div>
With this structure, I'm not quite sure how to index/search for specific players (beyond knowing that i should probably use queryselectALL and add for loops to some JS functions).
Any fixes? Currently the first player works perfectly, but no other player responds to clicks. Something with the event listener perhaps?
beyond knowing that i should probably use queryselectALL and add for loops to some JS functions
That's the point: you'll need to assign event listeners to each player instance.
let audioPlayers = document.querySelectorAll(".audio-player");
if (audioPlayers.length) {
audioPlayers.forEach(function(audioPlayer, i) {
let audio = audioPlayer.querySelector("audio");
let playerButton = audioPlayer.querySelector(".player-button");
playerButton.addEventListener("click", function(e) {
let current = e.currentTarget;
let audio = current.closest(".audio-player").querySelector("audio");
let btnSvg = current.querySelector(".useBtn");
if (!audio.paused) {
btnSvg.setAttribute("href", "#icon-play");
audio.pause();
} else {
btnSvg.setAttribute("href", "#icon-pause");
audio.play();
}
});
let timeline = audioPlayer.querySelector('.timeline');
timeline.addEventListener('change', function(e) {
let time = (timeline.value * audio.duration) / 100;
audio.currentTime = time;
});
audio.addEventListener('ended', function(e) {
console.log('audio finished');
timeline.value = 0;
});
audio.addEventListener('timeupdate', function(e) {
let percentagePosition = (100 * audio.currentTime) / audio.duration;
timeline.value = percentagePosition;
});
});
}
svg {
display: block;
width: 1em;
}
.player-button {
display: inline-block;
height: 1em;
background: none;
padding: 0;
border: none;
font-size: 1.2em;
position: relative;
bottom: -0.15em;
}
<div class="audio-player left">
<div class="icon-container">
<audio preload="metadata" src="https://cdn.plyr.io/static/demo/Kishi_Bashi_-_It_All_Began_With_a_Burst.mp3"></audio>
</div>
<div class="controls">
<button class="player-button">
<svg viewBox="0 0 20 20" fill="#3D3132">
<use class="useBtn" href="#icon-play" />
</svg>
</button>
<input type="range" class="timeline" min="0" max="100" step="1" value="0">
</div>
</div>
<div class="audio-player left">
<div class="icon-container">
<audio preload="metadata" src="https://cdn.plyr.io/static/demo/Kishi_Bashi_-_It_All_Began_With_a_Burst.mp3"></audio>
</div>
<div class="controls">
<button class="player-button">
<svg viewBox="0 0 20 20" fill="#3D3132">
<use class="useBtn" href="#icon-play" />
</svg>
</button>
<input type="range" class="timeline" min="0" max="100" step="1" value="0">
</div>
</div>
<svg class="plyrBtns" style="display:none" aria-hidden="true">
<symbol class="icon icon-play" id="icon-play" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z" clip-rule="evenodd" />
</symbol>
<symbol class="icon icon-pause" id="icon-pause" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zM7 8a1 1 0 012 0v4a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v4a1 1 0 102 0V8a1 1 0 00-1-1z" clip-rule="evenodd" />
</symbol>
</svg>
I have one common component for which I want to change its color property to use it at other place.
const ViewAllIcon = (props) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="18"
height="18"
viewBox="0 0 26 27"
{...props}
>
<path
fill="var(--primary)"
d="M13 0C5.832 0 0 5.86 0 13.061c0 7.202 5.832 13.062 13 13.062s13-5.86 13-13.062C26 5.86 20.168 0 13 0z"
/>
<path
fill="#FFF"
d="M14.764 13.061l-4.437-4.726c-.48-.512-.48-1.344 0-1.856s1.261-.512 1.742 0l5.357 5.708c.454.483.454 1.266 0 1.749l-5.357 5.707c-.48.512-1.261.512-1.742 0-.48-.512-.48-1.343 0-1.855l4.437-4.727z"
/>
</svg>
);
export default ViewAllIcon;
This is common component having primary blue and white color.
<ViewAllIcon className="ml8" fill="white" />
I am using it to change the fill color to white and green.
change fill value to "currentColor" and than pass color var to component.
ViewAllIcon({ color: 'var(--primary)' })
or
<ViewAllIcon color={'var(--primary)'} />
const ViewAllIcon = (props) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="18"
height="18"
viewBox="0 0 26 27"
{...props}
>
<path
fill="currentColor"
d="M13 0C5.832 0 0 5.86 0 13.061c0 7.202 5.832 13.062 13 13.062s13-5.86 13-13.062C26 5.86 20.168 0 13 0z"
/>
<path
fill="currentColor"
d="M14.764 13.061l-4.437-4.726c-.48-.512-.48-1.344 0-1.856s1.261-.512 1.742 0l5.357 5.708c.454.483.454 1.266 0 1.749l-5.357 5.707c-.48.512-1.261.512-1.742 0-.48-.512-.48-1.343 0-1.855l4.437-4.727z"
/>
</svg>
);
export default ViewAllIcon;
You could put the props directly to fill attribute
Something like this:
const ViewAllIcon = (props) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="18"
height="18"
viewBox="0 0 26 27"
{...props}
>
<path
fill={props.fill} // <--- UPDATE HERE!
d="M13 0C5.832 0 0 5.86 0 13.061c0 7.202 5.832 13.062 13 13.062s13-5.86 13-13.062C26 5.86 20.168 0 13 0z"
/>
<path
fill="#FFF"
d="M14.764 13.061l-4.437-4.726c-.48-.512-.48-1.344 0-1.856s1.261-.512 1.742 0l5.357 5.708c.454.483.454 1.266 0 1.749l-5.357 5.707c-.48.512-1.261.512-1.742 0-.48-.512-.48-1.343 0-1.855l4.437-4.727z"
/>
</svg>
);
export default ViewAllIcon;
Working Example:
This question already has answers here:
Want to add "addEventListener" on multiple elements with same class [duplicate]
(3 answers)
Closed 1 year ago.
I have an svg icon that on click, I want it to rotate 180 degrees. Currently, only the first icon toggles the class, but I'm trying to get all icons to toggle.
I'm not sure what I'm missing...
let accordionChevron = document.querySelector('.rotate');
accordionChevron.addEventListener('click', function() {
this.classList.toggle('down');
})
.rotate {
transition: all 0.2s ease-in-out;
}
.rotate.down {
transform: rotate(180deg);
}
<svg class="rotate" fill="none" height="11" viewBox="0 0 16 11" width="16" xmlns="http://www.w3.org/2000/svg">
<path d="m0 2.82837 2-2 6 6 6-6 2 2-8 8.00003z" fill="#000a70"></path>
</svg>
<hr>
<svg class="rotate" fill="none" height="11" viewBox="0 0 16 11" width="16" xmlns="http://www.w3.org/2000/svg">
<path d="m0 2.82837 2-2 6 6 6-6 2 2-8 8.00003z" fill="#000a70"></path>
</svg>
You may try the following:
let accordionChevronList = document.querySelectorAll('.rotate');
accordionChevronList.forEach(accordionChevron=>{
accordionChevron.addEventListener('click', function() {
this.classList.toggle('down');
});
});
I have this SVG:
<svg style="fill:#1780df; color: #1780df; " xmlns="http://www.w3.org/2000/svg" width=".8em"
height=".8em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
stroke-linecap="round" stroke-linejoin="round" class="feather feather-star"
data-v-41e50536="" data-v-50fd7d5a="">
<polygon
points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91
8.26 12 2"
data-v-41e50536="" data-v-50fd7d5a=""></polygon>
</svg>
This is a blue star. I want to do add an arbitrary number of these stars to an existing div using JavaScript.
How could I do it?
Update :
This is the existing div (it already has five stars and a short paragraph):
<div class="stars-real-container" id="dsc1">
<svg style="fill:#1780df; color: #1780df; margin-right: 6px; "
xmlns="http://www.w3.org/2000/svg" width=".8em" height=".8em" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" class="feather feather-star" data-v-41e50536=""
data-v-50fd7d5a="">
<polygon
points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"
data-v-41e50536="" data-v-50fd7d5a=""></polygon>
</svg>
<svg style="fill:#1780df; color: #1780df; " xmlns="http://www.w3.org/2000/svg" width=".8em"
height=".8em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
stroke-linecap="round" stroke-linejoin="round" class="feather feather-star"
data-v-41e50536="" data-v-50fd7d5a="">
<polygon
points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"
data-v-41e50536="" data-v-50fd7d5a=""></polygon>
</svg>
<svg style="fill:#1780df; color: #1780df; " xmlns="http://www.w3.org/2000/svg" width=".8em"
height=".8em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
stroke-linecap="round" stroke-linejoin="round" class="feather feather-star"
data-v-41e50536="" data-v-50fd7d5a="">
<polygon
points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"
data-v-41e50536="" data-v-50fd7d5a=""></polygon>
</svg>
<svg style="fill:#1780df; color: #1780df; " xmlns="http://www.w3.org/2000/svg" width=".8em"
height=".8em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
stroke-linecap="round" stroke-linejoin="round" class="feather feather-star"
data-v-41e50536="" data-v-50fd7d5a="">
<polygon
points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"
data-v-41e50536="" data-v-50fd7d5a=""></polygon>
</svg>
<svg style="fill:#1780df; color: #1780df; " xmlns="http://www.w3.org/2000/svg" width=".8em"
height=".8em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
stroke-linecap="round" stroke-linejoin="round" class="feather feather-star"
data-v-41e50536="" data-v-50fd7d5a="">
<polygon
points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"
data-v-41e50536="" data-v-50fd7d5a=""></polygon>
</svg>
<p class="number-of-comments" id="dc1">(۱۲ نظر )</p>
</div>
Its CSS:
.stars-real-container {
height: 100%;
width: 50%;
display: flex;
flex-direction: row-reverse;
justify-content: space-around;
}
The idea is to have stars to show the popularity of something. I have not ever created SVG elements with JavaScript. I checked several other stackoverflow threads like This. But it was a simple SVG.
There are many options to do that. The easiest way is this one in my opinion.
Updated code:
document.querySelector('.stars-real-container').innerHTML = '<svg style="fill:#1780df; color: #1780df; " xmlns="http://www.w3.org/2000/svg" width=".8em" height=".8em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" lass="feather feather-star" data-v-41e50536="" data-v-50fd7d5a=""><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" data-v-41e50536="" data-v-50fd7d5a=""></polygon></svg>' + document.querySelector('.stars-real-container').innerHTML;
To keep your paragraph as the last-child, you have to put the svg as first child and then add the existing content (+ document.querySelector('.stars-real-container').innerHTML)
This is a "deliberate" solution example where I clone the "star". Might be better ways but this is one way. Note I put the color of the star in CSS to illustrate how to do that also - could be done by using classes to provide a value fo the currentColor. I made mine more "pink" :)
Note I went with the "clone" approach so I could put the svg element in the HTML and not have to muck with string constants for the SVG, harder to maintain etc.
let howMany = 4;
let prettystar = document.getElementById("star-container").querySelector('svg');
let targetElement = document.querySelector("#star-target").querySelector('.star-me');
for (let step = 0; step < howMany; step++) {
let pclone = prettystar.cloneNode(true);
console.log(step)
targetElement.appendChild(pclone);
}
.star-me {
color: #df80df;
}
#star-container {
display: none;
}
<div id="star-container">
<svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" width=".8em" height=".8em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-star" data-v-41e50536=""
data-v-50fd7d5a="">
<polygon
points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91
8.26 12 2"
data-v-41e50536="" data-v-50fd7d5a=""></polygon></svg>
</div>
<div id="star-target"><span>Please make me a star!</span>
<span class="star-me"></span>
</div>
I have the following two blocks of code generated from React Material UI both contained within a larger React element written by myself.
<InputAdornment muiFormControl={{...}} position="end" classes={{...}} component="div" disablePointerEvents={false} disableTypography={false}>
<div className="MuiInputAdornment-root-35 MuiInputAdornment-positionEnd-38 Hook-searchFieldInputAdornmentStyle-1adbbdv">
<pure(SearchIcon)>
<SearchIcon>
<WithStyles(SvgIcon)>
<SvgIcon classes={{...}} color="inherit" component="svg" fontSize="default" viewBox="0 0 24 24">
<svg className="MuiSvgIcon-root-40" focusable="false" viewBox="0 0 24 24" color={[undefined]} aria-hidden="true" role="presentation">
<path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z" />
<path fill="none" d="M0 0h24v24H0z" />
</svg>
</SvgIcon>
</WithStyles(SvgIcon)>
</SearchIcon>
</pure(SearchIcon)>
</div>
</InputAdornment>
and
<InputAdornment muiFormControl={{...}} position="end" classes={{...}} component="div" disablePointerEvents={false} disableTypography={false}>
<div className="MuiInputAdornment-root-35 MuiInputAdornment-positionEnd-38">
<pure(ExpandLessIcon)>
<ExpandLessIcon>
<WithStyles(SvgIcon)>
<SvgIcon classes={{...}} color="inherit" component="svg" fontSize="default" viewBox="0 0 24 24">
<svg className="MuiSvgIcon-root-40" focusable="false" viewBox="0 0 24 24" color={[undefined]} aria-hidden="true" role="presentation">
<path d="M12 8l-6 6 1.41 1.41L12 10.83l4.59 4.58L18 14z" />
<path fill="none" d="M0 0h24v24H0z" />
</svg>
</SvgIcon>
</WithStyles(SvgIcon)>
</ExpandLessIcon>
</pure(ExpandLessIcon)>
</div>
</InputAdornment>
The only important difference is that one has a SearchIcon contained in it and the other has an ExpandLessIcon
I want to find the one with the SearchIcon using Enzyme. I have the following so far
wrapper.find(InputAdornment).containsNode(SearchIcon) but it gives me the following error
ReferenceError: SearchIcon is not defined
I should add that SearchIcon is not a component of mine and is dynamically generated by material-ui so I can't reference its type.
Any idea how I should adjust my enzyme query ?
.containsNode() needs a React Element like <div />, not React Component like div.
You can use a displayName in find, e.g. to get the SearchIcon element:
expect(wrapper.find(InputAdornment).find('SearchIcon')).toHaveLength(1)
or the InputAdornment containing SearchIcon:
expect(
wrapper.find(InputAdornment).filterWhere(x => x.find('SearchIcon').exists())
).toHaveLength(1)