media query inside styled components - result not showing in console - javascript

I am coding in Js and for the responsive design I created a responsible.js file:
import { css } from "styled-components";
export const mobile = (props) => {
return css`
#media only screen and (max-width: 380px) {
${props}
}
`;
};
For each component I wrote props in this way :
${mobile({height: "20vh"})}
But I can't see the result in the console and don't know why.
Did I miss something?
Thank you for any help!

Related

Using hooks inside createGlobalStyle

Hey I am trying to use hooks inside styled-components - createGlobalStyle.
I know that this is not possible, because createGlobalStyle is a function and neither a component nor a custom hook.
Maybe someone knows a workaround or a solution :).
export const GlobalStyle = createGlobalStyle`
p {
padding: ${p => useMediaQuery('min-width(768px)') && 12px};
}
`
One workaround can be to add a media query hook anywhere in your code, catch the screen size, send value in props (prop drilling, context Api, redux) to make your styled components adapt to your screen.
You may go through this link
You are not need to use hooks outside of functional components. Poof
Two ways, which i see, how you can do your task.
add media query directly in createGlobalStyle.
export const GlobalStyle = createGlobalStyle`
#media only screen and (min-width: 768px) {
p {
padding: 12px;
}
}
`
make separate function with some logic
const minWidthMedia = (minWidth: string) => {
const size = getScreenSize()
const isValid = minWidth > size.width
if (!isValid) return
return css`
p {
padding: 12px;
}
`
// or
// without validation logic
// return css`
// #media only screen and (min-width: ${minWidth}px) {
// p {
// padding: 12px;
// }
// }
}
export const GlobalStyle = createGlobalStyle`
${minWidthMedia('768px')}
`

Can't get MDX to work in a JavaScript Component. Just want Markdown to be turned to react components

Trying to make a react component with MDX that will turn markdown into react components. I want this so I can transform a blog article with embedded components (such as special article toolings and diagrams) from markdown stored in the DB into something presented on the page.
Been working on it for a few hours now and even my best attempts just result in literally nothing being displayed on the page. Where replacing the 'content' with a string displays.
I'm 100% baffled, lost and confused and really would appreciate help.
Original problem: https://www.reddit.com/r/reactjs/comments/mbdz7k/reactmarkdown_custom_component_declaration_how/
Working solution (but I am struggling to get it to work on my end). Provided by cmdq
https://codesandbox.io/s/dazzling-wescoff-ib8mv?file=/src/index.js
I've basically just moved the entire particular component file into being a JavaScript file but unfortunately I'm still running into many issues-- probably from lack of familiarality.
My current code is this in the file:
import ReactDOM from 'react-dom'
import renderToString from 'next-mdx-remote/render-to-string'
import hydrate from 'next-mdx-remote/hydrate'
import React, { Component } from 'react'
const exampleMdx = `
# h1
**foo**
<MyCustomComponent text="hell yeah" />
a
bar
`
const components = {
h1: (props) => <h1 style={{ color: 'tomato' }} {...props} />,
MyCustomComponent: ({ text }) => <marquee>{text}</marquee>,
}
const functionThing = async () => {
const mdxString = await renderToString(exampleMdx, {
components,
})
return hydrate(mdxString, { components });
}
export const ArticleTextTrial = () => {
let content = functionThing;
console.log(functionThing());
return (
<div className="articleMainTextSectionBody">{exampleMdx}
</div>
)
}

How to implement a class controller option in Flare React package

