Attribute selectors in emotion - emotion

The following code customizes the google maps DrawingManager crosshair cursor. It works but I would like to be able to pass an svg cursor as a prop. I was trying to get it working using emotion but couldn't find anything similar in the emotion docs and my attempts failed. Can it be done in emotion?
Code: There are really only two relevant lines here (indicated) - the rest is given for context.
import React, { useEffect, useContext } from 'react'
import { GoogleMapContext, MapBox } from '#googlemap-react/core'
import ThemeSwitcher from './theme-switcher'
import styles from './styles/styles'
import './map.css' <--------------------------------------------------
export default function Map(props) {
const { state: { map } } = useContext(GoogleMapContext);
useEffect(() => map && map.setOptions({ draggableCursor: props.cursor }));
return <>
<MapBox
className='crosshair-cursor' <---------------------
apiKey={process.env.REACT_APP_GMAPS}
opts={{
center: { lat: -37.815018, lng: 144.946014 },
zoom: 11,
styles: styles[localStorage.getItem('mapTheme')],
}}
useDrawing
useGeometry
useGoogleApi
onClick={props.onClick}
onRightClick={props.onRightClick}
LoadingComponent={null}
/>
<ThemeSwitcher bindingPosition='TOP_LEFT' map={map} />
{props.children}
</>
}
map.css:
.crosshair-cursor [style*='crosshair'] {
cursor: url("https://i.stack.imgur.com/mA4e2.jpg?s=48&g=1")24 24, crosshair !important;
}
My attempt:
import React, { useEffect, useContext } from 'react'
import { GoogleMapContext, MapBox } from '#googlemap-react/core'
import ThemeSwitcher from './theme-switcher'
import styles from './styles/styles'
import './map.css'
import {css} from '#emotion/core'
const cursor = css`[style*='crosshair'] {
cursor: url("https://i.stack.imgur.com/mA4e2.jpg?s=48&g=1")24 24, crosshair !important;
}`
export default function Map(props) {
const { state: { map } } = useContext(GoogleMapContext);
useEffect(() => map && map.setOptions({ draggableCursor: props.cursor }));
return <>
<MapBox
// className='crosshair-cursor'
css={cursor}
apiKey={process.env.REACT_APP_GMAPS}
opts={{
center: { lat: -37.815018, lng: 144.946014 },
zoom: 11,
styles: styles[localStorage.getItem('mapTheme')],
}}
useDrawing
useGeometry
useGoogleApi
onClick={props.onClick}
onRightClick={props.onRightClick}
LoadingComponent={null}
/>
<ThemeSwitcher bindingPosition='TOP_LEFT' map={map} />
{props.children}
</>
}

Related

Nextjs with Styled components not passing theme

