how to use react-leaflet-easyprint with react-leaflet 3 - react-leaflet-v3

react-leaflet-easyprint has examples and docs for react-leaflet v1 and v2.
However, out of the box it seems to be incompatible with v3.
How can i make it work with v3?

This is how i did it.
I used the following packages instead and maybe they will work the same way
// package.json
"leaflet-easyprint": "^2.1.9",
"react-leaflet": "^4.0.0",
// MapPrint.js
import L from 'leaflet';
import 'leaflet-easyprint';
import { useEffect } from 'react';
import { useMap } from 'react-leaflet';
function MapPrint(props) {
const map = useMap();
useEffect(() => {
const control = L.easyPrint({
...props
});
map.addControl(control)
return () => {
map.removeControl(control);
}
}, [map]);
return null;
}
export default MapPrint
after that you could use it like this (inside MapContainer from the new react-leaflet):
<MapContainer zoom={3} >
<MapPrint position="topleft" sizeModes={['Current', 'A4Portrait', 'A4Landscape']} hideControlContainer={false} title="Print" />
<MapPrint position="topleft" sizeModes={['Current', 'A4Portrait', 'A4Landscape']} hideControlContainer={false} title="Export as PNG" exportOnly />
</MapContainer>
So what i am saying is to use the js implementation of easyprint instead of using react wrapped version and wrap it by yourself.

Related

How to use quasar framework in vuepress 2?

