Create React apps using Kotlin and External - javascript

I'm trying to wrap this simple API: https://github.com/github-tools/github, just for study purpose. So, I created this external classes:
package index
import com.github.jesty.githubapi.Result
import com.github.jesty.githubapi.User
import kotlin.js.Promise
external class GitHub(user: User) {
fun getUser(): GHUser
}
external class GHUser {
fun listStarredRepos(): Promise<Result>
}
In a simple KotlinJS project everything is ok, but when I try to use in a project created with Create React Kotlin App I have the error below:
ReferenceError: GitHub is not defined

Just solved, I need to annotate the external class with #JsModule("github-api"):
package com.github.jesty.githubapi
import kotlin.js.Promise
#JsModule("github-api")
external class GitHub(user: User) {
fun getUser(): GHUser
}
#JsModule("github-api")
external class GHUser {
fun listStarredRepos(): Promise<Result>
}

Related

Should my function be in /mixins or /plugins?

If I have an external package that I'm using, for instance, vue-js-modal. And I import it in /plugins/vue-js-modal.js:
import Vue from 'vue'
import VModal from 'vue-js-modal'
Vue.use(VModal)
Now let's say I have a function that uses vue-js-modal that I want to use in a bunch of different components below:
function showHideModal(showModalName = null, hideModalName = null) {
if (hideModalName) {
this.$modal.hide(hideModalName)
}
if (showModalName) {
this.$modal.show(showModalName)
}
}
Should this function be stored in /plugins/vue-js-modal.js or should it be put into it's own /mixins/showHideModal.js file? Which is more appropriate here and why?
According to plugins document in Nuxt.js website:
Nuxt.js allows you to define JavaScript plugins to be run before instantiating the root Vue.js Application. This is especially helpful when using Vue libraries, external modules or your own plugins.
So if you want to use external modules it's better to have them stored/initiated in plugins, Whereas if you want to have reusable functions for components, you use Mixins which then "Mix" the function and the component together.
Read more about mixins here.

TypeScript declarations for JavaScript module

I recently started using a Node library called bpmn-js (npmjs.com).
It is written in JavaScript, and I'd like to have typings. Thus, I've began reading about d.ts files.
I created this folder structure
webapp
#types
bpmn-js
index.d.ts
With a simple content
declare module 'bpmn-js' {
export class BpmnJS {
constructor();
}
}
But this doesn't seem to work.
"Before" typings, I was able to import the object I needed using
import BpmnJS from 'bpmn-js';
And I was able to instantiate it using
new BpmnJS();
How can I get the typings file to be recognized?
I'm using WebStorm 2019.1.*.
Pretty simple, I was missing export default, or better, the default part.
declare module 'bpmn-js' {
export default class BpmnJS {
constructor(param?: { container: string });
...
}
}
Now this works too
import BpmnJS from 'bpmn-js';

How to import node module in React-Kotlin?