I'm trying to pass my theme object to styled-components on my Next.js project, but it keep's failing to receive it as a props.
That's my _document.tsx
import { getInitialProps } from "#expo/next-adapter/document";
import Document, { DocumentContext, DocumentInitialProps } from "next/document";
import { ServerStyleSheet } from "styled-components";
export default class MyDocument extends Document {
static async getInitialProps(ctx: DocumentContext): Promise<DocumentInitialProps> {
const sheet = new ServerStyleSheet();
const originalRenderPage = ctx.renderPage;
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) =>
sheet.collectStyles(<App {...props} />),
});
const initialProps = await getInitialProps(ctx);
return {
...initialProps,
styles: (
<>
{initialProps.styles}
{sheet.getStyleElement()}
</>
),
};
} finally {
sheet.seal();
}
}
}
After that I wrapped my _app.tsx with the ThemeProvider
import Layout from '../components/Layout'
import 'setimmediate';
import { ThemeProvider } from 'styled-components';
import { wrapperStore } from "../store";
import { ApolloProvider } from "#apollo/client";
import client from './api/apollo-client';
import React from 'react';
import lightTheme from '../helpers/light-mode';
import { AppProps } from 'next/app';
function MyApp({ Component, pageProps }: AppProps) {
return (
<React.Fragment>
<ApolloProvider client={client}>
<ThemeProvider theme={lightTheme}>
<Layout>
<Component {...pageProps} />
</Layout>
</ThemeProvider>
</ApolloProvider>
</React.Fragment>
)
}
export default wrapperStore.withRedux(MyApp);
From here I receive a warning when I try to wrap my component, exporting it withTheme
[withTheme] You are not using a ThemeProvider nor passing a theme prop or a theme in defaultProps in component class "Connect(Front)"
when I try to console log theme from my props, it returns undefined, and when I create a styled component, trying to use theme as props it causes an error
export const RecruitmentTextLocation = styled.Text`
fontSize: ${scaleFont(15)};
textAlign: left;
marginTop: ${scale(5)}px;
marginBottom: ${scale(1)}px;
fontFamily: roboto;
fontWeight: 500;
color: ${({theme}) => theme.colors.cardTitleColor};
`;
TypeError: Cannot read property 'colors' of undefined
I'm really stuck on how I can use theming with styled-components on Nextjs.
I suppose you problem is in light-mode.tsx. How can i see you use typescript in that case need create a declarations file and DefaultTheme interface. example
Create a declarations file
TypeScript definitions for styled-components can be extended by using declaration merging since version v4.1.4 of the definitions. documentation
light-mode.tsx
import { DefaultTheme } from 'styled-components';
export const lightTheme: DefaultTheme = {
colors: {
cardTitleColor: red;
}
};
I was looking for the same and found a solution for typing the theme object you receive as prop on your styled components.
First, export the types of your themes, e.g.:
export type LightTheme = typeof lightTheme;
Then add a src/declaration.d.ts file with the below, so to enhance the DefaultTheme exported by styled-components to be typed with your custom theme object:
import { Theme } from "globalStyles";
declare module "styled-components" {
export interface DefaultTheme extends Theme {}
}
From there you won't need any withTheme to use your theme object, as you will simply be able to access it through:
color: ${({theme}) => theme.colors.cardTitleColor};

React Native props from App.js through react-navigation to Screen not working

i tried first steps with Theming in react-native with react-native-paper but the first step is not working.
AppViewContainer
export default compose(
lifecycle({
componentDidMount() {
if (Platform.OS === 'android') {
// eslint-disable-next-line no-unused-expressions
UIManager.setLayoutAnimationEnabledExperimental &&
UIManager.setLayoutAnimationEnabledExperimental(true);
}
},
}),
)(AppView);
AppView.js
export default function App() {
return(
<PaperProvider theme={theme}>
<Navigator onNavigationStateChange={() => { }} uriPrefix="/app" />
</PaperProvider>
)
}
Navigator
export default createAppContainer( createSwitchNavigator({
AuthLoading: LoadingScreen,
App: AppStack,
Tabs: TabNavigator,
Auth: AuthStack,
},
{
initialRouteName: 'AuthLoading',
}
));
in next step my HomeScreen is coming but there
this.props.theme //undefined
It seems the props not going through react navigation. How i can tell the Navigator to loop it through?
Many Thx
My Solution was now:
App.tsx - including redux
import React from 'react';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { AppearanceProvider } from 'react-native-appearance';
import { Provider } from 'react-redux';
import { Main } from './src/main';
import store from "./src/store"; //redux store
export default function App() {
return (
<Provider store={store}>
<SafeAreaProvider>
<AppearanceProvider>
<Main />
</AppearanceProvider>
</SafeAreaProvider>
</Provider>
);
}
Main.tsx
import React from 'react';
import {
Provider as PaperProvider,
DefaultTheme,
DarkTheme,
} from 'react-native-paper';
import { I18nManager } from 'react-native';
import * as Updates from 'expo-updates';
import { useColorScheme } from 'react-native-appearance';
import { PreferencesContext } from './context/preferencesContext';
import { RootNavigator } from './rootNavigator';
...
return (
<PreferencesContext.Provider value={preferences}>
<PaperProvider
theme={
theme === 'light'
? {
...DefaultTheme,
colors: { ...DefaultTheme.colors,
primary: 'red',
background: '#f8f8f8',
listbg: '#ffffff',
bg: require('../assets/splash.png')
},
}
: {
...DarkTheme,
colors: { ...DarkTheme.colors,
primary: '#1ba1f2',
listbg: 'rgba(255, 255, 255, 0.1)',
bg: require('../assets/splash.png')
},
}
}
>
<RootNavigator />
</PaperProvider>
</PreferencesContext.Provider>
);
};
now u can use 'theme' in every function component with global defined values and switch between dark and light mode.
const theme = useTheme(); // imported from react-native-paper
The complete example found on github here: https://github.com/Trancever/twitterClone
if this info was useful, vote up. thx.

