Global toolbar in Ionic 4 (React) overlapping IonContent - ionic-framework

I am just getting to grips with Ionic from a React and Flutter background.
I am trying to achieve a global navigation top bar using Ionic 4 react. The only documentation that looks like it might work is the IonHeader.
I have tried to add this to my root App.tsx component but this does not seem to work as expected. The height of the Toolbar component is not recognised by the other components. I.e., the toolbar overlaps the page content.
Attempt at a global Toolbar from App.tsx:
import React from 'react';
import { Redirect, Route } from 'react-router-dom';
import {
IonApp,
IonRouterOutlet,
IonHeader,
IonToolbar,
IonTitle
} from '#ionic/react';
import { IonReactRouter } from '#ionic/react-router';
import DashboardA from './containers/Dashboards/DashboardA';
import DashboardB from './containers/Dashboards/DashboardB';
/* Core CSS required for Ionic components to work properly */
import '#ionic/react/css/core.css';
/* Basic CSS for apps built with Ionic */
import '#ionic/react/css/normalize.css';
import '#ionic/react/css/structure.css';
import '#ionic/react/css/typography.css';
/* Optional CSS utils that can be commented out */
import '#ionic/react/css/padding.css';
import '#ionic/react/css/float-elements.css';
import '#ionic/react/css/text-alignment.css';
import '#ionic/react/css/text-transformation.css';
import '#ionic/react/css/flex-utils.css';
import '#ionic/react/css/display.css';
/* Theme variables */
import './theme/variables.css';
import styled from 'styled-components';
const App: React.FC = () => (
<div>
<IonApp>
<IonHeader>
<IonToolbar>
<IonTitle>My Global Navigation</IonTitle>
</IonToolbar>
</IonHeader>
<IonReactRouter>
<IonRouterOutlet>
<Route
path="/DashboardA"
component={DashboardA}
exact={true}
/>
<Route
path="/DashboardB"
component={DashboardB}
exact={true}
/>
<Route
exact
path="/"
render={() => <Redirect to="/DashboardB" />}
/>
</IonRouterOutlet>
</IonReactRouter>
</IonApp>
</div>
);
export default App;
Dashboard A Component:
import React, { Component } from 'react';
import {
IonCard,
IonCardContent,
IonCardHeader,
IonCardTitle,
IonContent,
IonGrid,
IonRow,
IonCol
} from '#ionic/react';
class DashboardA extends Component {
render() {
return (
<IonContent padding-start="150">
<IonGrid>
<IonRow>
<IonCol size-xs="12" size-md="6">
<IonCard>
<IonCardHeader>
<IonCardTitle>Thing</IonCardTitle>
</IonCardHeader>
<IonCardContent>BAR CHART</IonCardContent>
</IonCard>
</IonCol>
<IonCol size-xs="12" size-md="6">
<IonCard>
<IonCardHeader>
<IonCardTitle>Other Thing</IonCardTitle>
</IonCardHeader>
<IonCardContent>BAR CHART</IonCardContent>
</IonCard>
</IonCol>
</IonRow>
</IonGrid>
</IonContent>
);
}
}
export default DashboardA;
The only workaround I can see is to have a navigation bar that I import and use in the IonHeader of each page but things seems really clunky. Is there a way to have one reference to the toolbar in App.tsx? I appreciate there is the obvious CSS hack to pad but I do not want to go down that route if there is a "proper" way of doing thins.
Thanks!

Having spoken to one of the developer advocates I think that it is fair to say that what I was trying to achieve is an Ionic anti pattern.
The navigation has been designed to be added to each and in the .
So you can just have a navigation components and import where you need it.

Related

Navigatiion Component using #mui/material not rendering [duplicate]

