How to change the properties of a Blaze Template inside a React Component - meteor

I'm using the Accounts UI meteor package in my React + Meteor project and want to render the loginButtons template with the property align="right". In Blaze the code would just be {{> loginButtons align="right"}}, but I'm at at a loss with how to add this property in React.
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Template } from 'meteor/templating';
import { Blaze } from 'meteor/blaze';
export default class AccountsUIContainer extends Component {
componentDidMount() {
this.view = Blaze.render(Template.loginButtons, // How do I give loginButtons `align="right`?
ReactDOM.findDOMNode(this.refs.container));
}
componentWillUnmount() {
Blaze.remove(this.view);
}
render() {
return <span ref="container" />;
}
}
I think Blaze.renderWithData() may be part of the solution, but my tests with this method haven't worked so far. I also think people have created solutions to using Blaze templates in React before, but I'm not sure these alternate solutions would be the "right" way to solve this problem in Meteor 1.4.

The answer was right inside the documentation. First meteor add gadicc:blaze-react-component, then in the component
import React from 'react';
import Blaze from 'meteor/gadicc:blaze-react-component';
const App = () => (
<div>
<Blaze template="loginButtons" align="right" />
</div>
);

Related

How to add a global decorator in Storybook

In ReactJs project you can use .storybook/preview.js file to add global decorators and parameters. How to achieve this same behaviour with #storybook/react-native?
What I need is to wrap all my stories with ThemeProvider but the unique way that I found is to wrap individual stories with .addDecorator().
Edit storybook/index.js, by using addDecorator on it.
Example:
import React from 'react'
import { getStorybookUI, configure, addDecorator } from '#storybook/react-native'
import Decorator from './Decorator'
addDecorator(storyFn => (
<Decorator>
{storyFn()}
</Decorator>
))
// import stories
configure(() => {
require('../stories')
}, module)
const StorybookUI = getStorybookUI({ onDeviceUI: true })
export default StorybookUI;;
Found an updated answer in Storybook's own documentation.
// .storybook/preview.js
import React from 'react';
export const decorators = [
(Story) => (
<div style={{ margin: '3em' }}>
<Story />
</div>
),
];
As of June 2021, using storybook v5.3.25, the above answer does not work. However I have managed to figure out a solution.
Decorators must be added to the storybook/index.js file in the following format:
import { ThemeDecorator } from './storybook/ThemeDecorator';
addDecorator(withKnobs); // inbuilt storybook addon decorator
addDecorator(ThemeDecorator);// custom decorator
configure(() => {
loadStories();
}, module);
in this instance, ThemeDecorator.js is a simple wrapper component that renders your story, it would look something like this:
import React from 'react';
import { Provider } from 'theme-provider';
export const ThemeDecorator = (getStory) => (
<Provider>{getStory()}</Provider>
);
Importantly, the addDecorator function expects a React component (not a wrapper function as other examples claim), that it will render, with its props being a reference to an individual story at runtime.

Theme with React and Redux

