diff --git a/examples/ReactExample/.eslintrc b/examples/ReactExample/.eslintrc new file mode 100644 index 00000000..98b5f8ba --- /dev/null +++ b/examples/ReactExample/.eslintrc @@ -0,0 +1,20 @@ +{ + "env": { + "commonjs": true, + "es6": true + }, + "ecmaFeatures": { + "jsx": true + }, + "plugins": [ + "react" + ], + "rules": { + "react/jsx-no-duplicate-props": 2, + "react/jsx-no-undef": 2, + "react/jsx-uses-react": 2, + "react/no-direct-mutation-state": 1, + "react/prefer-es6-class": 1, + "react/react-in-jsx-scope": 2 + } +} diff --git a/examples/ReactExample/components/realm.js b/examples/ReactExample/components/realm.js new file mode 100644 index 00000000..7a62e345 --- /dev/null +++ b/examples/ReactExample/components/realm.js @@ -0,0 +1,21 @@ +'use strict'; + +const Realm = require('realm'); + +module.exports = new Realm({ + schema: [ + { + name: 'Todo', + properties: [ + {name: 'text', type: Realm.Types.STRING}, + ] + }, + { + name: 'TodoList', + properties: [ + {name: 'name', type: Realm.Types.STRING}, + {name: 'items', type: Realm.Types.LIST, objectType: 'Todo'}, + ] + }, + ], +}); diff --git a/examples/ReactExample/components/styles.js b/examples/ReactExample/components/styles.js new file mode 100644 index 00000000..d02ea704 --- /dev/null +++ b/examples/ReactExample/components/styles.js @@ -0,0 +1,34 @@ +'use strict'; + +const React = require('react-native'); + +module.exports = React.StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + alignItems: 'stretch', + backgroundColor: '#ffffff', + }, + listItem: { + padding: 12, + borderColor: "#c8c7cc", + borderBottomWidth: 0.5, + alignItems: 'center', + alignSelf: 'stretch', + flexDirection: 'row', + flex: 1, + height: 44, + }, + listItemText: { + fontFamily: 'System', + fontSize: 15, + flexDirection: 'column', + flex: 1, + lineHeight: 16, + }, + instructions: { + textAlign: 'center', + color: '#333333', + marginBottom: 5, + } +}); diff --git a/examples/ReactExample/components/todo-app.js b/examples/ReactExample/components/todo-app.js new file mode 100644 index 00000000..afebfc09 --- /dev/null +++ b/examples/ReactExample/components/todo-app.js @@ -0,0 +1,51 @@ +'use strict'; + +const React = require('react-native'); +const TodoList = require('./todo-list'); +const realm = require('./realm'); + +const { NavigatorIOS } = React; + +class TodoApp extends React.Component { + componentWillMount() { + let todoLists = realm.objects('TodoList'); + + if (todoLists.length < 1) { + realm.write(() => { + realm.create('TodoList', {name: 'Todo List', items: []}); + }); + } + + this.todoLists = todoLists; + } + + render() { + let list = this.todoLists[0]; + + let route = { + title: list.name, + component: TodoList, + passProps: { + ref: 'todoList', + list: list, + }, + rightButtonTitle: 'Add', + onRightButtonPress: () => this._addNewItem(list) + }; + + return ( + + ); + } + + _addNewItem(list) { + realm.write(() => { + list.items.push({text: ''}); + }); + + let todoList = this.refs.nav.refs.todoList; + todoList.setState({editingRow: list.items.length - 1}); + } +} + +module.exports = TodoApp; diff --git a/examples/ReactExample/components/todo-item.js b/examples/ReactExample/components/todo-item.js new file mode 100644 index 00000000..1ca68343 --- /dev/null +++ b/examples/ReactExample/components/todo-item.js @@ -0,0 +1,77 @@ +'use strict'; + +const React = require('react-native'); +const realm = require('./realm'); +const styles = require('./styles'); + +const { Text, TextInput, View } = React; + +class TodoItem extends React.Component { + constructor(props) { + super(props); + + this._onChangeText = this._onChangeText.bind(this); + } + + componentDidMount() { + // The autoFocus prop on TextInput was not working for us :( + this._focusInputIfNecessary(); + } + + componentDidUpdate() { + this._focusInputIfNecessary(); + } + + render() { + let contents; + + if (this.props.editing) { + contents = ( + + ); + } else { + contents = ( + + {this.props.item.text} + + ); + } + + return ( + + {contents} + + ); + } + + _onChangeText(text) { + realm.write(() => { + this.props.item.text = text; + }); + + this.forceUpdate(); + } + + _focusInputIfNecessary() { + if (!this.props.editing) { + return; + } + + let input = this.refs.input; + if (!input.isFocused()) { + input.focus(); + } + } +} + +module.exports = TodoItem; diff --git a/examples/ReactExample/components/todo-list.js b/examples/ReactExample/components/todo-list.js new file mode 100644 index 00000000..c292f2d9 --- /dev/null +++ b/examples/ReactExample/components/todo-list.js @@ -0,0 +1,70 @@ +'use strict'; + +const React = require('react-native'); +const TodoItem = require('./todo-item'); +const realm = require('./realm'); +const styles = require('./styles'); + +const { ListView, Text, View } = React; + +class TodoList extends React.Component { + constructor(props) { + super(props); + + this.dataSource = new ListView.DataSource({ + rowHasChanged: (row1, row2) => row1 !== row2 + }); + + this.state = {}; + this._renderRow = this._renderRow.bind(this); + } + + render() { + let dataSource = this.dataSource.cloneWithRows(this.props.list.items); + + return ( + + + + Press Cmd+R to reload,{'\n'} + Cmd+D for dev menu + + + ); + } + + _renderRow(item, sectionIndex, rowIndex) { + return ( + this._onPressRow(rowIndex)} + onEndEditing={() => this._onEndEditingRow(rowIndex)} /> + ); + } + + _onPressRow(rowIndex) { + let editingRow = this.state.editingRow; + + if (editingRow != null && editingRow != rowIndex) { + this._onEndEditingRow(editingRow); + } + + this.setState({editingRow: rowIndex}); + } + + _onEndEditingRow(rowIndex) { + let items = this.props.list.items; + + // Delete the todo item if it doesn't have any text. + if (!items[rowIndex].text) { + realm.write(() => items.splice(rowIndex, 1)); + } + + if (this.state.editingRow == rowIndex) { + this.setState({editingRow: null}); + } + } +} + +module.exports = TodoList; diff --git a/examples/ReactExample/index.ios.js b/examples/ReactExample/index.ios.js index 4fd74391..e051fe32 100644 --- a/examples/ReactExample/index.ios.js +++ b/examples/ReactExample/index.ios.js @@ -1,198 +1,6 @@ -/** - * Sample React Native App - * https://github.com/facebook/react-native - */ 'use strict'; -var Realm = require('realm'); -var React = require('react-native'); +const React = require('react-native'); +const TodoApp = require('./components/todo-app'); -var { - AppRegistry, - StyleSheet, - NavigatorIOS, - AlertIOS, - ListView, - TouchableHighlight, - Text, - TextInput, - View, -} = React; - -var TodoItemSchema = { - name: 'Todo', - properties: [ - {name: 'text', type: Realm.Types.STRING}, - ] -}; -var TodoListSchmea = { - name: 'TodoList', - properties: [ - {name: 'name', type: Realm.Types.STRING}, - {name: 'items', type: Realm.Types.LIST, objectType: 'Todo'} - ] -}; - -console.log(Realm.defaultPath); -var realm = new Realm({schema: [TodoItemSchema, TodoListSchmea]}); - -class Edit extends React.Component { - componentWillMount() { - this.setState({text: this.props.text}); - } - - save() { - realm.write(function () { - if (this.props.todoId == this.props.list.items.length) { - this.props.list.items.push({text: this.state.text}); - } - else { - var todoItem = this.props.list.items[this.props.todoId]; - todoItem.text = this.state.text; - } - }.bind(this)); - // should not be needed once we have notifications - this.props.parent.updateDataSource(); - this.props.navigator.pop(); - } - - render() { - return ( - - this.setState({text})} value={this.state.text}/> - - Save - - - ) - } -}; - -class TodoList extends React.Component { - componentWillMount() { - this.lists = realm.objects('TodoList'); - if (this.lists.length < 1) { - realm.write(function() { - realm.create('TodoList', ['List', []]); - }); - } - this.list = this.lists[0]; - this.menu = this.menu.bind(this); - this.delete = this.delete.bind(this); - var dataSource = new ListView.DataSource({ - rowHasChanged: (row1, row2) => row1 !== row2 - }); - - this.updateDataSource(dataSource); - } - - updateDataSource(oldDataSource) { - if (!oldDataSource) { - oldDataSource = this.state.dataSource; - } - this.setState({dataSource: oldDataSource.cloneWithRows(this.list.items)}); - } - - menu(todo, todoID) { - AlertIOS.alert( - todo.text, - todoID, - [ - {text: 'Complete', onPress: () => this.delete(todoID)}, - {text: 'Edit', onPress: () => this.edit(todoID, todo.text)}, - {text: 'Cancel'} - ] - ) - } - - delete(todoID) { - var item = this.list.items[todoID]; - realm.write(function() { - realm.delete(item); - }) - this.updateDataSource(); - } - - edit(todoId, text) { - this.props.navigator.push({ - title: text, - component: Edit, - passProps: {list: this.list, todoId: todoId, text: text, parent: this} - }); - } - - render() { - return ( - - - this.menu(rowData, rowID)}> - {rowData.text} - - }/> - this.edit(this.list.items.length, "")}> - + - - - Press Cmd+R to reload,{'\n'} - Cmd+Control+Z for dev menu - - - ); - } -}; - -class Navigator extends React.Component { - render() { - return ( - - ); - } -}; -AppRegistry.registerComponent('ReactExample', () => Navigator); - -var styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - alignItems: 'stretch', - backgroundColor: '#ffffff', - }, - listItem: { - marginTop: 3, - padding: 6, - backgroundColor:'#ACACAC', - alignSelf: 'stretch', - flexDirection: 'row', - flex:1, - }, - textInput: { - alignSelf: 'stretch', - borderWidth: 0.5, - borderColor: '#0f0f0f', - height: 200, - fontSize: 13, - margin: 6, - marginTop: 70, - padding: 4, - }, - button: { - height: 36, - backgroundColor: '#48BBEC', - alignSelf: 'stretch', - justifyContent: 'center' - }, - buttonText: { - alignSelf: 'center', - }, - instructions: { - textAlign: 'center', - color: '#333333', - marginBottom: 5, - } -}); +React.AppRegistry.registerComponent('ReactExample', () => TodoApp);