instawork / hyperview Goto Github PK
View Code? Open in Web Editor NEWServer-driven mobile apps with React Native
Home Page: https://hyperview.org
License: MIT License
Server-driven mobile apps with React Native
Home Page: https://hyperview.org
License: MIT License
Hi @adamstep, sorry to disrupt you. We wonder if there are any plan or proposal to support the below feature:
[Feature] add the following triggers to the 'text-field' and 'text-area' component:
We found that in acutal work we often need to verify the correctness of the fields filled by the user, or have some linkage effects between fields. These situations all require timely feedback to the uses.
According to my understanding, now the only way to achieve this function is to encapsulate the 'Form' component of React Native by 'custom elements ' feature. but this method will be very inflexible, because the entire page would be a react native component, instead of a hyperview page.
In view of this, if hyperview can support 'focus' and 'blur' trigger for text-field component, there would be more flexibility to deal with the above cases.
Or would you have some other plans or suggestions on above requirements ?
Looking forward to reply, and thank you so much.
btw: now I am trying to implement it in my hyperview branch.
One of the problems with hyperview is 0 feedback from editor while writing code. This ends up creating a need to always keep on checking with existing XML files and the docs.
Ideally there should be some auto-complete feedback from the editor. I'm using VSCode but I guess grammar would be similar for all editors. Integrations and extensions might differ.
For example, this is how it works in react native code:
How easy is it to get a Hyperview app approved in the iOS App Store?
Since, as I understand it, the content of the app which is rendered is entirely controlled over-the-wire at runtime, the App Store reviewers won't know that what they are reviewing might be entirely changed immediately afterwards?
Or does Hyperview bundle and ship the views within the pre-downloaded app? Then merely allow the server to control navigation and select which of the pre-bundled views/components that are shown? That would be in line with Server-Driven Rendering, if I understand it correctly.
Hi,
lately I got an exception for hyperview text-field, but this error is a random error, it did NOT happen every time
** exception detailed **
open a hyperview form, press on the text-field, when the text-field is focused, it will throw an exception: TypeError null is not an object (evaluating 'o.isFocused'), please see this video for reference: text-field error screen capture video
to reproduce the error:
with above these steps 10% chance this error would happen
env:
Do you have any idea, what is going wrong here or how to avoid this error ?
please note that: the exception is catched by react-native-exception-handler, using below code:.
import { setJSExceptionHandler } from "react-native-exception-handler";
const errorHandler = (e, isFatal) => {
if (isFatal) {
Alert.alert(
"Unexpected error occurred",
`
Error: ${isFatal ? "Fatal:" : ""} ${e.name} ${e.message}
`,
[
{
text: "OK",
onPress: () => {},
},
]
);
} else {
// console.log("error:", e);
}
};
setJSExceptionHandler(errorHandler, true);
this is the hyperview page xml:
<doc lang="en" xmlns="https://hyperview.org/hyperview" xmlns:th="http://www.thymeleaf.org">
<screen>
<body style="Body Bg-White">
<header style="Header">
<text action="back" href="#" style="Header__Back">
<
<text style="Header__Title">
<![CDATA[ ]]>
Achieve My Goal
</text>
</text>
</header>
<view style="M-20" scroll="true">
<text style="Text2">this is the plan.</text>
<text style="Text1 M-T-20">Account type</text>
<form id="allocateSavingForm">
<select-single name="tab" style="Tabs">
<option id="atAccountTypeBankAccounts" value="users" style="Tab" selected="true">
<text style="Tab__Label">Bank accounts</text>
<behavior trigger="select" action="set-value" new-value="BANKSAVE" target="accountType"/>
</option>
<option id="atAccountTypeCashSavings" value="groups" style="Tab">
<text style="Tab__Label">Cash savings</text>
<behavior trigger="select" action="set-value" new-value="SAVINGS" target="accountType"/>
</option>
<option id="atAccountTypeEWallet" value="tab3" style="Tab">
<text style="Tab__Label">E-Wallet</text>
<behavior trigger="select" action="set-value" new-value="EWALLETSAVE" target="accountType"/>
</option>
</select-single>
<text style="Text1 M-T-20">
Account name
<text style="Main-Red">*</text>
</text>
<text-field id="atAccountName" placeholder="Please input account name" placeholderTextColor="#8D9494" name="accountName" style="input" value="My account" />
<text style="Text1 M-T-20">
My balance for this goal
<text style="Main-Red">*</text>
</text>
<text-field id="atAccountBalance" placeholder="Please input balance" placeholderTextColor="#8D9494" mask="$ **********************" keyboard-type="number-pad" name="accountBalance" style="input" />
<text-field id="accountType" name="accountType" value="BANKSAVE" hide="true"/>
<text-field name="goalId" th:value="${goalId}" hide="true"/>
<view id="atAllocateSaving" style="Button Button-Big-Primary M-T-20">
<behavior href="/preview" action="replace" target="allocateSavingForm" verb="get"/>
<text style="Button-Label Text-Center">Allocate Saving</text>
</view>
</form>
<spinner id="mySpinner" hide="true" />
</view>
</body>
<styles>
<style id="input" borderBottomColor="#E1E1E1" borderBottomWidth="1" borderColor="#4E4D4D" flex="1" fontSize="16" fontWeight="normal" paddingBottom="8" paddingTop="8" />
<style id="input-error" borderBottomColor="#FF4847" color="#FF4847">
<modifier focused="true">
<style borderBottomColor="#FF4847" />
</modifier>
</style>
<style id="Title1" fontWeight="700" fontSize="18" color="#2E384D" />
<style id="Title2" fontWeight="600" fontSize="16" />
<style id="Button-Label-Bold" fontWeight="600" fontSize="20" />
<style id="Button-Big-Primary" fontSize="18" height="48" />
<style id="Text-Center" textAlign="center" justifyContent='center' alignItems='center' />
<style id="Button" borderColor="#F52B39" backgroundColor="#F52B39" borderWidth="1" borderRadius="20" justifyContent="center" paddingLeft="26" paddingRight="26" height="40" />
<style id="Button-Label" color="#fff" fontSize="16" />
<style id="Text1" fontSize="14" color="#5A6170" />
<style id="Text2" fontSize="14" color="#596980" />
<style id="Main-Red" color="#ED1B2E" />
<style id="Main-Black" color="#2E3B4D" />
<style id="Grey3" color="#8F9EB2" />
<style id="Orange" color="#FA8025" />
<style id="Green" color="#27BDB3" />
<style id="Color-White" color="#fff" />
<style id="Bg-White" backgroundColor="#fff" />
<style id="Grey-Line" borderBottomWidth="1" borderColor="#F3F3F5" marginTop="15" marginBottom="15" />
<style id="Bg-Banner" height="12" backgroundColor="#F3F3F5" />
<style id="M-20" margin="20" />
<style id="M-T-20" marginTop="20" />
<style id="M-T-10" marginTop="10" />
<style id="Flex-Center-Wrap" display="flex" flexDirection="row" justifyContent="space-between" alignItems="center" alignContent="center" />
<style id="Tabs" flexDirection="row" marginTop="20" height="28" justifyContent="flex-start" />
<style id="Tab" alignItems="center" backgroundColor="white" marginRight="10" paddingLeft="10" paddingRight="10" flexDirection="row" borderColor="#C4C7CC" borderWidth="1" borderRadius="16" justifyContent="center">
<modifier selected="true">
<style backgroundColor="#FFF5F5" borderColor="#F52B39" />
</modifier>
</style>
<style id="Tab__Label" fontSize="12" color="#5A6170" fontWeight="normal">
<modifier selected="true">
<style color="#ED1B2E" />
</modifier>
</style>
<style id="Header" paddingLeft="21" paddingRight="20" paddingBottom="10" paddingTop="10" backgroundColor="white" borderColor="#eee" borderBottomWidth="1" flexDirection="row" justifyContent="space-between" alignItems="flex-end"/>
<style id="Header__Back" color="black" fontSize="18" fontWeight="600" />
<style id="Header__Title" color="black" fontSize="16" fontWeight="bold" />
<style id="Header_Logo" width="106" height="21" />
<style id="Body" flex="1" />
<style id="Color-Warning" color="#F52B39" />
</styles>
</screen>
</doc>
The "disabled" modifier styles should be applied to the element when disabled. Elements that support being disabled can set disabled="true" as an attribute.
First. thanks for the amazing framework you guys have created.
I was wondering if this works for web as well, and if not, are there any plans on porting it to web so you can write once and run it everywhere?
Thanks.
I cannot find any documentation how to add Hyperview to an existing native iOS/Android project. Is it possible at all? If yes, where can I find any documentation?
Right now we can only trigger one behavior on refresh, support <behavior>
elements as well
Does Hyperview support RTL languages and RTL layout?
With XML below, I would expect the behavior to only trigger once after the component has mounted. However, the two behaviors inside the select-single ("select" / "deselect") seem to cause the entire component to re-mount (not just the component backing the form).
<form style="Flex">
<text style="H7">Why are you cancelling this shift?</text>
<select-single style="Select" name="{{ form.business_cancelled_reason.name }}">
{% for choice_value, choice_label in form.fields.business_cancelled_reason.choices %}
<option style="Select__Option" value="{{choice_value}}"{% if choice_value == form.cleaned_data.business_cancelled_reason %} selected="true"{% endif %}>
{% if choice_value == form.instance.CANCEL_REASON_OTHER %}
<behavior trigger="select" href="#otherReasonInput" action="replace-inner" target="otherReason" />
<behavior trigger="deselect" href="#null" action="replace-inner" target="otherReason" />
{% endif %}
<text style="Select__Option__Label">{{choice_label}}</text>
<view style="Select__Option__RadioOuter"><view style="Select__Option__RadioInner" /></view>
</option>
{% endfor %}
</select-single>
<view id="otherReason" />
</form>
<view hide="true">
<view id="null" />
<view id="otherReasonInput">
<text-field name="{{ form.business_cancelled_reason_other.name }}" style="Input" placeholder="Reason for cancelation" placeholderTextColor="#8D9494" />
</view>
</view>
{% if form.cleaned_data.business_cancelled_reason == form.instance.CANCEL_REASON_OTHER %}
<behavior trigger="load" href="#otherReasonInput" action="replace-inner" target="otherReason" />
{% endif %}
Hi there, this isn't a real issue but I couldn't dig up a good way to get in touch with @adamstep otherwise. I am the creator of intercooler.js (and now htmx) and I came down to SF a while ago to chat with y'all about it and to see your awesome port of the concept to mobile development w/ hyperview.
Adam mentioned that, like me, he had done some hypercard work, and I wanted to let him know that when I ported intercooler to htmx, I decided to pull the event attributes and somewhat hacky ic-action
attribute out and create a new front end programming language that is based on HyperTalk:
I thought he might get a kick out of it.
When using the react dev tools, there is currently no way to map a rendered component in the tree to its source XML node. Dev tools are an integral part of UI development and we should look into integrations with the existing dev tools as a start.
when user swipe left(go back previous [specific] page) or swipe right(go to next [specific] page) in both iOS/Android,
Can the gestures be detected and handled by the same customized method with hardwareBackPress #268 ?
like the way #272 implemented by @ashwinibm about the Android physical back key.
if yes, how to implement it ?
Thanks a lot.
action="replace" doesn't take effect in some special case so far I found:
in Official Demo:
Behaviors -> Indicators -> Inline Indicator
(source file in hyperview/examples/behaviors/inline_button_indicator.xml)
issue is :
when press the button 'Press me', after delay, the content of view which id="container" would not be replaced.
I checked above issue by expo client app installed in emulator iPhone11(ios 14.3) and Android device(Android 10), both not work.
for reference: it can work if remove the both attribute: 'show-during-load' and 'hide-during-load'
in real project as below code,
`<view>
<text>select choice:</text>
<select-single name="choice">
<option value="1" trigger="select" action="replace" delay="300" show-during-load="ID_Spinner1" target="modal-uninterested" href="/behaviors/_target_sibling_fragment.xml" >
<text>option 1</text>
<spinner id="ID_Spinner1" color="red" hide="true" />
</option>
<option value="2" trigger="select" action="replace" delay="300" show-during-load="ID_Spinner2" target="modal-uninterested" href="/behaviors/_target_sibling_fragment.xml" >
<text>option 2</text>
</option>
<spinner id="ID_Spinner2" color="red" hide="true" />
</select-single>
</view>
`
I checked above issue in real project on Android device(Android 10);
please help check, feel free if need any more information, thanks a lot.
Now that eslint-plugin-instawork
includes the necessary eslint configs and plugin. We can update the dependency version and get rid of the stale configs from hyperview repo.
Also explicitly set printWidth
to 100 to match eslint config
hi, there is a question I'd like to ask:
How to go back specific page when use Android physical back key
? (key 2 in below pic)
Requirement:
when user press back key(key 1 in below pic), generally it will back to previous page.
but in some special case, it need go back further, like back to the home page.
in this case, I can set as below:
<text>
back
<behavior action="navigate" href="/home.xml" />
</text>
The question is:
How to do if I want to achieve the same effect with the Android physical 'back key' ? (key 2 in below pic)
React Native backhandler
Failed solution
I tried to use custom-behavior as below, but it failed with error shown in below pic:
<behavior
action="android-back-action"
action-href="/home.xml"
action-action="navigate"
/>
const androidBackBehavior = {
action: 'android-back-action',
callback: (element: Element, onUpdate: HvComponentOnUpdate, getRoot: HvGetRoot, updateRoot: HvUpdateRoot) => {
const href = element?.getAttributeNode('action-href')?.nodeValue;
const action = element?.getAttributeNode('action-action')?.nodeValue;
hyperviewRef.current.onUpdate(href, action, {}, {});
}
};
<Hyperview
ref={hyperviewRef}
back={goBack}
closeModal={closeModal}
fetch={(input: any) => {
return fetchWrapper(input, customHeaders);
}}
navigate={navigate}
navigation={navigation}
openModal={openModal}
push={push}
replace={navigation.replace}
formatDate={formatDate}
behaviors={[androidBackBehavior]}
/>
Quite often lists require line separators.
Right now we've to do this manually in markup. React native has a prop to simplify such use cases.
We recently added this for error screen, loading can be similar.
This causes issues in particular with amplitude behavior, as some events are logged multiple times while they should be logged only once.
https://github.com/Instawork/hyperview/blob/master/src/index.js#L402
Hi, I talked to one of your representatives a few days ago on twitter where I said I would reach out. So I did:
I have a few questions regarding how Hyperview works.
1.
As I understand it Hyperview renders views inside a react native client application based on the XML data it receives from the server. Though what is, at least to me, fairly unclear is how it does that. With that I mean, are the views the application renders based on that data actually native UI elements? Or are they more similar to web elements?
2.
Continuing from the first question: how does this approach differ from a webbrowser? You have a React native client which gets sent data that tells it how to render the UI. This concept appears to me very similar to a traditional webbrowser. So I wonder what the difference is and also, what the advantages are in using this approach over a traditional webbrowser. And that brings me to the next question.
3.
What advantage does Hyperview have over PWA's? When you come from a web background (like myself) what would be the advantage of using Hyperview over something like a PWA? It's a bit easier to write as they are basically websites that run in a webview on the device (and are in a sense the natural succession to something like Cordova).
4.
In what capacity can I mix web code with Hyperview? And by that I mean, can I run javascript libraries inside hyperview or does that only work inside the webview tag? or instance, can I choose to write Hyperview XML wherever I whish to have a native experience, and switch to a webview where I want to include something that the native UI doesnโt cover (for example: a custom navigation bar)? Iโm mainly thinking about animation in this instance (libraries like greensock and the like).
5.
This may be a bit of an odd question but here it goes anyway: Since it is mentioned in the docs that Hyperview is supposed to work with any backend technology that is capable of handling HTTP requests, would it theoretically be possible to combine Hyperview with Wordpress? In the sense of having Wordpress build the XML files using PHP and serving that to the react native client? And if that would be possible, would you recommend it? why yes or why not? (or perhaps you are neutral about it).
I may follow up with a few more questions in the future as these are the ones that I had at the top of my head.
With kind regards
Roel Van Eyken
Unlike other nav actions, "reload" does not yet support delay and loading indicators. We should add this for consistency.
The concept of "components" helps in abstracting different pieces of the UI so we can work and collaborate in an easier way.
The current state of art is extending XMLs from different files and including them in an templating engine (for example Django) which only helps to a small extent.
Some of the advantages of a first class component system are:
All of these are already available in the react ecosystem and heavily increase productivity and maintain sanity.
Hi, I want to use the hyperview to implement the whole app, and use jsp or asp to bind data into the hxml. Could you give me some suggestions?
Implement add/remove/toggle style actions for behaviors. Ideally, these should behavior similarly to jQuery's addClass/removeClass/toggleClass functions:
add-style
adds the specified style(s) to the target, without creating duplicate style IDs
remove-style
removes the specified style(s) from the target, no errors if the styles do not exist
toggle-style
adds style(s) the target does not have, and removes style(s) the target does have
TBD: should toggle-style
be allowed to mix operations (e.g. add some styles and remove others) for a single trigger?
Currently there is no way to take advantage of hot reload / fast refresh.
With hot reloading only the tree which is changing should reload and rest of the app should maintain its state. When hot reloading is not feasible (component tree throws some error or network connectivity) it should fallback to fast refresh (full tree reload).
hi, this is a really great lib!!!
but i'm noticing there is no graph in the demo, can you tell me how to add dynamic graph into the screen?
for example: if i want some screen have a bar/pie chart base on some data from server side, what should i do?
another question: for some reason, if i want to change some screen with React-native UI (like page a is hyperview, and navigate to page b which is react-native page), is it possible?
When triggering a behavior multiple times with a large delay (say 1000), the UI becomes inconsistent and leads to buggy behavior. Please check the attached screen-cast. This probably happens since the newer behaviors will be added to the event loop and executed after the second screen has loaded.
We should figure out a better way to handle such cases. Probably ignoring the triggers after the first one (not sure if there is a use case for handling all the triggers with delay):
The purpose of SafeAreaView is to render content within the safe area boundaries of a device, so in my code I just wrap Hyperview with the SafeAreaView component.
actual result:
the first page in Hyperview is good, it display all content in the safe area, but when navigate to next hyperview page, the SafeAreaView is not working
expected result:
content expected to render in the safe area for all page
what should I do to make it work for all page?
in the demo it just set the Header height=72, I think this is not a best practices, so any solutions for this? thanks
<style id="Header"
alignItems="center"
backgroundColor="white"
borderBottomColor="#eee"
borderBottomWidth="1"
flexDirection="row"
height="72"
paddingLeft="24"
paddingRight="24"
paddingTop="24" />
this is what I do for my code
import { SafeAreaView } from 'react-native-safe-area-view';
export default function MyAwesomeApp() {
return (
<SafeAreaView style={{ flex: 1 }}>
<Hyperview
entrypointUrl={url}
fetch={fetch}
back={this.back}
closeModal={this.closeModal}
openModal={this.openModal}
navigate={this.navigate}
push={this.push}
/>
</SafeAreaView>
);
}
Would you have a complete example in order to provide authentication to an app by using username/password?
Would it be possible to use Bearer Authentication by passing a token in every request to the backend?
While in dev mode, it's often required to make changes on the template on server side and reload the screen on mobile client.
True hot reloading might be tricky to handle for now; we can render an absolute positioned view which reloads the screen (probably using the reload
action
would just work)
The implementation of behaviors in select-single and select-multiple does not run one-after-another, causing crashes due to references that don't exist.
Hi, it seems that when set action to back
in hyperview xml, it behaves not as expectation described in doc as below.
In official demo, press button "Back to other", it just goes back to previous page, does not make a new request to the new url.
Please help check, thanks a lot.
When the user presses "Go to second screen", the second screen will be pushed onto the stack. Then, if the user pushes "Go back", the stack will unwind, and the user will see screen 1 again. However, if the user pushes "Go back to a different place", the stack will unwind, and Hyperview will make a request to https://mysite.com/third. The content of the first screen will be replaced with the content from the third request.
Any change in the URL will cause a reload, including changes in the search string.
If a element has once="true", then ran-once="true" should be set on that element, not on the triggering element. Otherwise, we can block other behaviors from running.
This action will not run properly:
<behavior
action="alert"
alert:title="Contact"
trigger="press"
>
<alert:option
action="phone"
alert:label="Call phone"
phone:number="123456"
xmlns:phone="https://instawork.com/hyperview-phone"
/>
</behavior>
However, this one would:
<behavior
action="alert"
alert:title="Contact"
trigger="press"
>
<alert:option
action="phone"
alert:label="Call phone"
href="#"
phone:number="123456"
xmlns:phone="https://instawork.com/hyperview-phone"
/>
</behavior>
The alert
element should be able to trigger the phone
action without requiring href
Currently we've a very tedious way of sending JSON data which looks something like this:
<behavior
...
redux:extra="{"payload":{"params":{"title":"{% trans 'FAQ' %}","url":"{% trans faq.answer_link %}"},"routeName":"MODALS/WEB_VIEW_MODAL"}}"
/>
I don't think this is readable. Currently we've to copy paste it into editor, replace characters and then replace everything back and paste it into the XML and hope it works.
Hi genius, I have read the guide of basic form section here https://hyperview.org/docs/example_basic_form. But I fond some issues.
Even if I use the "verb=post" property in xml it send a "GET" request.
When I play with the case study examples of basic form section, after I click the Submit button whithout nothing input I got the bellow error.
How to send http post request from hyperview xml to java backend controller?
My system version is Macos catalina 10.15.6. The simulator version is Iphone11pro-14.1
Could you pls help on above questions?
this is my situation:
I think this is not a good practice, my question is: how can I include one common style for each hyperview page๏ผso every time when there are changes for the common-style, I only need to update it in one place.
something just like when we working on a web project, we just need to include a common.css for all page
<link rel="stylesheet" type="text/css" href="css/common.css">
<doc lang="en"
xmlns="https://hyperview.org/hyperview"
xmlns:th="http://www.thymeleaf.org">
<screen>
<body style="Body">
<header style="Header">
<text action="back" delay='300' href="#" style="Header__Back">
<text style="Header__Title">Title</text>
</text>
</header>
<view scroll="true">
<view style="m-16">
<view style="flex-center-wrap">
<text style="18-bold gray4">test text</text>
<view style="btn btn-medium btn-primary">
<text style="btn-label btn-primary"> === medium === </text>
</view>
</view>
</view>
</body>
<styles>
<style id="Header" paddingLeft="21" paddingRight="20" paddingBottom="10" paddingTop="10" backgroundColor="white" borderColor="#eee" borderBottomWidth="1" flexDirection="row" justifyContent="space-between" alignItems="flex-end"/>
<style id="Header__Back" color="black" fontSize="18" fontWeight="500" />
<style id="Header__Title" color="black" fontSize="16" fontWeight="bold" />
<style id="Body" flex="1" backgroundColor="#fff" />
<!-- common style start -->
<!-- margin -->
<style id="m-0" margin="0" />
<style id="m-4" margin="4" />
<style id="m-8" margin="8" />
<style id="m-12" margin="12" />
<style id="m-16" margin="16" />
<style id="m-t-0" marginTop="0" />
<style id="m-t-4" marginTop="4" />
<style id="m-t-8" marginTop="8" />
<style id="m-t-12" marginTop="12" />
<style id="m-t-16" marginTop="16" />
<style id="m-t-24" marginTop="24" />
<style id="m-b-0" marginBottom="0" />
<style id="m-b-4" marginBottom="4" />
<style id="m-b-8" marginBottom="8" />
<style id="m-b-12" marginBottom="12" />
<style id="m-b-16" marginBottom="16" />
<style id="m-b-24" marginBottom="24" />
<style id="gray1" color="#283542"/>
<style id="gray2" color="#596980"/>
<style id="gray3" color="#8F9EB2"/>
<style id="gray4" color="#BCC2CC"/>
<style id="gray5" color="#E1E3E6"/>
<style id="gray6" color="#E8E9EB"/>
<style id="gray7" color="#F3F3F5"/>
<style id="bold" fontWeight="700"/>
<style id="medium" fontWeight="500"/>
<style id="regular" fontWeight="400"/>
<!-- button -->
<style id="btn" borderColor="#ED1B2E" backgroundColor="#fff" borderWidth="1" borderRadius="24" justifyContent="center" paddingLeft="24" paddingRight="24" />
<style id="btn-large" height="48" marginBottom="12"/>
<style id="btn-medium" height="44" marginBottom="12"/>
<style id="btn-small" height="36" marginBottom="12"/>
<style id="btn-primary" backgroundColor="#ED1B2E" color="#fff" />
<style id="btn-label" color="#ED1B2E" textAlign="center" fontSize="16" fontWeight="500"/>
<style id="btn-label-small" fontSize="14" fontWeight="400"/>
<!-- common style end -->
</styles>
</screen>
</doc>
hi, one question: how do you do the unit test for custom component by using Jest?
for example, for below [hv-web-view] component, how do I write the unit test?
import * as Events from 'hyperview/src/services/events';
import * as Namespaces from 'hyperview/src/services/namespaces';
import { ActivityIndicator, StyleSheet } from 'react-native';
import React, { PureComponent } from 'react';
import type { HvComponentProps } from 'hyperview/src/types';
import { LOCAL_NAME } from 'hyperview/src/types';
import WebView from 'react-native-webview';
import { createProps } from 'hyperview/src/services';
export default class HvWebView extends PureComponent<HvComponentProps> {
static namespaceURI = Namespaces.HYPERVIEW;
static localName = LOCAL_NAME.WEB_VIEW;
static localNameAliases = [];
props: HvComponentProps;
onMessage = (event: ?{ nativeEvent: { data: string } }) => {
if (!event) {
return;
}
const matches = event.nativeEvent.data.match(/^hyperview:(.*)$/);
if (matches) {
Events.dispatch(matches[1]);
}
};
render() {
const props: any = createProps(
this.props.element,
this.props.stylesheets,
this.props.options,
);
const color = props['activity-indicator-color'];
const injectedJavaScript = props['injected-java-script'];
const source = { html: props.html, uri: props.url };
return (
<WebView
injectedJavaScript={injectedJavaScript}
onMessage={this.onMessage}
renderLoading={() => (
<ActivityIndicator
color={color}
style={StyleSheet.absoluteFillObject}
/>
)}
source={source}
startInLoadingState
/>
);
}
}
thanks very much
hi @adamstep , would you please release a new version?
we need the feature of navigate. it will be great to have a new version base the latest branch master
.
thank you so much.
Authentication should be preserved via cookies (as per a web browser), so that when the server does a redirect authentication information is not lost.
Right now, if we return a 302 on a Hyperview page the user will land on the target page as if they're not authenticated.
Currently, adding a behavior to a will wrap that view in a TouchableOpacity component in React Native. This can have unintended consequences if the view is using flexbox styling, because the view will be limited in its layout to the wrapping touchable component.
The current workaround is to set "href-style" attribute with styles that will get applied to the touchable component, but this is not intuitive and has led to developer confusion.
Ideally, we can somehow determine which flebox styles applied to the view should be automatically added to the wrapping component. Maybe it's as simple as applying all flex properties to the wrapper, and setting the view to flex="1"?
Hi ;
In demo app , any refresh part gives this error ::
(Like List with refresh )
ReferenceError: Can't find variable: later
This error is located at:
in HvOption (at render/index.js:81)
in RCTView (at View.js:44)
in HvSelectSingle (at render/index.js:81)
in RCTView (at View.js:44)
in HyperScreen (at HyperviewScreen.js:70)
in HyperviewScreen (at SceneView.js:9)
in SceneView (at StackViewLayout.js:483)
in RCTView (at View.js:44)
in AnimatedComponent (at screens.native.js:58)
in Screen (at StackViewCard.js:42)
in Card (at createPointerEventsContainer.js:26)
in Container (at StackViewLayout.js:507)
in RCTView (at View.js:44)
in ScreenContainer (at StackViewLayout.js:401)
in RCTView (at View.js:44)
in StackViewLayout (at withOrientation.js:30)
in withOrientation (at StackView.js:49)
in RCTView (at View.js:44)
in Transitioner (at StackView.js:19)
in StackView (at createNavigator.js:57)
in Navigator (at createKeyboardAwareNavigator.js:11)
in KeyboardAwareNavigator (at createNavigationContainer.js:376)
in NavigationContainer (at SceneView.js:9)
in SceneView (at StackViewLayout.js:483)
in RCTView (at View.js:44)
in AnimatedComponent (at screens.native.js:58)
in Screen (at StackViewCard.js:42)
in Card (at createPointerEventsContainer.js:26)
in Container (at StackViewLayout.js:507)
in RCTView (at View.js:44)
in ScreenContainer (at StackViewLayout.js:401)
in RCTView (at View.js:44)
in StackViewLayout (at withOrientation.js:30)
in withOrientation (at StackView.js:49)
in RCTView (at View.js:44)
in Transitioner (at StackView.js:19)
in StackView (at createNavigator.js:57)
in Navigator (at createKeyboardAwareNavigator.js:11)
in KeyboardAwareNavigator (at createNavigationContainer.js:376)
in NavigationContainer (at App.js:15)
in App (at registerRootComponent.js:17)
in RootErrorBoundary (at registerRootComponent.js:16)
in ExpoRootComponent (at renderApplication.js:34)
in RCTView (at View.js:44)
in RCTView (at View.js:44)
in AppContainer (at renderApplication.js:33)
onUpdateFragment
AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false&assetPlugin=%2FUsers%2Fmikail%2Fhyperview%2Fdemo%2Fnode_modules%2Fexpo%2Ftools%2FhashAssetFiles.js:163922:16
onUpdate
AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false&assetPlugin=%2FUsers%2Fmikail%2Fhyperview%2Fdemo%2Fnode_modules%2Fexpo%2Ftools%2FhashAssetFiles.js:163734:34
AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false&assetPlugin=%2FUsers%2Fmikail%2Fhyperview%2Fdemo%2Fnode_modules%2Fexpo%2Ftools%2FhashAssetFiles.js:167363:19
triggerSelectBehaviors
AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false&assetPlugin=%2FUsers%2Fmikail%2Fhyperview%2Fdemo%2Fnode_modules%2Fexpo%2Ftools%2FhashAssetFiles.js:167354:32
componentDidUpdate
AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false&assetPlugin=%2FUsers%2Fmikail%2Fhyperview%2Fdemo%2Fnode_modules%2Fexpo%2Ftools%2FhashAssetFiles.js:167412:38
commitLifeCycles
AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false&assetPlugin=%2FUsers%2Fmikail%2Fhyperview%2Fdemo%2Fnode_modules%2Fexpo%2Ftools%2FhashAssetFiles.js:17582:46
commitAllLifeCycles
AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false&assetPlugin=%2FUsers%2Fmikail%2Fhyperview%2Fdemo%2Fnode_modules%2Fexpo%2Ftools%2FhashAssetFiles.js:18736:29
invokeGuardedCallbackImpl
AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false&assetPlugin=%2FUsers%2Fmikail%2Fhyperview%2Fdemo%2Fnode_modules%2Fexpo%2Ftools%2FhashAssetFiles.js:9710:21
invokeGuardedCallback
AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false&assetPlugin=%2FUsers%2Fmikail%2Fhyperview%2Fdemo%2Fnode_modules%2Fexpo%2Ftools%2FhashAssetFiles.js:9796:42
commitRoot
AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false&assetPlugin=%2FUsers%2Fmikail%2Fhyperview%2Fdemo%2Fnode_modules%2Fexpo%2Ftools%2FhashAssetFiles.js:18873:34
completeRoot
AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false&assetPlugin=%2FUsers%2Fmikail%2Fhyperview%2Fdemo%2Fnode_modules%2Fexpo%2Ftools%2FhashAssetFiles.js:20017:19
performWorkOnRoot
AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false&assetPlugin=%2FUsers%2Fmikail%2Fhyperview%2Fdemo%2Fnode_modules%2Fexpo%2Ftools%2FhashAssetFiles.js:19957:27
performWork
AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false&assetPlugin=%2FUsers%2Fmikail%2Fhyperview%2Fdemo%2Fnode_modules%2Fexpo%2Ftools%2FhashAssetFiles.js:19877:30
performSyncWork
AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false&assetPlugin=%2FUsers%2Fmikail%2Fhyperview%2Fdemo%2Fnode_modules%2Fexpo%2Ftools%2FhashAssetFiles.js:19852:20
batchedUpdates$1
AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false&assetPlugin=%2FUsers%2Fmikail%2Fhyperview%2Fdemo%2Fnode_modules%2Fexpo%2Ftools%2FhashAssetFiles.js:20053:28
batchedUpdates
AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false&assetPlugin=%2FUsers%2Fmikail%2Fhyperview%2Fdemo%2Fnode_modules%2Fexpo%2Ftools%2FhashAssetFiles.js:11127:37
_receiveRootNodeIDEvent
AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false&assetPlugin=%2FUsers%2Fmikail%2Fhyperview%2Fdemo%2Fnode_modules%2Fexpo%2Ftools%2FhashAssetFiles.js:11184:23
receiveTouches
AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false&assetPlugin=%2FUsers%2Fmikail%2Fhyperview%2Fdemo%2Fnode_modules%2Fexpo%2Ftools%2FhashAssetFiles.js:11214:34
__callFunction
AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false&assetPlugin=%2FUsers%2Fmikail%2Fhyperview%2Fdemo%2Fnode_modules%2Fexpo%2Ftools%2FhashAssetFiles.js:3624:49
AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false&assetPlugin=%2FUsers%2Fmikail%2Fhyperview%2Fdemo%2Fnode_modules%2Fexpo%2Ftools%2FhashAssetFiles.js:3397:31
__guard
AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false&assetPlugin=%2FUsers%2Fmikail%2Fhyperview%2Fdemo%2Fnode_modules%2Fexpo%2Ftools%2FhashAssetFiles.js:3578:15
callFunctionReturnFlushedQueue
AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false&assetPlugin=%2FUsers%2Fmikail%2Fhyperview%2Fdemo%2Fnode_modules%2Fexpo%2Ftools%2FhashAssetFiles.js:3396:21
When an error is thrown in hyperview the stack trace should point to the XML file (line and column) where the error was caused. The current workflow involves hit and trial, opening the XML in editor and trying to figure out what went wrong without much leads.
For example, here's how error stack trace looks like on JS (works directly in editor as well):
The legacy lifecycle methods have been deprecated and will be removed in the next major version of react. They might also cause problems with async rendering in the future.
For new code, we should only use the newer lifecycle methods.
I see your examples are all static files. The data to show in the pages will need query from db in server side and refer to the user's permissions. but how should I place these data into the xml which need to return to the client? Is there a reactlike lib for generate the page?
Currently there is no linting support for HXML. This often leads to problematic issues which are hard to debug. For example, I once wasted quite a bit of time trying to debug scrolling on a view
just to realize later that the attribute scroll
was misspelled.
Some of the most basic features are:
include
)Several rules from eslint-plugin-hyperview
were disabled when upgrading the plugin in #125
Re-enable the following rules in .eslintrc
and fix the errors:
import/no-cycle
lines-between-class-members
no-else-return
no-restricted-globals
prefer-destructuring
react/destructuring-assignment
react/jsx-sort-props
react/no-access-state-in-setstate
sort-keys
in order to implement some complicated UI like below two-layer cascading menu, it's found that current actions can not match this requirement.
And below actions are needed in this case
include
include
means replace the target element with the contents of source element
, instead of source element itself.include-inner
include-inner
means replace the target element's children with the contents of source element
.The name and meaning of both new actions are referred from the include syntax of Thymeleaf.
I'm testing these new actions now, and want to hear your opinions before raising a PR.
the implement code is like below:
// hyperview/src/services/behaviors/index.js
/**
* Returns a new Document object where the given action was applied to the target element
* with the new element.
*/
export const performUpdate = (
action: UpdateAction,
targetElement: Element,
newElement: Element,
): Document => {
if (action === ACTIONS.REPLACE) {
const { parentNode } = targetElement;
if (parentNode) {
parentNode.replaceChild(newElement, targetElement);
return shallowCloneToRoot((parentNode: any));
}
}
if (action === ACTIONS.REPLACE_INNER) {
let child: ?Node = targetElement.firstChild;
// Remove the target's children
while (child !== null && child !== undefined) {
const nextChild: ?Node = child.nextSibling;
targetElement.removeChild(child);
child = nextChild;
}
targetElement.appendChild(newElement);
return shallowCloneToRoot(targetElement);
}
// new action : include
if (action === ACTIONS.INCLUDE) {
const { parentNode } = targetElement;
if (parentNode) {
let child: ?Node = newElement.firstChild;
// Insert the newElement's children
while (child !== null && child !== undefined) {
const nextChild: ?Node = child.nextSibling;
parentNode.insertBefore(child, targetElement);
child = nextChild;
}
parentNode.removeChild(targetElement);
return shallowCloneToRoot((parentNode: any));
}
}
// new action : include-inner
if (action === ACTIONS.INCLUDE_INNER) {
let child: ?Node = targetElement.firstChild;
// Remove the target's children
while (child !== null && child !== undefined) {
const nextChild: ?Node = child.nextSibling;
targetElement.removeChild(child);
child = nextChild;
}
child = newElement.firstChild;
// Append the newElement's children
while (child !== null && child !== undefined) {
const nextChild: ?Node = child.nextSibling;
targetElement.appendChild(child);
child = nextChild;
}
return shallowCloneToRoot(targetElement);
}
...
};
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.