I created an app using the create-react-kotlin-app command and it loads in Chrome fine. I added the React Material UI package via NPM and that was successful. Now how do I use the Material UI module in my component?
Normally with JavaScript, it's a simple import Button from '#material-ui/core/Button' at the top of the component's file, but Kotlin doesn't like that.
How do I translate that line to Kotlin? I am not using Gradle.
I have been struggling with this problem for days now. I came up with the following solution. First we will see multiple ways to declare external modules, then I will show how to use them
.
Consider the following javascript code
import Button from '#material-ui/core/Button' // this means button is exported as default
This will be imported in kotlin in the following ways
Button.kt
#file:JsModule("#material-ui/core/Button")
#file:JsNonModule
package com.mypckage.mykillerapp
import react.Component
import react.RProps
import react.RState
import react.ReactElement
#JsName("default") // because it was exported as default
external val Button : RClass<RProps>
// way 2
#JsName("default")
external class Button : Component<RProps,RState> {
override fun render(): ReactElement?
}
But again, if the statement intend for kotlin has to match the javascript import statement bellow,
import { Button } from "material-ui" // not exported as default
We use the following approach: Button.kt
#file:JsModule("material-ui")
#file:JsNonModule
package com.mypckage.mykillerapp
import react.Component
import react.RProps
import react.RState
import react.ReactElement
// way 1
#JsName("Button") // because it was exported as default
external val Button : RClass<RProps>
// way 2
#JsName("Button")
external class Button : Component<RProps,RState> {
override fun render(): ReactElement?
}
once you have declared on how to use your components, you can just use them as follows:
//way 1:
fun RBuilder.render() {
div {
Button {
attrs.asDynamic().className="submit-button"
+"Submit"
}
}
}
//way 2:
fun RBuilder.render() {
div {
child(Button::class) {
attrs.asDynamic().className="submit-button"
+"Submit"
}
}
}
great. you have imported your component. But until then your are not relying on kotlin type safety and even code completion, to achieve that, you have to go to extra length
as shown bellow
external interface ButtonProps: RProps {
var className : String
var onClick: (Event?)->Unit
var color: String
// . . .
var href: String
}
then go ahead and declare your button as
#JsModule("#material-ui/core/Button")
#JsNonModule
#JsName("default") // because it was exported as default
external val Button : RClass<ButtonProps>
and you can now use it with type safety and code completion as shown bellow
fun RBuilder.render() {
div {
Button {
attrs {
className = "submit-button"
onClick = {
window.alert("Vois La")
}
}
+"Submit"
}
}
}
Hope this helps. Happy coding
EDIT:
There is a community wrapper for material-ui components here
HINT:
Use way 1, as you can see, it is less verbose
The Kotlin way for importing dependencies is close to standard JS importing:
import React from 'react';
export function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
Based on Creating a simple React component with Kotlin.
package hello
import react.*
import react.dom.*
fun RBuilder.hello(name: String) {
h1 {
+"Hello, $name"
}
}
Usually (as Kotlin is Java-based) it uses Gradle tool to handle dependencies:
// part of build.gradle
kotlinFrontend {
// ...
npm {
// ...
dependency("react")
dependency("react-dom")
dependency("react-router")
dependency("react-markdown")
devDependency("css-loader")
devDependency("babel-core")
// ...
}
And are referenced like above:
HomeView.kt:
// https://github.com/Kotlin/kotlin-fullstack-sample/blob/master/frontend/src/org/jetbrains/demo/thinkter/HomeView.kt
import kotlinx.html.*
import org.jetbrains.demo.thinkter.model.*
import react.*
import react.dom.*
import kotlinx.coroutines.experimental.launch
ReactMarkdown.kt:
// https://github.com/Kotlin/kotlin-fullstack-sample/blob/master/frontend/src/org/jetbrains/demo/thinkter/ReactMarkdown.kt
package org.jetbrains.demo.thinkter
import react.*
private val ReactMarkdown: dynamic = runtime.wrappers.require("react-markdown")
Based on: kotlin-fullstack-sample
In create-react-kotlin-app additionally faced the possibility of importing with #JsModule() annotation, while dependencies managing is handled in standard way via package.json:
// src/logo/Logo.kt (outcome of creating new app)
package logo
import react.*
import react.dom.*
import kotlinext.js.*
import kotlinx.html.style
#JsModule("src/logo/react.svg")
external val reactLogo: dynamic
#JsModule("src/logo/kotlin.svg")
external val kotlinLogo: dynamic
And can be also successfully used for JS libraries importing.
Another way would be to use kotlinext.js.*:
// index/index.kt
import kotlinext.js.*
fun main(args: Array<String>) {
requireAll(require.context("src", true, js("/\\.css$/")))
// ...
}
Which provides also require(module: String) function.

Custom Uppy Plugin

I'm trying to make a custom Uppy React plugin but I'm getting the following error
'TypeError: Cannot call a class as a function'
import Plugin from 'uppy/src/core/Plugin';
export default class DropZone extends Plugin {
}
I am then consuming the component as follows:
import React from 'react';
import Uppy from 'uppy/lib/core/Core';
import DropZone from '../DropZone';
const uppy = new Uppy({ debug: true });
uppy.run();
export default class FileManager extends React.Component {
render() {
return (<DropZone uppy={uppy} />);
}
}
I've cut down the code for simplicity. I looked at the implementation of the uppy DragDrop plugin and followed its implement but still get the same error.
Has anyone had experience writing a react plugin for Uppy? as I'm lost as to how I can resolve this error.
Thanks
I've successfully created a plugin using the following import statement:
import { Uppy, Plugin, PluginOptions, UppyFile } from "#uppy/core";
It's not clear from your question whether you're using the npm package or have downloaded manually, but in my case I installed Uppy using:
npm i #uppy/core
First of all, in your "DropZone" plugin, you'll need to implement at least the install() and uninstall() methods (those get called by uppy).
Second, if you want to tell uppy to use your plugin, you need to do something like:
const uppy =
new Uppy({ debug: true })
.use(DropZone)
.run();
I suggest simply looking at the source code for other plugins to understand how they work, there are different kinds of Plugins - Providers for files management, GUI plugins for display in the Dashboard, etc...
Hope this helps

How to import Parse JS sdk into ionic 2 beta

am trying to import JS sdk into ionic 2 app, but i keep getting parse is undefined
In ionic 1.x ,parse js sdk is loaded via
<script ..parse.js </script>
and exposed as a global var, how do import in ionic 2 ,am using the npm module ,and tried
import * as parse from 'parse'
Do npm install parse --save in your project directory
Then import parse using
import { Parse } from 'parse';
It is better to create an parse provider.
You can use this starter template as a guide. It is a simple GameScores application in ionic to get you started.
https://github.com/Reinsys/Ionic-Parse
It shows how to create and read data from parse server. I also includes paging with ion-infinite-scroll scrolling.
After searching for a solution I came up with my own.
After installing the package and the typings, I opened the index.js of the node-module ionic-gulp-scripts-copy and added 'node_modules/parse/dist/parse.min.js' to the defaultSrc array.
Then, in my index.html, I included the script above the cordova.js.
Now I just need to declare var Parse: any; in every Component I want to use the SDK in.
For example, in my app.ts:
import {Component} from '#angular/core';
import {Platform, ionicBootstrap} from 'ionic-angular';
import {StatusBar} from 'ionic-native';
import {TabsPage} from './pages/tabs/tabs';
import{LoginPage} from './pages/login/login';
declare var Parse: any;
#Component({
template: '<ion-nav [root]="rootPage"></ion-nav>',
})
export class MyApp {
private rootPage: any;
private parse;
constructor(private platform: Platform) {
//this.rootPage = TabsPage;
this.rootPage = LoginPage;
platform.ready().then(() => {
console.log("Platform ready!");
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
StatusBar.styleDefault();
Parse.initialize('myStartUp', 'someKey');
Parse.serverURL = 'http://localhost:1337/parse';
});
}
}
ionicBootstrap(MyApp);
I do not think this is the way it should be used, but in the end I can use the SDK pretty easy and without much lines of implementation code.

Categories

Resources