Change FlatButton icon size - reactjs

I'm building a react material-ui virtual (on-screen) keyboard. And I'm having hard time implementing key size future. I'm using FlatButtton I figured a way to change label's size when i use label to display symbol key but I haven't found a way to change icon's size when using icon and SvgIcon. I have tried with label and labelStyle but dose not look stylish as with text label.
Here is how I change label's size:
let theme: MuiTheme = getMuiTheme();
theme.button.height += 10;
theme.button.minWidth += 10;
theme.flatButton.fontSize += 10;
return (
<MuiThemeProvider muiTheme={theme}>
<div>
<link href="https://fonts.googleapis.com/css?family=Roboto:400,300,500" rel="stylesheet" type="text/css"/>
<Keyboard
textField={textField}
open={this.state.open}
onRequestClose={this._onRequestClose}
onInput={this._onInput}
layout={[AlphaNumericKeyboard]}
/>
</div>
</MuiThemeProvider>
);
The code is just for developing, my idea when I'm done is to remove link and div and replace getMuiTheme() with this.context.muiTheme and += 10 with a = this.props.keySize.
This is the code which I use to change icon's size:
React.cloneElement(icon, {style: {width: 34, height: 34}});
This works when I render just the icon but when I render using <FlatButton icon={React.cloneElement(icon, {style: {width: 34, height: 34}})} />;
It's always with size 24x24. I've tried with theme.button.iconButtonSize += 10; but still no results.
I've started browsing material-ui's source code but still haven't found a way to change it's size.
This is the last think I've tried since I found that FlatButton dose change margin and padding and thought space is not enough but there is still total of 42x42 space empty and this dose not help ...
const noStyl: React.CSSProperties = {
marginLeft: 0,
marginRight: 0,
paddingLeft: 0,
paddingRight: 0
};
keyboardKey = <FlatButton icon={React.cloneElement(icon, {style: {width: 34, height: 34}})} labelStyle={noStyl} />;
So is there a way to change icon's size when using a FlatButton ?