I have been learning React for few days and I wrote simple project (single page application). Problem is that my page doesn't show anything - it's a blank page.
App.js
import './App.css';
import {BrowserRouter as Router,Routes,Route,} from "react-router-dom";
import { Home } from './components/Home';
import { Wallet } from './components/Wallet';
function App() {
return (
<Router>
<Routes>
<Route exact path="/" component={Home}/>
<Route path="/wallet" component={Wallet}/>
</Routes>
</Router>
);
}
export default App;
Wallet.js
import React from "react";
export function Wallet() {
return (
<div>
<h1>Wallet Page!</h1>
</div>
);
}
Home.js
import React from "react";
export function Home() {
return (
<div>
<h1>Home Page!</h1>
</div>
);
}
So when I go to http://localhost:3001/ or http://localhost:3001/wallet I receive blank page. Could someone point me where I made a mistake?
In react-router-dom#6 the Route components render the routed content on the element prop as a ReactNode, i.e. as JSX. There is no longer any component, or render and children function props.
Routes and Route
declare function Route(
props: RouteProps
): React.ReactElement | null;
interface RouteProps {
caseSensitive?: boolean;
children?: React.ReactNode;
element?: React.ReactNode | null;
index?: boolean;
path?: string;
}
Move the components into the element prop and pass them as normal JSX instead of as a reference to a component.
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/wallet" element={<Wallet />} />
</Routes>
</Router>

Ionic 5 / React: Use ion-icon to embed custom SVG

I have a React app in Ionic 5 and I want to add some custom SVGs to it.
This SO question is about Angular, but my question is about React.
My app folder structure looks like this:
src
assets
listen.svg
SvgListen.tsx
Here is SvgListen.tsx:
import React from 'react';
import { ReactComponent as ListenSvg } from './listen.svg';
import { IonIcon } from '#ionic/react';
const SvgListen = () => (
<>
<ListenSvg />
<IonIcon src="./listen.svg" font-size="48px" />
</>
);
export default SvgListen;
When testing the app in Chrome, I get this HTML:
<ion-icon src="./listen.svg" font-size="48px" role="img" class="ios hydrated"></ion-icon>
The <ListenSvg /> that I imported is displayed correctly; however, the ion-icon is not displayed. There is no error message, either.
I checked this blog post, but no luck with the approach outlined there, either.
How can I show a custom SVG using <IonIcon> in Ionic 5?
According do the Create React App docs you can import images to get their final path in the output bundle:
import React from 'react';
import { IonIcon } from '#ionic/react';
import listenSvg from './listen.svg';
const SvgListen = () => (
<IonIcon src={listenSvg} font-size="48px" />
);
export default SvgListen;

React Hook Form with MUI Toggle Group

I'm trying to use the MUI toggle group with React Hook Form however I can't get the value to post when submitting the form. My toggle group component looks like this:
import FormatAlignCenterIcon from '#material-ui/icons/FormatAlignCenter';
import FormatAlignLeftIcon from '#material-ui/icons/FormatAlignLeft';
import FormatAlignRightIcon from '#material-ui/icons/FormatAlignRight';
import FormatAlignJustifyIcon from '#material-ui/icons/FormatAlignJustify';
import ToggleButton from '#material-ui/lab/ToggleButton';
import ToggleButtonGroup from '#material-ui/lab/ToggleButtonGroup';
import React from 'react';
import {Controller} from "react-hook-form";
export default function TestToggleGroup(props) {
const {control} = props;
const [alignment, setAlignment] = React.useState('left');
const handleAlignment = (event) => {
setAlignment(event[1]);
};
return (
<Controller
name="ToggleTest"
as={
<ToggleButtonGroup
value={alignment}
exclusive
onChange={handleAlignment}
aria-label="text alignment"
>
<ToggleButton value="left" aria-label="left aligned" key="left">
<FormatAlignLeftIcon/>
</ToggleButton>
<ToggleButton value="center" aria-label="centered" key="center">
<FormatAlignCenterIcon/>
</ToggleButton>
<ToggleButton value="right" aria-label="right aligned" key="right">
<FormatAlignRightIcon/>
</ToggleButton>
<ToggleButton value="justify" aria-label="justified" disabled key="justify">
<FormatAlignJustifyIcon/>
</ToggleButton>
</ToggleButtonGroup>
}
value={alignment}
onChange={(e) => {
handleAlignment(e);
}}
valueName={"alignment"}
control={control}
/>
);
}
Not sure exactly what I'm doing wrong but any assistance would be greatly appreciated.
My workaround was using an effect to manually set the value using setValue and then using getValues() inside your handleSubmit function to get the values.
const { control, setValue } = props;
//Effect
React.useEffect(() => {
setAlignment('ToggleTest', alignment);
}, [alignment, setAlignment]);