Update: I added a codesanbox at the bottom of this with a more detailed explanation of what I need done.
So I don't quite understand how classes work in React, I am new to react and have used useState a little bit, but never have know what to do with a class. I am using this react package that has an example of how to use a controller to make you animation interactive built with flare now called rive. https://github.com/2d-inc/Flare-React#readme
What I want to achieve is to either run a different animation, or the same animation again when I hover over canvas element that is generated. I can create a second animation in flate(rive) that would still output in the same .flr file and I should then be able to reference it in the controller and run it on hover, just stuck on how to even do that part, or even get this controller to work. One thing to note is I can get the animation to run fine without the controller.
In the docs they have this example code
class PenguinController extends FlareComponent.Controller
{
constructor()
{
super();
this._MusicWalk = null;
this._Walk = null;
this._WalkTime = 0;
}
initialize(artboard)
{
this._MusicWalk = artboard.getAnimation("music_walk");
this._Walk = artboard.getAnimation("walk");
}
advance(artboard, elapsed)
{
// advance the walk time
this._WalkTime += elapsed;
const { _MusicWalk: musicWalk, _Walk: walk, _WalkTime: walkTime } = this;
// mix the two animations together by applying one and then the other (note that order matters).
walk.apply(walkTime % walk.duration, artboard, 1.0);
// if you want to slowly disable the head bobbing (musicWalk animation) you could ramp down the
// final argument (the mix argument) to 0.0 over some time. For now we're mixing at full strength.
musicWalk.apply(walkTime % musicWalk.duration, artboard, 1.0);
// keep rendering
return true;
}
}
First of all what is a constructor? what does super mean? then what are they defining in the constructor, is that some state, how do I determine what to define here?
For the initialized I assume I match it to the state above, and get the animation by the name I named it in flare(rive)
The advance part I don't really understand are we setting the animation with this._WalkTime += elapsed; to how long the animation runs? I think I understand the apply section, it is applying a duration to the animation.
Next it has this code
class MyComponent extends React.Component
{
constructor()
{
this.state = { penguinController: new PenguinController() };
}
render()
{
return <FlareComponent controller={this.state.penguinController} /*... more properties here ...*/ />;
}
}
Here is my attempted code currently I get the following error
TypeError: Cannot set property 'state' of undefined
import React from "react"
import PropTypes from "prop-types"
import { useStaticQuery, graphql } from "gatsby"
import FlareComponent from 'flare-react';
import styled from 'styled-components'
import Header from "./header"
import "../sass/index.scss"
const LogoWrapper = styled.div`
width:200px;
height:200px;
`
class AnimationController extends FlareComponent.Controller
{
constructor()
{
super();
this._MusicWalk = null;
}
initialize(artboard)
{
this._MusicWalk = artboard.getAnimation("Wispy Appear");
}
advance(artboard, elapsed)
{
const { _MusicWalk: musicWalk } = this;
musicWalk.apply(musicWalk.duration, artboard, 1.0);
// keep rendering
return true;
}
}
const Layout = ({ children }) => {
const data = useStaticQuery(graphql`
query SiteTitleQuery {
site {
siteMetadata {
title
}
}
}
`)
this.state = { AnimationController: new AnimationController() };
return (
<>
<LogoWrapper>
<FlareComponent width={200} height={200} animationName="Wispy Appear" controller={this.state.AnimationController} file="/wispy-2.flr"/>
</LogoWrapper>
<main className="main-wrapper">{children}</main>
<footer>
© {new Date().getFullYear()}, Built with
{` `}
Gatsby
</footer>
</>
)
}
Layout.propTypes = {
children: PropTypes.node.isRequired,
}
export default Layout
For reference there is a a tutorial on how to make an animation interactive but it's for flutter, but it has some insights into there api https://medium.com/rive/building-a-responsive-house-with-flare-flutter-31af823ba805
Update
Here is my new attempted code after trying to read up on classes in es6, I still need to learn more.
So how do I go about running a second animation on click or hover or any event. The animation runs once now, but I don't know whow to use the controller?
import React from "react"
import Img from 'gatsby-image'
import styled from "styled-components"
import FlareComponent from 'flare-react';
import Layout from "../components/layout"
const LogoWrapper = styled.div`
width:200px;
height:200px;
`
class wispyController extends FlareComponent.Controller
{
constructor()
{
super();
this._Animate = null;
}
initialize(artboard)
{
this._Animate = artboard.getAnimation("Wispy Appear");
}
advance(artboard, elapsed)
{
const { _Animate: animate } = this;
animate.apply(5, artboard, 1.0);
// keep rendering
return true;
}
}
class IndexPage extends React.Component {
constructor()
{
super();
this.state = { wispyController: new wispyController() };
}
render(){
const {data} = this.props;
return(
<Layout>
<LogoWrapper>
<FlareComponent width={200} height={200} animationName="Wispy Appear" controller={this.state.wispyController} file="/Wispy.flr"/>
</LogoWrapper>
{data.allSanityBlogPost.edges.map(({ node: post }) => (
<article key={post.id}>
<h1>{post.name}</h1>
<img src={post.imageGif.asset.url}/>
</article>
))}
</Layout>
)
}
}
export default IndexPage
export const query = graphql`
query IndexQuery {
allSanityBlogPost {
edges {
node {
name
id
imageGif {
asset {
url
}
}
}
}
}
}
`
Ok Hopefully someone can help here, I made a codesandbox so someone can see what I am trying to achieve. There are two animations, on the page you can see the first one which has a controller which should be mixing the two, and then the other two animations on there own. What I want to happen is the first animation run and then the second one to run on hover. HEre is the code sandbox https://codesandbox.io/s/frosty-water-jnj9m
Classes in the context of React can be thought of as classes in most Object Oriented Programming language, they are a blueprint to create an object from. In order to let the language know how and what to do when we create it, it needs a constructor method. This constructor method is calling a special method called super() so that it calls the constructor of the class it is extending from, in this case FlareComponent.Controller
The method advance will be called to add to the captured walk time that the class is keepi track of.
One of the problems is that you are trying to set the state of the component directly instead of using setState https://reactjs.org/docs/react-component.html
I would highly recommend brushing up on React basics before you continue with this, it will really help you get the proper foundation you need.