As of v0.15.2 icon style prop is been overwritten (there is no way to style icon from FlatButton/RiasedButton.

Related

React Native Vector Icons to fit the parent container without specifying a size prop (Expo)

I am using the Vector Icons provided by Expo https://github.com/expo/vector-icons
All the icons accept a size prop which is an integer, my use case is to see if there to adjust the icon size automatically based on the parent container without having to worry about the size on each and every device (because size seems to translate the same on every device despite the pixel ratio, dimensions etc)
<View style={{flex: 1}}>
<Icon name="app-logo" size={30} color="white" />
</View>
I tried setting style prop to the below options but no luck. I would expect that this will not work because after all they are just fonts and they need not support the width and height
<Icon name="app-logo" style={{flex: 1}} color="white" />
<Icon name="app-logo" style={{width: '100%', height: '100%' color="white" />
Is there any cleaner or suggested way to do this? Using dimensions and ratios of the devices is my last resort.
Here's an example of the closest I've been able to get:
import React from "react"
import { PixelRatio, StyleSheet, Text, View } from "react-native"
import { FontAwesome5 } from "#expo/vector-icons"
const getRandomNumber = (min: number, max: number) =>
Math.random() * (max - min) + min
const App = () => {
const [containerSize, setContainerSize] = React.useState<number>()
const randomDimension = React.useMemo(() => getRandomNumber(100, 400), [])
return (
<View
style={{
flex: 1,
backgroundColor: "green",
justifyContent: "center",
alignItems: "center",
}}
>
<View
style={{
width: randomDimension,
aspectRatio: 1,
backgroundColor: "red",
}}
onLayout={layoutEvent =>
setContainerSize(layoutEvent.nativeEvent.layout.width)
}
>
<FontAwesome5
name="app-store-ios"
size={containerSize || 0}
style={{
textAlign: "center",
}}
color="blue"
/>
</View>
</View>
)
}
export default App
There's some code in here for intentionally setting the icon's parent container to a randomly sized square, and setting that on the parent, which is not what you're looking for but helped me re-create the problem.
The interesting bit which I think you want is the value passed to the onLayout prop of the icon's parent container, which gets the parent container's size and puts it in state. That state will be empty until the first render & layout, so we have the size of the vector icon defaulted to 0 until that happens. Once we have the size of the parent in state, we can set the size of the vector icon.
The vector icon doesn't actually fill the entire parent's space, but it scales pretty close pretty well. I think that's because the vector icon itself is a font under the hood (?) and we're trying to set the size of a font (in pts really (I think?)) to the size we got from the parent in pixels. There's probably a neat way to clean that up using react native's PixelRatio - I spent a bit of time trying but couldn't get it working perfectly.
The last thing I needed to do (since the vector icon doesn't actually "fill" the parent view was set the style prop of the icon to { textAlign: 'center' } which keeps it centered horizontally within the parent view (it was already centered vertically) instead of being off on the left side of the parent.
You could jank the whole thing into submission by adding a constant to the size and putting a negative top margin on the icon, but that's kind of a PITA and obviously not a great solution (it'll be a headache every time you do it and it probably won't work cross platform / on different pixel densities).
The reason I actually arrived at this post was because I was trying to keep an icon the same size as text; I was working on an app which showed a comment count (integer) to the left of a little chat bubble icon and I wanted the icon's size to scale with the system's font size if the user had adjusted that in their system settings. This is actually easier (which makes sense given my theory about vector icons being represented as fonts under the hood is correct). Here's the relevant part of my code that achieved that:
const StoryCommentsLabel = ({ story }: { story: HackerNewsItem }) => {
const navigation = useNavigation()
const numberOfComments = story.descendants || 0
const doNotActTouchable = { activeOpacity: 1 }
const fontScale = React.useMemo(() => PixelRatio.getFontScale(), [])
const defaultFontSize = 14
const iconSize = defaultFontSize * fontScale
return (
<TouchableOpacity
style={{ flexDirection: "row", justifyContent: "flex-end" }}
onPress={() => {
if (numberOfComments > 0) {
navigation.navigate("Story Comments", { story })
}
}}
hitSlop={{ top: 20, left: 20, bottom: 20, right: 20 }}
{...(numberOfComments === 0 ? doNotActTouchable : {})}
>
<Text
style={{
fontSize: 14,
color: PlatformColor("secondaryLabel"),
}}
>
{numberOfComments}
</Text>
<View style={{ width: 5 }} />
<Ionicons
name="chatbubble"
size={iconSize}
color={PlatformColor("secondaryLabel")}
/>
</TouchableOpacity>
)
}
There's more in there than you need, but the important bit is this:
const fontScale = React.useMemo(() => PixelRatio.getFontScale(), [])
const defaultFontSize = 14
const iconSize = defaultFontSize * fontScale

If i don't hardcode <div> height component inside is hidden

I like to make a div expand according to its content height but the hole Component inside that div is hidden if I use like height: '100%'. It's a bit complex and wish for some extra eyes!
I made a CodeSandbox
Looks like this in Chrome:
I can see during debug that the "hidden" Component is rendering ok so it's strange that it's "hidden"
If I set the same Style to height: 1000 the <ul> have Children:
But I want it to expand according to its content height so height: 1000 will not work.
In this CodeSandbox I set the height: 1000, to demonstrate what happens. The Component that refuse to expand height is a Masonry image gallery Component
style={{
width,
height: 1000,
position: 'relative',
margin: '0 auto',
}}
When you open the Sandbox you see in the left editor windows this TimeLineViewer.js and the Style code problem. The TimeLineViewer.js loads the Masonry image gallery Component Masonry.js
What I have tried is to set parent to also 100% height but with no luck.. I'm a little bit new to JavaScript and HTML so advice would be good
To debug this, start by taking off or commenting out the LeComponent and then testing your div actual height when you are implementing the 100% height.
<div
style={{
width,
height: !fullscreen && "100%",
position: fullscreen ? 'initial' : 'relative',
margin: '0 auto',
}}
>
{/* <LeComponent
infinite
items={items}
itemRenderer={ItemRenderer}
gutter={gutter}
outerGutter={outerGutter}
extraPx={0}
debug={debug}
rows={{
0: 1,
320: 2,
480: 3,
640: 4,
}}
cols={{
0: 1,
360: 2,
640: 2,
960: 3,
1280: 4,
1400: 5,
1720: 6,
2040: 7,
2360: 8,
}}
onEnd={() => {
// TODO possible when many items lazy load them
// this.addItems();
}}
/> */}
</div>
You will notice, that it still takes up no height at all and the component you created did not have any bearing to that. This is because it is a CSS issue. The height percentage cannot be determined because there is no parent or ancestor with a height definition. You are getting the percentage of void.
After that, we can take a glance at your Masonry component. Just by looking at the method identifiers (such as _getDimensions, _setContainerHeight) and further reviewing the code base, we can learn that this component is actually dependent on certain element dimensions (most likely the parent div dimension as well) - and from what we learned from the CSS issue awhile ago, the parent div actually has a height of 0.
At this point, I took out the style props on your Masonry Component so that it would not be dependent on the parent dimensions and that fixed the issue
<div ref={this.container}>
<ul ref={this.list}>
{mounted && items.map((item, index) => this.renderItem({ index, item, maxIndex }))}
</ul>
</div>

Adding touchableOpacity to an Image component

Simple question: How do I add a TouchableOpacity component to an image? This is the way I'm doing it:
<View style = { styles.categoryContainer }>
<TouchableOpacity
onPress = {() => navigation.navigate('xScreen')}
>
<Image
style = {styles.categoriesImages}
source = {require('./img/xImage.png')}
/>
</TouchableOpacity>
These are the styles that are mapped to the components:
categoryContainer: {
flex: 1,
flexDirection: 'column',
margin: 10,
},
categoriesImages: {
display: 'flex',
height: 70,
width: 70
},
When I run the app on expo, the image simply disappears. Removing the TouchableOpacity component brings the image back.
Maybe someone can provide an explanation as to why this doesn't work? Thanks a lot!
I'm just assuming this is the problem, but without the styles it's a bit hard to really know.
Basically your Image must have a width and height in percentage, and you wrapped the image with TouchableOpacity, which doesn't have "size". So you have two ways to solve your issue:
You map a style to TouchableOpacity with the width and height of your
styles.categoriesImages and the Image will simply have 100% on both
width and height
Define a width and height for the image that's not a percentage but an actual value, and the TouchableOpacity will simply adapt to it's content size

Why is there massive white space under my image in React? What's creating this mysterious div?

I'm building a login Component in React, and trying to add the brand image. When I do this, I'm getting a huge amount of white space underneath it.
I've been working on this for a bit now, and I've discovered that, when I look in the dev tools, I can make headway by modifying this mysterious div that seems to be created by Material-UI, the front-end framework I'm using.
When I look into this in the dev tools, I find that there's a div with the attribute padding-top: calc(100%) which, when modified to something like padding-top: calc(30%), reduces the size of this whitespace underneath the image.
I've also tried some of the basic layout solutions suggested in many of the answers to similar questions here on SO, but none of them make a difference. It seems that this padding issue is at the heart of the problem.
The Problem
Because I don't know what's creating this div, I'm not able to override the padding to work towards a solution. I've tried modifying paddingTop and padding with the !important tag in the styling of both the image, and the parent element of the image.
Code Sample
<Paper variant='outlined' style={{ width: '380px' }}>
<Box m={4}>
<Image
src='../static/images/TextLogo.svg'
imageStyle={{
height: 'auto',
width: '100%',
}}
/>
</Box>
...
Stack
"#material-ui/core": "^4.0.0-alpha.8",
"material-ui-image": "^3.2.3",
"next": "^8.1.0",
"react": "^16.8.6",
"react-dom": "^16.8.6"
Thanks. I'd appreciate your help!
The <div> with the padding-top and other styles is coming from the Image component that you are using from material-ui-image.
Below is the overall structure rendered by that Image component:
<div
style={styles.root}
onClick={onClick}
>
{image.src && <img
{...image}
style={styles.image}
onLoad={this.handleLoadImage}
onError={this.handleImageError}
/>}
<div style={styles.iconContainer}>
{!disableSpinner && !this.state.imageLoaded && !this.state.imageError && loading}
{!disableError && this.state.imageError && errorIcon}
</div>
</div>
padding-top is part of the styles in styles.root.
styles.root:
const styles = {
root: {
backgroundColor: color,
paddingTop: `calc(1 / ${aspectRatio} * 100%)`,
position: 'relative',
...style
},
When padding-top is a percentage, it is a percentage of the width, so it is important to control the width of the container in order to have predictable behavior.
You can modify the padding-top by either explicitly overriding it via the style prop or by specifying the appropriate value in the aspectRatio prop. By default, this Image component is assuming square images (aspectRatio: 1).
Here is a working example demonstrating both ways of controlling padding-top:
import React from "react";
import Image from "material-ui-image";
import Box from "#material-ui/core/Box";
export default function App() {
return (
<>
<Box m={4} width={200}>
<Image
aspectRatio={1.5}
src="https://www.publicdomainpictures.net/pictures/10000/velka/black-monkey-11280155875i3QV.jpg"
/>
Something under image 1
</Box>
<Box m={4} width={200}>
<Image
style={{
paddingTop: "calc(66.7%)"
}}
src="https://www.publicdomainpictures.net/pictures/10000/velka/black-monkey-11280155875i3QV.jpg"
/>
Something under image 2
</Box>
</>
);
}
Slightly related answer (with regard to the use of padding-top): A good way to handle #material-ui Skeleton scaling within a variable height grid row?

TouchableOpacity breaks styling

I'm attempting to create navigation in React Native. I've made a custom component that consists of an image and some text. Before applying TouchableOpacity the styling works fine. But after I apply it to one of the components, this happens.
All of the code can be found here, ready to run.
I'd like that the component titles MojQR doesn't deform, but stays like the rest of them. Currently, as seen in the code, the TouchableOpacity is only applied to MojQR
You have a problem with the styling you are using. When you set the dimensions (width, height) to take a percentage, it will take the percentage from the component that is wrapping it. That's why when you added TouchableOpacity it mess all the styling. You have 2 options, change the styling pattern you are using or make a simple change that can change the width dynamically from MenuItem like so:
//App.js
<TouchableOpacity style={styles.touchableContainer} onPress={() => navigation.navigate('Details')}>
<MenuItem itemImage={require('./app/img/QR_code_for_mobile_English_Wikipedia.svg.png')} children='Moj QR' isWrapped={true} />
</TouchableOpacity>
...
//And the styling inside your style object
touchableContainer: {
width: '50%'
}
In the code above, you add that prop that will be used to change the styles in
//MenuItem.js
//change the wrapper for this one:
<View style={this.props.isWrapped ? {...styles.menuItem, width: '100%'} : styles.menuItem}>
...
//And add the flexGrow property to your styles.menuItem
menuItem: {
width: '50%',
height: '33.3333%',
padding: 10,
flexGrow: 1,
},

Resources