import abcjs from 'abcjs';
export default class MusicScore extends Component {
constructor(props) {
super(props);
this.state={
data: this.props.navigation.getParam('abctune'),
}
}
render(){
data = this.state.data;
renderScore = () => {
abcjs.renderAbc('notation', data);
}
return(
<WebView
source={
{html: `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="notation"></div>
</body>
</html>
`}
}
domStorageEnabled
javaScriptEnabled
injectJavaScript={renderScore}
/>
);
}
}
The code above produces the following
OUTPUT
dev enviornment:
OS: Windows 10
node: v12.10.0
Android Studio: 3.5.2
installed via package manager:
npm install --save abcjs
Unfortunately, you need a DOM set up. I haven't used react-native, so I'm not sure if this will work:
What works for me when using a SSR package (like Nuxt) is to change the import to later in the process. So:
mounted() {
const abcjs = require('abcjs');
}
Is there something analogous in react-native?
Related
so im trying to create a react webcomponent. I wrap it and on VSCode looks fine, but when I'm trying to load it, it gives me the error: Unexpected token '<' on the line:
ReactDOM.render(<Counter/>, mountPoint);
Does anyone know why and how to fix it? thanks
This is my WebComponent:
import React from 'react';
import * as ReactDOM from 'react-dom';
import Counter from './counter';
class CounterWC extends HTMLElement {
connectedCallback() {
// Create a ShadowDOM
const root = this.attachShadow({ mode: 'open' });
// Create a mount element
const mountPoint = document.createElement('div');
root.appendChild(mountPoint);
// You can directly use shadow root as a mount point
ReactDOM.render(<Counter/>, mountPoint);
}
}
customElements.define('counter-wc', CounterWC)
And this is my html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-9" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<h1>React webcomponent:</h1>
<counter-wc></counter-wc>
<script type="module" src="./counterWC.js"></script>
</body>
</html>
Re: comments
The fact that you name your file *.js doesn't mean it is JavaScript
ReactDOM.render(<Counter/>, mountPoint); is JSX, not JavaScript, it needs to be converted in a Build step to JavaScript.
Or do not use React at all:
class CounterWC extends HTMLElement {
constructor(){
super()
.attachShadow({mode: 'open'})
.append(this.div = document.createElement('div'));
}
connectedCallback() {
this.div.innerHTML = `Am I a counter?`;
}
}
customElements.define('counter-wc', CounterWC);
<counter-wc></counter-wc>
Issue:
I have a laravel 9 app builded with vue3 , inertia-laravel , inertiajs and laravel-vite , it works perfetct on PC but when I try to open it in mobile device It show a blank page without any console log.
NB : when I toggle device toolbar to mobile in a navigator it works correctly but in real mobile no ( I tested on different navigators)
I can't fix this issue come from inertiajs\inertia-vue3 or inertiajs/inertia-laravel
When I render a blade view it works, just when I render inertia object
Versions:
inertiajs/inertia-laravel version: 0.6.3
#inertiajs/inertia version: 0.11.0
#inertiajs/inertia-vue3 version: 0.6.0
Codes:
web.php:
Route::get('/', function() {
return Inertia::render('WelcomeView');
});
app.js
import './bootstrap';
import '../css/main.css'
import { createPinia } from 'pinia'
import { useStyleStore } from '#/Stores/style.js'
import { darkModeKey } from '#/config.js'
import { createApp, h } from 'vue'
import { createInertiaApp } from '#inertiajs/inertia-vue3'
import { InertiaProgress } from '#inertiajs/progress'
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers'
import { ZiggyVue } from '../../vendor/tightenco/ziggy/dist/vue.m'
import Notifications from 'notiwind'
import * as ConfirmDialog from 'vuejs-confirm-dialog'
const appName = window.document.getElementsByTagName('title')[0]?.innerText || 'Laravel'
const pinia = createPinia()
createInertiaApp({
title: (title) => `${title} - ${appName}`,
resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue')),
setup({ el, app, props, plugin }) {
return createApp({ render: () => h(app, props) })
.use(plugin)
.use(pinia)
.use(Notifications)
.use(ConfirmDialog)
.use(ZiggyVue, Ziggy)
.mount(el);
},
});
InertiaProgress.init({
color: '#5136a8',
showSpinner:true
})
const styleStore = useStyleStore(pinia)
/* App style */
//styleStore.setStyle(localStorage[styleKey] ?? 'basic')
styleStore.setStyle()
/* Dark mode */
if ((!localStorage[darkModeKey] && window.matchMedia('(prefers-color-scheme: dark)').matches) || localStorage[darkModeKey] === '1') {
styleStore.setDarkMode(true)
}
WelcomeVue.vue (under pages folder) :
<template>
<div>
hellow world
</div>
</template>
and app.blade.php :
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{!! csrf_token() !!}" />
<title inertia>{{ config('app.name', 'Laravel') }}</title>
<!-- Fonts -->
<!-- Scripts -->
#routes
#vite('resources/js/app.js')
#inertiaHead
</head>
<body class="font-sans antialiased">
#inertia
</body>
</html>
I have a react app embedded in a webpage and the app should start with parameters it gets from the page. Now I pass the parameters on index.HTML file in a div but the problem is if the parameters are updated the app won't notice the changes.
index.HTML
<html>
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="Web site created using create-react-app" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>Sales flow</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div class="staringId" packageId="2" itemId="5" channelId="9"></div>
</body>
</html>
index.js
import './index.scss';
import App from './App'
const div = document.querySelector('.staringId')
ReactDOM.render(
<App domElement={div} />,
div
);
App.js
const App = ({ domElement }) => {
const package = domElement.getAttribute("packageId")
const item = domElement.getAttribute("itemId")
const channel = domElement.getAttribute("channelId")
const [data, setData] = useState({
packageId: '',
itemId: '',
channelId: '',
})
useEffect(() => {
setSelData({
packageId: package,
itemId: item,
channelId: channel,
})
}, [package, item, channel])
}
javascript file to embed the app
<div class="staringId" packageId="2" itemId="5" channelId="9"</div>
<script src="./dist/runtime-main.8d32315e.js"></script>
<script src="./dist/2.4c89be1e.chunk.js"></script>
<script src="./dist/main.a41deb26.chunk.js"></script>
My question is how I can pass some external parameters to the app and update(restart) the app after each update to the parameters.
The idea is to have only one top-level component in your HTML, and whatever parameters(props) you are trying to pass sit on the other components within the top-level . Following is the rough structure how it would look like.
index.html
<html>
<body>
<div id="app"></div>
</body>
</html>
index.js
import './index.scss';
import App from './App'
ReactDOM.render(
<App packageId="2" itemId="5" channelId="9" />, // you can choose to dynamically pass the value depends on what you get from page
document.getElementById("app")
);
App.js
const App = ( props ) => {
// props.packageId and etc are available here
// you can then choose to render it with these props value
return (
<MyOtherComponent otherProps="ifany" />
);
}
export default App;
I have a simple index.html file. It includes the Vue JS application and has the following code.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Test</title>
<script>
const foo = {
bar: 100
};
</script>
<script src="main.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
Here's how the Vue JS app looks like.
main.js
import Vue from "vue"
import App from "./App.vue"
Vue.config.productionTip = false
new Vue({
render: h => h(App)
}).$mount("#app")
App.vue
<template>
<div>
{{ config.bar }}
</div>
</template>
<script>
export default {
props: {
config: {
type: Object,
default: () => {},
},
}
}
</script>
I simply want to pass the const foo variable into the App.vue file. I already tried to pass it as a prop to the <div id="app" :config="foo"></div>, however it did throw an undefined error in App.vue.
How can I pass a JS variable from HTML into a Vue Application and to the component?
I am aiming to use a Vanilla JavaScript package in a more sophisticated React app to build additional logic around the JavaScript package.
The JavaScript library is LabelStudio and docs can be found here: https://github.com/heartexlabs/label-studio-frontend
However, when I try to import the LabelStudio I get an error saying Module not found: Can't resolve 'label-studio' , as described here https://github.com/heartexlabs/label-studio-frontend/issues/55
Since my understanding of frontend code is limited, I am not sure whether this is something the developers did not expected users to do and just wanted them to use the entire library and customized instead of using the library as a component. My idea was to use the library as in the vanilla javascript example here:
<!-- Include Label Studio stylesheet -->
<link href="https://unpkg.com/label-studio#0.7.1/build/static/css/main.0a1ce8ac.css" rel="stylesheet">
<!-- Create the Label Studio container -->
<div id="label-studio"></div>
<!-- Include the Label Studio library -->
<script src="https://unpkg.com/label-studio#0.7.1/build/static/js/main.3ee35cc9.js"></script>
<!-- Initialize Label Studio -->
<script>
var labelStudio = new LabelStudio('label-studio', {
config: `
<View>
<Image name="img" value="$image"></Image>
<RectangleLabels name="tag" toName="img">
<Label value="Hello"></Label>
<Label value="World"></Label>
</RectangleLabels>
</View>
`,
interfaces: [
"panel",
"update",
"controls",
"side-column",
"completions:menu",
"completions:add-new",
"completions:delete",
"predictions:menu",
],
user: {
pk: 1,
firstName: "James",
lastName: "Dean"
},
task: {
completions: [],
predictions: [],
id: 1,
data: {
image: "https://htx-misc.s3.amazonaws.com/opensource/label-studio/examples/images/nick-owuor-astro-nic-visuals-wDifg5xc9Z4-unsplash.jpg"
}
},
onLabelStudioLoad: function(LS) {
var c = LS.completionStore.addCompletion({
userGenerate: true
});
LS.completionStore.selectCompletion(c.id);
}
});
</script>
How can I make use of the above code in a React Component to facilitate dynamic data loading and use of state to customize the functions?
I don't have a solution making the npm module label-studio to work. I tried importing the dist file instead, but it errors
Expected an assignment or function call and instead saw an expression
So here's a workaround until the maintainers address this.
Copy the JS file from build/static/js, then place it in a script in the public folder on index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="Web site created using create-react-app" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script src="%Your_Path_To_Label-Studio%/main.js"></script>
</body>
</html>
The script file defines a global function variable, so you can access it in React by using the window object. The useEffect hook is to make sure the initialization is only run once.
import React, { useEffect, useRef } from "react";
function App() {
const LabelStudio = window.LabelStudio; // label-studio script stores the api globally, similar to how jQuery does
const myLabelStudioRef = useRef(null); // store it and then pass it other components
useEffect(() => {
myLabelStudioRef.current = new LabelStudio("label-studio", {
config: `
<View>
<Image name="img" value="$image"></Image>
<RectangleLabels name="tag" toName="img">
<Label value="Hello"></Label>
<Label value="World"></Label>
</RectangleLabels>
</View>
`,
interfaces: [
"panel",
"update",
"controls",
"side-column",
"completions:menu",
"completions:add-new",
"completions:delete",
"predictions:menu",
],
user: {
pk: 1,
firstName: "James",
lastName: "Dean",
},
task: {
completions: [],
predictions: [],
id: 1,
data: {
image:
"https://htx-misc.s3.amazonaws.com/opensource/label-studio/examples/images/nick-owuor-astro-nic-visuals-wDifg5xc9Z4-unsplash.jpg",
},
},
onLabelStudioLoad: function (LS) {
var c = LS.completionStore.addCompletion({
userGenerate: true,
});
LS.completionStore.selectCompletion(c.id);
},
});
}, []);
return (
<div className="App">
{/* Use Label Studio container */}
<div id="label-studio"></div>
</div>
);
}
export default App;
As far as storing the new instance of LabelStudio, there's many ways to go about it. You can store it as variable on the root component using either useState or useRef hooks and then pass it to child components. If you want to avoid manually passing variable down the component tree, then you need a state manager such as React Context or Redux.
This is the basic setup using LabelStudio as a module in a React component.
yarn add #heartexlabs/label-studio
import LabelStudio from '#heartexlabs/label-studio'
import { useEffect } from 'react'
import '#heartexlabs/label-studio/build/static/css/main.css'
const ReactLabelStudio = () => {
useEffect(() => {
new LabelStudio('label-studio', {
config: {...},
interfaces: [...],
user: {...},
task: {...},
onLabelStudioLoad: function(LS) {
const c = LS.annotationStore.addAnnotation({
userGenerate: true,
});
LS.annotationStore.selectAnnotation(c.id);
}
})
}, [])
return <div id="label-studio" />
}
export default ReactLabelStudio