@callstack/brownie 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,63 @@
1
+ <a href="https://www.callstack.com/open-source?utm_campaign=generic&utm_source=github&utm_medium=referral&utm_content=brownie" align="center">
2
+ <img alt="Brownie" src="https://github.com/callstack/react-native-brownfield/raw/refs/heads/main/img/brownie-banner.jpg">
3
+ </a>
4
+
5
+ <p align="center">
6
+ A shared state management library for React Native brownfield apps that enables seamless state synchronization between your React Native code and native code.
7
+ </p>
8
+
9
+ ---
10
+
11
+ [![Build Status][build-badge]][build]
12
+ [![Version][version-badge]][package]
13
+ [![MIT License][license-badge]][license]
14
+
15
+ [![PRs Welcome][prs-welcome-badge]][prs-welcome]
16
+ [![Chat][chat-badge]][chat]
17
+ [![Code of Conduct][coc-badge]][coc]
18
+ [![Sponsored by Callstack][callstack-badge]][callstack]
19
+
20
+ [![tweet][tweet-badge]][tweet]
21
+
22
+ ## Features
23
+
24
+ - **Shared State** - Single source of truth accessible from both TypeScript and Swift
25
+ - **Type Safety** - Full type inference from TypeScript schema to generated Swift types
26
+ - **React Integration** - `useStore` hook with selector support for optimal re-renders
27
+ - **SwiftUI Integration** - `@UseStore` property wrapper for reactive UI updates
28
+ - **UIKit Support** - Subscribe-based API for imperative UI updates
29
+
30
+ ## Documentation
31
+
32
+ For full documentation, visit [our documentation](https://oss.callstack.com/react-native-brownfield/brownie/overview).
33
+
34
+ <a href="https://www.callstack.com/ebooks/incremental-react-native-adoption-in-native-apps?utm_campaign=brownfield&utm_source=github&utm_medium=referral&utm_content=react-native-brownfield" align="center">
35
+ <img alt="Download a free copy of Incremental React Native adoption in native apps ebook" src="https://github.com/user-attachments/assets/ba42bb29-1e7a-4683-80c5-2602afb1a7e6">
36
+ </a>
37
+
38
+ ## Made with ❤️ at Callstack
39
+
40
+ React Native Brownfield is an open source project and will always remain free to use. If you think it's cool, please star it 🌟. [Callstack](https://callstack.com) is a group of React and React Native geeks, contact us at [hello@callstack.com](mailto:hello@callstack.com) if you need any help with these or just want to say hi!
41
+
42
+ Like the project? ⚛️ [Join the team](https://callstack.com/careers/?utm_campaign=Senior_RN&utm_source=github&utm_medium=readme) who does amazing stuff for clients and drives React Native Open Source! 🔥
43
+
44
+ <!-- badges -->
45
+
46
+ [build-badge]: https://img.shields.io/circleci/build/github/callstack/react-native-brownfield/master.svg?style=flat-square
47
+ [build]: https://circleci.com/gh/callstack/react-native-brownfield
48
+ [ci]: https://github.com/callstack/react-native-brownfield/actions/workflows/ci.yml/badge.svg
49
+ [version-badge]: https://img.shields.io/npm/v/@callstack/react-native-brownfield.svg?style=flat-square
50
+ [package]: https://www.npmjs.com/package/@callstack/react-native-brownfield
51
+ [license-badge]: https://img.shields.io/npm/l/@callstack/react-native-brownfield.svg?style=flat-square
52
+ [license]: https://opensource.org/licenses/MIT
53
+ [prs-welcome-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square
54
+ [prs-welcome]: http://makeapullrequest.com
55
+ [coc-badge]: https://img.shields.io/badge/code%20of-conduct-ff69b4.svg?style=flat-square
56
+ [coc]: https://github.com/callstack/react-native-brownfield/blob/master/CODE_OF_CONDUCT.md
57
+ [all-contributors-badge]: https://img.shields.io/badge/all_contributors-2-orange.svg?style=flat-square
58
+ [chat-badge]: https://img.shields.io/discord/613446453762719798.svg?style=flat-square&colorB=758ED3
59
+ [chat]: https://discord.gg/2SR9Mua
60
+ [tweet-badge]: https://img.shields.io/badge/tweet-%23reactnativebrownfield-blue.svg?style=flat-square&colorB=1DA1F2&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAUCAYAAACXtf2DAAAAAXNSR0IArs4c6QAAAaRJREFUOBGtlM8rBGEYx3cWtRHJRaKcuMtBSitxkCQ3LtzkP9iUUu5ODspRHLhRLtq0FxeicEBC2cOivcge%2FMgan3fNM8bbzL4zm6c%2BPT%2Fe7%2FO8887svrFYBWbbtgWzsAt3sAcpqJFxxF1QV8oJFqFPFst5dLWQAT87oTgPB7DtziFRT1EA4yZolsFkhwjGYFRO8Op0KD8HVe7unoB6PRTBZG8IctAmG1xrHcfkQ2B55sfI%2ByGMXSBqV71xZ8CWdxBxN6ThFuECDEAL%2Bc9HIzDYumVZ966GZnX0SzCZvEqTbkaGywkyFE6hKAsBPhFQ18uPUqh2ggJ%2BUor%2F4M%2F%2FzOC8g6YzR1i%2F8g4vvSI%2ByD7FFNjexQrjHd8%2BnjABI3AU4Wl16TuF1qANGll81jsi5qu%2Bw6XIsCn4ijhU5FmCJpkV6BGNw410hfSf6JKBQ%2FUFxHGYBnWnmOwDwYQ%2BwzdHqO75HtiAMJfaC7ph32FSRJCENUhDHsLaJkL%2FX4wMF4%2BwA5bgAcrZE4sr0Cu9Jq9fxyrvBHWbNkMD5CEHWTjjT2m6r5D92jfmbbKJEWuMMAAAAABJRU5ErkJggg%3D%3D
61
+ [tweet]: https://twitter.com/intent/tweet?text=Check%20out%20react-native-brownfield!%20https://github.com/callstack/react-native-brownfield%20%F0%9F%91%8D
62
+ [callstack-badge]: https://callstack.com/images/callstack-badge.svg
63
+ [callstack]: https://callstack.com/open-source/?utm_source=github.com&utm_medium=referral&utm_campaign=rnbrownfield&utm_term=readme
@@ -0,0 +1,52 @@
1
+ #include "BrownieHostObject.h"
2
+ #include <jsi/JSIDynamic.h>
3
+
4
+ namespace brownie {
5
+
6
+ BrownieHostObject::BrownieHostObject(std::shared_ptr<BrownieStore> store)
7
+ : store_(std::move(store)) {}
8
+
9
+ facebook::jsi::Value BrownieHostObject::get(facebook::jsi::Runtime &rt,
10
+ const facebook::jsi::PropNameID &name) {
11
+ std::string propName = name.utf8(rt);
12
+
13
+ if (propName == "unbox") {
14
+ return facebook::jsi::Function::createFromHostFunction(
15
+ rt, facebook::jsi::PropNameID::forAscii(rt, "unbox"), 0,
16
+ [this](facebook::jsi::Runtime &rt, const facebook::jsi::Value &,
17
+ const facebook::jsi::Value *, size_t) -> facebook::jsi::Value {
18
+ auto snapshot = store_->getSnapshot();
19
+ return facebook::jsi::valueFromDynamic(rt, snapshot);
20
+ });
21
+ }
22
+
23
+ auto value = store_->get(propName);
24
+ return facebook::jsi::valueFromDynamic(rt, value);
25
+ }
26
+
27
+ void BrownieHostObject::set(facebook::jsi::Runtime &rt,
28
+ const facebook::jsi::PropNameID &name,
29
+ const facebook::jsi::Value &value) {
30
+ std::string propName = name.utf8(rt);
31
+ auto dynamicValue = facebook::jsi::dynamicFromValue(rt, value);
32
+ store_->set(propName, std::move(dynamicValue));
33
+ }
34
+
35
+ std::vector<facebook::jsi::PropNameID>
36
+ BrownieHostObject::getPropertyNames(facebook::jsi::Runtime &rt) {
37
+ std::vector<facebook::jsi::PropNameID> names;
38
+ names.push_back(facebook::jsi::PropNameID::forAscii(rt, "unbox"));
39
+
40
+ auto snapshot = store_->getSnapshot();
41
+ if (snapshot.isObject()) {
42
+ for (const auto &pair : snapshot.items()) {
43
+ if (pair.first.isString()) {
44
+ names.push_back(facebook::jsi::PropNameID::forUtf8(rt, pair.first.getString()));
45
+ }
46
+ }
47
+ }
48
+
49
+ return names;
50
+ }
51
+
52
+ } // namespace brownie
@@ -0,0 +1,26 @@
1
+ #pragma once
2
+
3
+ #include "BrownieStore.h"
4
+ #include <jsi/jsi.h>
5
+ #include <memory>
6
+
7
+ namespace brownie {
8
+
9
+ class BrownieHostObject : public facebook::jsi::HostObject {
10
+ public:
11
+ explicit BrownieHostObject(std::shared_ptr<BrownieStore> store);
12
+
13
+ facebook::jsi::Value get(facebook::jsi::Runtime &rt,
14
+ const facebook::jsi::PropNameID &name) override;
15
+
16
+ void set(facebook::jsi::Runtime &rt, const facebook::jsi::PropNameID &name,
17
+ const facebook::jsi::Value &value) override;
18
+
19
+ std::vector<facebook::jsi::PropNameID>
20
+ getPropertyNames(facebook::jsi::Runtime &rt) override;
21
+
22
+ private:
23
+ std::shared_ptr<BrownieStore> store_;
24
+ };
25
+
26
+ } // namespace brownie
@@ -0,0 +1,31 @@
1
+ #include "BrownieInstaller.h"
2
+ #include "BrownieHostObject.h"
3
+ #include "BrownieStoreManager.h"
4
+
5
+ namespace brownie {
6
+
7
+ void BrownieInstaller::install(facebook::jsi::Runtime &runtime) {
8
+ auto getStore = facebook::jsi::Function::createFromHostFunction(
9
+ runtime, facebook::jsi::PropNameID::forAscii(runtime, "__brownieGetStore"), 1,
10
+ [](facebook::jsi::Runtime &rt, const facebook::jsi::Value &,
11
+ const facebook::jsi::Value *args, size_t count) -> facebook::jsi::Value {
12
+ if (count < 1 || !args[0].isString()) {
13
+ throw facebook::jsi::JSError(rt,
14
+ "getStore requires a string key argument");
15
+ }
16
+
17
+ std::string key = args[0].asString(rt).utf8(rt);
18
+ auto store = BrownieStoreManager::shared().getStore(key);
19
+
20
+ if (!store) {
21
+ return facebook::jsi::Value::undefined();
22
+ }
23
+
24
+ auto hostObject = std::make_shared<BrownieHostObject>(store);
25
+ return facebook::jsi::Object::createFromHostObject(rt, hostObject);
26
+ });
27
+
28
+ runtime.global().setProperty(runtime, "__brownieGetStore", getStore);
29
+ }
30
+
31
+ } // namespace brownie
@@ -0,0 +1,12 @@
1
+ #pragma once
2
+
3
+ #include <jsi/jsi.h>
4
+
5
+ namespace brownie {
6
+
7
+ class BrownieInstaller {
8
+ public:
9
+ static void install(facebook::jsi::Runtime &runtime);
10
+ };
11
+
12
+ } // namespace brownie
@@ -0,0 +1,53 @@
1
+ #include "BrownieStore.h"
2
+
3
+ namespace brownie {
4
+
5
+ BrownieStore::BrownieStore() : state_(folly::dynamic::object()) {}
6
+
7
+ BrownieStore::BrownieStore(folly::dynamic initialState)
8
+ : state_(std::move(initialState)) {}
9
+
10
+ folly::dynamic BrownieStore::get(const std::string &key) const {
11
+ std::lock_guard<std::mutex> lock(mutex_);
12
+ if (state_.isObject() && state_.count(key)) {
13
+ return state_[key];
14
+ }
15
+ return nullptr;
16
+ }
17
+
18
+ void BrownieStore::set(const std::string &key, folly::dynamic value) {
19
+ {
20
+ std::lock_guard<std::mutex> lock(mutex_);
21
+ if (!state_.isObject()) {
22
+ state_ = folly::dynamic::object();
23
+ }
24
+ state_[key] = std::move(value);
25
+ }
26
+
27
+ if (changeCallback_) {
28
+ changeCallback_();
29
+ }
30
+ }
31
+
32
+ folly::dynamic BrownieStore::getSnapshot() const {
33
+ std::lock_guard<std::mutex> lock(mutex_);
34
+ return state_;
35
+ }
36
+
37
+ void BrownieStore::setState(folly::dynamic state) {
38
+ {
39
+ std::lock_guard<std::mutex> lock(mutex_);
40
+ state_ = std::move(state);
41
+ }
42
+
43
+ if (changeCallback_) {
44
+ changeCallback_();
45
+ }
46
+ }
47
+
48
+ void BrownieStore::setChangeCallback(ChangeCallback callback) {
49
+ std::lock_guard<std::mutex> lock(mutex_);
50
+ changeCallback_ = std::move(callback);
51
+ }
52
+
53
+ } // namespace brownie
@@ -0,0 +1,30 @@
1
+ #pragma once
2
+
3
+ #include <folly/dynamic.h>
4
+ #include <functional>
5
+ #include <mutex>
6
+ #include <string>
7
+
8
+ namespace brownie {
9
+
10
+ class BrownieStore {
11
+ public:
12
+ using ChangeCallback = std::function<void()>;
13
+
14
+ BrownieStore();
15
+ explicit BrownieStore(folly::dynamic initialState);
16
+
17
+ folly::dynamic get(const std::string &key) const;
18
+ void set(const std::string &key, folly::dynamic value);
19
+ folly::dynamic getSnapshot() const;
20
+ void setState(folly::dynamic state);
21
+
22
+ void setChangeCallback(ChangeCallback callback);
23
+
24
+ private:
25
+ mutable std::mutex mutex_;
26
+ folly::dynamic state_;
27
+ ChangeCallback changeCallback_;
28
+ };
29
+
30
+ } // namespace brownie
@@ -0,0 +1,31 @@
1
+ #include "BrownieStoreManager.h"
2
+
3
+ namespace brownie {
4
+
5
+ BrownieStoreManager &BrownieStoreManager::shared() {
6
+ static BrownieStoreManager instance;
7
+ return instance;
8
+ }
9
+
10
+ void BrownieStoreManager::registerStore(const std::string &key,
11
+ std::shared_ptr<BrownieStore> store) {
12
+ std::lock_guard<std::mutex> lock(mutex_);
13
+ stores_[key] = std::move(store);
14
+ }
15
+
16
+ std::shared_ptr<BrownieStore>
17
+ BrownieStoreManager::getStore(const std::string &key) const {
18
+ std::lock_guard<std::mutex> lock(mutex_);
19
+ auto it = stores_.find(key);
20
+ if (it != stores_.end()) {
21
+ return it->second;
22
+ }
23
+ return nullptr;
24
+ }
25
+
26
+ void BrownieStoreManager::removeStore(const std::string &key) {
27
+ std::lock_guard<std::mutex> lock(mutex_);
28
+ stores_.erase(key);
29
+ }
30
+
31
+ } // namespace brownie
@@ -0,0 +1,26 @@
1
+ #pragma once
2
+
3
+ #include "BrownieStore.h"
4
+ #include <memory>
5
+ #include <mutex>
6
+ #include <string>
7
+ #include <unordered_map>
8
+
9
+ namespace brownie {
10
+
11
+ class BrownieStoreManager {
12
+ public:
13
+ static BrownieStoreManager &shared();
14
+
15
+ void registerStore(const std::string &key,
16
+ std::shared_ptr<BrownieStore> store);
17
+ std::shared_ptr<BrownieStore> getStore(const std::string &key) const;
18
+ void removeStore(const std::string &key);
19
+
20
+ private:
21
+ BrownieStoreManager() = default;
22
+ mutable std::mutex mutex_;
23
+ std::unordered_map<std::string, std::shared_ptr<BrownieStore>> stores_;
24
+ };
25
+
26
+ } // namespace brownie
File without changes
package/package.json CHANGED
@@ -1,16 +1,19 @@
1
1
  {
2
2
  "name": "@callstack/brownie",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "license": "MIT",
5
5
  "author": "Oskar Kwaśniewski <oskarkwasniewski@icloud.com>",
6
6
  "bin": {
7
- "brownfield": "./lib/commonjs/scripts/brownfield.js"
7
+ "brownfield": "lib/commonjs/scripts/brownfield.js"
8
8
  },
9
9
  "contributors": [
10
10
  "Artur Morys-Magiera <artus9033@gmail.com>",
11
11
  "Oskar Kwasniewski <oskarkwasniewski@icloud.com>"
12
12
  ],
13
13
  "homepage": "https://github.com/callstack/react-native-brownfield",
14
+ "repository": {
15
+ "url": "https://github.com/callstack/react-native-brownfield"
16
+ },
14
17
  "description": "Shared state management between React Native and Native apps",
15
18
  "main": "lib/commonjs/index",
16
19
  "module": "lib/module/index",
@@ -48,12 +51,14 @@
48
51
  "src",
49
52
  "lib",
50
53
  "ios",
54
+ "cpp",
51
55
  "*.podspec",
52
56
  "!ios/build",
53
57
  "!**/__tests__",
54
58
  "!**/__fixtures__",
55
59
  "!**/__mocks__",
56
- "!**/.*"
60
+ "!**/.*",
61
+ "README.md"
57
62
  ],
58
63
  "publishConfig": {
59
64
  "access": "public",
@@ -64,7 +69,7 @@
64
69
  "react-native": "*"
65
70
  },
66
71
  "dependencies": {
67
- "@callstack/brownfield-cli": "^1.0.0",
72
+ "@callstack/brownfield-cli": "workspace:^",
68
73
  "quicktype-core": "^23.2.6",
69
74
  "quicktype-typescript-input": "^23.2.6",
70
75
  "ts-morph": "^27.0.2"
@@ -98,4 +103,4 @@
98
103
  "engines": {
99
104
  "node": ">=20"
100
105
  }
101
- }
106
+ }
@@ -1,42 +0,0 @@
1
- // This file was generated from JSON Schema using quicktype, do not modify it directly.
2
- // To parse the JSON, add this file to your project and do:
3
- //
4
- // let brownfieldStore = try? JSONDecoder().decode(BrownfieldStore.self, from: jsonData)
5
-
6
- //
7
- // Hashable or Equatable:
8
- // The compiler will not be able to synthesize the implementation of Hashable or Equatable
9
- // for types that require the use of JSONAny, nor will the implementation of Hashable be
10
- // synthesized for types that have collections (such as arrays or dictionaries).
11
-
12
- import Foundation
13
-
14
- // MARK: - BrownfieldStore
15
- public struct BrownfieldStore: Codable, Equatable {
16
- public var counter: Double
17
- public var user: User
18
-
19
- public init(counter: Double, user: User) {
20
- self.counter = counter
21
- self.user = user
22
- }
23
- }
24
-
25
- //
26
- // Hashable or Equatable:
27
- // The compiler will not be able to synthesize the implementation of Hashable or Equatable
28
- // for types that require the use of JSONAny, nor will the implementation of Hashable be
29
- // synthesized for types that have collections (such as arrays or dictionaries).
30
-
31
- // MARK: - User
32
- public struct User: Codable, Equatable {
33
- public var name: String
34
-
35
- public init(name: String) {
36
- self.name = name
37
- }
38
- }
39
-
40
- extension BrownfieldStore: BrownieStoreProtocol {
41
- public static let storeName = "BrownfieldStore"
42
- }
@@ -1,33 +0,0 @@
1
- // This file was generated from JSON Schema using quicktype, do not modify it directly.
2
- // To parse the JSON, add this file to your project and do:
3
- //
4
- // let settingsStore = try? JSONDecoder().decode(SettingsStore.self, from: jsonData)
5
-
6
- //
7
- // Hashable or Equatable:
8
- // The compiler will not be able to synthesize the implementation of Hashable or Equatable
9
- // for types that require the use of JSONAny, nor will the implementation of Hashable be
10
- // synthesized for types that have collections (such as arrays or dictionaries).
11
-
12
- import Foundation
13
-
14
- // MARK: - SettingsStore
15
- public struct SettingsStore: Codable, Equatable {
16
- public var notificationsEnabled, privacyMode: Bool
17
- public var theme: Theme
18
-
19
- public init(notificationsEnabled: Bool, privacyMode: Bool, theme: Theme) {
20
- self.notificationsEnabled = notificationsEnabled
21
- self.privacyMode = privacyMode
22
- self.theme = theme
23
- }
24
- }
25
-
26
- public enum Theme: String, Codable, Equatable {
27
- case dark = "dark"
28
- case light = "light"
29
- }
30
-
31
- extension SettingsStore: BrownieStoreProtocol {
32
- public static let storeName = "SettingsStore"
33
- }