diff --git a/.yarn/install-state.gz b/.yarn/install-state.gz index 524e948d..cbb1d2d3 100644 Binary files a/.yarn/install-state.gz and b/.yarn/install-state.gz differ diff --git a/packages/arbor-plugins/package.json b/packages/arbor-plugins/package.json index 15dd5dcf..a6ca0ec7 100644 --- a/packages/arbor-plugins/package.json +++ b/packages/arbor-plugins/package.json @@ -1,6 +1,6 @@ { "name": "@arborjs/plugins", - "version": "0.0.1-alpha.87", + "version": "0.0.1-alpha.88", "sideEffects": false, "description": "Community driven plugins for @arborjs/store.", "keywords": [ @@ -46,7 +46,7 @@ "access": "public" }, "devDependencies": { - "@arborjs/store": "0.0.1-alpha.87", + "@arborjs/store": "0.0.1-alpha.88", "@types/jest": "^29.5.1", "esbuild": "^0.17.19", "eslint": "^8.40.0", @@ -57,7 +57,7 @@ "typescript": "^5.0.4" }, "peerDependencies": { - "@arborjs/store": "0.0.1-alpha.87" + "@arborjs/store": "0.0.1-alpha.88" }, "scripts": { "prettier": "prettier -w . ", diff --git a/packages/arbor-react/package.json b/packages/arbor-react/package.json index 67a9b73d..52cbbf11 100644 --- a/packages/arbor-react/package.json +++ b/packages/arbor-react/package.json @@ -1,6 +1,6 @@ { "name": "@arborjs/react", - "version": "0.0.1-alpha.87", + "version": "0.0.1-alpha.88", "sideEffects": false, "description": "A fully typed, minimalistic proxy-based state tree library with very little boilerplate for React apps.", "keywords": [ @@ -45,7 +45,7 @@ "access": "public" }, "devDependencies": { - "@arborjs/store": "0.0.1-alpha.87", + "@arborjs/store": "0.0.1-alpha.88", "@testing-library/react": "14.0.0", "@types/jest": "^29.5.1", "@types/react": "18.2.31", @@ -71,7 +71,7 @@ "build:dev": "yarn clean && NODE_ENV=development node ../../tools/build.js && yarn tsc" }, "peerDependencies": { - "@arborjs/store": "0.0.1-alpha.87", + "@arborjs/store": "0.0.1-alpha.88", "react": "18.2.0", "react-dom": "18.2.14" } diff --git a/packages/arbor-rxjs/package.json b/packages/arbor-rxjs/package.json index 1870bc29..d92d9f5c 100644 --- a/packages/arbor-rxjs/package.json +++ b/packages/arbor-rxjs/package.json @@ -1,6 +1,6 @@ { "name": "@arborjs/rxjs", - "version": "0.0.1-alpha.87", + "version": "0.0.1-alpha.88", "sideEffects": false, "description": "rxjs binding for @arborjs/store", "keywords": [ @@ -55,7 +55,7 @@ "typescript": "^5.0.4" }, "peerDependencies": { - "@arborjs/store": "0.0.1-alpha.87", + "@arborjs/store": "0.0.1-alpha.88", "rxjs": "*" }, "scripts": { diff --git a/packages/arbor-store/package.json b/packages/arbor-store/package.json index 8d64b7ba..74d69f53 100644 --- a/packages/arbor-store/package.json +++ b/packages/arbor-store/package.json @@ -1,7 +1,7 @@ { "name": "@arborjs/store", "sideEffects": false, - "version": "0.0.1-alpha.87", + "version": "0.0.1-alpha.88", "description": "A fully typed, minimalistic proxy-based state tree library with very little boilerplate.", "keywords": [ "arbor", diff --git a/packages/arbor-store/src/Arbor.test.ts b/packages/arbor-store/src/Arbor.test.ts index c6247f09..7c05ea46 100644 --- a/packages/arbor-store/src/Arbor.test.ts +++ b/packages/arbor-store/src/Arbor.test.ts @@ -2581,4 +2581,34 @@ describe("Arbor", () => { expect(subscriber.mock.calls[1][0].metadata.operation).toEqual("set") expect(subscriber.mock.calls[2][0].metadata.operation).toEqual("push") }) + + it("binds methods to the instance of the node they belong to", () => { + @proxiable + class Todo { + constructor(public text = "", public done = false) {} + + toggle() { + this.done = !this.done + } + } + + @proxiable + class TodoApp { + todos: Todo[] = [] + } + + const store = new TrackedArbor(new Arbor(new TodoApp())) + const subscriber = jest.fn() + + store.subscribe(subscriber) + + const state = store.state + state.todos = [new Todo("Do the dishes"), new Todo("Clean the house")] + + state.todos[0].toggle() + state.todos[1].toggle() + + expect(state.todos[0].done).toBe(true) + expect(state.todos[1].done).toBe(true) + }) }) diff --git a/packages/arbor-store/src/TrackedArbor.ts b/packages/arbor-store/src/TrackedArbor.ts index 67ffe557..95aeddb4 100644 --- a/packages/arbor-store/src/TrackedArbor.ts +++ b/packages/arbor-store/src/TrackedArbor.ts @@ -23,7 +23,7 @@ export function isArborNodeTracked( } class Tracker { - private readonly bindings = new WeakMap() + private readonly bindings = new WeakMap>() private readonly cache = new WeakMap() private tracking = new WeakMap>() @@ -127,13 +127,18 @@ class Tracker { // class methods of Arbor nodes a great option for components event handlers. const unwrappedTarget = recursivelyUnwrap(target) const unwrappedChild = Reflect.get(unwrappedTarget, prop, proxy) - if (!bindings.has(unwrappedChild)) { + if (!bindings.has(unwrappedTarget)) { // Methods are bound to the proxy so that 'this' within the method context // points back to the proxy itself, allowing it to intercept access to nested objects. - bindings.set(unwrappedChild, child.bind(proxy)) + bindings.set(unwrappedTarget, new WeakMap()) } - return bindings.get(unwrappedChild) + const targetBidings = bindings.get(unwrappedTarget) + if (!targetBidings.has(unwrappedChild)) { + targetBidings.set(unwrappedChild, child.bind(proxy)) + } + + return bindings.get(unwrappedTarget).get(unwrappedChild) } return child diff --git a/yarn.lock b/yarn.lock index 2064f1cb..e9881f41 100644 --- a/yarn.lock +++ b/yarn.lock @@ -39,7 +39,7 @@ __metadata: version: 0.0.0-use.local resolution: "@arborjs/plugins@workspace:packages/arbor-plugins" dependencies: - "@arborjs/store": 0.0.1-alpha.87 + "@arborjs/store": 0.0.1-alpha.88 "@types/jest": ^29.5.1 esbuild: ^0.17.19 eslint: ^8.40.0 @@ -49,7 +49,7 @@ __metadata: ts-jest: ^29.1.0 typescript: ^5.0.4 peerDependencies: - "@arborjs/store": 0.0.1-alpha.87 + "@arborjs/store": 0.0.1-alpha.88 languageName: unknown linkType: soft @@ -57,7 +57,7 @@ __metadata: version: 0.0.0-use.local resolution: "@arborjs/react@workspace:packages/arbor-react" dependencies: - "@arborjs/store": 0.0.1-alpha.87 + "@arborjs/store": 0.0.1-alpha.88 "@testing-library/react": 14.0.0 "@types/jest": ^29.5.1 "@types/react": 18.2.31 @@ -73,7 +73,7 @@ __metadata: ts-jest: ^29.1.0 typescript: ^5.0.4 peerDependencies: - "@arborjs/store": 0.0.1-alpha.87 + "@arborjs/store": 0.0.1-alpha.88 react: 18.2.0 react-dom: 18.2.14 languageName: unknown @@ -91,7 +91,7 @@ __metadata: ts-jest: ^29.1.0 typescript: ^5.0.4 peerDependencies: - "@arborjs/store": 0.0.1-alpha.87 + "@arborjs/store": 0.0.1-alpha.88 rxjs: "*" languageName: unknown linkType: soft @@ -105,7 +105,7 @@ __metadata: languageName: unknown linkType: soft -"@arborjs/store@0.0.1-alpha.87, @arborjs/store@workspace:*, @arborjs/store@workspace:^, @arborjs/store@workspace:packages/arbor-store": +"@arborjs/store@0.0.1-alpha.88, @arborjs/store@workspace:*, @arborjs/store@workspace:^, @arborjs/store@workspace:packages/arbor-store": version: 0.0.0-use.local resolution: "@arborjs/store@workspace:packages/arbor-store" dependencies: