Skip to content

Commit

Permalink
Fix: Possible fix for #13 - Node re-creation on the native side (#14)
Browse files Browse the repository at this point in the history
* hack: add a recreate method

on each child node tree there's a new recreate method which get's fired
everytime something is removed, since
react native also removes it's existence from the native side causing re-
mounting errors

* simplify examples

* add rebuildTree on append instead of remove

* add a multipage example component

* simplify nested condition for removal

* change the increment count for allocation of tags

hack to avoid colliding tags with react native

* ci: disable build

* chore: proper demo
  • Loading branch information
barelyhuman committed Oct 28, 2022
1 parent d884984 commit f40715c
Show file tree
Hide file tree
Showing 13 changed files with 468 additions and 204 deletions.
3 changes: 2 additions & 1 deletion .codesandbox/ci.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"sandboxes": ["vanilla"],
"node": "14"
"node": "14",
"buildCommand": false
}
181 changes: 9 additions & 172 deletions example/App.js
Original file line number Diff line number Diff line change
@@ -1,175 +1,12 @@
/** @jsxImportSource preact */
import DomApp from './components/DomCounter'
import MultiPage from './components/MultiPage'
import PreactCounter from './components/PreactCounter'
import { Demo } from './components/Demo'

import { TextInput, Text, View, SafeAreaView } from '@barelyhuman/preact-native'
import { Component } from 'preact'
import { signal } from '@preact/signals'
import { Alert } from 'react-native'
import { createApp, h as vueJSX } from 'vue'

function App() {
// VueCounter()
return <Counter />
}

// FIXME: event handlers compat for vue
function VueCounter() {
const saView = document.createElement('SafeAreaView')
document.appendChild(saView)

const app = createApp({
data() {
return {
count: 0,
}
},
render() {
return vueJSX(
'View',
{
style: {
backgroundColor: '#333',
height: 52,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 6,
},
},
vueJSX('Text', { style: { color: 'white' } }, this.count)
)
},
})
app.mount(saView)
}

const count = signal(0)

function Counter() {
const handleInc = e => {
e.stopPropagation()
count.value++
}

const handleDec = e => {
e.stopPropagation()
count.value--
}

return (
<>
<SafeAreaView>
<View alignItems="center" justifyContent="center">
<Text fontSize={30} margin={10} color="white">
{count.value}
</Text>
<View>
<View
onClick={handleInc}
borderRadius={6}
width={250}
margin={10}
backgroundColor={'#333'}
alignItems="center"
justifyContent="center"
>
<Text fontSize={30} margin={10} color="white">
+
</Text>
</View>

<View
onClick={handleDec}
borderRadius={6}
width={250}
margin={10}
backgroundColor={'#333'}
alignItems="center"
justifyContent="center"
>
<Text fontSize={30} margin={10} color="white">
-
</Text>
</View>
</View>
</View>
</SafeAreaView>
</>
)
export default function App() {
// DomApp()
// return <MultiPage />
// return <PreactCounter />
return <Demo />
}

class TestRenderable extends Component {
state = { email: '' }
constructor(props) {
super(props)
}

render() {
return (
<>
<SafeAreaView backgroundColor="#181819">
<View
height="100%"
width="100%"
padding={10}
alignItems="center"
justifyContent="center"
>
<TextInput
width={'100%'}
height={52}
marginBottom={8}
padding={10}
placeholder="email"
borderRadius={10}
borderWidth={1}
borderColor="slategray"
color="white"
value={this.state.email}
backgroundColor="transparent"
onFocus={e => {
console.log('focus')
}}
onBlur={e => {
console.log('blur')
}}
onChange={e => {
this.setState({ email: e.data })
}}
/>
<TextInput
width={'100%'}
height={52}
marginBottom={8}
padding={10}
placeholder="password"
secureTextEntry={true}
borderRadius={10}
borderWidth={1}
borderColor="slategray"
color="white"
backgroundColor="transparent"
/>
<View
height={52}
padding={15}
width={'100%'}
borderRadius={6}
justifyContent="center"
alignItems="center"
backgroundColor="white"
onClick={e => {
e.stopPropagation()
Alert.alert(`Oh hey, ${this.state.email}`)
}}
>
<Text fontSize={16} fontWeight="bold">
Login
</Text>
</View>
</View>
</SafeAreaView>
</>
)
}
}

export default App
154 changes: 154 additions & 0 deletions example/components/Demo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/**@jsxImportSource preact*/
import { Component } from 'preact'
import { SafeAreaView, Text, View } from '@barelyhuman/preact-native'
import { StyleSheet } from 'react-native'

export class Demo extends Component {
state = {
activeTab: 0,
}
render() {
return (
<>
<SafeAreaView height={'100%'} backgroundColor={'#673ab8'}>
<View
padding={12}
flexDirection={'row'}
backgroundColor={'#673ab8'}
alignItems={'baseline'}
justifyContent={'space-between'}
>
<View>
<Text fontSize={24} style={styles.primaryText}>
Preact Native
</Text>
</View>
<View flexDirection={'row'} alignItems={'baseline'}>
<View
style={styles.tabView}
borderColor={
this.state.activeTab === 0 ? '#ad80ff' : 'transparent'
}
onClick={() => {
this.setState({
activeTab: 0,
})
}}
>
<Text style={styles.primaryText}>About</Text>
</View>
<View
style={styles.tabView}
borderColor={
this.state.activeTab === 1 ? '#ad80ff' : 'transparent'
}
onClick={() => {
this.setState({
activeTab: 1,
})
}}
>
<Text style={styles.primaryText}>Counter</Text>
</View>
</View>
</View>
<View style={styles.tabPageContainer}>
<About show={this.state.activeTab === 0} />
<Counter show={this.state.activeTab === 1} />
</View>
</SafeAreaView>
</>
)
}
}

function About({ show }) {
if (!show) {
return null
}
return (
<>
<Text color={'#ccc'}>
Preact Native, as of now is an experimental approach at connecting the
react-native SDK to the preact web UI library
</Text>
</>
)
}

class Counter extends Component {
state = {
count: 0,
focused: false,
}

render({ show }) {
if (!show) {
return null
}
return (
<View justifyContent="center" alignItems="center">
<Text style={styles.primaryText} fontSize={24}>
{this.state.count}
</Text>
<View
style={styles.button}
backgroundColor={this.state.focused ? 'white' : 'transparent'}
marginTop={20}
onClick={() => {
this.setState(() => ({
focused: true,
count: this.state.count + 1,
}))
setTimeout(() => {
this.setState(() => ({
focused: false,
}))
}, 250)
}}
>
<Text
style={styles.buttonText}
color={this.state.focused ? 'black' : 'white'}
>
Inc
</Text>
</View>
</View>
)
}
}

const styles = StyleSheet.create({
tabView: {
marginHorizontal: 2,
padding: 4,
borderTopWidth: 4,
},
primaryText: {
color: '#fff',
},
secondaryText: {
color: '#ccc',
},
tabPageContainer: {
marginTop: 12,
padding: 12,
height: '100%',
backgroundColor: '#1c2027',
},
button: {
borderRadius: 6,
borderWidth: 3,
justifyContent: 'center',
alignItems: 'center',
borderColor: '#fff',
marginHorizontal: 16,
minWidth: 200,
paddingHorizontal: 32,
paddingVertical: 12,
},
buttonText: {
fontSize: 18,
},
})
33 changes: 33 additions & 0 deletions example/components/DomCounter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
export default function DomApp() {
let count = 0

const saView = document.createElement('SafeAreaView')
const view = document.createElement('View')
const text = document.createElement('Text')
text.textContent = count

Object.assign(text.style, {
color: 'white',
fontSize: 24,
})

Object.assign(view.style, {
backgroundColor: 'dodgerblue',
padding: 16,
borderRadius: 6,
margin: 10,
justifyContent: 'center',
alignItems: 'center',
})

view.addEventListener('click', e => {
e.stopPropagation()
text.textContent = ++count
})

view.appendChild(text)
saView.appendChild(view)
document.appendChild(saView)

return null
}

0 comments on commit f40715c

Please sign in to comment.