Combine multiple styled elements with styled-components

I know that we can extend or add styling to existing components with styled-components like the Link component of react-router-dom. The said feature is indicated here. But, my problem is, how can I combine two or more existing components then add some more styles?
In my case, I have a reusable component for text elements like span, p and a with standard font-size, font-weight, etc. At the same time, I want to use the react-router-dom's Link component. Currently, I have something like this:
import styled from 'styled-components';
import { Link } from 'react-router-dom';
import { TextElement } from '../common';
/*
Can I do something like this?
const MyLink = styled(Link, TextElement)`
margin: 10px 0;
`;
or this?
const MyLink = styled([Link, TextElement])`
margin: 10px 0;
`;
*/
const MyPage = props => (
<>
<MyLink to="/next-page" />
</>
);
Any suggestion would be appreciated.
EDIT
My TextElement component is just something like this:
const Element = styled.span`
font-size: 13px;
font-weight: 500;
`;
// These styles are sample only. Actual styles depend on a "variant" prop.
// I did not show it here since it doesn't have to do with the question I'm asking.
export default ({ tag }) => (<Element as={tag} />);
You can use mixin for this using css helper.
Let's say you put the code for TextElement in a spaced mixin like:
import { css } from 'styled-components';
const spaced = css`
margin: 10px 0;
`;
And another mixin for Link
const styledLink = css`
color: blue;
`;
Then you can define your MyLink as:
import styled from 'styled-components'
const MyLink = styled(Link)`
${spaced}
${styledLink}
`;
The style component could be the wrapper of your custom component. For example:
Your style component:
export const CustomSpanWrapper = styled.div`
span {
...your-styles
}
`;
Your other component:
<CustomSpanWrapper>
<CustomSpan>
</CustomSpanWrapper>

How to add a warning/notification for a delete button in React?

