how to make a message without wrapping in span in react-intl - reactjs

i have a problem with yahoo/react-intl thats i want to make messages in string type but when im using FormattedMessage it gives me message wrapped in span and thats not cool.
i tried formatMessage and that not working too.
i be very thankful for any help or advise this is my code:
import React from 'react';
import {FormattedMessage} from 'react-intl';
export default {
items: [
{
name: <FormattedMessage id='app.dashboard'/>,
url: '/dashboard',
icon: 'icon-speedometer',
badge: {
variant: 'info',
text: 'New',
},
},
{
title: true,
name: <FormattedMessage id='app.dashboard'/>,
// optional wrapper object
wrapper: {
// required valid HTML5 element tag
element: 'strong',
// optional valid JS object with JS API naming ex: { className: "my-class", style: { fontFamily: "Verdana" }, id: "my-id"}
attributes: {},
},
// optional class names space delimited list for title item ex: "text-center"
class: '',`enter code here`
},

for use in jsx:
it's rendered as a <span>:
<FormattedMessage id='app.dashboard'/>
it's rendered as an <option>:
<FormattedMessage id='app.dashboard' children={msg=> <option>{msg}</option>}/>
or:
<FormattedMessage id='app.dashboard' tagName="option"/>
it's rendered to nothing:
<FormattedMessage id='app.dashboard' children={msg=> <>{msg}</>}/>
or:
<FormattedMessage id="app.dashboard">{txt => txt}</FormattedMessage>
To use it in a component, you can use formatMessage() like this:
const App=()=>{
const value = intl.formatMessage({ id: 'header.nav.login' });
return(<div>{value}</>)
}

Given that you inject the intl context by yourself, Then you can use the formatMessage function.
For example, in your case:
items: [
{
name: intl.formatMessage({id:'app.dashboard'});
}
]
To get intl in your component you have two choices:
get it from your component's context
use injectIntl to get it in your props.
If you're not in a component, it gets slightly harder but I would just put the id instead of the formatted message in name and then use the react-intl context when available. Here, in the component that consumes and displays this list of items.

The solution here is to upgrade react-intl to version 3.
In version 3, the <FormattedMesage> (and similarly others react-intl components) is rendering into React.Fragment.
If you want to render it to something else you can specify textComponent prop on IntlProvider, eg.:
<IntlProvider textComponent="span" />
See info in Migration Guide (v2 -> v3).

Related

AntD Tree: need help! can't pass react element as icon OR title for antd tree

I'm using the AntD tree and I have a react element that I want to pass as either an icon or a title because it has custom styling. Due to it being IP I can't share too much code, but my question is:
how can I pass a react element (see below i.e. generic name) as either a title or icon and have antD tree render it?
i.e. this is what I want to pass as a prop to the icon or title
import React from 'react';
const genericName = (props) => {
// code uses props to get some infor for Color
// cant share code due to proprietary reasons
// but it is not needed for this question
const colorHTML = getColor(Color);
return (
<div>
<div className={`colors from`}>${colorHTML}</div>
{pin}
</div>
);
};
export default genericName;
in my console you can see node.icon is a typeof react.element. I want to target that and just pass the prop into antD tree as either title or icon
i.e.
return (
<Tree
icon={node.icon}
/>
)
I've searched and similar answers were given before antD forbid the use of children and strictly allows treeData. All examples I see only use strings in titles/icons, but since antD documentation is very limited, I need to know if my use case is possible. Right now, for the life of me I can't understand why it doesn't populate.
Thank you in advance.
It should definitely work to put a JSX component as title within treeData. Take a look at this snippet, I added a Icon here in one of the titles:
import React from 'react'
import { RightCircleOutlined } from '#ant-design/icons'
type Props = {}
import { Tree } from 'antd';
import type { DataNode, TreeProps } from 'antd/es/tree';
const treeData: DataNode[] = [
{
title: <span>{<RightCircleOutlined />} parent</span>, //icon added here
key: '0-0',
children: [
{
title: 'parent 1-0',
key: '0-0-0',
disabled: true,
children: [
{
title: 'leaf',
key: '0-0-0-0',
disableCheckbox: true,
},
{
title: 'leaf',
key: '0-0-0-1',
},
],
},
{
title: 'parent 1-1',
key: '0-0-1',
children: [{ title: <span style={{ color: '#1890ff' }}>sss</span>, key: '0-0-1-0' }],
},
],
},
];
const Demo: React.FC = () => {
const onSelect: TreeProps['onSelect'] = (selectedKeys, info) => {
console.log('selected', selectedKeys, info);
};
const onCheck: TreeProps['onCheck'] = (checkedKeys, info) => {
console.log('onCheck', checkedKeys, info);
};
return (
<Tree
checkable
defaultExpandedKeys={['0-0-0', '0-0-1']}
defaultSelectedKeys={['0-0-0', '0-0-1']}
defaultCheckedKeys={['0-0-0', '0-0-1']}
onSelect={onSelect}
onCheck={onCheck}
treeData={treeData}
/>
);
};
export default Demo;

Including fontawesome brand icons on frontmatter metadata

I'm making some changes to a Gatsby starter and ran into an annoying problem with fontawesome brand icons. The problem is that unlike most icons, that are called faPhone or something like that, the brand icons also need a prefix ,fab.
So I can make them work in the body of my posts, like this: <Icon icon={['fab', 'github']} />
The problem is when I wanna include it on the frontmatter metadata like:
---
category: 'socials'
title: 'Github'
icon: 'fab github'
content: 'janedoegithub'
---
I have tried passing it like the above example, as 2 separate strings, as a list, and nothing seems to work. Does anyone know how to solve this?
Edit: both of these formats also don't work
---
category: 'socials'
title: 'Github'
icon:
- fab
- github
content: 'janedoegithub'
---
---
category: 'socials'
title: 'Github'
icon: ['fab', 'github']
content: 'janedoegithub'
---
when I try them I get this error:
GRAPHQL
There was an error in your GraphQL query:
Cannot query field "icon" on type "MdxFrontmatter".
If you don't expect "icon" to exist on the type "MdxFrontmatter" it is most
likely a typo.
However, if you expect "icon" to exist there are a couple of solutions to common
problems:
- If you added a new data source and/or changed something inside
gatsby-node.js/gatsby-config.js, please try a restart of your development server
- The field might be accessible in another subfield, please try your query in
GraphiQL and use the GraphiQL explorer to see which fields you can query and
what shape they have
- You want to optionally use your field "icon" and right now it is not used
anywhere. Therefore Gatsby can't infer the type and add it to the GraphQL
schema. A quick fix is to add at least one entry with that field ("dummy
content")
It is recommended to explicitly type your GraphQL schema if you want to use
optional fields. This way you don't have to add the mentioned "dummy content".
Visit our docs to learn how you can define the schema for "MdxFrontmatter":
https://www.gatsbyjs.org/docs/schema-customization/#creating-type-definitions
File: src/components/ContactInfo/index.js:25:15
this is the index.js mentioned in the error:
import React from 'react';
import { useStaticQuery, graphql } from 'gatsby';
import InfoBlock from 'components/ui/InfoBlock';
import Container from 'components/ui/Container';
import TitleSection from 'components/ui/TitleSection';
import * as Styled from './styles';
const ConctactInfo = () => {
const { mdx, allMdx } = useStaticQuery(graphql`
query {
mdx(frontmatter: { category: { eq: "socials section" } }) {
frontmatter {
title
subtitle
}
}
allMdx(filter: { frontmatter: { category: { eq: "socials" } } }, sort: { fields: fileAbsolutePath }) {
edges {
node {
id
frontmatter {
title
icon
content
}
}
}
}
}
`);
const sectionTitle = mdx.frontmatter;
const socials = allMdx.edges;
return (
<Container section>
<TitleSection title={sectionTitle.title} subtitle={sectionTitle.subtitle} center />
{socials.map((item) => {
const {
id,
frontmatter: { title, icon, content }
} = item.node;
return (
<Styled.ContactInfoItem key={id}>
<InfoBlock icon={icon} title={title} content={content} center />
</Styled.ContactInfoItem>
);
})}
</Container>
);
};
export default ConctactInfo;
As far as I understand your issue, you want to pass the icon data field from the markdown to the template/component. In that case, you can use:
---
category: 'socials'
title: 'Github'
icon:
- fab
- github
content: 'janedoegithub'
---
Note: be careful with the indentation
Or:
---
category: 'socials'
title: 'Github'
icon: ['fab', 'github']
content: 'janedoegithub'
---
You can store arrays in markdown files both ways.
Then, once your GraphQL query have retrieved and filtered your results, your component may look like:
<Icon icon={markdownData.icon} />

How to show JSDoc based prop tooltips in VSCode for React functional component prop?

I have a React functional component:
interface ISpecialButton {
text: string;
}
const SpecialButton: FC<ISpecialButton > = ({
/* Prop description */
text
} = {
//code
});
And would like a developer who uses it in a JSX template to see "Prop description" when he hovers over text prop when adding the SpecialButton to a template. I have tried various ways to do it with JSDoc, but none of these work. What is the correct way to use JSDoc for a React functional component so that VSCode shows tooltips?
The interface is the one that should be documented so every other place it's going to show the docs when hovering over it. Something like this:
interface ISpecialButton {
/**
* Prop description
*/
text: string;
}
const SpecialButton: React.FC<ISpecialButton> = ({
text
}) => {
return <>{ text }</>;
};
const Template: React.FC = () => {
return <>
<SpecialButton text='' />
</>
}

pass a variable which is inside a React function

I have this React component
import React from "react";
import "./search.css";
// Table package
import MaterialTable from 'material-table';
function BasicSearch(props) {
return (
<div className="hovered-styled-row">
<MaterialTable
title="Students"
columns={[
{ title: 'Name', field: 'name' },
{ title: 'Surname', field: 'surname' }
]}
data={props.data}
options={{
search: true
}}
actions={[
{
icon: "add",
tooltip: 'Save User',
onClick: (event, rowData) => {
// console.log(rowData);
}
}
]}
/>
</div>
)
}
export default BasicSearch;
I am using Material Design for this component. I need to export a rowData variable which is inside
actions inside onClick.
Then the container which imports this function should be able to use this data inside a container itself. when the rowData changes the data inside a container should also change. i mean the rowData has to be
in the form of a useState function
The approach you are taking is wrong. The below are the ways to pass data from one component to another depending on your design structure.
Pass data as props and use events to communicate data changes back to parent.
If global data/or shared data use Context API.
Without full context of how the data is intend to be used and how the final jsx looks like, it's difficult to further update this answer.

Invalid prop `children` of type `string` supplied to `ForwardRef(ListItemIcon)` when using .map to create MUI list items

So i am trying to create a dynamic navigation sidebar for my react app with Material UI. I saved all of the information i should need in a DB. Then i pull the information out of the db and use .map to create the sidebar links. I have everything working besides the " part, those dont render. When mapping the data to my 'template' the following error pops up:
Warning: Failed prop type: Invalid prop `children` of type `string` supplied to `ForwardRef(ListItemIcon)`, expected a single ReactElement.
my source array:
[{…}, {…}, {…}, {…}]
0:{id: 0, label: "Dashboard", link: "/dashboard", icon: "<HomeIcon />"}
1: {id: 1, label: "test", link: "/test", icon: "<SettingsInputComponentIcon />"}
2: {id: 2, label: "test1", link: "/test1", icon: "<TypographyIcon />"}
3: {id: 3, label: "test2", link: "/test2", icon: "<NotificationsIcon />"}
I believe the issue is because the "icon" field is in double quotes. I have been trying to get the icon value out of quotes with with following methods:
for (var i = 0; i < data.length; i++) {
data[i] = data[i].icon.replace(/"/g, "");
or just placing it when i'm mapping like this:
<ListItemIcon>
{icon.replace(/"/g, "")}
</ListItemIcon>
Is there an approved way to do this?
EDIT:
I wanted to point out that i am importing the icons from material UI as follows:
import {
Home as HomeIcon,
NotificationsNone as NotificationsIcon,
FormatSize as TypographyIcon,
ArrowBack as ArrowBackIcon,
SettingsInputComponent as SettingsInputComponentIcon
} from "#material-ui/icons";
JSX !== HTML
JSX is a superset of JavaScript, meaning that you can't treat JSX as a string like you can with raw HTML.
If you're using Material UI's icons, you need to import their implementation like any other component and use the reference in your data.
import { AccessAlarm, ThreeDRotation } from '#material-ui/icons';
export const nav = [
{ id: 1, label: "test", link: "/test", NavIcon: AccessAlarm },
{ id: 2, label: "test2", link: "/test2", NavIcon: ThreeDRotation }
];
ListItemIcon and React Element
ListItemIcon children prop expects a single React Element.
The content of the component, normally Icon, SvgIcon, or a #material-ui/icons SVG icon element.
An element is a rendered React component, e.g. the plain object returned by React.createElement. Though we don't want to pre-render these outside the render cycle of React since it'll mess up the lifecycle of the Icon components.
To achieve this, only keep the component type instead of a string.
{
id: 3,
label: "test2",
link: "/test2",
NavIcon: NotificationsIcon // also notice the capital "NavIcon" key.
}
Then, render the icon using its type. Something like the following
{data.map(({ id, label, link, NavIcon }) => (
<ListItem key={id}>
<ListItemText primary={label} />
<ListItemIcon>
<NavIcon />
</ListItemIcon>
</ListItem>
))}
Dynamically loading icons
If you really can't change the database format, it's possible to sanitize the icon names and load them by name later using the Material UI Icon component.
children: The name of the icon font ligature.
If you can keep only the "NotificationsIcon" part of the string and remove any tag like special characters from the icons value in the database, then it would be only:
import Icon from '#material-ui/core/Icon';
// somewhere
const data = [
{ id: 1, label: "test", link: "/test", icon: "AccessAlarm" },
{ id: 2, label: "test2", link: "/test2", icon: "ThreeDRotation" }
]
// then when rendering
{data.map(({ id, label, link, icon }) => (
<ListItem key={id}>
<ListItemText primary={label} />
<ListItemIcon>
<Icon>{icon}</Icon>
</ListItemIcon>
</ListItem>
))}
But you most keep the name that Material UI is using to identify its icons.
Note that a string doesn't contain its own quotes as part of its value, so .replace(/"/g, "") does nothing at all and will return the same string, unless it had other " inside, like quoted string props.
console.log("<SettingsInputComponentIcon />".replace(/"/g, ""))
// => "<SettingsInputComponentIcon />"

Resources