i am trying to make a theme system on a react project that uses redux with a reducer that manages themes according to the user's local storage. But here my problem is that I used css files to define my styles on all of my components. However, I have all my logic with 2 javascript objects for light or dark mode. So I can't use js in css files unless I use css variables but I don't know how.
Here is my structure :
In my app.js I imported useSelector and useDispatch from react redux to access the global state :
import React from 'react';
import './App.css';
import Footer from './components/Footer';
import Header from './components/Header';
import Presentation from './components/Presentation';
import Projects from './components/Projects';
import Skills from './components/Skills';
import Timeline from './components/Timeline';
import { switchTheme } from './redux/themeActions';
import { useSelector, useDispatch } from 'react-redux';
import { lightTheme, darkTheme } from './redux/Themes';
function App() {
const theme = useSelector(state => state.themeReducer.theme);
const dispatch = useDispatch();
return (
<div className="App">
<Header />
<input type='checkbox' checked={theme.mode === 'light' ? true : false}
onChange={
() => {
if(theme.mode === 'light') {
dispatch(switchTheme(darkTheme))
} else {
dispatch(switchTheme(lightTheme))
}
}} />
<div className="top">
<div className="leftPart">
<Presentation />
<Skills />
</div>
<Timeline />
</div>
<Projects />
<Footer />
</div>
);
}
export default App;
and in themes.js I have my 2 objects which represent the themes :
export const darkTheme = {
mode: 'dark',
PRIMARY_BACKGROUND_COLOR: '#171933',
SECONDARY_BACKGROUND_COLOR: '#1e2144',
TERTIARY_BACKGROUND_COLOR: '#0a0c29',
PRIMARY_TEXT_COLOR: '#eee',
SECONDARY_TEXT_COLOR: '#ccc',
PRIMARY_BORDER_COLOR: '#aaa'
}
export const lightTheme = {
mode: 'light',
PRIMARY_BACKGROUND_COLOR: '#D3CEC8',
SECONDARY_BACKGROUND_COLOR: '#E5DFD9',
TERTIARY_BACKGROUND_COLOR: '#C1BFBC',
PRIMARY_TEXT_COLOR: '#222',
SECONDARY_TEXT_COLOR: '#333',
PRIMARY_BORDER_COLOR: '#555'
}
You can make use of data attributes.
I have done the same in one my project like so :-
[data-color-mode="light"] {
--color-focus-ring: #7daee2;
--color-link-hover: #0039bd;
--color-primary-bg: #eef6ff;
--color-primary-text: #212121;
--color-primary-border: #98b2c9;
--color-secondary-bg: #c3d7f0;
--color-secondary-text: #1a1a1a;
}
[data-color-mode="dark"] {
--color-focus-ring: #5355d4;
--color-link-hover: #4183c4;
--color-primary-bg: #080808;
--color-primary-text: #f1f1f1;
--color-primary-border: #525252;
--color-secondary-bg: #191919;
--color-secondary-text: #d8d5d5;
}
You can add the attribute to your top-level element (assuming div) like so:-
<div className="appContainer" data-color-mode="light" ref={appRef}> ></div>
Now use that appRef to change the data-color-mode attribute as well update the localstorage in one function. Updating the data-color-mode allows you to toggle between css variable colors easily. In my code, I have done this the following way:-
const toggleColorMode = () => {
const nextMode = mode === "light" ? "dark" : "light";
// container is appRef.current only
container?.setAttribute("data-color-mode", nextMode);
setMode(nextMode);
};
I am not using redux for this. Simply React Context API is being used by me but it's doable in your scenario as well.
You can take more reference from the repo - https://github.com/lapstjup/animeccha/tree/main/src
Note - I think there are other routes where people go with CSS-IN-JS but I haven't explored them yet. This solution is one of the pure css ways.
Fun fact - Github has implemented their newest dark mode in a similar way and that's where I got the idea as well. You can inspect their page to see the same attribute name :D.

React style/css/sass order

I have my "App-component" and a "B-component" that gets rendered inside my app component. Each has its own style.
But when it gets compiled, my ComponentB.css is put before my app.css, making the ComponentB styles being overwritten by my app styles.
Why is this happening??
APP
import React, { Component } from 'react';
import ComponentB from './components/ComponentB';
import './styles/app.css';
class App extends Component {
render() {
return (
<div className="App">
<ComponentB />
</div>
);
}
}
export default App;
COMPONENT B
import React, { Component } from 'react';
import './styles/ComponentB.css';
class ComponentB extends Component {
render() {
return (
<div>
<h1>Hello from ComponentB</h1>
</div>
);
}
}
export default ComponentB;
The way you do it results in a styles conflicts(one style overwriting another style), because after React compiles your code you are still using the same selectors for the same classes.
If you want to use different css files for different components while using the same class names, you should use CSS modules.
This will make your CSS class names scoped locally by default.

JssProvider in Material-UI isn't applying my custom production prefix to CSS