ImagesUpload.jsx --> the Presentational component
deleteImageWarning.jsx --> the Notifications component
index.js --> where I exported the deleteImageWarning function
The goal
I want to include a notification or popup in my React app that alerts the user and gives them the choice to either cancel or confirm an action, in this case, deleting an image attached to a job sheet. This notification should be triggered when the user clicks the Delete button located next to the image that has been attached to the page.
Where to look for the issue
What I wrote (please have a look below) is not working whatsoever. I feel there is something wrong with the validateBeforeDelete function; I just wanted to have something that returns the notification function with the right values in the DOM. In addition, I am missing what to write in the Content section in the deleteImageWarning component.
Brief overview
To give you an idea, the button's delete functionality was working perfectly fine prior to working on the notification. There is a container for the ImagesUpload file, therefore, we could state that the ImagesUpload.jsx file is the Presentational Component and there is a ImagesUploadContainer.jsx file that acts as the Container Component for the Presentational Component.
The issue
The problem is that I don't know how to pass the delete function that I declared in the ImagesUpload.jsx file to the deleteImageWarning.jsx component. And that's surely what I am missing in the Content constant of my deleteImageWarning component. Does it have anything to do with the constants declared in my render() function?
ImagesUpload.jsx
//importing the deleteImageWarning function
import {
deleteImageWarning,
} from '../common/notifications';
//this is the function that deletes the image with the required values
async handleDeleteImage (jobsheetId, imageId) {
this.props.deleteImage({jobsheetId: jobsheetId, imageId: imageId});
}
//this is a validate function that is supposed to trigger the deleteImageWarning function
validateBeforeDelete = (jobsheetId, imageId) => {
return deleteImageWarning(this.notificationDOMRef.current, () => this.handleDeleteImage(jobsheetId, imageId));
}
render() {
const { ... } = this.props;
const { ... } = this.state;
return (
//TO BE AWARE! the following delete button with an onClick function has been written using React final form's syntax
...
<StyledSectionColRight>
<Button red type="button" onClick={() => this.validateBeforeDelete(id, image.id)}>Delete</Button>
</StyledSectionColRight>
...
);
}
export default ImagesUpload;
index.js
(Nothing really important, just in case someone thinks the error is due to not exporting deleteImageWarning)
//deleteImageWarning included in the index.js file
export { default as deleteImageWarning } from './deleteImageWarning';
deleteImageWarning.jsx
import React from 'react';
import styled from 'styled-components';
import { Button, ButtonInverted } from '../button';
const StyledNotification = styled.div`
background: var(--white);
padding: var(--spacer-m);
`;
const StyledMessage = styled.p`
font-size: var(--font-s);
line-height: var(--lineHeight-s);
margin: 0 0 var(--spacer-l) 0;
`;
const Content = ({ ????? }) => (
<StyledNotification>
<StyledMessage>
Are you sure you want to delete this image? This process cannot be undone.
</StyledMessage>
<Button type="button" red onClick={?????}>Confirm</Button>
<ButtonInverted type="button">Cancel</ButtonInverted>
</StyledNotification>
);
const deleteImageWarning = (node, ?????) => {
node.addNotification({
content: <Content ?????={?????} />,
type: "info",
title: "",
message: "",
insert: "top",
container: "top-center",
animationIn: ["animated", "fadeIn"],
animationOut: ["animated", "fadeOut"],
dismissable: { click: true },
width: 400
});
}
export default deleteImageWarning;
To make it super obvious, I have added a few question marks in the code to highlight where I don't know what to write.
I think your way of thinking is somewhat (not to be harsh) wrong, please correct me if I am missunderstanding. Where should the Content be rendered? I don't see a place where it would be.
What I would do is make a new Component (instead of a function) and render it only when a flag in the state (e.g. state = { ... , isdeleting = true }) turns true. You might also store the information of the image to be deletet in the state and pass it down to the Component:
//[prev. Code in ImagesUpload.jsx]
{ this.state.isdeleting ? <DeletImgWaring handleDeleteImage = {this.handleDeleteImage} imgInformation={//e.g. this.state.imgToBeDelInfo}
In this way you think more in component-based. And you can reuse the DeletImgWaring-Component somewhere else.
Does this help?
Regards

Categories