null is not an object (evaluating 'this.nativeCommandsModule.push')

I am using WIX-React-Native-Navigation and while pushing a component in the stack I am getting this error.
Error
One thing to say, I am using Viro-React ARScene Navigation (Scene Navigation) in WIX-React-Native-Navigation.
Here's my code
index.js
import { AppRegistry } from 'react-native';
var OpenDoor = require('./app/base')
import Stack from './app/navigation';
import { Navigation } from "react-native-navigation";
AppRegistry.registerComponent('ViroSample', () => OpenDoor);
Navigation.events().registerAppLaunchedListener(() => {
Navigation.setRoot({
root: {
stack: Stack
}
});
});
navigation.js
import { Navigation } from "react-native-navigation";
import Base from './base';
import Menu from './components/Menu/menu';
Navigation.registerComponent('Base', () => Base);
Navigation.registerComponent('Menu', () => Menu);
const Stack = {
children: [{
component: {
name: 'Base'
},
}
]
};
export default Stack;
base.js
import React, {Component} from 'react';
import {
Alert,
View
} from 'react-native';
import {ViroARSceneNavigator} from 'react-viro';
import { Navigation } from 'react-native-navigation';
import APIKeys from './index';
import Camera from './components/Camera/camera';
import MenuButton from './components/Menu/menu_button';
class Base extends Component {
constructor(props) {
super(props);
this.navigateScreen = this.navigateScreen.bind(this);
}
navigateScreen(location) {
Navigation.push(this.props.componentId, {
component: {
name: location
}
});
}
render() {
return(
<View style={styles.container}>
<ViroARSceneNavigator
initialScene = {{
scene: Camera
}}
apiKey = {APIKeys.ViroReact}
style = {styles.ar_scene}
/>
<MenuButton navigation={this.navigateScreen}/>
</View>
);
}
};
const styles = {
container: {
flex: 1
}
};
export default Base;
module.exports = Base;
Correct me, If I am wrong somewhere.
What I am doing is, creating an application where users can decorate home virtually with the help of Augmented Reality. The mobile app is created on React-Native while the library used for augmented reality is Viro-React.
So, When I want to navigate from One Screen to another, then while pushing component in the stack I am getting this error.
Thanks.

How can I pass the navigator prop from react-native-navigation v2 to my splash screen via Navigation.setRoot

