Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/soiu/pyrex
React bindings in RPython/RapydScript/Javascripthon
https://github.com/soiu/pyrex
Last synced: about 1 month ago
JSON representation
React bindings in RPython/RapydScript/Javascripthon
- Host: GitHub
- URL: https://github.com/soiu/pyrex
- Owner: soIu
- License: mit
- Created: 2020-10-02T03:47:03.000Z (over 4 years ago)
- Default Branch: main
- Last Pushed: 2024-09-05T00:09:08.000Z (5 months ago)
- Last Synced: 2024-10-16T00:31:51.854Z (3 months ago)
- Language: Python
- Homepage: https://solu.js.org
- Size: 34.2 KB
- Stars: 0
- Watchers: 2
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Pyrex
Statically compiled React bindings in RPython, or a loosely transpiled in RapydScript/Javascripthon# Comparison
Here is a few comparison with Flutter widgets and React Components (JSX):```dart
//Flutterimport 'package:flutter/material.dart';
class MyAppBar extends StatelessWidget {
MyAppBar({required this.title});// Fields in a Widget subclass are always marked "final".
final Widget title;
@override
Widget build(BuildContext context) {
return Container(
height: 56.0, // in logical pixels
padding: const EdgeInsets.symmetric(horizontal: 8.0),
decoration: BoxDecoration(color: Colors.blue[500]),
// Row is a horizontal, linear layout.
child: Row(
// is the type of items in the list.
children: [
IconButton(
icon: Icon(Icons.menu),
tooltip: 'Navigation menu',
onPressed: null, // null disables the button
),
// Expanded expands its child
// to fill the available space.
Expanded(
child: title,
),
IconButton(
icon: Icon(Icons.search),
tooltip: 'Search',
onPressed: null,
),
],
),
);
}
}
``````javascript
//Reactclass Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}componentWillUnmount() {
clearInterval(this.timerID);
}tick() {
this.setState({
date: new Date()
});
}render() {
return (
Hello, world!
It is {this.state.date.toLocaleTimeString()}.
);
}
}
``````python
#Pyrex (in RPython)from react import Component, Text
from react.components import Typography, IconButton, MoreVertical, Menu, MenuItem
from javascript import JSON, Object, function, types@Component(path='Module.Admin.AppBar')
class AppBar:
elevation = types.int@Component
class span:
className = types.ref@Component
class div: passclass Props: pass
@Component(Props=Props)
class Submenu:@function
def onClick(setElement, event):
setElement.call(event['currentTarget'].toRef())@function
def onClose(setElement):
setElement.call(None)@function
def onMenu(setElement, menu):
setElement.call(None)
#Object.get('window', 'location')['hash'] = '#/' + menu['model'].toString()def render(self):
menu = Object.get('Module')['orm_active_menu']
if not menu.toBoolean() or not menu['childs']['length'].toInteger(): return div()
id = 'solu-appbar-submenu'
states = Object.get('window', 'React', 'useState').call(None)
element, setElement = states['0'], states['1'] #.toFunction()
return (
div ([
IconButton (props={'aria-controls': id, 'aria-haspopup': 'true', 'color': 'inherit'}, onClick=Object.createClosure(self.onClick, setElement).toRef(), children=[
MoreVertical ()
]),
Menu (id=id, anchorEl=element.toRef(), keepMounted=True, open=element.toBoolean(), onClose=Object.createClosure(self.onClose, setElement).toRef(), children=[
MenuItem (props={'component': 'a', 'href': '#/' + child['model'].toString()}, onClick=Object.createClosure(self.onMenu, setElement, child).toRef(), children=[
Text (child['string'].toString())
])
for child in menu['childs'].toArray()])
])
)
```# Using for RapydScript/Javascripthon or even on pure JS/TS (without JSX)
There's a RapydScript and ~~Transcrypt~~ Javascripthon version that our team use to develop React Native apps. Both uses babel plugins ([RapydScript](https://github.com/soIu/rapydscript-plugin)/[Javascripthon](https://github.com/soIu/javascripthon-plugin)) to load Python code in a project that use babel as the loader.```python
React = require('react')
Native = require('react-native')
StyleSheet = Native.StyleSheetView, Text, StatusBar = require('pyrex').component(require('pyrex').kwargs(require('react-native'), 'View', 'Text'), require('expo-status-bar').StatusBar)
styles = StyleSheet.create({
'container': {
'flex': 1,
'backgroundColor': "#fff",
'alignItems': 'center',
'justifyContent': 'center',
}
})#RapydScript supports inverted order of kwargs and args
def App():
return (
View (style=styles.container,
Text ('Hello, this is from RapydScript!'),
)
)
#Javascripthon and Transcrypt version, closer to RPython
def App():
return (
View (style=styles.container, children=[
Text ('Hello, this is from Transcrypt!'),
])
)module.exports = App
```You can also use it from JS/TS without JSX, but it'll be more awkward
```javascript
//Bunch of importing things and other stuff...class App extends React.Component {
async stream() {
try {
if (!this.recorder) return;
if (this.recorder.state === 'inactive') this.recorder.start();
await sleep(0);
const blob = await this.recorder.requestData();
return this.stream();
}
catch (error) {
console.error(error);
return this.stream();
}
}
unmutePlayers() {
for (let user in this.state.users) this.state.users[user].ogvPlayer && (this.state.users[user].ogvPlayer.muted = this.state.unmute);
}
render () {
const style = this.state.width > this.state.height ? {maxWidth: Object.keys(this.state.users).length > 0 ? 'calc(80vw - 24px)' : '100vw'} : {height: 'calc(100vh - 75px)'};
if (!this.state.username) return div();
return (
div ({style: {display: 'flex'}},
div ({style: {width: '20vw', margin: '2px'}}, ...Object.keys(this.state.users).map((user) =>
div ({style: {}}, !this.state.users[user].Player ?
video ({onProgress, onError: (event) => socket.emit('restart', user) && (delete self.state.users[user]) && self.setState(self.state), onClick, style: {'width': '20vw'}, autoplay: true, muted: !this.state.unmute, src: this.state.users[user].url}) :
this.state.users[user].Player(),
p (this.state.users[user].name)
)), Object.keys(this.state.users).length > 0 &&
div ( //{style: {display: 'none'}},
input ({type: 'checkbox', name: 'mute', checked: !this.state.unmute, onClick: () => self.unmutePlayers() || self.setState({unmute: !this.state.unmute})}),
label ({for: 'mute'}, 'Mute')
)
),
div ({style: {margin: '2px'}},
(this.recorder && this.recorder.video) ?
div ({ref: (ref) => ref && !ref.children.length && (this.recorder.video.onclick = onClick) && (this.recorder.video.onloadedmetadata = () => self.stream()) && ref.appendChild(this.recorder.video) && Object.keys(style).forEach(key => this.recorder.video.style[key] = style[key])}) :
video ({onClick, style, muted: true, ref: (ref) => ref && (!ref.srcObject) && (ref.srcObject = console.log(self) || self.state.stream) && (ref.onloadedmetadata = () => ref.play() && self.stream())}),
p (this.state.username)
)
)
)
}
}
```