Material UI filled input for KeyboardDatePicker

I know that with an InputField one is able to pass down the variant="filled" prop to get input box filled. However, is it also possible to pass down a prop with the similar effect using a Material UI date picker (not using the native datepicker from the browser)?
Example of filled input:
I think you are looking for inputVariant={"filled"} prop
import "date-fns";
import React from "react";
import Grid from "#material-ui/core/Grid";
import DateFnsUtils from "#date-io/date-fns";
import {
MuiPickersUtilsProvider,
KeyboardTimePicker,
KeyboardDatePicker
} from "#material-ui/pickers";
export default function MaterialUIPickers() {
// The first commit of Material-UI
const [selectedDate, setSelectedDate] = React.useState(
new Date("2014-08-18T21:11:54")
);
const handleDateChange = date => {
setSelectedDate(date);
};
return (
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<Grid container justify="space-around">
<KeyboardDatePicker
inputVariant={"filled"}
disableToolbar
variant="inline"
format="MM/dd/yyyy"
margin="normal"
id="date-picker-inline"
label="Date picker inline"
value={selectedDate}
onChange={handleDateChange}
KeyboardButtonProps={{
"aria-label": "change date"
}}
/>
</Grid>
</MuiPickersUtilsProvider>
);
}
Working sandbox project link
The #material-ui/pickers has been moved to the #mui/lab.
Checkout the migration guide Here !
Below is a sample code to implement the same
import React from "react";
import TextField from "#mui/material/TextField";
import AdapterDateFns from "#mui/lab/AdapterDateFns";
import LocalizationProvider from "#mui/lab/LocalizationProvider";
import DatePicker from "#mui/lab/DatePicker";
export default function filledDatePicker() {
const [selectedDate, setSelectedDate] = React.useState(new Date());
const handleDateChange = date => {
setSelectedDate(date);
};
return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<DatePicker
value={selectedDate}
onChange={handleDateChange}
renderInput={(props) => (
<TextField {...props} variant="filled" label="Select Date" />
)}
/>
</LocalizationProvider>
);
}

Material UI RTL

The RTL demo provided in material ui guides seems does not work for components.
As they said in the Right-to-left guide internally they are dynamically enabling jss-rtl plugin when direction: 'rtl' is set on the theme but in the demo only the html input is rtl and TextField isn't.
Here's the demo code from https://material-ui-next.com/guides/right-to-left/#demo
import React from 'react';
import { MuiThemeProvider, createMuiTheme } from 'material-ui/styles';
import TextField from 'material-ui/TextField';
const theme = createMuiTheme({
direction: 'rtl', // Both here and <body dir="rtl">
});
function Direction() {
return (
<MuiThemeProvider theme={theme}>
<div dir="rtl">
<TextField label="Name" />
<input type="text" placeholder="Name" />
</div>
</MuiThemeProvider>
);
}
export default Direction;
Once you have created a new JSS instance with the plugin, you need to
make it available to all components in the component tree. JSS has a
JssProvider component for this:
import { create } from 'jss';
import rtl from 'jss-rtl';
import JssProvider from 'react-jss/lib/JssProvider';
import { createGenerateClassName, jssPreset } from '#material-ui/core/styles';
// Configure JSS
const jss = create({ plugins: [...jssPreset().plugins, rtl()] });
// Custom Material-UI class name generator.
const generateClassName = createGenerateClassName();
function RTL(props) {
return (
<JssProvider jss={jss} generateClassName={generateClassName}>
{props.children}
</JssProvider>
);
}