simple solution for sizing sidebar of a react-admin app - react-admin

I simply want to define the width of the sidebar according to the documentation "Sidebar Customization" here: https://marmelab.com/react-admin/Theming.html
import { createMuiTheme } from '#material-ui/core/styles';
const theme = createMuiTheme({
sidebar: { // <- Error 'sidebar' does not exist in type 'ThemeOptions'
width: 300, // The default value is 240
closedWidth: 70, // The default value is 55
},
});
const App = () => (
<Admin theme={theme} dataProvider={simpleRestProvider('http://path.to.my.api')}>
// ...
</Admin>
);
I get a :
'sidebar' does not exist in type 'ThemeOptions'
which is correct, when looking into material-ui.core.styles.ThemeOptions
What is the simpliest way to simply size the sidebar ? I like to do because my MenuItemLink texts overlaps the size of the sidebar.

The createMuiTheme() call is not needed:
const darkTheme = {
sidebar: {
width: 220,
closedWidth: 55,
},
}

Only this code worked for me, because they don't export types on v3.9.4, but I am using TS.
import { ThemeOptions } from "#material-ui/core";
export interface CustomThemeOptions extends ThemeOptions {
sidebar?: {
width?: number;
closedWidth?: number;
};
}
const theme: CustomThemeOptions = {
...defaultTheme,
sidebar: {
width: 100,
closedWidth: 40,
},
};
issue https://github.com/marmelab/react-admin/issues/5426

With the current version 3.19.10 you also have to widen the menu if you don't want menu item labels to wrap at the original sidebar width of 240px. e.g.
import { defaultTheme } from "react-admin";
export const defaultAppTheme = {
...defaultTheme,
sidebar: {
width: 260,
closedWidth: 55,
},
menu: {
width: 260,
closedWidth: 55,
},
};
You can see where the menu widths are pulled from the theme and applied here in their source code

Related

Creating customize theme variant for Button in Native Base (changing disabled colors)