I'm now using vuepress2 with quasar 2.7.1 like this:
import { Quasar } from 'quasar';
export default defineClientAppEnhance(({ app, router, siteData }) => {
app.use(Quasar);
}
#import url(https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons|Material+Icons+Outlined);
#import 'quasar/src/css/variables.sass';
#import 'quasar/src/css/core/colors.sass';
.quasar-comp {
#import 'quasar/src/css/index.sass';
}
/* I wrap the custome component in class .quasar-comp
so that the style from quasar won't conflict with style from vuepress. */
but there are 2 issues:
The style from quasar cannot works on some components, like q-btn-dropdown or q-menu.
It works well on dev mode(npm run docs:dev), but failed to build(npm run docs:build).
✔ Compiling with vite - done
✖ Rendering pages - failed
TypeError: Cannot convert undefined or null to object
at Function.assign (<anonymous>)
at installQuasar (/Users/lxm/Documents/neo/leaneo-docs/node_modules/quasar/dist/quasar.cjs.prod.js:6:15228)
at Object.install (/Users/lxm/Documents/neo/leaneo-docs/node_modules/quasar/dist/quasar.cjs.prod.js:6:479348)
at Object.use (/Users/lxm/Documents/neo/leaneo-docs/node_modules/#vue/runtime-core/dist/runtime-core.cjs.prod.js:3393:28)
at /Users/lxm/Documents/neo/leaneo-docs/docs/.vuepress/dist/.server/app.js:3745:7
at createVueApp (/Users/lxm/Documents/neo/leaneo-docs/docs/.vuepress/dist/.server/app.js:4177:11)
at async /Users/lxm/Documents/neo/leaneo-docs/node_modules/vuepress-vite/node_modules/#vuepress/bundler-vite/lib/build/build.js:49:52
at async /Users/lxm/Documents/neo/leaneo-docs/node_modules/#vuepress/utils/lib/withSpinner.js:12:24
at async build (/Users/lxm/Documents/neo/leaneo-docs/node_modules/vuepress-vite/node_modules/#vuepress/bundler-vite/lib/build/build.js:34:5)
at async /Users/lxm/Documents/neo/leaneo-docs/node_modules/#vuepress/cli/lib/commands/build/createBuild.js:51:5
Is there a better way to make quasar and vuepress works together?
Here is the implementation in Vuepress 2 (beta) and Quasar with Typescript.
First, install Quasar into Vuepress with the new syntax and import all styles:
client.ts:
import { defineClientConfig } from "#vuepress/client";
import { Quasar } from "quasar";
import 'quasar/src/css/index.sass';
export default defineClientConfig({
enhance({app, router, siteData}) {
app.use(Quasar);
},
setup() {},
rootComponents: [],
});
Then, ignore deprecation errors from sass if you're using vite.
config.ts
import { viteBundler } from '#vuepress/bundler-vite'
import { defineUserConfig } from '#vuepress/cli'
export default defineUserConfig({
// your config
...
bundler: viteBundler({
viteOptions: {
css: {
preprocessorOptions: {
scss: {
sassOptions: {
// ignore sass deprecation errors
quietDeps: true
}
}
}
}
},
}),
});
Hope it helps :)
Quasar needs some globales to be defined (ie if it's SSR). My following solution works ONYL on client-side so be sure to wrap your custom-quasar component in <ClientOnly> !
// .vuepress/config.ts
bundler: viteBundler({
viteOptions: {
define: {
__QUASAR_VERSION__: `'dev'`,
__QUASAR_SSR__: false,
__QUASAR_SSR_SERVER__: false,
__QUASAR_SSR_CLIENT__: false,
__QUASAR_SSR_PWA__: false
}
}
}),
// .vuepress/client.ts
import { defineClientConfig } from '#vuepress/client'
import Quasar from "quasar/src/install-quasar.js";
// optionally import your styles here
// import 'quasar/src/css/index.sass';
export default defineClientConfig({
enhance({ app, router, siteData }) {
app.use(Quasar);
},
setup() {
},
rootComponents: [],
});
<!-- README.md -->
<ClientOnly>
<MyComponent />
</ClientOnly>

electron-react-boilerplate: window.electron does not exist Error

I'm using electron-react-boilerplate v4.0.0
I've exposed this electron api from preload.js to use in renderer process.
preload.js
The problem comes when trying use "window.electron.ipcRenderer.printTicket()" inside a react component.
Hello React Component
I have the Error: "window.electron does not exist on type 'Window & typeof globalThis'".
#Daniel,
Try this:-
Edit your index.tsx from something like this:-
import { render } from "react-dom";
import App from "./App";
render(<App />, document.getElementById("root"));
to something like this:-
import { render } from "react-dom";
import App from "./App";
declare global {
interface Window {
electron: any;
}
}
render(<App />, document.getElementById("root"));
Now you can use window.electron anywhere in the renderer. This fixed the problem for me. You could also add this in the App.js file.
Although I have not tested it, you can do something like this too:-
preload.js
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electron', {
hworld: "Hello world" // window.electron.hworld is a string ("Hello world")
});
index.tsx
import { render } from "react-dom";
import App from "./App";
declare global {
interface Window {
electron: {
hworld: string // Since you know window.electron.hworld is a string
}
}
}
render(<App />, document.getElementById("root"));

Notifications failing at notify()

I am trying to fire a simple notification in Quasar 2:
setup() {
const $q = useQuasar()
$q.notify('hello')
}
This fails with:
Uncaught TypeError: $q.notify is not a function
This is a UMD application that works fine without these two lines - I do not really know where to go from there as the docs say that there is nothing special to configure before using it.
Incindentally, my IDE is suggesting me notify() when typing $q. so at least at that level is it well recognized.
I think you forgot to add notify in plugins(quasar.conf.js).
return {
framework: {
plugins: [
'Notify'
],
}
}
For those using Vue CLI, you will need to work on quasar-user-options.js:
import { Notify } from "quasar";
// To be used on app.use(Quasar, { ... })
export default {
plugins: { Notify },
};
Quasar vite plugin + vue3
In main.ts or main.js, just add these 2 lines :
JS
import { Notify } from "quasar";
.use(Quasar, {
plugins: {
Notify,
}, // import Quasar plugins and add here
})
Here a example of my code :
JS
import { createApp } from 'vue'
import { Quasar } from 'quasar'
import quasarLang from 'quasar/lang/fr'
import { Notify } from "quasar";
import router from './router'
import { createPinia } from 'pinia'
import './style.css'
// Import icon libraries
import '#quasar/extras/material-icons/material-icons.css'
// Import Quasar css
import 'quasar/src/css/index.sass'
import App from './App.vue'
const pinia = createPinia()
createApp(App)
.use(Quasar, {
plugins: {
Notify,
}, // import Quasar plugins and add here
lang: quasarLang,
})
.use(router)
.use(pinia)
.mount('#app')

Deeplinking with a domain name

I have the following code in my App.js:
import React, { useState, useRef, useEffect } from 'react';
import { SafeAreaView, Text } from 'react-native';
import { NavigationContainer, useLinking } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
const Stack = createStackNavigator();
const Screen1 = () => <SafeAreaView><Text>Screen1</Text></SafeAreaView>;
const Screen2 = () => <SafeAreaView><Text>Screen2</Text></SafeAreaView>;
export default function App() {
const ref = useRef();
const [isReady, setIsReady] = useState(false);
const [initialState, setInitialState] = useState();
const { getInitialState } = useLinking(ref, {
prefixes: ['http://example.com', 'mychat://'],
config: {
screens: {
Screen2: 'screen-2',
},
},
});
useEffect(() => {
getInitialState().then((state) => {
if (state !== undefined) setInitialState(state);
setIsReady(true);
});
}, [getInitialState]);
if (!isReady) return null;
return (
<NavigationContainer ref={ref} initialState={initialState}>
<Stack.Navigator>
<Stack.Screen name='Screen1' component={Screen1} />
<Stack.Screen name='Screen2' component={Screen2} />
</Stack.Navigator>
</NavigationContainer>
);
}
Most of them are copied from https://reactnavigation.org/docs/deep-linking/ and https://reactnavigation.org/docs/use-linking/.
In the docs there is prefixes: ['https://mychat.com', 'mychat://'], I just changed https://mychat.com to http://example.com. But it doesn't seem to work.
When I open the following links in Safari:
mychat:// (works, gets redirected to app Screen1)
mychat://screen-2 (works, gets redirected to app Screen2)
http://example.com (just opens the link in the browser, no popup to redirect to app)
What change do I need to make to redirect the domain name to the mobile app? Am I missing something?
You need to use a domain that you have access to alongside a server.
Your server needs to host a couple of files, typically within the .well-known directory:
apple-app-site-association (note the .json is not needed)
assetlinks.json
You also need to enable some entitlements within your app for iOS, this may also be true for Android. On iOS, this will be enabling the Associated Domains entitlement alongside an entry for webcredentials:yourdomain.com
The documentation is pretty good to go through to give an understanding on what needs to be done in order to achieve Universal Links
https://developer.apple.com/library/archive/documentation/General/Conceptual/AppSearch/UniversalLinks.html
https://developer.android.com/training/app-links/verify-site-associations
Examples:
iOS - https://stackoverflow.com/.well-known/apple-app-site-association
Android - https://stackoverflow.com/.well-known/assetlinks.json

React native: TypeError: null is not an object (evaluating 'SplashScreen.preventAutoHide')

My react native app was working just fine before I used expo eject. I ejected it because I now intend to build and release the app to the ios app store. As soon as I attempt to start the ejected app using react-native run-ios after it's been ejected I get the exception below.
Please could someone help to understand what's causing this issue and how to tackle it?
react Native versions as follows:
react-native-cli: 2.0.1
react-native: 0.61.5
TypeError: null is not an object (evaluating 'SplashScreen.preventAutoHide')
This error is located at:
in AppLoading (at AppLoading.js:52)
in AppLoading (at App.js:464)
in App (at renderApplication.js:40)
in RCTView (at AppContainer.js:101)
in RCTView (at AppContainer.js:119)
in AppContainer (at renderApplication.js:39)
preventAutoHide
SplashScreen.js:4:21
AppLoading#constructor
AppLoadingNativeWrapper.js:6:8
renderRoot
[native code]:0
runRootCallback
[native code]:0
renderApplication
renderApplication.js:52:52
runnables.appKey.run
AppRegistry.js:116:10
runApplication
AppRegistry.js:197:26
callFunctionReturnFlushedQueue
[native code]:0
The AppLoading component is not available in the bare workflow. As #gaurav-roy said you have to refactor your code.
Install the expo-splash-screen package with npm install expo-splash-screen
Add a splash-screen to your Android and iOS projects. Run npm run expo-splash-screen --help and follow the instructions of this CLI tool. (Because of a bug you might have to run the command again with the -p "ios" flag if it only adds the SplashScreen for Android after running it.
Change your code inside App.tsx in a similar way as in this example.
If you're working with hooks you probably want to add an useEffect
hook with an empty dependency list which runs an async function. Here an example of how it could be done:
const App = (props: Props) => {
const [isLoadingComplete, setLoadingComplete] = useState(false);
const init = async () => {
try {
// Keep on showing the SlashScreen
await SplashScreen.preventAutoHideAsync();
await loadResourcesAsync();
} catch (e) {
console.warn(e);
} finally {
setLoadingComplete(true);
// Hiding the SplashScreen
await SplashScreen.hideAsync();
}
useEffect(() => {
init();
}, []);
const renderApp = () => {
if (!isLoadingComplete && !props.skipLoadingScreen) {
return null;
}
return (
<Main />
);
};
return <StoreProvider>{renderApp()}</StoreProvider>;
}
As its evident from docs , SplashScreen is an inbuilt api for expo apps, and since you ejected it , it throws an error since it cant be used.
You can see this in the docs expo splashscreen .
First you should download npm i expo-splash-screen
And then change your import statement to :
import * as SplashScreen from 'expo-splash-screen';
Hope it helps. feel free for doubts
After looking through this SO page and then digging into some links, especially this expo page where they kind of provide a solution for this, I was able to get my app running after about 3 hours of struggle. They haven't added any functional component example, so I am sharing my code below in case someone came here looking for the solution.
import { Asset } from "expo-asset";
import * as Font from "expo-font";
import React, { useState, useEffect } from "react";
import { Platform, StatusBar, StyleSheet, View } from "react-native";
import { Ionicons } from "#expo/vector-icons";
import * as SplashScreen from 'expo-splash-screen';
import AppNavigator from "./navigation/AppNavigator";
export default props => {
const [isLoadingComplete, setLoadingComplete] = useState(false);
const theme = {
...DefaultTheme,
roundness: 2,
colors: {
...DefaultTheme.colors,
primary: "#E4002B",
accent: "#E4002B",
},
};
useEffect(() => {
async function asyncTasks() {
try {
await SplashScreen.preventAutoHideAsync();
} catch (e) {
console.warn(e);
}
await loadResourcesAsync()
setLoadingComplete(true);
}
asyncTasks()
}, []);
return (
!isLoadingComplete && !props.skipLoadingScreen ? null :
<View style={styles.container}>
{Platform.OS === "ios" && <StatusBar barStyle="default" />}
<AppNavigator />
</View>
);
}
async function loadResourcesAsync() {
await Promise.all([
Asset.loadAsync([
require("./assets/images/logo.png") // Load your resources here (if any)
]),
Font.loadAsync({
// You can remove this if you are not loading any fonts
"space-mono": require("./assets/fonts/SpaceMono-Regular.ttf"),
}),
]);
await SplashScreen.hideAsync();
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
},
});
This solved it for me for an ejected expo app. Looks like expo was referencing it wrongly.
https://github.com/expo/expo/issues/7718#issuecomment-610508510
What worked for me was updating node_modules/expo/build/launch/splashScreen.js to the following as suggested by adamsolomon1986 in the repo (issue #7718):
import { NativeModules } from 'react-native';
import* as SplashScreen from 'expo-splash-screen'
export function preventAutoHide() {
if (SplashScreen.preventAutoHide) {
SplashScreen.preventAutoHide();
}
}
export function hide() {
if (SplashScreen.hide) {
SplashScreen.hide();
}
}
//# sourceMappingURL=SplashScreen.js.map

Resources