I've built a fairly simple React app based on create-react-app which uses the Material-UI for its interface components. It also depends on one of my own packages which also uses Material-UI (same version) for a couple of shared components.
Things were looking good locally until I ran a production build and deployed it. Some of the styles were behaving oddly, for example the Material-UI grid was much narrower than when running locally.
I did some reading and found a few instances of people discussing colliding class names under my scenario. This took me to some official Material-UI documentation which provides the following example code to use a custom class name prefix:
import JssProvider from 'react-jss/lib/JssProvider';
import { createGenerateClassName } from '#material-ui/core/styles';
const generateClassName = createGenerateClassName({
dangerouslyUseGlobalCSS: true,
productionPrefix: 'c',
});
function App() {
return (
<JssProvider generateClassName={generateClassName}>
...
</JssProvider>
);
}
export default App;
Before applying this fix when inspecting my production app's source code I could see the outermost DIV using the CSS class jss2 jss24.
After applying this fix my production app actually visually renders the same layout as my development version and so would appear to be fixed. However, examining the source shows the outermost DIV to have the class MuiGrid-container-2 MuiGrid-spacing-xs-8-24 which suggests to me something isn't right. I could leave it like this but it does mean I'm running with unoptimised code.
Am I doing something wrong here? Or is there an alternative resolution? I'm using current latest version of #material-ui/core (3.3.2) and the full contents of my App.js are:
import React, { Component } from 'react';
import { Provider } from "react-redux";
import { OidcProvider } from 'redux-oidc';
import JssProvider from 'react-jss/lib/JssProvider';
import Routes from './routes';
import store from './store';
import userManager from './utils/userManager';
import {
CustomUiTheme as Theme,
CustomUiLayout as Layout,
CustomUiSnackbar as Snackbar,
CustomUiModalAlert as Alert
} from 'custom-ui';
import Loading from './components/loading';
import { createGenerateClassName } from '#material-ui/core/styles';
const generateClassName = createGenerateClassName({
dangerouslyUseGlobalCSS: true,
productionPrefix: 'tw',
});
class App extends Component {
render() {
return (
<JssProvider generateClassName={generateClassName}>
<Provider store={store}>
<OidcProvider store={store} userManager={userManager}>
<Theme>
<Loading />
<Layout variant="xmas">
<Alert />
<Routes />
<Snackbar />
</Layout>
</Theme>
</OidcProvider>
</Provider>
</JssProvider>
);
}
}
export default App;

Material UI Theme Provider not being included properly in react/blaze app

Greetings fellow meteorites!
I am in the process of including material ui (react based) into an existing blaze app. I'm using the meteor guide and the material-ui docs as my instructions to do this properly but unfortunately to no avail. Has anyone successfully done this before? According to the material-ui docs you are supposed to inject an MuiThemeProvider into your main App Component but I keep getting the following error:
MuiThemeProvider.render(): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.
Here is my root blaze html template:
<template name="main">
<head>...</head>
<body>
<div id="wrap">
<div id="react-app-wrapper">
{{> React component=App}}
</div>
</div>
</body>
</template>
Notice I am using https://guide.meteor.com/react.html#react-in-blaze as my guidelines and am using the meteor package react-template-helper.
Here is my main.js file:
if(Meteor.isClient){
import App from './users/client/ui/components/App.js';
Template.main.onCreated(function(){
});
Template.main.helpers({
'App' : function(){
return App;
}
}
And my App.js Component File:
import React, { Component, PropTypes } from 'react';
import lightBaseTheme from 'material-ui/styles/baseThemes/lightBaseTheme';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
const lightMuiTheme = getMuiTheme(lightBaseTheme);
export default class App extends Component{
constructor(props){
super(props);
}
render() {
return (
<div>
<MuiThemeProvider muiTheme={lightMuiTheme} >
</MuiThemeProvider >
</div>
);
}
}
Appreciate your help big time! I have tried everything and feeling pretty stumped right now. :( If you give the correct answer I will obviously mark it as so!
Alex
This is how MuiThemeProvider renders
render() {
return this.props.children;
}
And therefore it, React actually, complained of nothing to render since this is you use it.
render() {
return (
<div>
<MuiThemeProvider muiTheme={lightMuiTheme} >
{/* There should be something here. */}
</MuiThemeProvider >
</div>
);
}
Start to put some contents that it can serve for you.
A side notice here is that the outer <div> wrapper can be dropped on the premise that it is not of some particular use.
Good luck!

Resources