I'm recently using Native Base in my React Native app.
I'm creating my customize theme and creating some variant for my buttons.
I want to change background color if button is disabled.
These are default native base variants
[https://github.com/GeekyAnts/NativeBase/blob/v3-pre-beta/src/theme/components/button.ts] and I've seen how they're using props.isDisabled to change some props.
But for me console.log are sending me undefined
Here is my code
import { extendTheme } from 'native-base'
import { Dict } from 'native-base/lib/typescript/theme/tools'
const variantLogin = (props: Dict) => {
console.log('const is disabled', props.isDisabled)
return {
bg: props.isDisabled
? theme?.colors?.gray['200']
: theme?.colors?.orange?.main,
_text: {
color: props.isDisabled
? theme?.colors?.gray['500']
: theme?.colors?.white,
},
}
}
export const theme = extendTheme({
colors: {
white: '#ffffff',
black: '#000000',
gray: {
100: '#f5f5f5',
200: '#d8d8d8',
300: '#c4c4c4',
500: '#828282',
800: '#4b4a4a',
900: '#1a1a1a',
},
gold: {
main: '#e7c14d',
},
},
components: {
Button: {
variants: {
login: variantLogin
}
}
}
})
export default theme
Color changes right with
<Button isDisabled={disabled} variant={'login'}>{text}</NativeButton>
It shows and orange button with white letters, but not when is disabled, only more transparency appears.
I don't know if there's a way to pass isDisabled prop, but here's a way to solve it:
const variantLogin = (props: Dict) => {
return {
bg: theme?.colors?.orange?.main,
_disabled: {
bg: theme?.colors?.gray['200'],
},
_text: {
color: theme?.colors?.white,
_disabled: { color: theme?.colors?.gray['500']}
},
}
}

Render children of ViroARImageMarker onAnchorFound

I'm currently working with the ViroReact Community Package in React Native to display a video in AR when a specific image is found. However the onTargetFound function of the ViroARImageMarker is not triggered, and the children of the ViroARImageMarker are not displayed.
When I added the onAnchorFound function to the ARScene (parent) the onAnchorFound method was triggered, however the children of the ViroARImageMarker still weren't rendered. Why is the function not triggered and therefore the children not displayed? How do I fix this?
The image is a 12x12cm black card with a bright orange logo (about 3cm) in the center. Neither of the targets are found in the ViroARImageMarker.
Here's my code:
Image Recognition Class
import React, { useEffect, useState } from 'react';
const {
ViroARScene,
ViroARImageMarker,
ViroARTrackingTargets,
ViroAnimations,
ViroVideo,
ViroMaterials,
ViroBox
} = require('#viro-community/react-viro');
const NewViroTracker = () => {
const videoPath = require('#assets/videos/wham.mp4');
const [videoAnimationName] = useState('showVideo');
const [playAnim, setPlayAnim] = useState(false);
function _onAnchorFound(evt: any) {
console.log('Anchor found in Marker :', evt);
setPlayAnim(true);
}
return (
<ViroARScene>
<ViroARImageMarker
target={'inviteCard'}
onAnchorFound={_onAnchorFound}>
<ViroVideo source={videoPath} />
</ViroARImageMarker>
<ViroARImageMarker
target={'logo'}>
<ViroBox position={[0, 0.25, 0]} scale={[0.5, 0.5, 0.5]} />
</ViroARImageMarker>
</ViroARScene>
);
};
ViroARTrackingTargets.createTargets({
inviteCard: {
source: require('#assets/images/invite-card.png'),
orientation: 'Up',
physicalWidth: 0.12 // real world width in meters
},
logo: {
source: require('#assets/images/logo-empty.png'),
orientation: 'Up',
physicalWidth: 0.0287 // real world width in meters
}
});
ViroMaterials.createMaterials({
chromaKeyFilteredVideo: {
chromaKeyFilteringColor: '#00FF00'
}
});
ViroAnimations.registerAnimations({
showVideo: {
properties: { scaleX: 1, scaleY: 1, scaleZ: 1 },
duration: 1000
},
closeVideo: {
properties: { scaleX: 0, scaleY: 0, scaleZ: 0 },
duration: 1
}
});
export default NewViroTracker;
App
import React from 'react';
const { ViroARSceneNavigator } = require('#viro-community/react-viro');
import styled from 'styled-components/native';
import NewViroTracker from 'components/NewViroTracker';
const App = () => {
return (
<ViroWrapper
autofocus={true}
initialScene={{
scene: NewViroTracker
}}
/>
);
};
export default App;
const ViroWrapper = styled(ViroARSceneNavigator)`
flex: 1;
`;
Dependencies:
"#viro-community/react-viro": "^2.21.1",
"react": "17.0.2",
"react-native": "0.66.3",

Detox: detect that element was displayed

We have a toast component in our app that is adding considerable flakiness to our tests. The toast component displays an animated View for 4s and then disappears. In a lot of tests I need to check what the message content is in order to continue with the test.
The toast component is implemented with the following code:
// #flow
import * as React from "react"
import { StyleSheet, View, Animated, Dimensions, Text } from "react-native"
import type {
TextStyle,
ViewStyle,
} from "react-native/Libraries/StyleSheet/StyleSheet"
import type AnimatedValue from "react-native/Libraries/Animated/src/nodes/AnimatedValue"
import type { CompositeAnimation } from "react-native/Libraries/Animated/src/AnimatedImplementation"
import { AnimationConstants } from "constants/animations"
const styles = StyleSheet.create({
container: {
position: "absolute",
left: 0,
right: 0,
elevation: 999,
alignItems: "center",
zIndex: 10000,
},
content: {
backgroundColor: "black",
borderRadius: 5,
padding: 10,
},
text: {
color: "white",
},
})
type Props = {
style: ViewStyle,
position: "top" | "center" | "bottom",
textStyle: TextStyle,
positionValue: number,
fadeInDuration: number,
fadeOutDuration: number,
opacity: number,
}
type State = {
isShown: boolean,
text: string | React.Node,
opacityValue: AnimatedValue,
}
export const DURATION = AnimationConstants.durationShort
const { height } = Dimensions.get("window")
export default class Toast extends React.PureComponent<Props, State> {
static defaultProps = {
position: "bottom",
textStyle: styles.text,
positionValue: 120,
fadeInDuration: AnimationConstants.fadeInDuration,
fadeOutDuration: AnimationConstants.fadeOutDuration,
opacity: 1,
}
isShown: boolean
duration: number
callback: Function
animation: CompositeAnimation
timer: TimeoutID
constructor(props: Props) {
super(props)
this.state = {
isShown: false,
text: "",
opacityValue: new Animated.Value(this.props.opacity),
}
}
show(text: string | React.Node, duration: number, callback: Function) {
this.duration = typeof duration === "number" ? duration : DURATION
this.callback = callback
this.setState({
isShown: true,
text: text,
})
this.animation = Animated.timing(this.state.opacityValue, {
toValue: this.props.opacity,
duration: this.props.fadeInDuration,
useNativeDriver: true,
})
this.animation.start(() => {
this.isShown = true
this.close()
})
}
close(duration?: number) {
const delay = typeof duration === "undefined" ? this.duration : duration
if (!this.isShown && !this.state.isShown) return
this.timer && clearTimeout(this.timer)
this.timer = setTimeout(() => {
this.animation = Animated.timing(this.state.opacityValue, {
toValue: 0.0,
duration: this.props.fadeOutDuration,
useNativeDriver: true,
})
this.animation.start(() => {
this.setState({
isShown: false,
})
this.isShown = false
if (typeof this.callback === "function") {
this.callback()
}
})
}, delay)
}
componentWillUnmount() {
this.animation && this.animation.stop()
this.timer && clearTimeout(this.timer)
}
render() {
const { isShown, text, opacityValue } = this.state
const { position, positionValue } = this.props
const pos = {
top: positionValue,
center: height / 2,
bottom: height - positionValue,
}[position]
if (isShown) {
return (
<View style={[styles.container, { top: pos }]}>
<Animated.View
style={[
styles.content,
{ opacity: opacityValue },
this.props.style,
]}
>
{React.isValidElement(text) ? (
text
) : (
<Text style={this.props.textStyle}>{text}</Text>
)}
</Animated.View>
</View>
)
}
return null
}
}
Normally we display the toast message for 4s, but I decided to display it in e2e tests for 1.5s in order to make some what faster.
I'm testing for the presence of the toast like this:
await expect(element(by.text(text))).toBeVisible()
await waitFor(element(by.text(text))).toBeNotVisible().withTimeout(2000)
However it happens often that detox fails at "toBeVisible". I can see the message on the screen, but for some reason detox is missing it.
What is the minimum time I should keep the message on the screen for detox to detect it?
On .circleCI we record videos of failing tests. When a test fails with "cannot find element" and I watch the video I clearly see the toast appearing on the screen, but detox fails to find it.
I'm still not sure if there is a better way, but I found a way that currently works for us.
Instead of automatically hiding the toast in e2e test, we mock the modal component to display and stay visible until tapped on.
Once detox sees the element we tap on it, close it and continue with our test.
I also had exactly the same problem in my project and the the solution that we found was to disable detox synchronization around the toast.
As an example, this is how the code would look like:
await device.disableSynchronization();
await element(by.id(showToastButtonId)).tap();
await waitFor(element(by.text('Toast Message')))
.toExist()
.withTimeout(TIMEOUT_MS);
await device.enableSynchronization();
Reference: https://github.com/wix/Detox/blob/master/docs/Troubleshooting.Synchronization.md#switching-to-manual-synchronization-as-a-workaround

Combine react-native component with vue-native

Is there any way I could combine react native component like this one https://github.com/archriss/react-native-snap-carousel/tree/master/example with a vue native?
I have a project in vue-native and want to use react-native component inside it, but I have an erro I do not understand: The console says: Invariant Violation: expected a string (for built-in components) or a class/function (for composite components) but got: undefined
<template>
<nb-container>
<nb-content>
<carousel
:data="similarEventsData"
:renderItem="_renderItem"
:sliderWidth="sliderWidth"
:itemWidth="itemWidth"
:inactiveSlideScale="0.95"
:inactiveSlideOpacity="1"
:enableMomentum="true"
:activeSlideAlignment="'start'"
:containerCustomStyle="stylesObj.slider"
:contentContainerCustomStyle="stylesObj.sliderContentContainer"
:activeAnimationType="'spring'"
:activeAnimationOptions="{ friction: 4, tension: 40 }"
/>
</nb-content>
</nb-container>
</template>
<script>
import { Dimensions, Platform, Share } from "react-native";
import Carousel from 'react-native-snap-carousel';
import { scrollInterpolators, animatedStyles } from '../../utils/animations';
const { width: viewportWidth, height: viewportHeight } = Dimensions.get('window');
const slideHeight = viewportHeight * 0.36;
const slideWidth = wp(75);
const itemHorizontalMargin = wp(2);
export default {
components: { carousel: Carousel },
computed: {
similarEventsData () {
return [1, 2, 3]
}
},
data: function() {
return {
sliderWidth: viewportWidth,
itemWidth: slideWidth + itemHorizontalMargin * 2,
stylesObj: {
slider: {
marginTop: 15,
overflow: 'visible'
},
sliderContentContainer: {
paddingVertical: 10
},
}
};
},
methods: {
_renderItem ({item, index}) {
return <Text>fsd</Text>;
},
},
};
</script>
I expect to render a component but with no luck
this question is about 2 years old and I think in that time the devs added the functionality to do so, if somehow anyone is experiencing this question and ran into this post, here's what to do:
Example with Entypo icon pack from expo vector icons:
<script>
import { Entypo } from '#expo/vector-icons';
export default {
data(){
components: { Entype }
}
}
</script>
and then in template:
<template>
<entypo />
</template>

React Native - style responsiveness for different screen sizes

We are building an app which is going to run on multiple devices (iOS, Android) and therefore on many screen sizes. After reading about PixelRatio it still doesn't seem as if there is a magic solution to scale automatically all style values according to the different screen sizes.
The only solution I could think of was to override the Stylesheet class to automatically scale all sizes according to the current screen size. For example:
import {StyleSheet} from ‘react-native’;
import { Dimensions, Platform, PixelRatio } from ‘react-native’;
const {
width,
height
} = Dimensions.get(‘window’);
const scale = width / 320;
const ratioKeys = {
fontSize: true,
paddingHorizontal: true,
paddingVertical: true,
paddingTop: true,
paddingLeft: true,
paddingRight: true,
paddingBottom: true,
padding: true,
marginHorizontal: true,
marginVertical: true,
marginTop: true,
marginRight: true,
marginLeft: true,
marginBottom: true,
margin: true,
width: true,
height: true,
lineHeight: true,
}
// automatically scale specific keys (specified above) according to the screen size
const parseKey = (key, value) => {
if (ratioKeys[key]) {
value = value * scale;
}
return value;
}
export const parseStyle = (style) => {
console.log(‘style -> ’, style);
return Object.keys(style).reduce((output, key) => {
output[key] = parseKey(key, style[key]);
return output;
}, {});
}
const parseStyleSheet = (styles) => {
console.log(‘styles -> ’, styles);
return Object.keys(styles).reduce((output, key) => {
output[key] = parseStyle(styles[key]);
return output;
}, {});
}
export default {
create: (style) => {
return StyleSheet.create(parseStyleSheet(style));
}
}
It seems pretty strange that this wouldn't actually be supported out of the box, so I guess I am missing something?
I've seen this library as a solution, it supports media queries, and we may eventually use it if we feel we need more customization than flexbox. I've seen it in action and it looks like it might address some of your needs: https://github.com/vitalets/react-native-extended-stylesheet