[
  {
    "path": ".gitignore",
    "content": "/.vscode\n/lib\n/coverage\nnode_modules\npackage-lock.json\nshrinkwrap.yaml\nyarn.lock\npnpm-lock.yaml"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2018 Andre 'Staltz' Medeiros\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"@cycle/react-native\",\n  \"version\": \"3.0.0\",\n  \"description\": \"Cycle.js driver that uses React Native to render\",\n  \"author\": \"Andre Staltz <contact@staltz.com>\",\n  \"license\": \"MIT\",\n  \"bugs\": \"https://github.com/cyclejs/react-native/issues\",\n  \"repository\": \"https://github.com/cyclejs/react-native/tree/master\",\n  \"keywords\": [\n    \"react\",\n    \"cyclejs\",\n    \"xstream\",\n    \"mvi\",\n    \"react-native\",\n    \"driver\"\n  ],\n  \"files\": [\n    \"lib\"\n  ],\n  \"main\": \"lib/cjs/index.js\",\n  \"typings\": \"lib/cjs/index.d.ts\",\n  \"dependencies\": {\n    \"@cycle/react\": \"2.x\",\n    \"xstream\": \"11.x.x\"\n  },\n  \"peerDependencies\": {\n    \"react\": \">=16.8.0\",\n    \"react-native\": \">=0.64.0\"\n  },\n  \"devDependencies\": {\n    \"@cycle/run\": \"^5.4.0\",\n    \"@huston007/react-native-mock\": \"^0.3.3\",\n    \"@types/mocha\": \"^9.0.0\",\n    \"@types/node\": \"^14.6.0\",\n    \"@types/react\": \"16.9.46\",\n    \"@types/react-native\": \"0.63.8\",\n    \"@types/react-test-renderer\": \"^16.9.3\",\n    \"babel-cli\": \"^6.26.0\",\n    \"babel-preset-react-native\": \"4.0.1\",\n    \"expo\": \"38.x.x\",\n    \"mocha\": \"^9.1.3\",\n    \"prettier\": \"^2.5.1\",\n    \"react\": \">=17.0.2\",\n    \"react-native\": \">=0.64.0\",\n    \"react-test-renderer\": \"17.0.2\",\n    \"ts-node\": \"^10.4.0\",\n    \"typescript\": \"4.5.2\",\n    \"xstream\": \"^11.14.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"scripts\": {\n    \"prepublishOnly\": \"npm run compile\",\n    \"compile\": \"rm -rf lib && npm run compile-cjs && npm run compile-es6\",\n    \"compile-cjs\": \"tsc --module commonjs --outDir ./lib/cjs\",\n    \"compile-es6\": \"tsc --module es6 --outDir ./lib/es6\",\n    \"test\": \"ts-node -P test/tsconfig.json --require @huston007/react-native-mock/mock.js node_modules/mocha/bin/mocha test/*.ts\"\n  },\n  \"prettier\": {\n    \"singleQuote\": true,\n    \"trailingComma\": \"es5\",\n    \"bracketSpacing\": false\n  }\n}\n"
  },
  {
    "path": "readme.md",
    "content": "# Cycle React Native\n\n> Cycle.js driver that uses React Native to render\n\n- Provides a driver factory `makeReactNativeDriver`\n- Contains hyperscript helper functions, such as `View()`, `Text()`, etc\n\n```\nnpm install @cycle/react-native\n```\n\n## Example\n\n```js\nimport xs from 'xstream';\nimport {run} from '@cycle/run';\nimport {makeReactNativeDriver, TouchableOpacity, View, Text} from '@cycle/react-native';\n\nfunction main(sources) {\n  const inc = Symbol();\n  const inc$ = sources.react.select(inc).events('press');\n\n  const count$ = inc$.fold(count => count + 1, 0);\n\n  const elem$ = count$.map(i =>\n    TouchableOpacity(inc, [\n      View([\n        Text(`Counter: ${i}`),\n      ])\n    ]),\n  );\n\n  return {\n    react: elem$,\n  };\n}\n\n// Necessary shim in React Native's JS engine\nglobal.queueMicrotask = fn => setTimeout(fn, 1);\n\nrun(main, {\n  react: makeReactNativeDriver('MyApp'),\n});\n```\n\n\n## Installation\n\nStart by installing React Native prerequisites (XCode, react-native-cli, watchman).\n\nThen create a React Native project using the CLI.\n\nWhen the project is set up, npm install `@cycle/react-native`, `@cycle/run`, and a stream library like `xstream`, then replace the index.js with something that looks like the example code in this readme.\n\n## API\n\n### `makeReactNativeDriver(appKey)`\n\nReturns a driver that uses React Native to render your Cycle.js app in the native application known by the string `appKey`.\n\n### Hyperscript helpers\n\nImport hyperscript helpers such as `View`, `Text`, `TouchableOpacity`, etc to create React elements to represent the respective built-in native components: `<View>`, `<Text>`, `<TouchableOpacity>`, etc.\n\nThe basic usage is `View(props, children)`, but some variations and shortcuts are allowed:\n\n- `View()` becomes `<View/>`\n- `View(props)` becomes `<View {...props}></View>`\n- `Text('text content')` becomes `<Text>text content</Text>`\n- `View([child1, child2])`\n- `Text(props, 'text content')`\n- `View(props, [child1, child2])`\n- etc\n\nThere are also shortcuts for (MVI) intent selectors:\n\n- `Touchable(someSymbol)` becomes `h(Touchable, {sel: someSymbol})`\n- `Touchable(sym, props)` becomes `h(Touchable, {sel: sym, ...props})`\n- `Text('myselector', 'text content')`\n- `Touchable('inc', [child])`\n- `Touchable('inc', propsObject, [child])`\n- etc\n\nFor non-built-in components (e.g. third party) components, you can use `h(ThirdPartyComponent)` with `h` from `@cycle/react` or you can build a helper using `makeHelper(ThirdPartyComponent)` with `makeHelper` from `@cycle/react-native`.\n\n## Other native drivers\n\nThis library only covers React components in React Native and View-related rendering. For other native APIs in React Native, use drivers specifically built for those. See the list below:\n\n- [cycle-native-alert](https://gitlab.com/staltz/cycle-native-alert)\n- [cycle-native-asyncstorage](https://gitlab.com/staltz/cycle-native-asyncstorage)\n- [cycle-native-android-local-notification](https://gitlab.com/staltz/cycle-native-android-local-notification)\n- [cycle-native-clipboard](https://gitlab.com/staltz/cycle-native-clipboard)\n- [cycle-native-keyboard](https://gitlab.com/staltz/cycle-native-keyboard)\n- [cycle-native-linking](https://gitlab.com/staltz/cycle-native-linking)\n- [cycle-native-share](https://gitlab.com/staltz/cycle-native-share)\n- [cycle-native-toastandroid](https://gitlab.com/staltz/cycle-native-toastandroid)\n- (please build more of these and add them here!)\n\n## License\n\nMIT, Andre 'Staltz' Medeiros 2018\n\n"
  },
  {
    "path": "src/components.ts",
    "content": "import {\n  // General\n  ActivityIndicator as _ActivityIndicator,\n  Button as _Button,\n  FlatList as _FlatList,\n  Image as _Image,\n  KeyboardAvoidingView as _KeyboardAvoidingView,\n  Modal as _Modal,\n  Pressable as _Pressable,\n  RefreshControl as _RefreshControl,\n  ScrollView as _ScrollView,\n  SectionList as _SectionList,\n  StatusBar as _StatusBar,\n  Switch as _Switch,\n  Text as _Text,\n  TextInput as _TextInput,\n  TouchableHighlight as _TouchableHighlight,\n  TouchableOpacity as _TouchableOpacity,\n  TouchableWithoutFeedback as _TouchableWithoutFeedback,\n  View as _View,\n  // Android\n  DrawerLayoutAndroid as _DrawerLayoutAndroid,\n  TouchableNativeFeedback as _TouchableNativeFeedback,\n  // iOS\n  InputAccessoryView as _InputAccessoryView,\n  SafeAreaView as _SafeAreaView,\n} from 'react-native';\nimport {makeHelper} from './helper';\n\nexport const ActivityIndicator = makeHelper(_ActivityIndicator);\nexport const Button = makeHelper(_Button);\nexport const DrawerLayoutAndroid = makeHelper(_DrawerLayoutAndroid);\nexport const FlatList = makeHelper(_FlatList);\nexport const Image = makeHelper(_Image);\nexport const InputAccessoryView = makeHelper(_InputAccessoryView);\nexport const KeyboardAvoidingView = makeHelper(_KeyboardAvoidingView);\nexport const Modal = makeHelper(_Modal);\nexport const RefreshControl = makeHelper(_RefreshControl);\nexport const ScrollView = makeHelper(_ScrollView);\nexport const SectionList = makeHelper(_SectionList);\nexport const StatusBar = makeHelper(_StatusBar);\nexport const Switch = makeHelper(_Switch);\nexport const TextInput = makeHelper(_TextInput);\nexport const Text = makeHelper(_Text);\nexport const TouchableHighlight = makeHelper(_TouchableHighlight);\nexport const TouchableNativeFeedback = makeHelper(_TouchableNativeFeedback);\nexport const TouchableOpacity = makeHelper(_TouchableOpacity);\nexport const TouchableWithoutFeedback = makeHelper(_TouchableWithoutFeedback);\nexport const View = makeHelper(_View);\n"
  },
  {
    "path": "src/driver.ts",
    "content": "import {Stream} from 'xstream';\nimport {ReactSource, makeCycleReactComponent} from '@cycle/react';\nimport {ReactElement} from 'react';\nimport {AppRegistry} from 'react-native';\n\nexport function makeReactNativeDriver(\n  appKey: string,\n  {\n    registerRootComponent = (Root) =>\n      AppRegistry.registerComponent(appKey, () => Root),\n  }: {registerRootComponent?: (component: React.ComponentType) => any} = {}\n) {\n  return function reactNativeDriver(sink: Stream<ReactElement<any>>) {\n    const source = new ReactSource();\n    const Root = makeCycleReactComponent(() => ({source, sink}));\n    registerRootComponent(Root);\n    return source;\n  };\n}\n"
  },
  {
    "path": "src/helper.ts",
    "content": "import {ReactElement, ComponentType} from 'react';\nimport {h} from '@cycle/react';\n\nfunction parseSelector(param: any) {\n  if (typeof param === 'symbol') return param;\n  if (typeof param === 'string' && param.length > 0) return param;\n  return null;\n}\n\nexport type Children = Array<ReactElement<any>> | string;\n\nexport type HelperSig<P> = {\n  (sel: symbol): ReactElement<P>;\n  (child: string): ReactElement<P>;\n  (props: P): ReactElement<P>;\n  (children: Children): ReactElement<P>;\n  (sel: string | symbol, props: P): ReactElement<P>;\n  (props: P, children: Children): ReactElement<P>;\n  (sel: string | symbol, children: Children): ReactElement<P>;\n  (sel: string | symbol, props: P, children: Children): ReactElement<P>;\n};\n\nexport function makeHelper<P>(type: ComponentType<P>): HelperSig<P> {\n  return function helper(a?: any, b?: any, c?: any): ReactElement<P> {\n    const hasA = typeof a !== 'undefined';\n    const hasB = typeof b !== 'undefined';\n    const hasBChildren = Array.isArray(b) || typeof b === 'string';\n    const hasC = typeof c !== 'undefined';\n    const sel = parseSelector(a);\n    if (sel) {\n      if (hasB && hasC) {\n        return h(type, {...b, sel}, c);\n      } else if (hasB && hasBChildren) {\n        return h(type, {sel} as any, b as Array<ReactElement<any>>);\n      } else if (hasB) {\n        return h(type, {...b, sel});\n      } else if (typeof sel === 'symbol') {\n        return h(type, {sel} as any);\n      } else {\n        return h(type, sel as any /* child, not a sel */);\n      }\n    } else if (hasC) {\n      return h(type, b, c);\n    } else if (hasB) {\n      return h(type, a, b);\n    } else if (hasA) {\n      return h(type, a);\n    } else {\n      return h(type);\n    }\n  };\n}\n"
  },
  {
    "path": "src/index.ts",
    "content": "export * from './helper';\nexport * from './components';\nexport * from './driver';\n"
  },
  {
    "path": "test/helpers.ts",
    "content": "import 'mocha';\nimport * as renderer from 'react-test-renderer';\nimport * as React from 'react';\nimport xs, {Stream} from 'xstream';\nimport {h, ReactSource, makeCycleReactComponent} from '@cycle/react';\nimport {run} from '@cycle/run';\nimport {makeHelper, View, Text} from '../src/index';\nimport {View as _View} from 'react-native';\nconst assert = require('assert');\n\nclass _Touchable extends React.PureComponent<any, any> {\n  public press() {\n    if (this.props.onPress) {\n      this.props.onPress(null);\n    }\n  }\n\n  public render() {\n    return this.props.children;\n  }\n}\n\ndescribe('helpers', function () {\n  it('Touchable w/ selector, Text w/ text child, View w/ children', (done) => {\n    const Touchable = makeHelper(_Touchable);\n\n    function main(sources: {react: ReactSource}) {\n      const inc$ = sources.react.select('button').events('press');\n      const count$ = inc$.fold((acc: number, x: any) => acc + 1, 0);\n      const vdom$ = count$.map((i: number) =>\n        Touchable('button', [View([Text('' + i)])])\n      );\n      return {react: vdom$};\n    }\n\n    function testDriver(sink: Stream<React.ReactElement<any>>) {\n      let turn = 0;\n      const source = new ReactSource();\n      const Root = makeCycleReactComponent(() => ({source, sink}));\n      const r = renderer.create(React.createElement(Root as any));\n      const root = r.root;\n      const check = () => {\n        const to = root.findByType(_Touchable);\n        const view = to.props.children;\n        const text = view.props.children;\n        assert.strictEqual(text.props.children, `${turn}`);\n        to.instance.press();\n        turn++;\n        if (turn === 3) {\n          done();\n        }\n      };\n      setTimeout(check, 50);\n      setTimeout(check, 100);\n      setTimeout(check, 150);\n      return source;\n    }\n\n    run(main, {react: testDriver});\n  });\n\n  it('View w/ symbol selector', (done) => {\n    function main(sources: {react: ReactSource}) {\n      const foo = Symbol();\n      const vdom$ = xs.of(View(foo));\n      return {react: vdom$};\n    }\n\n    function testDriver(sink: Stream<React.ReactElement<any>>) {\n      const source = new ReactSource();\n      const Root = makeCycleReactComponent(() => ({source, sink}));\n      const r = renderer.create(React.createElement(Root as any));\n      const root = r.root;\n      setTimeout(() => {\n        const view = root.findByType(_View);\n        assert.strictEqual(!!view, true);\n        done();\n      }, 50);\n      return source;\n    }\n\n    run(main, {react: testDriver});\n  });\n\n  it('View w/ selector and props', (done) => {\n    function main(sources: {react: ReactSource}) {\n      const vdom$ = xs.of(View('foo', {accessible: true}));\n      return {react: vdom$};\n    }\n\n    function testDriver(sink: Stream<React.ReactElement<any>>) {\n      const source = new ReactSource();\n      const Root = makeCycleReactComponent(() => ({source, sink}));\n      const r = renderer.create(React.createElement(Root as any));\n      const root = r.root;\n      setTimeout(() => {\n        const view = root.findByType(_View);\n        assert.strictEqual(view.props.accessible, true);\n        done();\n      }, 50);\n      return source;\n    }\n\n    run(main, {react: testDriver});\n  });\n\n  it('View w/ selector and children', (done) => {\n    function main(sources: {react: ReactSource}) {\n      const vdom$ = xs.of(View('foo', [Text('hello world')]));\n      return {react: vdom$};\n    }\n\n    function testDriver(sink: Stream<React.ReactElement<any>>) {\n      const source = new ReactSource();\n      const Root = makeCycleReactComponent(() => ({source, sink}));\n      const r = renderer.create(React.createElement(Root as any));\n      const root = r.root;\n      setTimeout(() => {\n        const view = root.findByType(_View);\n        const text = view.props.children;\n        assert.strictEqual(text.props.children, 'hello world');\n        done();\n      }, 50);\n      return source;\n    }\n\n    run(main, {react: testDriver});\n  });\n\n  it('View w/ selector and props and children', (done) => {\n    function main(sources: {react: ReactSource}) {\n      const vdom$ = xs.of(\n        View('foo', {accessible: true}, [Text('hello world')])\n      );\n      return {react: vdom$};\n    }\n\n    function testDriver(sink: Stream<React.ReactElement<any>>) {\n      const source = new ReactSource();\n      const Root = makeCycleReactComponent(() => ({source, sink}));\n      const r = renderer.create(React.createElement(Root as any));\n      const root = r.root;\n      setTimeout(() => {\n        const view = root.findByType(_View);\n        const text = view.props.children;\n        assert.strictEqual(view.props.accessible, true);\n        assert.strictEqual(text.props.children, 'hello world');\n        done();\n      }, 50);\n      return source;\n    }\n\n    run(main, {react: testDriver});\n  });\n\n  it('View w/ props and children', (done) => {\n    function main(sources: {react: ReactSource}) {\n      const vdom$ = xs.of(View({accessible: true}, [Text('hello world')]));\n      return {react: vdom$};\n    }\n\n    function testDriver(sink: Stream<React.ReactElement<any>>) {\n      const source = new ReactSource();\n      const Root = makeCycleReactComponent(() => ({source, sink}));\n      const r = renderer.create(React.createElement(Root as any));\n      const root = r.root;\n      setTimeout(() => {\n        const view = root.findByType(_View);\n        const text = view.props.children;\n        assert.strictEqual(view.props.accessible, true);\n        assert.strictEqual(text.props.children, 'hello world');\n        done();\n      }, 50);\n      return source;\n    }\n\n    run(main, {react: testDriver});\n  });\n\n  it('Text w/ selector and text child', (done) => {\n    function main(sources: {react: ReactSource}) {\n      const vdom$ = xs.of(View([Text('foo', 'hello world')]));\n      return {react: vdom$};\n    }\n\n    function testDriver(sink: Stream<React.ReactElement<any>>) {\n      const source = new ReactSource();\n      const Root = makeCycleReactComponent(() => ({source, sink}));\n      const r = renderer.create(React.createElement(Root as any));\n      const root = r.root;\n      setTimeout(() => {\n        const view = root.findByType(_View);\n        const text = view.props.children;\n        assert.strictEqual(text.props.children, 'hello world');\n        done();\n      }, 50);\n      return source;\n    }\n\n    run(main, {react: testDriver});\n  });\n});\n"
  },
  {
    "path": "test/index.ts",
    "content": "import 'mocha';\nimport * as renderer from 'react-test-renderer';\nimport * as React from 'react';\nimport xs, {Stream} from 'xstream';\nimport * as ReactNative from 'react-native';\nimport {h, ReactSource, makeCycleReactComponent} from '@cycle/react';\nimport {run} from '@cycle/run';\nconst assert = require('assert');\nconst {View, Text} = ReactNative;\n\nclass Touchable extends React.PureComponent<any, any> {\n  public press() {\n    if (this.props.onPress) {\n      this.props.onPress(null);\n    }\n  }\n\n  public render() {\n    return this.props.children;\n  }\n}\n\ndescribe('React Native driver', function () {\n  it('converts an MVI Cycle app into a React component', function (done) {\n    function main(sources: {react: ReactSource}) {\n      const inc = Symbol();\n      const inc$ = sources.react.select(inc).events('press');\n      const count$ = inc$.fold((acc: number, x: any) => acc + 1, 0);\n      const vdom$ = count$.map((i: number) =>\n        h(Touchable, {sel: inc}, [h(View, [h(Text, {}, '' + i)])])\n      );\n      return {react: vdom$};\n    }\n\n    function testDriver(sink: Stream<React.ReactElement<any>>) {\n      let turn = 0;\n      const source = new ReactSource();\n      const Root = makeCycleReactComponent(() => ({source, sink}));\n      const r = renderer.create(React.createElement(Root as any));\n      const root = r.root;\n      const check = () => {\n        const to = root.findByType(Touchable);\n        const view = to.props.children;\n        const text = view.props.children;\n        assert.strictEqual(text.props.children, `${turn}`);\n        to.instance.press();\n        turn++;\n        if (turn === 3) {\n          done();\n        }\n      };\n      setTimeout(check, 50);\n      setTimeout(check, 100);\n      setTimeout(check, 150);\n      return source;\n    }\n\n    run(main, {react: testDriver});\n  });\n});\n"
  },
  {
    "path": "test/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"removeComments\": false,\n    \"preserveConstEnums\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"module\": \"commonjs\",\n    \"target\": \"ES5\",\n    \"rootDir\": \"../\",\n    \"outDir\": \"lib/\",\n    \"lib\": [\n      \"dom\",\n      \"es5\",\n      \"scripthost\",\n      \"es2015.collection\",\n      \"es2015.promise\",\n      \"es2015.iterable\"\n    ]\n  },\n  \"formatCodeOptions\": {\n    \"indentSize\": 2,\n    \"tabSize\": 2\n  },\n  \"files\": [\"index.ts\", \"helpers.ts\"]\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"removeComments\": false,\n    \"preserveConstEnums\": true,\n    \"strictNullChecks\": true,\n    \"declaration\": true,\n    \"sourceMap\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"module\": \"commonjs\",\n    \"target\": \"ES5\",\n    \"rootDir\": \"src/\",\n    \"outDir\": \"lib/cjs/\",\n    \"skipLibCheck\": true,\n    \"noImplicitAny\": true,\n    \"newLine\": \"LF\",\n    \"moduleResolution\": \"node\",\n    \"lib\": [\"dom\", \"es5\", \"scripthost\", \"es2015\"]\n  },\n  \"include\": [\"src/**/*\"]\n}\n"
  }
]