Flags inside a React Bootstrap select option renders as [object, object] - css

I want to display Flags icons inside a React Bootstrap selection Option. I have tried both CSS based and React based libraries to do so and in each case I get only [object object]
I have tried with the https://github.com/lipis/flag-icon-css CSS library
<Form.Control as="select">
<option><span className="flag-icon flag-icon-gr"></span></option>
</Form.Control>
Which gives me a warning and the same [Object object]
Warning: Only strings and numbers are supported as <option> children.
I have also attempted with the React wrapper for the same library https://www.npmjs.com/package/react-flag-icon-css
<Form.Control as="select">
<option><FlagIcon className="countryIcon" code="us" size="lg"/></option>
</Form.Control>
Which does not generate a warning but no results either
Does anyone know how I can get something else than string or number in the Option, or another way to include an icon ?

Option HTML tag accepts text only, it can't accept any other HTML, it will strip it. You can check this React issue [bug][16.5.0] option returns [object Object] instead of string and read the comment by Dan Abramov:
I don't think it was strictly a regression. This is kind of a thorny
area. It was never intentionally supported. It accidentally worked on
initial mount but then crashed on updates (#13261). Fixing the crash
was more important, so we fixed it to be treated as text content
(which it should be). Unfortunately this means putting custom
components in the middle is not supported. That's consistent with how
textarea and similar elements work.
I think it's better to show invalid output and warn about something
that breaks on updates, than to let people use it only to discover it
crashes in production. But I can see arguments for why this should be
supported when the custom component returns a string. Unfortunately I
don't know how to fix it in a way that would both solve the update
crashes and support text-only content. I think for now it's reasonable
to say putting custom components into doesn't really work
(and never quite worked correctly), and ask you to manually provide a
string to it.
Alternatively, you can use Bootstrap Dropdowns to create a dropdown button with a list of countries using the code below:
App.js:
...
import Dropdown from 'react-bootstrap/Dropdown';
import FlagIcon from './FlagIcon.js'
function App() {
const [countries] = useState([
{ code: 'gr', title: 'Greece'},
{ code: 'gb', title: 'United Kingdom'},
{ code: 'us', title: 'United States'}
]);
const [toggleContents, setToggleContents] = useState("Select a country");
const [selectedCountry, setSelectedCountry] = useState();
return (
<div className="App">
<Form>
<Dropdown
onSelect={eventKey => {
const { code, title } = countries.find(({ code }) => eventKey === code);
setSelectedCountry(eventKey);
setToggleContents(<><FlagIcon code={code}/> {title}</>);
}}
>
<Dropdown.Toggle variant="secondary" id="dropdown-flags" className="text-left" style={{ width: 300 }}>
{toggleContents}
</Dropdown.Toggle>
<Dropdown.Menu>
{countries.map(({ code, title }) => (
<Dropdown.Item key={code} eventKey={code}><FlagIcon code={code}/> {title}</Dropdown.Item>
))}
</Dropdown.Menu>
</Dropdown>
</Form>
</div>
);
}
FlagIcon.js:
import React from 'react';
import FlagIconFactory from 'react-flag-icon-css';
// const FlagIcon = FlagIconFactory(React);
// If you are not using css modules, write the following:
const FlagIcon = FlagIconFactory(React, { useCssModules: false })
export default FlagIcon;
You'll get a dropdown button like this:
You can also check this working Stackblitz: https://stackblitz.com/edit/react-bootstrap-flags-dropdown-menu

Are you closing the tag
<Form.Control as="select">
[object Object] is displayed e.g when you are concatenating a string with an object, for example:
console.log(""+{})

Related

changing css code and setting focus at the same time (why doesn't it work?)

I tried to make...
There is no input on the screen at the first rendering. When I click the button, input appears. And I want to set focuse on the input at the same time.
Let me explain what i made.
At first, the input is not visible on the screen.
Because the display property of the Box(the div tag), which is the parent component of the input, is none.
But when i click the button, the display property of the Box changes to block.
And here is what i want to do.
i'm going to set focus on the input on the screen.
In the function called when the button is clicked, I wrote a code that changes the css code and sets the focus on the input.
But it didn't work.
Please take a look at the following code.
const [inputDisplay, setInputDisplay] = useState("none");
const refInput = useRef(null);
const HandleShowInput = () => {
setInputDisplay("block");
refInput.current.focus();
};
return (
<>
<Box theme={inputDisplay}>
<Input ref={refInput}/>
<Box/>
<Button onClick={HandleShowInput}/>
</>
)
Below is the code that is dynamically changing the css of the Box component.
import styled, { css } from "styled-components";
const Box = ({ children, ...props }) => {
return <StBox {...props}>{children}</StBox>;
};
const StBox = styled.div`
${({ theme }) => {
switch (theme) {
case "block":
return css`
display: ${theme} !important;
`;
default:
break;
}
}}
`;
export default Box;
But this below code is worked. I separated the code by putting it in useEffect.
const [inputDisplay, setInputDisplay] = useState("none");
const refInput = useRef(null);
const HandleShowInput = () => {
setInputDisplay("block");
};
useEffect(() => {
refInput.current.focus();
}, [inputDisplay]);
return (
<>
<Box theme={inputDisplay}>
<Input ref={refInput}/>
<Box/>
<Button onClick={HandleShowInput}/>
</>
)
I want to know why the upper case not works and the lower case works. I don't know if I have lack react knowledge or css knowledge. I would be very grateful if you could help a beginner in react. Also, please understand if there are any unnatural sentences because i'm not good at English. thank you.
When you are trying to focus on the input element by HandleShowInput this function.Here two things are happening your changing the state and focus of input.It will focus the input but time will be so less that we can't see on the ui.And also due to the state change render will happen and again ref will get the input element. Thus you are not able to see this focussed input
But in case of useEffect this will happen after the render. After this no rendering. So we can see the focussed input
The way of thinking about React is a little different from Javascript.
You may expect the below two run in the same way.
setInputDisplay("block");
refInput.current.focus();
and
document.querySelector('#canFocus').style.display='block'
document.querySelector('#canFocus').focus();
NO~ It's not.
JS block the Dom and then focus it, it works well.
But React works like the code below.
setTimeout(()=>{
// next react render cycle callback
document.querySelector('#canNotFocus').style.display='block'
}, 1000)
document.querySelector('#canNotFocus').focus();
While focus method is called, the dom is display as none;
You set state in react, ReactDom will make it as a display block in the next life cycle of function component.
demo here : https://codesandbox.io/s/confident-wilson-q01ktj?file=/index.html
useEffect(() => {
refInput.current.focus();
}, [inputDisplay]);
is a watching function. While inputDisplay changed, the function inside will be called.
you set state to block
react re-render the component as a newer state
render function called, and dom is block
Effect watching function is called and the focus() called.

React ChakraUI ForwardRef child ignoring variant prop

I'm having an issue with forwardRef and Input from ChakraUI.
I tried to do a generic input component which has always flushed variant. My problem is Chakra does reset variant to default.
ModalInput Component
import { forwardRef, InputProps, Input } from '#chakra-ui/react';
const ModalInput = forwardRef<InputProps, 'input'>((props, ref) => (
<Input ref={ref} color="gray.600" variant="flushed" {...props}>
{props.children}
</Input>
));
export default ModalInput;
ModalInput Component
<ModalInput placeholder="ex: Entreprise Dupont" />
This way, all my ModalInput should have variant flushed, but you can see on the screenshot below it is outline.
Thanks for help !
I finally discovered this bug was due to InputGroup, which was enclosing my ModalInput.
Reported this bug here.
Find the sandbox here

Font Awesome 6 (beta) and dynamic icon name in Next JS

I am developing a website with Next JS. This is the first time I use this language and I still have a lot to learn.
Now, I have a Pro subscription to Font Awesome and I am looking to use their component directly in my project, as described in their guides.
https://fontawesome.com/v6.0/docs/web/use-with/react/
https://fontawesome.com/v6.0/docs/web/use-with/react/add-icons
Basically, just using a component like this:
<FontAwesomeIcon icon={brands("google")} />
It works.
The problem, which I can't solve, is how to set the "google" value dynamically, in a previously initialized variable. I need that because this values are coming dynamically from a database.
If I try:
var example = "google";
<FontAwesomeIcon icon={brands(example)} />
Then I receive this error: "Only string literals are supported when referencing icons (use a string here instead)".
Anyone have any ideas?
The way you import your icons uses a babel macro. It means that the referenced icon must be known at build time. It just won't work, because Babel can't figure out what icon should be imported, it can only be done during runtime. That's why it tells you that only string literals are supported.
So you need to use the second method, explained in the docs. You have to have some kind of mapping between icon and the value from DB and then grab the relevant icon. Something like this:
// not sure about exact import
import { faGoogle } from '#fortawesome/free-brand-svg-icons';
// you'd put all valid values that can come from the backend here
const myIcons = {
google: faGoogle
}
// ...
const example = 'google';
<FontAwesomeIcon icon={myIcons[example]} />
The other option is to use library.add, explained here and then do the same as above but instead of imported icon use a string, e.g. google: 'fa-brands fa-google' (again, not sure about exact value here).
Would the following work?
var example = ['fab', 'google'];
<FontAwesomeIcon icon={example} />
P.S. It is recommended to use the let or const keywords with ES6.
// Utils
const UpperFirst = (sentence) => {
if (!sentence || (typeof sentence !== 'string')) return null
return `${sentence.charAt(0).toUpperCase()}${sentence.slice(1)}`
}
// React Generic Component
import React from 'react'
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
import * as solid from '#fortawesome/free-solid-svg-icons'
import * as regular from '#fortawesome/free-regular-svg-icons'
import { UpperFirst } from '#utils'
const GenFontAwe = ({ isReg, customClass, nameIco }) => {
if (!nameIco) return null
const finalName = nameIco.split('-').map((cv, ind) => ind === 0 ? cv : UpperFirst(cv)).join('')
const finalIcon = isReg ? regular[finalName] : solid[finalName]
if(!finalIcon) return null
return <FontAwesomeIcon icon={finalIcon} className={customClass || ''} />
}
export default GenFontAwe
// Consume that way:
<GenFontAwe nameIco='fa-folder-open' isReg customClass="h1 p-5" />

How to test React dynamic style prop?

Am teaching myself React and am starting on testing. Using the recommended stuff from the docs... create-react-app, jest, testing-library/react. I have a component that renders a dynamic style, something like this
const ScalingDiv = (props) => (
<StyledDiv size={props.size || 42}>
<OtherEl>
{props.text}
</OtherEl>
</StyledDiv>
);
I would like to verify that my logic in there is working correctly (that 42 is used as a fallback size). I cannot find any examples or docs of this. I had hoped that something like this would work-
test('check fallback size', async () => {
const {container} = render(<ScalingDiv/>);
expect(container.firstChild).toHaveAttribute('size', 42);
});
But I haven't found any combination of matchers and queries that returns ANY attributes. Then I tried to just check the style directly using jest-dom, but toHaveStyle('this_isnt_valid_css: 199') passes- I couldn't stick anything in there to get it to fail. So... what is the right way to do this?
It's not attribute but prop. So we can refer to prop() and props() methods like
expect(container.firstChild.prop('size')).toEqual(42);
or
expect(container.firstChild.props()).toEqual({
size: 42
});

How to use react-jsonschema-form with material-ui?

I am doing a form using react-jsonschema-form, but i really want to customize my application (including the form) with the Material-UI.
I am having trouble to use both together because react-jsonchema-form uses a uiSchema for styling and the Material-UI is set on a prop like this :
SimpleModal.propTypes = {
classes: PropTypes.object.isRequired,
};
<FormControl className={classes.formControl}>
How can i use the Material-UI inside the schema forms?
Now you can start use it with standard react-jsonschema-form library! I searched for a long time and found that now it can already be done.
This PR explain using HOC: https://github.com/mozilla-services/react-jsonschema-form/issues/1222
GitHub: https://github.com/cybertec-postgresql/rjsf-material-ui
Playground with material-ui components: https://cybertec-postgresql.github.io/rjsf-material-ui/
import { withTheme } from 'react-jsonschema-form';
import { Theme as MuiTheme } from 'rjsf-material-ui';
const Form = withTheme(MuiTheme);
If you want use component in material UI i did like this...
import material UI
import TextField from '#material-ui/core/TextField'
declare constant and costum widgets
const MyCustomWidget = props => {
return (
<TextField
type="text"
label="Name1"
value={props.value}
onChange={event => props.onChange(event.target.value)}
margin="normal"
/>
)
}
const widgets = {
TextWidget: MyCustomWidget,
}
and in the return of my component
return (
<div>
{' '}
<Form schema={schema1} widgets={widgets} >
{/* this is for disable the button Submit of Form */}{' '}
</Form>
</div>
It works for me
Weird to see there's no answer.
Quick answer: you cant!
Check out project's FAQ about that, it says:
Q: Will react-jsonschema-form support Material, Ant-Design, Foundation, or [some other specific widget library or frontend style]?
A: Probably not. We use Bootstrap v3 and it works fine for our needs. We would like for react-jsonschema-form to support other frameworks, we just don't want to support them ourselves. Ideally, these frontend styles could be added to react-jsonschema-form with a third-party library.
But! ... :) don't go so fast!
The closest I have come to achieve a Material "look and feel" was to use a Bootstrap Theme, Paper by Bootswatch which is quite nice!
Hope this helps anyone

Resources