I am trying to migrate from react-native-navigation v1 to react-native-navigation v2. I am struggling to move from
Navigation.startSingleScreenApp
to
Navigation.setRoot
When I switch from Navigation.startSingleScreenApp (v1) to Navigation.setRoot (v2), I no longer have the navigator prop that I was relying on to navigate around the application.
I have copy and pasted all relevant code below
RegisterScreens
import { Navigation } from 'react-native-navigation';
import SplashScreenScreen from './components/SplashScreen';
import { Provider } from 'react-redux';
import React from "react";
import SCREEN from './screenNames';
export default function registerScreens(store) {
Navigation.registerComponent(
SCREEN.SPLASH_SCREEN,
() => props => (<Provider store={store}><SplashScreenScreen {...props} /></Provider>), () => SplashScreenScreen);
App
import { Platform } from 'react-native';
import { Navigation } from 'react-native-navigation';
import registerScreens from './registerScreens';
import { Colors, Fonts } from './themes';
import { store } from './configureStore';
import NavigationListener from './NavigationEventListener';
import configureNotification from './configureNotification';
import SCREEN from './screenNames';
import Reactotron from 'reactotron-react-native';
const navBarTranslucent = Platform.OS === 'ios';
configureNotification();
registerScreens(store);
new NavigationListener(store);
const STARTING_SCREEN = SCREEN.SPLASH_SCREEN;
Navigation.events().registerAppLaunchedListener(() => {
Reactotron.log('5');
Navigation.setRoot({
root: {
stack: {
children: [{
component: {
id: STARTING_SCREEN,
name: STARTING_SCREEN
}
}],
}
},
layout: {
orientation: 'portrait',
},
});
});
SplashScreen
import React from 'react';
import { View, StyleSheet, Text } from 'react-native';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { PersistGate } from 'redux-persist/es/integration/react';
import { navigateToFirstScreen } from '../redux/splash';
import { Colors, Fonts, Metrics } from '../themes';
import { persistor } from '../configureStore';
export class SplashScreen extends React.Component {
navigateTo = (screen) =>
this.props.navigator.push({
screen,
overrideBackPress: true,
backButtonHidden: true,
animated: false,
navigatorStyle: {
disabledBackGesture: true,
},
});
render() {
const { dispatchNavigateToFirstScreen } = this.props;
return (
<PersistGate
persistor={persistor}
onBeforeLift={() => setTimeout(() => dispatchNavigateToFirstScreen(this.navigateTo), 2000)}><View style={styles.bodyContainer}
>
<Text>Jono</Text>
</View>
</PersistGate>
);
}
}
const styles = StyleSheet.create({
bodyContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: Colors.splashScreen,
},
appTitleText: {
fontSize: Fonts.size.splashScreenTitle,
fontFamily: Fonts.type.extraBold,
lineHeight: Metrics.lineHeight.appTitle,
textAlign: 'center',
color: Colors.textLightColor,
},
});
SplashScreen.propTypes = {
navigator: PropTypes.shape({
push: PropTypes.func.isRequired,
}).isRequired,
dispatchNavigateToFirstScreen: PropTypes.func.isRequired,
};
const mapDispatchToProps = (dispatch) => {
return {
dispatchNavigateToFirstScreen: (navigateTo) =>
dispatch(navigateToFirstScreen(navigateTo)),
};
};
export default connect(null, mapDispatchToProps)(SplashScreen);
I spent multiple hours trying to solve this problem so I am going to post my conclusion as an answer.
this.props.navigator is not used anymore in 2.x.
You need to use Navigation
This dude had the same problem and reached the same conclusion: https://github.com/wix/react-native-navigation/issues/3795

test with enzyme a react component with context: return an empty object

I'm trying to execute a dummy test with enzyme over a component. the test is about to check the context. even though I'm writing the same code as enzyme's documentation the context is always empty.
import React from 'react';
import { shallow } from 'enzyme';
import Overlay from '../../../../app/components/Overlay/Overlay';
describe('<Overlay />', () => {
it.only('return a context', () => {
const wrapper = shallow(<Overlay />, { context: { foo: 10 } });
console.log(wrapper.context());
// expect(wrapper.context().foo).to.equal(10);
});
})
the test's output is:
<Overlay />
{}
✓ return a context
where am I wrong?
Since the details of Overlay component is not given, I assume the context is not used in it (pls check childContextTypes and getChildContext are defined properly)
For example, refer the explanation for contexts in react documents
I have taken the same example to enable the test,
import React from 'react';
export default class Button extends React.Component {
render() {
return (
<button style={{ background: this.context.color }}>
{this.props.children}
</button>
);
}
}
Button.contextTypes = {
color: React.PropTypes.string,
};
class Message extends React.Component {
render() {
return (
<div>
{this.props.text} <Button>Delete</Button>
</div>
);
}
}
class MessageList extends React.Component {
getChildContext() {
return { color: 'purple' };
}
render() {
const children = this.props.messages.map((message) =>
<Message text={message.text} />
);
return <div>{children}</div>;
}
}
MessageList.childContextTypes = {
color: React.PropTypes.string,
};
I've created the test for Button component as below,
import React from 'react';
import { shallow } from 'enzyme';
import { expect } from 'chai';
import Button from '../../src/components/SampleComp';
describe.only('<Button />', () => {
it('assert for context', () => {
const wrapper = shallow(
<Button />,
{ context: { color: 'red' } }
);
expect(wrapper.context().color).to.equal('red');
expect(wrapper.context('color')).to.equal('red');
});
});
<Button />
✓ assert for context
1 passing (214ms)
This will assert it correctly.